mirror of
https://github.com/gnosygnu/xowa.git
synced 2026-03-02 03:49:30 +00:00
Source: Restore broken commit
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.htmls.modules.popups; import gplx.*; import gplx.xowa.*; import gplx.xowa.htmls.*; import gplx.xowa.htmls.modules.*;
|
||||
public class Xopg_popup_mgr {
|
||||
public Ordered_hash Itms() {return itms;} private Ordered_hash itms = Ordered_hash_.New();
|
||||
public void Clear() {
|
||||
itms.Clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.htmls.modules.popups; import gplx.*; import gplx.xowa.*; import gplx.xowa.htmls.*; import gplx.xowa.htmls.modules.*;
|
||||
import gplx.xowa.parsers.*;
|
||||
class Xow_popup_anchor_finder {
|
||||
private byte[] src, find;
|
||||
private int src_len, nl_lhs;
|
||||
public int Find(byte[] src, int src_len, byte[] find, int bgn) {
|
||||
this.src = src; this.src_len = src_len; this.find = find; this.nl_lhs = bgn;
|
||||
if (bgn == Xop_parser_.Doc_bgn_bos && Find_hdr(bgn)) return Xop_parser_.Doc_bgn_bos;// handle BOS separately which won't fit "\n=" search below; EX: "BOS==A==\n"
|
||||
int lhs_bgn = bgn;
|
||||
while (true) {
|
||||
lhs_bgn = Bry_find_.Find_fwd(src, Hdr_bgn, nl_lhs, src_len);
|
||||
if (lhs_bgn == Bry_find_.Not_found) break; // "\n=" not found; exit;
|
||||
if (Find_hdr(lhs_bgn)) return lhs_bgn;
|
||||
}
|
||||
return Find_id(bgn);
|
||||
}
|
||||
private boolean Find_hdr(int lhs_bgn) {
|
||||
int nl_rhs = Bry_find_.Find_fwd(src, Byte_ascii.Nl, nl_lhs + 1, src_len); // look for \n
|
||||
if (nl_rhs == Bry_find_.Not_found) nl_rhs = src_len - 1; // no more \n; set to last idx
|
||||
nl_lhs = nl_rhs; // update nl_lhs for loop
|
||||
int lhs_end = Bry_find_.Find_fwd_while(src, lhs_bgn + 1, nl_rhs, Byte_ascii.Eq); // skip eq; EX: "\n==="; +1 to skip eq
|
||||
int rhs_end = Bry_find_.Trim_bwd_space_tab(src, nl_rhs, lhs_end); // skip ws bwd; EX: "== \n"
|
||||
int rhs_bgn = Bry_find_.Find_bwd_while(src, rhs_end, lhs_end, Byte_ascii.Eq); // skip eq; EX: "==\n" -> pos before =
|
||||
if (rhs_bgn < lhs_end) return false; // eq found, but is actually lhs_eq; no rhs_eq, so exit; EX: "\n== \n"
|
||||
++rhs_bgn; // rhs_bgn is 1st char before eq; position at eq; neede for txt_end below
|
||||
int txt_bgn = Bry_find_.Trim_fwd_space_tab(src, lhs_end, nl_rhs); // trim ws
|
||||
int txt_end = Bry_find_.Trim_bwd_space_tab(src, rhs_bgn, lhs_end); // trim ws
|
||||
return Bry_.Eq(src, txt_bgn, txt_end, find); // check for strict match
|
||||
}
|
||||
private int Find_id(int bgn) {
|
||||
byte[] quoted = Bry_.Add(Byte_ascii.Quote_bry, find, Byte_ascii.Quote_bry);
|
||||
int rv = Find_id_by_quoted(bgn, quoted);
|
||||
if (rv == Bry_find_.Not_found) {
|
||||
quoted[0] = Byte_ascii.Apos; quoted[quoted.length - 1] = Byte_ascii.Apos;
|
||||
rv = Find_id_by_quoted(bgn, quoted);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
private int Find_id_by_quoted(int bgn, byte[] quoted) {
|
||||
int rv = Bry_find_.Not_found;
|
||||
int pos = Bry_find_.Find_fwd(src, quoted, bgn);
|
||||
if (pos == Bry_find_.Not_found) return rv;
|
||||
pos = Bry_find_.Trim_bwd_space_tab(src, pos, bgn);
|
||||
if (src[pos - 1] != Byte_ascii.Eq) return rv;
|
||||
int id_end = Bry_find_.Trim_bwd_space_tab(src, pos - 1, bgn);
|
||||
int id_bgn = Bry_find_.Find_bwd_ws(src, id_end - 1, bgn);
|
||||
boolean id_match = Int_.Bounds_chk(id_bgn, id_end, src_len) && Bry_.Eq(src, id_bgn + 1, id_end, Id_bry);
|
||||
if (!id_match) return rv;
|
||||
rv = Bry_find_.Find_bwd(src, Byte_ascii.Nl, id_bgn);
|
||||
return rv == Bry_find_.Not_found ? 0 : rv;
|
||||
}
|
||||
private static final byte[] Hdr_bgn = Bry_.new_a7("\n="), Id_bry = Bry_.new_a7("id");
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.htmls.modules.popups; import gplx.*; import gplx.xowa.*; import gplx.xowa.htmls.*; import gplx.xowa.htmls.modules.*;
|
||||
import org.junit.*;
|
||||
import gplx.xowa.apps.apis.xowa.html.modules.*;
|
||||
import gplx.xowa.guis.views.*;
|
||||
public class Xow_popup_anchor_finder__hdr_tst {
|
||||
@Before public void init() {fxt.Clear();} private Xop_popup_hdr_finder_fxt fxt = new Xop_popup_hdr_finder_fxt();
|
||||
@Test public void Basic() {
|
||||
String src_str = String_.Concat_lines_nl_skip_last
|
||||
( "a"
|
||||
, "==b1=="
|
||||
, "c"
|
||||
);
|
||||
fxt.Test_find(src_str, "b1", 1);
|
||||
fxt.Test_find_not(src_str, "b");
|
||||
fxt.Test_find_not(src_str, "a");
|
||||
}
|
||||
@Test public void Mid() {
|
||||
String src_str = String_.Concat_lines_nl_skip_last
|
||||
( "a"
|
||||
, "==b=="
|
||||
, "c"
|
||||
, "==d=="
|
||||
, "e"
|
||||
);
|
||||
fxt.Test_find(src_str, "d", 9);
|
||||
}
|
||||
@Test public void Eos() {
|
||||
String src_str = String_.Concat_lines_nl_skip_last
|
||||
( "a"
|
||||
, "==b=="
|
||||
);
|
||||
fxt.Test_find(src_str, "b", 1);
|
||||
}
|
||||
@Test public void Bos() {
|
||||
String src_str = String_.Concat_lines_nl_skip_last
|
||||
( "==a=="
|
||||
, "b"
|
||||
);
|
||||
fxt.Test_find(src_str, "a", -1);
|
||||
}
|
||||
@Test public void Trim() {
|
||||
String src_str = String_.Concat_lines_nl_skip_last
|
||||
( "a"
|
||||
, "== b =="
|
||||
, "c"
|
||||
);
|
||||
fxt.Test_find(src_str, "b", 1);
|
||||
}
|
||||
@Test public void Ws() {
|
||||
String src_str = String_.Concat_lines_nl_skip_last
|
||||
( "a"
|
||||
, "== b c =="
|
||||
, "d"
|
||||
);
|
||||
fxt.Test_find(src_str, "b c", 1);
|
||||
}
|
||||
}
|
||||
class Xop_popup_hdr_finder_fxt {
|
||||
private Xow_popup_anchor_finder finder = new Xow_popup_anchor_finder();
|
||||
public void Clear() {
|
||||
}
|
||||
public void Test_find_not(String src_str, String hdr_str) {Test_find(src_str, hdr_str, Bry_find_.Not_found);}
|
||||
public void Test_find(String src_str, String hdr_str, int expd) {
|
||||
byte[] src = Bry_.new_u8(src_str);
|
||||
byte[] hdr = Bry_.new_u8(hdr_str);
|
||||
Tfds.Eq(expd, finder.Find(src, src.length, hdr, 0), hdr_str);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.htmls.modules.popups; import gplx.*; import gplx.xowa.*; import gplx.xowa.htmls.*; import gplx.xowa.htmls.modules.*;
|
||||
import org.junit.*;
|
||||
import gplx.xowa.apps.apis.xowa.html.modules.*;
|
||||
import gplx.xowa.guis.views.*;
|
||||
public class Xow_popup_anchor_finder__id_tst {
|
||||
@Before public void init() {fxt.Clear();} private Xop_popup_hdr_finder_fxt fxt = new Xop_popup_hdr_finder_fxt();
|
||||
@Test public void Basic() {
|
||||
String src_str = String_.Concat_lines_nl_skip_last
|
||||
( "b"
|
||||
, "<span id=\"a\"/>"
|
||||
, "c"
|
||||
);
|
||||
fxt.Test_find(src_str, "a", 1);
|
||||
fxt.Test_find_not(src_str, "b");
|
||||
fxt.Test_find_not(src_str, "c");
|
||||
}
|
||||
@Test public void Ws() {
|
||||
String src_str = String_.Concat_lines_nl_skip_last
|
||||
( "b"
|
||||
, "<span id = \"a\"/>"
|
||||
, "c"
|
||||
);
|
||||
fxt.Test_find(src_str, "a", 1);
|
||||
}
|
||||
@Test public void Fail() {
|
||||
String src_str = String_.Concat_lines_nl_skip_last
|
||||
( "b"
|
||||
, "<span xid = \"a\"/>"
|
||||
, "c"
|
||||
);
|
||||
fxt.Test_find_not(src_str, "a");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.htmls.modules.popups; import gplx.*; import gplx.xowa.*; import gplx.xowa.htmls.*; import gplx.xowa.htmls.modules.*;
|
||||
import gplx.xowa.apps.apis.xowa.html.modules.*;
|
||||
public class Xow_popup_cfg {
|
||||
public int Show_all_if_less_than() {return show_all_if_less_than;} public void Show_all_if_less_than_(int v) {show_all_if_less_than = v;} private int show_all_if_less_than;
|
||||
public int Tmpl_read_max() {return tmpl_read_max;} public void Tmpl_read_max_(int v) {tmpl_read_max = v;} private int tmpl_read_max;
|
||||
public int Tmpl_read_len() {return tmpl_read_len;} public void Tmpl_read_len_(int v) {tmpl_read_len = v;} private int tmpl_read_len;
|
||||
public int Read_til_stop_fwd() {return read_til_stop_fwd;} public void Read_til_stop_fwd_(int v) {read_til_stop_fwd = v;} private int read_til_stop_fwd;
|
||||
public int Read_til_stop_bwd() {return read_til_stop_bwd;} public void Read_til_stop_bwd_(int v) {read_til_stop_bwd = v;} private int read_til_stop_bwd;
|
||||
public int Stop_if_hdr_after() {return stop_if_hdr_after;} public void Stop_if_hdr_after_(int v) {stop_if_hdr_after = v;} private int stop_if_hdr_after;
|
||||
public boolean Stop_if_hdr_after_enabled() {return stop_if_hdr_after > 0;}
|
||||
public byte[] Ellipsis() {return ellipsis;} public void Ellipsis_(byte[] v) {ellipsis = v;} private byte[] ellipsis = Bry_.Empty;
|
||||
public byte[] Notoc() {return notoc;} public void Notoc_(byte[] v) {notoc = v;} private byte[] notoc = Notoc_const;
|
||||
public static final byte[]
|
||||
Notoc_const = Bry_.new_a7("\n__NOTOC__") // NOTE: always add a whitespace tkn else __NOTOC__ will be deactivated if last tkn is lnke; DATE:2014-06-22
|
||||
, Msg_key_ellipsis = Bry_.new_a7("ellipsis")
|
||||
;
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.htmls.modules.popups; import gplx.*; import gplx.xowa.*; import gplx.xowa.htmls.*; import gplx.xowa.htmls.modules.*;
|
||||
import gplx.core.brys.fmtrs.*;
|
||||
import gplx.xowa.apps.apis.xowa.html.modules.*;
|
||||
public class Xow_popup_html_mkr {
|
||||
private Xoae_app app; private Xowe_wiki wiki;
|
||||
public Bry_fmtr Fmtr_popup() {return fmtr_popup;} private Bry_fmtr fmtr_popup = Bry_fmtr.new_(Dflt_html_fmtr_popup, Dflt_html_fmtr_popup_keys);
|
||||
public Bry_fmtr Fmtr_viewed() {return fmtr_viewed;} private Bry_fmtr fmtr_viewed = Bry_fmtr.new_(Dflt_html_fmtr_viewed, Dflt_html_fmtr_viewed_keys);
|
||||
public Bry_fmtr Fmtr_wiki() {return fmtr_wiki;} private Bry_fmtr fmtr_wiki = Bry_fmtr.new_(Dflt_html_fmtr_wiki, Dflt_html_fmtr_wiki_keys);
|
||||
public Bry_fmtr Fmtr_next_sect() {return fmtr_next_sect;} private Bry_fmtr fmtr_next_sect = Bry_fmtr.new_(Dflt_html_fmtr_next_sect, Dflt_html_fmtr_next_sect_keys);
|
||||
public void Output_js_clean_(boolean v) {output_js_clean = v;} private boolean output_js_clean = true;
|
||||
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;
|
||||
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) {
|
||||
if (output_js_clean) cur_wiki.Html_mgr().Js_cleaner().Clean_bfr(wiki, page.Ttl(), wrdx_bfr, 0);
|
||||
if (output_tidy) cur_wiki.Html_mgr().Tidy_mgr().Exec_tidy(wrdx_bfr, Bool_.Y, page.Url_bry_safe());
|
||||
byte[] hdom_bry = wrdx_bfr.To_bry_and_clear();
|
||||
String page_url = wrdx_bfr.Add(page.Wiki().Domain_bry()).Add(gplx.xowa.htmls.hrefs.Xoh_href_.Bry__wiki).Add(gplx.langs.htmls.encoders.Gfo_url_encoder_.Href
|
||||
.Encode(page.Ttl().Full_db())) // NOTE: was page.Url().Raw(), but that doesn't work for Special:Search; PAGE:en.w:Earth and "Quotations"; DATE:2014-06-29
|
||||
.To_str_and_clear()
|
||||
;
|
||||
fmtr_popup.Bld_bfr_many
|
||||
( wrdx_bfr
|
||||
, hdom_bry
|
||||
, wiki.Lang().Dir_ltr_bry()
|
||||
, page_url
|
||||
, String_.new_u8(page.Ttl().Full_txt_w_ttl_case())
|
||||
, popup_itm.Popup_id()
|
||||
, Xow_popup_html_bldr_.Bld_fmtr_wiki(fmtr_wiki, wrdx_bfr, cur_wiki.Domain_bry(), page.Wiki().Domain_bry()) // NOTE: use cur_wiki, not page_wiki; DATE:2014-06-28
|
||||
, gplx.core.ios.Io_size_.To_str(page.Db().Text().Text_bry().length)
|
||||
, page.Db().Page().Modified_on().XtoStr_fmt_yyyy_MM_dd_HH_mm_ss()
|
||||
, Xow_popup_html_bldr_.Bld_fmtr_viewed(fmtr_viewed, app, wiki, wrdx_bfr, page.Ttl())
|
||||
, app.Fsys_mgr().Root_dir().To_http_file_bry()
|
||||
);
|
||||
return wrdx_bfr.To_bry_and_clear();
|
||||
}
|
||||
|
||||
private static final byte[]
|
||||
Dflt_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='xowa-cmd:xowa.api.nav.goto(\"~{page_url}\");' title='~{<>msgs.get('api-xowa.gui.browser.url.exec-name');<>}'><img src='~{xowa_root_dir}bin/any/xowa/file/app.menu/page/open.png'></a></span>"
|
||||
, " <span><a href='xowa-cmd:xowa.api.gui.browser.tabs.new_link__at_dflt__focus_y(\"~{page_url}\");' title='~{<>msgs.get('api-xowa.gui.browser.tabs.new_link__at_dflt__focus_y-name');<>}'><img src='~{xowa_root_dir}bin/any/xowa/file/app.menu/tabs/new.png'></a></span>"
|
||||
, " <span><a href='xowa-cmd:xowa.api.gui.browser.tabs.new_link__at_dflt__focus_n(\"~{page_url}\");' title='~{<>msgs.get('api-xowa.gui.browser.tabs.new_link__at_dflt__focus_n-name');<>}'><img src='~{xowa_root_dir}bin/any/xowa/file/app.menu/tabs/new_background.png'></a></span>"
|
||||
, " <span><a href='xowa-cmd:xowa.api.usr.bookmarks.add(\"~{page_url}\");' title='~{<>msgs.get('api-xowa.usr.bookmarks.add-name');<>}'><img src='~{xowa_root_dir}bin/any/xowa/file/app.menu/bookmarks/add.png'></a></span>"
|
||||
, " <span><a href='xowa-cmd:xowa.api.html.modules.popups.show_more(\"~{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>"
|
||||
, " <span><a href='xowa-cmd:xowa.api.html.modules.popups.show_all (\"~{popup_id}\");' title='~{<>msgs.get('api-xowa.html.modules.popups.show_all-tip');<>}'> <img src='~{xowa_root_dir}bin/any/xowa/html/res/src/xowa/popups/imgs/show_all.png' ></a></span>"
|
||||
, " <span><a href='/wiki/Special:XowaPopupHistory' title='~{<>msgs.get('api-xowa.html.modules.popups.history-tip');<>}'><img src='~{xowa_root_dir}bin/any/xowa/file/app.menu/history/show.png'></a></span>"
|
||||
, " <span><a href='xowa-cmd:xowa.api.gui.browser.tabs.new_link__at_dflt__focus_y(\"home/wiki/Options/Popups\");' title='~{<>msgs.get('api-xowa.nav.cfg.main-name');<>}'><img src='~{xowa_root_dir}bin/any/xowa/file/app.menu/tools/options.png'></a></span>" // HOME
|
||||
, " </div>"
|
||||
, "</div>"
|
||||
))
|
||||
, 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>")
|
||||
;
|
||||
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")
|
||||
, Dflt_html_fmtr_viewed_keys = String_.Ary("viewed_val")
|
||||
, Dflt_html_fmtr_wiki_keys = String_.Ary("wiki_val")
|
||||
, Dflt_html_fmtr_next_sect_keys = String_.Ary("next_sect_val")
|
||||
;
|
||||
}
|
||||
class Xow_popup_html_bldr_ {
|
||||
public static byte[] Bld_fmtr_wiki(Bry_fmtr fmtr, Bry_bfr wrdx_bfr, byte[] wiki_domain, byte[] page_domain) {
|
||||
return Bry_.Eq(wiki_domain, page_domain)
|
||||
? Bry_.Empty // same domain; return "";
|
||||
: fmtr.Bld_bry_many(wrdx_bfr, page_domain);
|
||||
}
|
||||
public static byte[] Bld_fmtr_viewed(Bry_fmtr fmtr, Xoae_app app, Xowe_wiki wiki, Bry_bfr wrdx_bfr, Xoa_ttl ttl) {
|
||||
byte[] view_time_item = Bry_.Empty;
|
||||
gplx.xowa.users.history.Xou_history_itm history_itm = app.Usere().History_mgr().Get_or_null(wiki.Domain_bry(), ttl.Full_txt_w_ttl_case());
|
||||
if (history_itm != null)
|
||||
view_time_item = fmtr.Bld_bry_many(wrdx_bfr, history_itm.View_end().XtoStr_fmt_yyyy_MM_dd_HH_mm_ss());
|
||||
return view_time_item;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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);
|
||||
this.words_needed = init_words_needed;
|
||||
this.page_href = page_href;
|
||||
this.tooltip = tooltip;
|
||||
}
|
||||
public boolean Canceled() {return canceled;} private boolean canceled = false;
|
||||
public void Cancel() {canceled = true;}
|
||||
public byte Mode() {return mode;} private byte mode = Mode_tid_init;
|
||||
public Xow_popup_itm Mode_more_(int more_words) {
|
||||
mode = Mode_tid_more;
|
||||
words_needed = words_found + more_words;
|
||||
return this;
|
||||
}
|
||||
public boolean Mode_all() {return mode == Mode_tid_all;}
|
||||
public Xow_popup_itm Mode_all_() {
|
||||
mode = Mode_tid_all;
|
||||
words_needed = Int_.Max_value;
|
||||
return this;
|
||||
}
|
||||
public String Popup_id() {return popup_id;} private String popup_id;
|
||||
public byte[] Popup_html() {return popup_html;} public void Popup_html_(byte[] v) {popup_html = v;} private byte[] popup_html;
|
||||
public byte[] Tooltip() {return tooltip;} private byte[] tooltip;
|
||||
public byte[] Wiki_domain() {return wiki_domain;} private byte[] wiki_domain;
|
||||
public byte[] Page_href() {return page_href;} private byte[] page_href;
|
||||
public Xoa_ttl Page_ttl() {return page_ttl;} private Xoa_ttl page_ttl;
|
||||
public void Init(byte[] wiki_domain, Xoa_ttl page_ttl) {this.wiki_domain = wiki_domain; this.page_ttl = page_ttl;}
|
||||
public int Words_needed() {return words_needed;} private int words_needed;
|
||||
public int Words_found() {return words_found;} public void Words_found_(int v) {words_found = v;} private int words_found;
|
||||
public static final byte Mode_tid_init = 0, Mode_tid_more = 1, Mode_tid_all = 2;
|
||||
}
|
||||
251
400_xowa/src/gplx/xowa/htmls/modules/popups/Xow_popup_mgr.java
Normal file
251
400_xowa/src/gplx/xowa/htmls/modules/popups/Xow_popup_mgr.java
Normal file
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.htmls.modules.popups; import gplx.*; import gplx.xowa.*; import gplx.xowa.htmls.*; import gplx.xowa.htmls.modules.*;
|
||||
import gplx.core.primitives.*; import gplx.core.threads.*; import gplx.core.envs.*;
|
||||
import gplx.core.js.*;
|
||||
import gplx.xowa.addons.apps.cfgs.*;
|
||||
import gplx.xowa.wikis.nss.*;
|
||||
import gplx.xowa.guis.views.*;
|
||||
import gplx.xowa.htmls.hrefs.*;
|
||||
import gplx.xowa.specials.*;
|
||||
import gplx.xowa.apps.apis.xowa.html.modules.*;
|
||||
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;
|
||||
public Xow_popup_mgr(Xowe_wiki wiki) {
|
||||
this.wiki = wiki; this.app = wiki.Appe();
|
||||
ev_mgr = new Gfo_evt_mgr(this);
|
||||
}
|
||||
public Gfo_evt_mgr Evt_mgr() {return ev_mgr;} private Gfo_evt_mgr ev_mgr;
|
||||
public Xow_popup_parser Parser() {return parser;} private Xow_popup_parser parser = new Xow_popup_parser();
|
||||
public boolean Enabled() {return enabled;} public void Enabled_(boolean v) {this.enabled = v;} private boolean enabled = true; // TEST: false will fail Xob_init_base_tst; DATE:2016-12-13
|
||||
public void Init_by_wiki(Xowe_wiki wiki) {
|
||||
parser.Init_by_wiki(wiki);
|
||||
wiki.App().Cfg().Bind_many_wiki(this, wiki
|
||||
, Cfg__enabled
|
||||
, Cfg__show_init_word_count, Cfg__show_more_word_count
|
||||
, Cfg__show_all_if_less_than, Cfg__read_til_stop_fwd, Cfg__read_til_stop_bwd, Cfg__stop_if_hdr_after
|
||||
, Cfg__tmpl_tkn_max, Cfg__tmpl_keeplist
|
||||
, Cfg__ns_allowed, Cfg__xnde_ignore_ids, Cfg__scan_len, Cfg__scan_max
|
||||
);
|
||||
}
|
||||
public String Show_init(int 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);
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
public static boolean Running() {
|
||||
boolean rv = false;
|
||||
synchronized (thread_lock) {
|
||||
rv = running;
|
||||
}
|
||||
return rv;
|
||||
} private static boolean running = false;
|
||||
private static void Running_(boolean v) {
|
||||
synchronized (thread_lock) {
|
||||
running = v;
|
||||
}
|
||||
}
|
||||
private byte[] Get_popup_html(Xowe_wiki cur_wiki, Xoae_page cur_page, Xow_popup_itm itm) {
|
||||
try {
|
||||
synchronized (thread_lock) { // queue popups to reduce contention with Load_page_wkr; DATE:2014-08-24
|
||||
// Load_popup_wkr load_popup_wkr = new Load_popup_wkr(wiki, cur_page, itm, temp_href, ns_allowed_regy, ns_allowed_regy_key);
|
||||
// app.Thread_mgr().Page_load_mgr().Add_at_end(load_popup_wkr);
|
||||
// load_popup_wkr.Exec();
|
||||
// while (!load_popup_wkr.Rslt_done()) {
|
||||
// Thread_adp_.Sleep(100);
|
||||
// }
|
||||
// return load_popup_wkr.Rslt_bry();
|
||||
Running_(true);
|
||||
if (itm.Canceled()) return null;
|
||||
cur_page.Popup_mgr().Itms().Add_if_dupe_use_nth(itm.Popup_id(), itm);
|
||||
app.Html__href_parser().Parse_as_url(tmp_url, itm.Page_href(), wiki, cur_page.Ttl().Full_url()); // NOTE: use Full_url, not Page_url, else anchors won't work for non-main ns; PAGE:en.w:Project:Sandbox; DATE:2014-08-07
|
||||
if (!Xoa_url_.Tid_is_pagelike(tmp_url.Tid())) return Bry_.Empty; // NOTE: do not get popups for "file:///"; DATE:2015-04-05
|
||||
Xowe_wiki popup_wiki = (Xowe_wiki)app.Wiki_mgr().Get_by_or_null(tmp_url.Wiki_bry());
|
||||
popup_wiki.Init_assert();
|
||||
Xoa_ttl popup_ttl = Xoa_ttl.Parse(popup_wiki, tmp_url.To_bry_page_w_anch());
|
||||
switch (popup_ttl.Ns().Id()) {
|
||||
case Xow_ns_.Tid__media:
|
||||
case Xow_ns_.Tid__file:
|
||||
return Bry_.Empty; // do not popup for media or file
|
||||
case Xow_ns_.Tid__special:
|
||||
if (!Xow_special_meta_.Itm__popup_history.Match_ttl(popup_ttl)) return Bry_.Empty; // do not popup for special, unless popupHistory; DATE:2015-04-20
|
||||
break;
|
||||
}
|
||||
if (ns_allowed_regy.Count() > 0 && !ns_allowed_regy.Has(ns_allowed_regy_key.Val_(popup_ttl.Ns().Id()))) return Bry_.Empty;
|
||||
itm.Init(popup_wiki.Domain_bry(), popup_ttl);
|
||||
int wait_count = 0;
|
||||
while (gplx.xowa.guis.views.Load_page_wkr.Running() && ++wait_count < 100) {
|
||||
Thread_adp_.Sleep(10);
|
||||
}
|
||||
Xoae_page popup_page = popup_wiki.Data_mgr().Load_page_by_ttl(popup_ttl);
|
||||
byte[] rv = popup_wiki.Html_mgr().Head_mgr().Popup_mgr().Parser().Parse(wiki, popup_page, cur_page.Tab_data().Tab(), itm);
|
||||
Update_progress_bar(app, cur_wiki, cur_page, itm);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
app.Usr_dlg().Warn_many("", "", "failed to get popup: href=~{0} err=~{1}", itm.Page_href(), Err_.Message_gplx_full(e));
|
||||
return null;
|
||||
}
|
||||
finally {
|
||||
Running_(false);
|
||||
}
|
||||
}
|
||||
public static void Update_progress_bar(Xoae_app app, Xowe_wiki cur_wiki, Xoae_page cur_page, Xow_popup_itm itm) {
|
||||
byte[] href = itm.Page_href();
|
||||
byte[] tooltip = itm.Tooltip();
|
||||
if (Bry_.Len_gt_0(tooltip))
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
public void Ns_allowed_(byte[] raw) {
|
||||
ns_allowed_regy.Clear();
|
||||
Int_obj_ref[] ns_ids = Ns_allowed_parse(wiki, raw);
|
||||
int len = ns_ids.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
Int_obj_ref ns_id = ns_ids[i];
|
||||
ns_allowed_regy.Add(ns_id, ns_id);
|
||||
}
|
||||
}
|
||||
public static Int_obj_ref[] Ns_allowed_parse(Xowe_wiki wiki, byte[] raw) {
|
||||
List_adp rv = List_adp_.New();
|
||||
byte[][] ary = Bry_split_.Split(raw, Byte_ascii.Pipe);
|
||||
int ary_len = ary.length;
|
||||
Xow_ns_mgr ns_mgr = wiki.Ns_mgr();
|
||||
for (int i = 0; i < ary_len; i++) {
|
||||
byte[] bry = ary[i];
|
||||
int bry_len = bry.length; if (bry_len == 0) continue; // ignore empty entries; EX: "0|"
|
||||
Xow_ns ns = Bry_.Eq(bry, Xow_ns_.Bry__main)
|
||||
? ns_mgr.Ns_main()
|
||||
: ns_mgr.Names_get_or_null(bry)
|
||||
;
|
||||
if (ns == null) {
|
||||
wiki.Appe().Usr_dlg().Log_many("", "", "popup.ns_allowed: ns not in wiki: ns=~{0} wiki=~{1}", String_.new_u8(bry), wiki.Domain_str()); // ns may not be in wiki; EX: Portal and www.wikidata.org
|
||||
continue;
|
||||
}
|
||||
Int_obj_ref ns_id_itm = Int_obj_ref.New(ns.Id());
|
||||
rv.Add(ns_id_itm);
|
||||
}
|
||||
return (Int_obj_ref[])rv.To_ary(Int_obj_ref.class);
|
||||
} private Hash_adp ns_allowed_regy = Hash_adp_.New(); private Int_obj_ref ns_allowed_regy_key = Int_obj_ref.New_zero();
|
||||
private Xoae_page Cur_page() {return app.Gui_mgr().Browser_win().Active_page();}
|
||||
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");
|
||||
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"));
|
||||
else if (ctx.Match(k, Cfg__read_til_stop_fwd)) parser.Cfg().Read_til_stop_fwd_(m.ReadInt("v"));
|
||||
else if (ctx.Match(k, Cfg__read_til_stop_bwd)) parser.Cfg().Read_til_stop_bwd_(m.ReadInt("v"));
|
||||
else if (ctx.Match(k, Cfg__stop_if_hdr_after)) parser.Cfg().Stop_if_hdr_after_(m.ReadInt("v"));
|
||||
else if (ctx.Match(k, Cfg__tmpl_tkn_max)) parser.Tmpl_tkn_max_(m.ReadInt("v"));
|
||||
else if (ctx.Match(k, Cfg__tmpl_keeplist)) parser.Tmpl_keeplist_init_(m.ReadBry("v"));
|
||||
else if (ctx.Match(k, Cfg__ns_allowed)) Ns_allowed_(m.ReadBry("v"));
|
||||
else if (ctx.Match(k, Cfg__xnde_ignore_ids)) parser.Wrdx_mkr().Xnde_ignore_ids_(m.ReadBry("v"));
|
||||
else if (ctx.Match(k, Cfg__scan_len)) parser.Cfg().Tmpl_read_len_(m.ReadInt("v"));
|
||||
else if (ctx.Match(k, Cfg__scan_max)) parser.Cfg().Tmpl_read_max_(m.ReadInt("v"));
|
||||
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"
|
||||
;
|
||||
private static final byte[]
|
||||
Mode_show_more = Bry_.new_a7("more")
|
||||
, Mode_show_all = Bry_.new_a7("all")
|
||||
;
|
||||
private static final String
|
||||
Cfg__enabled = "xowa.addon.popups.enabled"
|
||||
, Cfg__show_init_word_count = "xowa.addon.popups.content.show_init_word_count"
|
||||
, Cfg__show_more_word_count = "xowa.addon.popups.content.show_more_word_count"
|
||||
, Cfg__show_all_if_less_than = "xowa.addon.popups.content.show_all_if_less_than"
|
||||
, Cfg__read_til_stop_fwd = "xowa.addon.popups.content.read_til_stop_fwd"
|
||||
, Cfg__read_til_stop_bwd = "xowa.addon.popups.content.read_til_stop_bwd"
|
||||
, Cfg__stop_if_hdr_after = "xowa.addon.popups.content.stop_if_hdr_after"
|
||||
, Cfg__tmpl_tkn_max = "xowa.addon.popups.wtxt.tmpl_tkn_max"
|
||||
, Cfg__tmpl_keeplist = "xowa.addon.popups.wtxt.tmpl_keeplist"
|
||||
, Cfg__ns_allowed = "xowa.addon.popups.ns_allowed"
|
||||
, Cfg__xnde_ignore_ids = "xowa.addon.popups.content.xnde_ignore_ids"
|
||||
, Cfg__scan_len = "xowa.addon.popups.scanner.scan_len"
|
||||
, Cfg__scan_max = "xowa.addon.popups.scanner.scan_max"
|
||||
;
|
||||
public static final String
|
||||
Cfg__win_show_delay = "xowa.addon.popups.window.show_delay"
|
||||
, Cfg__win_hide_delay = "xowa.addon.popups.window.hide_delay"
|
||||
, Cfg__win_max_w = "xowa.addon.popups.window.max_w"
|
||||
, Cfg__win_max_h = "xowa.addon.popups.window.max_h"
|
||||
, Cfg__win_show_all_max_w = "xowa.addon.popups.window.show_all_max_w"
|
||||
, Cfg__win_bind_focus_blur = "xowa.addon.popups.window.bind_focus_blur"
|
||||
;
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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;
|
||||
private Int_obj_ref ns_allowed_regy_key = Int_obj_ref.New_zero();
|
||||
public Load_popup_wkr(Xowe_wiki wiki, Xoae_page cur_page, Xow_popup_itm itm, Xoa_url tmp_url, Hash_adp ns_allowed_regy, Int_obj_ref ns_allowed_regy_key) {
|
||||
this.wiki = wiki; this.cur_page = cur_page; this.itm = itm; this.tmp_url = tmp_url; this.ns_allowed_regy = ns_allowed_regy; this.ns_allowed_regy_key = ns_allowed_regy_key;
|
||||
}
|
||||
public String Thread__name() {return "xowa.load_popup_wkr";}
|
||||
public boolean Thread__resume() {return false;}
|
||||
public Xowe_wiki Wiki() {return wiki;} private Xowe_wiki wiki;
|
||||
public byte[] Rslt_bry() {return rslt_bry;} private byte[] rslt_bry;
|
||||
public boolean Rslt_done() {return rslt_done;} private boolean rslt_done;
|
||||
public void Rslt_(byte[] bry) {this.rslt_done = true; rslt_bry = bry;}
|
||||
public void Thread__exec() {
|
||||
Xoae_app app = wiki.Appe();
|
||||
try {
|
||||
if (itm.Canceled()) return;
|
||||
cur_page.Popup_mgr().Itms().Add_if_dupe_use_nth(itm.Popup_id(), itm);
|
||||
app.Html__href_parser().Parse_as_url(tmp_url, itm.Page_href(), wiki, cur_page.Ttl().Full_url()); // NOTE: use Full_url, not Page_url, else anchors won't work for non-main ns; PAGE:en.w:Project:Sandbox; DATE:2014-08-07
|
||||
if (!Xoa_url_.Tid_is_pagelike(tmp_url.Tid())) return; // NOTE: do not get popups for "file:///"; DATE:2015-04-05
|
||||
Xowe_wiki popup_wiki = (Xowe_wiki)app.Wiki_mgr().Get_by_or_null(tmp_url.Wiki_bry());
|
||||
popup_wiki.Init_assert();
|
||||
Xoa_ttl popup_ttl = Xoa_ttl.Parse(popup_wiki, tmp_url.To_bry_page_w_anch());
|
||||
switch (popup_ttl.Ns().Id()) {
|
||||
case Xow_ns_.Tid__media:
|
||||
case Xow_ns_.Tid__file:
|
||||
return; // do not popup for media or file
|
||||
case Xow_ns_.Tid__special:
|
||||
if (!Xow_special_meta_.Itm__popup_history.Match_ttl(popup_ttl)) return; // do not popup for special, unless popupHistory; DATE:2015-04-20
|
||||
break;
|
||||
}
|
||||
if (ns_allowed_regy.Count() > 0 && !ns_allowed_regy.Has(ns_allowed_regy_key.Val_(popup_ttl.Ns().Id()))) return;
|
||||
itm.Init(popup_wiki.Domain_bry(), popup_ttl);
|
||||
Xoae_page popup_page = popup_wiki.Data_mgr().Load_page_by_ttl(popup_ttl);
|
||||
byte[] rv = popup_wiki.Html_mgr().Head_mgr().Popup_mgr().Parser().Parse(wiki, popup_page, cur_page.Tab_data().Tab(), itm);
|
||||
Xow_popup_mgr.Update_progress_bar(app, wiki, cur_page, itm);
|
||||
Rslt_(rv);
|
||||
}
|
||||
catch(Exception e) {
|
||||
app.Usr_dlg().Warn_many("", "", "failed to get popup: href=~{0} err=~{1}", itm.Page_href(), Err_.Message_gplx_full(e));
|
||||
Rslt_(null);
|
||||
}
|
||||
finally {
|
||||
app.Thread_mgr_old().Page_load_mgr().Resume();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.htmls.modules.popups; import gplx.*; import gplx.xowa.*; import gplx.xowa.htmls.*; import gplx.xowa.htmls.modules.*;
|
||||
import gplx.core.btries.*;
|
||||
import gplx.xowa.wikis.domains.*;
|
||||
import gplx.xowa.apps.apis.xowa.html.modules.*; import gplx.xowa.htmls.modules.popups.keeplists.*; import gplx.xowa.htmls.core.htmls.*; import gplx.xowa.htmls.core.wkrs.hdrs.*;
|
||||
import gplx.xowa.guis.views.*;
|
||||
import gplx.xowa.parsers.*; import gplx.xowa.parsers.hdrs.*; import gplx.xowa.parsers.tblws.*; import gplx.xowa.parsers.tmpls.*;
|
||||
public class Xow_popup_parser {
|
||||
private Xoae_app app; private Xowe_wiki wiki; private Xop_parser parser;
|
||||
private Btrie_fast_mgr tmpl_trie, wtxt_trie; private Xop_tkn_mkr tkn_mkr;
|
||||
private Xop_ctx tmpl_ctx; private Xop_root_tkn tmpl_root, wtxt_root; private Xot_compile_data tmpl_props = new Xot_compile_data();
|
||||
private Xoh_wtr_ctx hctx = Xoh_wtr_ctx.Popup;
|
||||
private Xow_popup_anchor_finder hdr_finder = new Xow_popup_anchor_finder();
|
||||
private final Bry_bfr hdr_html_bfr = Bry_bfr_.New();
|
||||
public Xow_popup_cfg Cfg() {return cfg;} private Xow_popup_cfg cfg = new Xow_popup_cfg();
|
||||
public Xow_popup_wrdx_mkr Wrdx_mkr() {return wrdx_mkr;} private Xow_popup_wrdx_mkr wrdx_mkr = new Xow_popup_wrdx_mkr();
|
||||
public Xow_popup_html_mkr Html_mkr() {return html_mkr;} private Xow_popup_html_mkr html_mkr = new Xow_popup_html_mkr();
|
||||
public Xow_popup_parser_data Data() {return data;} private Xow_popup_parser_data data = new Xow_popup_parser_data();
|
||||
public Xop_keeplist_wiki Tmpl_keeplist() {return tmpl_keeplist;} private Xop_keeplist_wiki tmpl_keeplist; // private byte[] tmpl_keeplist_bry = Bry_.Empty;
|
||||
public Xop_ctx Wtxt_ctx() {return wtxt_ctx;} private Xop_ctx wtxt_ctx;
|
||||
public void Tmpl_tkn_max_(int v) {
|
||||
if (v < 0) v = Int_.Max_value; // allow -1 as shortcut to deactivate
|
||||
tmpl_ctx.Tmpl_tkn_max_(v);
|
||||
wtxt_ctx.Tmpl_tkn_max_(v);
|
||||
}
|
||||
public void Init_by_wiki(Xowe_wiki wiki) {
|
||||
this.wiki = wiki; this.app = wiki.Appe(); this.parser = wiki.Parser_mgr().Main(); this.tkn_mkr = app.Parser_mgr().Tkn_mkr();
|
||||
this.tmpl_ctx = Xop_ctx.New__top(wiki); this.wtxt_ctx = Xop_ctx.New__top(wiki);
|
||||
Xop_lxr_mgr tmpl_lxr_mgr = Xop_lxr_mgr.Popup_lxr_mgr;
|
||||
tmpl_lxr_mgr.Init_by_wiki(wiki);
|
||||
this.tmpl_trie = tmpl_lxr_mgr.Trie(); this.wtxt_trie = parser.Wtxt_lxr_mgr().Trie();
|
||||
tmpl_ctx.Parse_tid_(Xop_parser_tid_.Tid__tmpl); wtxt_ctx.Parse_tid_(Xop_parser_tid_.Tid__wtxt);
|
||||
tmpl_ctx.Xnde_names_tid_(Xop_parser_tid_.Tid__wtxt);
|
||||
tmpl_ctx.Tid_is_popup_(true); wtxt_ctx.Tid_is_popup_(true);
|
||||
tmpl_root = tkn_mkr.Root(Bry_.Empty); wtxt_root = tkn_mkr.Root(Bry_.Empty);
|
||||
html_mkr.Ctor(app, wiki);
|
||||
cfg.Ellipsis_(wiki.Msg_mgr().Val_by_key_obj(Xow_popup_cfg.Msg_key_ellipsis));
|
||||
}
|
||||
public void Tmpl_keeplist_(Xop_keeplist_wiki v) {this.tmpl_keeplist = v;}
|
||||
public void Tmpl_keeplist_init_(byte[] raw) {
|
||||
if (tmpl_keeplist == null) {
|
||||
tmpl_keeplist = new Xop_keeplist_wiki(wiki);
|
||||
tmpl_ctx.Tmpl_keeplist_(tmpl_keeplist);
|
||||
}
|
||||
if (!Bry_.Has_at_end(raw, Byte_ascii.Nl_bry)) raw = Bry_.Add(raw, Byte_ascii.Nl_bry);
|
||||
tmpl_keeplist.Srl().Load_by_bry(raw);
|
||||
}
|
||||
private boolean Canceled(Xow_popup_itm popup_itm, Xog_tab_itm cur_tab) {return popup_itm.Canceled() || cur_tab != null && cur_tab.Tab_is_loading();}
|
||||
private void Init_ctxs(byte[] tmpl_src, Xoa_ttl ttl) {
|
||||
tmpl_ctx.Clear_all();
|
||||
tmpl_ctx.Page().Ttl_(ttl); // NOTE: must set cur_page, else page-dependent templates won't work; EX: {{FULLPAGENAME}}; PAGE:en.w:June_20; DATE:2014-06-20
|
||||
tmpl_ctx.Page().Html_data().Html_restricted_(data.Html_restricted()); // NOTE: must set data.Html_restricted() if Special:XowaPopupHistory
|
||||
tmpl_ctx.Parser__page_init(tmpl_root, tmpl_src);
|
||||
Wtxt_ctx_init(true, tmpl_src);
|
||||
wtxt_ctx.Page().Ttl_(ttl); // NOTE: must set cur_page, or rel lnkis won't work; EX: [[../A]]
|
||||
}
|
||||
public byte[] Parse(Xowe_wiki cur_wiki, Xoae_page page, Xog_tab_itm cur_tab, Xow_popup_itm popup_itm) { // NOTE: must pass cur_wiki for xwiki label; DATE:2014-07-02
|
||||
if (Bry_.Eq(popup_itm.Wiki_domain(), Xow_domain_itm_.Bry__wikidata)) {
|
||||
data.Wrdx_bfr().Add(app.Wiki_mgr().Wdata_mgr().Popup_text(page));
|
||||
}
|
||||
else {
|
||||
byte[] tmpl_src = page.Db().Text().Text_bry(); int tmpl_len = tmpl_src.length; if (tmpl_len == 0) return Bry_.Empty;
|
||||
int tmpl_bgn_orig = Xow_popup_parser_.Tmpl_bgn_get_(app, popup_itm, page.Ttl(), hdr_finder, tmpl_src, tmpl_len);
|
||||
int tmpl_bgn = tmpl_bgn_orig;
|
||||
int tmpl_read_len_cur = cfg.Tmpl_read_len();
|
||||
wrdx_mkr.Init();
|
||||
data.Init(cfg, popup_itm, tmpl_len);
|
||||
Init_ctxs(tmpl_src, page.Ttl());
|
||||
while (data.Words_needed_chk()) {
|
||||
if (Canceled(popup_itm, cur_tab)) return null;
|
||||
tmpl_root.Clear();
|
||||
int tmpl_end = tmpl_bgn + tmpl_read_len_cur; if (tmpl_end > tmpl_len) tmpl_end = tmpl_len; // limit to tmpl_len; EX: page is 16 bytes, but block is 1024
|
||||
int new_tmpl_bgn = parser.Parse_to_stack_end(tmpl_root, tmpl_ctx, tkn_mkr, tmpl_src, tmpl_len, tmpl_trie, tmpl_bgn, tmpl_end);
|
||||
if (Canceled(popup_itm, cur_tab)) return null;
|
||||
byte[] wtxt_bry = Parse_to_wtxt(tmpl_src);
|
||||
int wtxt_len = wtxt_bry.length;
|
||||
wtxt_root.Clear();
|
||||
int wtxt_bgn = (tmpl_bgn == Xop_parser_.Doc_bgn_bos) ? Xop_parser_.Doc_bgn_bos : 0; // if first pass, parse from -1; needed for lxrs which assume nl at bos; EX: "*a"
|
||||
if (Canceled(popup_itm, cur_tab)) return null;
|
||||
parser.Parse_to_src_end(wtxt_root, wtxt_ctx, tkn_mkr, wtxt_bry, wtxt_trie, wtxt_bgn, wtxt_len);
|
||||
if ( wtxt_ctx.Stack_len() > 0 // dangling lnki / hdr / tblw
|
||||
&& (tmpl_bgn + tmpl_read_len_cur) < data.Tmpl_max() // too much read; stop and give whatever's available; PAGE:en.w:List_of_air_forces; DATE:2014-06-18
|
||||
&& tmpl_read_len_cur < tmpl_len // only reparse if tmpl_read_len_cur is < entire page; needed for pages which have dangling items; EX:"<i>a"
|
||||
) {
|
||||
new_tmpl_bgn = tmpl_bgn;
|
||||
tmpl_read_len_cur = Xow_popup_parser_.Calc_read_len(wtxt_ctx, tmpl_read_len_cur, cfg.Tmpl_read_len(), tmpl_src, tmpl_bgn, tmpl_end);
|
||||
wtxt_ctx.Clear_all();
|
||||
}
|
||||
else {
|
||||
wrdx_mkr.Process_tkn(cfg, data, data.Wrdx_bfr(), wtxt_root, wtxt_bry, wtxt_len);
|
||||
tmpl_read_len_cur = cfg.Tmpl_read_len();
|
||||
}
|
||||
tmpl_bgn = new_tmpl_bgn;
|
||||
data.Tmpl_loop_count_add();
|
||||
if ( tmpl_bgn == tmpl_len // end of template
|
||||
|| tmpl_bgn - tmpl_bgn_orig > data.Tmpl_max() // too much read; stop and give whatever's available
|
||||
)
|
||||
break;
|
||||
}
|
||||
if (Canceled(popup_itm, cur_tab)) return null;
|
||||
Parse_wrdx_to_html(popup_itm, data.Wrdx_bfr());
|
||||
}
|
||||
byte[] rv = html_mkr.Bld(cur_wiki, page, popup_itm, data.Wrdx_bfr());
|
||||
return (Canceled(popup_itm, cur_tab)) ? null : rv;
|
||||
}
|
||||
private void Parse_wrdx_to_html(Xow_popup_itm popup_itm, Bry_bfr wrdx_bfr) {
|
||||
Adjust_wrdx_end(popup_itm, wrdx_bfr);
|
||||
wrdx_bfr.Add(cfg.Notoc()); // always add notoc at end
|
||||
byte[] wrdx_bry = wrdx_bfr.To_bry_and_clear();
|
||||
wtxt_root.Clear(); // now start parsing wrdx_bry from wtxt to html
|
||||
Wtxt_ctx_init(false, wrdx_bry);
|
||||
parser.Parse_to_src_end(wtxt_root, wtxt_ctx, tkn_mkr, wrdx_bry, wtxt_trie, Xop_parser_.Doc_bgn_bos, wrdx_bry.length);
|
||||
wtxt_ctx.Parser__page_term(wtxt_root, wrdx_bry, wrdx_bry.length);
|
||||
wiki.Html_mgr().Html_wtr().Write_doc(wrdx_bfr, wtxt_ctx, hctx, wrdx_bry, wtxt_root);
|
||||
wiki.Parser_mgr().Uniq_mgr().Parse(wrdx_bfr);
|
||||
}
|
||||
private void Adjust_wrdx_end(Xow_popup_itm popup_itm, Bry_bfr wrdx_bfr) {
|
||||
popup_itm.Words_found_(data.Words_found());
|
||||
if (popup_itm.Mode_all()) return; // mode_all needs no adjustments
|
||||
Xow_popup_word[] words = data.Words_found_ary();
|
||||
int words_len = words.length;
|
||||
int last_word_idx = -1; Xow_popup_word last_hdr_tkn = null;
|
||||
int words_needed_val = data.Words_needed_val();
|
||||
if (cfg.Read_til_stop_fwd() != -1) {
|
||||
for (int i = words_needed_val; i < words_len; ++i) { // find hdr after orig
|
||||
Xow_popup_word word = words[i];
|
||||
if (word.Tid() == Xop_tkn_itm_.Tid_hdr) {
|
||||
last_hdr_tkn = word;
|
||||
break;
|
||||
}
|
||||
}
|
||||
last_word_idx = (last_hdr_tkn == null) // no hdr found
|
||||
? words_needed_val - List_adp_.Base1 // get last word
|
||||
: last_hdr_tkn.Idx() - 1 // get word before hdr
|
||||
;
|
||||
if (last_word_idx >= words_len)
|
||||
last_word_idx = -1;
|
||||
}
|
||||
boolean page_partially_parsed = data.Words_found() == data.Words_needed_max(); // adhoc way of figuring out if parsing prematurely stopped before eos; PAGE:en.q:Anaximander DATE:2014-07-02
|
||||
if ( cfg.Read_til_stop_bwd() != -1
|
||||
&& page_partially_parsed // never read bwd if entire tmpl is read; DATE:2014-07-01
|
||||
) {
|
||||
int read_bwd_end = last_word_idx == -1 ? words_len - 1 : last_word_idx; // if !cfg.Read_til_stop_fwd() use last_wrd, else use read_fwd's last_word
|
||||
int read_bwd_bgn = read_bwd_end - cfg.Read_til_stop_bwd();
|
||||
if (read_bwd_bgn > -1) { // handle pages with "==a==" near start
|
||||
int last_hdr_idx = -1;
|
||||
for (int i = read_bwd_end; i >= read_bwd_bgn; i--) {
|
||||
Xow_popup_word word = words[i];
|
||||
if (word.Tid() == Xop_tkn_itm_.Tid_hdr) {
|
||||
if (last_hdr_idx == -1) // last_hdr_idx not set
|
||||
last_hdr_idx = i; // set it
|
||||
else { // last_hdr_idx set
|
||||
if (i + 1 == last_hdr_idx) // two consecutive hdrs; update earlier and continue
|
||||
last_hdr_idx = i;
|
||||
else // earlier hdr; ignore it and take later one
|
||||
break;
|
||||
}
|
||||
last_hdr_tkn = word;
|
||||
}
|
||||
}
|
||||
if (last_hdr_idx != -1) // hdr found
|
||||
last_word_idx = last_hdr_idx - 1; // get word before last_word_idx
|
||||
}
|
||||
}
|
||||
if (last_word_idx != -1) {
|
||||
Xow_popup_word last_word = words[last_word_idx];
|
||||
wrdx_bfr.Delete_rng_to_end(last_word.Bfr_end());// delete everything after last_word
|
||||
popup_itm.Words_found_(last_word_idx + List_adp_.Base1); // last_word_idx = 0 -> words_found = 1
|
||||
if (last_word.Tid() == Xop_tkn_itm_.Tid_hdr) // on odd case where hdr is still last word, add \n else text will literally be "==A==" b/c no trailing \n
|
||||
wrdx_bfr.Add_byte_nl();
|
||||
}
|
||||
if (last_hdr_tkn != null) {
|
||||
wrdx_bfr.Trim_end(Byte_ascii.Nl);
|
||||
|
||||
// reparse hdr b/c existing hdr_tkn has Src_bgn / Src_end, but no src;
|
||||
byte[] hdr_src = Bry_.Mid(wrdx_bfr.Bfr(), last_hdr_tkn.Bfr_bgn(), last_hdr_tkn.Bfr_end());
|
||||
Xop_root_tkn hdr_root = wtxt_ctx.Tkn_mkr().Root(hdr_src);
|
||||
wiki.Parser_mgr().Main().Parse_wtxt_to_wdom(hdr_root, wtxt_ctx, wtxt_ctx.Tkn_mkr(), hdr_src, 0);
|
||||
byte[] last_hdr_bry = Bry_.Empty;
|
||||
for (int i = 0; i < hdr_root.Subs_len(); ++i) {
|
||||
Xop_tkn_itm sub = hdr_root.Subs_get(i);
|
||||
if (sub.Tkn_tid() == Xop_tkn_itm_.Tid_hdr) {
|
||||
last_hdr_bry = Xoh_hdr_html.Bld_hdr_html(hdr_html_bfr, wiki.Html_mgr().Html_wtr(), wtxt_ctx.Page(), wtxt_ctx, hctx, hdr_src, (Xop_hdr_tkn)sub);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// byte[] last_hdr_bry = ((Xop_hdr_tkn)last_hdr_tkn.Tkn()).Hdr_html_text();
|
||||
html_mkr.Fmtr_next_sect().Bld_bfr_one(wrdx_bfr, last_hdr_bry);
|
||||
}
|
||||
else {
|
||||
if (page_partially_parsed)
|
||||
wrdx_bfr.Add(cfg.Ellipsis());
|
||||
}
|
||||
}
|
||||
private void Wtxt_ctx_init(boolean incremental, byte[] bry) {
|
||||
wtxt_ctx.Clear_all();
|
||||
wtxt_ctx.Page().Html_data().Html_restricted_(data.Html_restricted());
|
||||
wtxt_ctx.Para().Enabled_(!incremental); // NOTE: if incremental, disable para; easier to work with \n rather than <p>; also, must be enabled before Page_bgn; DATE:2014-06-18DATE:2014-06-18
|
||||
wtxt_ctx.Lnke().Dangling_goes_on_stack_(incremental);
|
||||
wtxt_ctx.Parser__page_init(wtxt_root, bry);
|
||||
}
|
||||
private byte[] Parse_to_wtxt(byte[] src) {
|
||||
int subs_len = tmpl_root.Subs_len();
|
||||
for (int i = 0; i < subs_len; i++)
|
||||
tmpl_root.Subs_get(i).Tmpl_compile(tmpl_ctx, src, tmpl_props);
|
||||
return Xot_tmpl_wtr.Instance.Write_all(tmpl_ctx, tmpl_root, src);
|
||||
}
|
||||
}
|
||||
class Xow_popup_parser_ {
|
||||
public static int Tmpl_bgn_get_(Xoae_app app, Xow_popup_itm itm, Xoa_ttl page_ttl, Xow_popup_anchor_finder hdr_finder, byte[] src, int src_len) {
|
||||
int rv = Xop_parser_.Doc_bgn_bos; if (itm.Mode_all()) return rv;
|
||||
byte[] anch = itm.Page_href()[0] == Byte_ascii.Hash ? Bry_.Mid(gplx.langs.htmls.encoders.Gfo_url_encoder_.Href.Decode(itm.Page_href()), 1) : page_ttl.Anch_txt();
|
||||
if (anch == null) return rv;
|
||||
int hdr_bgn = hdr_finder.Find(src, src_len, anch, rv); // NOTE: starting search from Xop_parser_.Doc_bgn_bos
|
||||
return hdr_bgn == Bry_find_.Not_found ? rv : hdr_bgn;
|
||||
}
|
||||
public static int Calc_read_len(Xop_ctx ctx, int tmpl_read_cur, int tmpl_read_len, byte[] src, int bgn, int end) {// DATE:2014-07-19
|
||||
int rv_default = tmpl_read_cur + tmpl_read_len;
|
||||
Xop_tkn_itm tkn = Get_expensive_dangling_tkn(ctx);
|
||||
if (tkn == null) return rv_default; // no expensive tkns found; return rv_default; EX: headers are not considered expensive
|
||||
int tkn_end = Calc_tkn_end(tkn, src, end);
|
||||
if (tkn_end == Bry_find_.Not_found) return rv_default; // no end found; return rv_default; might want to return src.length at future date
|
||||
return tkn_end - bgn;
|
||||
}
|
||||
private static Xop_tkn_itm Get_expensive_dangling_tkn(Xop_ctx ctx) {
|
||||
int stack_len = ctx.Stack_len();
|
||||
if (stack_len == 0) return null; // no dangling tkns; just add tmpl_read_len; shouldn't happen, but keep prior behavior
|
||||
for (int i = 0; i < stack_len; ++i) {
|
||||
Xop_tkn_itm tkn = ctx.Stack_get(i);
|
||||
switch (tkn.Tkn_tid()) {
|
||||
case Xop_tkn_itm_.Tid_tblw_tb:
|
||||
return tkn;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private static int Calc_tkn_end(Xop_tkn_itm tkn, byte[] src, int pos) {
|
||||
byte[] end_bry = null;
|
||||
switch (tkn.Tkn_tid()) {
|
||||
case Xop_tkn_itm_.Tid_tblw_tb: // "{|" can be expensive; PAGE:en.w:List_of_countries_and_dependencies_by_area; DATE:2014-07-19
|
||||
end_bry = Xop_tblw_lxr.Hook_te;
|
||||
break;
|
||||
}
|
||||
if (end_bry == null) return Bry_find_.Not_found; // no end defined for tkn; return null which should revert to dflt
|
||||
int end_pos = Bry_find_.Find_fwd(src, end_bry, pos);
|
||||
return end_pos == Bry_find_.Not_found ? Bry_find_.Not_found : end_pos + end_bry.length;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.htmls.modules.popups; import gplx.*; import gplx.xowa.*; import gplx.xowa.htmls.*; import gplx.xowa.htmls.modules.*;
|
||||
import gplx.xowa.apps.apis.xowa.html.modules.*;
|
||||
import gplx.xowa.parsers.*;
|
||||
public class Xow_popup_parser_data {
|
||||
public int Tmpl_max() {return tmpl_max;} private int tmpl_max;
|
||||
public int Words_needed_val() {return words_needed_val;} private int words_needed_val;
|
||||
public int Words_needed_max() {return words_needed_max;} private int words_needed_max;
|
||||
private int words_needed_min;
|
||||
public int Words_found() {return words_found;} private int words_found;
|
||||
public Bry_bfr Wrdx_bfr() {return wrdx_bfr;} private Bry_bfr wrdx_bfr = Bry_bfr_.Reset(255);
|
||||
public Xow_popup_word[] Words_found_ary() {return (Xow_popup_word[])words_found_list.To_ary_and_clear(Xow_popup_word.class);} private List_adp words_found_list = List_adp_.New();
|
||||
public int Tmpl_loop_count() {return tmpl_loop_count;} private int tmpl_loop_count;
|
||||
public void Tmpl_loop_count_add() {++tmpl_loop_count;}
|
||||
private Xow_popup_itm popup_itm;
|
||||
public boolean Html_restricted() {return html_restricted;} private boolean html_restricted;
|
||||
public void Init(Xow_popup_cfg cfg, Xow_popup_itm popup_itm, int tmpl_len) {
|
||||
words_found = tmpl_loop_count= 0;
|
||||
words_found_list.Clear();
|
||||
wrdx_bfr.Clear();
|
||||
|
||||
html_restricted = !gplx.xowa.specials.xowa.popup_history.Popup_history_page.Ttl_chk(popup_itm.Page_ttl());
|
||||
this.popup_itm = popup_itm;
|
||||
if (tmpl_len < cfg.Show_all_if_less_than()) popup_itm.Mode_all_();
|
||||
words_needed_min = popup_itm.Words_found();
|
||||
words_needed_val = words_needed_max = popup_itm.Words_needed();
|
||||
switch (popup_itm.Mode()) {
|
||||
case Xow_popup_itm.Mode_tid_all:
|
||||
tmpl_max = Int_.Max_value;
|
||||
break;
|
||||
case Xow_popup_itm.Mode_tid_init:
|
||||
case Xow_popup_itm.Mode_tid_more:
|
||||
tmpl_max = cfg.Tmpl_read_max();
|
||||
if (cfg.Read_til_stop_fwd() > 0)
|
||||
words_needed_max += cfg.Read_til_stop_fwd();
|
||||
break;
|
||||
}
|
||||
}
|
||||
public boolean Words_needed_chk() {return words_found < words_needed_max;}
|
||||
public void Words_found_add(Xop_tkn_itm tkn) {
|
||||
words_found_list.Add(new Xow_popup_word(tkn.Tkn_tid(), wrdx_bfr.Len(), words_found, tkn.Src_bgn(), tkn.Src_end(), tkn));
|
||||
++words_found;
|
||||
}
|
||||
public boolean Stop_if_hdr_after_chk(Xow_popup_cfg cfg) {
|
||||
boolean rv = words_found > words_needed_min + cfg.Stop_if_hdr_after() && !popup_itm.Mode_all();
|
||||
if (rv) words_needed_max = words_found;
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,522 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.htmls.modules.popups; import gplx.*; import gplx.xowa.*; import gplx.xowa.htmls.*; import gplx.xowa.htmls.modules.*;
|
||||
import org.junit.*; import gplx.core.primitives.*;
|
||||
import gplx.xowa.apps.apis.xowa.html.modules.*;
|
||||
import gplx.xowa.wikis.nss.*;
|
||||
import gplx.xowa.guis.views.*;
|
||||
public class Xow_popup_parser_tst {
|
||||
@Before public void init() {fxt.Clear();} private final Xop_popup_parser_fxt fxt = new Xop_popup_parser_fxt();
|
||||
@Test public void Text_chars_one() {
|
||||
fxt.Test_parse
|
||||
( "a b c d", String_.Concat_lines_nl_skip_last
|
||||
( "<p>a b"
|
||||
, "</p>"
|
||||
));
|
||||
}
|
||||
@Test public void Text_chars_many() { // PURPOSE: text.read_spans_scan
|
||||
fxt.Test_parse
|
||||
( "abc def ghi", String_.Concat_lines_nl_skip_last
|
||||
( "<p>abc def"
|
||||
, "</p>"
|
||||
));
|
||||
}
|
||||
@Test public void Text_chars_bound() {// PURPOSE: text.word_spans_scan
|
||||
fxt.Test_parse
|
||||
( "abcde fghij k l", String_.Concat_lines_nl_skip_last
|
||||
( "<p>abcde fghij"
|
||||
, "</p>"
|
||||
));
|
||||
}
|
||||
@Test public void Apos() {
|
||||
fxt.Test_parse
|
||||
( "'''ab''' ''c'' de", String_.Concat_lines_nl_skip_last
|
||||
( "<p><b>ab</b> <i>c"
|
||||
, "</p>"
|
||||
, "</i>"
|
||||
));
|
||||
}
|
||||
@Test public void Lnki() {
|
||||
fxt.Test_parse("a [[b|c d e]] f"
|
||||
, String_.Concat_lines_nl_skip_last
|
||||
( "<p>a <a href=\"/site/en.wiki/wiki/B\">c d e</a>"
|
||||
, "</p>"
|
||||
));
|
||||
}
|
||||
@Test public void Lnke_brack() { // PURPOSE: count lnke caption words; DATE:2014-06-20
|
||||
fxt.Init_tmpl_read_len_(32).Init_word_needed_(5).Test_parse
|
||||
( "a [http://b.org b c] d e f g", String_.Concat_lines_nl_skip_last
|
||||
( "<p>a b c d e"
|
||||
, "</p>"
|
||||
));
|
||||
}
|
||||
@Test public void Lnke_text() { // PURPOSE: count entire lnke as one word
|
||||
fxt.Init_tmpl_read_len_(32).Init_word_needed_(5).Test_parse
|
||||
( "a http://b.org c d e f g", String_.Concat_lines_nl_skip_last
|
||||
( "<p>a <a href=\"http://b.org\" rel=\"nofollow\" class=\"external free\">http://b.org</a> c d e"
|
||||
, "</p>"
|
||||
));
|
||||
}
|
||||
@Test public void Lnke_dangling() { // PURPOSE: handle dangling lnke; DATE:2014-06-20
|
||||
fxt.Test_parse
|
||||
( "a [http://b.org c d] e f g", String_.Concat_lines_nl_skip_last // NOTE: scan_len = 4, so 1st pass will be "a [h"
|
||||
( "<p>a c d" // NOTE: (a) lnke correctly parsed, else would see "[" or "http"; (b) "c d" counts as 1 word
|
||||
, "</p>"
|
||||
));
|
||||
}
|
||||
@Test public void Hdr() {
|
||||
fxt.Test_parse
|
||||
( "a\n===b===\n c", String_.Concat_lines_nl_skip_last
|
||||
( "<p>a"
|
||||
, "</p>"
|
||||
, ""
|
||||
, "<h3>b</h3>"
|
||||
));
|
||||
}
|
||||
@Test public void Hdr_one_word() { // PURPOSE: hdr.entire_tkn_counts_as_one_word
|
||||
fxt.Test_parse
|
||||
( "===a b c===\nd", String_.Concat_lines_nl_skip_last
|
||||
( "<h3>a b c</h3>"
|
||||
, ""
|
||||
, "<p>d"
|
||||
, "</p>"
|
||||
));
|
||||
}
|
||||
@Test public void Hdr_para() { // PURPOSE: hdr.para; handle para mode and hdr (para causes trailing \n to be para, not \n); PAGE:en.w:Flavius_Valerius_Severus DATE:2014-06-17
|
||||
fxt.Init_para_enabled_(true).Test_parse(String_.Concat_lines_nl_skip_last
|
||||
( ""
|
||||
, "a"
|
||||
, ""
|
||||
, "==b=="
|
||||
, "c"
|
||||
, ""
|
||||
, "d"
|
||||
), String_.Concat_lines_nl_skip_last
|
||||
( "<p>a"
|
||||
, "</p>"
|
||||
, ""
|
||||
, "<h2>b</h2>"
|
||||
, ""
|
||||
));
|
||||
}
|
||||
@Test public void List() {
|
||||
fxt.Test_parse(String_.Concat_lines_nl_skip_last
|
||||
( "a"
|
||||
, "*b"
|
||||
, "c"
|
||||
), String_.Concat_lines_nl_skip_last
|
||||
( "<p>a"
|
||||
, "</p>"
|
||||
, ""
|
||||
, "<ul>"
|
||||
, " <li>b"
|
||||
, " </li>"
|
||||
, "</ul>"
|
||||
));
|
||||
}
|
||||
@Test public void Xnde_pair() {
|
||||
fxt.Test_parse
|
||||
( "<span id='a'>b</span>"
|
||||
, String_.Concat_lines_nl_skip_last
|
||||
( "<p><span id='a'>b</span>"
|
||||
, "</p>"
|
||||
));
|
||||
}
|
||||
@Test public void Xnde_inline() {
|
||||
fxt.Test_parse
|
||||
( "<span id='a'/>"
|
||||
, String_.Concat_lines_nl_skip_last
|
||||
( "<p><span id='a'></span>"
|
||||
, "</p>"
|
||||
));
|
||||
}
|
||||
@Test public void Xnde_br() { // PURPOSE: check that br is added correctly; PAGE:en.q:Earth; DATE:2014-06-30
|
||||
fxt.Init_word_needed_(3).Test_parse
|
||||
( "a<br>b<br/>"
|
||||
, String_.Concat_lines_nl_skip_last
|
||||
( "<p>a<br>b<br/>"
|
||||
, "</p>"
|
||||
));
|
||||
}
|
||||
@Test public void Xnde_math() { // PURPOSE: <math> should be treated as one word; PAGE:en.w:System_of_polynomial_equations; DATE:2014-07-01
|
||||
fxt .Init_word_needed_(5) // need to read more words to pick up 1st word after header
|
||||
.Init_read_til_stop_bwd_(2) // need to do read_bwd to start counting before ==e== into <math> node
|
||||
.Test_parse
|
||||
( "a <math>b c d</math> \n==e==\nf g h i"
|
||||
, String_.Concat_lines_nl_skip_last
|
||||
( "<p>a <span id='xowa_math_txt_0'>b c d</span> (e)" // used to fail as <p>a <math>b c d (e)
|
||||
, "</p>"
|
||||
));
|
||||
}
|
||||
@Test public void Ignore_tblw() {// also checks for tbl spanning multiple blocks; PAGE:en.w:Stratosphere; DATE:2014-06-17
|
||||
fxt.Test_parse(String_.Concat_lines_nl_skip_last
|
||||
( "a "
|
||||
, "{|"
|
||||
, "|-"
|
||||
, "|b"
|
||||
, "|} c"
|
||||
), String_.Concat_lines_nl_skip_last
|
||||
( "<p>a c"
|
||||
, "</p>"
|
||||
));
|
||||
}
|
||||
@Test public void Ignore_tblw_nested() {// PAGE:en.w:Cosmoloyg; DATE:2014-06-17
|
||||
fxt.Test_parse(String_.Concat_lines_nl_skip_last
|
||||
( "<span>a"
|
||||
, "{|"
|
||||
, "|-"
|
||||
, "|b"
|
||||
, "|}"
|
||||
, "</span>"
|
||||
), String_.Concat_lines_nl_skip_last
|
||||
( "<p><span>a"
|
||||
, "</span>"
|
||||
, "</p>"
|
||||
));
|
||||
}
|
||||
@Test public void Ignore_tblx() {
|
||||
fxt.Test_parse
|
||||
( "a <table><tr><td>b</td></tr></table> c"
|
||||
, String_.Concat_lines_nl_skip_last
|
||||
( "<p>a c"
|
||||
, "</p>"
|
||||
));
|
||||
}
|
||||
@Test public void Ignore_ref() {
|
||||
fxt.Test_parse
|
||||
( "a <ref>b</ref> c"
|
||||
, String_.Concat_lines_nl_skip_last
|
||||
( "<p>a c"
|
||||
, "</p>"
|
||||
));
|
||||
}
|
||||
@Test public void Ignore_div() {
|
||||
fxt.Test_parse
|
||||
( "a <div>b</div> c"
|
||||
, String_.Concat_lines_nl_skip_last
|
||||
( "<p>a c"
|
||||
, "</p>"
|
||||
));
|
||||
}
|
||||
@Test public void Ignore_space_bos() { // pre. ignore spaces, else pre; PAGE:en.w:Volcano; en.w:War_elephant; DATE:2014-06-17
|
||||
fxt.Test_parse
|
||||
( "<div>a</div> b c d" // spaces before "b" are ignored
|
||||
, String_.Concat_lines_nl_skip_last
|
||||
( "<p>b c"
|
||||
, "</p>"
|
||||
));
|
||||
}
|
||||
@Test public void Ignore_space_nl() {
|
||||
fxt.Test_parse(String_.Concat_lines_nl_skip_last
|
||||
( "a"
|
||||
, "<div>b</div> c" // space before "c" is ignored
|
||||
), String_.Concat_lines_nl_skip_last
|
||||
( "<p>a"
|
||||
, "c"
|
||||
, "</p>"
|
||||
));
|
||||
}
|
||||
@Test public void Ignore_nl_bos() {
|
||||
fxt.Test_parse(String_.Concat_lines_nl_skip_last
|
||||
( ""
|
||||
, ""
|
||||
, "a"
|
||||
), String_.Concat_lines_nl_skip_last
|
||||
( "<p>a"
|
||||
, "</p>"
|
||||
));
|
||||
}
|
||||
@Test public void Ignore_nl_multiple() {
|
||||
fxt.Test_parse(String_.Concat_lines_nl_skip_last
|
||||
( "a"
|
||||
, ""
|
||||
, ""
|
||||
, "" // ignored
|
||||
, "b"
|
||||
), String_.Concat_lines_nl_skip_last
|
||||
( "<p>a"
|
||||
, "</p>"
|
||||
, ""
|
||||
, "<p>b"
|
||||
, "</p>"
|
||||
));
|
||||
}
|
||||
@Test public void Ignore_nl_hdr() {
|
||||
fxt.Test_parse(String_.Concat_lines_nl_skip_last
|
||||
( "a"
|
||||
, ""
|
||||
, ""
|
||||
, "" // ignored
|
||||
, "==b=="
|
||||
), String_.Concat_lines_nl_skip_last
|
||||
( "<p>a"
|
||||
, "</p>"
|
||||
, ""
|
||||
, "<h2>b</h2>"
|
||||
));
|
||||
}
|
||||
@Test public void Ignore_lnki_file() {
|
||||
fxt.Test_parse
|
||||
( "a [[File:b.png|thumb]] c"
|
||||
, String_.Concat_lines_nl_skip_last
|
||||
( "<p>a c"
|
||||
, "</p>"
|
||||
));
|
||||
}
|
||||
@Test public void Ignore_gallery() {
|
||||
fxt.Test_parse
|
||||
( "a <gallery>File:B.png|c</gallery> d"
|
||||
, String_.Concat_lines_nl_skip_last
|
||||
( "<p>a d"
|
||||
, "</p>"
|
||||
));
|
||||
}
|
||||
@Test public void Ignore_xnde() {
|
||||
fxt.Test_parse
|
||||
( "a <span id='coordinates'>b</span> c"
|
||||
, String_.Concat_lines_nl_skip_last
|
||||
( "<p>a c"
|
||||
, "</p>"
|
||||
));
|
||||
}
|
||||
@Test public void Dangling() { // make sure dangling nodes don't fail
|
||||
fxt.Test_parse
|
||||
( "<i>a"
|
||||
, String_.Concat_lines_nl_skip_last
|
||||
( "<p><i>a</i>"
|
||||
, "</p>"
|
||||
));
|
||||
}
|
||||
@Test public void End_early_dangling() { // PURPOSE: dangling tkn is too long; end early; PAGE:en.w:List_of_air_forces; DATE:2014-06-18
|
||||
fxt.Init_tmpl_read_max_(8).Test_parse
|
||||
( "a [[File:Test.png]] k"
|
||||
, String_.Concat_lines_nl_skip_last
|
||||
( "<p>a "
|
||||
, "</p>"
|
||||
));
|
||||
}
|
||||
@Test public void Ellipsis_() {
|
||||
fxt.Init_ellipsis_("...").Test_parse
|
||||
( "a b c d"
|
||||
, String_.Concat_lines_nl_skip_last
|
||||
( "<p>a b..."
|
||||
, "</p>"
|
||||
));
|
||||
fxt.Test_parse // no ellipsis: entire extract
|
||||
( "a"
|
||||
, String_.Concat_lines_nl_skip_last
|
||||
( "<p>a"
|
||||
, "</p>"
|
||||
));
|
||||
fxt.Test_parse // no ellipsis: entire extract multiple reads
|
||||
( "a <div>b</div>"
|
||||
, String_.Concat_lines_nl_skip_last
|
||||
( "<p>a "
|
||||
, "</p>"
|
||||
));
|
||||
}
|
||||
@Test public void Ns_allowed() {
|
||||
fxt.Test_ns_allowed("Help" , Xow_ns_.Tid__help);
|
||||
fxt.Test_ns_allowed("(Main)" , Xow_ns_.Tid__main);
|
||||
fxt.Test_ns_allowed("" );
|
||||
fxt.Test_ns_allowed("(Main)|Help" , Xow_ns_.Tid__main, Xow_ns_.Tid__help);
|
||||
}
|
||||
@Test public void Read_til_stop_fwd() {
|
||||
fxt.Init_word_needed_(2).Init_read_til_stop_fwd_(2) // read fwd found hdr
|
||||
.Test_parse("a b c\n==d==", String_.Concat_lines_nl_skip_last
|
||||
( "<p>a b c (d)"
|
||||
, "</p>"
|
||||
));
|
||||
fxt.Init_word_needed_(2).Init_read_til_stop_fwd_(2) // read fwd did not find hdr; reset back to min
|
||||
.Test_parse("a b c d", String_.Concat_lines_nl_skip_last
|
||||
( "<p>a b"
|
||||
, "</p>"
|
||||
));
|
||||
}
|
||||
@Test public void Read_til_stop_bwd() {
|
||||
fxt.Init_word_needed_(8).Init_read_til_stop_bwd_(4) // read bwd found hdr
|
||||
.Test_parse("01 02 03 04 05\n==06==\n07 08 09 10 11 12 13 14 15 16", String_.Concat_lines_nl_skip_last
|
||||
( "<p>01 02 03 04 05 (06)"
|
||||
, "</p>"
|
||||
));
|
||||
fxt.Init_tmpl_read_len_(40).Init_word_needed_(5).Init_read_til_stop_bwd_(3) // read bwd at eos should not return "next_sect"; DATE:2014-07-01
|
||||
.Test_parse("01 02 03 \n==04==\n", String_.Concat_lines_nl_skip_last
|
||||
( "<p>01 02 03 "
|
||||
, "</p>"
|
||||
, ""
|
||||
, "<h2>04</h2>"
|
||||
));
|
||||
}
|
||||
@Test public void Stop_if_hdr_after() {
|
||||
fxt.Init_word_needed_(5).Init_stop_if_hdr_after_(1)
|
||||
.Test_parse("a b\n==c==\nd e", String_.Concat_lines_nl_skip_last
|
||||
( "<p>a b"
|
||||
, "</p>"
|
||||
, ""
|
||||
, "<h2>c</h2>"
|
||||
));
|
||||
}
|
||||
@Test public void Anchor() {
|
||||
fxt.Test_parse(String_.Concat_lines_nl_skip_last
|
||||
( "a b c d"
|
||||
, ""
|
||||
, "== e =="
|
||||
, "f g h i"
|
||||
), "#e", String_.Concat_lines_nl_skip_last
|
||||
( "<h2> e </h2>"
|
||||
, ""
|
||||
, "<p>f"
|
||||
, "</p>"
|
||||
));
|
||||
}
|
||||
@Test public void Anchor_underline() {
|
||||
fxt.Test_parse(String_.Concat_lines_nl_skip_last
|
||||
( "a b c d"
|
||||
, ""
|
||||
, "== e f =="
|
||||
, "g h i"
|
||||
), "#e_f", String_.Concat_lines_nl_skip_last
|
||||
( "<h2> e f </h2>"
|
||||
, ""
|
||||
, "<p>g"
|
||||
, "</p>"
|
||||
));
|
||||
}
|
||||
@Test public void Tmpl_tkn_max() {
|
||||
fxt.Init_tmpl_tkn_max_(5).Init_page("Template:A", "a"); // eval
|
||||
fxt.Test_parse
|
||||
( "{{A}}"
|
||||
, String_.Concat_lines_nl_skip_last
|
||||
( "<p>a"
|
||||
, "</p>"
|
||||
));
|
||||
fxt.Test_parse("{{A|b|c}}" , ""); // skip; NOTE: output should be blank, not <p>\n</p>; PAGE:en.w:List_of_countries_by_GDP_(PPP); DATE:2014-07-01
|
||||
}
|
||||
@Test public void Tmpl_tkn_max__comment_and_tblw() { // PURPOSE: garbled popup when tmpl_tkn_max is set and comments in front of tblw; PAGE:en.w:Gwynedd; DATE:2014-07-01
|
||||
fxt .Init_tmpl_tkn_max_(5) // set tmpl_tkn_max
|
||||
.Init_tmpl_read_len_(20) // set read_len to 20 (must read entire "<!---->\n{|" at once
|
||||
.Test_parse(String_.Concat_lines_nl_skip_last
|
||||
( "{{A|b}}"
|
||||
, "{{A|b}}"
|
||||
, "{|"
|
||||
, "|-"
|
||||
, "|a b c d"
|
||||
, "|}"
|
||||
), ""); // should be blank, not <table>]
|
||||
}
|
||||
@Test public void Tmpl_tkn_max__apos() { // PURPOSE: handle apos around skipped tmpl token; PAGE:en.w:Somalia; DATE:2014-07-02
|
||||
fxt.Init_tmpl_tkn_max_(5).Test_parse("a''{{A|b}}''b", String_.Concat_lines_nl_skip_last
|
||||
( "<p>a<i> </i>b"
|
||||
, "</p>"
|
||||
));
|
||||
}
|
||||
@Test public void Notoc_and_para_issue() { // PURPOSE.fix: issue with "\s__NOTOC__" and "a\n"b; PAGE:en.w:Spain; DATE:2014-07-05
|
||||
fxt.Init_word_needed_(3).Init_notoc_(" __NOTOC__").Test_parse("a\nb", String_.Concat_lines_nl_skip_last
|
||||
( "<p>a" // was <p>a</p>b
|
||||
, "b "
|
||||
, "</p>"
|
||||
));
|
||||
}
|
||||
@Test public void Test_Assert_at_end() {
|
||||
fxt.Test_Assert_at_end("a" , "a\n"); // add one
|
||||
fxt.Test_Assert_at_end("a\n" , "a\n"); // noop
|
||||
fxt.Test_Assert_at_end("a\n\n\n" , "a\n"); // remove til one
|
||||
fxt.Test_Assert_at_end("" , ""); // empty check
|
||||
}
|
||||
@Test public void Skip_to_end__tblw() { // PURPOSE: skip to end of tblw; PAGE:en.w:List_of_countries_and_dependencies_by_area; DATE:2014-07-19
|
||||
fxt.Init_tmpl_read_len_(4).Test_parse
|
||||
( String_.Concat_lines_nl_skip_last
|
||||
( "a"
|
||||
, "{|"
|
||||
, "|-"
|
||||
, "|b"
|
||||
, "|c"
|
||||
, "|d"
|
||||
, "|}"
|
||||
)
|
||||
, String_.Concat_lines_nl_skip_last
|
||||
( "<p>a"
|
||||
, "</p>"
|
||||
));
|
||||
fxt.Expd_tmpl_loop_count(2);
|
||||
}
|
||||
}
|
||||
class Xop_popup_parser_fxt {
|
||||
private Xow_popup_parser parser; private Xowe_wiki wiki;
|
||||
private int word_min = 2;
|
||||
public void Clear() {
|
||||
Xoae_app app = Xoa_app_fxt.Make__app__edit();
|
||||
this.wiki = Xoa_app_fxt.Make__wiki__edit(app, "en.wiki");
|
||||
parser = wiki.Html_mgr().Head_mgr().Popup_mgr().Parser();
|
||||
parser.Init_by_wiki(wiki);
|
||||
parser.Cfg().Tmpl_read_len_(4);
|
||||
parser.Cfg().Tmpl_read_max_(32 * Io_mgr.Len_kb);
|
||||
parser.Cfg().Ellipsis_(Bry_.Empty);
|
||||
parser.Cfg().Notoc_(Bry_.Empty);
|
||||
parser.Cfg().Show_all_if_less_than_(-1);
|
||||
parser.Cfg().Read_til_stop_fwd_(-1);
|
||||
parser.Cfg().Read_til_stop_bwd_(-1);
|
||||
parser.Cfg().Stop_if_hdr_after_(-1);
|
||||
parser.Html_mkr().Fmtr_popup().Fmt_("~{content}");
|
||||
parser.Html_mkr().Output_js_clean_(false);
|
||||
parser.Html_mkr().Output_tidy_(false);
|
||||
parser.Html_mkr().Fmtr_next_sect().Fmt_(" (~{next_sect_val})");
|
||||
parser.Wrdx_mkr().Xnde_ignore_ids_(Bry_.new_a7("coordinates"));
|
||||
word_min = 2;
|
||||
}
|
||||
public Xop_popup_parser_fxt Init_notoc_(String v) {parser.Cfg().Notoc_(Bry_.new_u8(v)); return this;}
|
||||
public Xop_popup_parser_fxt Init_tmpl_read_len_(int v) {parser.Cfg().Tmpl_read_len_(v); return this;}
|
||||
public Xop_popup_parser_fxt Init_tmpl_read_max_(int v) {parser.Cfg().Tmpl_read_max_(v); return this;}
|
||||
public Xop_popup_parser_fxt Init_word_needed_(int v) {word_min = v; return this;}
|
||||
public Xop_popup_parser_fxt Init_para_enabled_(boolean v) {parser.Wtxt_ctx().Para().Enabled_(v); return this;}
|
||||
public Xop_popup_parser_fxt Init_ellipsis_(String v) {parser.Cfg().Ellipsis_(Bry_.new_u8(v)); return this;}
|
||||
public Xop_popup_parser_fxt Init_read_til_stop_fwd_(int v) {parser.Cfg().Read_til_stop_fwd_(v); return this;}
|
||||
public Xop_popup_parser_fxt Init_read_til_stop_bwd_(int v) {parser.Cfg().Read_til_stop_bwd_(v); return this;}
|
||||
public Xop_popup_parser_fxt Init_stop_if_hdr_after_(int v) {parser.Cfg().Stop_if_hdr_after_(v); return this;}
|
||||
public Xop_popup_parser_fxt Init_tmpl_tkn_max_(int v) {parser.Tmpl_tkn_max_(v); return this;}
|
||||
public Xop_popup_parser_fxt Init_fmtr_next_sect_(String v) {parser.Html_mkr().Fmtr_next_sect().Fmt_(v); return this;}
|
||||
public Xop_popup_parser_fxt Init_page(String ttl, String txt) {Xop_fxt.Init_page_create_static(wiki, ttl, txt); return this;}
|
||||
public Xop_popup_parser_fxt Expd_tmpl_loop_count(int expd) {Tfds.Eq(expd, parser.Data().Tmpl_loop_count()); return this;}
|
||||
public Xop_popup_parser_fxt Test_ns_allowed(String raw, int... expd) {
|
||||
Int_obj_ref[] ids = Xow_popup_mgr.Ns_allowed_parse(wiki, Bry_.new_u8(raw));
|
||||
Tfds.Eq_ary(expd, To_int_ary(ids));
|
||||
return this;
|
||||
}
|
||||
private static int[] To_int_ary(Int_obj_ref[] ary) {
|
||||
int len = ary.length;
|
||||
int[] rv = new int[len];
|
||||
for (int i = 0; i < len; ++i)
|
||||
rv[i] = ary[i].Val();
|
||||
return rv;
|
||||
}
|
||||
public void Test_parse(String raw, String expd) {Test_parse(raw, "Test_1", expd);}
|
||||
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);
|
||||
itm.Init(wiki.Domain_bry(), page.Ttl());
|
||||
byte[] actl = parser.Parse(wiki, page, null, itm);
|
||||
Tfds.Eq_str_lines(expd, String_.new_u8(actl));
|
||||
}
|
||||
public void Test_Assert_at_end(String raw, String expd) {
|
||||
if (test_bfr == null) test_bfr = Bry_bfr_.New();
|
||||
test_bfr.Clear().Add_str_u8(raw);
|
||||
Bry_bfr_.Assert_at_end(test_bfr, Byte_ascii.Nl);
|
||||
Tfds.Eq(expd, test_bfr.To_str_and_clear());
|
||||
} private Bry_bfr test_bfr;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.htmls.modules.popups; import gplx.*; import gplx.xowa.*; import gplx.xowa.htmls.*; import gplx.xowa.htmls.modules.*;
|
||||
import gplx.xowa.parsers.*;
|
||||
public class Xow_popup_word {
|
||||
public Xow_popup_word(int tid, int bfr_bgn, int idx, int bgn, int end, Xop_tkn_itm tkn) {this.tid = tid; this.bfr_bgn = bfr_bgn; this.idx = idx; this.bgn = bgn; this.end = end; this.tkn = tkn;}
|
||||
public int Tid() {return tid;} private int tid;
|
||||
public int Bfr_bgn() {return bfr_bgn;} private int bfr_bgn;
|
||||
public int Bfr_end() {return bfr_bgn + this.Len();}
|
||||
public int Idx() {return idx;} private int idx;
|
||||
public int Bgn() {return bgn;} private int bgn;
|
||||
public int End() {return end;} private int end;
|
||||
public int Len() {return end - bgn;}
|
||||
public Xop_tkn_itm Tkn() {return tkn;} private Xop_tkn_itm tkn;
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.htmls.modules.popups; import gplx.*; import gplx.xowa.*; import gplx.xowa.htmls.*; import gplx.xowa.htmls.modules.*;
|
||||
import gplx.langs.htmls.*;
|
||||
import gplx.xowa.wikis.nss.*;
|
||||
import gplx.xowa.parsers.*; import gplx.xowa.parsers.lnkes.*; import gplx.xowa.parsers.xndes.*; import gplx.xowa.parsers.htmls.*; import gplx.xowa.parsers.lnkis.*;
|
||||
public class Xow_popup_wrdx_mkr {
|
||||
private boolean skip_space;
|
||||
private Xop_tkn_itm prv_tkn_seen, prv_tkn_added;
|
||||
public Hash_adp_bry Xnde_id_ignore_list() {return xnde_id_ignore_list;} private Hash_adp_bry xnde_id_ignore_list = Hash_adp_bry.ci_a7();
|
||||
public void Init() {
|
||||
skip_space = false;
|
||||
prv_tkn_seen = prv_tkn_added = null;
|
||||
}
|
||||
public void Process_tkn(Xow_popup_cfg cfg, Xow_popup_parser_data data, Bry_bfr wrdx_bfr, Xop_tkn_itm tkn, byte[] wtxt_bry, int wtxt_len) {
|
||||
boolean add_tkn = true, add_subs = true; Xop_xnde_tkn xnde = null;
|
||||
int tkn_src_bgn = tkn.Src_bgn(), tkn_src_end = tkn.Src_end();
|
||||
prv_tkn_seen = tkn;
|
||||
switch (tkn.Tkn_tid()) {
|
||||
case Xop_tkn_itm_.Tid_root:
|
||||
add_tkn = false; // don't add_tkn root
|
||||
break;
|
||||
case Xop_tkn_itm_.Tid_txt:
|
||||
data.Words_found_add(tkn);
|
||||
break;
|
||||
case Xop_tkn_itm_.Tid_apos:
|
||||
if ( prv_tkn_added != null
|
||||
&& prv_tkn_seen != prv_tkn_added // prv seen tkn was skipped
|
||||
&& prv_tkn_added.Tkn_tid() == Xop_tkn_itm_.Tid_apos // prv added tkn was apos
|
||||
)
|
||||
wrdx_bfr.Add_byte_space(); // prv && cur are apos, but something was skipped inbetween; add a space so that apos doesn't combine EX:''{{skip}}'' x> ''''; PAGE:en.w:Somalia; DATE:2014-07-02
|
||||
break;
|
||||
case Xop_tkn_itm_.Tid_ignore: // always skip ignores, particularly comments; PAGE:en.w:List_of_countries_by_GDP_(PPP); DATE:2014-07-01
|
||||
case Xop_tkn_itm_.Tid_tblw_tb: case Xop_tkn_itm_.Tid_tblw_tc: case Xop_tkn_itm_.Tid_tblw_td:
|
||||
case Xop_tkn_itm_.Tid_tblw_te: case Xop_tkn_itm_.Tid_tblw_th: case Xop_tkn_itm_.Tid_tblw_tr:
|
||||
add_tkn = add_subs = false; // skip tblws
|
||||
break;
|
||||
case Xop_tkn_itm_.Tid_xnde:
|
||||
xnde = (Xop_xnde_tkn)tkn;
|
||||
switch (xnde.Tag().Id()) {
|
||||
case Xop_xnde_tag_.Tid__div:
|
||||
case Xop_xnde_tag_.Tid__table: case Xop_xnde_tag_.Tid__tr: case Xop_xnde_tag_.Tid__td: case Xop_xnde_tag_.Tid__th:
|
||||
case Xop_xnde_tag_.Tid__caption: case Xop_xnde_tag_.Tid__thead: case Xop_xnde_tag_.Tid__tfoot: case Xop_xnde_tag_.Tid__tbody:
|
||||
case Xop_xnde_tag_.Tid__ref: case Xop_xnde_tag_.Tid__gallery: case Xop_xnde_tag_.Tid__imageMap: case Xop_xnde_tag_.Tid__timeline:
|
||||
case Xop_xnde_tag_.Tid__xowa_wiki_setup:
|
||||
case Xop_xnde_tag_.Tid__xowa_html: // needed for Help:Options, else \n at top of doc; DATE:2014-06-22
|
||||
add_tkn = add_subs = false; // skip tblxs
|
||||
xnde = null;
|
||||
break;
|
||||
case Xop_xnde_tag_.Tid__math: // add <math> as one unit; PAGE:en.w:System_of_polynomial_equations DATE:2014-07-01
|
||||
add_subs = false; // never recur
|
||||
xnde = null;
|
||||
data.Words_found_add(tkn); // treat it as one word
|
||||
break;
|
||||
case Xop_xnde_tag_.Tid__br:
|
||||
add_tkn = false; // never add_tkn Src_bgn / Src_end; note add_subs should still be true; PAGE:en.q:Earth; DATE:2014-06-30
|
||||
if (wrdx_bfr.Len_eq_0()) // don't add <br/> to start of document; needed for Help:Options, but good to have everywhere; DATE:2014-06-22
|
||||
add_subs = false;
|
||||
break;
|
||||
default:
|
||||
add_tkn = false; // don't add_tkn xnde, but still add_subs
|
||||
if (Xnde_id_ignore_list_chk(xnde, wtxt_bry)) {
|
||||
add_subs = false;
|
||||
xnde = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Xop_tkn_itm_.Tid_lnke:
|
||||
Xop_lnke_tkn lnke = (Xop_lnke_tkn)tkn;
|
||||
switch (lnke.Lnke_typ()) {
|
||||
case Xop_lnke_tkn.Lnke_typ_brack:
|
||||
Process_subs(cfg, data, wrdx_bfr, tkn, wtxt_bry, wtxt_len, Bool_.N); // add subs which are caption tkns; note that Bool_.N will add all words so that captions don't get split; EX: "a [http://a.org b c d]" -> "a b c d" if words_needed == 2;
|
||||
add_tkn = add_subs = false; // ignore lnke, but add any text tkns; EX: [http://a.org b c d] -> "b c d"
|
||||
break;
|
||||
case Xop_lnke_tkn.Lnke_typ_text:
|
||||
data.Words_found_add(tkn); // increment words_found; EX: a http://b.org c -> 3 words;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Xop_tkn_itm_.Tid_lnki:
|
||||
Xop_lnki_tkn lnki = (Xop_lnki_tkn)tkn;
|
||||
switch (lnki.Ns_id()) {
|
||||
case Xow_ns_.Tid__category: // skip [[Category:]]
|
||||
case Xow_ns_.Tid__file: // skip [[File:]]
|
||||
add_tkn = add_subs = false;
|
||||
break;
|
||||
default:
|
||||
data.Words_found_add(tkn); // increment words_found; EX: a [[B|c d e]] f -> 3 words;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Xop_tkn_itm_.Tid_space:
|
||||
if ( skip_space // previous tkn skipped add and set skip_space to true
|
||||
&& wrdx_bfr.Match_end_byt_nl_or_bos() // only ignore space if it will cause pre; note that some <ref>s will have spaces that should be preserved; EX:"a<ref>b</ref> c"; PAGE:en.w:Mehmed_the_Conqueror; DATE:2014-06-18
|
||||
)
|
||||
add_tkn = false; // skip ws
|
||||
break;
|
||||
case Xop_tkn_itm_.Tid_newLine: {
|
||||
// heuristic to handle skipped <div> / <table> which does not skip \n; EX:"<div>a</div>\nb"; div is skipped, but "\n" remains; PAGE:en.w:Eulogy;DATE:2014-06-18
|
||||
int wrdx_bfr_len = wrdx_bfr.Len();
|
||||
if (wrdx_bfr_len == 0) // don't add_tkn \n at bos; does not handle pages where bos intentionally has multiple \n\n
|
||||
add_tkn = false;
|
||||
else if (wrdx_bfr_len > 2) { // bounds check
|
||||
if (Wtxt_bfr_ends_w_2_nl(wrdx_bfr, wrdx_bfr_len)) // don't add \n if "\n\n"; does not handle intentional sequences of 2+ \n;
|
||||
add_tkn = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Xop_tkn_itm_.Tid_hdr: {
|
||||
data.Words_found_add(tkn); // count entire header as one word; not worth counting words in header
|
||||
add_subs = false; // add entire tkn; do not add_subs
|
||||
int wrdx_bfr_len = wrdx_bfr.Len();
|
||||
if (wrdx_bfr_len > 2) { // bounds check
|
||||
if (Wtxt_bfr_ends_w_2_nl(wrdx_bfr, wrdx_bfr_len)) // heuristic: 2 \n in bfr, and about to add a hdr tkn which starts with "\n"; delete last \n
|
||||
wrdx_bfr.Del_by_1();
|
||||
}
|
||||
if ( tkn_src_end < wtxt_len // bounds check
|
||||
&& wtxt_bry[tkn_src_end] == Byte_ascii.Nl // hdr_tkn will not include trailing "\n". add it; note that this behavior is by design. NOTE:hdr.trailing_nl; DATE:2014-06-17
|
||||
) {
|
||||
wrdx_bfr.Add_mid(wtxt_bry, tkn_src_bgn, tkn_src_end + 1); // +1 to add the trailing \n
|
||||
add_tkn = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
skip_space = false; // always reset; only used once above for Tid_space; DATE:2014-06-17
|
||||
if (add_tkn && xnde == null) {
|
||||
if (tkn_src_end - tkn_src_bgn > 0) { // handle paras which have src_bgn == src_end
|
||||
wrdx_bfr.Add_mid(wtxt_bry, tkn_src_bgn, tkn_src_end);
|
||||
prv_tkn_added = tkn;
|
||||
}
|
||||
}
|
||||
else // tkn not added
|
||||
skip_space = true; // skip next space; note this is done with member variable to handle recursive iteration; DATE:2014-06-17
|
||||
if (add_subs) {
|
||||
if (xnde != null) wrdx_bfr.Add_mid(wtxt_bry, xnde.Tag_open_bgn(), xnde.Tag_open_end()); // add open tag; EX: "<span id=a>"
|
||||
Process_subs(cfg, data, wrdx_bfr, tkn, wtxt_bry, wtxt_len, Bool_.Y);
|
||||
if (xnde != null) wrdx_bfr.Add_mid(wtxt_bry, xnde.Tag_close_bgn(), xnde.Tag_close_end()); // add close tag; EX: "</span>"
|
||||
}
|
||||
switch (tkn.Tkn_tid()) {
|
||||
case Xop_tkn_itm_.Tid_hdr:
|
||||
if ( cfg.Stop_if_hdr_after_enabled()
|
||||
&& data.Stop_if_hdr_after_chk(cfg))
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
private void Process_subs(Xow_popup_cfg cfg, Xow_popup_parser_data data, Bry_bfr wrdx_bfr, Xop_tkn_itm tkn, byte[] wtxt_bry, int wtxt_len, boolean chk_words_found) {
|
||||
int subs_len = tkn.Subs_len();
|
||||
for (int i = 0; i < subs_len; i++) {
|
||||
Xop_tkn_itm sub = tkn.Subs_get(i);
|
||||
Process_tkn(cfg, data, wrdx_bfr, sub, wtxt_bry, wtxt_len);
|
||||
if (chk_words_found && !data.Words_needed_chk()) break;
|
||||
}
|
||||
}
|
||||
private boolean Xnde_id_ignore_list_chk(Xop_xnde_tkn xnde, byte[] src) {
|
||||
Mwh_atr_itm[] atrs_ary = xnde.Atrs_ary();
|
||||
int atrs_len = atrs_ary.length;
|
||||
for (int i = 0; i < atrs_len; i++) {
|
||||
Mwh_atr_itm atr = atrs_ary[i];
|
||||
if ( Bry_.Eq(atr.Key_bry(), Gfh_atr_.Bry__id)
|
||||
&& xnde_id_ignore_list.Get_by_bry(atr.Val_as_bry()) != null
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public void Xnde_ignore_ids_(byte[] xnde_id_ignore_bry) {
|
||||
byte[][] ary = Bry_split_.Split(xnde_id_ignore_bry, Byte_ascii.Pipe);
|
||||
int ary_len = ary.length;
|
||||
xnde_id_ignore_list.Clear();
|
||||
for (int i = 0; i < ary_len; i++) {
|
||||
byte[] bry = ary[i];
|
||||
if (bry.length == 0) continue; // ignore empty entries; EX: "a|"
|
||||
xnde_id_ignore_list.Add(bry, bry);
|
||||
}
|
||||
}
|
||||
private boolean Wtxt_bfr_ends_w_2_nl(Bry_bfr wrdx_bfr, int wrdx_bfr_len) {
|
||||
byte[] hdom_bfr_bry = wrdx_bfr.Bfr();
|
||||
return
|
||||
( hdom_bfr_bry[wrdx_bfr_len - 1] == Byte_ascii.Nl // prv 2 bytes are \n
|
||||
&& hdom_bfr_bry[wrdx_bfr_len - 2] == Byte_ascii.Nl
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.htmls.modules.popups.keeplists; import gplx.*; import gplx.xowa.*; import gplx.xowa.htmls.*; import gplx.xowa.htmls.modules.*; import gplx.xowa.htmls.modules.popups.*;
|
||||
import gplx.langs.regxs.*;
|
||||
public class Xop_keeplist_rule {
|
||||
private Gfo_pattern[] excludes; private int excludes_len;
|
||||
public Xop_keeplist_rule(Gfo_pattern[] includes, Gfo_pattern[] excludes) {
|
||||
this.includes = includes; this.includes_len = includes.length;
|
||||
this.excludes = excludes; this.excludes_len = excludes.length;
|
||||
}
|
||||
public Gfo_pattern[] Includes() {return includes;} private Gfo_pattern[] includes; private int includes_len;
|
||||
public boolean Match(byte[] ttl) {
|
||||
boolean match_found = false;
|
||||
for (int i = 0; i < includes_len; ++i) {
|
||||
Gfo_pattern skip = includes[i];
|
||||
if (skip.Match(ttl)) {
|
||||
match_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (match_found) {
|
||||
for (int i = 0; i < excludes_len; ++i) {
|
||||
Gfo_pattern keep = excludes[i];
|
||||
if (keep.Match(ttl)) {
|
||||
match_found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return match_found;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.htmls.modules.popups.keeplists; import gplx.*; import gplx.xowa.*; import gplx.xowa.htmls.*; import gplx.xowa.htmls.modules.*; import gplx.xowa.htmls.modules.popups.*;
|
||||
import gplx.langs.regxs.*;
|
||||
public class Xop_keeplist_wiki {
|
||||
public Xop_keeplist_wiki(Xowe_wiki wiki) {
|
||||
srl = new Xop_keeplist_wiki_srl(wiki);
|
||||
}
|
||||
public boolean Enabled() {return enabled;} public void Enabled_(boolean v) {enabled = v;} private boolean enabled = false; // NOTE: default to false, b/c wikis that are not listed in cfg will not call Rules_seal
|
||||
public Xop_keeplist_rule[] Rules() {return rules;} private Xop_keeplist_rule[] rules; private int rules_len;
|
||||
public Xop_keeplist_wiki_srl Srl() {return srl;} private Xop_keeplist_wiki_srl srl;
|
||||
public void Rules_add(Xop_keeplist_rule rule) {rules_list.Add(rule);} private List_adp rules_list = List_adp_.New();
|
||||
public void Rules_seal() {
|
||||
this.rules = (Xop_keeplist_rule[])rules_list.To_ary_and_clear(Xop_keeplist_rule.class);
|
||||
this.rules_len = rules.length;
|
||||
if (rules_len == 0) return;
|
||||
if (rules_len == 1) {
|
||||
Xop_keeplist_rule rule_0 = rules[0];
|
||||
if (rule_0.Includes().length == 0)
|
||||
enabled = false;
|
||||
else
|
||||
enabled = true;
|
||||
}
|
||||
else
|
||||
enabled = true;
|
||||
}
|
||||
public boolean Match(byte[] ttl) {
|
||||
for (int i = 0; i < rules_len; ++i) {
|
||||
Xop_keeplist_rule rule = rules[i];
|
||||
if (rule.Match(ttl)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.htmls.modules.popups.keeplists; import gplx.*; import gplx.xowa.*; import gplx.xowa.htmls.*; import gplx.xowa.htmls.modules.*; import gplx.xowa.htmls.modules.popups.*;
|
||||
import gplx.langs.dsvs.*;
|
||||
import gplx.langs.regxs.*;
|
||||
import gplx.xowa.langs.cases.*;
|
||||
public class Xop_keeplist_wiki_srl extends Dsv_wkr_base {
|
||||
private Xol_case_mgr case_mgr; private Xowe_wiki wiki;
|
||||
private byte[] wiki_bry;
|
||||
private byte[] keeps_bry;
|
||||
private byte[] skips_bry;
|
||||
private int rules_count;
|
||||
public Xop_keeplist_wiki_srl(Xowe_wiki wiki) {this.wiki = wiki; this.case_mgr = wiki.Lang().Case_mgr();}
|
||||
@Override public Dsv_fld_parser[] Fld_parsers() {return new Dsv_fld_parser[] {Dsv_fld_parser_.Bry_parser, Dsv_fld_parser_.Bry_parser, Dsv_fld_parser_.Bry_parser};}
|
||||
@Override public boolean Write_bry(Dsv_tbl_parser parser, int fld_idx, byte[] src, int bgn, int end) {
|
||||
switch (fld_idx) {
|
||||
case 0: wiki_bry = Xoa_ttl.Replace_spaces(case_mgr.Case_build_lower(Bry_.Mid(src, bgn, end))); return true;
|
||||
case 1: keeps_bry = Xoa_ttl.Replace_spaces(case_mgr.Case_build_lower(Bry_.Mid(src, bgn, end))); return true;
|
||||
case 2: skips_bry = Xoa_ttl.Replace_spaces(case_mgr.Case_build_lower(Bry_.Mid(src, bgn, end))); return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
@Override public void Commit_itm(Dsv_tbl_parser parser, int pos) {
|
||||
if (wiki_bry == null) throw parser.Err_row_bgn("wikis missing", pos);
|
||||
if (keeps_bry == null) throw parser.Err_row_bgn("keeps missing", pos);
|
||||
if (skips_bry == null) throw parser.Err_row_bgn("skips missing", pos);
|
||||
if (!Bry_.Eq(wiki_bry, wiki.Domain_bry())) return;
|
||||
Xop_keeplist_wiki tmpl_keeplist = Get_tmpl_keeplist();
|
||||
Gfo_pattern[] keeps = Gfo_pattern.Parse_to_ary(keeps_bry);
|
||||
Gfo_pattern[] skips = Gfo_pattern.Parse_to_ary(skips_bry);
|
||||
Xop_keeplist_rule rule = new Xop_keeplist_rule(keeps, skips);
|
||||
tmpl_keeplist.Rules_add(rule);
|
||||
wiki_bry = skips_bry = keeps_bry = null;
|
||||
++rules_count;
|
||||
}
|
||||
@Override public void Load_by_bry_end() {
|
||||
if (rules_count == 0) return; // NOTE: keeplist set in global cfg, so fires when each wiki loads; if loading wiki does not match keeplist, then noop; DATE:2014-07-05
|
||||
Xop_keeplist_wiki tmpl_keeplist = Get_tmpl_keeplist();
|
||||
tmpl_keeplist.Rules_seal();
|
||||
rules_count = 0;
|
||||
}
|
||||
public Xop_keeplist_wiki Get_tmpl_keeplist() {
|
||||
Xow_popup_parser popup_parser = wiki.Html_mgr().Head_mgr().Popup_mgr().Parser();
|
||||
Xop_keeplist_wiki rv = popup_parser.Tmpl_keeplist();
|
||||
if (rv == null) {
|
||||
rv = new Xop_keeplist_wiki(wiki);
|
||||
popup_parser.Tmpl_keeplist_(rv);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.htmls.modules.popups.keeplists; import gplx.*; import gplx.xowa.*; import gplx.xowa.htmls.*; import gplx.xowa.htmls.modules.*; import gplx.xowa.htmls.modules.popups.*;
|
||||
import org.junit.*;
|
||||
public class Xop_keeplist_wiki_tst {
|
||||
@Before public void init() {fxt.Clear();} private Xop_keeplist_wiki_fxt fxt = new Xop_keeplist_wiki_fxt();
|
||||
@Test public void Tmpl_keeplist() {
|
||||
Xop_keeplist_wiki keeplist_wiki = fxt.keeplist_wiki_(String_.Concat_lines_nl
|
||||
( "enwiki|a*|abc*"
|
||||
));
|
||||
fxt.Test_Match_y(keeplist_wiki, "a", "ab");
|
||||
fxt.Test_Match_n(keeplist_wiki, "abc", "abcd", "d");
|
||||
}
|
||||
@Test public void Tmpl_keeplist2() {
|
||||
Xop_keeplist_wiki keeplist_wiki = fxt.keeplist_wiki_(String_.Concat_lines_nl
|
||||
( "enwiki|a*|abc*"
|
||||
, "enwiki|b*|*xyz"
|
||||
));
|
||||
fxt.Test_Match_y(keeplist_wiki, "a", "ab");
|
||||
fxt.Test_Match_n(keeplist_wiki, "d", "abc", "abcd");
|
||||
fxt.Test_Match_y(keeplist_wiki, "b", "bxy");
|
||||
fxt.Test_Match_n(keeplist_wiki, "bxyz", "bcdxyz");
|
||||
}
|
||||
}
|
||||
class Xop_keeplist_wiki_fxt {
|
||||
public void Clear() {
|
||||
}
|
||||
public Xop_keeplist_wiki keeplist_wiki_(String raw) {
|
||||
Xoae_app app = Xoa_app_fxt.Make__app__edit();
|
||||
Xowe_wiki wiki = Xoa_app_fxt.Make__wiki__edit(app, "enwiki");
|
||||
Xow_popup_mgr popup_mgr = wiki.Html_mgr().Head_mgr().Popup_mgr();
|
||||
popup_mgr.Init_by_wiki(wiki);
|
||||
popup_mgr.Parser().Tmpl_keeplist_init_(Bry_.new_u8(raw));
|
||||
Xop_keeplist_wiki rv = popup_mgr.Parser().Tmpl_keeplist();
|
||||
return rv;
|
||||
}
|
||||
public void Test_Match_y(Xop_keeplist_wiki keeplist_wiki, String... itms) {Test_Match(keeplist_wiki, itms, Bool_.Y);}
|
||||
public void Test_Match_n(Xop_keeplist_wiki keeplist_wiki, String... itms) {Test_Match(keeplist_wiki, itms, Bool_.N);}
|
||||
private void Test_Match(Xop_keeplist_wiki keeplist_wiki, String[] itms, boolean expd) {
|
||||
int len = itms.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
String itm = itms[i];
|
||||
Tfds.Eq(expd, keeplist_wiki.Match(Bry_.new_u8(itm)), "itm={0} expd={1}", itm, expd);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user