diff --git a/150_gfui/src/gplx/gfui/kits/swts/Swt_html.java b/150_gfui/src/gplx/gfui/kits/swts/Swt_html.java index a1ba42b5f..073a03a59 100644 --- a/150_gfui/src/gplx/gfui/kits/swts/Swt_html.java +++ b/150_gfui/src/gplx/gfui/kits/swts/Swt_html.java @@ -185,11 +185,24 @@ public class Swt_html implements Gxw_html, Swt_control, FocusListener, Gfo_evt_m , Browser_tid_mozilla = SWT.MOZILLA , Browser_tid_webkit = SWT.WEBKIT ; - private static final String URL_ABOUT_PREFIX = "about:"; - public static String StripAboutFromUrl(String url) { - return String_.Has_at_bgn(url, URL_ABOUT_PREFIX) - ? String_.Mid(url, URL_ABOUT_PREFIX.length()) - : url; + + private static final String URL_PREFIX_ABOUT = "about:"; + private static final String URL_PREFIX_BLANK = "blank"; + public static String NormalizeSwtUrl(String url) { + String rv = url; + + // 2020-09-19|ISSUE#:799|strip "about:" from url due to SWT 4.16 + rv = String_.Has_at_bgn(rv, URL_PREFIX_ABOUT) + ? String_.Mid(rv, URL_PREFIX_ABOUT.length()) + : rv; + + // 2015-06-09|webkit prefixes "about:blank" to anchors; causes TOC to fail when clicking on links; EX:about:blank#TOC1 + // 2020-09-22|removed webkit check due to SWT 4.16; `html_box.Browser_tid() == Swt_html.Browser_tid_webkit` + // still strip "blank"; note that SWT 4.16 changes anchors from "file:///#anchor" to "en.w/wiki/page/#anchor" + rv = String_.Has_at_bgn(rv, URL_PREFIX_BLANK) + ? String_.Mid(rv, URL_PREFIX_BLANK.length()) + : rv; + return rv; } } class Swt_core_cmds_html extends Swt_core__basic { @@ -238,8 +251,10 @@ class Swt_html_lnr_status implements StatusTextListener { public void Host_set(Gfo_evt_itm host) {this.host = host;} Gfo_evt_itm host; @Override public void changed(StatusTextEvent ev) { if (html_box.Kit().Kit_mode__term()) return; // shutting down raises status changed events; ignore, else SWT exception thrown; DATE:2014-05-29 - String ev_text = ev.text; - ev_text = Swt_html.StripAboutFromUrl(ev_text); // 2020-09-19|ISSUE#:799|strip "about:/" from url due to SWT 4.16 + + // 2020-09-22|ISSUE#:799|normalize URL due to SWT 4.16 + String ev_text = Swt_html.NormalizeSwtUrl(ev.text); + String load_by_url_path = html_box.Load_by_url_path(); if (load_by_url_path != null) ev_text = String_.Replace(ev_text, load_by_url_path, ""); // remove "C:/xowa/tab_1.html" // if (String_.Has(ev_text, "Loading [MathJax]")) return; // suppress MathJax messages; // NOTE: disabled for 2.1 (which no longer outputs messages to status); DATE:2013-05-03 @@ -259,24 +274,16 @@ class Swt_html_lnr_location implements LocationListener { public void Host_set(Gfo_evt_itm host) {this.host = host;} private Gfo_evt_itm host; @Override public void changed(LocationEvent arg) {Pub_evt(arg, Gfui_html.Evt_location_changed);} @Override public void changing(LocationEvent arg) {Pub_evt(arg, Gfui_html.Evt_location_changing);} - private void Pub_evt(LocationEvent arg, String evt) { - String location = arg.location; + private void Pub_evt(LocationEvent arg, String evt) { + // 2020-09-22|ISSUE#:799|normalize URL due to SWT 4.16 + String location = Swt_html.NormalizeSwtUrl(arg.location); - // location_changing fires once when page is loaded; ignore - if (String_.Eq(location, "about:blank")) { + // location_changing fires once when page is loaded -> ignore + if (String_.Eq(location, String_.Empty)) { return; } - // webkit prefixes "about:blank" to anchors; causes TOC to fail when clicking on links; EX:about:blank#TOC1; DATE:2015-06-09 - if (html_box.Browser_tid() == Swt_html.Browser_tid_webkit - && String_.Has_at_bgn(location, "about:blank")) { - location = String_.Mid(location, 11); // 11 = "about:blank".length - } - - // 2020-09-19|ISSUE#:799|strip "about:/" from url due to SWT 4.16 - location = Swt_html.StripAboutFromUrl(location); - - // navigating to file://page.html will fire location event; ignore if url mode + // navigating to file://page.html will fire location event; ignore if url mode (loading pages from file) if (html_box.Html_doc_html_load_tid() == Gxw_html_load_tid_.Tid_url && String_.Has_at_bgn(location, "file:") && String_.Has_at_end(location, ".html") diff --git a/400_xowa/src/gplx/xowa/guis/history/Xog_history_mgr.java b/400_xowa/src/gplx/xowa/guis/history/Xog_history_mgr.java index 8e488a3d3..ec2b03ef8 100644 --- a/400_xowa/src/gplx/xowa/guis/history/Xog_history_mgr.java +++ b/400_xowa/src/gplx/xowa/guis/history/Xog_history_mgr.java @@ -1,6 +1,6 @@ /* XOWA: the XOWA Offline Wiki Application -Copyright (C) 2012-2017 gnosygnu@gmail.com +Copyright (C) 2012-2020 gnosygnu@gmail.com XOWA is licensed under the terms of the General Public License (GPL) Version 3, or alternatively under the terms of the Apache License Version 2.0. @@ -13,63 +13,89 @@ The terms of each license can be found in the source code repository: GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt */ -package gplx.xowa.guis.history; import gplx.*; import gplx.xowa.*; import gplx.xowa.guis.*; -public class Xog_history_mgr { - private final Ordered_hash hash = Ordered_hash_.New_bry(); private final Xog_history_stack stack = new Xog_history_stack(); - public int Count() {return hash.Count();} - public Xoae_page Cur_page(Xowe_wiki wiki) {return Get_or_fetch(wiki, stack.Cur_itm());} - public Xoae_page Go_bwd(Xowe_wiki wiki) {return Go_by_dir(wiki, Bool_.N);} - public Xoae_page Go_fwd(Xowe_wiki wiki) {return Go_by_dir(wiki, Bool_.Y);} - public Xoae_page Go_by_dir(Xowe_wiki wiki, boolean fwd) { - Xog_history_itm itm = fwd ? stack.Go_fwd() : stack.Go_bwd(); - if (itm == Xog_history_itm.Null) return Xoae_page.Empty; - Xoae_page rv = Get_or_fetch(wiki, itm); - byte[] anch_key = itm.Anch(); - rv.Url().Anch_bry_(anch_key); // must override anchor as it may be different for cached page - rv.Html_data().Bmk_pos_(itm.Bmk_pos()); - return rv; - } - public void Add(Xoae_page page) { - Xog_history_itm new_itm = Xog_history_mgr.new_(page); - stack.Add(new_itm); - byte[] page_key = Build_page_key(page); - if (!hash.Has(page_key)) - hash.Add(page_key, page); - } - public void Update_html_doc_pos(Xoae_page page, byte history_nav_type) { - Xog_history_itm itm = Get_recent(page, history_nav_type); - if (itm != null) itm.Bmk_pos_(page.Html_data().Bmk_pos()); - } - private Xog_history_itm Get_recent(Xoae_page page, byte history_nav_type) { - int pos = -1; - int list_pos = stack.Cur_pos(); - switch (history_nav_type) { - case Xog_history_stack.Nav_fwd: pos = list_pos - 1; break; - case Xog_history_stack.Nav_bwd: pos = list_pos + 1; break; - case Xog_history_stack.Nav_by_anchor: pos = list_pos; break; - } - if (pos < 0 || pos >= stack.Len()) return null; - Xog_history_itm recent = stack.Get_at(pos); - Xog_history_itm page_itm = Xog_history_mgr.new_(page); - return page_itm.Eq_wo_bmk_pos(recent) ? recent : null; // check that recent page actually matches current; DATE:2014-05-10 - } - private Xoae_page Get_or_fetch(Xowe_wiki wiki, Xog_history_itm itm) { - byte[] page_key = Build_page_key(itm.Wiki(), itm.Page(), itm.Qarg()); - Xoae_page rv = (Xoae_page)hash.Get_by(page_key); - if (rv != null) return rv; - Xoa_ttl ttl = Xoa_ttl.Parse(wiki, itm.Page()); - return wiki.Data_mgr().Load_page_by_ttl(ttl); - } - private static byte[] Build_page_key(Xoae_page page) {return Build_page_key(page.Wiki().Domain_bry(), page.Ttl().Full_url(), page.Url().Qargs_mgr().To_bry());} - private static byte[] Build_page_key(byte[] wiki_key, byte[] page_key, byte[] args_key) {return Bry_.Add_w_dlm(Byte_ascii.Pipe, wiki_key, page_key, args_key);} - public static Xog_history_itm new_(Xoae_page pg) { - byte[] wiki = pg.Wiki().Domain_bry(); - byte[] page = pg.Ttl().Full_url(); // get page_name only (no anchor; no query args) - byte[] anch = pg.Url().Anch_bry(); - byte[] qarg = pg.Url().Qargs_mgr().To_bry(); - boolean redirect_force = pg.Url().Qargs_mgr().Match(Xoa_url_.Qarg__redirect, Xoa_url_.Qarg__redirect__no); - String bmk_pos = pg.Html_data().Bmk_pos(); - if (bmk_pos == null) bmk_pos = Xog_history_itm.Html_doc_pos_toc; // never allow null doc_pos; set to top - return new Xog_history_itm(wiki, page, anch, qarg, redirect_force, bmk_pos); - } -} +package gplx.xowa.guis.history; + +import gplx.Bool_; +import gplx.Bry_; +import gplx.Byte_ascii; +import gplx.Ordered_hash; +import gplx.Ordered_hash_; +import gplx.xowa.Xoa_ttl; +import gplx.xowa.Xoa_url; +import gplx.xowa.Xoa_url_; +import gplx.xowa.Xoae_page; +import gplx.xowa.Xowe_wiki; + +public class Xog_history_mgr { + private final Ordered_hash hash = Ordered_hash_.New_bry(); private final Xog_history_stack stack = new Xog_history_stack(); + public int Count() {return hash.Count();} + public Xoae_page Cur_page(Xowe_wiki wiki) {return Get_or_fetch(wiki, stack.Cur_itm());} + public Xoae_page Go_bwd(Xowe_wiki wiki) {return Go_by_dir(wiki, Bool_.N);} + public Xoae_page Go_fwd(Xowe_wiki wiki) {return Go_by_dir(wiki, Bool_.Y);} + public Xoae_page Go_by_dir(Xowe_wiki wiki, boolean fwd) { + Xog_history_itm itm = fwd ? stack.Go_fwd() : stack.Go_bwd(); + if (itm == Xog_history_itm.Null) return Xoae_page.Empty; + Xoae_page rv = Get_or_fetch(wiki, itm); + byte[] anch_key = itm.Anch(); + rv.Url().Anch_bry_(anch_key); // must override anchor as it may be different for cached page + rv.Html_data().Bmk_pos_(itm.Bmk_pos()); + return rv; + } + public void Add(Xoae_page page) { + this.Add(page, Xog_history_mgr.new_(page)); + } + public void Add(Xoae_page page, Xoa_url url) { + this.Add(page, Xog_history_mgr.new_(url, page.Html_data().Bmk_pos())); + } + private void Add(Xoae_page page, Xog_history_itm new_itm) { + stack.Add(new_itm); + byte[] page_key = Build_page_key(page); + if (!hash.Has(page_key)) + hash.Add(page_key, page); + } + public void Update_html_doc_pos(Xoae_page page, byte history_nav_type) { + Xog_history_itm itm = Get_recent(page, history_nav_type); + if (itm != null) itm.Bmk_pos_(page.Html_data().Bmk_pos()); + } + private Xog_history_itm Get_recent(Xoae_page page, byte history_nav_type) { + int pos = -1; + int list_pos = stack.Cur_pos(); + switch (history_nav_type) { + case Xog_history_stack.Nav_fwd: pos = list_pos - 1; break; + case Xog_history_stack.Nav_bwd: pos = list_pos + 1; break; + case Xog_history_stack.Nav_by_anchor: pos = list_pos; break; + } + if (pos < 0 || pos >= stack.Len()) return null; + Xog_history_itm recent = stack.Get_at(pos); + Xog_history_itm page_itm = Xog_history_mgr.new_(page); + return page_itm.Eq_wo_bmk_pos(recent) ? recent : null; // check that recent page actually matches current; DATE:2014-05-10 + } + private Xoae_page Get_or_fetch(Xowe_wiki wiki, Xog_history_itm itm) { + byte[] page_key = Build_page_key(itm.Wiki(), itm.Page(), itm.Qarg()); + Xoae_page rv = (Xoae_page)hash.Get_by(page_key); + if (rv != null) return rv; + Xoa_ttl ttl = Xoa_ttl.Parse(wiki, itm.Page()); + return wiki.Data_mgr().Load_page_by_ttl(ttl); + } + private static byte[] Build_page_key(Xoae_page page) {return Build_page_key(page.Wiki().Domain_bry(), page.Ttl().Full_url(), page.Url().Qargs_mgr().To_bry());} + private static byte[] Build_page_key(byte[] wiki_key, byte[] page_key, byte[] args_key) {return Bry_.Add_w_dlm(Byte_ascii.Pipe, wiki_key, page_key, args_key);} + public static Xog_history_itm new_(Xoae_page pg) { + byte[] wiki = pg.Wiki().Domain_bry(); + byte[] page = pg.Ttl().Full_url(); // get page_name only (no anchor; no query args) + byte[] anch = pg.Url().Anch_bry(); + byte[] qarg = pg.Url().Qargs_mgr().To_bry(); + boolean redirect_force = pg.Url().Qargs_mgr().Match(Xoa_url_.Qarg__redirect, Xoa_url_.Qarg__redirect__no); + String bmk_pos = pg.Html_data().Bmk_pos(); + if (bmk_pos == null) bmk_pos = Xog_history_itm.Html_doc_pos_toc; // never allow null doc_pos; set to top + return new Xog_history_itm(wiki, page, anch, qarg, redirect_force, bmk_pos); + } + public static Xog_history_itm new_(Xoa_url url, String bmk_pos) { + byte[] wiki = url.Wiki_bry(); + byte[] page = url.Page_bry(); + byte[] anch = url.Anch_bry(); + byte[] qarg = url.Qargs_mgr().To_bry(); + boolean redirect_force = url.Qargs_mgr().Match(Xoa_url_.Qarg__redirect, Xoa_url_.Qarg__redirect__no); + if (bmk_pos == null) bmk_pos = Xog_history_itm.Html_doc_pos_toc; // never allow null doc_pos; set to top + return new Xog_history_itm(wiki, page, anch, qarg, redirect_force, bmk_pos); + } +} diff --git a/400_xowa/src/gplx/xowa/guis/urls/Xog_url_wkr.java b/400_xowa/src/gplx/xowa/guis/urls/Xog_url_wkr.java index 0ba06891f..c15861939 100644 --- a/400_xowa/src/gplx/xowa/guis/urls/Xog_url_wkr.java +++ b/400_xowa/src/gplx/xowa/guis/urls/Xog_url_wkr.java @@ -1,6 +1,6 @@ /* XOWA: the XOWA Offline Wiki Application -Copyright (C) 2012-2017 gnosygnu@gmail.com +Copyright (C) 2012-2020 gnosygnu@gmail.com XOWA is licensed under the terms of the General Public License (GPL) Version 3, or alternatively under the terms of the Apache License Version 2.0. @@ -13,67 +13,86 @@ The terms of each license can be found in the source code repository: GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt */ -package gplx.xowa.guis.urls; import gplx.*; import gplx.xowa.*; import gplx.xowa.guis.*; -import gplx.core.net.*; import gplx.core.net.qargs.*; import gplx.core.envs.*; -import gplx.gfui.controls.standards.*; -import gplx.xowa.files.*; import gplx.xowa.files.repos.*; import gplx.xowa.files.origs.*; -import gplx.langs.htmls.encoders.*; import gplx.xowa.htmls.hrefs.*; import gplx.xowa.htmls.doms.*; -import gplx.xowa.guis.views.*; -public class Xog_url_wkr { - private final Xoa_url tmp_url = Xoa_url.blank(); - private Xoae_app app; private Xog_win_itm win; private Xowe_wiki wiki; private Xoae_page page; - public Xoa_url Parse(Xog_win_itm win, String href_str) { - if (href_str == null) return tmp_url; // text is not link; return; - byte[] href_bry = Bry_.new_u8(href_str); - this.win = win; this.app = win.App(); - this.page = win.Active_page(); - this.wiki = win.Active_tab().Wiki(); - app.Html__href_parser().Parse_as_url(tmp_url, href_bry, wiki, page.Ttl().Page_url()); - return tmp_url; - } - public void Init(Xowe_wiki wiki) { // TEST: - this.wiki = wiki; - } - public Xoa_url Exec_url(Xoa_url url) { - switch (url.Tid()) { - case Xoa_url_.Tid_unknown: return Xoa_url.Null; // unknown; return null which will become a noop - case Xoa_url_.Tid_inet: return Exec_url_http(app); // http://site.org - case Xoa_url_.Tid_anch: return Exec_url_anchor(win); // #anchor - case Xoa_url_.Tid_xcmd: return Exec_url_xowa(app); // xowa:app.version or /xcmd/app.version - case Xoa_url_.Tid_file: return Exec_url_file(app, wiki, page, win, url.Raw()); // file:///xowa/A.png - case Xoa_url_.Tid_page: return Exec_url_page(wiki, url.Orig()); // /wiki/Page - default: throw Err_.new_unhandled(url.Tid()); - } - } - private Xoa_url Exec_url_xowa(Xoae_app app) { // EX: xowa:app.version - // NOTE: must catch exception else it will bubble to SWT browser and raise secondary exception of xowa is not a registered protocol - try {app.Gfs_mgr().Run_str(String_.new_u8(tmp_url.Page_bry()));} - catch (Exception e) {app.Gui_mgr().Kit().Ask_ok("", "", Err_.Message_gplx_full(e));} - return Rslt_handled; - } - private Xoa_url Exec_url_http(Xoae_app app) { // EX: http://a.org - app.Prog_mgr().Exec_view_web(tmp_url.Raw()); - return Rslt_handled; - } - private Xoa_url Exec_url_anchor(Xog_win_itm win) { // EX: #anchor - win.Active_html_itm().Scroll_page_by_id_gui(tmp_url.Anch_str()); // NOTE: was originally directly; changed to call on thread; DATE:2014-05-03 - return Rslt_handled; - } - private Xoa_url Exec_url_file(Xoae_app app, Xowe_wiki cur_wiki, Xoae_page page, Xog_win_itm win, byte[] href_bry) { // EX: file:///xowa/A.png - Xog_url_wkr__file wkr = new Xog_url_wkr__file(app, cur_wiki, page); - wkr.Extract_data(win.Active_html_box().Html_js_eval_proc_as_str(Xog_js_procs.Doc__root_html_get), href_bry); - wkr.Download_and_run(); - return Rslt_handled; - } - private Xoa_url Exec_url_page(Xowe_wiki wiki, byte[] href_bry) { // EX: "Page"; "/wiki/Page"; // rewritten; DATE:2014-01-19 - return wiki.Utl__url_parser().Parse(href_bry); - } - public static Xoa_url Rslt_handled = null; - public static Xoa_url Exec_url(Xog_win_itm win, String href_str) { - Xog_url_wkr url_wkr = new Xog_url_wkr(); - Xoa_url url = url_wkr.Parse(win, href_str); - return url_wkr.Exec_url(url); - } - public static void Get_href_url() { - } -} +package gplx.xowa.guis.urls; + +import gplx.Bry_; +import gplx.Err_; +import gplx.String_; +import gplx.xowa.Xoa_ttl; +import gplx.xowa.Xoa_url; +import gplx.xowa.Xoa_url_; +import gplx.xowa.Xoae_app; +import gplx.xowa.Xoae_page; +import gplx.xowa.Xowe_wiki; +import gplx.xowa.guis.views.Xog_js_procs; +import gplx.xowa.guis.views.Xog_win_itm; + +public class Xog_url_wkr { + private final Xoa_url tmp_url = Xoa_url.blank(); + private Xoae_app app; private Xog_win_itm win; private Xowe_wiki wiki; private Xoae_page page; + public Xoa_url Parse(Xog_win_itm win, String href_str) { + if (href_str == null) return tmp_url; // text is not link; return; + byte[] href_bry = Bry_.new_u8(href_str); + this.win = win; this.app = win.App(); + this.page = win.Active_page(); + this.wiki = win.Active_tab().Wiki(); + app.Html__href_parser().Parse_as_url(tmp_url, href_bry, wiki, page.Ttl().Page_url()); + return tmp_url; + } + public void Init(Xowe_wiki wiki) { // TEST: + this.wiki = wiki; + } + public Xoa_url Exec_url(Xoa_url url) { + switch (url.Tid()) { + case Xoa_url_.Tid_unknown: return Xoa_url.Null; // unknown; return null which will become a noop + case Xoa_url_.Tid_inet: return Exec_url_http(app); // http://site.org + case Xoa_url_.Tid_anch: return Exec_url_anchor(win); // #anchor + case Xoa_url_.Tid_xcmd: return Exec_url_xowa(app); // xowa:app.version or /xcmd/app.version + case Xoa_url_.Tid_file: return Exec_url_file(app, wiki, page, win, url.Raw()); // file:///xowa/A.png + case Xoa_url_.Tid_page: return Exec_url_page(wiki, url.Orig()); // /wiki/Page + default: throw Err_.new_unhandled(url.Tid()); + } + } + private Xoa_url Exec_url_xowa(Xoae_app app) { // EX: xowa:app.version + // NOTE: must catch exception else it will bubble to SWT browser and raise secondary exception of xowa is not a registered protocol + try {app.Gfs_mgr().Run_str(String_.new_u8(tmp_url.Page_bry()));} + catch (Exception e) {app.Gui_mgr().Kit().Ask_ok("", "", Err_.Message_gplx_full(e));} + return Rslt_handled; + } + private Xoa_url Exec_url_http(Xoae_app app) { // EX: http://a.org + app.Prog_mgr().Exec_view_web(tmp_url.Raw()); + return Rslt_handled; + } + private Xoa_url Exec_url_anchor(Xog_win_itm win) { // EX: #anchor + // 2014-05-03|was originally called directly; changed to call on thread + win.Active_html_itm().Scroll_page_by_id_gui(tmp_url.Anch_str()); + + // 2020-09-22|ISSUE#:799|SWT 4.16 changes anchors from "file:///#anchor" to "en.w/wiki/page/#anchor" + if (app.Mode().Tid_is_gui()) { + // manually update url box + win.Gui_mgr().Browser_win().Url_box().Text_(tmp_url.To_str()); + + // manually register url; note that tmp_url needs to be passed b/c page.Url() doesn't have #anchor info + win.Tab_mgr().Active_tab().History_mgr().Add(page, tmp_url); + } + + return Rslt_handled; + } + private Xoa_url Exec_url_file(Xoae_app app, Xowe_wiki cur_wiki, Xoae_page page, Xog_win_itm win, byte[] href_bry) { // EX: file:///xowa/A.png + Xog_url_wkr__file wkr = new Xog_url_wkr__file(app, cur_wiki, page); + wkr.Extract_data(win.Active_html_box().Html_js_eval_proc_as_str(Xog_js_procs.Doc__root_html_get), href_bry); + wkr.Download_and_run(); + return Rslt_handled; + } + private Xoa_url Exec_url_page(Xowe_wiki wiki, byte[] href_bry) { // EX: "Page"; "/wiki/Page"; // rewritten; DATE:2014-01-19 + return wiki.Utl__url_parser().Parse(href_bry); + } + public static Xoa_url Rslt_handled = null; + public static Xoa_url Exec_url(Xog_win_itm win, String href_str) { + Xog_url_wkr url_wkr = new Xog_url_wkr(); + Xoa_url url = url_wkr.Parse(win, href_str); + return url_wkr.Exec_url(url); + } + public static void Get_href_url() { + } +}