From 38bdc95acf791f3cde32208a0f63f9e4fbab30a7 Mon Sep 17 00:00:00 2001 From: gnosygnu Date: Sun, 25 Nov 2018 10:17:03 -0500 Subject: [PATCH] HTTP Server: Support popups [#264] --- 100_core/src/gplx/core/js/Js_wtr.java | 5 +- .../src/gplx/core/net/Gfo_url_parser_tst.java | 3 + .../core/net/Http_request_parser_tst.java | 8 +- .../edits/objs/Xoedit_itm_html_tst.java | 12 +- .../maints/services/Xocfg_maint_svc.java | 21 +- 400_xowa/src/gplx/xowa/apps/Xoa_thread_.java | 1 - .../apps/servers/http/Http_server_mgr.java | 43 +- .../apps/servers/http/Http_server_wkr.java | 3 +- .../apps/servers/http/Http_url_parser.java | 55 +- .../servers/http/Http_url_parser_tst.java | 12 +- .../src/gplx/xowa/guis/views/Xog_tab_itm.java | 7 +- .../views/Xog_win_itm__prog_href_mgr.java | 3 +- .../htmls/heads/Xoh_head_itm__popups.java | 2 +- .../gplx/xowa/htmls/heads/Xoh_head_mgr.java | 8 +- .../src/gplx/xowa/htmls/js/Xoh_js_cbk.java | 28 +- .../modules/popups/Xow_popup_html_mkr.java | 21 + .../htmls/modules/popups/Xow_popup_itm.java | 4 +- .../htmls/modules/popups/Xow_popup_mgr.java | 66 +- .../htmls/modules/popups/Xow_popup_mgr_.java | 10 - .../modules/popups/Xow_popup_parser_tst.java | 2 +- .../addon/app/cfg/edit/bin/xo.cfg_edit.js | 6 +- .../searcher/bin/xofulltext_searcher.js | 8 +- .../any/xowa/html/res/src/xowa/core/core.js | 31 +- .../html/res/src/xowa/popups/mocks/basic.html | 614 ++++++++++++++++++ .../xowa/popups/mocks/pages/Blog.init.html | 75 +++ .../xowa/html/res/src/xowa/popups/popups.js | 277 -------- .../xowa/html/res/src/xowa/popups/xo.popup.js | 454 +++++++++++++ .../xowa/html/res/src/xowa/xoelem/xo.elem.js | 21 +- 28 files changed, 1375 insertions(+), 425 deletions(-) create mode 100644 res/bin/any/xowa/html/res/src/xowa/popups/mocks/basic.html create mode 100644 res/bin/any/xowa/html/res/src/xowa/popups/mocks/pages/Blog.init.html delete mode 100644 res/bin/any/xowa/html/res/src/xowa/popups/popups.js create mode 100644 res/bin/any/xowa/html/res/src/xowa/popups/xo.popup.js diff --git a/100_core/src/gplx/core/js/Js_wtr.java b/100_core/src/gplx/core/js/Js_wtr.java index 35bb23c6d..fc2369cb5 100644 --- a/100_core/src/gplx/core/js/Js_wtr.java +++ b/100_core/src/gplx/core/js/Js_wtr.java @@ -31,9 +31,10 @@ public class Js_wtr { bfr.Add_byte(Byte_ascii.Paren_end).Add_byte_semic(); return this; } - public Js_wtr Prm_bry(byte[] bry) { + public Js_wtr Prm_str(String v) {return Prm_bry(Bry_.new_u8(v));} + public Js_wtr Prm_bry(byte[] v) { Prm_spr(); - Write_val(bry); + Write_val(v); return this; } public Js_wtr Prm_obj_ary(Object[] ary) { diff --git a/400_xowa/src/gplx/core/net/Gfo_url_parser_tst.java b/400_xowa/src/gplx/core/net/Gfo_url_parser_tst.java index 7832257b3..dcc8f0736 100644 --- a/400_xowa/src/gplx/core/net/Gfo_url_parser_tst.java +++ b/400_xowa/src/gplx/core/net/Gfo_url_parser_tst.java @@ -113,6 +113,9 @@ public class Gfo_url_parser_tst { @Test public void Protocol_less__qargs() { tstr.Exec__parse("Special:Search/Earth?fulltext=yes").Test__segs("Special:Search", "Earth").Test__page("Earth").Test__qargs("fulltext", "yes"); } + @Test public void Http_server() { + tstr.Exec__parse("/wiki/Page?A=B").Test__segs("wiki", "Page").Test__page("Page").Test__qargs("A", "B"); + } @Test public void Parse_site_fast() { tstr.Test_Parse_site_fast("http://a.org/B" , "a.org"); tstr.Test_Parse_site_fast("http://a.org" , "a.org"); diff --git a/400_xowa/src/gplx/core/net/Http_request_parser_tst.java b/400_xowa/src/gplx/core/net/Http_request_parser_tst.java index 571e38c50..b031af312 100644 --- a/400_xowa/src/gplx/core/net/Http_request_parser_tst.java +++ b/400_xowa/src/gplx/core/net/Http_request_parser_tst.java @@ -16,7 +16,7 @@ Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt package gplx.core.net; import gplx.*; import gplx.core.*; import org.junit.*; import gplx.core.tests.*; public class Http_request_parser_tst { - @Before public void init() {fxt.Clear();} private final Http_request_parser_fxt fxt = new Http_request_parser_fxt(); + @Before public void init() {fxt.Clear();} private final Http_request_parser_fxt fxt = new Http_request_parser_fxt(); @Test public void Type_post() { fxt.Test_type_post("POST /url HTTP/1.1", Http_request_itm.Type_post, "/url", "HTTP/1.1"); } @@ -53,9 +53,9 @@ public class Http_request_parser_tst { } } class Http_request_parser_fxt { - private final Http_request_parser parser; - private final Http_client_rdr client_rdr = Http_client_rdr_.new_mem(); - private final Http_server_wtr__mock server_wtr = new Http_server_wtr__mock(); + private final Http_request_parser parser; + private final Http_client_rdr client_rdr = Http_client_rdr_.new_mem(); + private final Http_server_wtr__mock server_wtr = new Http_server_wtr__mock(); public Http_request_parser_fxt() { this.parser = new Http_request_parser(server_wtr, false); } diff --git a/400_xowa/src/gplx/xowa/addons/apps/cfgs/specials/edits/objs/Xoedit_itm_html_tst.java b/400_xowa/src/gplx/xowa/addons/apps/cfgs/specials/edits/objs/Xoedit_itm_html_tst.java index 2edc6a9fb..deccdb63c 100644 --- a/400_xowa/src/gplx/xowa/addons/apps/cfgs/specials/edits/objs/Xoedit_itm_html_tst.java +++ b/400_xowa/src/gplx/xowa/addons/apps/cfgs/specials/edits/objs/Xoedit_itm_html_tst.java @@ -17,24 +17,26 @@ package gplx.xowa.addons.apps.cfgs.specials.edits.objs; import gplx.*; import gp import org.junit.*; import gplx.core.tests.*; import gplx.xowa.addons.apps.cfgs.mgrs.types.*; public class Xoedit_itm_html_tst { - private final Xoedit_itm_html_fxt fxt = new Xoedit_itm_html_fxt(); + private final Xoedit_itm_html_fxt fxt = new Xoedit_itm_html_fxt(); @Test public void Build_html__memo() { fxt.Type_("memo").Key_("key1").Name_("name1").Html_cls_("html_cls1").Html_atrs_("key1=val1"); // normal - fxt.Val_("data1").Test__Build_html("\n"); // xml-tags - fxt.Val_("
~{page_text}
").Test__Build_html("\n"); } } class Xoedit_itm_html_fxt { - private final Xocfg_type_mgr type_mgr = new Xocfg_type_mgr(); - private final Bry_bfr bry = Bry_bfr_.New(); + private final Xocfg_type_mgr type_mgr = new Xocfg_type_mgr(); + private final Bry_bfr bry = Bry_bfr_.New(); public Xoedit_itm_html_fxt Type_(String v) {this.type = v; return this;} private String type; public Xoedit_itm_html_fxt Key_(String v) {this.key = v; return this;} private String key; diff --git a/400_xowa/src/gplx/xowa/addons/apps/cfgs/specials/maints/services/Xocfg_maint_svc.java b/400_xowa/src/gplx/xowa/addons/apps/cfgs/specials/maints/services/Xocfg_maint_svc.java index 0e7739d46..669d1fc9c 100644 --- a/400_xowa/src/gplx/xowa/addons/apps/cfgs/specials/maints/services/Xocfg_maint_svc.java +++ b/400_xowa/src/gplx/xowa/addons/apps/cfgs/specials/maints/services/Xocfg_maint_svc.java @@ -33,13 +33,30 @@ public class Xocfg_maint_svc { // exec Xocfg_db_app db_app = Xocfg_db_app.New(app); db_app.Conn().Txn_bgn("xo__cfg_maint__upsert"); - byte[] anch_find_bry = Bry_.new_a7("
}' class='xowa-hover-off'>" + , " }' class='xowa-hover-off' target='_blank'>" +// , " }'>" + , "
" + , "
" + )) ; private static final String[] Dflt_html_fmtr_popup_keys = String_.Ary("content", "page_lang_ltr", "page_url", "page_title", "popup_id", "wiki_item", "page_size", "edit_time", "view_time_item", "xowa_root_dir") diff --git a/400_xowa/src/gplx/xowa/htmls/modules/popups/Xow_popup_itm.java b/400_xowa/src/gplx/xowa/htmls/modules/popups/Xow_popup_itm.java index 52885df4e..d21eb74a0 100644 --- a/400_xowa/src/gplx/xowa/htmls/modules/popups/Xow_popup_itm.java +++ b/400_xowa/src/gplx/xowa/htmls/modules/popups/Xow_popup_itm.java @@ -15,8 +15,8 @@ Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt */ package gplx.xowa.htmls.modules.popups; import gplx.*; import gplx.xowa.*; import gplx.xowa.htmls.*; import gplx.xowa.htmls.modules.*; public class Xow_popup_itm implements Cancelable { - public Xow_popup_itm(int id, byte[] page_href, byte[] tooltip, int init_words_needed) { - this.popup_id = gplx.xowa.apps.Xoa_thread_.Key_page_popup + Int_.To_str(id); + public Xow_popup_itm(String popup_id, byte[] page_href, byte[] tooltip, int init_words_needed) { + this.popup_id = popup_id; this.words_needed = init_words_needed; this.page_href = page_href; this.tooltip = tooltip; diff --git a/400_xowa/src/gplx/xowa/htmls/modules/popups/Xow_popup_mgr.java b/400_xowa/src/gplx/xowa/htmls/modules/popups/Xow_popup_mgr.java index ac49e2a07..4d92872bc 100644 --- a/400_xowa/src/gplx/xowa/htmls/modules/popups/Xow_popup_mgr.java +++ b/400_xowa/src/gplx/xowa/htmls/modules/popups/Xow_popup_mgr.java @@ -26,7 +26,7 @@ public class Xow_popup_mgr implements Gfo_invk, Gfo_evt_itm { private Xoae_app app; private Xowe_wiki wiki; private Js_wtr js_wtr = new Js_wtr(); private int show_init_word_count, show_more_word_count; private Xoa_url tmp_url = Xoa_url.blank(); - private static final Object thread_lock = new Object(); private Xow_popup_itm async_itm; private Gfo_invk async_cmd_show; private int async_id_next = 1; + private static final Object thread_lock = new Object(); public Xow_popup_mgr(Xowe_wiki wiki) { this.wiki = wiki; this.app = wiki.Appe(); ev_mgr = new Gfo_evt_mgr(this); @@ -44,35 +44,27 @@ public class Xow_popup_mgr implements Gfo_invk, Gfo_evt_itm { , Cfg__ns_allowed, Cfg__xnde_ignore_ids, Cfg__scan_len, Cfg__scan_max ); } - public String Show_init(int id, byte[] href, byte[] tooltip) { + public String Show_init(String popup_id, byte[] href, byte[] tooltip) { Xoae_page cur_page = Cur_page(); Xog_tab_itm tab = cur_page.Tab_data().Tab(); if (tab != null && tab.Tab_is_loading()) return ""; // NOTE: tab is null when previewing - Xow_popup_itm itm = new Xow_popup_itm(id, href, tooltip, show_init_word_count); + Xow_popup_itm itm = new Xow_popup_itm(popup_id, href, tooltip, show_init_word_count); String rv = String_.new_u8(Get_popup_html(Cur_wiki(), cur_page, itm)); return tab != null && tab.Tab_is_loading() ? "" : rv; } - public void Show_more(String popup_id) { + public String Show_more(String popup_id) { Xoae_page cur_page = Cur_page(); Xow_popup_itm popup_itm = Itms_get_or_null(cur_page, popup_id).Mode_more_(show_more_word_count); - popup_itm.Popup_html_(Get_popup_html(Cur_wiki(), cur_page, popup_itm)); - Show_popup_html(Cbk_xowa_popups_show_update, Mode_show_more, popup_itm); + byte[] html = Get_popup_html(Cur_wiki(), cur_page, popup_itm); + popup_itm.Popup_html_(html); + Show_popup_html(popup_itm, Cbk_update_popup_html, Mode_show_more); + return String_.new_u8(html); } public void Show_all(String popup_id) { Xoae_page cur_page = Cur_page(); Xow_popup_itm popup_itm = Itms_get_or_null(cur_page, popup_id).Mode_all_(); popup_itm.Popup_html_(Get_popup_html(Cur_wiki(), cur_page, popup_itm)); - Show_popup_html(Cbk_xowa_popups_show_update, Mode_show_all, popup_itm); - } - public String Get_async_bgn(byte[] js_cbk, byte[] href) { - if (Bry_.Has_at_bgn(href, gplx.xowa.parsers.lnkes.Xop_lnke_wkr.Bry_xowa_protocol)) return null; // ignore xowa-cmd - synchronized (thread_lock) { - if (async_itm != null) async_itm.Cancel(); - async_itm = new Xow_popup_itm(++async_id_next, href, Bry_.Empty, show_init_word_count); - String id_str = async_itm.Popup_id(); - Thread_adp_.Start_by_key(id_str, this, Invk_show_popup_async); - return id_str; - } + Show_popup_html(popup_itm, Cbk_update_popup_html, Mode_show_all); } public static boolean Running() { boolean rv = false; @@ -139,27 +131,18 @@ public class Xow_popup_mgr implements Gfo_invk, Gfo_evt_itm { href = Bry_.Add(tooltip); Xog_win_itm__prog_href_mgr.Hover(app, app.Gui_mgr().Browser_win().Cfg().Status__show_short_url(), cur_wiki, cur_page, String_.new_u8(href)); // set page ttl again in prog bar; DATE:2014-06-28 } - public void Show_popup_html(String cbk, byte[] mode, Xow_popup_itm popup_itm) { + private void Show_popup_html(Xow_popup_itm popup_itm, String cbk, byte[] mode) { + // build js cmd + js_wtr.Func_init(cbk); + js_wtr.Prm_str(popup_itm.Popup_id()); + js_wtr.Prm_bry(mode); + js_wtr.Prm_bry(popup_itm.Popup_html()); + js_wtr.Func_term(); + String js_cmd = js_wtr.To_str_and_clear(); + + // send it Xog_tab_itm cur_tab = app.Gui_mgr().Browser_win().Active_tab(); - cur_tab.Html_box().Html_js_eval_script(Xow_popup_mgr_.Bld_js_cmd(js_wtr, cbk, mode, popup_itm.Page_href(), popup_itm.Popup_html())); - } - private void Show_popup_async() { - try { - synchronized (thread_lock) { - Xoae_page cur_page = app.Gui_mgr().Browser_win().Active_page(); - async_itm.Popup_html_(Get_popup_html(app.Gui_mgr().Browser_win().Active_wiki(), cur_page, async_itm)); - } - if (async_cmd_show == null) - async_cmd_show = app.Gui_mgr().Kit().New_cmd_sync(this); - Gfo_invk_.Invk_by_key(async_cmd_show, Invk_show_popup); - } - catch(Exception e) { - app.Usr_dlg().Warn_many("", "", "failed to get popup: href=~{0} err=~{1}", async_itm.Page_href(), Err_.Message_gplx_full(e)); - } - } - private void Show_popup() { - if (async_itm.Canceled()) return; - Show_popup_html(Cbk_xowa_popups_show_create, Bry_.Empty, async_itm); + cur_tab.Html_box().Html_js_eval_script(js_cmd); } public void Ns_allowed_(byte[] raw) { ns_allowed_regy.Clear(); @@ -195,10 +178,7 @@ public class Xow_popup_mgr implements Gfo_invk, Gfo_evt_itm { private Xowe_wiki Cur_wiki() {return app.Gui_mgr().Browser_win().Active_tab().Wiki();} private Xow_popup_itm Itms_get_or_null(Xoae_page page, String popup_id) {return (Xow_popup_itm)page.Popup_mgr().Itms().Get_by(popup_id);} public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) { - if (ctx.Match(k, Invk_show_popup_async)) Show_popup_async(); - else if (ctx.Match(k, Invk_show_popup)) Show_popup(); - - else if (ctx.Match(k, Cfg__enabled)) enabled = m.ReadYn("v"); + if (ctx.Match(k, Cfg__enabled)) enabled = m.ReadYn("v"); else if (ctx.Match(k, Cfg__show_init_word_count)) show_init_word_count = m.ReadInt("v"); else if (ctx.Match(k, Cfg__show_more_word_count)) show_more_word_count = m.ReadInt("v"); else if (ctx.Match(k, Cfg__show_all_if_less_than)) parser.Cfg().Show_all_if_less_than_(m.ReadInt("v")); @@ -214,10 +194,8 @@ public class Xow_popup_mgr implements Gfo_invk, Gfo_evt_itm { else return Gfo_invk_.Rv_unhandled; return this; } - public static final String Invk_show_popup_async = "show_popup_async", Invk_show_popup = "show_popup"; private static final String - Cbk_xowa_popups_show_update = "xowa_popups_show_update" - , Cbk_xowa_popups_show_create = "xowa_popups_show_create" + Cbk_update_popup_html = "window.xowa.popups.UpdatePopupHtml" ; private static final byte[] Mode_show_more = Bry_.new_a7("more") diff --git a/400_xowa/src/gplx/xowa/htmls/modules/popups/Xow_popup_mgr_.java b/400_xowa/src/gplx/xowa/htmls/modules/popups/Xow_popup_mgr_.java index 32b1544b6..624dd674d 100644 --- a/400_xowa/src/gplx/xowa/htmls/modules/popups/Xow_popup_mgr_.java +++ b/400_xowa/src/gplx/xowa/htmls/modules/popups/Xow_popup_mgr_.java @@ -16,16 +16,6 @@ Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt package gplx.xowa.htmls.modules.popups; import gplx.*; import gplx.xowa.*; import gplx.xowa.htmls.*; import gplx.xowa.htmls.modules.*; import gplx.core.threads.*; import gplx.core.primitives.*; import gplx.core.js.*; import gplx.xowa.wikis.nss.*; import gplx.xowa.specials.*; -class Xow_popup_mgr_ { - public static String Bld_js_cmd(Js_wtr js_wtr, String cbk, byte[] mode, byte[] href, byte[] html) { - js_wtr.Func_init(cbk); - js_wtr.Prm_bry(mode); - js_wtr.Prm_bry(href); - js_wtr.Prm_bry(html); - js_wtr.Func_term(); - return js_wtr.To_str_and_clear(); - } -} class Load_popup_wkr implements Gfo_thread_wkr { private Xow_popup_itm itm; private Xoae_page cur_page; private Xoa_url tmp_url; private Hash_adp ns_allowed_regy; diff --git a/400_xowa/src/gplx/xowa/htmls/modules/popups/Xow_popup_parser_tst.java b/400_xowa/src/gplx/xowa/htmls/modules/popups/Xow_popup_parser_tst.java index fa9e4b874..de4237ef0 100644 --- a/400_xowa/src/gplx/xowa/htmls/modules/popups/Xow_popup_parser_tst.java +++ b/400_xowa/src/gplx/xowa/htmls/modules/popups/Xow_popup_parser_tst.java @@ -506,7 +506,7 @@ class Xop_popup_parser_fxt { public void Test_parse(String raw, String ttl, String expd) { Xoae_page page = Xoae_page.New_edit(wiki, Xoa_ttl.Parse(wiki, Bry_.new_a7(ttl))); page.Db().Text().Text_bry_(Bry_.new_u8(raw)); - Xow_popup_itm itm = new Xow_popup_itm(1, Bry_.new_u8(raw), Bry_.Empty, word_min); + Xow_popup_itm itm = new Xow_popup_itm("popup_1", Bry_.new_u8(raw), Bry_.Empty, word_min); itm.Init(wiki.Domain_bry(), page.Ttl()); byte[] actl = parser.Parse(wiki, page, null, itm); Tfds.Eq_str_lines(expd, String_.new_u8(actl)); diff --git a/res/bin/any/xowa/addon/app/cfg/edit/bin/xo.cfg_edit.js b/res/bin/any/xowa/addon/app/cfg/edit/bin/xo.cfg_edit.js index ddae54a9e..6221a1f7c 100644 --- a/res/bin/any/xowa/addon/app/cfg/edit/bin/xo.cfg_edit.js +++ b/res/bin/any/xowa/addon/app/cfg/edit/bin/xo.cfg_edit.js @@ -243,11 +243,9 @@ // bind update and popups xo.cfg_edit.cfg_val__bind_all(); - try { - xowa_popups_bind_to_owner(document); - } catch (err) {} + xowa.js.doc.evtElemAdd.pub(document); return true; - } catch (err) {alert(err);} + } catch (err) {alert('xo.cfg_edit:' + err);} } //} diff --git a/res/bin/any/xowa/addon/wiki/fulltext/searcher/bin/xofulltext_searcher.js b/res/bin/any/xowa/addon/wiki/fulltext/searcher/bin/xofulltext_searcher.js index 86fbf51a3..10f1736c6 100644 --- a/res/bin/any/xowa/addon/wiki/fulltext/searcher/bin/xofulltext_searcher.js +++ b/res/bin/any/xowa/addon/wiki/fulltext/searcher/bin/xofulltext_searcher.js @@ -24,13 +24,14 @@ // onload fires multiple times on drd; only run once if (this.loaded) return; this.loaded = true; - + // init notify anchor; focus search_btn xo.notify.elem_anchor = '#main_div'; xo.elem.get('search_txt').focus(); // run search var query = xo.elem.get_val_or_null('search_txt'); + if (query && query.length > 0) { this.search_run(); } @@ -61,7 +62,6 @@ // get search_text var search_text = xo.elem.get_val_or_null('search_txt'); search_text = search_text.replace(/ /g, "_"); // replace " " with "_"; this replacement is done automatically in drd.WebView, but is done manually here with swt.swtbrowser for consistency - // get data specified by user var msg = { search: xo.elem.get_val_or_null('search_txt') @@ -100,6 +100,7 @@ try { // get search_text var search_text = xo.elem.get_val_or_null('search_txt'); + search_text = encodeURI(search_text); // if search_text has changed, reset offsets; EX: on 21-40 of 'earth'; changing search to 'moon' should start from 1, not 21 if (search_text !== xo.elem.get_val_or_null('qarg_search')) { @@ -127,7 +128,6 @@ // get qarg / dflt values var qarg_val = xo.elem.get_val_or_null('qarg_' + key); var dflt_val = xo.elem.get_val_or_null('dflt_' + key); - // if qarg === dflt, return url if (qarg_val === dflt_val) { return url; @@ -308,7 +308,7 @@ // publish elem_add event for popups var page_elem_key = 'results_wiki_' + wiki + '_page_' + msg.page_id; var page_elem = xo.elem.get(page_elem_key); - xo.elem.elem_add__pub(page_elem); + xowa.js.doc.evtElemAdd.pub(page_elem); } catch (err) { this.handle_err(err + " proc=results__page__add; msg=" + JSON.stringify(msg)); } diff --git a/res/bin/any/xowa/html/res/src/xowa/core/core.js b/res/bin/any/xowa/html/res/src/xowa/core/core.js index 7a148f43e..c7205caa4 100644 --- a/res/bin/any/xowa/html/res/src/xowa/core/core.js +++ b/res/bin/any/xowa/html/res/src/xowa/core/core.js @@ -1,3 +1,25 @@ +// Add Event Manager for simple pub/sub pattern; DATE:2018-11-11 +var XoEvtMgr = (function(){ + var funcs = []; + function XoEvtMgr() { + } + + XoEvtMgr.prototype.sub = function(func) { + funcs.push(func); + } + + XoEvtMgr.prototype.pub = function() { + var funcsIdx = 0; + var funcsLen = funcs.length; + for (funcsIdx = 0; funcsIdx < funcsLen; funcsIdx++) { + var func = funcs[funcsIdx]; + func(arguments); + } + } + + return XoEvtMgr; +}()); + if (!window.xowa) { window.xowa = { root_dir : xowa_root_dir, @@ -409,6 +431,8 @@ if (!window.xowa) { return or_val; }; + xowa.js.doc.evtElemAdd = new XoEvtMgr(); + // PURPOSE: used when clicking on file to get xowa_title xowa.js.doc.root_html_get = function() { return document.getElementsByTagName("html")[0].innerHTML; @@ -435,11 +459,12 @@ if (!window.xowa) { xowa.js.doc.process_new_elem(elem.parentNode); // NOTE: elem is placeholder item; html is inserted after it; need to call process_new_elem on parentNode; DATE:2015-08-03 }; - +/* + xowa.js.doc.ElemAdd.publish() +*/ // PURPOSE: process new element such as adding bindings; DATE:2015-07-09 xowa.js.doc.process_new_elem = function(elem) { - if (elem == null) elem = document; - xowa_popups_bind_to_owner($(elem)); + xowa.js.doc.EvtElemAdd.pub(elem); } // PURPOSE: async search; gallery; imap diff --git a/res/bin/any/xowa/html/res/src/xowa/popups/mocks/basic.html b/res/bin/any/xowa/html/res/src/xowa/popups/mocks/basic.html new file mode 100644 index 000000000..c095f63be --- /dev/null +++ b/res/bin/any/xowa/html/res/src/xowa/popups/mocks/basic.html @@ -0,0 +1,614 @@ + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+

Main Page

+
+
From XOWA: the free, open-source, offline wiki application
+
+ +
+ +

+ Disclaimer +

+

+ Please note that this program is beta software. Although it is my best hope that you find this program functional and useful, I make no assurances regarding stability or fitness of purpose. For more details, see Help/License/Code. +

+

+ Release notes +

+

+ v4.5.21.1808 features the following: +

+
    +
  • + (Wiki) Publish 2018-07 English Wikipedia +
  • +
  • + (PC) Fix multiple script errors due to Wikibase and Scribunto. +
  • +
+

+ For more details about this release, please see the blog and the change log. +

+

+ For more details about the release schedule, please see the release schedule. +

+

+ New users +

+

+ If this is the first time you've run XOWA, then please choose from the following: +

+
    +
  • + Build a wiki while online +
  • +
  • + Build a wiki while offline +
  • +
  • + Download pre-built wikis within XOWA +
  • +
  • + Download pre-built wikis within a browser +
  • +
+

+ In addition, XOWA now supports creation of your own personal wiki. +

+
+ Build a wiki while online +
+
+
    +
  • + Import Simple Wikipedia +
  • +
+
+
+ Simple Wikipedia is a small wiki that fits in about 200 MB and sets up in about 3 minutes. +
+
+ When you are ready to start, click this link: +
+
+ Set up Simple Wikipedia +
+
+
+
+ Feel free to look around during the import process. You can start at Help/Contents. When the process completes, it will open Simple Wikipedia. +
+
+
+
+ After the setup completes, you can visit these pages: +
+
+ Gothic architecture +
+
+ Saturn (planet) +
+
+ Chess +
+
+ World History +
+
+
+
+
    +
  • + Import other wikis +
  • +
+
+
+ After exploring Simple Wikipedia, you may want to import another wiki such as English Wikipedia, French Wiktionary, German Wikisource, Wikidata, Commons, etc. +
+
+ To import another wiki, please visit import online. +
+
+
+ Build a wiki while offline +
+ +
+ Download pre-built wikis within XOWA +
+ +
+ Download pre-built wikis within a browser +
+
    +
  • + Go to Wiki_setup/Listing +
  • +
  • + Navigate to your wiki page from the list +
  • +
  • + Download the listed urls +
  • +
+
+ Creating a personal wiki +
+
    +
  • + From the main menu, choose Personal wikis -> New personal wiki +
  • +
  • + Fill in domain, name, and folder +
  • +
  • + Press the Save icon +
  • +
+

+ Upgrade users +

+ +
+
+ v3.3.4 uses sqlite 3.8.2 +
+
+
    +
  • + v3.1.3 features the XOWA Android application +
  • +
  • + v2.8.1 has a language converter dropdown for the Chinese wikis. +
  • +
  • + v2.7.3 introduces a new Bookmarks page. See Special:XowaBookmarks +
  • +
  • + v2.6.5 uses SWT v4.5 and XULRunner v24. See Dev/SWT and HTML Browser +
  • +
  • + v2.6.3 uses WebKit for MacOSX. For more info, see Blog
    +
  • +
+
+
+ v2.6.3 also fully supports multiple-word-highlight when using find. Press Ctrl+F and try it out. +
+
+
    +
  • + v2.5.4 has changed online file downloads. Among other things, ImageMagick and Inkscape are no longer required. For more info, see Files +
  • +
  • + v2.4.2 has improved Search performance and v2.4.4 has added multi-wiki Search. For more info, see App/Search +
  • +
  • + v2.4.1 has introduced major database layout changes. For more info, see Database +
  • +
+

+ Tips +

+
    +
  • + Autocomplete address bar: The address bar supports autocomplete. Type something like "search" and see the results. +
  • +
  • + Navigation buttons: The arrow icons in the upper left-hand corner represent the back and forward button. Click on them just like you would in a web browser. You can also use Alt+Left and Alt+Right. +
  • +
  • + Font size: + +
  • +
  • + Find box: Press Ctrl+F on your keyboard. This will show the Find box (in the lower left-hand corner). Type "tips". Notice that the word "Tips" is highlighted above. Note that Alt+P (Previous) and Alt+N (Next) will change search direction. See Find Box for more info. +
  • +
  • + Address bar: Press Alt+D or Ctrl+L on your keyboard. This will take you to the Address bar at the top of the screen. Type "s.w:Earth" (no quotes) and press Enter. This will open the Simple Wikipedia page for Earth. See Address bar/Shortcuts for more shortcuts. +
  • +
  • + Middle-click in address bar: Copy and paste urls directly into the address bar with the middle mouse button to open the page. For example: + +
  • +
+
+
+
+
+ Now you can copy and paste any Wikipedia url directly into XOWA and its page will open (and all its images will download.) See Address_bar/URLs for more info +
+
+
+
+
    +
  • + Middle-click on link: Open a tab in a new link by middle-clicking on it. Try middle-clicking the following: Options +
  • +
  • + Right-click: Right click on an image and click save as file +
  • +
+

+ Notes +

+
    +
  • + Wikidata: If you're seeing {{#property}} in your wikis you should also set up Wikidata. See App/Wiki_types/Wikidata +
  • +
+

+ Links +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Download Central + + Download an Android-ready wiki with images from archive.org +
+ Import Online + + Import a wiki from a list of 829 known Wikimedia Foundation wikis +
+ Import Offline + + Import a wiki through a dump; import also through script; also upgrade category to version 2 +
+ Image databases + + Download image databases for your wiki +
+ Wiki Maintenance + + Update your wikis if they are outdated +
+ FAQs + + View questions asked by other users +
+ Contents + + View all help topics +
+ Options + + Configure XOWA options +
+ Change log + + View changes for each XOWA release +
+ Diagnostics + + Run test pages to make sure that XOWA works on your system. +
+ Report issues + + Report bugs / issues on Github +
+ +
+ +
+
+
+
+ + + +
+
+

Personal tools

+
+
+
+

Namespaces

+ +
+
+
+
+

Views

+ +
+
+
+ +
+ +

+ + + + + +
+
+ + + \ No newline at end of file diff --git a/res/bin/any/xowa/html/res/src/xowa/popups/mocks/pages/Blog.init.html b/res/bin/any/xowa/html/res/src/xowa/popups/mocks/pages/Blog.init.html new file mode 100644 index 000000000..145d92534 --- /dev/null +++ b/res/bin/any/xowa/html/res/src/xowa/popups/mocks/pages/Blog.init.html @@ -0,0 +1,75 @@ +
+
+

+ Release: v4.8.21.1808 (2018-08-06 21:00 Mon) +

+

+ The PC version is a minor release. It fixes parsing issues for 2018-07 English Wikipedia +

+

+ The Android version is a trivial release. It updates the list of wikis for Download Central. +

+

+ (Wiki) Publish 2018-08 English Wikipedia +

+

+ You can get them from Download Central or see the following links: +

+ +

+ (PC) Fix multiple script errors due to Wikibase and Scribunto +

+

+ There were a handful of parsing issues with English and German Wikipedia. In brief: +

+
    +
  • + Graph: Support v2 (some pages can only be viewable in HTTP_Server; EX: en.w:Obesity) +
  • +
  • + Wikibase: Add isValidEntityId and getSetting +
  • +
  • + Scribunto: Add stripNoWiki +
  • +
  • + Scribunto: Return empty string for invalid languages +
  • +
  • + Scribunto: Add better support for balanced pairs +
  • +
  • + Parser: Cache ifexist calls +
  • +
+

+ Next section: Next release +

+ +
+
+
+ Blog/2018-01 + size:2.288 KB + edited:2018-08-05 21:16:54 + 2018-08-12 21:37:03 +
+
+
+ + + + + + + + +
+
\ No newline at end of file diff --git a/res/bin/any/xowa/html/res/src/xowa/popups/popups.js b/res/bin/any/xowa/html/res/src/xowa/popups/popups.js deleted file mode 100644 index e26b3ec29..000000000 --- a/res/bin/any/xowa/html/res/src/xowa/popups/popups.js +++ /dev/null @@ -1,277 +0,0 @@ -/* -Based on Schnark's javascript for Reference tooltips -*/ -(function($){ -var cfg = { - show_delay : xowa.cfg.get('popups-win-show_delay'), - hide_delay : xowa.cfg.get('popups-win-hide_delay'), - max_w : xowa.cfg.get('popups-win-max_w'), - max_h : xowa.cfg.get('popups-win-max_h'), - show_all_max_w : xowa.cfg.get('popups-win-show_all_max_w'), - bind_focus_blur : xowa.cfg.get('popups-win-bind_focus_blur'), - bind_hover_area : xowa.cfg.get('popups-win-bind_hover_area'), - }; -var fudge_size = 8; - -if (window.xowa_popups_show_update == null) { - window.xowa_popups_show_update = xowa_popups_show_update; -} -if (window.xowa_popups_hide_all == null) { - window.xowa_popups_hide_all = xowa_popups_hide_all; -} -if (window.xowa_popups_bind_doc == null) { - window.xowa_popups_bind_doc = bind_hover_to_doc; -} -if (window.xowa_popups_bind_to_owner == null) { - window.xowa_popups_bind_to_owner = bind_hover_to_owner; -} -if (window.xowa_popups_bind_to_owner_js == null) { - window.xowa_popups_bind_to_owner_js = bind_hover_to_owner_js; - - // subscribe to elem_add notifications - if (window.xo != null && window.xo.elem != null) { - xo.elem.elem_add__sub(window.xowa_popups_bind_to_owner_js); - } -} -if (window.xowa_popups_bind_elem == null) { - window.xowa_popups_bind_elem = bind_hover_to; -} -var popup_cache = {}; -var popup_next_id = 1; -var protocol_pattern = /^(((http|https|ftp):\/\/)|(javascript:|xowa-cmd:)|#cite_)/; -function show_init(elem, popup_itm, anchor_x, anchor_y) { - var elem_is_area = elem.prop('tagName') === 'AREA'; - var popup_tooltip = elem_is_area ? elem.data('title') : ''; // only show tooltip if area - if (elem_is_area) { - window.status = popup_tooltip; - } - if (!popup_itm.html || popup_itm.href === '/wiki/Special:XowaPopupHistory') { - var html = xowa_exec('popups_get_html', popup_next_id, popup_itm.href, popup_tooltip); - if (!html) { // html is null; occurs for protocols such as http: and xowa-cmd: - elem.attr('title', elem.data('title')); // restore tooltip - return; - } - popup_itm.html = html; - } - var popup_id = 'popup_' + (popup_next_id++).toString(); - popup_itm.id = popup_id; - /* - */ - // insert popup to body else Read / Edit / View HTML will show on top; use multiple div wrappers to inherit same text styles from MW style sheet; DATE:2015-07-31 - // var $wrapper_1 = $('
',{'class':'mw-body'}) .appendTo('body'); // TOMBSTONE: do not dynamically add element; just use pre-existing item; DATE:2016-12-13 - var $wrapper_1 = $('#xo-popup-div-id'); - var $wrapper_2 = $('
',{'class':'mw-body-content'}).appendTo($wrapper_1); - var $wrapper_3 = $('
',{'class':'mw-content-ltr'}) .appendTo($wrapper_2); - var $popup = $('
').attr('id', popup_id).addClass('xowa_popup').append(popup_itm.html).appendTo($wrapper_3); - // var $popup = $('
').attr('id', popup_id).addClass('xowa_popup').append(popup_itm.html).appendTo($('#mw-content-text')); - var window_max_w = cfg.max_w; - if (popup_itm.show_all_anchor_x) { - anchor_x = popup_itm.show_all_anchor_x; - window_max_w = popup_itm.show_all_max_w; - } - return show_popup(popup_itm, $popup, anchor_x, anchor_y, window_max_w); -} -function xowa_popups_show_update(mode, href, html) { - var popup_itm = popup_cache[href]; - if (!popup_itm) return; // shouldn't happen - var $popup = $("#" + popup_itm.id); - $popup.html(html); - popup_itm.html = html; - var $window = $(window); - var $anchor = $(popup_itm.anchor); - var anchor_x = $popup.offset().left; - var popup_max_w = cfg.max_w; - if (mode == 'all' && cfg.show_all_max_w != -1) { - popup_max_w = cfg.show_all_max_w; - var window_width = $window.width(); - if (anchor_x + popup_max_w > window_width) - anchor_x = window_width - popup_max_w; - if (anchor_x < 0) anchor_x = 0; - popup_itm.show_all_anchor_x = anchor_x; - popup_itm.show_all_max_w = popup_max_w; - } - var anchor_y = $anchor.offset().top - $window.scrollTop(); - if (anchor_y < 0) anchor_y = 0; // sometimes < 0; not sure why - show_popup(popup_itm, $popup, anchor_x - fudge_size, anchor_y, popup_max_w); // need to subtract fudge_size, or else popup drifts rightwards -} -function xowa_popups_hide_all() { - var now_time = new Date().getTime(); - for (var popup_key in popup_cache) { - var popup_itm = popup_cache[popup_key]; - if (now_time - popup_itm.show_time < cfg.show_delay) // hide popup only if shown recently; allows popups that were showing to still show while page is loaded - popup_itm.popup.hide(); - } -} -function show_focus ($this) { - var ev = { - clientX : $this.offset().left - $(window).scrollLeft(), - clientY : $this.offset().top - $(window).scrollTop(), - } - show($this, ev); -} -function show ($this, ev) { - var href = $this.attr('href'); - if (!href || href.length == 0) return; - if (href.charAt(0) === '#') return; // ignore "#" which is used for javascript; DATE:2014-08-21 - if (protocol_pattern.test(href)) return; // ignore hrefs with absolute protocol of "http:", etc. which won't point to XOWA content - if ($this.hasClass('xowa-hover-off')) return; // ignore href if "xowa-hover-off" (for sidebar itms) - var popup_itm = popup_cache[href]; - if (!popup_itm) { - popup_itm = { - href : href, - anchor : $this, - }; - popup_cache[href] = popup_itm; - } - data = $this.data(); - if (data.willShow) { - return; - } - if (data.willHide) { - $this.data('willHide', false); - window.clearTimeout(data.hideTimer); - return; - } - if (data.popupVisible) { - return; - } - if (!$this.data('title')) { - $this.data('title', $this.attr('title')); - $this.attr('title', ''); - } - $this.data({ - willShow: true, - showTimer: window.setTimeout(function () { - $this.data({ - willShow: false, - popupVisible: true, - popupRef: show_init($this, popup_itm, ev.clientX, ev.clientY).hover( - function () { - show($this, ev); - }, function () { - hide($this); - }) - }); - }, cfg.show_delay) - }); -} -function show_popup(popup_itm, $popup, anchor_x, anchor_y, popup_max_w) { - var $window = $(window); - var popup_pos = calc_popup_pos(anchor_x, anchor_y, $popup.outerWidth(), $popup.outerHeight(), $window.width(), $window.height()); - if (window.xowa.js.mathJax == null) - window.xowa.js.load_lib(xowa.root_dir + 'bin/any/javascript/xowa/mathjax/xowa_mathjax.js', xowa_mathjax_run); // note that this will only load mathjax if math items are on page - else - xowa_mathjax_run(); - bind_hover_to($('a', $popup)); - $popup.css({ - left: popup_pos.x, - top : popup_pos.y, - }); - if (popup_max_w > 0) - $popup.css({maxWidth: popup_max_w}); - else - $popup.css({maxWidth : cfg.max_w}); - var max_h = $window.height() - 20; //margin, border, padding + noch ein bisschen Sicherheit - if (cfg.max_h > 0 && cfg.max_h < max_h) - max_h = cfg.max_h; - $popup.css({maxHeight: max_h}); - popup_itm.popup = $popup; - popup_itm.show_time = new Date().getTime(); - return $popup.hide().fadeIn('fast'); -} -function xowa_mathjax_run() { // NOTE: need indirection via function else null ref when window.xowa.js.mathJax == null - window.xowa.js.mathJax.run(); -} -function calc_popup_pos (x, y, w, h, W, H) { - var d = fudge_size; // increase distance to prevent popup from overlapping with link - if (x + d + w > W) { - x = W - w - 2; - d = 20; - if (x < 0) { - x = 0; - } - } else { - x = x + d; - } - if (y < h + d) { - if (y + d + h < H) { - y = y + d; - } else { - y = 0; - } - } else { - y = y - h - d; - } - return {x: x, y: y}; -} -function hide ($this) { - var data = $this.data(); - if (data.willHide) { - return; - } - if (data.willShow) { - $this.data('willShow', false); - window.clearTimeout(data.showTimer); - return; - } - if (!data.popupVisible) { - return; - } - $this.data({ - willHide: true, - hideTimer: window.setTimeout(function () { - $this.data({ - willHide: false, - popupVisible: false - }); - reallyHide(data.popupRef); - }, cfg.hide_delay) - }); -} - -function reallyHide ($popup) { - $popup.fadeOut('fast', function () { - if ($popup.find('a').length) { - $popup.detach(); - } else { - $popup.remove(); - } - }); -} -function bind_hover_to_doc() { - bind_hover_to($('a')); - if (cfg.bind_hover_area) - bind_hover_to($('area')); -} -function bind_hover_to_owner_js(owner) { - bind_hover_to_owner(owner); -} -function bind_hover_to_owner(owner) { - bind_hover_to($(owner).find('a')); - if (cfg.bind_hover_area) - bind_hover_to($(owner).find('a')); -} -function bind_hover_to(elems) { - elems.hover( - function (e) { - show($(this), e); - }, function () { - hide($(this)); - }); - if (cfg.bind_focus_blur) { - elems.focus( - function (e) { - show_focus($(this), e); - } - ); - elems.blur( - function (e) { - hide($(this), e); - } - ); - } -} - -$(bind_hover_to_doc); - -})(jQuery); diff --git a/res/bin/any/xowa/html/res/src/xowa/popups/xo.popup.js b/res/bin/any/xowa/html/res/src/xowa/popups/xo.popup.js new file mode 100644 index 000000000..f656ef68a --- /dev/null +++ b/res/bin/any/xowa/html/res/src/xowa/popups/xo.popup.js @@ -0,0 +1,454 @@ +(function($){ // self-invoking anonymous function to reduce pollution of global namespace + +var XoPopupMode = { + Hidden: 'hidden' +, ShowConfirming: 'confirmingShow' +, Shown: 'shown' +, HideConfirming: 'confirmingHide' +} +Object.freeze(XoPopupMode); + +var XoPopupItm = (function(){ + XoPopupItm.prototype.Html = null; + XoPopupItm.prototype.Mode = XoPopupMode.Hidden; + XoPopupItm.prototype.AnchorElem = null; + XoPopupItm.prototype.AnchorTitle = null; + XoPopupItm.prototype.PopupElem = null; + XoPopupItm.prototype.ShowConfirmedCbk = null; + XoPopupItm.prototype.HideConfirmedCbk = null; + XoPopupItm.prototype.HoverX = 0; + XoPopupItm.prototype.HoverY = 0; + + function XoPopupItm(AnchorElem) { + this.Id = 'popup_' + (XoPopupItm.IdNext++).toString(); + this.AnchorElem = AnchorElem; + } + + XoPopupItm.IdNext = 1; + return XoPopupItm; +}()); + +var XoPopupCfg = (function(){ + function XoPopupCfg() { + this.WriteLogEnabled = false; + this.ShowConfirmingDelay = xowa.cfg.get('popups-win-show_delay'); + this.HideConfirmingDelay = xowa.cfg.get('popups-win-hide_delay'); + this.MaxW = xowa.cfg.get('popups-win-max_w'); + this.MaxH = xowa.cfg.get('popups-win-max_h'); + this.ShowAllMaxW = xowa.cfg.get('popups-win-show_all_max_w'); + this.AllowPopupsForKeyboardTabbing = xowa.cfg.get('popups-win-bind_focus_blur'); + this.BindHoverArea = xowa.cfg.get('popups-win-bind_hover_area'); + } + return XoPopupCfg; +}()); + +var XoPopupMgr = (function(){ + // ---------------------------------- + // Ctor; props + // ---------------------------------- + function XoPopupMgr() { + this.BindHoverToDoc(); + + // subscribe to callback + var mgr = this; + xowa.js.doc.evtElemAdd.sub( + function(elem) { + var anchs = $('a', $(elem)); + mgr.BindHoverTo(anchs); + } + ); + } + XoPopupMgr.prototype.Cfg = new XoPopupCfg(); + XoPopupMgr.prototype.Cache = {}; + + // ---------------------------------- + // Bind / to hover + // ---------------------------------- + XoPopupMgr.prototype.BindHoverToDoc = function() { + this.BindHoverTo($('a')); + if (this.Cfg.BindHoverArea) { // tags have href param; REF:en.w:Samuel_Johnson + this.BindHoverTo($('area')); + } + } + XoPopupMgr.prototype.BindHoverTo = function(elems) { + elems = this.BindHoverToFilter(elems); + elems.hover + ( function(ev) {XoPopupMgr.prototype.ShowConfirming($(this), ev);} + , function() {XoPopupMgr.prototype.HideConfirming($(this));} + ); + if (this.Cfg.AllowPopupsForKeyboardTabbing){ + elems.focus(function(ev) {XoPopupMgr.prototype.ShowFocus($(this), ev);}); + elems.blur (function(ev) {XoPopupMgr.prototype.Hide($(this), ev);}); + } + } + // NOTE: ".*/wiki/File:" is for HTTP: ("/en.wikipedia.org/wiki/File:...") and SWT ("/wiki/File:...") + XoPopupMgr.ProtocolPattern = /^(((http|https|ftp):\/\/)|(javascript:|xowa-cmd:|.*\/wiki\/File:|.*\/wiki\/Image:)|#cite_)/; + XoPopupMgr.prototype.BindHoverToFilter = function(elems) { + var array = []; + var len = elems.length; + for (var i = 0; i < len; i++) { + var $anch = $(elems[i]); + var href = $anch.attr('href'); + if (!href || href.length == 0) continue; // ignore empty anch; EX: '' + if (href.charAt(0) === '#') continue; // ignore "#" which is used for javascript; DATE:2014-08-21 + if (XoPopupMgr.ProtocolPattern.test(href)) continue; // ignore hrefs with absolute protocol of "http:", etc. which won't point to XOWA content + if ($anch.hasClass('xowa-hover-off')) continue; // ignore href if "xowa-hover-off" (for sidebar itms) + array.push($anch); + } + return $(array).map (function () {return this.toArray();}); // REF:https://stackoverflow.com/questions/6867184/turn-array-of-jquery-elements-into-jquery-wrapped-set-of-elements + } + + // ---------------------------------- + // Show / hide + // ---------------------------------- + XoPopupMgr.prototype.ShowConfirming = function($anch, ev) { + if (this.Cfg.WriteLogEnabled) this.WriteLogByAnch($anch, 'XoPopupMgr.ShowConfirming.Bgn'); + + // exit unless mode is hidden + var popupItm = this.GetItmOrNew($anch); + switch (popupItm.Mode) { + case XoPopupMode.Hidden: + popupItm.Mode = XoPopupMode.ShowConfirming; + break; + case XoPopupMode.HideConfirming: + popupItm.Mode = XoPopupMode.Shown; + window.clearTimeout(popupItm.HideConfirmedCbk); + return; + case XoPopupMode.ShowConfirming: + case XoPopupMode.Shown: + return; + default: + console.log('XoPopupMgr.ShowConfirming:unknown ' + popupItm.Mode); + return; + } + + // set title to '' b/c we don't want it to show before popup does + if (!popupItm.AnchorTitle) { + popupItm.AnchorTitle = $anch.attr('title'); + $anch.attr('title', ''); + } + + // cache X,Y of mouse pointer + popupItm.HoverX = ev.clientX; + popupItm.HoverY = ev.clientY; + + // set-up callback + var mgr = this; + popupItm.ShowConfirmedCbk = window.setTimeout( + function() {mgr.ShowConfirmed($anch, popupItm);} + , this.Cfg.ShowConfirmingDelay + ); + + if (this.Cfg.WriteLogEnabled) this.WriteLogByAnch($anch, 'XoPopupMgr.ShowConfirming.End'); + } + + XoPopupMgr.prototype.ShowConfirmed = function($anch, popupItm) { + if (this.Cfg.WriteLogEnabled) this.WriteLogByAnch($anch, 'XoPopupMgr.ShowConfirmed.Bgn'); + + // set mode to shown + popupItm.Mode = XoPopupMode.Shown; + + // create popup + var html = popupItm.Html; + if (!html) html = 'retrieving data' + this.CreatePopup(true, popupItm, popupItm.AnchorElem, html); + + // no cached html; call XOWA + if (!popupItm.Html) { + var href = $anch.attr('href'); + var mgr = this; + var showMode = 'init'; + switch (xowa.app.mode) { + case 'http_server': + var req = new XMLHttpRequest(); + if (href.startsWith('/wiki/')) href = xowa.page.wiki + href; // Special:XowaCfg and other pages use AJAX to update page content which won't pass through Convert_page; DATE:2018-11-11 + var path = href + '?action=popup&popup_mode=init&popup_id=' + popupItm.Id; + req.onload = function(e) { + mgr.UpdatePopupHtml(popupItm.Id, showMode, req.responseText); + } + req.open("GET", path, true); // 'false': synchronous. + req.send(null); + break; + case 'mock': + xowa.popups.Mock_popups_get_html(mgr, 'init', popupItm, href); // NOTE: must be "xowa.popups", not "this", b/c "this" will call prototype first + break; + default: + var elemIsArea = $anch.prop('tagName') === 'AREA'; + var popupTooltip = elemIsArea ? $anch.attr('title') : ''; // only show tooltip if area + mgr.UpdatePopupHtml(popupItm.Id, showMode, xowa_exec('popups_get_html', "init", popupItm.Id, href, popupTooltip)); + break; + } + } + + if (this.Cfg.WriteLogEnabled) this.WriteLogByAnch($anch, 'XoPopupMgr.ShowConfirmed.End'); + } + + XoPopupMgr.prototype.HideConfirming = function($anch) { + if (this.Cfg.WriteLogEnabled) this.WriteLogByAnch($anch, 'XoPopupMgr.HideConfirming.Bgn'); + + // exit unless mode is Shown + var popupItm = this.GetItmOrNew($anch); + switch (popupItm.Mode) { + case XoPopupMode.Shown: + popupItm.Mode = XoPopupMode.HideConfirming; + break; + case XoPopupMode.ShowConfirming: + popupItm.Mode = XoPopupMode.Hidden; + window.clearTimeout(popupItm.ShowConfirmedCbk); + return; + case XoPopupMode.HideConfirming: + case XoPopupMode.Hidden: + return; + default: + console.log('XoPopupMgr.HideConfirming:unknown ' + popupItm.Mode); + return; + } + + // set-up callback + var mgr = this; + popupItm.HideConfirmedCbk = window.setTimeout(function () {mgr.HideConfirmed($anch, popupItm);}, this.Cfg.HideConfirmingDelay); + + if (this.Cfg.WriteLogEnabled) this.WriteLogByAnch($anch, 'XoPopupMgr.HideConfirming.End'); + } + + XoPopupMgr.prototype.HideConfirmed = function($anch, popupItm) { + if (this.Cfg.WriteLogEnabled) this.WriteLogByAnch($anch, 'XoPopupMgr.HideConfirmed.Bgn'); + + // set to hidden + popupItm.Mode = XoPopupMode.Hidden; + + // fade item out + var $popup = popupItm.PopupElem; + if ($popup) { + $popup.fadeOut('fast', function () { + $('#' + popupItm.Id + '_body').remove(); + }); + } + + if (this.Cfg.WriteLogEnabled) this.WriteLogByAnch($anch, 'XoPopupMgr.HideConfirmed.End'); + } + + // ---------------------------------- + // create / update popup html + // ---------------------------------- + XoPopupMgr.prototype.CreatePopup = function(create, popupItm, $anch, html) { + // create popup + // insert popup to body, else "Read / Edit / View HTML" will show on top; use multiple div wrappers to inherit same text styles from MW style sheet; DATE:2015-07-31 + // var $wrapper_1 = $('
',{'class':'mw-body'}).appendTo('body'); // TOMBSTONE: do not dynamically add element; just use pre-existing item; DATE:2016-12-13 + var $popup = null; + + if (create) { + var $wrapper_1 = $('#xo-popup-div-id'); + var $wrapper_2 = $('
',{'class':'mw-body-content', 'id':popupItm.Id + '_body'}).appendTo($wrapper_1); + var $wrapper_3 = $('
',{'class':'mw-content-ltr'}) .appendTo($wrapper_2); + $popup = $('
').attr('id', popupItm.Id).addClass('xowa_popup').append(html).appendTo($wrapper_3); + // var $popup = $('
').attr('id', popup_id).addClass('xowa_popup').append(popupItm.html).appendTo($('#mw-content-text')); + popupItm.PopupElem = $popup; + } + else { + $popup = popupItm.PopupElem; + } + + // calc position + var popupX = popupItm.HoverX; + var popupY = popupItm.HoverY; + + // set popup's left / top + var $window = $(window); + var popupPos = XoPopupMgr.AdjustPopupPos(popupX, popupY, $popup.outerWidth(), $popup.outerHeight(), $window.width(), $window.height()); + $popup.css({ + left: popupPos.X, + top : popupPos.Y, + }); + + // default maxW to this.Cfg.MaxW which is ordinarily "-1" which means fit to html; if "all", default to window.width + var popupMaxW = this.Cfg.MaxW; + if (popupItm.ShowMode === 'all') { + popupMaxW = $window.width() - 20; //margin, border, padding + } + $popup.css({maxWidth: popupMaxW}); + + // default maxH to window.height(); can't be -1, else div won't scroll + var popupMaxH = $window.height() - 20; //margin, border, padding + noch ein bisschen Sicherheit + if (this.Cfg.MaxH > 0) { // NOTE: > 0 b/c defaults to -1 + popupMaxH = this.Cfg.MaxH; + } + $popup.css({maxHeight: popupMaxH}); + + // allow popups for any anchor in popup + this.BindHoverTo($('a', $popup)); + + // bind popup's hover to anch; allows hovering over popup to keep popup open + $popup.hover( + function(ev) {XoPopupMgr.prototype.ShowConfirming($anch, ev);} + , function() {XoPopupMgr.prototype.HideConfirming($anch);} + ); + + $popup.fadeIn('fast'); + } + + XoPopupMgr.prototype.UpdatePopupHtml = function(popupItmId, showMode, html) { + // get $anch + var popupItm = this.Cache[popupItmId]; + var $anch = popupItm.AnchorElem; + if (this.Cfg.WriteLogEnabled) this.WriteLogByAnch($anch, 'XoPopupMgr.UpdatePopupHtml.Bgn'); + + // set html + if (!html) { // html is null; occurs for protocols such as http: and xowa-cmd: + $anch.attr('title', popupItm.AnchorTitle); // restore tooltip + return; + } + var mgr = this; + + // update html + var popupHtmlElem = $('#' + popupItm.Id); + popupHtmlElem.fadeOut('fast', function() { + popupItm.ShowMode = showMode; + popupItm.Html = html; + popupHtmlElem.html(html); + mgr.CreatePopup(false, popupItm, popupItm.AnchorElem, html); + popupHtmlElem.fadeIn('fast'); + xowa.js.doc.evtElemAdd.pub(popupItm.PopupElem[0]); // "[0]" -> REF:https://learn.jquery.com/using-jquery-core/faq/how-do-i-pull-a-native-dom-element-from-a-jquery-object/ + }); + + // only show tooltip if area + if ($anch.prop('tagName') === 'AREA') { + window.status = $anch.data('title'); + } + + if (this.Cfg.WriteLogEnabled) this.WriteLogByAnch($anch, 'XoPopupMgr.UpdatePopupHtml.End'); + } + + XoPopupMgr.AdjustPopupPos = function(popupX, popupY, popupW, popupH, windowW, windowH) { + // if popupX causes popup to not show entirely on screen, right-align to window-right + var offsetX = 8; + if (popupX + popupW + offsetX > windowW) { + popupX = windowW - popupW - offsetX; + if (popupX < 0) { + popupX = 0; + } + // else just nudge it by offset to prevent popup from overlapping with link + } else { + popupX = popupX + offsetX; + } + + // if popupY causes popup to not show entirely on screen, bottom-align to window-bottom + var offsetY = 20; // adjust for statusBar + if (popupY + popupH + offsetY > windowH) { + popupY = windowH - popupH - offsetY; + if (popupY < 0) { + popupY = 0; + } + } + // else just nudge it by offset to prevent popup from overlapping with link + else { + popupY = popupY + offsetY; + } + + return {X: popupX, Y: popupY}; + } + + // ---------------------------------- + // Utility + // ---------------------------------- + XoPopupMgr.prototype.GetItmOrNew = function($anch) { + var popupId = $anch.attr('xo_popup_id'); + if (popupId) { + popupItm = this.Cache[popupId]; + } + else { + popupItm = new XoPopupItm($anch); + $anch.attr('xo_popup_id', popupItm.Id); + this.Cache[popupItm.Id] = popupItm; + } + return popupItm; + } + + XoPopupMgr.prototype.WriteLogByAnch = function($anch, message) { + console.log(message + ':' + ' id=' + $anch.attr('xo_popup_id') + ' href=' + $anch.attr('href')); + } + + XoPopupMgr.prototype.dbg = function() { + var args_len = arguments.length; + var elem = document.getElementById('siteSub'); + for (var i = 0; i < args_len; i++) { + elem.innerHTML += ' ' + arguments[i]; + } + } + + /* + XoPopupMgr.prototype.FetchMore = function(popupItmId) { + var popupItm = this.Cache[popupItmId]; + switch (xowa.app.mode) { + case 'http_server': + var href = popupItm.AnchorElem.attr('href'); + var req = new XMLHttpRequest(); + if (href.startsWith('/wiki/')) href = xowa.page.wiki + href; // Special:XowaCfg and other pages use AJAX to update page content which won't pass through Convert_page; DATE:2018-11-11 + var path = href + '?action=popup&popup_mode=more&popup_id=' + popupItmId; + req.onload = function(e) { + mgr.UpdatePopupHtml(popupItm.Id, req.responseText); + } + req.open("GET", path, true); // 'false': synchronous. + req.send(null); + break; + default: + this.UpdatePopupHtml(popupItm.Id, xowa_exec('popups_get_html', "more", popupItm.Id)); + break; + } + } + */ + + return XoPopupMgr; +}()); + +$(document).ready(function() { + window.xowa.popups = new XoPopupMgr(); +}); +})(jQuery); + +/* +# TESTING +## SWT +### en.w:Earth +Basic popup +* Hover over planet -> popup +* Hover over Sun -> popup +* Hover over planet -> cached, and still planet (not sun) +* Hover over Sun -> cached, and still planet (not sun) +* Double hover: hover over any link in Sun popup + +Show more +* Show more a few times -> make sure vertical scroll bar +* Show all -> make sure popup widens + +Ignored links +* xowa-hover-off links should not show +** any link in sidebar +** Article / Talk +** Read, Edit, View HTML +* Http links (scroll down to any link in references) +* Images +* Reference links (should show Reference tool tip) + +### en.w:Samuel_Johnson +Image map via area +(NOTE: this behavior only works in XULRunner; latest Chrome / Firefox no longer captures onmouseenter / onmouseexit for ) +* Scroll down to "A literary party... The Club" and hover over any of the figures + +### Special:XowaSearch?search=test&fulltext=y +Full-text search +* Hover over any of the search results + +---- + +## HTTP server (Firefox) +### http://localhost:8080/en.wikipedia.org/wiki/Earth + +Basic popup +* Same as SWT/Basic_popup above + +Hover over image -> should not show "retrieving data" + +### http://localhost:8080/home/wiki/Special:XowaCfg?grp=xowa.addon.popups +AJAX: b/c HTML comes from AJAX which doesn't pass through Convert_page +*/ diff --git a/res/bin/any/xowa/html/res/src/xowa/xoelem/xo.elem.js b/res/bin/any/xowa/html/res/src/xowa/xoelem/xo.elem.js index 3e57faeed..d9890f501 100644 --- a/res/bin/any/xowa/html/res/src/xowa/xoelem/xo.elem.js +++ b/res/bin/any/xowa/html/res/src/xowa/xoelem/xo.elem.js @@ -2,11 +2,6 @@ "use strict"; xo.mode_is_debug = false; - // NOTE: xo.elem is now init'd by default on all pages - // it will then be init'd a 2nd time for special pages - // ignore 2nd init else elem_add_subs will be cleared - if (xo.elem) return; - // standard creation xo.elem = new function () { this.get = function (elem_id) { @@ -60,20 +55,10 @@ this.insert_html_above = function(elem_id, html) { var elem = document.getElementById(elem_id); - elem.insertAdjacentHTML('beforebegin', html); - xo.elem.elem_add__pub(elem.parentNode); + elem.insertAdjacentHTML('beforebegin', html); + xowa.js.doc.evtElemAdd.pub(elem); }; - this.elem_add__subs = []; - this.elem_add__pub = function(elem) { - if (elem == null) elem = document; - var len = xo.elem.elem_add__subs.length; - for (var i = 0; i < len; i++) { - xo.elem.elem_add__subs[i](elem); - } - } - this.elem_add__sub = function(func) { - xo.elem.elem_add__subs.push(func); - } + this.selectbox__selected_set = function(sel_id) { try { var sel = document.getElementById(sel_id);