mirror of
https://github.com/gnosygnu/xowa.git
synced 2026-03-02 03:49:30 +00:00
HTTP Server: Support popups [#264]
This commit is contained in:
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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<textarea id=\"key1\" data-xocfg-key=\"key1\" data-xocfg-type=\"memo\" accesskey=\"d\" class=\"xocfg_data__memo html_cls1\" key1=val1>"
|
||||
fxt.Val_("data1")
|
||||
.Test__Build_html("\n<textarea id=\"key1\" data-xocfg-key=\"key1\" data-xocfg-type=\"memo\" accesskey=\"d\" class=\"xocfg_data__memo html_cls1\" key1=val1>"
|
||||
+ "data1"
|
||||
+ "</textarea>");
|
||||
|
||||
// xml-tags
|
||||
fxt.Val_("<pre>~{page_text}</pre>").Test__Build_html("\n<textarea id=\"key1\" data-xocfg-key=\"key1\" data-xocfg-type=\"memo\" accesskey=\"d\" class=\"xocfg_data__memo html_cls1\" key1=val1>"
|
||||
fxt.Val_("<pre>~{page_text}</pre>")
|
||||
.Test__Build_html("\n<textarea id=\"key1\" data-xocfg-key=\"key1\" data-xocfg-type=\"memo\" accesskey=\"d\" class=\"xocfg_data__memo html_cls1\" key1=val1>"
|
||||
+ "<pre>~{page_text}</pre>"
|
||||
+ "</textarea>");
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
@@ -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("<a "), anch_repl_bry = Bry_.new_a7("<a tabindex=\"-1\" ");
|
||||
byte[] anch_find_bry = Bry_.new_a7("<a "), anch_repl_bry = Bry_.new_a7(" tabindex=\"-1\"");
|
||||
Bry_bfr tmp_bfr = Bry_bfr_.New();
|
||||
for (Xocfg_maint_nde nde : ndes) {
|
||||
// parse help to html
|
||||
parser_mgr.Main().Parse_text_to_html(tmp_bfr, parser_mgr.Ctx(), parser_mgr.Ctx().Page(), true, Bry_.new_u8(nde.Help()));
|
||||
byte[] help = tmp_bfr.To_bry_and_clear();
|
||||
help = Bry_.Replace(help, anch_find_bry, anch_repl_bry); // replace "<a " with "<a tabindex=-1 " else tabbing will go to hidden anchors in help text
|
||||
|
||||
// add "tabindex=-1" to "<a>" tages else tabbing will go to hidden anchors in help text
|
||||
int help_pos = 0;
|
||||
while (true) {
|
||||
int a_bgn = Bry_find_.Find_fwd(help, anch_find_bry, help_pos, help.length);
|
||||
if (a_bgn == Bry_find_.Not_found) break;
|
||||
int a_end = Bry_find_.Find_fwd(help, Byte_ascii.Angle_end, a_bgn, help.length);
|
||||
if (a_end == Bry_find_.Not_found) {
|
||||
Gfo_usr_dlg_.Instance.Warn_many("", "", "could not find closing > after <a", "src", help);
|
||||
break;
|
||||
}
|
||||
|
||||
tmp_bfr.Add_mid(help, 0, a_end);
|
||||
tmp_bfr.Add(anch_repl_bry);
|
||||
tmp_bfr.Add_mid(help, a_end, help.length);
|
||||
help = tmp_bfr.To_bry_and_clear();
|
||||
help_pos = a_end;
|
||||
}
|
||||
|
||||
// do insert
|
||||
if (nde.Type_is_grp()) {
|
||||
|
||||
@@ -18,7 +18,6 @@ public class Xoa_thread_ {
|
||||
public static final String
|
||||
Key_page_async = "xowa.page.async"
|
||||
, Key_page_redlink = "xowa.page.redlink"
|
||||
, Key_page_popup = "xowa.page.popup"
|
||||
, Key_http_server_main = "xowa.http_server.main"
|
||||
, Key_bldr_download = "xowa.bldr.download"
|
||||
, Key_special_search_db = "xowa.special.search.db"
|
||||
|
||||
@@ -91,7 +91,7 @@ public class Http_server_mgr implements Gfo_invk {
|
||||
String cmd = url_converter.Decode_str(url_encoded_str);
|
||||
app.Gfs_mgr().Run_str(cmd);
|
||||
}
|
||||
public String Parse_page_to_html(Http_data__client data__client, byte[] wiki_domain, byte[] ttl_bry, byte mode) {
|
||||
public String Parse_page_to_html(Http_data__client data__client, byte[] wiki_domain, byte[] ttl_bry, byte mode, boolean popup_enabled, String popup_mode, String popup_id) {
|
||||
synchronized (thread_lock) {
|
||||
// create a shim gui to automatically handle default XOWA gui JS calls
|
||||
if (init_gui_needed) {
|
||||
@@ -102,7 +102,7 @@ public class Http_server_mgr implements Gfo_invk {
|
||||
// get the wiki
|
||||
Xowe_wiki wiki = (Xowe_wiki)app.Wiki_mgr().Get_by_or_make_init_y(wiki_domain); // assert init for Main_Page; EX:click zh.w on wiki sidebar; DATE:2015-07-19
|
||||
if (Runtime_.Memory_total() > Io_mgr.Len_gb) Xowe_wiki_.Rls_mem(wiki, true); // release memory at 1 GB; DATE:2015-09-11
|
||||
|
||||
|
||||
// get the url / ttl
|
||||
if (Bry_.Len_eq_0(ttl_bry)) ttl_bry = wiki.Props().Main_page();
|
||||
Xoa_url url = wiki.Utl__url_parser().Parse(ttl_bry);
|
||||
@@ -119,22 +119,31 @@ public class Http_server_mgr implements Gfo_invk {
|
||||
page.Html_data().Head_mgr().Itm__server().Init_by_http(data__client).Enabled_y_();
|
||||
|
||||
// generate html
|
||||
String rv = String_.new_u8(wiki.Html_mgr().Page_wtr_mgr().Gen(page, mode)); // NOTE: must generate HTML now in order for "wait" and "async_server" to work with text_dbs; DATE:2016-07-10
|
||||
boolean rebuild_html = false;
|
||||
switch (retrieve_mode) {
|
||||
case File_retrieve_mode.Mode_skip: // noop
|
||||
break;
|
||||
case File_retrieve_mode.Mode_async_server:
|
||||
rebuild_html = true;
|
||||
app.Gui_mgr().Browser_win().Page__async__bgn(tab);
|
||||
break;
|
||||
case File_retrieve_mode.Mode_wait:
|
||||
rebuild_html = true;
|
||||
gplx.xowa.guis.views.Xog_async_wkr.Async(page, tab.Html_itm());
|
||||
page = wiki.Page_mgr().Load_page(url, ttl, tab); // HACK: fetch page again so that HTML will now include img data
|
||||
break;
|
||||
String rv = null;
|
||||
if (popup_enabled) {
|
||||
if (String_.Eq(popup_mode, "more"))
|
||||
rv = wiki.Html_mgr().Head_mgr().Popup_mgr().Show_more(popup_id);
|
||||
else
|
||||
rv = wiki.Html_mgr().Head_mgr().Popup_mgr().Show_init(popup_id, ttl_bry, ttl_bry);
|
||||
}
|
||||
else {
|
||||
rv = String_.new_u8(wiki.Html_mgr().Page_wtr_mgr().Gen(page, mode)); // NOTE: must generate HTML now in order for "wait" and "async_server" to work with text_dbs; DATE:2016-07-10
|
||||
boolean rebuild_html = false;
|
||||
switch (retrieve_mode) {
|
||||
case File_retrieve_mode.Mode_skip: // noop
|
||||
break;
|
||||
case File_retrieve_mode.Mode_async_server:
|
||||
rebuild_html = true;
|
||||
app.Gui_mgr().Browser_win().Page__async__bgn(tab);
|
||||
break;
|
||||
case File_retrieve_mode.Mode_wait:
|
||||
rebuild_html = true;
|
||||
gplx.xowa.guis.views.Xog_async_wkr.Async(page, tab.Html_itm());
|
||||
page = wiki.Page_mgr().Load_page(url, ttl, tab); // HACK: fetch page again so that HTML will now include img data
|
||||
break;
|
||||
}
|
||||
if (rebuild_html) rv = String_.new_u8(wiki.Html_mgr().Page_wtr_mgr().Gen(page, mode));
|
||||
}
|
||||
if (rebuild_html) rv = String_.new_u8(wiki.Html_mgr().Page_wtr_mgr().Gen(page, mode));
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ class Http_server_wkr implements Gfo_invk {
|
||||
private final Bry_bfr tmp_bfr = Bry_bfr_.New_w_size(64);
|
||||
private Socket_adp socket;
|
||||
private Http_data__client data__client;
|
||||
private final Gfo_url_parser url_parser = new Gfo_url_parser();
|
||||
public Http_server_wkr(Http_server_mgr server_mgr, int uid){
|
||||
this.server_mgr = server_mgr; this.uid = uid;
|
||||
this.app = server_mgr.App(); this.server_wtr = server_mgr.Server_wtr(); this.url_encoder = server_mgr.Encoder();
|
||||
@@ -105,7 +106,7 @@ class Http_server_wkr implements Gfo_invk {
|
||||
page_html = url_parser.Err_msg();
|
||||
}
|
||||
else {
|
||||
page_html = app.Http_server().Parse_page_to_html(data__client, url_parser.Wiki(), url_parser.Page(), url_parser.Action());
|
||||
page_html = app.Http_server().Parse_page_to_html(data__client, url_parser.Wiki(), url_parser.Page(), url_parser.Action(), url_parser.Popup(), url_parser.Popup_mode(), url_parser.Popup_id());
|
||||
page_html = Convert_page(page_html, root_dir_http, String_.new_u8(url_parser.Wiki()));
|
||||
}
|
||||
Xosrv_http_wkr_.Write_response_as_html(client_wtr, Bool_.N, page_html);
|
||||
|
||||
@@ -14,6 +14,7 @@ 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.apps.servers.http; import gplx.*; import gplx.xowa.*; import gplx.xowa.apps.*; import gplx.xowa.apps.servers.*;
|
||||
import gplx.core.net.*; import gplx.core.net.qargs.*;
|
||||
import gplx.langs.htmls.encoders.*;
|
||||
import gplx.xowa.htmls.hrefs.*;
|
||||
import gplx.xowa.wikis.pages.*;
|
||||
@@ -25,13 +26,17 @@ class Http_url_parser {
|
||||
public byte[] Wiki() {return wiki;} public Http_url_parser Wiki_(String v) {this.wiki = Bry_.new_u8(v); return this;} private byte[] wiki;
|
||||
public byte[] Page() {return page;} public Http_url_parser Page_(String v) {this.page = Bry_.new_u8(v); return this;} private byte[] page;
|
||||
public byte Action() {return action;} public Http_url_parser Action_(byte v) {this.action = v; return this;} private byte action;
|
||||
public String Popup_mode() {return popup_mode;} public Http_url_parser Popup_mode_(String v) {this.popup_mode = v; return this;} private String popup_mode;
|
||||
public boolean Popup() {return popup;} public Http_url_parser Popup_(boolean v) {this.popup = v; return this;} private boolean popup;
|
||||
public String Popup_id() {return popup_id;} public Http_url_parser Popup_id_(String v) {this.popup_id = v; return this;} private String popup_id;
|
||||
public String Err_msg() {return err_msg;} public Http_url_parser Err_msg_(String v) {this.err_msg = v; return this;} private String err_msg;
|
||||
|
||||
public String To_str() {
|
||||
Bry_bfr bfr = Bry_bfr_.New();
|
||||
bfr.Add_str_a7("wiki=").Add_safe(wiki).Add_byte_nl();
|
||||
bfr.Add_str_a7("page=").Add_safe(page).Add_byte_nl();
|
||||
bfr.Add_str_a7("action=").Add_byte(action).Add_byte_nl();
|
||||
bfr.Add_str_a7("action=").Add_byte_variable(action).Add_byte_nl();
|
||||
bfr.Add_str_a7("popup=").Add_yn(popup).Add_byte_nl();
|
||||
bfr.Add_str_a7("err_msg=").Add_str_u8_null(err_msg).Add_byte_nl();
|
||||
return bfr.To_str_and_clear();
|
||||
}
|
||||
@@ -40,11 +45,45 @@ class Http_url_parser {
|
||||
public boolean Parse(byte[] url) {
|
||||
try {
|
||||
// initial validations
|
||||
if (url == null) return Fail(url, "invalid url; url is null");
|
||||
if (url == null) return Fail(null, "invalid url; url is null");
|
||||
int url_len = url.length;
|
||||
if (url_len == 0) return Fail(url, "invalid url; url is empty");
|
||||
if (url_len == 0) return Fail(null, "invalid url; url is empty");
|
||||
if (url[0] != Byte_ascii.Slash) return Fail(url, "invalid url; must start with '/'");
|
||||
|
||||
Gfo_url_parser url_parser = new Gfo_url_parser();
|
||||
Gfo_url url_obj = url_parser.Parse(url);
|
||||
this.wiki = url_obj.Segs()[0];
|
||||
|
||||
int segs_len = url_obj.Segs().length;
|
||||
if (segs_len > 1) {
|
||||
byte[] x = url_obj.Segs()[2];
|
||||
if (segs_len > 2) {
|
||||
Bry_bfr bfr = Bry_bfr_.New();
|
||||
for (int i = 2; i < segs_len; i++) {
|
||||
if (i != 2) bfr.Add_byte_slash();
|
||||
bfr.Add(url_obj.Segs()[i]);
|
||||
}
|
||||
x = bfr.To_bry_and_clear();
|
||||
}
|
||||
this.page = x;
|
||||
}
|
||||
|
||||
Gfo_qarg_mgr qarg_mgr = new Gfo_qarg_mgr().Init(url_obj.Qargs());
|
||||
byte[] action_val = qarg_mgr.Read_bry_or("action", Bry_.Empty);
|
||||
if (Bry_.Eq(action_val, Xoa_url_.Qarg__action__read))
|
||||
this.action = Xopg_page_.Tid_read;
|
||||
else if (Bry_.Eq(action_val, Xoa_url_.Qarg__action__edit))
|
||||
this.action = Xopg_page_.Tid_edit;
|
||||
else if (Bry_.Eq(action_val, Xoa_url_.Qarg__action__html))
|
||||
this.action = Xopg_page_.Tid_html;
|
||||
else if (Bry_.Eq(action_val, Qarg__action__popup)) {
|
||||
this.popup = true;
|
||||
this.popup_id = qarg_mgr.Read_str_or_null(Bry_.new_a7("popup_id"));
|
||||
this.popup_mode = qarg_mgr.Read_str_or_null(Bry_.new_a7("popup_mode"));
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
// get wiki
|
||||
int wiki_bgn = 1; // skip initial "/"
|
||||
int wiki_end = Bry_find_.Find_fwd_or(url, Byte_ascii.Slash, wiki_bgn, url_len, url_len);
|
||||
@@ -73,13 +112,16 @@ class Http_url_parser {
|
||||
this.action = Xopg_page_.Tid_edit;
|
||||
else if (Bry_.Eq(url, action_val_bgn, action_val_end, Xoa_url_.Qarg__action__html))
|
||||
this.action = Xopg_page_.Tid_html;
|
||||
else
|
||||
else if (Bry_.Eq(url, action_val_bgn, action_val_end, Qarg__action__popup))
|
||||
this.popup = true;
|
||||
else // no "?action=" found; ignore "?"; EX: "A?action=unknown"
|
||||
trim_page = false;
|
||||
if (trim_page)
|
||||
page_end = action_key_bgn;
|
||||
}
|
||||
|
||||
this.page = url_encoder.Decode(Bry_.Mid(url, page_bgn, page_end));
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
catch (Exception e) {
|
||||
@@ -90,10 +132,13 @@ class Http_url_parser {
|
||||
private boolean Fail(byte[] url, String err_msg) {
|
||||
this.wiki = null;
|
||||
this.page = null;
|
||||
this.err_msg = err_msg + "; url=" + String_.new_u8(url);
|
||||
this.err_msg = err_msg;
|
||||
if (url != null)
|
||||
this.err_msg += "; url=" + String_.new_u8(url);
|
||||
return false;
|
||||
}
|
||||
private static final byte[]
|
||||
Qarg__action__frag = Bry_.Add(Byte_ascii.Question_bry, Xoa_url_.Qarg__action, Byte_ascii.Eq_bry) // "?action="
|
||||
, Qarg__action__popup = Bry_.new_a7("popup")
|
||||
;
|
||||
}
|
||||
|
||||
@@ -38,20 +38,24 @@ public class Http_url_parser_tst {
|
||||
// action=html
|
||||
fxt.Test__parse("/en.wikipedia.org/wiki/Page_1?action=html", fxt.Make().Wiki_("en.wikipedia.org").Page_("Page_1").Action_(Xopg_page_.Tid_html));
|
||||
|
||||
// action=popup
|
||||
fxt.Test__parse("/en.wikipedia.org/wiki/Page_1?action=popup", fxt.Make().Wiki_("en.wikipedia.org").Page_("Page_1").Popup_(true));
|
||||
|
||||
// action=N/A
|
||||
fxt.Test__parse("/en.wikipedia.org/wiki/Page_1?action=a", fxt.Make().Wiki_("en.wikipedia.org").Page_("Page_1?action=a"));
|
||||
fxt.Test__parse("/en.wikipedia.org/wiki/Page_1?action=a", fxt.Make().Wiki_("en.wikipedia.org").Page_("Page_1"));
|
||||
|
||||
// fail: null
|
||||
fxt.Test__parse(null, fxt.Make().Err_msg_("invalid url; url is null; url="));
|
||||
fxt.Test__parse(null, fxt.Make().Err_msg_("invalid url; url is null"));
|
||||
|
||||
// fail: empty
|
||||
fxt.Test__parse("", fxt.Make().Err_msg_("invalid url; url is empty; url="));
|
||||
fxt.Test__parse("", fxt.Make().Err_msg_("invalid url; url is empty"));
|
||||
|
||||
// fail: missing '/' at start
|
||||
fxt.Test__parse("en.wikipedia.org", fxt.Make().Err_msg_("invalid url; must start with '/'; url=en.wikipedia.org"));
|
||||
|
||||
/*
|
||||
// fail: missing '/wiki/'
|
||||
fxt.Test__parse("/en.wikipedia.org/Page_1", fxt.Make().Err_msg_("invalid url; must have '/wiki/' after wiki_domain; url=/en.wikipedia.org/Page_1"));
|
||||
*/
|
||||
}
|
||||
}
|
||||
class Http_url_parser_fxt {
|
||||
|
||||
@@ -142,8 +142,11 @@ public class Xog_tab_itm implements Gfo_invk {
|
||||
}
|
||||
Tab_name_(new_tab_name);
|
||||
usr_dlg.Prog_one("", "", "loading: ~{0}", String_.new_u8(ttl.Raw()));
|
||||
if (wiki.Html_mgr().Head_mgr().Popup_mgr().Enabled())
|
||||
this.Html_box().Html_js_eval_script("if (window.xowa_popups_hide_all != null) window.xowa_popups_hide_all();"); // should be more configurable; DATE:2014-07-09
|
||||
|
||||
// DELETE: no longer seems needed; popups always disappear when navigating to new page; DATE:2018-11-11
|
||||
// if (wiki.Html_mgr().Head_mgr().Popup_mgr().Enabled())
|
||||
// this.Html_box().Html_js_eval_script("if (window.xowa_popups_hide_all != null) window.xowa_popups_hide_all();"); // should be more configurable; DATE:2014-07-09
|
||||
|
||||
app.Thread_mgr_old().Page_load_mgr().Add_at_end(new Load_page_wkr(this, wiki, url, ttl)).Run();
|
||||
}
|
||||
private void Show_url_loaded(Load_page_wkr wkr) {
|
||||
|
||||
@@ -31,6 +31,7 @@ public class Xog_win_itm__prog_href_mgr {
|
||||
}
|
||||
Xoa_url url = Xoa_url.blank();
|
||||
app.Html__href_parser().Parse_as_url(url, Bry_.new_u8(href), wiki, page.Ttl().Page_txt());
|
||||
usr_dlg.Prog_direct(String_.new_u8(url.To_bry(!show_status_url, Bool_.Y)));
|
||||
if (!app.Mode().Tid_is_http()) // if http_server, do not write to progress bar, else will show up in console output (b/c gui_wkr for http_server is console); DATE:2018-11-11
|
||||
usr_dlg.Prog_direct(String_.new_u8(url.To_bry(!show_status_url, Bool_.Y)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ public class Xoh_head_itm__popups extends Xoh_head_itm__base {
|
||||
}
|
||||
@Override public void Write_js_tail_script(Xoae_app app, Xowe_wiki wiki, Xoae_page page, Xoh_head_wtr wtr) {
|
||||
wtr.Write_js_line(Jquery_init); // NOTE: must assert that jquery is init'd, else popup.js will not compile after going back / forward; DATE:2014-09-10
|
||||
wtr.Write_js_tail_load_lib(app.Fsys_mgr().Bin_any_dir().GenSubFil_nest("xowa", "html", "res", "src", "xowa", "popups", "popups.js"));
|
||||
wtr.Write_js_tail_load_lib(app.Fsys_mgr().Bin_any_dir().GenSubFil_nest("xowa", "html", "res", "src", "xowa", "popups", "xo.popup.js"));
|
||||
} public static final byte[] Jquery_init = Bry_.new_a7("xowa.js.jquery.init();"), Mw_init = Bry_.new_a7("xowa.js.mediaWiki.init();");
|
||||
private static byte[] Css_url_day, Css_url_night;
|
||||
private static final byte[]
|
||||
|
||||
@@ -15,6 +15,7 @@ Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.xowa.htmls.heads; import gplx.*; import gplx.xowa.*; import gplx.xowa.htmls.*;
|
||||
import gplx.core.bits.*;
|
||||
import gplx.xowa.wikis.pages.*;
|
||||
public class Xoh_head_mgr implements gplx.core.brys.Bfr_arg {
|
||||
private Xoae_app app; private Xowe_wiki wiki; private Xoae_page page;
|
||||
private Xoh_head_itm__base[] itms; private int itms_len;
|
||||
@@ -59,7 +60,7 @@ public class Xoh_head_mgr implements gplx.core.brys.Bfr_arg {
|
||||
this.app = app; this.wiki = wiki; this.page = page;
|
||||
return this;
|
||||
}
|
||||
public Xoh_head_mgr Init_dflts() {
|
||||
public Xoh_head_mgr Init_dflts(byte html_gen_tid) {
|
||||
if (page.Wtxt().Toc().Enabled()) itm__toc.Enabled_y_();
|
||||
if (wiki.Html_mgr().Head_mgr().Itm__top_icon().Enabled_y()) itm__top_icon.Enabled_y_();
|
||||
if (wiki.Html_mgr().Head_mgr().Itm__title_rewrite().Enabled_y()) itm__title_rewrite.Enabled_y_();
|
||||
@@ -70,9 +71,7 @@ public class Xoh_head_mgr implements gplx.core.brys.Bfr_arg {
|
||||
itm__xo_elem.Enabled_y_();
|
||||
itm__collapsible.Enabled_y_();
|
||||
itm__navframe.Enabled_y_();
|
||||
boolean popups_enabled
|
||||
= !app.Mode().Tid_is_http() // do not enable if http_server, else js errors when calling xowa_exec; DATE:2016-06-22
|
||||
&& wiki.Html_mgr().Head_mgr().Popup_mgr().Enabled(); // check user_cfg
|
||||
boolean popups_enabled = html_gen_tid != Xopg_page_.Tid_edit && wiki.Html_mgr().Head_mgr().Popup_mgr().Enabled();
|
||||
itm__popups.Enabled_(popups_enabled);
|
||||
return this;
|
||||
}
|
||||
@@ -123,6 +122,7 @@ public class Xoh_head_mgr implements gplx.core.brys.Bfr_arg {
|
||||
Xoh_head_itm__base itm = list__js_include.Get_at(i);
|
||||
itm.Write_js_include(app, wiki, page, wtr);
|
||||
}
|
||||
|
||||
int tail_script_len = list__js_tail_script.Len();
|
||||
int window_onload_len = list__js_window_onload.Len();
|
||||
if (tail_script_len + window_onload_len > 0) {
|
||||
|
||||
@@ -19,6 +19,7 @@ import gplx.langs.jsons.*;
|
||||
import gplx.xowa.htmls.js.*;
|
||||
import gplx.xowa.guis.views.*;
|
||||
import gplx.xowa.parsers.*;
|
||||
import gplx.xowa.htmls.modules.popups.*;
|
||||
public class Xoh_js_cbk implements Gfo_invk {
|
||||
private Xoae_app app;
|
||||
private Xog_html_itm html_itm;
|
||||
@@ -67,19 +68,22 @@ public class Xoh_js_cbk implements Gfo_invk {
|
||||
return String_.new_u8(page.Db().Text().Text_bry());
|
||||
} catch (Exception e) {Err_.Noop(e); return null;}
|
||||
}
|
||||
private String Popups_get_async_bgn(GfoMsg m) {
|
||||
try {
|
||||
byte[] js_cbk = m.Args_getAt(0).Val_to_bry();
|
||||
byte[] href_bry = m.Args_getAt(1).Val_to_bry();
|
||||
return html_itm.Owner_tab().Wiki().Html_mgr().Head_mgr().Popup_mgr().Get_async_bgn(js_cbk, href_bry);
|
||||
} catch (Exception e) {Err_.Noop(e); return null;}
|
||||
}
|
||||
private String Popups_get_html(GfoMsg m) {
|
||||
try {
|
||||
int popups_id = Int_.By_double(Double_.cast(m.Args_getAt(0).Val()));
|
||||
byte[] href_bry = m.Args_getAt(1).Val_to_bry();
|
||||
byte[] tooltip_bry = m.Args_getAt(2).Val_to_bry();
|
||||
return html_itm.Owner_tab().Wiki().Html_mgr().Head_mgr().Popup_mgr().Show_init(popups_id, href_bry, tooltip_bry);
|
||||
String mode = m.Args_getAt(0).Val_to_str_or_empty();
|
||||
String popups_id = m.Args_getAt(1).Val_to_str_or_empty();
|
||||
|
||||
Xow_popup_mgr popup_mgr = html_itm.Owner_tab().Wiki().Html_mgr().Head_mgr().Popup_mgr();
|
||||
if (String_.Eq(mode, "init")) {
|
||||
byte[] href_bry = m.Args_getAt(2).Val_to_bry();
|
||||
byte[] tooltip_bry = m.Args_getAt(3).Val_to_bry();
|
||||
return popup_mgr.Show_init(popups_id, href_bry, tooltip_bry);
|
||||
}
|
||||
else if (String_.Eq(mode, "more"))
|
||||
return popup_mgr.Show_more(popups_id);
|
||||
else if (String_.Eq(mode, "all"))
|
||||
popup_mgr.Show_all(popups_id);
|
||||
return "";
|
||||
} catch (Exception e) {Err_.Noop(e); return null;}
|
||||
}
|
||||
private String[] Get_title_meta(Xowe_wiki wiki, byte[] ttl_bry) {
|
||||
@@ -175,7 +179,6 @@ public class Xoh_js_cbk implements Gfo_invk {
|
||||
else if (ctx.Match(k, Invk_get_page)) return Get_page(m);
|
||||
else if (ctx.MatchIn(k, Invk_cmd, Invk_scripts_exec)) return Scripts_exec(m);
|
||||
else if (ctx.Match(k, Invk_scripts_exec)) return Scripts_exec(m);
|
||||
else if (ctx.Match(k, Invk_popups_get_async_bgn)) return Popups_get_async_bgn(m);
|
||||
else if (ctx.Match(k, Invk_popups_get_html)) return Popups_get_html(m);
|
||||
else if (ctx.Match(k, Invk_get_search_suggestions)) return Get_search_suggestions(m);
|
||||
else if (ctx.Match(k, Invk_get_titles_meta)) return Get_titles_meta(m);
|
||||
@@ -190,7 +193,6 @@ public class Xoh_js_cbk implements Gfo_invk {
|
||||
public static final String Invk_parse_to_html = "parse_to_html", Invk_wikidata_get_label = "wikidata_get_label", Invk_get_page = "get_page", Invk_cmd = "cmd", Invk_scripts_exec = "scripts_exec"
|
||||
, Invk_get_search_suggestions = "get_search_suggestions", Invk_get_titles_meta = "get_titles_meta", Invk_get_titles_exists = "get_titles_exists", Invk_get_current_url = "get_current_url"
|
||||
, Invk_xowa_exec_test = "xowa_exec_test", Invk_xowa_exec_test_as_array = "xowa_exec_test_as_array"
|
||||
, Invk_popups_get_async_bgn = "popups_get_async_bgn"
|
||||
, Invk_popups_get_html = "popups_get_html"
|
||||
, Invk_exec_json = "exec_json"
|
||||
, Invk_bldr_exec = "bldr_exec"
|
||||
|
||||
@@ -26,6 +26,9 @@ public class Xow_popup_html_mkr {
|
||||
public void Output_tidy_(boolean v) {output_tidy = v;} private boolean output_tidy = true;
|
||||
public void Ctor(Xoae_app app, Xowe_wiki wiki) {
|
||||
this.wiki = wiki; this.app = app;
|
||||
this.fmtr_popup = app.Mode().Tid_is_http() ?
|
||||
Bry_fmtr.new_(Web_html_fmtr_popup, Dflt_html_fmtr_popup_keys) :
|
||||
Bry_fmtr.new_(Dflt_html_fmtr_popup, Dflt_html_fmtr_popup_keys);
|
||||
wiki.Eval_mgr().Eval_mgr_(fmtr_popup, fmtr_viewed, fmtr_wiki, fmtr_next_sect);
|
||||
}
|
||||
public byte[] Bld(Xowe_wiki cur_wiki, Xoae_page page, Xow_popup_itm popup_itm, Bry_bfr wrdx_bfr) {
|
||||
@@ -79,6 +82,24 @@ public class Xow_popup_html_mkr {
|
||||
, Dflt_html_fmtr_viewed = Bry_.new_a7("\n <span class='data_key'>~{<>msgs.get('api-xowa.html.modules.popups.msgs.view_time-name');<>}</span><span class='data_val'>~{viewed_val}</span>")
|
||||
, Dflt_html_fmtr_wiki = Bry_.new_a7("\n <span class='data_key'>~{<>msgs.get('api-xowa.html.modules.popups.msgs.wiki-name');<>}</span><span class='data_val'>~{wiki_val}</span>")
|
||||
, Dflt_html_fmtr_next_sect = Bry_.new_a7("\n\n<span class='next_sect'>~{<>msgs.get('api-xowa.html.modules.popups.msgs.next_sect-name');<>}~{next_sect_val}</span>")
|
||||
, Web_html_fmtr_popup = Bry_.new_a7(String_.Concat_lines_nl_skip_last
|
||||
( "<div dir=~{page_lang_ltr}>"
|
||||
, " <div>~{content}"
|
||||
, " </div>"
|
||||
, " <hr/>"
|
||||
, " <div>"
|
||||
, " <span class='data_val'><b>~{page_title}</b></span>~{wiki_item}"
|
||||
, " <span class='data_key'>~{<>msgs.get('api-xowa.html.modules.popups.msgs.size-name');<>}</span><span class='data_val'>~{page_size}</span>"
|
||||
, " <span class='data_key'>~{<>msgs.get('api-xowa.html.modules.popups.msgs.edited-name');<>}</span><span class='data_val'>~{edit_time}</span>~{view_time_item}"
|
||||
, " </div>"
|
||||
, " <hr/>"
|
||||
, " <div style='float:bottom;'>"
|
||||
, " <span><a href='/~{page_url}' title='~{<>msgs.get('api-xowa.gui.browser.url.exec-name');<>}' class='xowa-hover-off'><img src='~{xowa_root_dir}bin/any/xowa/file/app.menu/page/open.png'></a></span>"
|
||||
, " <span><a href='/~{page_url}' title='~{<>msgs.get('api-xowa.gui.browser.tabs.new_link__at_dflt__focus_y-name');<>}' class='xowa-hover-off' target='_blank'><img src='~{xowa_root_dir}bin/any/xowa/file/app.menu/tabs/new.png'></a></span>"
|
||||
// , " <span><a href='javascript:xowa.popups.FetchMore(\"~{popup_id}\");' title='~{<>msgs.get('api-xowa.html.modules.popups.show_more-tip');<>}'><img src='~{xowa_root_dir}bin/any/xowa/html/res/src/xowa/popups/imgs/show_more.png'></a></span>"
|
||||
, " </div>"
|
||||
, "</div>"
|
||||
))
|
||||
;
|
||||
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")
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
|
||||
Reference in New Issue
Block a user