1
0
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:
gnosygnu
2017-02-06 22:14:55 -05:00
parent 938beac9f9
commit 3bfeb94b43
4380 changed files with 328018 additions and 0 deletions

View File

@@ -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();
}
}

View File

@@ -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");
}

View File

@@ -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);
}
}

View File

@@ -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");
}
}

View File

@@ -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")
;
}

View File

@@ -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;
}
}

View File

@@ -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;
}

View 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"
;
}

View File

@@ -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();
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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 &lt;math&gt;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;
}

View File

@@ -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;
}

View File

@@ -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
);
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}