1
0
mirror of https://github.com/gnosygnu/xowa.git synced 2026-03-02 03:49:30 +00:00
This commit is contained in:
gnosygnu
2015-07-12 21:10:02 -04:00
commit 794b5a232f
3099 changed files with 238212 additions and 0 deletions

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.specials; import gplx.*; import gplx.xowa.*;
public class Xoa_special_mgr implements GfoInvkAble {
private Ordered_hash hash = Ordered_hash_.new_();
public Xoa_special_mgr() {
hash.Add(gplx.xowa.xtns.wdatas.specials.Wdata_itemByTitle_cfg.Key, new gplx.xowa.xtns.wdatas.specials.Wdata_itemByTitle_cfg());
}
public void Add(String key, GfoInvkAble cfg) {hash.Add(key, cfg);}
public GfoInvkAble Get_or_null(String key) {return (GfoInvkAble)hash.Get_by(key);}
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk_get)) return Get_or_null(m.ReadStr("v"));
else return GfoInvkAble_.Rv_unhandled;
} private static final String Invk_get = "get";
}

View File

@@ -0,0 +1,95 @@
/*
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.specials; import gplx.*; import gplx.xowa.*;
import gplx.xowa.users.history.*;
import gplx.xowa.specials.*;
import gplx.xowa.specials.allPages.*; import gplx.xowa.specials.search.*; import gplx.xowa.specials.nearby.*; import gplx.xowa.specials.randoms.*; import gplx.xowa.specials.statistics.*; import gplx.xowa.xtns.translates.*; import gplx.xowa.specials.movePage.*;
import gplx.xowa.specials.xowa.system_data.*; import gplx.xowa.specials.xowa.default_tab.*; import gplx.xowa.specials.xowa.popup_history.*; import gplx.xowa.specials.xowa.file_browsers.*; import gplx.xowa.specials.xowa.bookmarks.*; import gplx.xowa.specials.xowa.diags.*;
import gplx.xowa.xtns.wdatas.specials.*;
import gplx.xowa.users.data.*;
public class Xows_mgr {
private final Hash_adp_bry hash;
public Xows_mgr(Xowe_wiki wiki, Xol_lang lang) {
hash = Hash_adp_bry.ci_utf8_(lang.Case_mgr());
page_allpages = new Xows_page_allpages(wiki);
page_search = new Xows_page__search(wiki);
page_random = new Xows_page_random(wiki);
Evt_lang_changed(wiki.Lang());
}
public Xows_page_allpages Page_allpages() {return page_allpages;} private final Xows_page_allpages page_allpages;
public Xows_page__search Page_search() {return page_search;} private final Xows_page__search page_search;
public Xows_page_random Page_random() {return page_random;} private final Xows_page_random page_random;
public Xop_randomRootPage_page Page_randomRootPage() {return page_randomRootPage;} private final Xop_randomRootPage_page page_randomRootPage = new Xop_randomRootPage_page();
public Xou_history_html Page_history() {return page_history;} private final Xou_history_html page_history = new Xou_history_html();
public Xoud_history_special Page_history2() {return page_history2;} private final Xoud_history_special page_history2 = new Xoud_history_special();
public Nearby_mgr Page_nearby() {return page_nearby;} private final Nearby_mgr page_nearby = new Nearby_mgr();
public Xop_mylanguage_page Page_mylanguage() {return page_mylanguage;} private final Xop_mylanguage_page page_mylanguage = new Xop_mylanguage_page();
public Wdata_itemByTitle_page Page_itemByTitle() {return page_itemByTitle;} private final Wdata_itemByTitle_page page_itemByTitle = new Wdata_itemByTitle_page();
public Xop_statistics_page Page_statistics() {return page_statistics;} private final Xop_statistics_page page_statistics = new Xop_statistics_page();
public Move_page Page_movePage() {return page_movePage;} private final Move_page page_movePage = new Move_page();
public System_data_page Page_system_data() {return page_system_data;} private final System_data_page page_system_data = new System_data_page();
public Default_tab_page Page_default_tab() {return page_default_tab;} private final Default_tab_page page_default_tab = new Default_tab_page();
public Popup_history_page Page_popup_history() {return page_popup_history;} private final Popup_history_page page_popup_history = new Popup_history_page();
public Xosp_fbrow_special Page_file_browser() {return page_file_browser;} private final Xosp_fbrow_special page_file_browser = new Xosp_fbrow_special();
public Xows_bmk_page Page_bmk() {return page_bmk;} private final Xows_bmk_page page_bmk = new Xows_bmk_page();
public Xows_diag_page Page_diag() {return page_diag;} private final Xows_diag_page page_diag = new Xows_diag_page();
public void Evt_lang_changed(Xol_lang lang) {
hash.Clear();
hash.Add_str_obj(Xows_special_meta_.Key__search , page_search);
hash.Add_str_obj(Xows_special_meta_.Key__all_pages , page_allpages);
hash.Add_str_obj("prefixindex" , page_allpages);
hash.Add_str_obj(Xows_special_meta_.Key__random , page_random);
hash.Add_str_obj("random" , page_random);
hash.Add_str_obj(Xows_special_meta_.Key__random_root_page , page_randomRootPage);
hash.Add_bry_obj(Xou_history_mgr.Ttl_name , page_history);
hash.Add_str_obj(Xows_special_meta_.Key__page_history , page_history2);
hash.Add_str_obj(Xows_special_meta_.Key__nearby , page_nearby);
hash.Add_str_obj(Xows_special_meta_.Key__my_language , page_mylanguage);
hash.Add_str_obj(Xows_special_meta_.Key__item_by_title , page_itemByTitle);
hash.Add_str_obj(Xows_special_meta_.Key__statistics , page_statistics);
hash.Add_str_obj(Xows_special_meta_.Key__move_page , page_movePage);
hash.Add_str_obj(Xows_special_meta_.Key__system_data , page_system_data);
hash.Add_str_obj(Xows_special_meta_.Key__default_tab , page_default_tab);
hash.Add_str_obj(Xows_special_meta_.Key__popup_history , page_popup_history);
hash.Add_str_obj(Xows_special_meta_.Key__file_browser , page_file_browser);
hash.Add_str_obj(Xows_special_meta_.Key__bookmarks , page_bmk);
hash.Add_str_obj(Xows_special_meta_.Key__diag , page_diag);
}
public void Special_gen(Xowe_wiki wiki, Xoae_page page, Xoa_url url, Xoa_ttl ttl) {
int slash_pos = Bry_finder.Find_fwd(ttl.Page_txt_wo_qargs(), Xoa_ttl.Subpage_spr); // check for slash
byte[] special_name = slash_pos == Bry_.NotFound
? ttl.Base_txt_wo_qarg() // no slash found; use base_txt; ignore qry args and just get page_names; EX: Search/Earth?fulltext=y; Allpages?from=Earth...
: Bry_.Mid(ttl.Page_txt_wo_qargs(), 0, slash_pos); // slash found; use root page; EX: Special:ItemByTitle/enwiki/Earth
// byte[] special_name = ttl.Base_txt_wo_qarg(); // NOTE: ignore qry args and just get page_names; EX: Search/Earth?fulltext=y; Allpages?from=Earth...
Object o = hash.Get_by_bry(special_name);
if (o == null) {
gplx.xowa.Xol_specials_itm special_itm = wiki.Lang().Specials_mgr().Get_by_alias(special_name);
if (special_itm != null)
o = hash.Get_by_bry(special_itm.Special());
}
if (o != null) {
Xows_page special = (Xows_page)o;
page.Revision_data().Modified_on_(DateAdp_.Now());
special.Special_gen(wiki, page, url, ttl);
}
}
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk_search)) return page_search;
else return GfoInvkAble_.Rv_unhandled;
} private static final String Invk_search = "search";
}

View File

@@ -0,0 +1,22 @@
/*
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.specials; import gplx.*; import gplx.xowa.*;
public interface Xows_page {
Xows_special_meta Special_meta();
void Special_gen(Xowe_wiki wiki, Xoae_page page, Xoa_url url, Xoa_ttl ttl);
}

View File

@@ -0,0 +1,35 @@
/*
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.specials; import gplx.*; import gplx.xowa.*;
public class Xows_special_meta {
public Xows_special_meta(int src, int uid, String key_str) {
this.src = src; this.uid = uid; this.key_str = key_str;
this.key_bry = Bry_.new_u8(key_str);
this.ttl_str = "Special:" + key_str; // canonical name
this.ttl_bry = Bry_.new_u8(ttl_str);
}
public int Src() {return src;} private final int src;
public int Uid() {return uid;} private final int uid;
public String Key_str() {return key_str;} private final String key_str;
public byte[] Key_bry() {return key_bry;} private final byte[] key_bry;
public String Ttl_str() {return ttl_str;} private final String ttl_str;
public byte[] Ttl_bry() {return ttl_bry;} private final byte[] ttl_bry;
public boolean Match_ttl(Xoa_ttl ttl) {
return ttl.Ns().Id_special() && Bry_.Eq(ttl.Root_txt(), key_bry);
}
}

View File

@@ -0,0 +1,75 @@
/*
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.specials; import gplx.*; import gplx.xowa.*;
public class Xows_special_meta_ {
public static final int Src__mw = 1, Src__xowa = 2;
public static final int
Uid__all_pages = 1
, Uid__random = 2
, Uid__random_root_page = 3
, Uid__search = 4
, Uid__statistics = 5
, Uid__move_page = 6
, Uid__my_language = 7
, Uid__item_by_title = 8
, Uid__default_tab = 9
, Uid__file_browser = 10
, Uid__popup_history = 11
, Uid__system_data = 12
, Uid__nearby = 13
, Uid__page_history = 14
, Uid__bookmarks = 15
, Uid__diag = 16
;
public static final String
Key__all_pages = "AllPages"
, Key__random = "RandomPage"
, Key__random_root_page = "RandomRootPage"
, Key__search = "Search"
, Key__statistics = "Statistics"
, Key__move_page = "MovePage"
, Key__my_language = "MyLanguage"
, Key__item_by_title = "ItemByTitle"
, Key__default_tab = "XowaDefaultTab"
, Key__file_browser = "XowaFileBrowser"
, Key__popup_history = "XowaPopupHistory"
, Key__system_data = "XowaSystemData"
, Key__nearby = "Nearby"
, Key__page_history = "XowaHistory"
, Key__bookmarks = "XowaBookmarks"
, Key__diag = "XowaDiag"
;
public static final Xows_special_meta
Itm__all_pages = new Xows_special_meta(Src__mw , Uid__all_pages , Key__all_pages)
, Itm__random = new Xows_special_meta(Src__mw , Uid__random , Key__random)
, Itm__random_root_page = new Xows_special_meta(Src__mw , Uid__random_root_page , Key__random_root_page)
, Itm__search = new Xows_special_meta(Src__mw , Uid__search , Key__search)
, Itm__statistics = new Xows_special_meta(Src__mw , Uid__statistics , Key__statistics)
, Itm__move_page = new Xows_special_meta(Src__xowa , Uid__move_page , Key__move_page)
, Itm__my_language = new Xows_special_meta(Src__xowa , Uid__my_language , Key__my_language)
, Itm__item_by_title = new Xows_special_meta(Src__xowa , Uid__item_by_title , Key__item_by_title)
, Itm__default_tab = new Xows_special_meta(Src__xowa , Uid__default_tab , Key__default_tab)
, Itm__file_browser = new Xows_special_meta(Src__xowa , Uid__file_browser , Key__file_browser)
, Itm__popup_history = new Xows_special_meta(Src__xowa , Uid__popup_history , Key__popup_history)
, Itm__system_data = new Xows_special_meta(Src__xowa , Uid__system_data , Key__system_data)
, Itm__nearby = new Xows_special_meta(Src__xowa , Uid__nearby , Key__nearby)
, Itm__page_history = new Xows_special_meta(Src__xowa , Uid__page_history , Key__page_history)
, Itm__bookmarks = new Xows_special_meta(Src__xowa , Uid__bookmarks , Key__bookmarks)
, Itm__diag = new Xows_special_meta(Src__xowa , Uid__diag , Key__diag)
;
}

View File

@@ -0,0 +1,196 @@
/*
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.specials.allPages; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import gplx.core.primitives.*;
import gplx.xowa.html.*; import gplx.xowa.html.hrefs.*; import gplx.xowa.html.lnkis.*;
import gplx.xowa.wikis.*; import gplx.xowa.wikis.data.tbls.*;
public class Xows_page_allpages implements GfoInvkAble, Bry_fmtr_arg, Xows_page {
public Xows_page_allpages(Xowe_wiki wiki) {
this.wiki = wiki;
html_itm_fmtr = new Xos_pagelist_html_itm_fmtr(this, wiki);
} private Xos_pagelist_html_itm_fmtr html_itm_fmtr;
public Xows_special_meta Special_meta() {return Xows_special_meta_.Itm__all_pages;}
public Xowe_wiki Wiki() {return wiki;} private Xowe_wiki wiki;
public Bry_fmtr Html_all() {return html_all;} Bry_fmtr html_all = Bry_fmtr.new_(String_.Concat_lines_nl
( "<table class=\"mw-allpages-table-form\">"
, " <tr>"
, " <td class=\"mw-allpages-nav\">"
, "~{anchor_prv} |"
, "~{anchor_nxt}"
, " </td>"
, " </tr>"
, "</table>"
, "<table class=\"mw-allpages-table-chunk\">"
, "<tbody>~{grps}"
, "</tbody>"
, "</table>"
, "<hr/>"
, "<div class=\"mw-allpages-nav\">"
, "~{anchor_prv} |"
, "~{anchor_nxt}"
, "</div>"
), "grps", "anchor_prv", "anchor_nxt");
public Bry_fmtr Html_list_grp() {return html_list_grp;} Bry_fmtr html_list_grp = Bry_fmtr.new_(String_.Concat_lines_nl_skip_last
( ""
, " <tr>~{itms}"
, " </tr>"
), "itms");
public Bry_fmtr Html_list_itm_normal() {return html_list_itm_normal;} Bry_fmtr html_list_itm_normal = Bry_fmtr.new_(String_.Concat_lines_nl_skip_last
( ""
, " <td style=\"width:~{itm_pct}%\"><a~{lnki_atr_cls} href=\"~{lnki_href}\" title=\"~{lnki_title}\">~{lnki_text}</a></td>"
), "itm_pct", "lnki_href", "lnki_title", "lnki_text", "lnki_atr_cls");
public Bry_fmtr Html_list_itm_redirect() {return html_list_itm_redirect;} Bry_fmtr html_list_itm_redirect = Bry_fmtr.new_(String_.Concat_lines_nl_skip_last
( ""
, " <td style=\"width:~{itm_pct}%\"><div class=\"allpagesredirect\"><a href=\"~{lnki_href}\" class=\"mw-redirect\" title=\"~{lnki_title}\">~{lnki_text}</a></div></td>"
), "itm_pct", "lnki_href", "lnki_title", "lnki_text");
public Bry_fmtr Html_list_end() {return html_list_end;} Bry_fmtr html_list_end = Bry_fmtr.new_(String_.Concat_lines_nl_skip_last
( "<a href=\"/wiki/Special:AllPages?from=~{arg_from}~{args__rest}\" title=\"Special:AllPages\">~{lbl_text}</a>"
), "arg_from", "args__rest", "lbl_text");
public int Itms_per_page() {return itms_per_page;} private int itms_per_page = 345;
public void Itms_per_page_(int v) {itms_per_page = v; rslt_list_ttls = new Xowd_page_itm[v];}
public int Itms_per_grp() {return itms_per_grp;} private int itms_per_grp = 3;
public boolean List_include_redirects() {return show_redirects;} private boolean show_redirects = true;
public Xowd_page_itm Rslt_prv() {return rslt_prv;} public void Rslt_prv_(Xowd_page_itm v) {rslt_prv = v;} private Xowd_page_itm rslt_prv;
public Xowd_page_itm Rslt_nxt() {return rslt_nxt;} public void Rslt_nxt_(Xowd_page_itm v) {rslt_nxt = v;} private Xowd_page_itm rslt_nxt;
public int Rslt_list_len() {return rslt_list_len;} public void Rslt_list_len_(int v) {rslt_list_len = v;} private int rslt_list_len;
public Xowd_page_itm[] Rslt_list_ttls() {return rslt_list_ttls;} private Xowd_page_itm[] rslt_list_ttls;
public void Special_gen(Xowe_wiki wiki, Xoae_page page, Xoa_url url, Xoa_ttl ttl) {
wiki.Ctx().Cur_page().Html_data().Display_ttl_(wiki.Msg_mgr().Val_by_id(Xol_msg_itm_.Id_sp_allpages_hdr));
url.Page_bry_(Bry_.Add(Bry_.new_a7("Special:"), ttl.Page_txt_wo_qargs())); // HACK: need to re-set Page b/c href_parser does not eliminate qargs; DATE:2013-02-08
if (wiki.Domain_tid() == Xow_domain_type_.Tid_home) {wiki.Appe().Usr_dlg().Prog_many(GRP_KEY, "home.invalid", "AllPages not implemented for home wiki"); return;}
if (rslt_list_ttls == null) this.Itms_per_page_(itms_per_page);
boolean found = Build_data(url, ttl); if (!found) return;
Build_html(page);
}
private static byte[] Get_from(Xoa_url_arg_hash arg_hash, Xowe_wiki wiki, Xoa_url url, Xoa_ttl ttl) {
return ttl.Leaf_bgn() == -1
? arg_hash.Get_val_bry_or(Bry_arg_from, null)
: ttl.Leaf_url()
;
}
public boolean Build_data(Xoa_url url, Xoa_ttl ttl) {
init_ns = wiki.Ns_mgr().Ns_main();
arg_hash.Load(url);
byte[] from_val = Get_from(arg_hash, wiki, url, ttl); if (from_val == null) return false;
from_val = Xoa_app_.Utl__encoder_mgr().Id().Decode(from_val);
int ns_val = arg_hash.Get_val_int_or(Bry_arg_ns, init_ns.Id()); init_ns = wiki.Ns_mgr().Ids_get_or_null(ns_val);
boolean hide_redirects_val = arg_hash.Get_val_int_or(Bry_arg_hideredirects, 0) == 1;
for (int i = 0; i < itms_per_page; i++)
rslt_list_ttls[i] = null;
rslt_list_len = 0;
rslt_nxt = rslt_prv = null;
Xoa_ttl from_ttl = Xoa_ttl.parse_(wiki, from_val); if (from_ttl == null) return false;
if (!from_ttl.Ns().Id_main()) { // ns specified in title
init_ns = from_ttl.Ns();
arg_hash.Set_val_by_int(Bry_arg_ns, init_ns.Id());
arg_hash.Set_val_by_bry(Bry_arg_from, from_ttl.Page_db());
arg_hash.Save(url);
}
Int_obj_ref rslt_len = Int_obj_ref.new_(rslt_list_len);
Xowd_page_itm rslt_nxt2 = new Xowd_page_itm();
Xowd_page_itm rslt_prv2 = new Xowd_page_itm();
int all_pages_min = 0;// no minimum for all pages
List_adp rslt_list = List_adp_.new_();
wiki.Db_mgr().Load_mgr().Load_ttls_for_all_pages(Cancelable_.Never, rslt_list, rslt_nxt2, rslt_prv2, rslt_len, init_ns, from_ttl.Page_db(), itms_per_page, all_pages_min, itms_per_page, !hide_redirects_val, true);
rslt_list_len = rslt_len.Val();
for (int i = 0; i < rslt_list_len; i++)
rslt_list_ttls[i] = (Xowd_page_itm)rslt_list.Get_at(i);
rslt_nxt = rslt_nxt2;
rslt_prv = rslt_prv2;
return true;
} private Xoa_url_arg_hash arg_hash = new Xoa_url_arg_hash();
private static final byte[] Bry_arg_from = Bry_.new_a7("from"), Bry_arg_ns = Bry_.new_a7("namespace"), Bry_arg_hideredirects = Bry_.new_a7("hideredirects");
public Xow_ns Init_ns() {return init_ns;} private Xow_ns init_ns;
public void Build_html(Xoae_page page) {
Bry_bfr tmp_bfr = wiki.Utl__bfr_mkr().Get_m001();
byte[] anchor_prv = Build_html_end(tmp_bfr, rslt_prv, false);
byte[] anchor_nxt = Build_html_end(tmp_bfr, rslt_nxt, true);
html_all.Bld_bfr_many(tmp_bfr, this, anchor_prv, anchor_nxt);
page.Data_raw_(tmp_bfr.Xto_bry_and_clear());
tmp_bfr.Mkr_rls();
page.Html_data().Html_restricted_n_();
}
byte[] Build_html_end(Bry_bfr bfr, Xowd_page_itm itm, boolean fwd) {
Xoa_ttl ttl = Xows_page_allpages.ttl_(wiki, init_ns, itm); if (ttl == null) return Bry_.Empty; // occurs when range is empty; EX: Module:A in simplewikibooks
int msg_id = fwd ? Xol_msg_itm_.Id_sp_allpages_fwd : Xol_msg_itm_.Id_sp_allpages_bwd;
Xol_msg_itm msg_itm = wiki.Lang().Msg_mgr().Itm_by_id_or_null(msg_id);
Bry_bfr tmp_bfr = wiki.Utl__bfr_mkr().Get_b512().Mkr_rls();
byte[] lbl_text = msg_itm.Fmt(tmp_bfr, ttl.Full_txt());
byte[] args__rest = arg_hash.Concat(tmp_bfr, Bry_arg_ns, Bry_arg_hideredirects);
byte[] arg_from = Xoa_app_.Utl__encoder_mgr().Id().Encode(ttl.Page_txt_wo_qargs());
return html_list_end.Bld_bry_many(bfr, arg_from, args__rest, lbl_text);
}
public static Xoa_ttl ttl_(Xowe_wiki wiki, Xow_ns ns, Xowd_page_itm itm) {
byte[] ttl_bry = itm.Ttl_page_db();
if (!ns.Id_main()) ttl_bry = Bry_.Add(ns.Name_db_w_colon(), ttl_bry);
return Xoa_ttl.parse_(wiki, ttl_bry);
}
public void XferAry(Bry_bfr bfr, int idx) {
int len = rslt_list_ttls.length;
html_itm_fmtr.XferAry_bgn();
for (int i = 0; i < len; i += itms_per_grp) {
html_itm_fmtr.Itm_idx_(i);
html_list_grp.Bld_bfr_many(bfr, html_itm_fmtr);
}
html_itm_fmtr.XferAry_end();
}
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk_html_all_)) html_all.Fmt_(m.ReadBry("v"));
else if (ctx.Match(k, Invk_html_list_grp_)) html_list_grp.Fmt_(m.ReadBry("v"));
else if (ctx.Match(k, Invk_html_list_itm_normal_)) html_list_itm_normal.Fmt_(m.ReadBry("v"));
else if (ctx.Match(k, Invk_html_list_itm_redirect_)) html_list_itm_redirect.Fmt_(m.ReadBry("v"));
else if (ctx.Match(k, Invk_itms_per_page_)) Itms_per_page_(m.ReadInt("v"));
else if (ctx.Match(k, Invk_itms_per_grp_)) itms_per_grp = m.ReadInt("v");
else if (ctx.Match(k, Invk_show_redirects_)) show_redirects = m.ReadYn("v");
else return GfoInvkAble_.Rv_unhandled;
return this;
}
public static final String Invk_html_all_ = "html_all_", Invk_html_list_grp_ = "html_list_grp_", Invk_html_list_itm_normal_ = "html_list_itm_normal_", Invk_html_list_itm_redirect_ = "html_list_itm_redirect_"
, Invk_itms_per_page_ = "itms_per_page_", Invk_itms_per_grp_ = "itms_per_grp_", Invk_show_redirects_ = "show_redirects_";
public static final String GRP_KEY = "xowa.special.allpages";
}
class Xos_pagelist_html_itm_fmtr implements Bry_fmtr_arg {
public Xos_pagelist_html_itm_fmtr(Xows_page_allpages mgr, Xowe_wiki wiki) {
this.mgr = mgr; this.wiki = wiki; this.href_parser = wiki.Appe().Href_parser(); this.wiki_key = wiki.Domain_bry();
this.itm_normal = mgr.Html_list_itm_normal(); this.itm_redirect = mgr.Html_list_itm_redirect();
history_mgr = wiki.Appe().Usere().History_mgr();
} private Xows_page_allpages mgr; Xowe_wiki wiki; Xoh_href_parser href_parser; Bry_fmtr itm_normal, itm_redirect; byte[] wiki_key; gplx.xowa.users.history.Xou_history_mgr history_mgr;
public void Itm_idx_(int v) {itm_idx = v;} private int itm_idx;
public void XferAry_bgn() {
itms_per_grp = mgr.Itms_per_grp();
ttls = mgr.Rslt_list_ttls();
ttls_len = ttls.length;
itm_pct = 100 / itms_per_grp;
init_ns = mgr.Init_ns();
} int itms_per_grp, ttls_len, itm_pct; Xowd_page_itm[] ttls; Xow_ns init_ns;
public void XferAry_end() {ttls = null;}
public void XferAry(Bry_bfr bfr, int idx) {
int itm_end = itm_idx + itms_per_grp;
for (int i = itm_idx; i < itm_end; i++) {
if (i >= ttls_len) break; // handle odd number of itms; EX: interval=3; items=4; proc gets called on 0 (0-2) and 3 (3-5); ArrayIndex for 4, 5
Xowd_page_itm ttl_itm = ttls[i];
if (ttl_itm == null) break; // ttl_itm can be null at bgn or end of title list; EX: list=A-Z; count=5; key=Z; itms=X,Y,Z,null,null
Xoa_ttl ttl = Xows_page_allpages.ttl_(wiki, init_ns, ttl_itm);
byte[] href = href_parser.Build_to_bry(wiki, ttl);
byte[] title = Xoh_html_wtr.Ttl_to_title(ttl.Full_txt());
byte[] cls = Xoh_lnki_wtr.Lnki_cls_visited(history_mgr, wiki_key, ttl.Page_txt()); // NOTE: must be ttl.Page_txt() in order to match Xou_history_mgr.Add
Bry_fmtr fmtr = ttl_itm.Redirected() ? itm_redirect : itm_normal;
fmtr.Bld_bfr_many(bfr, itm_pct, href, title, ttl.Full_txt(), cls);
}
}
}

View File

@@ -0,0 +1,205 @@
/*
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.specials.allPages; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import org.junit.*; import gplx.xowa.wikis.data.tbls.*;
public class Xows_page_allpages_tst {
@Before public void init() {fxt.Clear();} private Xows_page_allpages_fxt fxt = new Xows_page_allpages_fxt();
@Test public void Build_data() {
Xow_hive_mgr_fxt.Ttls_create_rng(fxt.Wiki(), 5, 7);
fxt.Clear().Init_ttl_leaf("/B1").Expd_prv("A3").Expd_nxt("B6").Expd_ttls("B1", "B2", "B3", "B4", "B5").Test_build_data(); // SpecialPage:AllPages/B1
fxt.Clear().Init_arg("from", "B1").Expd_prv("A3").Expd_nxt("B6").Expd_ttls("B1", "B2", "B3", "B4", "B5").Test_build_data(); // single file
fxt.Clear().Init_arg("from", "A6").Expd_prv("A1").Expd_nxt("B4").Expd_ttls("A6", "B0", "B1", "B2", "B3").Test_build_data(); // overflow rhs
fxt.Clear().Init_arg("from", "E4").Expd_prv("D6").Expd_nxt("E6").Expd_ttls("E4", "E5", "E6", null, null).Test_build_data(); // bounds rhs
fxt.Clear().Init_arg("from", "A0").Expd_prv("A0").Expd_nxt("A5").Expd_ttls("A0", "A1", "A2", "A3", "A4").Test_build_data(); // bounds lhs
fxt.Clear().Init_arg("from", "B0a").Expd_prv("A3").Expd_nxt("B6").Expd_ttls("B1", "B2", "B3", "B4", "B5").Test_build_data(); // inexact match; B0a matches "hi" value
fxt.Clear().Init_arg("from", "B1").Init_arg("hideredirects", "1").Expd_prv("A0").Expd_nxt("C4").Expd_ttls("B2", "B4", "B6", "C0", "C2").Test_build_data(); // hide redirects
fxt.Clear().Init_arg("from", "A6").Expd_prv("A0").Expd_nxt("E1").Init_itms_per_page(23).Expd_ttls("A6", "B0", "B1", "B2", "B3", "B4", "B5", "B6", "C0", "C1", "C2", "C3", "C4", "C5", "C6", "D0", "D1", "D2", "D3", "D4", "D5", "D6", "E0").Test_build_data(); // overflow rhs x2
}
@Test public void Build_html_main() {
Xow_hive_mgr_fxt.Ttls_create_rng(fxt.Wiki(), 5, 7);
fxt.Clear().Init_arg("from", "B2").Init_itms_per_page(5).Test_build_html(String_.Concat_lines_nl
( "<table class=\"mw-allpages-table-form\">"
, " <tr>"
, " <td class=\"mw-allpages-nav\">"
, "<a href=\"/wiki/Special:AllPages?from=A4\" title=\"Special:AllPages\">Previous page (A4)</a> |"
, "<a href=\"/wiki/Special:AllPages?from=C0\" title=\"Special:AllPages\">Next page (C0)</a>"
, " </td>"
, " </tr>"
, "</table>"
, "<table class=\"mw-allpages-table-chunk\">"
, "<tbody>"
, " <tr>"
, " <td style=\"width:33%\"><a href=\"/wiki/B2\" title=\"B2\">B2</a></td>"
, " <td style=\"width:33%\"><div class=\"allpagesredirect\"><a href=\"/wiki/B3\" class=\"mw-redirect\" title=\"B3\">B3</a></div></td>"
, " <td style=\"width:33%\"><a href=\"/wiki/B4\" title=\"B4\">B4</a></td>"
, " </tr>"
, " <tr>"
, " <td style=\"width:33%\"><div class=\"allpagesredirect\"><a href=\"/wiki/B5\" class=\"mw-redirect\" title=\"B5\">B5</a></div></td>"
, " <td style=\"width:33%\"><a href=\"/wiki/B6\" title=\"B6\">B6</a></td>"
, " </tr>"
, "</tbody>"
, "</table>"
, "<hr/>"
, "<div class=\"mw-allpages-nav\">"
, "<a href=\"/wiki/Special:AllPages?from=A4\" title=\"Special:AllPages\">Previous page (A4)</a> |"
, "<a href=\"/wiki/Special:AllPages?from=C0\" title=\"Special:AllPages\">Next page (C0)</a>"
, "</div>"
));
}
@Test public void Build_html_redirect() {
Xow_hive_mgr_fxt.Ttls_create_rng(fxt.Wiki(), 1, 7);
fxt.Clear().Init_arg("from", "A2").Init_arg("hideredirects", "1").Init_itms_per_page(2).Test_build_html(String_.Concat_lines_nl
( "<table class=\"mw-allpages-table-form\">"
, " <tr>"
, " <td class=\"mw-allpages-nav\">"
, "<a href=\"/wiki/Special:AllPages?from=A0&hideredirects=1\" title=\"Special:AllPages\">Previous page (A0)</a> |"
, "<a href=\"/wiki/Special:AllPages?from=A6&hideredirects=1\" title=\"Special:AllPages\">Next page (A6)</a>"
, " </td>"
, " </tr>"
, "</table>"
, "<table class=\"mw-allpages-table-chunk\">"
, "<tbody>"
, " <tr>"
, " <td style=\"width:33%\"><a href=\"/wiki/A2\" title=\"A2\">A2</a></td>"
, " <td style=\"width:33%\"><a href=\"/wiki/A4\" title=\"A4\">A4</a></td>"
, " </tr>"
, "</tbody>"
, "</table>"
, "<hr/>"
, "<div class=\"mw-allpages-nav\">"
, "<a href=\"/wiki/Special:AllPages?from=A0&hideredirects=1\" title=\"Special:AllPages\">Previous page (A0)</a> |"
, "<a href=\"/wiki/Special:AllPages?from=A6&hideredirects=1\" title=\"Special:AllPages\">Next page (A6)</a>"
, "</div>"
));
}
@Test public void Build_html_ns() {
Xow_hive_mgr_fxt.Ttls_create_rng(fxt.Wiki(), fxt.Wiki().Ns_mgr().Ns_template(), 1, 7);
fxt.Clear().Init_arg("from", "A2").Init_arg("namespace", "10").Init_itms_per_page(2).Test_build_html(String_.Concat_lines_nl
( "<table class=\"mw-allpages-table-form\">"
, " <tr>"
, " <td class=\"mw-allpages-nav\">"
, "<a href=\"/wiki/Special:AllPages?from=A0&namespace=10\" title=\"Special:AllPages\">Previous page (Template:A0)</a> |"
, "<a href=\"/wiki/Special:AllPages?from=A4&namespace=10\" title=\"Special:AllPages\">Next page (Template:A4)</a>"
, " </td>"
, " </tr>"
, "</table>"
, "<table class=\"mw-allpages-table-chunk\">"
, "<tbody>"
, " <tr>"
, " <td style=\"width:33%\"><a href=\"/wiki/Template:A2\" title=\"Template:A2\">Template:A2</a></td>"
, " <td style=\"width:33%\"><div class=\"allpagesredirect\"><a href=\"/wiki/Template:A3\" class=\"mw-redirect\" title=\"Template:A3\">Template:A3</a></div></td>"
, " </tr>"
, "</tbody>"
, "</table>"
, "<hr/>"
, "<div class=\"mw-allpages-nav\">"
, "<a href=\"/wiki/Special:AllPages?from=A0&namespace=10\" title=\"Special:AllPages\">Previous page (Template:A0)</a> |"
, "<a href=\"/wiki/Special:AllPages?from=A4&namespace=10\" title=\"Special:AllPages\">Next page (Template:A4)</a>"
, "</div>"
));
}
@Test public void Misc() {
Xow_hive_mgr_fxt.Ttls_create_rng(fxt.Wiki(), fxt.Wiki().Ns_mgr().Ns_template(), 1, 7);
fxt.Clear().Init_arg("from", "Template:B1").Expd_arg("from", "B1").Expd_arg("namespace", "10").Test_build_data(); // extract ns from ttl
fxt.Clear().Init_arg("from", "Template:B1").Expd_display_ttl("All pages").Expd_address_page("Special:AllPages").Test_special_gen(); // display ttl
}
}
class Xows_page_allpages_fxt {
public Xows_page_allpages_fxt Clear() {
if (app == null) {
app = Xoa_app_fxt.app_();
wiki = Xoa_app_fxt.wiki_tst_(app);
allpages = wiki.Special_mgr().Page_allpages();
GfoInvkAble_.InvkCmd_val(allpages, Xows_page_allpages.Invk_itms_per_page_, 5);
}
init_ttl_leaf = "";
expd_prv = expd_nxt = null;
expd_ttls = null;
expd_display_ttl = null;
return this;
} private Xoae_app app;
public Xowe_wiki Wiki() {return wiki;} private Xowe_wiki wiki; Xows_page_allpages allpages;
public Xows_page_allpages_fxt Init_arg(String key, String val) {init_args.Add(new Gfo_url_arg(Bry_.new_a7(key), Bry_.new_a7(val))); return this;} private List_adp init_args = List_adp_.new_();
public Xows_page_allpages_fxt Init_ttl_leaf(String val) {init_ttl_leaf = val; return this;} private String init_ttl_leaf;
public Xows_page_allpages_fxt Init_itms_per_page(int v) {init_itms_per_page = v; return this;} private int init_itms_per_page = 5;
public Xows_page_allpages_fxt Expd_arg(String key, String val) {expd_args.Add(new Gfo_url_arg(Bry_.new_a7(key), Bry_.new_a7(val))); return this;} private List_adp expd_args = List_adp_.new_();
public Xows_page_allpages_fxt Expd_prv(String v) {expd_prv = v; return this;} private String expd_prv;
public Xows_page_allpages_fxt Expd_nxt(String v) {expd_nxt = v; return this;} private String expd_nxt;
public Xows_page_allpages_fxt Expd_ttls(String... v) {expd_ttls = v; return this;} private String[] expd_ttls;
public Xows_page_allpages_fxt Expd_display_ttl(String v) {expd_display_ttl = v; return this;} private String expd_display_ttl;
public Xows_page_allpages_fxt Expd_address_page(String v) {expd_address_page = v; return this;} private String expd_address_page;
public static String Xto_str(Xowe_wiki wiki, Xowd_page_itm v) {
if (v == null) return null;
Xow_ns ns = wiki.Ns_mgr().Ids_get_or_null(v.Ns_id());
String ns_str = ns == null ? "" : String_.new_a7(ns.Name_db_w_colon());
return ns_str + String_.new_a7(v.Ttl_page_db());
}
public static String[] Xto_str_ary(Xowe_wiki wiki, Xowd_page_itm[] ary) {
int ary_len = ary.length;
String[] rv = new String[ary_len];
for (int i = 0; i < ary_len; i++) {
Xowd_page_itm itm = ary[i];
rv[i] = Xto_str(wiki, itm);
}
return rv;
}
public static String[] Xto_str_ary(Gfo_url_arg[] ary) {
int ary_len = ary.length;
String[] rv = new String[ary_len];
for (int i = 0; i < ary_len; i++) {
Gfo_url_arg itm = ary[i];
rv[i] = String_.new_u8(itm.Key_bry()) + "=" + String_.new_u8(itm.Val_bry());
}
return rv;
}
public Xows_page_allpages_fxt Test_special_gen() {
Xoa_url_parser parserx = new Xoa_url_parser();
parserx.Parse(init_url, Xows_special_meta_.Itm__all_pages.Ttl_bry());
Xoa_ttl init_ttl = Make_init_ttl();
allpages.Special_gen(wiki, wiki.Ctx().Cur_page(), init_url, init_ttl);
if (expd_display_ttl != null) Tfds.Eq(expd_display_ttl, String_.new_u8(wiki.Ctx().Cur_page().Html_data().Display_ttl()));
if (expd_address_page != null) Tfds.Eq(expd_address_page, String_.new_u8(init_url.Page_bry()));
return this;
}
public Xows_page_allpages_fxt Test_build_data() {
Exec_build();
if (expd_ttls != null) Tfds.Eq_ary_str(expd_ttls, Xto_str_ary(wiki, allpages.Rslt_list_ttls()));
if (expd_nxt != null) Tfds.Eq(expd_nxt, Xto_str(wiki, allpages.Rslt_nxt()));
if (expd_prv != null) Tfds.Eq(expd_prv, Xto_str(wiki, allpages.Rslt_prv()));
if (expd_args.Count() > 0) {
Gfo_url_arg[] expd_args_ary = (Gfo_url_arg[])expd_args.To_ary(Gfo_url_arg.class);
Tfds.Eq_ary_str(Xto_str_ary(init_url.Args()), Xto_str_ary(expd_args_ary));
}
return this;
} private Xoa_url init_url = Xoa_url.blank_();
public Xows_page_allpages_fxt Test_build_html(String expd) {
Exec_build();
allpages.Build_html(wiki.Ctx().Cur_page());
Tfds.Eq_str_lines(expd, String_.new_a7(wiki.Ctx().Cur_page().Data_raw()));
return this;
}
private void Exec_build() {
if (allpages.Itms_per_page() != init_itms_per_page) allpages.Itms_per_page_(init_itms_per_page);
init_url.Args_((Gfo_url_arg[])init_args.To_ary(Gfo_url_arg.class));
init_args.Clear();
Xoa_ttl init_ttl = Make_init_ttl();
allpages.Build_data(init_url, init_ttl);
}
private Xoa_ttl Make_init_ttl() {return Xoa_ttl.parse_(wiki, Bry_.new_u8(Xows_special_meta_.Itm__all_pages.Ttl_str() + init_ttl_leaf));}
}

View File

@@ -0,0 +1,181 @@
/*
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.specials.movePage; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import gplx.core.primitives.*; import gplx.xowa.wikis.data.tbls.*;
import gplx.xowa.html.hrefs.*;
public class Move_page implements Xows_page {
private Move_trg_ns_list_fmtr ns_list_fmtr = new Move_trg_ns_list_fmtr();
private Move_url_args args = new Move_url_args();
private Xoa_ttl src_ttl;
public Xows_special_meta Special_meta() {return Xows_special_meta_.Itm__move_page;}
public void Special_gen(Xowe_wiki wiki, Xoae_page page, Xoa_url url, Xoa_ttl ttl) {
args.Parse(url);
byte[] src_ttl_bry = args.Src_ttl();
src_ttl = Xoa_ttl.parse_(wiki, src_ttl_bry);
if (args.Submitted()) {
Exec_rename(wiki, page);
return;
}
byte[] html = Bld_html(page);
page.Html_data().Html_restricted_n_(); // [[Special:]] pages allow all HTML
page.Data_raw_(html);
}
private void Exec_rename(Xowe_wiki wiki, Xoae_page page) {
gplx.xowa.dbs.Xodb_save_mgr save_mgr = wiki.Db_mgr().Save_mgr();
int trg_ns_id = args.Trg_ns();
Xow_ns trg_ns = wiki.Ns_mgr().Ids_get_or_null(trg_ns_id); if (trg_ns == null) throw Exc_.new_("unknown ns", "ns", trg_ns_id);
byte[] trg_ttl_bry = args.Trg_ttl();
Xoa_ttl trg_ttl = Xoa_ttl.parse_(wiki, trg_ns_id, trg_ttl_bry);
Xowd_page_itm src_page = new Xowd_page_itm();
wiki.Db_mgr().Load_mgr().Load_by_ttl(src_page, src_ttl.Ns(), src_ttl.Page_db());
page.Revision_data().Id_(src_page.Id());
page.Revision_data().Modified_on_(src_page.Modified_on());
page.Data_raw_(src_page.Text());
if (args.Create_redirect()) { // NOTE: not tested; DATE:2014-02-27
save_mgr.Data_update(page, Xop_redirect_mgr.Make_redirect_text(trg_ttl.Full_db()));
Xowd_page_itm trg_page = new Xowd_page_itm();
boolean trg_page_exists = wiki.Db_mgr().Load_mgr().Load_by_ttl(trg_page, trg_ns, trg_ttl_bry);
if (trg_page_exists)
save_mgr.Data_update(page, page.Data_raw());
else
save_mgr.Data_create(trg_ttl, page.Data_raw());
}
else
save_mgr.Data_rename(page, trg_ns_id, trg_ttl_bry);
wiki.Data_mgr().Redirect(page, trg_ns.Gen_ttl(trg_ttl_bry));
}
private byte[] Bld_html(Xoae_page page) {
Xowe_wiki wiki = page.Wikie(); Xow_msg_mgr msg_mgr = wiki.Msg_mgr();
if (src_ttl == null) return Bry_.Empty;
ns_list_fmtr.Init_by_page(wiki, page, src_ttl);
Bry_bfr tmp_bfr = wiki.Utl__bfr_mkr().Get_m001();
wiki.Parser().Parse_text_to_html(tmp_bfr, page, true, msg_mgr.Val_by_key_obj("movepagetext"));
fmtr_all.Bld_bfr_many(tmp_bfr
, msg_mgr.Val_by_key_obj("move-page-legend")
, Bry_.Add(Xoh_href_parser.Href_wiki_bry, src_ttl.Full_db())
, gplx.html.Html_utl.Escape_html_as_bry(src_ttl.Full_txt())
, src_ttl.Full_txt()
, msg_mgr.Val_by_key_obj("newtitle")
, ns_list_fmtr
, args.Trg_ttl()
, msg_mgr.Val_by_key_obj("move-leave-redirect")
, msg_mgr.Val_by_key_obj("movepagebtn")
);
return tmp_bfr.To_bry_and_rls();
}
private Bry_fmtr fmtr_all = Bry_fmtr.new_(String_.Concat_lines_nl_skip_last
( "<form action='/wiki/Special:MovePage' id='movepage'>"
, " <fieldset>"
, " <legend>~{move-page-legend}</legend>"
, " <table id='mw-movepage-table'>"
, " <tr>"
, " <td class='mw-label'>Move page:</td>"
, " <td class='mw-input'>"
, " <strong><a href='~{src_href}' title='~{src_title}'>~{src_text}</a></strong>"
, " </td>"
, " </tr>"
, " <tr>"
, " <td class='mw-label'>"
, " <label for='wpNewTitleMain'>~{newtitle}</label>"
, " </td>"
, " <td class='mw-input'>"
, " <select id='wpNewTitleNs' name='wpNewTitleNs'>~{trg_ns_list}"
, " </select>"
, " <input name='wpNewTitleMain' size='60' value='~{trg_title}' type='text' id='wpNewTitleMain' maxlength='255' />"
, " <input type='hidden' value='~{src_title}' name='wpOldTitle' />"
, " </td>"
, " </tr>"
, "<!-- <tr>"
, " <td></td>"
, " <td class='mw-input'>"
, " <input name='wpLeaveRedirect' type='checkbox' value='1' checked='checked' id='wpLeaveRedirect' />&#160;<label for='wpLeaveRedirect'>~{move-leave-redirect}</label>"
, " </td>"
, " </tr> -->"
, " <tr>"
, " <td>&#160;</td>"
, " <td class='mw-submit'>"
, " <input type='submit' value='~{movepagebtn}' name='wpMove' />"
, " </td>"
, " </tr>"
, " </table>"
, " </fieldset>"
, "</form>"
), "move-page-legend", "src_href", "src_title", "src_text", "newtitle", "trg_ns_list", "trg_title", "move-leave-redirect", "movepagebtn");
}
class Move_trg_ns_list_fmtr implements Bry_fmtr_arg {
private Xowe_wiki wiki; private Xoa_ttl ttl;
public void Init_by_page(Xowe_wiki wiki, Xoae_page page, Xoa_ttl ttl) {
this.wiki = wiki;
this.ttl = ttl;
}
public void XferAry(Bry_bfr bfr, int idx) {
Xow_ns_mgr ns_mgr = wiki.Ns_mgr();
int ns_len = ns_mgr.Ids_len();
for (int i = 0; i < ns_len; i++) {
Xow_ns ns = ns_mgr.Ids_get_at(i);
if (ns.Is_meta()) continue; // ignore [[Special:]] and [[Media:]]
byte[] bry_selected = ttl.Ns().Id() == ns.Id() ? Bry_selected : Bry_.Empty;
fmtr.Bld_bfr_many(bfr, ns.Id(), bry_selected, ns.Name_ui());
}
}
private static final byte[] Bry_selected = Bry_.new_a7(" selected=''");
private Bry_fmtr fmtr = Bry_fmtr.new_(String_.Concat_lines_nl_skip_last
( ""
, " <option value='~{ns_id}' ~{ns_selected}>~{ns_name}</option>"
), "ns_id", "ns_selected", "ns_name");
}
class Move_url_args {
public boolean Submitted() {return submitted;} private boolean submitted;
public byte[] Src_ttl() {return src_ttl;} private byte[] src_ttl;
public byte[] Trg_ttl() {return trg_ttl;} private byte[] trg_ttl;
public int Trg_ns() {return trg_ns;} private int trg_ns;
public boolean Create_redirect() {return create_redirect;} private boolean create_redirect;
public void Parse(Xoa_url url) {
this.Clear();
Gfo_url_arg[] args = url.Args();
int args_len = args.length;
for (int i = 0; i < args_len; i++) {
Gfo_url_arg arg = args[i];
Object tid_obj = arg_keys.Get_by(arg.Key_bry());
byte[] val_bry = arg.Val_bry();
if (tid_obj != null) {
switch (((Byte_obj_val)tid_obj).Val()) {
case Key_submitted: submitted = true; break; // wpMove will only be in query_args if move button is pressed
case Key_src_ttl: src_ttl = val_bry; break;
case Key_trg_ns: trg_ns = Bry_.Xto_int_or_fail(val_bry); break;
case Key_trg_ttl: trg_ttl = val_bry; break;
case Key_create_redirect: create_redirect = Bry_.Xto_bool_by_int_or_fail(val_bry); break;
}
}
}
}
private void Clear() {
submitted = false;
src_ttl = trg_ttl = null;
trg_ns = Int_.MinValue;
create_redirect = false;
}
private static final byte Key_submitted = 1, Key_src_ttl = 2, Key_trg_ns = 3, Key_trg_ttl = 4, Key_create_redirect = 5;
private static final Hash_adp_bry arg_keys = Hash_adp_bry.ci_ascii_()
.Add_str_byte("wpMove" , Key_submitted)
.Add_str_byte("wpOldTitle" , Key_src_ttl)
.Add_str_byte("wpNewTitleNs" , Key_trg_ns)
.Add_str_byte("wpNewTitleMain" , Key_trg_ttl)
.Add_str_byte("wpLeaveRedirect" , Key_create_redirect)
;
}

View File

@@ -0,0 +1,196 @@
/*
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.specials.nearby; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
public class Nearby_mgr implements Xows_page {
Xowe_wiki wiki; byte[] trg;
private Hash_adp_bry excluded = Hash_adp_bry.ci_ascii_();
private Hash_adp_bry visited = Hash_adp_bry.ci_ascii_();
List_adp trail = List_adp_.new_();
List_adp results = List_adp_.new_();
int results_cur = 0;
// int depth_max = 5;
// int pages_count = 0;
Bry_bfr tmp_bfr = Bry_bfr.new_();
public int Results_max() {return results_max;} public Nearby_mgr Results_max_(int v) {results_max = v; return this;} private int results_max = 1;
public Xows_special_meta Special_meta() {return Xows_special_meta_.Itm__nearby;}
public void Special_gen(Xowe_wiki wiki, Xoae_page page, Xoa_url url, Xoa_ttl ttl) {
page.Data_raw_(Bld_html(wiki));
page.Html_data().Html_restricted_n_(); // [[Special:]] pages allow all HTML
// wiki.ParsePage(page, false); // do not clear else previous Search_text will be lost
}
byte[] Bld_html(Xowe_wiki wiki) {
form_fmtr.Bld_bfr_many(tmp_bfr);
List_adp list = Find_from_to(wiki, Bry_.new_a7("Earth"), Bry_.new_a7("Atom"), excluded);
tmp_bfr.Add_str_a7("<table>");
int len = list.Count();
for (int i = 0; i < len; i++) {
Nearby_rslt rslt = (Nearby_rslt)list.Get_at(i);
tmp_bfr.Add_str_a7("<tr>");
int cell_len = rslt.Len();
for (int j = 0; j < cell_len; j++) {
Xoa_ttl ttl = (Xoa_ttl)rslt.Get_at(j);
tmp_bfr.Add_str_a7("<td>[[");
tmp_bfr.Add(ttl.Page_db());
tmp_bfr.Add_str_a7("]]</td>");
}
tmp_bfr.Add_str_a7("</tr>");
}
tmp_bfr.Add_str_a7("</table>");
return tmp_bfr.Xto_bry_and_clear();
}
Bry_fmtr form_fmtr = Bry_fmtr.new_(String_.Concat_lines_nl
( "<form id='xowa_nearby_form' action='/wiki/Special:XowaNearby'>"
, "<table>"
, " <tr><td>From:</td><td><input name='xowa_bgn' value='Earth' /></td></tr>"
, " <tr><td>To: </td><td><input name='xowa_end' value='Atom' /></td></tr>"
, " <tr><td>Max: </td><td><input name='xowa_max' value='1' /></td></tr>"
, " <tr><td>Skip:</td><td><input name='xowa_skip' value='' /></td></tr>"
, " <tr><td/><td align='right'><input type='submit' value='go' /></td></tr>"
, "</table>"
, "</form>"
));
Xoa_ttl trg_ttl;
Ordered_hash src_pool = Ordered_hash_.new_bry_();
public List_adp Find_from_to(Xowe_wiki wiki, byte[] src_bry, byte[] trg_bry, Hash_adp_bry excluded) {
this.wiki = wiki; this.excluded = excluded;
Xoa_ttl src_ttl = Xoa_ttl.parse_(wiki, src_bry); if (src_ttl == null) return List_adp_.Noop;
trg_ttl = Xoa_ttl.parse_(wiki, trg_bry); if (trg_ttl == null) return List_adp_.Noop;
trg = trg_ttl.Page_db();
trail.Clear();
results.Clear();
results_cur = 0;
// pages_count = 0;
visited.Clear();
src_pool.Clear();
src_pool.Add(src_ttl.Page_db(), new Nearby_itmx(trail, src_ttl));
Examine_page(src_pool);
return results;
}
private void Examine_page(Ordered_hash src_pool){
int len = src_pool.Count();
Ordered_hash next_pool = Ordered_hash_.new_bry_();
for (int i = 0; i < len; i++) {
Nearby_itmx itmx = (Nearby_itmx)src_pool.Get_at(i);
Xoa_ttl ttl = itmx.Ttl();
byte[] ttl_bry = ttl.Page_db();
if (excluded.Has(ttl_bry)) continue;
if (visited.Has(ttl_bry)) continue;
visited.Add_bry_bry(ttl_bry);
Xoae_page page = wiki.Data_mgr().Get_page(ttl, false);
if (page.Missing()) continue;
wiki.ParsePage(page, true);
Ordered_hash lnkis = Ordered_hash_.new_bry_();
Collect_lnkis(lnkis, page.Root());
if (lnkis.Has(trg)) {
++results_cur;
results.Add(new Nearby_rslt(itmx.Trail(), trg_ttl));
if (results_cur == results_max) return;
}
int lnkis_len = lnkis.Count();
for (int j = 0; j < lnkis_len; j++) {
Xoa_ttl lnki_ttl = (Xoa_ttl)lnkis.Get_at(j);
if (next_pool.Has(lnki_ttl.Page_db())) continue;
Nearby_itmx next_itmx = new Nearby_itmx(itmx.Trail(), lnki_ttl);
next_pool.Add(lnki_ttl.Page_db(), next_itmx);
}
}
if (next_pool.Count() > 0)
Examine_page(next_pool);
// ++pages_count;
// wiki.ParsePage(page, true);
// Ordered_hash lnkis = Ordered_hash_.new_bry_();
// int len = lnkis.Count();
// for (int i = 0; i < len; i++) {
// Xoa_ttl lnki_ttl = (Xoa_ttl)lnkis.Get_at(i);
// if (!lnki_ttl.Ns().Id_main()) continue;
// if (Bry_.Eq(lnki_ttl.Page_db(), trg)) continue; // skip trg page
// trail.Add(lnki_ttl);
// Examine_page(wiki, lnki_ttl, trail);
// List_adp_.DelAt_last(trail);
// if (results_cur == results_max) return;
// }
}
// private void Examine_page(Xowe_wiki wiki, Xoa_ttl ttl, List_adp trail){
// byte[] ttl_bry = ttl.Page_db();
// if (excluded.Has(ttl_bry)) return;
// if (visited.Has(ttl_bry)) return;
// visited.Add_bry_bry(ttl_bry);
// Xoae_page page = wiki.Data_mgr().Get_page(ttl, false);
// if (page.Missing()) return;
// ++pages_count;
// wiki.ParsePage(page, true);
// Ordered_hash lnkis = Ordered_hash_.new_bry_();
// Collect_lnkis(lnkis, page.Root());
// if (lnkis.Has(trg)) {
// ++results_cur;
// results.Add(new Nearby_rslt(trail, trg_ttl));
// if (results_cur == results_max) return;
// }
// int len = lnkis.Count();
// for (int i = 0; i < len; i++) {
// Xoa_ttl lnki_ttl = (Xoa_ttl)lnkis.Get_at(i);
// if (!lnki_ttl.Ns().Id_main()) continue;
// if (Bry_.Eq(lnki_ttl.Page_db(), trg)) continue; // skip trg page
// trail.Add(lnki_ttl);
// Examine_page(wiki, lnki_ttl, trail);
// List_adp_.DelAt_last(trail);
// if (results_cur == results_max) return;
// }
// }
private void Collect_lnkis(Ordered_hash lnkis, Xop_tkn_itm tkn) {
if (tkn.Tkn_tid() == Xop_tkn_itm_.Tid_lnki) {
Xop_lnki_tkn lnki_tkn = (Xop_lnki_tkn)tkn;
Xoa_ttl lnki_ttl = lnki_tkn.Ttl();
if (!lnkis.Has(lnki_ttl.Page_db()))
lnkis.Add(lnki_ttl.Page_db(), lnki_ttl);
}
else {
int len = tkn.Subs_len();
for (int i = 0; i < len; i++) {
Xop_tkn_itm sub = tkn.Subs_get(i);
Collect_lnkis(lnkis, sub);
}
}
}
}
class Nearby_rslt {
public Nearby_rslt(List_adp trail, Xoa_ttl trg_ttl) {
int len = trail.Count();
for (int i = 0; i < len; i++) {
Xoa_ttl ttl = (Xoa_ttl)trail.Get_at(i);
list.Add(ttl);
}
list.Add(trg_ttl);
}
public int Len() {return list.Count();}
public Xoa_ttl Get_at(int i) {return (Xoa_ttl)list.Get_at(i);}
List_adp list = List_adp_.new_();
}
class Nearby_itmx {
public Nearby_itmx(List_adp v, Xoa_ttl ttl) {
int len = v.Count();
for (int i = 0; i < len; i++) {
Xoa_ttl v_ttl = (Xoa_ttl)v.Get_at(i);
trail.Add(v_ttl);
}
trail.Add(ttl);
this.ttl = ttl;
}
public Xoa_ttl Ttl() {return ttl;} private Xoa_ttl ttl;
public List_adp Trail() {return trail;} List_adp trail = List_adp_.new_();
}

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.specials.nearby; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import org.junit.*;
public class Nearby_mgr_tst {
@Before public void init() {fxt.Clear();} Nearby_mgr_fxt fxt = new Nearby_mgr_fxt();
@Test public void Basic() {
fxt.Init_page("A", "[[B]]");
fxt.Test_find("A", "B", "A|B");
}
@Test public void Shortest() {
fxt.Init_page("A", "[[B]]");
fxt.Init_page("B", "[[C]] [[D]]");
fxt.Init_page("C", "[[D]]");
fxt.Test_find("A", "D", "A|B|D");
fxt.Init_results_max(2).Test_find("A", "D", "A|B|D", "A|B|C|D");
}
@Test public void Circular() {
fxt.Init_page("A", "[[B]]");
fxt.Init_page("B", "[[C]]");
fxt.Init_page("C", "[[A]]");
fxt.Test_find("A", "D", "");
}
@Test public void Page_doesnt_exist() {
fxt.Init_page("A", "[[B]]");
fxt.Test_find("A", "C", "");
}
}
class Nearby_mgr_fxt {
public Nearby_mgr_fxt Clear() {
if (fxt == null) {
fxt = new Xop_fxt();
nearby_mgr = new Nearby_mgr();
excluded = Hash_adp_bry.ci_ascii_();
tmp_bfr = Bry_bfr.new_();
}
fxt.Reset();
Io_mgr.I.InitEngine_mem();
nearby_mgr.Results_max_(1);
return this;
} private Xop_fxt fxt; Nearby_mgr nearby_mgr; Hash_adp_bry excluded; Bry_bfr tmp_bfr;
public void Init_page(String ttl, String text) {fxt.Init_page_create(ttl, text);}
public Nearby_mgr_fxt Init_results_max(int v) {nearby_mgr.Results_max_(v); return this;}
public void Test_find(String src, String trg, String... expd) {
List_adp actl = nearby_mgr.Find_from_to(fxt.Wiki(), Bry_.new_a7(src), Bry_.new_a7(trg), excluded);
Tfds.Eq_ary(String_.SplitLines_nl(Xto_str(actl)), expd);
}
String Xto_str(List_adp list) {
int len = list.Count();
for (int i = 0; i < len; i++) {
Nearby_rslt rslt = (Nearby_rslt)list.Get_at(i);
int ttls = rslt.Len();
if (i != 0) tmp_bfr.Add_byte_nl();
for (int j = 0; j < ttls; j++) {
Xoa_ttl ttl = rslt.Get_at(j);
if (j != 0) tmp_bfr.Add_byte(Byte_ascii.Pipe);
tmp_bfr.Add(ttl.Page_db());
}
}
return tmp_bfr.Xto_str_and_clear();
}
}

View File

@@ -0,0 +1,27 @@
/*
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.specials.randoms; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
public class Xop_randomRootPage_page implements Xows_page {
public Xows_special_meta Special_meta() {return Xows_special_meta_.Itm__random_root_page;}
public void Special_gen(Xowe_wiki wiki, Xoae_page page, Xoa_url url, Xoa_ttl ttl) {
Xow_ns ns = wiki.Ns_mgr().Names_get_or_main(ttl.Rest_txt());
byte[] random_ttl_bry = wiki.Db_mgr().Load_mgr().Find_random_ttl(ns);
byte[] root_bry = Xoa_ttl.parse_(wiki, random_ttl_bry).Root_txt();
wiki.Data_mgr().Redirect(page, ns.Gen_ttl(root_bry));
}
}

View File

@@ -0,0 +1,55 @@
/*
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.specials.randoms; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import org.junit.*;
public class Xop_randomRootPage_page_tst {
@Before public void init() {fxt.Clear();} private Xop_randomRootPage_page_fxt fxt = new Xop_randomRootPage_page_fxt();
@Test public void Ns_main() {
fxt.Init_create_page("A");
fxt.Init_create_page("A/B/C");
fxt.Test_open("Special:RandomRootPage/Main", "A");
}
@Test public void Ns_help() {
fxt.Init_create_page("Help:A");
fxt.Init_create_page("Help:A/B/C");
fxt.Test_open("Special:RandomRootPage/Help", "Help:A");
}
}
class Xop_randomRootPage_page_fxt {
public void Clear() {
parser_fxt = new Xop_fxt();
parser_fxt.Reset();
wiki = parser_fxt.Wiki();
special_page = wiki.Special_mgr().Page_randomRootPage();
} private Xop_fxt parser_fxt; private Xop_randomRootPage_page special_page; private Xowe_wiki wiki;
public void Init_create_page(String page) {parser_fxt.Init_page_create(page, page);}
public void Test_open(String special_url, String expd) {
Xoae_page page = Test_special_open(wiki, special_page, special_url);
Tfds.Eq(expd, String_.new_a7(page.Url().Page_bry()));
Tfds.Eq(expd, String_.new_a7(page.Data_raw()));
}
public static Xoae_page Test_special_open(Xowe_wiki wiki, Xows_page special_page, String special_url) {
Xoae_page page = wiki.Ctx().Cur_page();
Xoa_url url = wiki.Appe().Utl__url_parser().Parse(Bry_.new_u8(special_url));
page.Url_(url);
Xoa_ttl ttl = Xoa_ttl.parse_(wiki, Bry_.new_a7(special_url));
page.Ttl_(ttl);
special_page.Special_gen(wiki, page, url, ttl);
return page;
}
}

View File

@@ -0,0 +1,27 @@
/*
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.specials.randoms; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
public class Xows_page_random implements Xows_page {
public Xows_page_random(Xowe_wiki wiki) {}
public Xows_special_meta Special_meta() {return Xows_special_meta_.Itm__random;}
public void Special_gen(Xowe_wiki wiki, Xoae_page page, Xoa_url url, Xoa_ttl ttl) {
Xow_ns ns = wiki.Ns_mgr().Names_get_or_main(ttl.Rest_txt());
byte[] random_ttl_bry = wiki.Db_mgr().Load_mgr().Find_random_ttl(ns);
wiki.Data_mgr().Redirect(page, ns.Gen_ttl(random_ttl_bry));
}
}

View File

@@ -0,0 +1,111 @@
/*
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.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import gplx.core.primitives.*; import gplx.xowa.wikis.data.tbls.*;
class Xog_search_suggest_cmd implements GfoInvkAble, Cancelable {
private Xowe_wiki wiki; private byte[] search_bry; private Xosrh_page_mgr searcher; private int max_results, all_pages_extend, all_pages_min;
public Xog_search_suggest_cmd(Xoae_app app, Xog_search_suggest_mgr mgr) {
this.app = app; this.mgr = mgr;
} private Xoae_app app; Xog_search_suggest_mgr mgr; Bry_bfr tmp_bfr = Bry_bfr.reset_(255); List_adp rslts_1 = List_adp_.new_(), rslts_2 = List_adp_.new_();
public void Init(Xowe_wiki wiki, byte[] search_bry, int max_results, byte search_mode, int all_pages_extend, int all_pages_min) {
this.wiki = wiki; this.search_bry = search_bry; this.max_results = max_results;
this.search_mode = search_mode; this.all_pages_extend = all_pages_extend; this.all_pages_min = all_pages_min;
searcher = new Xosrh_page_mgr();
}
private byte search_mode;
public byte[] Search_bry() {return search_bry;}
public boolean Canceled() {return canceled;}
public void Cancel() {this.canceled = true;} private boolean canceled;
public void Cancel_reset() {this.canceled = false;}
public boolean Working() {return working;} public void Working_(boolean v) {working = v;} private boolean working;
public List_adp Results() {return rslts_2;}
public void Search() {
try { // NOTE: must handle any errors in async mode
canceled = false;
working = true;
boolean pass = false;
switch (search_mode) {
case Xog_search_suggest_mgr.Tid_search_mode_all_pages_v2: pass = Search_by_all_pages_v2(); break;
case Xog_search_suggest_mgr.Tid_search_mode_all_pages_v1: pass = Search_by_all_pages_v1(); break;
case Xog_search_suggest_mgr.Tid_search_mode_search: pass = Search_by_search(); break;
}
if (!pass) return;
GfoInvkAble_.InvkCmd(app.Gui_mgr().Kit().New_cmd_sync(mgr), Xog_search_suggest_mgr.Invk_notify);
working = false;
}
catch(Exception e) {
app.Usr_dlg().Prog_many("", "", "error during search: ~{0}", Err_.Message_gplx_brief(e));
}
}
private boolean Search_by_all_pages_v2() {
rslts_2.Clear();
Xoa_ttl search_ttl = Xoa_ttl.parse_(wiki, search_bry); if (search_ttl == null) return false;
byte[] search_ttl_bry = search_ttl.Page_db();
wiki.Db_mgr().Load_mgr().Load_ttls_for_search_suggest(this, rslts_2, search_ttl.Ns(), search_ttl_bry, max_results, all_pages_min, all_pages_extend, true, false);
return true;
}
private boolean Search_by_all_pages_v1() {
rslts_2.Clear();
Xowd_page_itm rslt_nxt = new Xowd_page_itm();
Xowd_page_itm rslt_prv = new Xowd_page_itm();
Xoa_ttl search_ttl = Xoa_ttl.parse_(wiki, search_bry); if (search_ttl == null) return false;
byte[] search_ttl_bry = search_ttl.Page_db();
List_adp page_list = List_adp_.new_();
wiki.Db_mgr().Load_mgr().Load_ttls_for_all_pages(this, page_list, rslt_nxt, rslt_prv, Int_obj_ref.zero_(), wiki.Ns_mgr().Ns_main(), search_ttl_bry, max_results, all_pages_min, all_pages_extend, true, false);
Xowd_page_itm[] page_ary = (Xowd_page_itm[])page_list.To_ary_and_clear(Xowd_page_itm.class);
int idx = 0, page_ary_len = page_ary.length;
for (int i = 0; i < page_ary_len; i++) {
Xowd_page_itm page = page_ary[i];
if (page != null) {
if (!Bry_.Has_at_bgn(page.Ttl_page_db(), search_ttl_bry)) continue; // look-ahead may return other titles that don't begin with search; ignore
if (page.Text_len() > all_pages_min) {
rslts_2.Add(page);
idx++;
}
}
if (idx == max_results) break;
}
return true;
}
private boolean Search_by_search() {
Xosrh_rslt_grp rv = searcher.Itms_per_page_(max_results).Search(tmp_bfr, wiki, search_bry, 0, searcher, this);
if (canceled) {working = false; return false;}
rslts_1.Clear();
int len = rv.Itms_len();
for (int i = 0; i < len; i++)
rslts_1.Add(rv.Itms_get_at(i));
if (canceled) {working = false; return false;}
rslts_1.Sort_by(Xowd_page_itm_sorter.EnyLenDsc);
if (canceled) {working = false; return false;}
if (len > max_results) len = max_results;
rslts_2.Clear();
for (int i = 0; i < len; i++)
rslts_2.Add(rslts_1.Get_at(i));
if (canceled) {working = false; return false;}
rslts_2.Sort_by(Xowd_page_itm_sorter.IdAsc);
wiki.Db_mgr().Load_mgr().Load_by_ids(this, rslts_2, 0, len);
rslts_2.Sort_by(Xowd_page_itm_sorter.TitleAsc);
if (canceled) {working = false; return false;}
return true;
}
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk_search)) Search();
else return GfoInvkAble_.Rv_unhandled;
return this;
} public static final String Invk_search = "search";
}

View File

@@ -0,0 +1,146 @@
/*
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.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import gplx.gfui.*; import gplx.core.threads.*; import gplx.xowa.gui.*; import gplx.xowa.gui.views.*; import gplx.xowa.wikis.data.tbls.*;
import gplx.core.js.*;
public class Xog_search_suggest_mgr implements GfoInvkAble {
public Xog_search_suggest_mgr(Xoa_gui_mgr gui_mgr) {
this.app = gui_mgr.App();
this.main_win = gui_mgr.Browser_win();
cur_cmd = new Xog_search_suggest_cmd(app, this);
} private Xoae_app app; private Xog_win_itm main_win; private Js_wtr wtr = new Js_wtr();
private int results_max = 10; private boolean log_enabled = false;
public boolean Enabled() {return enabled;} private boolean enabled = true;
public byte Search_mode() {return search_mode;} public Xog_search_suggest_mgr Search_mode_(byte v) {search_mode = v; return this;} private byte search_mode = Tid_search_mode_all_pages_v2;
public int All_pages_extend() {return all_pages_extend;} private int all_pages_extend = 1000; // look ahead by 1000
public int All_pages_min() {return all_pages_min;} private int all_pages_min = 10000; // only look at pages > 10 kb
public boolean Auto_wildcard() {return auto_wildcard;} private boolean auto_wildcard = false; // automatically add wild-card; EX: Earth -> *Earth*
public Gfo_url_arg[] Args_default() {return args_default;} private Gfo_url_arg[] args_default = Gfo_url_arg.Ary_empty;
public void Args_default_str_(String v) {
this.args_default_str = v;
byte[] bry = Bry_.new_u8("http://x.org/a?" + v);
Gfo_url tmp_url = new Gfo_url();
app.Utl__url_parser().Url_parser().Parse(tmp_url, bry, 0, bry.length);
args_default = tmp_url.Args();
}
private String args_default_str = "";// default args for search
public static final int[] Ns_default_main = new int[] {Xow_ns_.Id_main};
public void Cancel() {
cur_cmd.Cancel();
long prv_time = Env_.TickCount();
while (cur_cmd.Working()) {
if (Env_.TickCount() - prv_time > 4000) {
if (log_enabled) app.Usr_dlg().Log_many("", "", "search cancel timeout: word=~{0}", String_.new_u8(search_bry));
cur_cmd.Working_(false);
break;
}
}
}
public void Search(Xowe_wiki wiki, byte[] search_bry, byte[] cbk_func) {
this.wiki = wiki; this.search_bry = search_bry; this.cbk_func = cbk_func;
Thread_adp_.invk_(gplx.xowa.apps.Xoa_thread_.Key_special_suggest, this, Invk_search_async).Start();
} private Xowe_wiki wiki; private byte[] search_bry, cbk_func;
private Object thread_lock = new Object();
private void Search_async() {
if (!enabled) return;
if (search_bry.length == 0) return;
this.Cancel();
synchronized (thread_lock) {
if (Bry_.Eq(search_bry , last_search_bry)) {
if (log_enabled) app.Usr_dlg().Log_many("", "", "search repeated?: word=~{0}", String_.new_u8(search_bry));
return;
}
cur_cmd.Init(wiki, search_bry, results_max, search_mode, all_pages_extend, all_pages_min);
this.last_search_bry = search_bry;
if (log_enabled) app.Usr_dlg().Log_many("", "", "search bgn: word=~{0}", String_.new_u8(search_bry));
cur_cmd.Search();
}
} private Xog_search_suggest_cmd cur_cmd; byte[] last_search_bry;
public void Notify() {// EX: receiveSuggestions('search_word', ['result_1', 'result_2']);
// synchronized (thread_lock) NOTE: never use synchronized here; will synchronized search; DATE:2013-09-24
byte[] search_bry = cur_cmd.Search_bry();
if (!Bry_.Eq(search_bry, last_search_bry)) {
if (log_enabled) app.Usr_dlg().Log_many("", "", "search does not match?: expd=~{0} actl=~{1}", String_.new_u8(last_search_bry), String_.new_u8(search_bry));
return; // do not notify if search terms do not match
}
List_adp found = cur_cmd.Results();
wtr.Func_init(cbk_func);
wtr.Prm_bry(search_bry);
wtr.Prm_spr();
wtr.Ary_init();
int len = found.Count();
for (int i = 0; i < len; i++) {
Xowd_page_itm p = (Xowd_page_itm)found.Get_at(i);
Xow_ns ns = wiki.Ns_mgr().Ids_get_or_null(p.Ns_id());
byte[] ttl = Xoa_ttl.Replace_unders(ns.Gen_ttl(p.Ttl_page_db()));
wtr.Ary_bry(ttl);
}
wtr.Ary_term();
wtr.Func_term();
if (log_enabled) app.Usr_dlg().Log_many("", "", "search end: word=~{0}", String_.new_u8(search_bry));
main_win.Active_html_box().Html_js_eval_script(wtr.To_str_and_clear());
}
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk_search_async)) Search_async();
else if (ctx.Match(k, Invk_notify)) Notify();
else if (ctx.Match(k, Invk_enabled)) return Yn.Xto_str(enabled);
else if (ctx.Match(k, Invk_enabled_)) enabled = m.ReadYn("v");
else if (ctx.Match(k, Invk_results_max)) return results_max;
else if (ctx.Match(k, Invk_results_max_)) results_max = m.ReadInt("v");
else if (ctx.Match(k, Invk_search_mode)) return Search_mode_str(search_mode);
else if (ctx.Match(k, Invk_search_mode_)) search_mode = Search_mode_parse(m.ReadStr("v"));
else if (ctx.Match(k, Invk_search_mode_list)) return Options_search_mode_list;
else if (ctx.Match(k, Invk_all_pages_extend)) return all_pages_extend;
else if (ctx.Match(k, Invk_all_pages_extend_)) all_pages_extend = m.ReadInt("v");
else if (ctx.Match(k, Invk_all_pages_min)) return all_pages_min;
else if (ctx.Match(k, Invk_all_pages_min_)) all_pages_min = m.ReadInt("v");
else if (ctx.Match(k, Invk_auto_wildcard)) return Yn.Xto_str(auto_wildcard);
else if (ctx.Match(k, Invk_auto_wildcard_)) auto_wildcard = m.ReadYn("v");
else if (ctx.Match(k, Invk_log_enabled)) return Yn.Xto_str(log_enabled);
else if (ctx.Match(k, Invk_log_enabled_)) log_enabled = m.ReadYn("v");
else if (ctx.Match(k, Invk_args_default)) return args_default_str;
else if (ctx.Match(k, Invk_args_default_)) Args_default_str_(m.ReadStr("v"));
else return GfoInvkAble_.Rv_unhandled;
return this;
}
public static final String Invk_search_async = "search_async", Invk_notify = "notify", Invk_enabled = "enabled", Invk_enabled_ = "enabled_", Invk_results_max = "results_max", Invk_results_max_ = "results_max_"
, Invk_search_mode = "search_mode", Invk_search_mode_ = "search_mode_", Invk_search_mode_list = "search_mode_list"
, Invk_all_pages_extend = "all_pages_extend", Invk_all_pages_extend_ = "all_pages_extend_"
, Invk_all_pages_min = "all_pages_min", Invk_all_pages_min_ = "all_pages_min_"
, Invk_auto_wildcard = "auto_wildcard", Invk_auto_wildcard_ = "auto_wildcard_"
, Invk_log_enabled = "log_enabled", Invk_log_enabled_ = "log_enabled_"
, Invk_args_default = "args_default", Invk_args_default_ = "args_default_"
;
private static final String Str_search_mode_search = "Search", Str_search_mode_all_pages_v1 = "AllPages", Str_search_mode_all_pages_v2 = "AllPages_(v2)";
public static final byte Tid_search_mode_all_pages_v1 = 0, Tid_search_mode_search = 1, Tid_search_mode_all_pages_v2 = 2;
private static KeyVal[] Options_search_mode_list = KeyVal_.Ary(KeyVal_.new_(Str_search_mode_search), KeyVal_.new_(Str_search_mode_all_pages_v1), KeyVal_.new_(Str_search_mode_all_pages_v2));
private static byte Search_mode_parse(String v) {
if (String_.Eq(v, Str_search_mode_search)) return Tid_search_mode_search;
else if (String_.Eq(v, Str_search_mode_all_pages_v1)) return Tid_search_mode_all_pages_v1;
else if (String_.Eq(v, Str_search_mode_all_pages_v2)) return Tid_search_mode_all_pages_v2;
else throw Exc_.new_unhandled(v);
}
private static String Search_mode_str(byte v) {
switch (v) {
case Tid_search_mode_search: return Str_search_mode_search;
case Tid_search_mode_all_pages_v1: return Str_search_mode_all_pages_v1;
case Tid_search_mode_all_pages_v2: return Str_search_mode_all_pages_v2;
default: throw Exc_.new_unhandled(v);
}
}
}

View File

@@ -0,0 +1,219 @@
/*
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.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import org.junit.*; import gplx.xowa.tdbs.*; import gplx.xowa.wikis.data.tbls.*;
public class Xosrh_core_tst {
// @Before public void Init() {fxt.Clear();} private Xos_search_mgr_fxt fxt = new Xos_search_mgr_fxt();
@Test public void Basic() {
// fxt.Init_basic();
// fxt.Test_search_exact("b2", "B2_22", "B2_12", "B2__2");
// fxt.Test_search_exact("a" , "A___0");
// fxt.Test_search_exact("b1a"); // missing: mid
// fxt.Test_search_exact("d"); // missing: end
// fxt.Test_search_exact("$"); // missing: bgn
// fxt.Test_search_match_bgn("b*", "B3_23", "B2_22", "B1_21", "B3_13", "B2_12", "B1_11", "B3__3", "B2__2", "B1__1");
}
// @Test public void Page_size() {
// fxt.Init_basic();
// fxt.Search_mgr().Page_mgr().Itms_per_page_(1);
// fxt.Test_search("b*", 0, "B3_23");
// fxt.Test_search("b*", 1, "B2_22");
// fxt.Test_search("b*", 2, "B1_21");
// fxt.Test_search("b*", 3, "B3_13");
// }
// @Test public void Url() {
// Xoa_url url = Xoa_url_parser.Parse_url(fxt.App(), fxt.Wiki(), "Special:Search/Abc?fulltext=y&xowa_sort=len_desc");
// fxt.Search_mgr().Args_mgr().Clear().Parse(url.Args());
// Tfds.Eq(Xosrh_rslt_itm_sorter.Tid_len_dsc, fxt.Search_mgr().Args_mgr().Sort_tid());
// }
// @Test public void Url_arg_title() {// http://en.wikipedia.org/wiki/Special:Search/Earth?fulltext=yes&title=Mars
// fxt.Test_url_search_bry("Special:Search?fulltext=y&search=Abc" , "Abc"); // query arg
//// fxt.Test_url_search_bry("Special:Search/Abc?fulltext=y" , "Abc"); // leaf
// fxt.Test_url_search_bry("Special:Search/Abc?fulltext=y&search=Def" , "Def"); // leaf overrides query arg
// }
// @Test public void Url_ns() {
// fxt.Test_url__ns("Special:Search?search=Abc&ns0=1&ns1=1", "0|1");
// fxt.Test_url__ns("Special:Search?search=Abc&ns*=1", "*");
// fxt.Test_url__ns("Special:Search?search=Abc", "0");
// }
// @Test public void Html() {
// fxt.Init_basic();
// fxt.Test_html_by_url("B1", "", String_.Concat_lines_nl
// ( "Result '''1''' of '''3''' for '''B1'''<br/>"
// , "{|"
// , "|-"
// , "| [[Special:Search/B1?fulltext=y&xowa_page_index=0|&lt;]]"
// , "| [[Special:Search/B1?fulltext=y&xowa_page_index=1|&gt;]]"
// , "|-"
// , "| [[Special:Search/B1?fulltext=y&xowa_sort=len_desc|length]]"
// , "| [[Special:Search/B1?fulltext=y&xowa_sort=title_asc|title]]"
// , "|-"
// , "| 42 || [[B1 21]]"
// , "|-"
// , "| 22 || [[B1 11]]"
// , "|-"
// , "| 2 || [[B1 1]]"
// , "|-"
// , "| [[Special:Search/B1?fulltext=y&xowa_page_index=0|&lt;]]"
// , "| [[Special:Search/B1?fulltext=y&xowa_page_index=1|&gt;]]"
// , "|}"
// ));
// }
//// @Test public void Page_next() {
//// fxt.Init_basic();
//// fxt.Search_mgr().Page_size_(1);
//// fxt.Test_search(Xows_page__search.Match_tid_all, "B1", 0, "B1 1");
//// fxt.Test_search(Xows_page__search.Match_tid_all, "B1", 1, "B1 11");
//// }
//// @Test public void Misc_url() {
//// fxt.Init_basic();
//// fxt.Search_mgr().Page_size_(1);
//// fxt.Expd_address_page_("Special:Search/B1");
//// fxt.Test_search(Xows_page__search.Match_tid_all, "B1", 0, "B1 1");
//// }
// @Test public void Sort_defaults_to_len_desc() {
// fxt.Init_basic();
// fxt.Search_mgr().Page_mgr().Itms_per_page_(3);
// fxt.Test_search2(Xows_page__search.Match_tid_bgn, "b" , 0, Xosrh_rslt_itm_sorter.Tid_ttl_asc , "B1_11", "B1_21", "B1__1"); // sort by name; note that _ sorts after alphabet
// fxt.Test_search2(Xows_page__search.Match_tid_bgn, "b" , 1, Xosrh_rslt_itm_sorter.Tid_none , "B2_12", "B2_22", "B2__2"); // sort by name still; next page should not reset
// fxt.Test_search2(Xows_page__search.Match_tid_bgn, "b2" , 0, Xosrh_rslt_itm_sorter.Tid_none , "B2_22", "B2_12", "B2__2"); // sort by len desc; new search should reset
// }
}
// class Xos_search_mgr_fxt {
// Xoae_app app; Xowe_wiki wiki; Bry_bfr bfr = Bry_bfr.reset_(500); Xows_page__search search_mgr;
// public Xoae_app App() {return app;}
// public Xowe_wiki Wiki() {return wiki;}
// public Xobl_regy_itm regy_itm_(int id, String bgn, String end, int count) {return new Xobl_regy_itm(id, Bry_.new_u8(bgn), Bry_.new_u8(end), count);}
// public Xowd_page_itm data_ttl_(int id, String ttl) {return data_ttl_(id, 0, 0, false, 0, ttl);}
// public Xowd_page_itm data_ttl_(int id, int fil, int row, boolean redirect, int len, String ttl) {return new Xowd_page_itm().Init(id, Bry_.new_u8(ttl), redirect, len, fil, row);}
// public Xowd_page_itm data_id_(int id, String ttl) {return data_id_(id, Xow_ns_.Id_main, ttl);}
// public Xowd_page_itm data_id_(int id, int ns, String ttl) {return new Xowd_page_itm().Id_(id).Ns_id_(ns).Ttl_page_db_(Bry_.new_u8(ttl)).Text_db_id_(0).Text_len_(0);}
// public Xobl_search_ttl data_sttl_(String word, params int[] ids) {return new Xobl_search_ttl(Bry_.new_u8(word), data_ttl_word_page_ary_(ids));}
// public Xobl_search_ttl_page[] data_ttl_word_page_ary_(params int[] ids) {
// int ids_len = ids.length;
// Xobl_search_ttl_page[] rv = new Xobl_search_ttl_page[ids_len];
// for (int i = 0; i < ids_len; i++) {
// int id = ids[i];
// rv[i] = new Xobl_search_ttl_page(id, id * 2);
// }
// return rv;
// }
// public void Init_regy_site(byte dir_info, params Xobl_regy_itm[] ary) {Init_regy(wiki.Tdb_fsys_mgr().Url_site_reg(dir_info), ary);}
// public void Init_regy_ns (String ns_num, byte tid, params Xobl_regy_itm[] ary) {Init_regy(wiki.Tdb_fsys_mgr().Url_ns_reg(ns_num, tid), ary);}
// public void Init_regy(Io_url url, Xobl_regy_itm[] ary) {
// int ary_len = ary.length;
// for (int i = 0; i < ary_len; i++) {
// Xobl_regy_itm itm = ary[i];
// itm.Srl_save(tmp_bfr);
// }
// Io_mgr.I.SaveFilBfr(url, tmp_bfr);
// } private Bry_bfr tmp_bfr = Bry_bfr.reset_(255);
// public void Init_data(Io_url fil, params Xobl_data_itm[] ary) {
// Xob_xdat_file xdat_file = new Xob_xdat_file();
// int ary_len = ary.length;
// for (int i = 0; i < ary_len; i++) {
// Xobl_data_itm itm = ary[i];
// itm.Srl_save(tmp_bfr);
// xdat_file.Insert(bfr, tmp_bfr.Xto_bry_and_clear());
// }
// xdat_file.Save(fil);
// }
// public void Init_basic() {
// this.Init_regy_ns(wiki.Ns_mgr().Ns_main().Num_str(), Xotdb_dir_info_.Tid_search_ttl, this.regy_itm_(0, "A", "C", 5));
// this.Init_data(wiki.Tdb_fsys_mgr().Url_ns_fil(Xotdb_dir_info_.Tid_search_ttl, Xow_ns_.Id_main, 0)
// , this.data_sttl_("a" , 0)
// , this.data_sttl_("b1" , 1, 11, 21)
// , this.data_sttl_("b2" , 2, 12, 22)
// , this.data_sttl_("b3" , 3, 13, 23)
// , this.data_sttl_("c" , 4)
// );
// this.Init_regy_site(Xotdb_dir_info_.Tid_id, this.regy_itm_(0, "A", "C", 11));
// this.Init_data(wiki.Tdb_fsys_mgr().Url_site_fil(Xotdb_dir_info_.Tid_id, 0)
// , this.data_id_( 0, "A___0")
// , this.data_id_( 1, "B1__1")
// , this.data_id_( 2, "B2__2")
// , this.data_id_( 3, "B3__3")
// , this.data_id_( 4, "C___4")
// , this.data_id_(11, "B1_11")
// , this.data_id_(12, "B2_12")
// , this.data_id_(13, "B3_13")
// , this.data_id_(21, "B1_21")
// , this.data_id_(22, "B2_22")
// , this.data_id_(23, "B3_23")
// );
// search_mgr.Page_mgr().Ns_mgr().Add_all(); // WORKAROUND: xdat fmt does not store ns with search data; pages will be retrieved with ns_id = null; force ns_all (instead of allowing ns_main default);
// }
// public void Clear() {
// Io_mgr.I.InitEngine_mem();
// app = Xoa_app_fxt.app_();
// wiki = Xoa_app_fxt.wiki_tst_(app);
// search_mgr = wiki.Special_mgr().Page_search();
// wiki.Appe().Gui_mgr().Search_suggest_mgr().Args_default_str_("ns*=1"); // WORKAROUND: xdat fmt does not store ns with search data; pages will be retrieved with ns_id = null; force ns_all (instead of allowing ns_main default);
// }
// public Xows_page__search Search_mgr() {return search_mgr;}
// public void Test_url_search_bry(String url_str, String expd) {
// Xoa_url url = Xoa_url_parser.Parse_url(app, wiki, url_str);
// search_mgr.Args_mgr().Clear().Parse(url.Args());
// Tfds.Eq(expd, String_.new_u8(search_mgr.Args_mgr().Search_bry()));
// }
// public void Test_url__ns(String url_str, String expd) {
// Xoa_url url = Xoa_url_parser.Parse_url(app, wiki, url_str);
// search_mgr.Args_mgr().Clear().Parse(url.Args());
// Tfds.Eq(expd, String_.new_a7(search_mgr.Args_mgr().Ns_mgr().Xto_hash_key()));
// }
// public void Test_search_exact(String ttl_str, params String[] expd_ary) {Test_search(ttl_str, 0, expd_ary);}
// public void Test_search_match_bgn(String ttl_str, params String[] expd_ary) {Test_search(ttl_str, 0, expd_ary);}
// public void Test_search(String ttl_str, int page_idx, params String[] expd_ary) {
// byte[] ttl_bry = Bry_.new_a7(ttl_str);
// Bry_bfr bfr = wiki.Utl__bfr_mkr().Get_b128();
// Xosrh_rslt_grp page = search_mgr.Page_mgr().Search(bfr, wiki, ttl_bry, page_idx, search_mgr.Page_mgr());
// bfr.Mkr_rls();
// Tfds.Eq_ary(expd_ary, Search_itms_to_int_ary(page));
// }
// public void Test_html_by_url(String ttl_str, String args_str, String expd_html) {
// wiki.Init_needed_(false);
// byte[] ttl_bry = Bry_.new_a7(ttl_str);
// Xoa_ttl ttl = Xoa_ttl.parse_(wiki, ttl_bry);
// Xoae_page page = Xoae_page.test_(wiki, ttl);
// byte[] url_bry = Bry_.new_u8("http://en.wikipedia.org/wiki/Special:Search/" + ttl_str + args_str);
// Xoa_url url = wiki.Appe().Url_parser().Parse(url_bry);
// search_mgr.Special_gen(url, page, wiki, ttl);
// Tfds.Eq_str_lines(expd_html, String_.new_u8(page.Root().Data_htm()));
// }
// public void Test_search2(byte match_tid, String ttl_str, int page_idx, byte sort_tid, params String[] expd_ary) {
// Bry_bfr bfr = wiki.Utl__bfr_mkr().Get_b128();
// Xoa_url_parser url_parser = new Xoa_url_parser();
// byte[] url_raw = Bry_.new_a7("Special:Search/" + ttl_str + ((match_tid == Xows_page__search.Match_tid_all) ? "" : "*") + "?fulltext=y" + Xosrh_rslt_itm_sorter.Xto_url_arg(sort_tid) + "&xowa_page_size=1&xowa_page_index=" + page_idx);
// Xoa_url url = url_parser.Parse(url_raw);
// Xoa_ttl ttl = Xoa_ttl.parse_(wiki, url_raw);
// Xoae_page page = wiki.Ctx().Cur_page();
// search_mgr.Special_gen(url, page, wiki, ttl);
// Xosrh_rslt_grp cur_grp = search_mgr.Cur_grp();
// bfr.Mkr_rls();
// Tfds.Eq_ary(expd_ary, Search_itms_to_int_ary(cur_grp));
// }
// String[] Search_itms_to_int_ary(Xosrh_rslt_grp page) {
// int itms_len = page.Itms_len();
// String[] rv = new String[itms_len];
// for (int i = 0; i < itms_len; i++) {
// Xowd_page_itm itm = page.Itms_get_at(i);
// rv[i] = String_.new_u8(itm.Ttl_page_db());
// }
// return rv;
// }
// }

View File

@@ -0,0 +1,98 @@
/*
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.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import gplx.xowa.wikis.data.tbls.*;
public class Xosrh_page_mgr implements Xosrh_page_mgr_searcher {
public int Pages_len() {return pages_ary.length;}
public int Itms_bgn() {return itms_bgn;} private int itms_bgn;
public int Itms_end() {return itms_end;} private int itms_end;
public int Itms_per_page() {return itms_per_page;} public Xosrh_page_mgr Itms_per_page_(int v) {itms_per_page = v; return this;} private int itms_per_page = 100;
public byte Sort_tid() {return sort_tid;}
public Xosrh_page_mgr Sort_tid_(byte v) {
if (sort_tid == v) return this;
sort_tid = v;
sorter.Tid_(v);
prv_search_bry = Bry_.Empty; // reset search
return this;
} byte sort_tid;
private byte[] prv_search_bry = Bry_.Empty, prv_ns_bry = Bry_.Empty;
public boolean Prv_search_is_same(byte[] cur_search_bry, byte[] cur_ns_bry) {
return Bry_.Eq(cur_ns_bry, prv_ns_bry) && Bry_.Eq(cur_search_bry, prv_search_bry);
}
private Xosrh_rslt_grp[] pages_ary; List_adp cur_ids = List_adp_.new_();
private Xosrh_rslt_itm_sorter sorter = new Xosrh_rslt_itm_sorter();
private Xowe_wiki wiki;
public Xows_ns_mgr Ns_mgr() {return ns_mgr;} public void Ns_mgr_(Xows_ns_mgr v) {ns_mgr = v;} private Xows_ns_mgr ns_mgr = new Xows_ns_mgr();
public Xosrh_rslt_grp Search(Bry_bfr bfr, Xowe_wiki wiki, byte[] search, int page_idx, Xosrh_page_mgr_searcher searcher) {return Search(bfr, wiki, search, page_idx, searcher, Cancelable_.Never);}
public Xosrh_rslt_grp Search(Bry_bfr bfr, Xowe_wiki wiki, byte[] search, int page_idx, Xosrh_page_mgr_searcher searcher, Cancelable cancelable) {
this.wiki = wiki;
Xosrh_rslt_grp rv = null;
itms_bgn = page_idx * itms_per_page;
itms_end = itms_bgn + itms_per_page;
if (Prv_search_is_same(search, ns_mgr.To_hash_key())) { // search is same
if (page_idx < pages_ary.length) { // page_idx is in bounds
rv = pages_ary[page_idx];
if (rv != null) return rv; // page_found; return it;
}
}
else { // search is new; rebuild;
List_adp ids = searcher.Parse_search_and_load_ids(cancelable, bfr, ns_mgr, search);
Rebuild(cancelable, wiki, ids);
prv_search_bry = search;
prv_ns_bry = ns_mgr.To_hash_key();
}
int ids_len = cur_ids.Count();
if (itms_end > ids_len) itms_end = ids_len;
if (page_idx < 0 || page_idx >= pages_ary.length) return Grp_empty;
if ( sort_tid != Xosrh_rslt_itm_sorter.Tid_ttl_asc
&& cancelable == Cancelable_.Never // cancelable != Cancelable_.Never for search_suggest
&& wiki.Db_mgr().Tid() == gplx.xowa.dbs.Xodb_mgr_txt.Tid_txt // txt only has search_title fields (page_id, word_id), so it needs to do another load to get page fields; note that sql has page fields already
) {
wiki.Db_mgr().Load_mgr().Load_by_ids(cancelable, cur_ids, itms_bgn, itms_end);
}
rv = new Xosrh_rslt_grp(page_idx);
for (int i = itms_bgn; i < itms_end; i++)
rv.Itms_add((Xowd_page_itm)cur_ids.Get_at(i));
pages_ary[page_idx] = rv;
rv.Itms_total_(cur_ids.Count());
return rv;
}
public List_adp Parse_search_and_load_ids(Cancelable cancelable, Bry_bfr bfr, Xows_ns_mgr ns_mgr, byte[] search) {
search = wiki.Lang().Case_mgr().Case_build_lower(search, 0, search.length);
Xosrh_qry_itm cur_root = Xosrh_parser._.Parse(search);
cur_root.Search(cancelable, bfr, search, wiki, itms_per_page, ns_mgr);
return cur_root.Matches(search).Ids();
}
private void Rebuild(Cancelable cancelable, Xowe_wiki wiki, List_adp ids) {
int ids_len = ids.Count();
int pages_len = ((ids_len - 1) / itms_per_page) + 1; if (pages_len == 0) pages_len = 1;
pages_ary = new Xosrh_rslt_grp[pages_len];
cur_ids.Clear();
for (int i = 0; i < ids_len; i++)
cur_ids.Add(ids.Get_at(i));
if (sort_tid == Xosrh_rslt_itm_sorter.Tid_ttl_asc) {
cur_ids.Sort_by(sorter.Tid_(Xosrh_rslt_itm_sorter.Tid_id));
wiki.Db_mgr().Load_mgr().Load_by_ids(cancelable, cur_ids, 0, ids_len);
cur_ids.Sort_by(sorter.Tid_(Xosrh_rslt_itm_sorter.Tid_ttl_asc));
}
else {
cur_ids.Sort_by(sorter.Tid_(Xosrh_rslt_itm_sorter.Tid_len_dsc));
}
}
private static final Xosrh_rslt_grp Grp_empty = new Xosrh_rslt_grp(-1);
}

View File

@@ -0,0 +1,21 @@
/*
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.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
public interface Xosrh_page_mgr_searcher {
List_adp Parse_search_and_load_ids(Cancelable cancelable, Bry_bfr bfr, Xows_ns_mgr ns_Mgr, byte[] search);
}

View File

@@ -0,0 +1,86 @@
/*
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.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import org.junit.*; import gplx.xowa.tdbs.*; import gplx.xowa.wikis.data.tbls.*;
public class Xosrh_page_mgr_tst {
@Before public void init() {fxt.Clear();} private Xosrh_page_mgr_fxt fxt = new Xosrh_page_mgr_fxt();
@Test public void Basic() {
fxt.Init_itms_per_page_(3).Init_site_ids(10, 20);
Xosrh_page_mgr_searcher ids_a = fxt.ids_(10, 17);
fxt.Test_search("A", ids_a, 0, Int_.Ary(16, 15, 14));
fxt.Test_search("A", ids_a, 1, Int_.Ary(13, 12, 11));
fxt.Test_search("A", ids_a, 2, Int_.Ary(10));
fxt.Test_search("A", ids_a, 0, Int_.Ary(16, 15, 14));
Xosrh_page_mgr_searcher ids_b = fxt.ids_(17, 20);
fxt.Init_sort_by_name_(true).Test_search("B", ids_b, 0, Int_.Ary(17, 18, 19));
}
}
class Xosrh_page_mgr_fxt {
public Xosrh_page_mgr_fxt Clear() {
if (app == null) {
app = Xoa_app_fxt.app_();
wiki = Xoa_app_fxt.wiki_tst_(app);
tmp_bfr = Bry_bfr.reset_(255);
page_mgr = new Xosrh_page_mgr();
hive_mgr = new Xowd_hive_mgr(wiki, Xotdb_dir_info_.Tid_id);
}
return this;
} private Xoae_app app; Xowe_wiki wiki; Bry_bfr tmp_bfr; Xosrh_page_mgr page_mgr; Xowd_hive_mgr hive_mgr;
public Xosrh_page_mgr_fxt Init_site_ids(int bgn, int end) {
Xowd_page_itm tmp_itm = new Xowd_page_itm();
for (int i = bgn; i < end; i++) {
byte[] id_bry = new byte[5]; // NOTE: do not reuse; will break hive_mgr
Base85_utl.XtoStrByAry(i, id_bry, 0, 5);
tmp_itm.Ns_id_(Xow_ns_.Id_main).Init(i, Bry_.XtoStrBytesByInt(i, 0), false, 10, 0, i - bgn);
Xotdb_page_itm_.Txt_id_save(tmp_bfr, tmp_itm);
hive_mgr.Create(id_bry, tmp_bfr.Xto_bry_and_clear(), null);
}
return this;
}
// public Xowd_page_itm Set_all(int id, int fil_idx, int row_idx, boolean type_redirect, int itm_len, int ns_id, byte[] ttl) {
public Xosrh_page_mgr_fxt Init_sort_by_name_(boolean v) {page_mgr.Sort_tid_(v ? Xosrh_rslt_itm_sorter.Tid_ttl_asc : Xosrh_rslt_itm_sorter.Tid_len_dsc); return this;}
public Xosrh_page_mgr_fxt Init_itms_per_page_(int v) {page_mgr.Itms_per_page_(v); return this;}
public Xosrh_page_mgr_searcher_mok ids_(int bgn, int end) {
List_adp rv = List_adp_.new_();
int len = end - bgn;
for (int i = 0; i < len; i++) {
int itm_id = i + bgn;
int itm_len = itm_id;
Xowd_page_itm itm = Xowd_page_itm.new_srch(itm_id, itm_len);
rv.Add(itm);
}
return new Xosrh_page_mgr_searcher_mok(rv);
}
public void Test_search(String search_str, Xosrh_page_mgr_searcher searcher, int page_idx, int[] expd) {
byte[] search_bry = Bry_.new_a7(search_str);
Xosrh_rslt_grp page = page_mgr.Search(tmp_bfr, wiki, search_bry, page_idx, searcher);
Tfds.Eq_ary(expd, Xto_int_ary(page));
}
int[] Xto_int_ary(Xosrh_rslt_grp page) {
int len = page.Itms_len();
int[] rv = new int[len];
for (int i = 0; i < len; i++) {
rv[i] = ((Xowd_page_itm)page.Itms_get_at(i)).Id();
}
return rv;
}
}
class Xosrh_page_mgr_searcher_mok implements Xosrh_page_mgr_searcher {
public Xosrh_page_mgr_searcher_mok(List_adp list) {this.list = list;} List_adp list;
public List_adp Parse_search_and_load_ids(Cancelable cancelable, Bry_bfr bfr, Xows_ns_mgr ns_mgr, byte[] search) {return list;}
}

View File

@@ -0,0 +1,88 @@
/*
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.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
class Xosrh_parser {
public Xosrh_qry_itm Parse(byte[] src) {
this.src = src;
Xosrh_qry_tkn[] tkns = Xosrh_scanner._.Scan(src);
return Parse_itm_or(make_ctx.Init(tkns));
} private Xosrh_parser_ctx make_ctx = new Xosrh_parser_ctx(); byte[] src;
Xosrh_qry_itm Parse_itm_or(Xosrh_parser_ctx make_ctx) {
Xosrh_qry_itm lhs = Parse_itm_and(make_ctx);
while (make_ctx.Cur_tid(Xosrh_qry_tkn.Tid_or)) {
make_ctx.Move_next();
Xosrh_qry_itm rhs = Parse_itm_and(make_ctx);
lhs = Xosrh_qry_itm.nde_(Xosrh_qry_itm.Tid_or, lhs, rhs);
}
return lhs;
}
Xosrh_qry_itm Parse_itm_and(Xosrh_parser_ctx make_ctx) {
Xosrh_qry_itm lhs = Parse_itm_not(make_ctx);
while (make_ctx.Cur_tid(Xosrh_qry_tkn.Tid_and)) {
make_ctx.Move_next();
Xosrh_qry_itm rhs = Parse_itm_not(make_ctx);
lhs = Xosrh_qry_itm.nde_(Xosrh_qry_itm.Tid_and, lhs, rhs);
}
return lhs;
}
Xosrh_qry_itm Parse_itm_not(Xosrh_parser_ctx make_ctx) {
Xosrh_qry_itm lhs = Parse_itm_leaf(make_ctx);
while (make_ctx.Cur_tid(Xosrh_qry_tkn.Tid_not)) {
make_ctx.Move_next();
Xosrh_qry_itm rhs = Parse_itm_leaf(make_ctx);
lhs = Xosrh_qry_itm.nde_(Xosrh_qry_itm.Tid_not, null, rhs);
}
return lhs;
}
Xosrh_qry_itm Parse_itm_leaf(Xosrh_parser_ctx make_ctx) {
if (make_ctx.Cur_tid(Xosrh_qry_tkn.Tid_paren_bgn)) {
make_ctx.Move_next();
Xosrh_qry_itm lhs = Parse_itm_or(make_ctx);
if (make_ctx.Cur_tid(Xosrh_qry_tkn.Tid_paren_end)) make_ctx.Move_next(); // skip token
return lhs;
}
else if (make_ctx.Cur_tid(Xosrh_qry_tkn.Tid_eos))
return Xosrh_qry_itm.Null;
else {
Xosrh_qry_tkn word_tkn = make_ctx.Move_next();
if (word_tkn.Tid() == Xosrh_qry_tkn.Tid_not) {
word_tkn = make_ctx.Move_next();
if (word_tkn == null) return Xosrh_qry_itm.Null; // occurs in "a -"
Xosrh_qry_itm word_itm = Xosrh_qry_itm.word_(src, word_tkn);
return Xosrh_qry_itm.nde_(Xosrh_qry_itm.Tid_not, null, word_itm);
}
else
return Xosrh_qry_itm.word_(src, word_tkn);
}
}
public static final Xosrh_parser _ = new Xosrh_parser(); Xosrh_parser() {}
}
class Xosrh_parser_ctx {
public Xosrh_parser_ctx Init(Xosrh_qry_tkn[] ary) {
this.ary = ary;
ary_len = ary.length;
this.pos = 0;
return this;
} private Xosrh_qry_tkn[] ary; int pos = 0; int ary_len;
public boolean Cur_tid(byte tid) {return pos < ary_len ? tid == ary[pos].Tid(): tid == Xosrh_qry_tkn.Tid_eos;}
public Xosrh_qry_tkn Move_next() {
Xosrh_qry_tkn rv = null;
if (pos < ary_len) rv = ary[pos++];
return rv;
}
}

View File

@@ -0,0 +1,168 @@
/*
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.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import org.junit.*; import gplx.xowa.tdbs.*; import gplx.xowa.wikis.data.tbls.*;
public class Xosrh_parser_tst {
@Before public void init() {fxt.Clear();} private Xosearch_parser_fxt fxt = new Xosearch_parser_fxt();
@Test public void Scan_word() {fxt.Test_scan("abc", "abc");}
@Test public void Scan_word_many() {fxt.Test_scan("abc d ef", "abc", "AND", "d", "AND", "ef");}
@Test public void Scan_word_symbol() {fxt.Test_scan("a, b", "a", "AND", "b");}
@Test public void Scan_and_embedded() {fxt.Test_scan("candy", "candy");} // check that andy does not become "AND" + y
@Test public void Scan_and_and() {fxt.Test_scan("a andand", "a", "AND", "andand");} // check that andand is word; note that AND is automatically inserted between consecutive words
@Test public void Scan_and_parentheses() {fxt.Test_scan("a and(b)", "a", "and", "(", "b", ")");} // check that ( causes and to be treated as separate word
@Test public void Scan_not() {fxt.Test_scan("-abc", "-", "abc");}
@Test public void Scan_not_and() {fxt.Test_scan("a -bc", "a", "AND", "-", "bc");} // auto-add AND for -
@Test public void Scan_space() {fxt.Test_scan(" a b ", "a", "AND", "b");} // spaces should not generate tkns
@Test public void Scan_quote() {fxt.Test_scan("\"abc\"", "abc");}
@Test public void Scan_complicated() {fxt.Test_scan("(a AND \"b\") OR -c", "(", "a","AND", "b", ")", "OR", "-", "c");}
@Test public void Scan_not_embedded() {
fxt.Test_scan ("a-b", "a-b"); // fail if "a", "NOT", "b"
fxt.Test_scan_tids ("a-b", Xosrh_qry_tkn.Tid_word_quoted); // symbols in unquoted word should convert word to quotes; EX: a-b -> "a-b"
}
@Test public void Parse_basic() {fxt.Test_parse("abc", "abc");}
@Test public void Parse_and() {fxt.Test_parse("abc AND def", "(abc AND def)");}
@Test public void Parse_not() {fxt.Test_parse("-abc", "NOT abc");}
@Test public void Parse_many() {fxt.Test_parse("A AND B OR C AND D", "((A AND B) OR (C AND D))");}
@Test public void Match() {
fxt.Init_match("A", 11, 12, 22);
fxt.Init_match("B", 21, 22, 12);
fxt.Test_match("A OR B" , 11, 12, 22, 21);
fxt.Test_match("A AND B" , 22, 12);
fxt.Test_match("A AND -B" , 11);
}
@Test public void Search() {
Xosearch_searcher_fxt fxt = new Xosearch_searcher_fxt().Clear();
fxt.Init_search("a1", 11, 12);
fxt.Init_search("b1", 21, 22);
fxt.Init_search("b2", 26, 27);
fxt.Init_search("c1", 31, 12);
fxt.Test_search("b1", 21, 22);
fxt.Test_search("b*", 21, 22, 26, 27);
}
}
class Xosearch_searcher_fxt {
public Xosearch_searcher_fxt Clear() {
if (app == null) {
app = Xoa_app_fxt.app_();
wiki = Xoa_app_fxt.wiki_tst_(app);
mgr = new Xowd_hive_mgr(wiki, Xotdb_dir_info_.Tid_search_ttl);
tmp_bfr = Bry_bfr.reset_(255);
parser = Xosrh_parser._;
}
return this;
}
Xoae_app app; Xowe_wiki wiki; Xowd_hive_mgr mgr; Bry_bfr tmp_bfr;
Xosrh_parser parser;
public void Init_search(String ttl_str, int... ids) {
byte[] ttl_bry = Bry_.new_a7(ttl_str);
tmp_bfr.Add(ttl_bry);
int len = ids.length;
for (int i = 0; i < len; i++) {
int id = ids[i];
tmp_bfr.Add_byte_pipe();
tmp_bfr.Add_base85_len_5(id);
tmp_bfr.Add_byte(Byte_ascii.Semic);
tmp_bfr.Add_base85_len_5(0);
}
mgr.Create(wiki.Ns_mgr().Ns_main(), ttl_bry, tmp_bfr.Xto_bry_and_clear(), null);
}
public void Test_search(String ttl_str, int... expd) {
byte[] ttl_bry = Bry_.new_a7(ttl_str);
Xosrh_qry_itm qry_root = parser.Parse(ttl_bry);
Xows_ns_mgr ns_mgr = new Xows_ns_mgr(); ns_mgr.Add_all(); // WORKAROUND: xdat fmt does not store ns with search data; pages will be retrieved with ns_id = null; force ns_all (instead of allowing ns_main default);
qry_root.Search(Cancelable_.Never, tmp_bfr, ttl_bry, wiki, 100, ns_mgr);
int[] actl = Xosearch_parser_fxt.Xto_ints(qry_root.Ids());
Tfds.Eq_ary(expd, actl);
}
}
class Xosearch_parser_fxt {
public Xosearch_parser_fxt Clear() {
if (parser == null) {
parser = Xosrh_parser._;
matches = Ordered_hash_.new_bry_();
}
matches.Clear();
return this;
} private Xosrh_parser parser; Ordered_hash matches;
public void Init_match(String name, int... ids) {
int len = ids.length;
List_adp id_vals = List_adp_.new_();
for (int i = 0; i < len; i++)
id_vals.Add(Xowd_page_itm.new_srch(ids[i], 0));
matches.Add(Bry_.new_a7(name), id_vals);
}
public void Test_match(String raw, int... expd) {
byte[] src = Bry_.new_a7(raw);
Xosrh_qry_itm qry_root = parser.Parse(src);
Test_match_assign_ids(src, qry_root);
Xosrh_qry_ids matches = qry_root.Matches(src);
Tfds.Eq_ary(expd, Xto_ints(matches.Ids()));
}
public static int[] Xto_ints(List_adp list) {
if (list == null) return Int_.Ary_empty;
int len = list.Count();
int[] rv = new int[len];
for (int i = 0; i < len; i++)
rv[i] = ((Xowd_page_itm)list.Get_at(i)).Id();
return rv;
}
private void Test_match_assign_ids(byte[] src, Xosrh_qry_itm itm) {
if (itm.Tid() == Xosrh_qry_itm.Tid_word) {
byte[] word = itm.Word();
List_adp ids = (List_adp)matches.Get_by(word);
itm.Ids_(ids);
}
else {
if (itm.Lhs() != null) Test_match_assign_ids(src, itm.Lhs());
if (itm.Rhs() != null) Test_match_assign_ids(src, itm.Rhs());
}
}
public void Test_scan(String raw, String... expd) {
byte[] src = Bry_.new_a7(raw);
Xosrh_qry_tkn[] actl_itms = Xosrh_scanner._.Scan(src);
Tfds.Eq_ary(expd, To_strings(src, actl_itms));
}
public void Test_scan_tids(String raw, byte... expd) {
byte[] src = Bry_.new_a7(raw);
Xosrh_qry_tkn[] actl_itms = Xosrh_scanner._.Scan(src);
Tfds.Eq_ary(expd, To_tids(actl_itms));
}
String[] To_strings(byte[] src, Xosrh_qry_tkn[] ary) {
int len = ary.length;
String[] rv = new String[len];
for (int i = 0; i < len; i++) {
Xosrh_qry_tkn tkn = ary[i];
rv[i] = String_.new_a7(tkn.Val(src));
}
return rv;
}
byte[] To_tids(Xosrh_qry_tkn[] ary) {
int len = ary.length;
byte[] rv = new byte[len];
for (int i = 0; i < len; i++) {
Xosrh_qry_tkn tkn = ary[i];
rv[i] = tkn.Tid();
}
return rv;
}
public void Test_parse(String raw, String expd) {
byte[] src = Bry_.new_a7(raw);
Xosrh_qry_itm qry_root = parser.Parse(src);
Tfds.Eq(expd, qry_root.Xto_str(src));
}
}

View File

@@ -0,0 +1,219 @@
/*
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.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import gplx.xowa.dbs.*; import gplx.xowa.wikis.data.tbls.*; import gplx.xowa.bldrs.cmds.texts.*;
class Xosrh_qry_itm {
public Xosrh_qry_itm(byte tid, byte[] word, Xosrh_qry_itm lhs, Xosrh_qry_itm rhs) {
this.tid = tid; this.word = word; this.lhs = lhs; this.rhs = rhs;
}
public byte Tid() {return tid;} private byte tid;
public Xosrh_qry_itm Lhs() {return lhs;} private Xosrh_qry_itm lhs;
public Xosrh_qry_itm Rhs() {return rhs;} private Xosrh_qry_itm rhs;
public List_adp Ids() {return ids;} public void Ids_(List_adp v) {this.ids = v;} List_adp ids = List_adp_.Noop;
public byte[] Word() {return word;} private byte[] word;
public String Xto_str(byte[] src) {
Bry_bfr bfr = Bry_bfr.new_();
Xto_str_bld(src, bfr);
return bfr.Xto_str_and_clear();
}
public Xosrh_qry_ids Matches(byte[] src) {
switch (tid) {
case Xosrh_qry_itm.Tid_word:
case Xosrh_qry_itm.Tid_word_quote:
return new Xosrh_qry_ids(false, ids);
case Xosrh_qry_itm.Tid_not: Xosrh_qry_ids rv = rhs.Matches(src); return rv.Not_(!rv.Not());
case Xosrh_qry_itm.Tid_or:
case Xosrh_qry_itm.Tid_and:
List_adp merged = Evaluate(src, tid == Xosrh_qry_itm.Tid_and, lhs, rhs);
return new Xosrh_qry_ids(false, merged);
case Xosrh_qry_itm.Tid_null: return Xosrh_qry_ids.Null;
default: throw Exc_.new_unhandled(tid);
}
}
private static List_adp Search_word(Xowe_wiki wiki, Cancelable cancelable, Bry_bfr tmp_bfr, Xows_ns_mgr ns_mgr, byte[] search_word, int results_max) {
List_adp found = List_adp_.new_();
byte wiki_db_tid = wiki.Db_mgr().Tid();
if (wiki_db_tid == Xodb_mgr_sql.Tid_sql
&& wiki.Appe().Gui_mgr().Search_suggest_mgr().Auto_wildcard()) { // HACK: auto-asterisk words for sqlite; DATE:2013-09-05
if (!Bry_.Has_at_end(search_word, new byte[] {Byte_ascii.Star}))
search_word = Bry_.Add(search_word, Byte_ascii.Star);
if (!Bry_.Has_at_bgn(search_word, new byte[] {Byte_ascii.Star}))
search_word = Bry_.Add(Byte_ascii.Star, search_word);
}
wiki.Db_mgr().Load_mgr().Load_search(cancelable, found, search_word, results_max);
List_adp rv = List_adp_.new_();
int found_len = found.Count();
for (int i = 0; i < found_len; i++) {
Xowd_page_itm page = (Xowd_page_itm)found.Get_at(i);
if ( ns_mgr.Has(page.Ns_id())
|| wiki_db_tid == Xodb_mgr_txt.Tid_txt) // xdat does not store ns, so ns will always be null; no choice but to bring back all results; DATE:2013-11-14
rv.Add(page);
}
return rv;
}
public void Search(Cancelable cancelable, Bry_bfr tmp_bfr, byte[] src, Xowe_wiki wiki, int results_max, Xows_ns_mgr ns_mgr) {
if (cancelable.Canceled()) return;
switch (tid) {
case Xosrh_qry_itm.Tid_null: return;
case Xosrh_qry_itm.Tid_word:
ids = Search_word(wiki, cancelable, tmp_bfr, ns_mgr, word, results_max);
break;
case Xosrh_qry_itm.Tid_word_quote:
Ordered_hash tmp_search_list = Ordered_hash_.new_();
byte[][] words = gplx.xowa.bldrs.cmds.texts.Xob_search_base.Split_ttl_into_words(wiki.Lang(), tmp_search_list, tmp_bfr, word);
int words_len = words.length;
List_adp prv_list = null;
for (int i = 0; i < words_len; i++) {
if (cancelable.Canceled()) return;
List_adp cur_list = Search_word(wiki, cancelable, tmp_bfr, ns_mgr, words[i], results_max);
if (prv_list == null) // 1st list; just set to cur_list
prv_list = cur_list;
else { // nth list; AND to prv_list; "A B" should find all titles with "A AND B"
prv_list = Evaluate(word, true, prv_list, false, cur_list, false);
}
}
List_adp tmp_ids = prv_list;
int ids_len = tmp_ids.Count();
if (ids_len == 0) return;
if (cancelable.Canceled()) return;
wiki.Db_mgr().Load_mgr().Load_by_ids(cancelable, tmp_ids, 0, ids_len);
if (cancelable.Canceled()) return;
ids = List_adp_.new_();
for (int i = 0; i < ids_len; i++) {
Xowd_page_itm itm = (Xowd_page_itm)tmp_ids.Get_at(i);
byte[] itm_ttl = itm.Ttl_page_db();
itm_ttl = wiki.Lang().Case_mgr().Case_build_lower(itm_ttl, 0, itm_ttl.length); // lowercase ttl (since all search words are lower-cased)
itm_ttl = Bry_.Replace(itm_ttl, Byte_ascii.Underline, Byte_ascii.Space); // replace _ with " " (assume user will use spaces in search term)
if (Bry_finder.Find_fwd(itm_ttl, word) != Bry_.NotFound)
ids.Add(itm);
}
break;
default:
if (lhs != null) lhs.Search(cancelable, tmp_bfr, src, wiki, results_max, ns_mgr);
if (rhs != null) rhs.Search(cancelable, tmp_bfr, src, wiki, results_max, ns_mgr);
break;
}
}
static final byte Evaluate_tid_null = 0, Evaluate_tid_and = 1, Evaluate_tid_or = 2, Evaluate_tid_not_and = 3;
List_adp Evaluate(byte[] src, boolean join_tid_is_and, Xosrh_qry_itm lhs, Xosrh_qry_itm rhs) {
Xosrh_qry_ids lhs_grp = lhs.Matches(src), rhs_grp = rhs.Matches(src);
boolean lhs_not = lhs_grp.Not(), rhs_not = rhs_grp.Not();
List_adp lhs_list = lhs_grp.Ids(), rhs_list = rhs_grp.Ids();
if (lhs_not && rhs_not) return Evaluate_not_found("NOT cannot be applied to both lists: lhs:~{0} rhs:~{1}", lhs.Xto_str(src), rhs.Xto_str(src));
return Evaluate(src, join_tid_is_and, lhs_list, lhs_not, rhs_list, rhs_not);
}
/*
AND,0 nots: hash a; iterate cur_b and add if in a
OR ,0 nots; hash a; add a; iterate cur_b and add if not in a
AND,1 nots; hash notted; iterate comp and add only if not in notted; (a,cur_b,c) AND NOT (cur_b)
AND,2 nots; fail; NOT xq AND NOT qx will yield all titles
OR ,2 nots; fail; NOT xq OR NOT qx will yield all titles
OR ,1 nots; fail; (a, cur_b, c, d) OR NOT (xq) will yield all titles
*/
List_adp Evaluate(byte[] src, boolean join_tid_is_and, List_adp lhs_list, boolean lhs_not, List_adp rhs_list, boolean rhs_not) {
List_adp list_to_hash = null, list_to_comp = null; int len = 0;
byte tid = Evaluate_tid_null;
List_adp rv = List_adp_.new_();
if (lhs_not || rhs_not) {
if (!join_tid_is_and)
return Evaluate_not_found("NOT cannot be applied with OR: lhs:~{0} rhs:~{1}", lhs.Xto_str(src), rhs.Xto_str(src));
if (lhs_not) {
list_to_hash = lhs_list;
list_to_comp = rhs_list;
}
else {
list_to_hash = rhs_list;
list_to_comp = lhs_list;
}
tid = Evaluate_tid_not_and;
}
else {
tid = join_tid_is_and ? Evaluate_tid_and : Evaluate_tid_or;
boolean rhs_is_smaller = rhs_list.Count() < lhs_list.Count();
if (rhs_is_smaller) {
list_to_hash = rhs_list;
list_to_comp = lhs_list;
}
else {
list_to_hash = lhs_list;
list_to_comp = rhs_list;
}
}
len = list_to_hash.Count();
for (int i = 0; i < len; i++) {
Xowd_page_itm id = (Xowd_page_itm)list_to_hash.Get_at(i);
try {
if (!tmp_hash.Has(id.Id_val())) tmp_hash.Add(id.Id_val(), id);
} catch (Exception e) {Exc_.Noop(e); tmp_hash.Clear(); return List_adp_.Noop;} // handle error in case of threading issues; must clear tmp_hash else will accumulate;
if (tid == Evaluate_tid_or)
rv.Add(id);
}
len = list_to_comp.Count();
for (int i = 0; i < len; i++) {
Xowd_page_itm id = (Xowd_page_itm)list_to_comp.Get_at(i);
boolean exists = tmp_hash.Has(id.Id_val());
switch (tid) {
case Evaluate_tid_and: // iterate comp and add if in a; EX: (a,cur_b,c) AND (a,d); add a
if (exists) rv.Add(id);
break;
case Evaluate_tid_or: // iterate comp and add if not in a; EX: (a,cur_b,c) OR (a,d); add d
case Evaluate_tid_not_and: // iterate comp and add only if not in notted; (a,cur_b,c) AND NOT (cur_b); add a, c
if (!exists)
rv.Add(id);
break;
case Evaluate_tid_null: default:
throw Exc_.new_unhandled(tid);
}
}
tmp_hash.Clear();
return rv;
} static Ordered_hash tmp_hash = Ordered_hash_.new_();
List_adp Evaluate_not_found(String msg, Object... args) {
return null;
}
public void Xto_str_bld(byte[] src, Bry_bfr bfr) {
switch (tid) {
case Xosrh_qry_itm.Tid_word: bfr.Add(word); break;
case Xosrh_qry_itm.Tid_not: bfr.Add(Bry_not); rhs.Xto_str_bld(src, bfr); break;
case Xosrh_qry_itm.Tid_or:
case Xosrh_qry_itm.Tid_and:
bfr.Add_byte(Byte_ascii.Paren_bgn);
lhs.Xto_str_bld(src, bfr);
bfr.Add(tid == Xosrh_qry_itm.Tid_or ? Bry_or : Bry_and);
rhs.Xto_str_bld(src, bfr);
bfr.Add_byte(Byte_ascii.Paren_end);
break;
case Xosrh_qry_itm.Tid_null: break;
default: throw Exc_.new_unhandled(tid);
}
}
public static final byte Tid_null = 0, Tid_root = 1, Tid_word = 2, Tid_word_quote = 3, Tid_not = 4, Tid_or = 5, Tid_and = 6;
public static byte[] Bry_not = Bry_.new_a7("NOT "), Bry_and = Bry_.new_a7(" AND "), Bry_or = Bry_.new_a7(" OR ");
public static final Xosrh_qry_itm Null = new Xosrh_qry_itm(Tid_null, null, null, null);
public static Xosrh_qry_itm nde_(byte tid, Xosrh_qry_itm lhs, Xosrh_qry_itm rhs) {return new Xosrh_qry_itm(tid, null, lhs, rhs);}
public static Xosrh_qry_itm word_(byte[] src, Xosrh_qry_tkn word_tkn) {
byte tid = word_tkn.Tid() == Xosrh_qry_tkn.Tid_word ? Xosrh_qry_itm.Tid_word : Xosrh_qry_itm.Tid_word_quote;
return new Xosrh_qry_itm(tid, word_tkn.Val(src), null, null);
}
}
class Xosrh_qry_ids {
public Xosrh_qry_ids(boolean not, List_adp ids) {this.not = not; this.ids = ids;}
public boolean Not() {return not;} public Xosrh_qry_ids Not_(boolean v) {not = v; return this;} private boolean not;
public List_adp Ids() {return ids;} public Xosrh_qry_ids Ids_(List_adp v) {ids = v; return this;} List_adp ids = List_adp_.Noop;
public static final Xosrh_qry_ids Null = new Xosrh_qry_ids(false, List_adp_.Noop);
}

View File

@@ -0,0 +1,44 @@
/*
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.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import gplx.xowa.wikis.data.tbls.*;
public class Xosrh_rslt_grp {
public Xosrh_rslt_grp(int idx) {this.idx = idx;} private Xowd_page_itm[] itms = Xowd_page_itm.Ary_empty;
public int Idx() {return idx;} private int idx;
public int Itms_len() {return itms_len;} private int itms_len; int itms_max;
public int Itms_total() {return itms_total;} public Xosrh_rslt_grp Itms_total_(int v) {itms_total = v; return this;} private int itms_total;
public Xowd_page_itm Itms_get_at(int i) {return itms[i];}
public void Itms_add(Xowd_page_itm itm) {
int new_itms_len = itms_len + 1;
if (new_itms_len > itms_max) {
itms_max = itms_max == 0 ? 2 : itms_max * 2;
itms = (Xowd_page_itm[])Array_.Resize(itms, itms_max);
}
itms[itms_len] = itm;
itms_len = new_itms_len;
}
public boolean Itms_full() {return itms_len >= itms_max;}
public void Itms_clear() {
for (int i = 0; i < itms_len; i++)
itms[i] = null;
itms = Xowd_page_itm.Ary_empty;
itms_len = itms_max = 0;
}
public void Itms_sort(Xowd_page_itm_sorter sorter) {Array_.Sort(itms, sorter);}
public static final Xosrh_rslt_grp[] Ary_empty = new Xosrh_rslt_grp[0];
}

View File

@@ -0,0 +1,52 @@
/*
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.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import gplx.xowa.wikis.data.tbls.*;
public class Xosrh_rslt_itm_sorter implements gplx.lists.ComparerAble {
public byte Tid() {return tid;} public Xosrh_rslt_itm_sorter Tid_(byte v) {tid = v; return this;} private byte tid = Tid_len_dsc;
public int compare(Object lhsObj, Object rhsObj) {
Xowd_page_itm lhs = (Xowd_page_itm)lhsObj;
Xowd_page_itm rhs = (Xowd_page_itm)rhsObj;
if (lhs == null || rhs == null || tid == Tid_none) return CompareAble_.Same;
// else if (lhs == null) return CompareAble_.Less;
// else if (rhs == null) return CompareAble_.More;
else {
switch (tid) {
case Tid_len_dsc: return Int_.Compare(lhs.Text_len(), rhs.Text_len()) * -1;
case Tid_ttl_asc: return Bry_.Compare(lhs.Ttl_page_db(), rhs.Ttl_page_db());
case Tid_id: return Int_.Compare(lhs.Id(), rhs.Id());
default: throw Exc_.new_unhandled(tid);
}
}
}
public static final byte Tid_none = 0, Tid_len_dsc = 1, Tid_ttl_asc = 2, Tid_id = 3;
public static byte parse_(String v) {
if (String_.Eq(v, "none")) return Tid_none;
else if (String_.Eq(v, "len_desc")) return Tid_len_dsc;
else if (String_.Eq(v, "title_asc")) return Tid_ttl_asc;
else throw Exc_.new_unhandled(v);
}
public static String Xto_url_arg(byte v) {
switch (v) {
case Tid_none: return "";
case Tid_len_dsc: return "&xowa_sort=len_desc";
case Tid_ttl_asc: return "&xowa_sort=title_asc";
default: throw Exc_.new_unhandled(v);
}
}
}

View File

@@ -0,0 +1,153 @@
/*
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.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import gplx.core.primitives.*; import gplx.core.btries.*;
class Xosrh_scanner {
List_adp tkns = List_adp_.new_(); byte[] src; int src_len; int pos; int txt_bgn;
public Xosrh_qry_tkn[] Scan(byte[] src) {
this.src = src; this.src_len = src.length;
tkns.Clear(); pos = 0; txt_bgn = -1;
while (pos < src_len) {
byte cur_b = src[pos];
Object cur_obj = trie.Match_bgn_w_byte(cur_b, src, pos, src_len);
if (cur_obj == null) { // text character
if (txt_bgn == -1) txt_bgn = pos; // 1st character not set; set it
++pos;
}
else { // AND, OR, (, ), -, \s, "
int pos_end = trie.Match_pos();
byte cur_tid = ((Byte_obj_val)cur_obj).Val();
if (Cur_join_is_word(cur_tid, pos_end)) continue;
if (txt_bgn != -1) { // pending word; create
Tkns_add_word(Xosrh_qry_tkn.Tid_word, txt_bgn, pos);
txt_bgn = -1;
}
switch (cur_tid) {
case Xosrh_qry_tkn.Tid_space: // discard spaces
pos = Bry_finder.Find_fwd_while(src, pos, src_len, Byte_ascii.Space);
break;
case Xosrh_qry_tkn.Tid_quote: // find end quote and add as word
int quote_bgn = pos + 1;
int quote_end = Bry_finder.Find_fwd(src, Byte_ascii.Quote, quote_bgn, src_len);
if (quote_end == Bry_.NotFound) throw Exc_.new_("could not find end quote", "src", String_.new_u8(src));
Tkns_add_word(Xosrh_qry_tkn.Tid_word_quoted, quote_bgn, quote_end);
pos = quote_end + 1; // +1 to place after quote
break;
case Xosrh_qry_tkn.Tid_not:
Tkns_add_word(Xosrh_qry_tkn.Tid_not, pos, pos_end);
pos = pos_end;
break;
case Xosrh_qry_tkn.Tid_paren_bgn: case Xosrh_qry_tkn.Tid_paren_end:
case Xosrh_qry_tkn.Tid_and: case Xosrh_qry_tkn.Tid_or:
tkns.Add(new_tkn_(cur_tid, pos, pos_end));
pos = pos_end;
break;
default: throw Exc_.new_unhandled(cur_tid);
}
}
}
if (txt_bgn != -1) { // pending word; create
Tkns_add_word(Xosrh_qry_tkn.Tid_word, txt_bgn, pos);
txt_bgn = -1;
}
return (Xosrh_qry_tkn[])tkns.To_ary_and_clear(Xosrh_qry_tkn.class);
}
boolean Cur_join_is_word(byte cur_tid, int pos_end) { // extra logic to handle and / or occuring in unquoted strings; EX: random; for
switch (cur_tid) {
default: return false; // only look at AND, OR, -
case Xosrh_qry_tkn.Tid_and: case Xosrh_qry_tkn.Tid_or: case Xosrh_qry_tkn.Tid_not:
break;
}
boolean join_is_word = true;
if (txt_bgn == -1) { // no pending word;
if (cur_tid == Xosrh_qry_tkn.Tid_not) return false; // NOT is only operator if no pending tkn; EX: -abc -> NOT abc; a-b -> a-b
byte nxt_b = pos_end < src_len ? src[pos_end] : Byte_ascii.Nil;
Object nxt_obj = trie.Match_bgn_w_byte(nxt_b, src, pos_end, src_len);
if (nxt_obj == null) // next tkn is text; join must be word
join_is_word = true;
else { // next tkn is tkn
byte nxt_tid = ((Byte_obj_val)nxt_obj).Val();
switch (nxt_tid) {
case Xosrh_qry_tkn.Tid_space: case Xosrh_qry_tkn.Tid_quote:
case Xosrh_qry_tkn.Tid_paren_bgn: case Xosrh_qry_tkn.Tid_paren_end:
join_is_word = false; // next tkn is sym; and/or is not word; EX: a AND ; a AND"b"; a AND(b)
break;
case Xosrh_qry_tkn.Tid_not: case Xosrh_qry_tkn.Tid_and: case Xosrh_qry_tkn.Tid_or:
join_is_word = true; // next tkn is and or not; and/or is word; EX: andor; oror; or-abc;
break;
default: throw Exc_.new_unhandled(cur_tid);
}
}
}
else { // pending word; cur join must be word; EX: "grand": "and" invoked and "gr" pending
join_is_word = true;
}
if (join_is_word) {
if (txt_bgn == -1) txt_bgn = pos; // 1st character not set; set it
pos = pos_end;
return true;
}
if (txt_bgn != -1) {
Tkns_add_word(Xosrh_qry_tkn.Tid_word, txt_bgn, pos); // create word
txt_bgn = -1;
}
return false;
}
private void Tkns_add_word(byte tid, int src_bgn, int src_end) {
if (tkns.Count() > 0) { // at least 1 tkn
Xosrh_qry_tkn last_tkn = (Xosrh_qry_tkn)tkns.Get_at_last();
if (last_tkn.Tid() == Xosrh_qry_tkn.Tid_word) // previous tkn is not word; auto "AND" words; EX: A B -> A AND B
tkns.Add(Xosrh_qry_tkn.new_bry_(Xosrh_qry_tkn.Tid_and, Bry_and));
}
if (tid == Xosrh_qry_tkn.Tid_word) { // if word has symbol, convert to quoted; EX: a-b should become "a-b"; otherwise searcher would search for a single word a-b
byte[] cur_word = Bry_.Mid(src, src_bgn, src_end);
byte[][] words = gplx.xowa.bldrs.cmds.texts.Xob_search_base.Split_ttl_into_words(null, tmp_list, tmp_bfr, cur_word);
int words_len = words.length;
if (words_len == 1 && !Bry_.Eq(words[0], cur_word) && Bry_finder.Find_fwd(cur_word, Byte_ascii.Star) == -1) {
tkns.Add(Xosrh_qry_tkn.new_bry_(tid, words[0]));
return;
}
if (words.length > 1)
tid = Xosrh_qry_tkn.Tid_word_quoted;
}
tkns.Add(new_tkn_(tid, src_bgn, src_end));
}
Ordered_hash tmp_list = Ordered_hash_.new_(); Bry_bfr tmp_bfr = Bry_bfr.new_();
Xosrh_qry_tkn new_tkn_(byte tid, int val_bgn, int val_end) {return Xosrh_qry_tkn.new_pos_(tid, val_bgn, val_end);}
private static byte[] Bry_and = Bry_.new_a7("AND");
private static final Btrie_slim_mgr trie = Btrie_slim_mgr.ci_ascii_()// NOTE:ci.ascii:OR / AND only
.Add_str_byte(" ", Xosrh_qry_tkn.Tid_space)
.Add_str_byte("\"", Xosrh_qry_tkn.Tid_quote)
.Add_str_byte("-", Xosrh_qry_tkn.Tid_not)
.Add_str_byte("(", Xosrh_qry_tkn.Tid_paren_bgn)
.Add_str_byte(")", Xosrh_qry_tkn.Tid_paren_end)
.Add_str_byte("or", Xosrh_qry_tkn.Tid_or)
.Add_str_byte("and", Xosrh_qry_tkn.Tid_and);
public static final Xosrh_scanner _ = new Xosrh_scanner(); Xosrh_scanner() {}
}
class Xosrh_qry_tkn {
Xosrh_qry_tkn(byte tid, int val_bgn, int val_end, byte[] val_bry) {this.tid = tid; this.val_bgn = val_bgn; this.val_end = val_end; this.val_bry = val_bry;}
public byte Tid() {return tid;} private byte tid;
int val_bgn = -1;
int val_end = -1;
byte[] val_bry;
public byte[] Val(byte[] src) {return val_bry == null ? Bry_.Mid(src, val_bgn, val_end) : val_bry;}
public static Xosrh_qry_tkn new_pos_(byte tid, int val_bgn, int val_end) {return new Xosrh_qry_tkn(tid, val_bgn, val_end, null);}
public static Xosrh_qry_tkn new_bry_(byte tid, byte[] val_bry) {return new Xosrh_qry_tkn(tid, -1, -1, val_bry);}
public static final byte Tid_root = 1, Tid_word = 2, Tid_word_quoted = 3, Tid_space = 4, Tid_quote = 5, Tid_not = 6, Tid_paren_bgn = 7, Tid_paren_end = 8, Tid_or = 9, Tid_and = 10, Tid_eos = 11;
}

View File

@@ -0,0 +1,121 @@
/*
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.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import gplx.core.primitives.*; import gplx.xowa.wikis.*; import gplx.xowa.langs.*;
import gplx.xowa.wikis.domains.crts.*;
class Xow_domain_sorter__manual implements gplx.lists.ComparerAble {
private final Xow_domain cur_domain;
private final Xow_domain_crt_itm[] ary; private final int ary_len;
public Xow_domain_sorter__manual(Xow_domain cur_domain, Xow_domain_crt_itm[] ary) {
this.cur_domain = cur_domain; this.ary = ary; this.ary_len = ary.length;
}
public int compare(Object lhsObj, Object rhsObj) {
Xow_domain lhs = (Xow_domain)lhsObj;
Xow_domain rhs = (Xow_domain)rhsObj;
int lhs_sort = Get_sort_idx_or_neg1(lhs);
int rhs_sort = Get_sort_idx_or_neg1(rhs);
if (lhs_sort == -1 && rhs_sort != -1) return rhs_sort;
else if (lhs_sort != -1 && rhs_sort == -1) return lhs_sort;
else if (lhs_sort != -1 && rhs_sort != -1) return Int_.Compare(lhs_sort, rhs_sort);
else return Bry_.Compare(lhs.Domain_bry(), rhs.Domain_bry());
}
private int Get_sort_idx_or_neg1(Xow_domain domain) {
int sort_idx = domain.Sort_idx(); if (sort_idx != -1) return sort_idx;
sort_idx = Int_.MaxValue;
for (int i = 0; i < ary_len; ++i) {
Xow_domain_crt_itm crt = ary[i];
if (crt.Matches(cur_domain, domain)) {sort_idx = i; break;}
}
domain.Sort_idx_(sort_idx);
return sort_idx;
}
public static void Sort(Xow_domain_sorter__manual sorter, Xow_domain[] ary) {
int len = ary.length;
for (int i = 0; i < len; ++i)
ary[i].Sort_idx_(-1);
Array_.Sort(ary, sorter);
}
}
class Xow_domain_sorter__manual_tid implements gplx.lists.ComparerAble {
private final Hash_adp sort_hash = Hash_adp_.new_(); private final Int_obj_ref sort_key = Int_obj_ref.neg1_();
public Xow_domain_sorter__manual_tid(int[] id_ary) {
int len = id_ary.length;
for (int i = 0; i < len; ++i) {
int id_itm = id_ary[i];
sort_hash.Add_if_dupe_use_nth(Int_obj_ref.new_(id_itm), Int_obj_ref.new_(i));
}
}
public int compare(Object lhsObj, Object rhsObj) {
Xow_domain lhs = (Xow_domain)lhsObj;
Xow_domain rhs = (Xow_domain)rhsObj;
int lhs_sort = Get_sort_idx_or_neg1(lhs.Domain_tid());
int rhs_sort = Get_sort_idx_or_neg1(rhs.Domain_tid());
if (lhs_sort == -1 && rhs_sort != -1) return rhs_sort;
else if (lhs_sort != -1 && rhs_sort == -1) return lhs_sort;
else if (lhs_sort != -1 && rhs_sort != -1) return Int_.Compare(lhs_sort, rhs_sort);
else return Bry_.Compare(Xow_domain_type_.Get_type_as_bry(lhs.Domain_tid()), Xow_domain_type_.Get_type_as_bry(rhs.Domain_tid()));
}
private int Get_sort_idx_or_neg1(int tid) {
Object o = sort_hash.Get_by(sort_key.Val_(tid));
return o == null ? -1 : ((Int_obj_ref)o).Val();
}
public static Xow_domain_sorter__manual_tid new_(byte[]... id_brys) {
int len = id_brys.length;
int[] id_ints = new int[len];
for (int i = 0; i < len; ++i) {
byte[] id_bry = id_brys[i];
int id_int = Xow_domain_type_.Get_type_as_tid(id_bry);
id_ints[i] = id_int;
}
return new Xow_domain_sorter__manual_tid(id_ints);
}
}
class Xow_domain_sorter__manual_lang implements gplx.lists.ComparerAble {
private final Hash_adp sort_hash = Hash_adp_.new_(); private final Int_obj_ref sort_key = Int_obj_ref.neg1_();
public Xow_domain_sorter__manual_lang(int[] id_ary) {
int len = id_ary.length;
for (int i = 0; i < len; ++i) {
int id_int = id_ary[i];
sort_hash.Add_if_dupe_use_nth(Int_obj_ref.new_(id_int), Int_obj_ref.new_(i));
}
}
public int compare(Object lhsObj, Object rhsObj) {
Xow_domain lhs = (Xow_domain)lhsObj;
Xow_domain rhs = (Xow_domain)rhsObj;
int lhs_sort = Get_sort_idx_or_neg1(lhs.Lang_uid());
int rhs_sort = Get_sort_idx_or_neg1(rhs.Lang_uid());
if (lhs_sort == -1 && rhs_sort != -1) return rhs_sort;
else if (lhs_sort != -1 && rhs_sort == -1) return lhs_sort;
else if (lhs_sort != -1 && rhs_sort != -1) return Int_.Compare(lhs_sort, rhs_sort);
else return Bry_.Compare(lhs.Lang_key(), rhs.Lang_key());
}
private int Get_sort_idx_or_neg1(int tid) {
Object o = sort_hash.Get_by(sort_key.Val_(tid));
return o == null ? -1 : ((Int_obj_ref)o).Val();
}
public static Xow_domain_sorter__manual_lang new_(byte[]... id_brys) {
int len = id_brys.length;
int[] id_ints = new int[len];
for (int i = 0; i < len; ++i) {
byte[] id_bry = id_brys[i];
int id_int = Xol_lang_itm_.Get_by_key_or_intl(id_bry).Id();
id_ints[i] = id_int;
}
return new Xow_domain_sorter__manual_lang(id_ints);
}
}

View File

@@ -0,0 +1,74 @@
/*
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.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import gplx.core.primitives.*;
class Xows_arg_mgr {
private final Xows_paging_parser paging_parser = new Xows_paging_parser();
public Xows_ns_mgr Ns_mgr() {return ns_mgr;} private final Xows_ns_mgr ns_mgr = new Xows_ns_mgr();
public byte[] Search_bry() {return search_bry;} private byte[] search_bry;
public int Paging_idx() {return paging_idx;} private int paging_idx;
public byte Sort_tid() {return sort_tid;} private byte sort_tid;
public byte[] Cancel() {return cancel;} private byte[] cancel;
public Xows_paging_itm[] Paging_itms() {return paging_itms;} private Xows_paging_itm[] paging_itms;
public Xows_arg_mgr Search_bry_(byte[] v) {search_bry = v; return this;}
public Xows_arg_mgr Clear() {
ns_mgr.Clear();
this.search_bry = null;
this.paging_idx = 0;
this.sort_tid = Xosrh_rslt_itm_sorter.Tid_none;
this.cancel = null;
return this;
}
public void Parse(Gfo_url_arg[] arg_ary) {
if (arg_ary == null) return;
int len = arg_ary.length;
for (int i = 0; i < len; ++i) {
Gfo_url_arg arg = arg_ary[i];
byte[] key = arg.Key_bry();
Object tid = url_args.Get_by(key);
if (tid != null) {
switch (((Byte_obj_val)tid).Val()) {
case Arg_search: this.search_bry = Bry_.Replace(arg.Val_bry(), Byte_ascii.Plus, Byte_ascii.Space); break;
case Arg_page_idx: this.paging_idx = Bry_.Xto_int_or(arg.Val_bry(), 0); break;
case Arg_sort: this.sort_tid = Xosrh_rslt_itm_sorter.parse_(String_.new_a7(arg.Val_bry())); break;
case Arg_cancel: this.cancel = arg.Val_bry(); break;
case Arg_paging: this.paging_itms = paging_parser.Parse(arg.Val_bry()); break;
default: break;
}
}
else {
if (Bry_.Has_at_bgn(key, Ns_bry)) // check for ns*; EX: &ns0=1&ns8=1; NOTE: lowercase only
ns_mgr.Add_by_parse(key, arg.Val_bry());
}
}
ns_mgr.Add_main_if_empty();
}
private static final byte Arg_search = 0, Arg_page_idx = 1, Arg_sort = 2, Arg_cancel = 3, Arg_paging = 4;
private static byte[] Ns_bry = Bry_.new_a7("ns");
public static final byte[]
Arg_bry_page_index = Bry_.new_a7("xowa_page_index")
, Arg_bry_cancel = Bry_.new_a7("cancel")
;
private static final Hash_adp_bry url_args = Hash_adp_bry.ci_ascii_()
.Add_str_byte("xowa_paging", Arg_paging)
.Add_bry_byte(Arg_bry_page_index, Arg_page_idx)
.Add_str_byte("xowa_sort", Arg_sort)
.Add_str_byte("search", Arg_search)
.Add_bry_byte(Arg_bry_cancel, Arg_cancel)
;
}

View File

@@ -0,0 +1,86 @@
/*
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.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import gplx.dbs.*; import gplx.xowa.wikis.*; import gplx.xowa.wikis.data.*;
class Xows_core {
private final Xoae_wiki_mgr wiki_mgr;
private final Hash_adp_bry cache_hash = Hash_adp_bry.cs_(); private final Hash_adp_bry cmd_hash = Hash_adp_bry.cs_();
private boolean ask_for_upgrade = true; private final Hash_adp_bry upgraded_wikis = Hash_adp_bry.cs_();
public Xows_core(Xoae_wiki_mgr wiki_mgr) {this.wiki_mgr = wiki_mgr;}
private final Xows_html_wkr html_wkr = new Xows_html_wkr();
public Xows_db_cache Get_cache_or_new(byte[] key) {
Xows_db_cache cache = (Xows_db_cache)cache_hash.Get_by_bry(key);
if (cache == null) {
cache = new Xows_db_cache();
cache_hash.Add_bry_obj(key, cache);
}
return cache;
}
public void Search(Xow_wiki search_wiki, Xoae_page page, Xows_ui_qry qry) {
// generate 1 cmd per wiki
Xow_domain[] domain_ary = qry.Wiki_domains(); int domain_ary_len = domain_ary.length;
for (int i = 0; i < domain_ary_len; ++i) {
Xow_domain domain = domain_ary[i];
try {
Xowe_wiki wiki = wiki_mgr.Get_by_key_or_make(domain.Domain_bry()); wiki.Init_assert();
Assert_page_count(wiki);
Xows_ui_cmd cmd = new Xows_ui_cmd(this, qry, wiki, page, page.Tab_data().Close_mgr(), page.Tab_data().Tab().Html_itm());
qry.Cmds__add(cmd);
} catch (Exception e) {Xoa_app_.Usr_dlg().Warn_many("", "", "search:wiki failed; wiki=~{0} err=~{1}", domain.Domain_str(), Err_.Message_lang(e));} // handle bad wikis, like "en.wikipedia.org-old"; DATE:2015-04-24
}
qry.Page_max_(Int_.MaxValue);
// do search and generate html
html_wkr.Init_by_wiki(search_wiki, search_wiki.Lang().Num_mgr(), qry);
int cmds_len = qry.Cmds__len();
Bry_bfr tmp_bfr = Bry_bfr.new_();
for (int i = 0; i < cmds_len; ++i) {
Xows_ui_cmd cmd = qry.Cmds__get_at(i); byte[] cmd_key = cmd.Key();
cmd_hash.Add_if_dupe_use_nth(cmd_key, cmd);
boolean searching_db = cmd.Search();
html_wkr.Gen_tbl(tmp_bfr, cmd.Rslt(), cmd_key, cmd.Wiki().Domain_bry(), searching_db);
}
page.Data_raw_(html_wkr.Gen_page(tmp_bfr.Xto_bry_and_clear()));
}
public void Search_end(Xows_ui_cmd cmd) {
cmd_hash.Del(cmd.Key());
}
public void Cancel(byte[] cmd_key) {
Xows_ui_cmd cmd = (Xows_ui_cmd)cmd_hash.Get_by_bry(cmd_key);
if (cmd == null) return;
cmd.Cancel();
cmd_hash.Del(cmd.Key());
}
private void Assert_page_count(Xowe_wiki wiki) {
Xowd_db_file search_db = wiki.Data__core_mgr().Db__search();
if (ask_for_upgrade
&& wiki.App().App_type().Uid_is_gui()
&& !search_db.Tbl__search_word().Ddl__page_count()
&& !upgraded_wikis.Has(wiki.Domain_bry()) ) {
ask_for_upgrade = false;
upgraded_wikis.Add_as_key_and_val(wiki.Domain_bry());
boolean ok = wiki.Appe().Gui_mgr().Kit().Ask_ok_cancel("", "", String_.Concat_lines_nl_skip_last
( "XOWA would like to upgrade your search database for " + wiki.Domain_str() + "."
, "* Press OK to upgrade. This may take a few minutes."
, "* Press Cancel to skip. You will be able to search, but the results may be slower for multi-word searches (EX: 'The Earth')."
, "If you cancel, XOWA will ask you to upgrade this wiki again next time you restart the application."
));
if (ok)
search_db.Tbl__search_word().Ddl__page_count__add(search_db.Tbl__search_link(), search_db.Tbl__cfg());
}
}
}

View File

@@ -0,0 +1,42 @@
/*
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.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import gplx.xowa.specials.search.parsers_old.*;
class Xows_db_cache { // one cache per search term; EX: "Earth* AND (History OR Future) AND -"middle earth"" is one cache
private final Ordered_hash hash = Ordered_hash_.new_bry_();
public Xows_db_word[] Words() {return words;} private Xows_db_word[] words; // words in cache; EX: earth, history, future but not "middle earth" (since not'ed)
public Xows_db_matcher Matcher() {return matcher;} private Xows_db_matcher matcher; // criteria
public boolean Done() {return done;} public void Done_y_() {done = true;} private boolean done; // marks if db search is done
public int Count() {return hash.Count();}
public int Itms_end() {return itms_end;} public void Itms_end_(int v) {itms_end = v;} private int itms_end;
public void Init_by_db(Cancelable cxl, byte[] raw, gplx.xowa.wikis.data.tbls.Xowd_search_word_tbl word_tbl) {
this.matcher = new Xow_search_parser().Parse(raw);
this.words = new Xows_db_matcher_bldr().Gather_words_for_db(cxl, matcher, word_tbl);
}
public boolean Has(byte[] key) {return hash.Has(key);}
public Xows_db_row Get_at(int i) {return (Xows_db_row)hash.Get_at(i);}
public void Add(Xows_db_row row) {hash.Add(row.Page_ttl().Full_db(), row);}
public void Get_between(Xows_ui_rslt search_ui, int bgn, int end) {
if (bgn >= hash.Count()) return; // requested start not in cache; exit
for (int i = bgn; i < end; ++i) {
if (i >= hash.Count()) break;
search_ui.Add((Xows_db_row)hash.Get_at(i));
}
}
public void Sort() {hash.Sort_by(Xows_db_row_sorter.Page_len_dsc);}
}

View File

@@ -0,0 +1,68 @@
/*
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.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import gplx.core.regxs.*;
public class Xows_db_matcher {
private final Gfo_pattern raw_pattern;
public Xows_db_matcher(int tid, byte[] raw, Xows_db_matcher lhs, Xows_db_matcher rhs) {
this.tid = tid; this.raw = raw; this.lhs = lhs; this.rhs = rhs;
this.raw_pattern = Bry_.Has(raw, Byte_ascii.Star) ? new Gfo_pattern(raw) : null;
}
public int Tid() {return tid;} private final int tid;
public int Page_count() {return page_count;} public void Page_count_(int v) {page_count = v;} private int page_count;
public byte[] Raw() {return raw;} private final byte[] raw;
public Xows_db_matcher Lhs() {return lhs;} private final Xows_db_matcher lhs;
public Xows_db_matcher Rhs() {return rhs;} private final Xows_db_matcher rhs;
public boolean Matches(byte[] page_ttl_lc, byte[][] page_ttl_words) {
switch (tid) {
case Xows_db_matcher.Tid_word: {
int len = page_ttl_words.length;
for (int i = 0; i < len; ++i) {
byte[] word = page_ttl_words[i];
if (raw_pattern == null) {
if (Bry_.Eq(word, raw)) return true;
}
else {
if (raw_pattern.Match(word)) return true;
}
}
return false;
}
case Xows_db_matcher.Tid_word_quote: // note that raw does not have quotes; EX: "B*" -> B*
return Bry_finder.Find_fwd(page_ttl_lc, raw) != Bry_finder.Not_found;
case Xows_db_matcher.Tid_not:
return !rhs.Matches(page_ttl_lc, page_ttl_words);
case Xows_db_matcher.Tid_or:
return lhs.Matches(page_ttl_lc, page_ttl_words) || rhs.Matches(page_ttl_lc, page_ttl_words);
case Xows_db_matcher.Tid_and:
return lhs.Matches(page_ttl_lc, page_ttl_words) && rhs.Matches(page_ttl_lc, page_ttl_words);
case Xows_db_matcher.Tid_null: return false;
default: throw Exc_.new_unhandled(tid);
}
}
public static final Xows_db_matcher Null = new Xows_db_matcher(Xows_db_matcher.Tid_null, null, null, null);
public static Xows_db_matcher new_join(byte tid, Xows_db_matcher lhs, Xows_db_matcher rhs) {return new Xows_db_matcher(tid, null, lhs, rhs);}
public static final int
Tid_word = 0
, Tid_and = 1
, Tid_or = 2
, Tid_not = 3
, Tid_word_quote = 4
, Tid_null = 5
;
}

View File

@@ -0,0 +1,95 @@
/*
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.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import gplx.xowa.wikis.data.tbls.*;
class Xows_db_matcher_bldr {
public Xows_db_word[] Gather_words_for_db(Cancelable cxl, Xows_db_matcher matcher, Xowd_search_word_tbl word_tbl) {
List_adp rv = List_adp_.new_();
Gather_words_for_db(cxl, matcher, rv, word_tbl);
rv.Sort_by(Xows_db_word_sorter.Page_count_dsc);
return (Xows_db_word[])rv.To_ary(Xows_db_word.class);
}
private void Gather_words_for_db(Cancelable cxl, Xows_db_matcher matcher, List_adp rv, Xowd_search_word_tbl word_tbl) {
switch (matcher.Tid()) {
case Xows_db_matcher.Tid_word:
byte[] word_text = matcher.Raw();
if (Bry_.Has(word_text, Byte_ascii.Star))
Load_word_many(cxl, rv, word_text, word_tbl);
else
Load_word_one(rv, word_text, word_tbl);
break;
case Xows_db_matcher.Tid_word_quote:
List_adp tmp = List_adp_.new_();
byte[][] words = Bry_.Split(matcher.Raw(), Byte_ascii.Space, Bool_.Y);
int words_len = words.length;
for (int i = 0; i < words_len; ++i) {
byte[] word = words[i];
Load_word_one(tmp, word, word_tbl);
}
if (tmp.Count() == 0) return; // no words in db; EX: "xyz cba"
tmp.Sort_by(Xows_db_word_sorter.Page_count_dsc);
rv.Add(tmp.Get_at(0)); // add lowest page_count word to db; EX: search for "earth and" should search for "earth" only, but match for "earth and"
break;
case Xows_db_matcher.Tid_and:
List_adp lhs_tmp = List_adp_.new_(), rhs_tmp = List_adp_.new_();
Gather_words_for_db(cxl, matcher.Lhs(), lhs_tmp, word_tbl);
Gather_words_for_db(cxl, matcher.Rhs(), rhs_tmp, word_tbl);
List_adp_.Add_list(rv, Calc_lowest(lhs_tmp, rhs_tmp)); // calc side with lowest count; add to rv;
break;
case Xows_db_matcher.Tid_or:
Gather_words_for_db(cxl, matcher.Lhs(), rv, word_tbl);
Gather_words_for_db(cxl, matcher.Rhs(), rv, word_tbl);
break;
case Xows_db_matcher.Tid_not: break; // never add "NOT" to db_search
case Xows_db_matcher.Tid_null: break; // should not happen
default: throw Exc_.new_unhandled(matcher.Tid());
}
}
private List_adp Calc_lowest(List_adp lhs, List_adp rhs) {
int lhs_count = Calc(lhs);
int rhs_count = Calc(rhs);
// never return 0 as lowest count; note that NOT will return 0;
if (lhs_count == 0) return rhs;
else if (rhs_count == 0) return lhs;
else return lhs_count < rhs_count ? lhs : rhs;
}
private int Calc(List_adp list) {
int rv = 0;
int len = list.Count();
for (int i = 0; i < len; ++i) {
Xows_db_word word = (Xows_db_word)list.Get_at(i);
rv += word.Page_count();
}
return rv;
}
private void Load_word_one(List_adp rv, byte[] word_text, Xowd_search_word_tbl word_tbl) {
Xoa_app_.Usr_dlg().Prog_many("", "", "search:word by text; word=~{0}", word_text);
Xowd_search_word_row row = word_tbl.Select_by_or_null(word_text); if (row == Xowd_search_word_row.Null) return;
Xows_db_word word = new Xows_db_word(row.Id(), row.Text(), row.Page_count());
rv.Add(word);
}
private void Load_word_many(Cancelable cxl, List_adp rv, byte[] word_text, Xowd_search_word_tbl word_tbl) {
Xoa_app_.Usr_dlg().Prog_many("", "", "search:word by wildcard; word=~{0}", word_text);
Xowd_search_word_row[] rows = word_tbl.Select_in(cxl, word_text);
int len = rows.length;
for (int i = 0; i < len; ++i) {
Xowd_search_word_row row = rows[i];
rv.Add(new Xows_db_word(row.Id(), row.Text(), row.Page_count()));
}
}
}

View File

@@ -0,0 +1,41 @@
/*
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.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
public class Xows_db_row {
public Xows_db_row(byte[] wiki_domain, Xoa_ttl page_ttl, int page_id, int page_len) {
this.wiki_domain = wiki_domain;
this.page_ttl = page_ttl;
this.page_id = page_id;
this.page_len = page_len;
this.key = Bry_.Add(wiki_domain, Byte_ascii.Pipe_bry, page_ttl.Full_db());
}
public byte[] Key() {return key;} private final byte[] key;
public byte[] Wiki_domain() {return wiki_domain;} private final byte[] wiki_domain;
public Xoa_ttl Page_ttl() {return page_ttl;} private final Xoa_ttl page_ttl;
public int Page_id() {return page_id;} private final int page_id;
public int Page_len() {return page_len;} private final int page_len;
public static Xows_db_row[] Ary(Xows_db_row... v) {return v;}
}
class Xows_db_row_sorter implements gplx.lists.ComparerAble {
public int compare(Object lhsObj, Object rhsObj) {
Xows_db_row lhs = (Xows_db_row)lhsObj;
Xows_db_row rhs = (Xows_db_row)rhsObj;
return -Int_.Compare(lhs.Page_len(), rhs.Page_len());
}
public static final Xows_db_row_sorter Page_len_dsc = new Xows_db_row_sorter(); Xows_db_row_sorter() {}
}

View File

@@ -0,0 +1,109 @@
/*
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.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import gplx.core.primitives.*; import gplx.dbs.*;
import gplx.xowa.wikis.data.*; import gplx.xowa.wikis.data.tbls.*; import gplx.xowa.langs.cases.*;
import gplx.gfui.*;
class Xows_db_wkr {
public void Search(Xows_ui_cmd cmd, Xows_ui_qry qry, Xows_ui_rslt rslt, Xows_db_cache cache, Xow_wiki wiki) {
// assert matcher
Xowd_db_file search_db = wiki.Data__core_mgr().Db__search();
Xoa_app_.Usr_dlg().Prog_many("", "", "search started (please wait)");
Xows_db_matcher matcher = cache.Matcher();
if (matcher == null) {
cache.Init_by_db
( cmd
, wiki.Lang().Case_mgr().Case_build_lower(qry.Search_raw()) // lower-case search
, search_db.Tbl__search_word()
);
matcher = cache.Matcher();
}
// init
int rslts_wanted = qry.Itms_end() - qry.Itms_bgn();
Xowd_db_file core_db = wiki.Data__core_mgr().Db__core();
Xowd_page_tbl page_tbl = core_db.Tbl__page();
Xowd_search_link_tbl link_tbl = search_db.Tbl__search_link();
Xows_db_word[] word_ary = cache.Words(); int word_ary_len = word_ary.length;
// read pages for each word from db
Db_attach_rdr attach_rdr = new Db_attach_rdr(search_db.Conn(), "page_db", core_db.Url());
attach_rdr.Attach();
int total_found = 0;
try {
while (true) {
boolean found_none = true;
for (int i = 0; i < word_ary_len; ++i) { // loop each word to get rslts_wanted
if (cmd.Canceled()) return;
Xows_db_word word = word_ary[i];
if (word.Rslts_done()) continue; // last db_search for word returned 0 results; don't search again;
int offset = word.Rslts_offset();
Xoa_app_.Usr_dlg().Prog_many("", "", "searching; wiki=~{0} total=~{1} offset=~{2} index=~{3} word=~{4}", wiki.Domain_str(), word_ary_len, offset, i, word.Text());
String sql = String_.Format(Search_sql, link_tbl.Tbl_name(), link_tbl.Fld_page_id(), link_tbl.Fld_word_id(), word.Id(), "page_len", "DESC", Int_.MaxValue, offset); // need to return enough results to fill qry.Page_len() as many results may be discarded below; DATE:2015-04-24
int rslts_found = Search_pages(cmd, qry, rslt, cache, wiki, page_tbl, attach_rdr, sql, word, matcher, rslts_wanted);
total_found += rslts_found;
if (rslts_found == -1) return; // canceled
else if (rslts_found > 0) found_none = false; // NOTE: do not reverse and do rslts_found == 0; want to check if any word returns results;
}
if (found_none) {cache.Done_y_(); break;}
if (total_found >= rslts_wanted) break;
}
cache.Itms_end_(qry.Itms_end());
cache.Sort();
} finally {attach_rdr.Detach();}
}
private int Search_pages(Xows_ui_cmd cmd, Xows_ui_qry qry, Xows_ui_rslt rslt, Xows_db_cache cache, Xow_wiki wiki, Xowd_page_tbl page_tbl, Db_attach_rdr attach_rdr, String sql, Xows_db_word word, Xows_db_matcher matcher, int rslts_wanted) {
int rslts_found = 0;
Xow_ns_mgr ns_mgr = wiki.Ns_mgr(); Xol_case_mgr case_mgr = wiki.Lang().Case_mgr();
Db_rdr rdr = attach_rdr.Exec_as_rdr(sql);
try {
while (rdr.Move_next()) {
if (cmd.Canceled()) return -1;
word.Rslts_offset_add_1();
int page_ns = rdr.Read_int(page_tbl.Fld_page_ns());
if (!qry.Ns_mgr().Has(page_ns)) continue; // ignore: ns doesn't match
byte[] page_ttl = rdr.Read_bry_by_str(page_tbl.Fld_page_title());
// Io_mgr.I.AppendFilStr("C:\\temp.txt", String_.new_u8(word.Text()) + "|" + Int_.Xto_str(page_ns) + "|" + String_.new_u8(page_ttl) + "\n");
byte[] page_ttl_lc = case_mgr.Case_build_lower(Xoa_ttl.Replace_unders(page_ttl));
byte[][] page_ttl_words = Bry_.Split(page_ttl_lc, Byte_ascii.Space, Bool_.Y);
if (!matcher.Matches(page_ttl_lc, page_ttl_words)) continue; // ignore: ttl doesn't match matcher
int page_id = rdr.Read_int(page_tbl.Fld_page_id());
int page_len = rdr.Read_int(page_tbl.Fld_page_len());
Xow_ns ns = ns_mgr.Ids_get_or_null(page_ns);
byte[] page_ttl_w_ns = ns.Gen_ttl(page_ttl);
if (cache.Has(page_ttl_w_ns)) continue; // ignore: page already added by another word; EX: "A B"; word is "B", but "A B" already added by "A"
Xoa_ttl ttl = wiki.Ttl_parse(page_ttl_w_ns);
Xows_db_row row = new Xows_db_row(wiki.Domain_bry(), ttl, page_id, page_len);
cmd.Add_rslt(row);
if (++rslts_found == rslts_wanted) break; // stop: found enough results; DATE:2015-04-24
}
} finally {rdr.Rls();}
if (rslts_found == 0) word.Rslts_done_y_(); // read through entire rdr and nothing found; mark word done
return rslts_found;
}
private static final String Search_sql = String_.Concat_lines_nl_skip_last
( "SELECT cp.page_id"
, ", cp.page_namespace"
, ", cp.page_title"
, ", cp.page_len"
, "FROM {0} sp"
, " JOIN <attach_db>page cp ON cp.page_id = sp.{1} "
, "WHERE sp.{2} = {3}"
, "ORDER BY {4} {5}"
, "LIMIT {6}"
, "OFFSET {7};"
);
}

View File

@@ -0,0 +1,36 @@
/*
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.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
public class Xows_db_word {
public Xows_db_word(int id, byte[] text, int page_count) {this.id = id; this.text = text; this.page_count = page_count;}
public int Id() {return id;} private final int id;
public byte[] Text() {return text;} private final byte[] text;
public int Page_count() {return page_count;} private final int page_count;
public int Rslts_offset() {return rslts_offset;} private int rslts_offset;
public boolean Rslts_done() {return rslts_done;} private boolean rslts_done;
public void Rslts_offset_add_1() {++rslts_offset;}
public void Rslts_done_y_() {rslts_done = true;}
}
class Xows_db_word_sorter implements gplx.lists.ComparerAble {
public int compare(Object lhsObj, Object rhsObj) {
Xows_db_word lhs = (Xows_db_word)lhsObj;
Xows_db_word rhs = (Xows_db_word)rhsObj;
return -Int_.Compare(lhs.Page_count(), rhs.Page_count());
}
public static final Xows_db_word_sorter Page_count_dsc = new Xows_db_word_sorter(); Xows_db_word_sorter() {}
}

View File

@@ -0,0 +1,123 @@
/*
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.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import gplx.html.*; import gplx.xowa.html.wtrs.*; import gplx.xowa.langs.numbers.*;
class Xows_html_wkr {
private final Bry_bfr tmp_bfr = Bry_bfr.new_(255);
private Xows_ui_qry qry; private Xow_wiki wiki; private Xol_num_mgr num_mgr;
private Xoh_lnki_bldr lnki_bldr; private Xoh_anchor_kv_bldr self_lnkr = new Xoh_anchor_kv_bldr(); private Xows_html_row html_rows;
public void Init_by_wiki(Xow_wiki wiki, Xol_num_mgr num_mgr, Xows_ui_qry qry) {
this.wiki = wiki; this.num_mgr = num_mgr; this.qry = qry;
this.lnki_bldr = wiki.App().Html__lnki_bldr();
this.html_rows = new Xows_html_row(lnki_bldr);
self_lnkr.Init_w_qarg(qry.Special_link_base_href());
}
public byte[] Gen_page(byte[] tbls) {
byte[] rslts_hdr = fmtr_rslts.Bld_bry_many(tmp_bfr, num_mgr.Format_num(qry.Itms_bgn() + List_adp_.Base1), num_mgr.Format_num(qry.Itms_end()), qry.Search_raw());
byte[] option_link = lnki_bldr.Href_(Bry_.new_a7("home"), wiki.Ttl_parse(Bry_.new_a7("Help:Options/Search"))).Img_16x16(Xoh_img_path.Img_option).Bld_to_bry();
fmtr_page.Bld_bfr_many(tmp_bfr, rslts_hdr, option_link, Paging_link(Bool_.N), Paging_link(Bool_.Y), tbls);
return tmp_bfr.Xto_bry_and_clear();
}
public void Gen_tbl(Bry_bfr bfr, Xows_ui_rslt rslt, byte[] cmd_key, byte[] wiki_domain, boolean searching_db) {
html_rows.Init(rslt);
byte[] search_link = lnki_bldr.Href_(wiki_domain, wiki.Ttl_parse(self_lnkr.Bld_to_bry())).Caption_(wiki_domain).Img_16x16(Xoh_img_path.Img_search).Img_pos_is_left_(Bool_.Y).Bld_to_bry();
fmtr_tbl.Bld_bfr_many(bfr, search_link, searching_db ? Cancel_link(wiki_domain, cmd_key) : Bry_.Empty, Bry_hdr_len, Bry_hdr_ttl, Xows_ui_async.Gen_insert_key(wiki_domain), html_rows);
}
private byte[] Cancel_link(byte[] domain, byte[] cmd_key) {
lnki_bldr.Id_(Bry_.Add(Bry_.new_a7("xowa_cancel_"), domain));
lnki_bldr.Href_(wiki, self_lnkr.Add_int(Xows_arg_mgr.Arg_bry_page_index, qry.Page_idx()).Add_bry(Xows_arg_mgr.Arg_bry_cancel, cmd_key).Bld_to_bry());
lnki_bldr.Title_(Bry_cancel);
lnki_bldr.Img_16x16(Xoh_img_path.Img_cancel);
return lnki_bldr.Bld_to_bry();
}
public byte[] Paging_link(boolean fwd) {
int paging_idx = qry.Page_idx();
byte[] title = null, img_path = Bry_.Empty;
boolean img_pos_is_left = true;
if (fwd) {
++paging_idx;
// if (paging_idx > qry.Page_max()) return Html_entity_.Nbsp_num_bry;
img_pos_is_left = false;
img_path = Xoh_img_path.Img_go_fwd;
title = Bry_paging_fwd;
}
else {
--paging_idx;
if (paging_idx < 0) return Html_entity_.Nbsp_num_bry;
img_path = Xoh_img_path.Img_go_bwd;
title = Bry_paging_bwd;
}
return lnki_bldr.Title_(title).Href_(wiki, self_lnkr.Add_int(Xows_arg_mgr.Arg_bry_page_index, paging_idx).Bld_to_bry()).Img_16x16(img_path).Img_pos_is_left_(img_pos_is_left).Caption_(title).Bld_to_bry();
}
private static final Bry_fmtr fmtr_page = Bry_fmtr.new_(String_.Concat_lines_nl_skip_last
( "~{rslts_hdr}<span style='margin-left:10px'>~{option_link}</span>"
, "<div id='xowa_panel_top' style='width:60%;'><div style='float:right;'><span>~{bwd_a}</span><span style='margin-left:10px'>~{fwd_a}</span></div></div>~{tbls}"
, "<div id='xowa_panel_bot' style='width:60%;'><div style='float:right;'><span>~{bwd_a}</span><span style='margin-left:10px'>~{fwd_a}</span></div></div>"
), "rslts_hdr", "option_link", "bwd_a", "fwd_a", "tbls");
private static final Bry_fmtr fmtr_tbl = Bry_fmtr.new_(String_.Concat_lines_nl_skip_last
( "<table class='wikitable sortable' style='width:60%;'>"
, " <tr>"
, " <th colspan='2' style='text-align:left'>~{wiki}<span style='float:right'>~{cancel}</span>"
, " </th>"
, " </tr>"
, " <tr>"
, " <th width='100'>~{hdr_len}"
, " </th>"
, " <th>~{hdr_ttl}"
, " </th>"
, " </tr>~{rows}"
, " <tr id='~{insert_key}' style='display:none;'>"
, " </tr>"
, "</table>"
), "wiki", "cancel", "hdr_len", "hdr_ttl", "insert_key", "rows");
private static final Bry_fmtr fmtr_rslts = Bry_fmtr.new_("Results <b>~{bgn}</b> of <b>~{end}</b> for <b>~{raw}</b>", "bgn", "end", "raw");
private static final byte[] Bry_paging_fwd = Bry_.new_a7("Next"), Bry_paging_bwd = Bry_.new_a7("Previous"), Bry_cancel = Bry_.new_a7("Stop searching")
, Bry_hdr_len = Bry_.new_a7("Page length"), Bry_hdr_ttl = Bry_.new_a7("Page title")
;
}
class Xows_html_row implements Bry_fmtr_arg {
private final Xoh_lnki_bldr lnki_bldr; private Xows_ui_rslt rslt;
private final Object thread_lock = new Object();
public Xows_html_row(Xoh_lnki_bldr lnki_bldr) {this.lnki_bldr = lnki_bldr;}
public Xows_html_row Init(Xows_ui_rslt rslt) {this.rslt = rslt; return this;}
public void XferAry(Bry_bfr bfr, int idx) { // <a href="/wiki/A" title="A" class="xowa-visited">A</a>
int len = rslt.Len();
for (int i = 0; i < len; ++i) {
Xows_db_row row = rslt.Get_at(i);
Gen_html(bfr, row);
}
}
public void Gen_html(Bry_bfr bfr, Xows_db_row row) {
synchronized (thread_lock) {
lnki_bldr.Href_(row.Wiki_domain(), row.Page_ttl());
byte[] title = row.Page_ttl().Full_txt();
lnki_bldr.Title_(title);
lnki_bldr.Caption_(title);
fmtr.Bld_bfr_many(bfr, Html_utl.Encode_id_as_str(row.Key()), row.Page_len(), lnki_bldr.Bld_to_bry());
}
}
public Bry_fmtr Fmtr() {return fmtr;} private final Bry_fmtr fmtr = Bry_fmtr.new_(String_.Concat_lines_nl_skip_last
( ""
, " <tr id='~{page_key}'>"
, " <td style='padding-right:5px; vertical-align:top; text-align:right;'>~{page_len}"
, " </td>"
, " <td style='padding-left:5px; vertical-align:top;'>~{lnki}" // SERVER:"<a href='"; DATE:2015-04-16
, " </td>"
, " </tr>"
), "page_key", "page_len", "lnki");
}

View File

@@ -0,0 +1,76 @@
/*
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.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import org.junit.*; import gplx.xowa.html.wtrs.*; import gplx.xowa.tdbs.*; import gplx.xowa.wikis.*; import gplx.xowa.wikis.data.tbls.*;
public class Xows_html_wkr_tst {
@Before public void init() {fxt.Clear();} private Xows_html_wkr_fxt fxt = new Xows_html_wkr_fxt();
@Test public void Paging() {
fxt.Test_paging(Bool_.Y, 1, "<a href='/site/en.wikipedia.org/wiki/Special:Search/A%3Ffulltext%3Dy%26xowa_page_index%3D2' title='Next'>Next<img src='file:///mem/xowa/user/anonymous/app/img/window/paging/go_fwd.png' width='16' height='16'/></a>");
fxt.Test_paging(Bool_.N, 1, "<a href='/site/en.wikipedia.org/wiki/Special:Search/A%3Ffulltext%3Dy%26xowa_page_index%3D0' title='Previous'><img src='file:///mem/xowa/user/anonymous/app/img/window/paging/go_bwd.png' width='16' height='16'/>Previous</a>");
fxt.Test_paging(Bool_.Y, 2, "<a href='/site/en.wikipedia.org/wiki/Special:Search/A%3Ffulltext%3Dy%26xowa_page_index%3D3' title='Next'>Next<img src='file:///mem/xowa/user/anonymous/app/img/window/paging/go_fwd.png' width='16' height='16'/></a>");
fxt.Test_paging(Bool_.N, 0, "&#160;");
}
@Test public void Rows() {
fxt.Test_rows(Xows_db_row.Ary(fxt.Make_row(10, "A"), fxt.Make_row(20, "B")), String_.Concat_lines_nl_skip_last
( ""
, " <tr id='w.7CA'>"
, " <td style='padding-right:5px; vertical-align:top; text-align:right;'>10"
, " </td>"
, " <td style='padding-left:5px; vertical-align:top;'><a href='/site/w/wiki/A' title='A'>A</a>"
, " </td>"
, " </tr>"
, " <tr id='w.7CB'>"
, " <td style='padding-right:5px; vertical-align:top; text-align:right;'>20"
, " </td>"
, " <td style='padding-left:5px; vertical-align:top;'><a href='/site/w/wiki/B' title='B'>B</a>"
, " </td>"
, " </tr>"
));
}
}
class Xows_html_wkr_fxt {
private Xoae_app app; private Xowe_wiki wiki; private Xows_html_wkr html_mgr; private final Bry_bfr tmp_bfr = Bry_bfr.new_(255);
public Xows_html_wkr_fxt Clear() {
if (app == null) {
app = Xoa_app_fxt.app_();
wiki = Xoa_app_fxt.wiki_tst_(app);
html_mgr = new Xows_html_wkr();
}
return this;
}
public void Test_paging(boolean fwd, int paging_idx, String expd) {
Xows_ui_qry qry = new Xows_ui_qry(Bry_.new_a7("A"), paging_idx, 100, Xosrh_rslt_itm_sorter.Tid_len_dsc, new Xows_ns_mgr(), true, new Xow_domain[] {Xow_domain_.parse(wiki.Domain_bry())});
qry.Page_max_(2);
html_mgr.Init_by_wiki(wiki, wiki.Lang().Num_mgr(), qry);
byte[] paging_link = html_mgr.Paging_link(fwd);
Tfds.Eq(expd, String_.new_a7(paging_link));
}
public void Test_rows(Xows_db_row[] rows, String expd) {
Xows_ui_rslt rslt = new Xows_ui_rslt();
Xows_html_row html_row = new Xows_html_row(wiki.App().Html__lnki_bldr());
html_row.Init(rslt);
for (int i = 0; i < rows.length; ++i)
rslt.Add(rows[i]);
html_row.XferAry(tmp_bfr, 0);
Tfds.Eq_str_lines(expd, tmp_bfr.Xto_str_and_clear());
}
public Xows_db_row Make_row(int len, String ttl_str) {
byte[] ttl_bry = Bry_.new_u8(ttl_str);
return new Xows_db_row(Bry_.new_a7("w"), wiki.Ttl_parse(ttl_bry), 1, len);
}
}

View File

@@ -0,0 +1,81 @@
/*
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.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import gplx.core.primitives.*;
public class Xows_ns_mgr {
private final Ordered_hash ns_hash = Ordered_hash_.new_(); private final Int_obj_ref tmp_ns_id = Int_obj_ref.neg1_(); private final Bry_bfr tmp_bfr = Bry_bfr.reset_(32);
private boolean ns_all, ns_main;
public void Clear() {
ns_hash.Clear();
ns_all = ns_main = false;
}
public boolean Has(int ns_id) {
return ns_all // all flag set
|| ns_main && ns_id == Xow_ns_.Id_main // main flag set
|| ns_hash.Has(tmp_ns_id.Val_(ns_id)) // check against ns_hash
;
}
public void Add_by_id(int ns_id) {
if (ns_hash.Has(tmp_ns_id.Val_(ns_id)))
ns_hash.Del(tmp_ns_id);
ns_hash.Add_as_key_and_val(Int_obj_ref.new_(ns_id));
}
public void Add_by_name(byte[] ns_name) {
int id = Xow_ns_.Canonical_id(ns_name);
if (id != Xow_ns_.Id_null)
Add_by_id(id);
}
public void Add_all() {
ns_all = true;
}
public void Add_by_parse(byte[] key, byte[] val) {
int ns_enabled = Bry_.Xto_int(val);
if (ns_enabled == 1) { // make sure set to 1; EX: ignore &ns0=0
int key_len = key.length;
if (key_len == 3 && key[2] == Byte_ascii.Star) // translate ns* as ns_all
ns_all = true;
else {
int ns_id = Bry_.Xto_int_or(key, 2, key_len, Int_.MinValue);
if (ns_id != Int_.MinValue) { // ignore invalid ints; EX: &nsabc=1;
Add_by_id(ns_id);
ns_main = ns_all = false;
}
}
}
}
public void Add_main_if_empty() {
if (ns_hash.Count() == 0)
ns_main = true;
}
public byte[] To_hash_key() {
if (ns_all)
return Hash_key_all;
else if (ns_main)
return Hash_key_main;
else {
int ns_hash_len = ns_hash.Count();
for (int i = 0; i < ns_hash_len; i++) {
if (i != 0) tmp_bfr.Add_byte_semic();
Int_obj_ref ns_id_ref = (Int_obj_ref)ns_hash.Get_at(i);
tmp_bfr.Add_int_variable(ns_id_ref.Val());
}
return tmp_bfr.Xto_bry_and_clear();
}
}
private static final byte[] Hash_key_all = new byte[] {Byte_ascii.Star}, Hash_key_main = new byte[] {Byte_ascii.Num_0};
}

View File

@@ -0,0 +1,102 @@
/*
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.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import gplx.core.primitives.*; import gplx.xowa.wikis.*; import gplx.xowa.apis.xowa.specials.*;
import gplx.xowa.wikis.domains.crts.*;
public class Xows_page__search implements Xows_page, GfoInvkAble, GfoEvObj {
private final Xoae_app app; private final Xow_domain wiki_domain; private final Xoapi_search search_api;
private final Xows_core search_mgr; private final Xows_arg_mgr args_mgr = new Xows_arg_mgr();
private Xow_domain[] search_domain_ary;
public Xows_page__search(Xowe_wiki wiki) {
this.app = wiki.Appe();
this.wiki_domain = wiki.Domain_itm();
this.search_mgr = new Xows_core(wiki.Appe().Wiki_mgr());
this.ev_mgr = GfoEvMgr.new_(this);
this.search_api = wiki.Appe().Api_root().Special().Search();
GfoEvMgr_.SubSame_many(search_api, this, Xoapi_search.Evt_multi_wikis_changed, Xoapi_search.Evt_multi_wikis_changed);
}
public GfoEvMgr EvMgr() {return ev_mgr;} private GfoEvMgr ev_mgr;
public Xows_special_meta Special_meta() {return Xows_special_meta_.Itm__search;}
private void Multi_wikis_changed() {
Xow_domain_crt_itm crt = search_api.Multi_wikis_crt(wiki_domain);
this.search_domain_ary = app.Usere().Wiki().Xwiki_mgr().Get_by_crt(wiki_domain, crt);
if (search_domain_ary.length == 0) search_domain_ary = new Xow_domain[] {wiki_domain}; // default to current if bad input
Multi_sorts_changed();
}
private void Multi_sorts_changed() {
Xow_domain_crt_itm[] ary = search_api.Multi_sorts_crt(wiki_domain);
if (ary == null) return; // default to no sort if bad input
Xow_domain_sorter__manual sorter = new Xow_domain_sorter__manual(wiki_domain, ary);
Xow_domain_sorter__manual.Sort(sorter, search_domain_ary);
}
public void Special_gen(Xowe_wiki wiki, Xoae_page page, Xoa_url url, Xoa_ttl ttl) {
if (wiki.Domain_tid() == Xow_domain_type_.Tid_home) return; // do not allow search in home wiki; will throw null ref error b/c no search_ttl dirs
if (search_domain_ary == null) Multi_wikis_changed();
// get args
Xog_search_suggest_mgr search_suggest_mgr = wiki.Appe().Gui_mgr().Search_suggest_mgr();
args_mgr.Clear();
args_mgr.Parse(search_suggest_mgr.Args_default());
args_mgr.Parse(url.Args());
args_mgr.Ns_mgr().Add_main_if_empty();
// get search_bry
byte[] search_bry = args_mgr.Search_bry();
if (search_bry == null) { // search is not in qarg; EX:Special:Search?search=Earth
search_bry = ttl.Leaf_txt_wo_qarg(); // assume search is in leaf; EX: Special:Search/Earth
args_mgr.Search_bry_(search_bry);
}
if ( search_suggest_mgr.Auto_wildcard() // add * automatically if option set
&& wiki.Db_mgr().Tid() == gplx.xowa.dbs.Xodb_mgr_sql.Tid_sql // only apply to sql
&& Bry_finder.Find_fwd(search_bry, Byte_ascii.Star) == -1 // search term does not have asterisk
)
search_bry = Bry_.Add(search_bry, Byte_ascii.Star);
url.Page_bry_(Bry_.Add(Xows_special_meta_.Itm__search.Ttl_bry(), Byte_ascii.Slash_bry, search_bry));// HACK: need to re-set Page b/c href_parser does not eliminate qargs; DATE:2013-02-08
// search wiki
Xoa_ttl search_ttl = Xoa_ttl.parse_(wiki, search_bry);
Xoae_page search_page = page;
if (!Bry_.Eq(search_bry, Xows_special_meta_.Itm__search.Ttl_bry())) // do not lookup page else stack overflow; happens when going directly to Special:Search (from history)
search_page = wiki.Data_mgr().Get_page(search_ttl, false); // try to find page; EX:Special:Search?search=Earth -> en.w:Earth; needed for search suggest
// page not found, or explicit_search invoked
if (search_page.Missing() || url.Search_fulltext()) {
if (args_mgr.Cancel() != null) {
search_mgr.Cancel(args_mgr.Cancel());
page.Tab_data().Cancel_show_y_();
return;
}
page.Html_data().Html_restricted_n_();
page.Html_data().Xtn_search_text_(search_bry);
Xows_ui_qry qry = new Xows_ui_qry(search_bry, args_mgr.Paging_idx(), search_api.Results_per_page(), args_mgr.Sort_tid(), args_mgr.Ns_mgr(), search_api.Async_db(), search_domain_ary);
search_mgr.Search(wiki, page, qry);
}
// page found; return it;
else {
wiki.ParsePage(search_page, true);
page.Data_raw_(search_page.Data_raw());
if (page.Root() != null) // NOTE: null when going from w:Earth -> q:Earth; DATE:2013-03-20
page.Root().Data_htm_(search_page.Root().Data_htm());
page.Ttl_(search_ttl).Url_(Xoa_url.new_(wiki.Domain_bry(), search_ttl.Full_txt())).Redirected_(true);
}
}
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Xoapi_search.Evt_multi_wikis_changed)) Multi_wikis_changed();
else if (ctx.Match(k, Xoapi_search.Evt_multi_sorts_changed)) Multi_sorts_changed();
else return GfoInvkAble_.Rv_unhandled;
return this;
}
public static final byte Match_tid_all = 0, Match_tid_bgn = 1;
public static final byte Version_null = 0, Version_1 = 1, Version_2 = 2;
}

View File

@@ -0,0 +1,40 @@
/*
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.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import gplx.core.brys.*;
class Xows_paging_parser {
private final List_adp itm_list = List_adp_.new_();
private final Bry_rdr rdr = new Bry_rdr();
public Xows_paging_itm[] Parse(byte[] raw) { // EX: en.wikipedia.org|41|60;en.wiktionary.org|21|40;
rdr.Init(raw);
while (!rdr.Pos_is_eos()) {
byte[] wiki = rdr.Read_bry_to_pipe();
int bgn = rdr.Read_int_to_pipe();
int end = rdr.Read_int_to_semic();
Xows_paging_itm itm = new Xows_paging_itm(wiki, bgn, end);
itm_list.Add(itm);
}
return (Xows_paging_itm[])itm_list.To_ary_and_clear(Xows_paging_itm.class);
}
}
class Xows_paging_itm {
public Xows_paging_itm(byte[] wiki, int bgn, int end) {this.wiki = wiki; this.bgn = bgn; this.end = end;}
public byte[] Wiki() {return wiki;} private final byte[] wiki;
public int Bgn() {return bgn;} private final int bgn;
public int End() {return end;} private final int end;
}

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.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import gplx.html.*; import gplx.xowa.files.gui.*;
class Xows_ui_async {
private final Xows_html_row html_row; private final Xog_js_wkr js_wkr;
private final Xows_db_row[] rows; private final int rows_len;
private final Bry_bfr bfr = Bry_bfr.new_(255);
private final byte[] insert_new_key;
private final Cancelable cxl;
public Xows_ui_async(Cancelable cxl, Xows_html_row html_row, Xog_js_wkr js_wkr, int paging_len, byte[] wiki) {
this.cxl = cxl;
this.html_row = html_row; this.js_wkr = js_wkr;
this.rows = new Xows_db_row[paging_len];
this.rows_len = paging_len;
this.insert_new_key = Gen_insert_key(wiki);
}
public void Add(Xows_db_row new_row) {
Xows_db_row last_row = rows[rows_len - 1];
if (last_row != null) {
if (Compare(new_row, last_row) == CompareAble_.MoreOrSame) return; // new_row is < last_row; exit
}
int new_row_slot = Find_insert_slot(new_row); if (new_row_slot == -1) return;
Xows_db_row insert_row = rows[new_row_slot];
byte[] insert_key = insert_row == null ? insert_new_key : insert_row.Key();
Displace(new_row_slot, new_row);
html_row.Gen_html(bfr, new_row);
String html_tbl = bfr.Xto_str_and_clear();
if (cxl.Canceled()) return;
js_wkr.Html_elem_append_above(Html_utl.Encode_id_as_str(insert_key), html_tbl);
if (last_row != null) {
if (cxl.Canceled()) return;
js_wkr.Html_elem_replace_html(Html_utl.Encode_id_as_str(last_row.Key()), "");
}
}
private int Find_insert_slot(Xows_db_row new_row) {
for (int i = 0; i < rows_len; ++i) {
Xows_db_row cur_row = rows[i];
if (cur_row == null) return i;
if (Compare(new_row, cur_row) == CompareAble_.Less) return i;
}
return -1;
}
private void Displace(int new_row_slot, Xows_db_row new_row) {
for (int i = rows_len - 2; i >= new_row_slot; --i) {
rows[i + 1] = rows[i];
}
rows[new_row_slot] = new_row;
}
private int Compare(Xows_db_row lhs, Xows_db_row rhs) {
return -Int_.Compare(lhs.Page_len(), rhs.Page_len());
}
public static byte[] Gen_insert_key(byte[] wiki) {return Bry_.Add(Bry_insert_key, wiki);}
private static final byte[] Bry_insert_key = Bry_.new_a7("xowa_insert_");
}

View File

@@ -0,0 +1,62 @@
/*
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.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import org.junit.*; import gplx.xowa.html.wtrs.*; import gplx.xowa.files.gui.*;
public class Xows_ui_async_tst {
@Before public void init() {fxt.Clear();} private Xows_ui_async_fxt fxt = new Xows_ui_async_fxt();
@Test public void Basic() {
fxt.Test_add(fxt.Make_rslt(50, "L"), fxt.Make_args_append("xowa_insert_w" , "w.7CL")); // insert new
fxt.Test_add(fxt.Make_rslt(30, "N"), fxt.Make_args_append("xowa_insert_w" , "w.7CN")); // insert below last
fxt.Test_add(fxt.Make_rslt(70, "J"), fxt.Make_args_append("w.7CL" , "w.7CJ")); // insert above first
fxt.Test_add(fxt.Make_rslt(60, "K"), fxt.Make_args_append("w.7CL" , "w.7CK")); // insert above mid
fxt.Test_add(fxt.Make_rslt(40, "M"), fxt.Make_args_append("w.7CN" , "w.7CM")); // insert below mid
fxt.Test_add(fxt.Make_rslt(10, "P")); // insert noop
fxt.Test_add(fxt.Make_rslt(80, "I"), fxt.Make_args_append("w.7CJ" , "w.7CI") , fxt.Make_args_replace("w.7CN")); // insert displace all
fxt.Test_add(fxt.Make_rslt(61, "K1"), fxt.Make_args_append("w.7CK" , "w.7CK1"), fxt.Make_args_replace("w.7CM")); // insert displace mid
}
}
class Xows_ui_async_fxt {
private Xows_html_row html_row; private static final byte[] Bry_enwiki = Bry_.new_a7("w");
private Xows_ui_async async;
private Xog_js_wkr__log js_wkr = new Xog_js_wkr__log();
private Xowe_wiki wiki;
public void Clear() {
Xoae_app app = Xoa_app_fxt.app_();
this.wiki = Xoa_app_fxt.wiki_(app, "w");
html_row = new Xows_html_row(wiki.App().Html__lnki_bldr());
html_row.Fmtr().Fmt_("~{page_key}");
async = new Xows_ui_async(Cancelable_.Never, html_row, js_wkr, 5, Bry_enwiki);
}
public Xows_db_row Make_rslt(int len, String ttl) {
byte[] ttl_bry = Bry_.new_a7(ttl);
return new Xows_db_row(Bry_enwiki, wiki.Ttl_parse(ttl_bry), 1, len);
}
public Object[] Make_args_append(String uid, String html) {return Object_.Ary(Xog_js_wkr__log.Proc_append_above, uid, html);}
public Object[] Make_args_replace(String uid) {return Object_.Ary(Xog_js_wkr__log.Proc_replace_html, uid, "");}
public void Test_add(Xows_db_row row, Object[]... expd) {
async.Add(row);
int expd_len = expd.length;
Tfds.Eq(expd_len, js_wkr.Log__len());
for (int i = 0; i < expd_len; ++i) {
String expd_str = String_.ConcatWith_any("\n", expd[i]);
String actl_str = String_.ConcatWith_any("\n", js_wkr.Log__get_at(i));
Tfds.Eq_str_lines(expd_str, actl_str);
}
js_wkr.Log__clear();
}
}

View File

@@ -0,0 +1,116 @@
/*
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.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import gplx.core.threads.*; import gplx.html.*;
import gplx.xowa.wikis.*; import gplx.xowa.files.gui.*; import gplx.xowa.gui.views.*;
class Xows_ui_cmd implements GfoInvkAble, Cancelable, Xog_tab_close_lnr {
private final Xows_core mgr; private final Xows_ui_qry qry; private final Xows_ui_rslt rslt;
private final Xow_wiki wiki; private final Xoae_page page; private final Xog_tab_close_mgr tab_close_mgr; private final Xog_js_wkr js_wkr;
private final boolean async; private Xows_ui_async async_wkr;
private Xows_db_cache cache;
public Xows_ui_cmd(Xows_core mgr, Xows_ui_qry qry, Xow_wiki wiki, Xoae_page page, Xog_tab_close_mgr tab_close_mgr, Xog_js_wkr js_wkr) {
this.mgr = mgr; this.qry = qry; this.wiki = wiki; this.page = page; this.tab_close_mgr = tab_close_mgr; this.js_wkr = js_wkr;
this.async = wiki.App().App_type().Uid_is_gui() && qry.Async_db();
this.rslt = new Xows_ui_rslt();
this.key = Html_utl.Encode_id_as_bry(Bry_.Add(qry.Key(), Byte_ascii.Pipe_bry, wiki.Domain_bry()));
}
public byte[] Key() {return key;} private final byte[] key;
public Xow_wiki Wiki() {return wiki;}
public Xows_ui_rslt Rslt() {return rslt;}
public boolean Canceled() {return canceled;} private boolean canceled;
public void Cancel() {
Xoa_app_.Usr_dlg().Prog_many("", "", "search canceled: key=~{0}", key);
canceled = true;
this.Hide_cancel_btn();
}
public void Cancel_reset() {}
public boolean Search() {
this.cache = mgr.Get_cache_or_new(key);
boolean rv = false, fill_from_cache = true;
if (!cache.Done() && (qry.Itms_end() > cache.Itms_end())) {
if (async) {
fill_from_cache = false; // NOTE: do not retrieve cached results to page, else ui_async cmd will add out of order; DATE:2015-04-24
if (async_wkr == null) async_wkr = new Xows_ui_async(this, new Xows_html_row(new gplx.xowa.html.wtrs.Xoh_lnki_bldr(wiki.App(), wiki.App().Html__href_parser())), js_wkr, qry.Page_len(), wiki.Domain_bry());
Thread_adp_.invk_(gplx.xowa.apps.Xoa_thread_.Key_special_search_db, this, Invk_search_db).Start();
}
else
Search_db();
rv = true;
}
if (fill_from_cache) {
cache.Get_between(rslt, qry.Itms_bgn(), qry.Itms_end());
qry.Page_max_(cache.Count() / qry.Page_len());
}
return rv;
}
public void Search_db() {
tab_close_mgr.Add(this);
if (async) {
while (!page.Html_data().Mode_wtxt_shown()) // NOTE:must check for wtxt_shown else async can happen first, and then be overwritten by wtxt; DATE:2015-04-26
Thread_adp_.Sleep(100);
// show any existing items in the cache on screen; new updates wil bump these off; SEE:NOTE:show_existing;DATE:2015-04-26
int qry_itms_bgn = qry.Itms_bgn(), cache_count = cache.Count();
for (int i = qry_itms_bgn; i < cache_count; ++i)
async_wkr.Add(cache.Get_at(i));
}
new Xows_db_wkr().Search(this, qry, rslt, cache, wiki);
mgr.Search_end(this);
if (this.Canceled()) return; // NOTE: must check else throws SWT exception
this.Hide_cancel_btn();
if (cache.Done())
qry.Page_max_(cache.Count() / qry.Page_len());
Xoa_app_.Usr_dlg().Prog_many("", "", "");
}
private void Hide_cancel_btn() {
Thread_adp_.invk_(gplx.xowa.apps.Xoa_thread_.Key_special_search_cancel, this, Invk_hide_cancel).Start();
}
private void Hide_cancel_btn_async() {
js_wkr.Html_atr_set("xowa_cancel_" + wiki.Domain_str(), "style", "display:none;");
}
public void Add_rslt(Xows_db_row rslt) {
cache.Add(rslt);
if (async) async_wkr.Add(rslt);
}
public boolean When_close(Xog_tab_itm tab, Xoa_url url) {
if (url != Xoa_url.Null) { // not called by close_tab (Ctrl+W)
byte[] cancel_arg = url.Args_hash().Get_val_bry_or(Xows_arg_mgr.Arg_bry_cancel, null);
if (cancel_arg != null) return true; // cancel arg exists; assume tab is not being closed; note that cancel will be processed by Xows_page__special; DATE:2015-04-30
}
this.Cancel();
return true;
}
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk_search_db)) Search_db();
else if (ctx.Match(k, Invk_hide_cancel)) Hide_cancel_btn_async();
else return GfoInvkAble_.Rv_unhandled;
return this;
}
private static final String Invk_search_db = "search_db", Invk_hide_cancel = "hide_cancel";
}
/*
NOTE:show_existing. code needed to show A1
EX: search="A*": "A" has 400 words; "A1" has 1;
. search 1-20 returns 20 words for A and 1 word for A1.
.. the 1st A word has a len of 999 and the 20th A word has a length of 900;
.. A1 has a length of 799
. search 21-40 returns 20 words for A
.. the 21st word has a len of 899 and the 40th has a len of 800
.. A1 should show up briefly, and then get pushed off screen by 21-40
. search 61-40 returns 20 words for A
.. A1 must show up
*/

View File

@@ -0,0 +1,45 @@
/*
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.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import gplx.xowa.wikis.*;
class Xows_ui_qry {
private final List_adp cmd_list = List_adp_.new_();
public Xows_ui_qry(byte[] search_raw, int page_idx, int page_len, byte sort_tid, Xows_ns_mgr ns_mgr, boolean async_db, Xow_domain[] wiki_domains) {
this.search_raw = search_raw; this.page_idx = page_idx; this.page_len = page_len; this.sort_tid = sort_tid; this.ns_mgr = ns_mgr; this.async_db = async_db; this.wiki_domains = wiki_domains;
this.itms_bgn = page_idx * page_len;
this.page_max = page_idx; // default page_max to page_idx; adjust later when all results are known
this.key = Bry_.Add_w_dlm(Byte_ascii.Pipe, search_raw, ns_mgr.To_hash_key());
this.special_link_base_href = Bry_.Add(Bry_.new_a7("Special:Search/"), search_raw, Bry_.new_a7("?fulltext=y"));
}
public byte[] Key() {return key;} private final byte[] key;
public byte[] Search_raw() {return search_raw;} private final byte[] search_raw;
public boolean Async_db() {return async_db;} private boolean async_db;
public int Page_idx() {return page_idx;} private final int page_idx;
public int Page_max() {return page_max;} private int page_max;
public int Page_len() {return page_len;} private final int page_len;
public int Itms_bgn() {return itms_bgn;} private final int itms_bgn;
public int Itms_end() {return itms_bgn + page_len;}
public byte Sort_tid() {return sort_tid;} private final byte sort_tid;
public Xows_ns_mgr Ns_mgr() {return ns_mgr;} private final Xows_ns_mgr ns_mgr;
public Xow_domain[] Wiki_domains() {return wiki_domains;} private final Xow_domain[] wiki_domains;
public void Page_max_(int v) {this.page_max = v;}
public int Cmds__len() {return cmd_list.Count();}
public Xows_ui_cmd Cmds__get_at(int i) {return (Xows_ui_cmd)cmd_list.Get_at(i);}
public void Cmds__add(Xows_ui_cmd cmd) {cmd_list.Add(cmd);}
public byte[] Special_link_base_href() {return special_link_base_href;} private final byte[] special_link_base_href;
}

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.specials.search; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
class Xows_ui_rslt {
private final List_adp rslt_list = List_adp_.new_();
public int Len() {return rslt_list.Count();}
public void Add(Xows_db_row rslt) {rslt_list.Add(rslt);}
public Xows_db_row Get_at(int i) {return (Xows_db_row)rslt_list.Get_at(i);}
}

View File

@@ -0,0 +1,68 @@
/*
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.specials.search.parsers; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*; import gplx.xowa.specials.search.*;
import gplx.core.primitives.*;
class Xows_text_parser__v1 {
private Xol_lang lang; private Bry_bfr bfr = Bry_bfr.new_(255);
private final Ordered_hash list = Ordered_hash_.new_bry_();
public void Init(Xol_lang lang) {this.lang = lang;}
public void Parse(byte[] src, int src_len, int bgn, int end) {
if (lang != null) { // null lang passed in by searcher
src = lang.Case_mgr().Case_build_lower(src);
src_len = src.length;
}
int i = 0; boolean word_done = false;
while (true) {
if (word_done || i == src_len) {
if (bfr.Len() > 0) {
byte[] word = bfr.Xto_bry_and_clear();
if (!list.Has(word)) list.Add(word, word); // don't add same word twice; EX: Title of "Can Can" should only have "Can" in index
}
if (i == src_len) break;
word_done = false;
}
byte b = src[i];
switch (b) {
case Byte_ascii.Underline: // underline is word-breaking; EX: A_B -> A, B
case Byte_ascii.Space: // should not occur, but just in case (only underscores)
case Byte_ascii.Tab: case Byte_ascii.Nl: case Byte_ascii.Cr: // should not occur in titles, but just in case
case Byte_ascii.Dash: // treat hypenated words separately
case Byte_ascii.Dot: // treat abbreviations as separate words; EX: A.B.C.
case Byte_ascii.Bang: case Byte_ascii.Hash: case Byte_ascii.Dollar: case Byte_ascii.Percent:
case Byte_ascii.Amp: case Byte_ascii.Paren_bgn: case Byte_ascii.Paren_end: case Byte_ascii.Star:
case Byte_ascii.Comma: case Byte_ascii.Slash:
case Byte_ascii.Colon: case Byte_ascii.Semic: case Byte_ascii.Gt:
case Byte_ascii.Question: case Byte_ascii.At: case Byte_ascii.Brack_bgn: case Byte_ascii.Brack_end:
case Byte_ascii.Pow: case Byte_ascii.Tick:
case Byte_ascii.Curly_bgn: case Byte_ascii.Pipe: case Byte_ascii.Curly_end: case Byte_ascii.Tilde:
case Byte_ascii.Quote: case Byte_ascii.Apos: // FUTURE: apos will split "Earth's" to Earth and s; should remove latter
++i;
word_done = true;
break;
default:
bfr.Add_byte(b);
++i;
break;
}
}
// byte[][] rv = (byte[][])list.To_ary(typeof(byte[]));
// list.Clear(); list.Resize_bounds(16);
// return rv;
}
}

View File

@@ -0,0 +1,107 @@
/*
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.specials.search.parsers; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*; import gplx.xowa.specials.search.*;
import gplx.core.btries.*; import gplx.xowa.langs.cases.*;
class Xows_text_parser__v2 {
private final Btrie_slim_mgr trie = Btrie_slim_mgr.cs_();
private final Bry_bfr bfr = Bry_bfr.new_(32);
private Xob_word_mgr word_mgr; private Xol_case_mgr case_mgr;
private byte[] src; private int end; // bgn,
private boolean dirty; private Xows_text_tkn__split parser__ws;
public void Init_for_ttl(Xob_word_mgr word_mgr, Xol_case_mgr case_mgr) {
this.word_mgr = word_mgr; this.case_mgr = case_mgr;
trie.Clear();
this.parser__ws = Xows_text_tkn__split.new_(trie, Bool_.N, " ", "\t", "\n", "\r", "_");
Xows_text_tkn__split.new_(trie, Bool_.N, "!", "?");
Xows_text_tkn__split.new_(trie, Bool_.N, "(", ")");
Xows_text_tkn__split.new_(trie, Bool_.N, "/");
Xows_text_tkn__ellipsis.new_(trie, "..");
Xows_text_tkn__apos.new_(trie, "'", Byte_ascii.Ltr_s);
}
public void Parse(byte[] src, int src_len, int bgn, int end) {
this.src = src; this.end = end; // this.bgn = bgn;
this.dirty = false; this.bgn__ws = bgn__dash = bgn__slash = -1;
this.src = case_mgr.Case_build_lower(src); src_len = this.src.length;
int pos = bgn;
while (true) {
boolean is_last = pos == end;
if (is_last) { // do split
Word__add(bgn__ws, end);
break;
}
byte b = src[pos];
Object o = trie.Match_bgn_w_byte(b, src, pos, end);
if (o == null) { // unknown sequence; word-char
Char__add(b, pos);
++pos;
}
else {
Xows_text_tkn parser = (Xows_text_tkn)o;
pos = parser.Parse(this, src, end, pos, trie.Match_pos());
}
}
}
public int Bgn__ws() {return bgn__ws;} private int bgn__ws;
public int Bgn__dash() {return bgn__dash;} private int bgn__dash;
public int Bgn__slash() {return bgn__slash;} private int bgn__slash;
public void Bgn__ws_clear() {this.bgn__ws = -1;}
public void Bgn__dash_(int v) {this.bgn__dash = v;}
public void Bgn__slash_(int v) {this.bgn__slash= v;}
public void Word__add(int bgn__ws, int word_end) {
if (bgn__ws == word_end) return; // handle situations like "A!" where sym is at eos
if (bgn__ws == -1) return; // handle situations like "A... " where " " is different than "..."
byte[] word = dirty ? bfr.Xto_bry_and_clear() : Bry_.Mid(src, bgn__ws, word_end);
word_mgr.Add(word);
if (bgn__dash != -1) {
word_mgr.Add(Bry_.Mid(src, bgn__dash, word_end));
bgn__dash = -1;
}
}
public void Char__add(byte b, int pos) {
if (dirty)
bfr.Add_byte(b);
else {
if (bgn__ws == -1)
bgn__ws = pos;
}
}
public boolean Ws__is_word_end(int pos) {return parser__ws.Is_word_end(src, end, pos);}
}
class Xob_word_mgr {
private final Ordered_hash hash = Ordered_hash_.new_bry_();
public void Clear() {hash.Clear();}
public int Len() {return hash.Count();}
public Xob_word_itm Get_at(int i) {return (Xob_word_itm)hash.Get_at(i);}
public void Add(byte[] word) {
Xob_word_itm itm = (Xob_word_itm)hash.Get_by(word);
if (itm == null) {
itm = new Xob_word_itm(word);
hash.Add(word, itm);
}
itm.Count_add_1_();
}
}
class Xob_word_itm {
public Xob_word_itm(byte[] word) {
this.word = word;
this.count = 0;
}
public byte[] Word() {return word;} private final byte[] word;
public int Count() {return count;} private int count; public void Count_add_1_() {++count;}
@gplx.Internal protected Xob_word_itm Count_(int v) {this.count = v; return this;}
}

View File

@@ -0,0 +1,156 @@
/*
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.specials.search.parsers; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*; import gplx.xowa.specials.search.*;
import org.junit.*; import gplx.xowa.langs.cases.*;
public class Xows_text_parser__v2_tst {
private final Xows_text_parser__v2_fxt fxt = new Xows_text_parser__v2_fxt();
@Before public void init() {fxt.Init();}
@Test public void Word__one() {
fxt.Clear().Test_split("abcd", "abcd");
}
@Test public void Word__many() {
fxt.Clear().Test_split("abc d ef", "abc", "d", "ef");
}
@Test public void Ws__many() {
fxt.Clear().Test_split("a b", "a", "b");
}
@Test public void Ws__bgn() {
fxt.Clear().Test_split(" a", "a");
}
@Test public void Ws__end() {
fxt.Clear().Test_split(" a", "a");
}
@Test public void Under() {
fxt.Clear().Test_split("a_b", "a", "b");
}
@Test public void Lowercase() {
fxt.Clear().Test_split("A B C", "a", "b", "c");
}
@Test public void Dupe() {
fxt.Clear().Test_split("a a a", fxt.Make_word("a", 3));
}
@Test public void Dupe__lowercase() {
fxt.Clear().Test_split("a A", fxt.Make_word("a", 2));
}
@Test public void Dot__acronym() { // EX: "History of U.S.A. Science "
fxt.Clear().Test_split("abc D.E.F. ghi", "abc", "d.e.f.", "ghi");
}
@Test public void Dot__initials() { // EX: "H. G. Wells"
fxt.Clear().Test_split("a. b. cde", "a.", "b.", "cde");
}
@Test public void Dot__abrv() { // EX: "vs.", "no."
fxt.Clear().Test_split("a vs. b", "a", "vs.", "b");
}
@Test public void Dot__internet() { // EX: "en.wikipedia.org"
fxt.Clear().Test_split("a.com", "a.com");
}
@Test public void Ellipsis__basic() { // EX: "Nights into Dreams..."
fxt.Clear().Test_split("a... bc d", "a", "...", "bc", "d");
}
@Test public void Ellipsis__bgn() {
fxt.Clear().Test_split("...a", "...", "a");
}
@Test public void Ellipsis__end() {
fxt.Clear().Test_split("a...", "a", "...");
}
@Test public void Ellipsis__no_ws() {
fxt.Clear().Test_split("a...b", "a", "...", "b");
}
@Test public void Apos__contraction() { // EX: "I'm"
fxt.Clear().Test_split("i'm", "i'm");
}
@Test public void Apos__multiple() {
fxt.Clear().Test_split("a''b", "a''b");
}
@Test public void Apos__possessive_singular_eos() {// EX: "wiki's"
fxt.Clear().Test_split("a's", "a", "a's");
}
@Test public void Apos__possessive_singular_word() {
fxt.Clear().Test_split("a's b", "a", "a's", "b");
}
@Test public void Apos__possessive_plural_eos() {// EX: "wiki'"
fxt.Clear().Test_split("a'", "a", "a'");
}
@Test public void Apos__possessive_plural_word() {
fxt.Clear().Test_split("a' b", "a", "a'", "b");
}
@Test public void Bang__lone() {
fxt.Clear().Test_split("! a", "a");
}
@Test public void Bang__word() {
fxt.Clear().Test_split("a!", "a");
}
@Test public void Bang__sentence() {// EX: "A!"
fxt.Clear().Test_split("a b!", "a", "b");
}
@Test public void Question__sentence() {// EX: "A?"
fxt.Clear().Test_split("a?", "a");
}
@Test public void Parens_both() {// EX: "A (letter)"
fxt.Clear().Test_split("a (b)", "a", "b");
}
@Test public void Slash__word() {// EX: "Good_cop/bad_cop"
fxt.Clear().Test_split("a/b", "a", "b");
}
// apos: 'Some apostrophe sentence' ?
}
class Xows_text_parser__v2_fxt {
private final Xows_text_parser__v2 word_parser = new Xows_text_parser__v2();
private final Xob_word_mgr word_mgr = new Xob_word_mgr();
private final Bry_bfr tmp_bfr = Bry_bfr.new_(32);
private Xol_case_mgr case_mgr;
public void Init() {
case_mgr = Xol_case_mgr_.Ascii();
word_parser.Init_for_ttl(word_mgr, case_mgr);
}
public Xows_text_parser__v2_fxt Clear() {
word_mgr.Clear();
return this;
}
public Xob_word_itm Make_word(String raw, int count) {return new Xob_word_itm(Bry_.new_u8(raw)).Count_(count);}
public void Test_split(String src, String... expd_words) {
int len = expd_words.length;
Xob_word_itm[] ary = new Xob_word_itm[len];
for (int i = 0; i < len; ++i) {
ary[i] = Make_word(expd_words[i], 1);
}
Test_split(src, ary);
}
public void Test_split(String src, Xob_word_itm... expd_words) {
byte[] src_bry = Bry_.new_u8(src);
word_parser.Parse(src_bry, src_bry.length, 0, src_bry.length);
Tfds.Eq_str_lines(To_str(expd_words), To_str(word_mgr));
}
private String To_str(Xob_word_itm[] word_ary) {
int len = word_ary.length;
for (int i = 0; i < len; ++i) {
if (i != 0) tmp_bfr.Add_byte_nl();
Xob_word_itm word = word_ary[i];
tmp_bfr.Add(word.Word()).Add_byte_pipe();
tmp_bfr.Add_int_variable(word.Count());
}
return tmp_bfr.Xto_str_and_clear();
}
private String To_str(Xob_word_mgr word_mgr) {
int len = word_mgr.Len();
Xob_word_itm[] ary = new Xob_word_itm[len];
for (int i = 0; i < len; ++i)
ary[i] = word_mgr.Get_at(i);
return To_str(ary);
}
}

View File

@@ -0,0 +1,146 @@
/*
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.specials.search.parsers; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*; import gplx.xowa.specials.search.*;
import gplx.core.btries.*; import gplx.core.primitives.*;
interface Xows_text_tkn {
int Parse(Xows_text_parser__v2 mgr, byte[] src, int src_end, int tkn_bgn, int tkn_end);
}
class Xows_text_tkn__split implements Xows_text_tkn {
private final boolean add_sym_as_word;
private final Btrie_slim_mgr trie = Btrie_slim_mgr.cs_();
public Xows_text_tkn__split(boolean add_sym_as_word, byte[][] ary) {
this.add_sym_as_word = add_sym_as_word;
int len = ary.length;
for (int i = 0; i < len; ++i) {
byte[] itm = ary[i];
trie.Add_obj(itm, Int_obj_val.new_(itm.length));
}
}
public int Parse(Xows_text_parser__v2 mgr, byte[] src, int src_end, int tkn_bgn, int tkn_end) {
if (mgr.Bgn__ws() != -1) // pending word
mgr.Word__add(mgr.Bgn__ws(), tkn_bgn); // make word; EX: "B" in "A B C"
mgr.Bgn__ws_clear();
if (add_sym_as_word)
mgr.Word__add(tkn_bgn, tkn_end);
int rv = tkn_end;
while (rv < src_end) { // skip ws; EX: "a b"
byte b = src[rv];
Object o = trie.Match_bgn_w_byte(b, src, rv, src_end);
if (o == null) break;
Int_obj_val itm_len = (Int_obj_val)o;
rv += itm_len.Val();
}
return rv;
}
public boolean Is_word_end(byte[] src, int end, int pos) {
if (pos >= end) return true;
byte b = src[pos];
Object o = trie.Match_bgn_w_byte(b, src, pos, end);
return o != null;
}
public static Xows_text_tkn__split new_(Btrie_slim_mgr trie, boolean add_sym_as_word, String... str_ary) {
byte[][] bry_ary = Bry_.Ary(str_ary);
Xows_text_tkn__split rv = new Xows_text_tkn__split(add_sym_as_word, bry_ary);
int len = bry_ary.length;
for (int i = 0; i < len; ++i)
trie.Add_obj(bry_ary[i], rv);
return rv;
}
}
class Xows_text_tkn__ellipsis implements Xows_text_tkn {
private final byte ellipsis_byte;
public Xows_text_tkn__ellipsis(byte ellipsis_byte) {
this.ellipsis_byte = ellipsis_byte;
}
public int Parse(Xows_text_parser__v2 mgr, byte[] src, int src_end, int tkn_bgn, int tkn_end) {
int bgn__ws = mgr.Bgn__ws();
if (bgn__ws != -1) {
mgr.Word__add(bgn__ws, tkn_bgn); // add word; EX: "Dreams" in "Dreams..."
mgr.Bgn__ws_clear(); // clear ws flag, else space will create word; EX: "A... B"
}
int rv = Bry_finder.Find_fwd_while(src, tkn_end, src_end, ellipsis_byte);
mgr.Word__add(tkn_bgn, rv); // add ellipssis
return rv;
}
public static Xows_text_tkn new_(Btrie_slim_mgr trie, String ellipsis) {
byte[] bry = Bry_.new_u8(ellipsis);
Xows_text_tkn rv = new Xows_text_tkn__ellipsis(Bry_.Get_at_end_or_fail(bry));
trie.Add_obj(bry, rv);
return rv;
}
}
class Xows_text_tkn__apos implements Xows_text_tkn {
private final byte possessive_byte;
public Xows_text_tkn__apos(byte possessive_byte) {this.possessive_byte = possessive_byte;}
public int Parse(Xows_text_parser__v2 mgr, byte[] src, int src_end, int tkn_bgn, int tkn_end) {
int rv = tkn_end;
byte apos_mode = Apos_contraction;
if (tkn_end == src_end) { // EX: "A'<EOS>"
apos_mode = Apos_possessive_plural;
rv = src_end;
}
else if (mgr.Ws__is_word_end(tkn_end)) { // EX: "A' "
apos_mode = Apos_possessive_plural;
rv = tkn_end;
}
else if ( src[tkn_end] == possessive_byte // EX: "A's "
&& mgr.Ws__is_word_end(tkn_end + 1))
{
apos_mode = Apos_possessive_singular;
rv = tkn_end + 1;
}
switch (apos_mode) {
case Apos_possessive_plural:
case Apos_possessive_singular:
int word_bgn = mgr.Bgn__ws();
mgr.Word__add(word_bgn, tkn_bgn); // add noun; EX: "wiki";
mgr.Word__add(word_bgn, rv); // add full; EX: "wiki's"
mgr.Bgn__ws_clear();
return rv;
case Apos_contraction:
break;
}
return rv;
}
private static final byte Apos_contraction = 1, Apos_possessive_plural = 2, Apos_possessive_singular = 3;
public static Xows_text_tkn new_(Btrie_slim_mgr trie, String apos, byte possessive_byte) {
byte[] bry = Bry_.new_u8(apos);
Xows_text_tkn rv = new Xows_text_tkn__apos(possessive_byte);
trie.Add_obj(bry, rv);
return rv;
}
}
// class Xows_text_tkn__slash : Xows_text_tkn {
// public int Parse(Xows_text_parser__v2 mgr, byte[] src, int src_end, int tkn_bgn, int tkn_end) {
// int bgn__dash = mgr.Bgn__dash();
// // add part;
// int part_bgn = mgr.Bgn__dash();
// if (part_bgn == -1) // no dash
// part_bgn = mgr.Bgn__ws();
// if (part_bgn != -1)
// mgr.Word__add(part_bgn, tkn_bgn); // add word; EX: "a" in "a-b"
// mgr.Bgn__dash_(tkn_end);
// return tkn_end;
// }
// public static Xows_text_tkn new_(Btrie_slim_mgr trie, String dash) {
// byte[] bry = Bry_.new_u8(dash);
// Xows_text_tkn rv = new Xows_text_tkn__slash();
// trie.Add_obj(bry, rv);
// return rv;
// }
// }

View File

@@ -0,0 +1,94 @@
/*
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.specials.search.parsers_old; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*; import gplx.xowa.specials.search.*;
public class Xow_search_parser {
private Xow_search_parser_ctx parse_ctx = new Xow_search_parser_ctx(); private byte[] src;
public Xows_db_matcher Parse(byte[] src) {
this.src = src;
Xow_search_tkn[] tkns = new Xow_search_scanner().Scan(src);
return Parse_itm_or(parse_ctx.Init(tkns));
}
private Xows_db_matcher Parse_itm_or(Xow_search_parser_ctx parse_ctx) {
Xows_db_matcher lhs = Parse_itm_and(parse_ctx);
while (parse_ctx.Cur_tid(Xow_search_tkn.Tid_or)) {
parse_ctx.Move_next();
Xows_db_matcher rhs = Parse_itm_and(parse_ctx);
lhs = new_join(Xows_db_matcher.Tid_or, lhs, rhs);
}
return lhs;
}
private Xows_db_matcher Parse_itm_and(Xow_search_parser_ctx parse_ctx) {
Xows_db_matcher lhs = Parse_itm_not(parse_ctx);
while (parse_ctx.Cur_tid(Xow_search_tkn.Tid_and)) {
parse_ctx.Move_next();
Xows_db_matcher rhs = Parse_itm_not(parse_ctx);
lhs = new_join(Xows_db_matcher.Tid_and, lhs, rhs);
}
return lhs;
}
private Xows_db_matcher Parse_itm_not(Xow_search_parser_ctx parse_ctx) {
Xows_db_matcher lhs = Parse_itm_leaf(parse_ctx);
while (parse_ctx.Cur_tid(Xow_search_tkn.Tid_not)) {
parse_ctx.Move_next();
Xows_db_matcher rhs = Parse_itm_leaf(parse_ctx);
lhs = new_join(Xows_db_matcher.Tid_not, null, rhs);
}
return lhs;
}
private Xows_db_matcher Parse_itm_leaf(Xow_search_parser_ctx parse_ctx) {
if (parse_ctx.Cur_tid(Xow_search_tkn.Tid_paren_bgn)) {
parse_ctx.Move_next();
Xows_db_matcher lhs = Parse_itm_or(parse_ctx);
if (parse_ctx.Cur_tid(Xow_search_tkn.Tid_paren_end)) parse_ctx.Move_next(); // skip token
return lhs;
}
else if (parse_ctx.Cur_tid(Xow_search_tkn.Tid_eos))
return Xows_db_matcher.Null;
else {
Xow_search_tkn word_tkn = parse_ctx.Move_next();
if (word_tkn.Tid() == Xow_search_tkn.Tid_not) {
word_tkn = parse_ctx.Move_next();
if (word_tkn == null) return Xows_db_matcher.Null; // occurs in "a -"
Xows_db_matcher word_itm = new_word(word_tkn, src);
return new_join(Xows_db_matcher.Tid_not, null, word_itm);
}
else
return new_word(word_tkn, src);
}
}
private static Xows_db_matcher new_word(Xow_search_tkn tkn, byte[] src) {
int tid = tkn.Tid() == Xow_search_tkn.Tid_word ? Xows_db_matcher.Tid_word : Xows_db_matcher.Tid_word_quote;
return new Xows_db_matcher(tid, tkn.Val(src), null, null);
}
private static Xows_db_matcher new_join(int tid, Xows_db_matcher lhs, Xows_db_matcher rhs) {return new Xows_db_matcher(tid, null, lhs, rhs);}
}
class Xow_search_parser_ctx {
private Xow_search_tkn[] ary; private int pos = 0; private int ary_len;
public Xow_search_parser_ctx Init(Xow_search_tkn[] ary) {
this.ary = ary;
this.ary_len = ary.length;
this.pos = 0;
return this;
}
public boolean Cur_tid(byte tid) {return pos < ary_len ? tid == ary[pos].Tid(): tid == Xow_search_tkn.Tid_eos;}
public Xow_search_tkn Move_next() {
Xow_search_tkn rv = null;
if (pos < ary_len) rv = ary[pos++];
return rv;
}
}

View File

@@ -0,0 +1,144 @@
/*
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.specials.search.parsers_old; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*; import gplx.xowa.specials.search.*;
import gplx.core.primitives.*; import gplx.core.btries.*;
class Xow_search_scanner {
private final List_adp tkns = List_adp_.new_(); private byte[] src; private int src_len, pos, txt_bgn;
private final Ordered_hash tmp_list = Ordered_hash_.new_(); private final Bry_bfr tmp_bfr = Bry_bfr.new_();
public Xow_search_tkn[] Scan(byte[] src) {
this.src = src; this.src_len = src.length;
tkns.Clear(); pos = 0; txt_bgn = -1;
while (pos < src_len) {
byte cur_b = src[pos];
Object cur_obj = trie.Match_bgn_w_byte(cur_b, src, pos, src_len);
if (cur_obj == null) { // text character
if (txt_bgn == -1) txt_bgn = pos; // 1st character not set; set it
++pos;
}
else { // AND, OR, (, ), -, \s, "
int pos_end = trie.Match_pos();
byte cur_tid = ((Byte_obj_val)cur_obj).Val();
if (Cur_join_is_word(cur_tid, pos_end)) continue; // ignore words containing "and", "or"; EX: "random"; "for"
if (txt_bgn != -1) { // pending word; create
Tkns_add_word(Xow_search_tkn.Tid_word, txt_bgn, pos);
txt_bgn = -1;
}
switch (cur_tid) {
case Xow_search_tkn.Tid_space: // discard spaces
pos = Bry_finder.Find_fwd_while(src, pos, src_len, Byte_ascii.Space);
break;
case Xow_search_tkn.Tid_quote: // find end quote and add as word
int quote_bgn = pos + 1;
int quote_end = Bry_finder.Find_fwd(src, Byte_ascii.Quote, quote_bgn, src_len);
if (quote_end == Bry_.NotFound) throw Exc_.new_("could not find end quote", "src", String_.new_u8(src));
Tkns_add_word(Xow_search_tkn.Tid_word_quoted, quote_bgn, quote_end);
pos = quote_end + 1; // +1 to place after quote
break;
case Xow_search_tkn.Tid_not:
Tkns_add_word(Xow_search_tkn.Tid_not, pos, pos_end);
pos = pos_end;
break;
case Xow_search_tkn.Tid_paren_bgn: case Xow_search_tkn.Tid_paren_end:
case Xow_search_tkn.Tid_and: case Xow_search_tkn.Tid_or:
tkns.Add(new_tkn(cur_tid, pos, pos_end));
pos = pos_end;
break;
default: throw Exc_.new_unhandled(cur_tid);
}
}
}
if (txt_bgn != -1) { // pending word; create
Tkns_add_word(Xow_search_tkn.Tid_word, txt_bgn, pos);
txt_bgn = -1;
}
return (Xow_search_tkn[])tkns.To_ary_and_clear(Xow_search_tkn.class);
}
private boolean Cur_join_is_word(byte cur_tid, int pos_end) { // extra logic to handle and / or occuring in unquoted strings; EX: "random"; "for"
switch (cur_tid) {
default: return false; // only look at AND, OR, -
case Xow_search_tkn.Tid_and: case Xow_search_tkn.Tid_or: case Xow_search_tkn.Tid_not:
break;
}
boolean join_is_word = true;
if (txt_bgn == -1) { // no pending word;
if (cur_tid == Xow_search_tkn.Tid_not) return false; // NOT is only operator if no pending tkn; EX: -abc -> NOT abc; a-b -> a-b
byte nxt_b = pos_end < src_len ? src[pos_end] : Byte_ascii.Nil;
Object nxt_obj = trie.Match_bgn_w_byte(nxt_b, src, pos_end, src_len);
if (nxt_obj == null) // next tkn is text; join must be word
join_is_word = true;
else { // next tkn is tkn
byte nxt_tid = ((Byte_obj_val)nxt_obj).Val();
switch (nxt_tid) {
case Xow_search_tkn.Tid_space: case Xow_search_tkn.Tid_quote:
case Xow_search_tkn.Tid_paren_bgn: case Xow_search_tkn.Tid_paren_end:
join_is_word = false; // next tkn is sym; and/or is not word; EX: a AND ; a AND"b"; a AND(b)
break;
case Xow_search_tkn.Tid_not: case Xow_search_tkn.Tid_and: case Xow_search_tkn.Tid_or:
join_is_word = true; // next tkn is and or not; and/or is word; EX: andor; oror; or-abc;
break;
default: throw Exc_.new_unhandled(cur_tid);
}
}
}
else { // pending word; cur join must be word; EX: "grand": "and" invoked and "gr" pending
join_is_word = true;
}
if (join_is_word) {
if (txt_bgn == -1) txt_bgn = pos; // 1st character not set; set it
pos = pos_end;
return true;
}
if (txt_bgn != -1) {
Tkns_add_word(Xow_search_tkn.Tid_word, txt_bgn, pos); // create word
txt_bgn = -1;
}
return false;
}
private void Tkns_add_word(byte tid, int src_bgn, int src_end) {
if (tkns.Count() > 0) { // at least 1 tkn; check for "auto-and"
Xow_search_tkn last_tkn = (Xow_search_tkn)tkns.Get_at_last();
if (last_tkn.Tid() == Xow_search_tkn.Tid_word) // previous tkn is word; auto "AND" words; EX: A B -> A AND B
tkns.Add(Xow_search_tkn.new_bry(Xow_search_tkn.Tid_and, Bry_and));
}
if (tid == Xow_search_tkn.Tid_word) { // if word has symbol, convert to quoted; EX: a-b should become "a-b"; otherwise searcher would search for a single word a-b
byte[] cur_word = Bry_.Mid(src, src_bgn, src_end);
byte[][] words = gplx.xowa.bldrs.cmds.texts.Xob_search_base.Split_ttl_into_words(null, tmp_list, tmp_bfr, cur_word);
int words_len = words.length;
if ( words_len == 1 // only one word
&& !Bry_.Eq(words[0], cur_word) // split word not same as raw
&& Bry_finder.Find_fwd(cur_word, Byte_ascii.Star) == -1 // no asterisk
) {
tkns.Add(Xow_search_tkn.new_bry(tid, words[0]));
return;
}
if (words.length > 1) // multiple words; add as quoted-term; EX: "a-b"
tid = Xow_search_tkn.Tid_word_quoted;
}
tkns.Add(new_tkn(tid, src_bgn, src_end));
}
private Xow_search_tkn new_tkn(byte tid, int val_bgn, int val_end) {return Xow_search_tkn.new_pos(tid, val_bgn, val_end);}
private static final byte[] Bry_and = Bry_.new_a7("AND");
private static final Btrie_slim_mgr trie = Btrie_slim_mgr.ci_ascii_()// NOTE:ci.ascii:OR / AND only
.Add_str_byte(" " , Xow_search_tkn.Tid_space)
.Add_str_byte("\"" , Xow_search_tkn.Tid_quote)
.Add_str_byte("-" , Xow_search_tkn.Tid_not)
.Add_str_byte("(" , Xow_search_tkn.Tid_paren_bgn)
.Add_str_byte(")" , Xow_search_tkn.Tid_paren_end)
.Add_str_byte("or" , Xow_search_tkn.Tid_or)
.Add_str_byte("and" , Xow_search_tkn.Tid_and);
}

View File

@@ -0,0 +1,40 @@
/*
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.specials.search.parsers_old; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*; import gplx.xowa.specials.search.*;
class Xow_search_tkn {
private final int val_bgn, val_end;
private final byte[] val_bry;
Xow_search_tkn(byte tid, int val_bgn, int val_end, byte[] val_bry) {this.tid = tid; this.val_bgn = val_bgn; this.val_end = val_end; this.val_bry = val_bry;}
public byte Tid() {return tid;} private final byte tid;
public byte[] Val(byte[] src) {return val_bry == null ? Bry_.Mid(src, val_bgn, val_end) : val_bry;}
public static Xow_search_tkn new_pos(byte tid, int val_bgn, int val_end) {return new Xow_search_tkn(tid, val_bgn, val_end, null);}
public static Xow_search_tkn new_bry(byte tid, byte[] val_bry) {return new Xow_search_tkn(tid, -1, -1, val_bry);}
public static final byte
Tid_root = 1
, Tid_word = 2
, Tid_word_quoted = 3
, Tid_space = 4
, Tid_quote = 5
, Tid_not = 6
, Tid_paren_bgn = 7
, Tid_paren_end = 8
, Tid_or = 9
, Tid_and = 10
, Tid_eos = 11
;
}

View File

@@ -0,0 +1,132 @@
/*
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.specials.statistics; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import gplx.xowa.langs.numbers.*;
public class Xop_statistics_page implements Xows_page {
private Xop_statistics_stats_page_grp stats_page = new Xop_statistics_stats_page_grp();
// private Xop_statistics_stats_wiki_grp stats_wiki = new Xop_statistics_stats_wiki_grp();
private Xop_statistics_stats_ns_grp stats_ns = new Xop_statistics_stats_ns_grp();
public Xows_special_meta Special_meta() {return Xows_special_meta_.Itm__statistics;}
public void Special_gen(Xowe_wiki wiki, Xoae_page page, Xoa_url url, Xoa_ttl ttl) {
byte[] html = Build_html(wiki);
page.Html_data().Html_restricted_n_(); // [[Special:]] pages allow all HTML
page.Data_raw_(html);
}
public byte[] Build_html(Xowe_wiki wiki) {
Bry_bfr tmp_bfr = wiki.Utl__bfr_mkr().Get_m001();
stats_page.Wiki_(wiki);
// stats_wiki.Wiki_(wiki);
stats_ns.Wiki_(wiki);
fmtr_all.Bld_bfr_many(tmp_bfr, stats_page, stats_ns);
return tmp_bfr.To_bry_and_rls();
}
private Bry_fmtr fmtr_all = Bry_fmtr.new_(String_.Concat_lines_nl_skip_last
( "<div id=\"mw-content-text\">"
, "<table class=\"wikitable mw-statistics-table\">~{page_stats}~{ns_stats}"
, "</table>"
, "</div>"
), "page_stats", "ns_stats");
}
class Xop_statistics_stats_page_grp implements Bry_fmtr_arg {
public void Wiki_(Xowe_wiki v) {this.wiki = v;} private Xowe_wiki wiki;
public void XferAry(Bry_bfr bfr, int idx) {
byte[] lbl_header_pages = wiki.Msg_mgr().Val_by_id(Xol_msg_itm_.Id_statistics_header_pages);
byte[] lbl_articles = wiki.Msg_mgr().Val_by_id(Xol_msg_itm_.Id_statistics_articles);
byte[] lbl_pages = wiki.Msg_mgr().Val_by_id(Xol_msg_itm_.Id_statistics_pages);
byte[] lbl_pages_desc = wiki.Msg_mgr().Val_by_id(Xol_msg_itm_.Id_statistics_pages_desc);
Xol_num_mgr num_mgr = wiki.Lang().Num_mgr();
fmtr_page.Bld_bfr_many(bfr, lbl_header_pages, lbl_articles, lbl_pages, lbl_pages_desc , num_mgr.Format_num(wiki.Stats().NumArticles()), num_mgr.Format_num(wiki.Stats().NumPages()));
}
private Bry_fmtr fmtr_page = Bry_fmtr.new_(String_.Concat_lines_nl_skip_last
( ""
, " <tr>"
, " <th colspan=\"2\">~{lbl_header_pages}</th>"
, " </tr>"
, " <tr class=\"mw-statistics-articles\">"
, " <td>~{lbl_articles}</td>"
, " <td class=\"mw-statistics-numbers\" style='text-align:right'>~{page_count_main}</td>"
, " </tr>"
, " <tr class=\"mw-statistics-pages\">"
, " <td>~{lbl_pages}<br /><small class=\"mw-statistic-desc\"> ~{lbl_pages_desc}</small></td>"
, " <td class=\"mw-statistics-numbers\" style='text-align:right'>~{page_count_all}</td>"
, " </tr>"
), "lbl_header_pages", "lbl_articles", "lbl_pages", "lbl_pages_desc", "page_count_main", "page_count_all");
}
class Xop_statistics_stats_ns_grp implements Bry_fmtr_arg {
private Xop_statistics_stats_ns_itm ns_itm_fmtr = new Xop_statistics_stats_ns_itm();
public void Wiki_(Xowe_wiki v) {this.wiki = v; ns_itm_fmtr.Wiki_(v);} private Xowe_wiki wiki;
public void XferAry(Bry_bfr bfr, int idx) {
byte[] lbl_header_ns = wiki.Msg_mgr().Val_by_id(Xol_msg_itm_.Id_statistics_header_ns);
fmtr_ns_grp.Bld_bfr_many(bfr, lbl_header_ns, ns_itm_fmtr);
}
private Bry_fmtr fmtr_ns_grp = Bry_fmtr.new_(String_.Concat_lines_nl_skip_last
( ""
, " <tr>"
, " <th colspan=\"2\">~{lbl_header_ns}</th>"
, " </tr>~{ns_itms}"
), "lbl_header_ns", "ns_itms");
}
class Xop_statistics_stats_ns_itm implements Bry_fmtr_arg {
public void Wiki_(Xowe_wiki v) {this.wiki = v;} private Xowe_wiki wiki;
public void XferAry(Bry_bfr bfr, int idx) {
Xow_ns_mgr ns_mgr = wiki.Ns_mgr();
int ns_len = ns_mgr.Count();
for (int i = 0; i < ns_len; i++) {
Xow_ns ns = ns_mgr.Ids_get_at(i);
if (ns.Is_meta()) continue;
if (ns.Count() == 0) continue;
byte[] ns_name = ns.Id_main() ? wiki.Msg_mgr().Val_by_id(Xol_msg_itm_.Id_ns_blankns) : ns.Name_txt();
fmtr_ns_itm.Bld_bfr_many(bfr, ns_name, wiki.Lang().Num_mgr().Format_num(ns.Count()));
}
}
private Bry_fmtr fmtr_ns_itm = Bry_fmtr.new_(String_.Concat_lines_nl_skip_last
( ""
, " <tr>"
, " <td>~{ns_name}</td>"
, " <td style='text-align:right'>~{ns_count}</td>"
, " </tr>"
), "ns_name", "ns_count");
}
class Xop_statistics_stats_wiki_grp implements Bry_fmtr_arg {
public void Wiki_(Xowe_wiki v) {this.wiki = v;} private Xowe_wiki wiki;
public void XferAry(Bry_bfr bfr, int idx) {
fmtr_wiki.Bld_bfr_many(bfr, wiki.Db_mgr().Tid_name(), wiki.Fsys_mgr().Root_dir().Raw(), Byte_.Xto_str(wiki.Db_mgr().Category_version()), wiki.Maint_mgr().Wiki_dump_date().XtoStr_fmt_iso_8561());
}
private Bry_fmtr fmtr_wiki = Bry_fmtr.new_(String_.Concat_lines_nl_skip_last
( ""
, " <tr>"
, " <th colspan=\"2\">Wiki statistics</th>"
, " </tr>"
, " <tr>"
, " <td>Wiki format</td>"
, " <td>~{wiki_format}</td>"
, " </tr>"
, " <tr>"
, " <td>Wiki location</td>"
, " <td>~{wiki_url}</td>"
, " </tr>"
, " <tr>"
, " <td>Category level</td>"
, " <td>~{ctg_version}</td>"
, " </tr>"
, " <tr>"
, " <td>Last page updated on</td>"
, " <td>~{page_modified_max}</td>"
, " </tr>"
), "wiki_format", "wiki_url", "ctg_version", "page_modified_max");
}

View File

@@ -0,0 +1,55 @@
/*
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.specials.statistics; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*;
import org.junit.*;
public class Xop_statistics_page_tst {
@Before public void init() {fxt.Clear();} private Xop_statistics_page_fxt fxt = new Xop_statistics_page_fxt();
@Test public void Basic() {
fxt.Test_html(String_.Concat_lines_nl_skip_last
( "<div id=\"mw-content-text\">"
, "<table class=\"wikitable mw-statistics-table\">"
, " <tr>"
, " <th colspan=\"2\">Page statistics</th>"
, " </tr>"
, " <tr class=\"mw-statistics-articles\">"
, " <td>Content pages</td>"
, " <td class=\"mw-statistics-numbers\" style='text-align:right'>0</td>"
, " </tr>"
, " <tr class=\"mw-statistics-pages\">"
, " <td>Pages<br /><small class=\"mw-statistic-desc\"> All pages in the wiki, including talk pages, redirects, etc.</small></td>"
, " <td class=\"mw-statistics-numbers\" style='text-align:right'>0</td>"
, " </tr>"
, " <tr>"
, " <th colspan=\"2\">Namespace statistics</th>"
, " </tr>"
, "</table>"
, "</div>"
));
}
}
class Xop_statistics_page_fxt {
public void Clear() {
parser_fxt = new Xop_fxt();
parser_fxt.Reset();
wiki = parser_fxt.Wiki();
special_page = wiki.Special_mgr().Page_statistics();
} private Xop_fxt parser_fxt; private Xop_statistics_page special_page; private Xowe_wiki wiki;
public void Test_html(String expd) {
Tfds.Eq_str_lines(expd, String_.new_u8(special_page.Build_html(wiki)));
}
}

View File

@@ -0,0 +1,107 @@
/*
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.specials.xowa.bookmarks; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*; import gplx.xowa.specials.xowa.*;
import gplx.json.*;
import gplx.xowa.users.data.*; import gplx.xowa.users.bmks.*;
import gplx.xowa.html.xouis.tbls.*; import gplx.xowa.html.xouis.fmtrs.*;
public class Xoui_tbl_itm__bmk implements Xoui_tbl_itm {
private final Xoud_bmk_itm_tbl tbl;
private final Json_wtr json_wtr = new Json_wtr();
private final Xoui_cells_fmtr cells_fmtr = new Xoui_cells_fmtr();
private final Xoui_val_fmtr edit_val_fmtr = Xoui_val_fmtr_.new_edit();
private final Xoui_val_fmtr view_val_fmtr = Xoui_val_fmtr_.new_view();
private final Bry_bfr tmp_bfr = Bry_bfr.new_(255);
public Xoui_tbl_itm__bmk(Xoud_bmk_itm_tbl tbl) {this.tbl = tbl;}
public byte[] Key() {return key;} private static final byte[] key = Bry_.new_a7("bmk");
public Xoui_btn_itm[] View_btns() {return view_btns;}
public Xoui_btn_itm[] Edit_btns() {return edit_btns;}
public Xoui_col_itm[] Cols() {return cols;}
public Xoui_row_itm[] Rows() {return rows;} public void Rows_(Xoui_row_itm[] v) {this.rows = v;} private Xoui_row_itm[] rows;
public void Del(byte[] row_pkey_bry) {
int bmk_id = To_bmk_id(row_pkey_bry);
tbl.Delete(bmk_id);
}
public String Edit(byte[] row_id, byte[] row_pkey_bry) {
return Write_cells(edit_val_fmtr, edit_btns, row_id, Get_row_by_pkey(row_pkey_bry));
}
public String Save(Xow_wiki wiki, byte[] row_id, byte[] row_pkey_bry, Xoui_val_hash hash) {
int bmk_id = To_bmk_id(row_pkey_bry);
byte[] name = hash.Get_val_as_bry_or_fail(Key_name);
byte[] url_bry = hash.Get_val_as_bry_or_fail(Key_url);
Xoa_url_parser url_parser = wiki.App().Utl__url_parser();
Xoa_url url = url_parser.Parse(url_bry);
Xoui_row_itm row_itm = Get_row_by_pkey(row_pkey_bry);
Set_vals(tmp_bfr, row_itm.Vals(), name, url_bry);
tbl.Update(bmk_id, -1, -1, name, url.Wiki_bry(), url_bry, Bry_.Empty);
return Write_cells(view_val_fmtr, view_btns, row_id, row_itm);
}
public void Set_order_adj(byte[] row_pkey, boolean adj_down) {throw Exc_.new_unimplemented();}
private int To_bmk_id(byte[] row_pkey_bry) {return Bry_.Xto_int_or_fail(row_pkey_bry);}
private Xoui_row_itm Get_row_by_pkey(byte[] row_pkey_bry) {
int len = rows.length;
for (int i = 0; i < len; ++i) {
Xoui_row_itm row = rows[i];
if (Bry_.Eq(row.Pkey(), row_pkey_bry)) return row;
}
return null;
}
private String Write_cells(Xoui_val_fmtr val_fmtr, Xoui_btn_itm[] btns, byte[] row_id, Xoui_row_itm row) {
cells_fmtr.Ctor(val_fmtr, btns);
cells_fmtr.Init(row_id, row);
cells_fmtr.XferAry(tmp_bfr, 0);
json_wtr.Doc_bgn();
json_wtr.Kv_bfr("html", tmp_bfr);
json_wtr.Doc_end();
return json_wtr.To_str_and_clear();
}
private static final byte[] Key_name = Bry_.new_a7("name"), Key_url = Bry_.new_a7("url");
private static final Xoui_col_itm[] cols = new Xoui_col_itm[]
{ new Xoui_col_itm(Xoui_col_itm.Type_id_str, 150, "name" , "Name")
, new Xoui_col_itm(Xoui_col_itm.Type_id_str, 350, "url" , "Url")
};
private static final Xoui_btn_itm[] view_btns = new Xoui_btn_itm[]
{ new Xoui_btn_itm("rows__edit" , "edit.png" , "edit")
, new Xoui_btn_itm("rows__delete" , "delete.png" , "delete")
};
private static final Xoui_btn_itm[] edit_btns = new Xoui_btn_itm[]
{ new Xoui_btn_itm("rows__save" , "save.png" , "save")
, new Xoui_btn_itm("rows__cancel" , "cancel.png" , "cancel")
};
private static final Bry_fmtr url_fmtr = Bry_fmtr.new_("<a href='/site/~{url}'>~{url}</a>", "url");
public static Xoui_tbl_itm new_(Xoud_bmk_itm_tbl dom_tbl, Xoud_bmk_itm_row[] dom_rows) {
Xoui_tbl_itm rv = new Xoui_tbl_itm__bmk(dom_tbl);
int len = dom_rows.length;
Xoui_row_itm[] gui_rows = new Xoui_row_itm[len];
Bry_bfr tmp_bfr = Bry_bfr.new_(255);
for (int i = 0; i < len; ++i) {
Xoud_bmk_itm_row dom_row = dom_rows[i];
Xoui_val_itm[] vals = new Xoui_val_itm[2];
Set_vals(tmp_bfr, vals, dom_row.Name(), dom_row.Url());
Xoui_row_itm gui_row = new Xoui_row_itm(rv, Int_.Xto_bry(dom_row.Id()), vals);
gui_rows[i] = gui_row;
}
rv.Rows_(gui_rows);
return rv;
}
private static void Set_vals(Bry_bfr tmp_bfr, Xoui_val_itm[] vals, byte[] name, byte[] url) {
vals[0] = new Xoui_val_itm(name, name);
url_fmtr.Bld_bfr_many(tmp_bfr, url);
vals[1] = new Xoui_val_itm(url, tmp_bfr.Xto_bry_and_clear());
}
}

View File

@@ -0,0 +1,33 @@
/*
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.specials.xowa.bookmarks; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*; import gplx.xowa.specials.xowa.*;
import gplx.core.primitives.*;
import gplx.xowa.html.xouis.tbls.*;
import gplx.xowa.users.data.*; import gplx.xowa.users.bmks.*;
public class Xows_bmk_page implements Xows_page {
public Xows_special_meta Special_meta() {return Xows_special_meta_.Itm__bookmarks;}
public void Special_gen(Xowe_wiki wiki, Xoae_page page, Xoa_url url, Xoa_ttl ttl) {
Xoud_bmk_mgr bmk_mgr = wiki.App().User().User_db_mgr().Bmk_mgr();
page.Html_data().Module_mgr().Itm__xoui().Init(wiki.Appe()).Enabled_y_();
Bry_bfr bfr = wiki.Utl__bfr_mkr().Get_m001();
Xoud_bmk_itm_row[] rows = bmk_mgr.Itms__get(Xoud_bmk_mgr.Owner_root);
Xoui_tbl_itm hui_tbl = Xoui_tbl_itm__bmk.new_(bmk_mgr.Tbl__itm(), rows);
wiki.Html__xoui_tbl_mgr().Write(bfr, hui_tbl);
page.Hdump_data().Body_(bfr.To_bry_and_rls());
}
}

View File

@@ -0,0 +1,27 @@
/*
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.specials.xowa.default_tab; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*; import gplx.xowa.specials.xowa.*;
public class Default_tab_page implements Xows_page {
public Xows_special_meta Special_meta() {return Xows_special_meta_.Itm__default_tab;}
public void Special_gen(Xowe_wiki wiki, Xoae_page page, Xoa_url url, Xoa_ttl ttl) {
page.Data_raw_(Bry_.Empty);
page.Html_data().Custom_html_(Bry_.Empty);
page.Html_data().Custom_name_(Tab_name_bry);
}
public static final byte[] Tab_name_bry = Bry_.new_a7("New Tab");
}

View File

@@ -0,0 +1,73 @@
/*
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.specials.xowa.diags; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*; import gplx.xowa.specials.xowa.*;
import gplx.dbs.*;
import gplx.dbs.engines.mems.*;
class Db_rdr_utl {
public static void Load_and_write(Db_conn conn, String sql, Bry_bfr bfr) {
Write_to_bfr(bfr, Load(conn, sql));
}
public static Mem_qry_set Load_as_qry_set(Db_conn conn, Db_meta_fld_list fld_list, String sql) {
Mem_qry_set qry_set = new Mem_qry_set();
DataRdr rdr = conn.Exec_sql_as_rdr(sql);
try {
int fld_count = rdr.FieldCount();
while (rdr.MoveNextPeer()) {
Mem_row row = new Mem_row();
for (int i = 0; i < fld_count; ++i)
row.Add(fld_list.Get_at(i).Name(), rdr.ReadAt(i));
qry_set.Add(row);
}
}
finally {
rdr.Rls();
}
return qry_set;
}
public static Object[][] Load(Db_conn conn, String sql) {
List_adp list = List_adp_.new_();
DataRdr rdr = conn.Exec_sql_as_rdr(sql);
try {
int fld_count = rdr.FieldCount();
while (rdr.MoveNextPeer()) {
Object[] row = new Object[fld_count];
for (int i = 0; i < fld_count; ++i) {
row[i] = rdr.ReadAt(i);
}
list.Add(row);
}
}
finally {
rdr.Rls();
}
return (Object[][])list.To_ary_and_clear(Object[].class);
}
public static void Write_to_bfr(Bry_bfr bfr, Object[][] rows, int... skip) {
int rows_len = rows.length;
for (int i = 0; i < rows_len; ++i) {
Object[] row = (Object[])rows[i];
int row_len = row.length;
for (int j = 0; j < row_len; ++j) {
if (skip != null && Int_.In(j, skip)) continue;
Object val = row[j];
bfr.Add_obj(val).Add_byte_pipe();
}
bfr.Add_byte_nl();
}
}
}

View File

@@ -0,0 +1,137 @@
/*
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.specials.xowa.diags; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*; import gplx.xowa.specials.xowa.*;
import gplx.fsdb.*; import gplx.fsdb.meta.*;
import gplx.xowa.files.origs.*;
class Xows_cmd__file_check {
private Io_url tmp_dir;
public void Exec(Bry_bfr bfr, Xoa_app app, Xoa_url url, Xoa_url_arg_hash arg_hash) {
byte[] wiki_bry = arg_hash.Get_val_bry_or(Arg_wiki, null); if (wiki_bry == null) {Xoa_app_.Usr_dlg().Warn_many("", "", "special.cmd; no wiki: url=~{0}", url.Raw()); return;}
byte[] file_bry = arg_hash.Get_val_bry_or(Arg_file, null); if (file_bry == null) {Xoa_app_.Usr_dlg().Warn_many("", "", "special.cmd; no file: url=~{0}", url.Raw()); return;}
Xow_wiki wiki = app.Wiki_mgri().Get_by_key_or_make_init_y(wiki_bry);
tmp_dir = wiki.Fsys_mgr().Tmp_dir();
boolean schema_1 = wiki.File__fsdb_core().File__schema_is_1();
Fsdb_db_file atr_main = null;
try {Write_kv(bfr, "machine.op_sys", Op_sys.Cur().Os_name());} catch (Exception e) {bfr.Add_str_u8(Err_.Message_gplx(e));}
try {Write_kv(bfr, "app.version", Xoa_app_.Version);} catch (Exception e) {bfr.Add_str_u8(Err_.Message_gplx(e));}
try {Write_kv(bfr, "cfg_file_retrieve", ((Xoae_app)app).File_mgr().Wmf_mgr().Enabled());} catch (Exception e) {bfr.Add_str_u8(Err_.Message_gplx(e));}
try {Write_kv(bfr, "fsdb.schema_is_1", schema_1);} catch (Exception e) {bfr.Add_str_u8(Err_.Message_gplx(e));}
try {Write_kv(bfr, "fsdb.mnt_file", wiki.File__fsdb_core().File__mnt_file().Url());} catch (Exception e) {bfr.Add_str_u8(Err_.Message_gplx(e));}
try {Write_kv(bfr, "fsdb.abc_file", wiki.File__fsdb_core().File__abc_file__at(Fsm_mnt_mgr.Mnt_idx_main).Url());} catch (Exception e) {bfr.Add_str_u8(Err_.Message_gplx(e));}
try {
atr_main = wiki.File__fsdb_core().File__atr_file__at(Fsm_mnt_mgr.Mnt_idx_main);
Write_kv(bfr, "fsdb.atr_file", atr_main.Url());
} catch (Exception e) {bfr.Add_str_u8(Err_.Message_gplx(e));}
try {Write_kv(bfr, "fsdb.orig", wiki.File__fsdb_core().File__orig_tbl_ary()[0].Conn().Conn_info().Xto_raw());} catch (Exception e) {bfr.Add_str_u8(Err_.Message_gplx(e));}
Fsdb_sql_mkr sql_mkr = schema_1 ? Fsdb_sql_mkr__v1.I : Fsdb_sql_mkr__v2.I;
String sql = "";
try {
Xof_orig_tbl orig_tbl = wiki.File__fsdb_core().File__orig_tbl_ary()[0];
sql = sql_mkr.Orig_by_ttl(file_bry);
Write_sect(bfr, "fsdb.orig.select", sql);
Db_rdr_utl.Load_and_write(orig_tbl.Conn(), sql, bfr);
} catch (Exception e) {bfr.Add_str_u8(Err_.Message_gplx(e));}
Object[][] rows = null;
try {
sql = sql_mkr.Fil_by_ttl(file_bry);
Write_sect(bfr, "fsdb.fil.select", sql);
rows = Db_rdr_utl.Load(atr_main.Conn(), sql);
Db_rdr_utl.Write_to_bfr(bfr, rows);
Write_thms(bfr, file_bry, sql_mkr, wiki.File__mnt_mgr().Mnts__get_main(), atr_main, rows);
} catch (Exception e) {bfr.Add_str_u8(Err_.Message_gplx(e));}
}
private void Write_thms(Bry_bfr bfr, byte[] file_bry, Fsdb_sql_mkr sql_mkr, Fsm_mnt_itm mnt_itm, Fsdb_db_file atr_main, Object[][] rows) {
int rows_len = rows.length;
for (int i = 0; i < rows_len; ++i) {
Object[] row = rows[i];
int file_id = Int_.cast_(row[0]);
String sql = sql_mkr.Thm_by_id(file_id);
Write_sect(bfr, "fsdb.thm.select", sql);
Object[][] thm_rows = Db_rdr_utl.Load(atr_main.Conn(), sql);
Db_rdr_utl.Write_to_bfr(bfr, thm_rows);
Write_bins(bfr, file_bry, sql_mkr, mnt_itm, thm_rows, 0, 6);
Object bin_db_id_obj = row[4];
if (bin_db_id_obj != null) {
Write_bins(bfr, file_bry, sql_mkr, mnt_itm, rows, 0, 4);
}
}
}
private void Write_bins(Bry_bfr bfr, byte[] file_bry, Fsdb_sql_mkr sql_mkr, Fsm_mnt_itm mnt_itm, Object[][] rows, int owner_id_ordinal, int bin_db_id_ordinal) {
int rows_len = rows.length;
for (int i = 0; i < rows_len; ++i) {
Object[] row = rows[i];
int bin_db_id = Int_.cast_(row[bin_db_id_ordinal]); if (bin_db_id == -1) continue;
Fsm_bin_fil bin_db = mnt_itm.Bin_mgr().Dbs__get_at(bin_db_id);
int owner_id = Int_.cast_(row[owner_id_ordinal]);
String sql = sql_mkr.Bin_by_id(owner_id);
Write_sect(bfr, "fsdb.bin.select", sql);
Object[][] bin_rows = Db_rdr_utl.Load(bin_db.Conn(), sql);
Db_rdr_utl.Write_to_bfr(bfr, bin_rows, 4);
Export_bins(bfr, file_bry, bin_rows, 0, 4);
}
}
private void Export_bins(Bry_bfr bfr, byte[] file_bry, Object[][] rows, int owner_id_ordinal, int bin_data_ordinal) {
int rows_len = rows.length;
Bry_bfr tmp_bfr = Bry_bfr.new_();
for (int i = 0; i < rows_len; ++i) {
Object[] row = rows[i];
int owner_id = Int_.cast_(row[owner_id_ordinal]);
byte[] bin_data = (byte[])row[bin_data_ordinal];
file_bry = gplx.xowa.files.repos.Xof_repo_itm_.Ttl_invalid_fsys_chars(tmp_bfr, file_bry);
Io_url bin_url = tmp_dir.GenSubFil(String_.new_u8(file_bry));
bin_url = tmp_dir.GenSubFil(bin_url.NameOnly() + "_" + Int_.Xto_str(owner_id) + bin_url.Ext());
Write_kv(bfr, "fsdb.bin.export", bin_url.Raw());
Write_kv(bfr, "fsdb.bin.len", bin_data.length);
Io_mgr.I.SaveFilBry(bin_url, bin_data);
}
}
private static void Write_kv(Bry_bfr bfr, String key, Object val) {
bfr.Add_str_u8(key);
bfr.Add_str_a7(" = ");
bfr.Add_obj(val);
bfr.Add_byte_nl();
}
private static void Write_sect(Bry_bfr bfr, String key, Object val) {
bfr.Add_byte_nl();
bfr.Add_str_u8("------------------------------------------------------").Add_byte_nl();
bfr.Add_str_u8(key).Add_str_a7(": ").Add_obj(val).Add_byte_nl();
bfr.Add_str_u8("------------------------------------------------------").Add_byte_nl();
}
private static final byte[] Arg_wiki = Bry_.new_a7("wiki"), Arg_file = Bry_.new_a7("file");
public static final Xows_cmd__file_check I = new Xows_cmd__file_check(); Xows_cmd__file_check() {}
}
interface Fsdb_sql_mkr {
String Orig_by_ttl(byte[] ttl);
String Fil_by_ttl(byte[] ttl);
String Thm_by_id(int id);
String Bin_by_id(int id);
}
abstract class Fsdb_sql_mkr__base {
public String Fil_by_ttl(byte[] ttl) {return String_.Format("SELECT * FROM fsdb_fil WHERE fil_name = '{0}';", ttl);}
public String Bin_by_id(int id) {return String_.Format("SELECT * FROM fsdb_bin WHERE bin_owner_id = {0};", id);}
}
class Fsdb_sql_mkr__v1 extends Fsdb_sql_mkr__base implements Fsdb_sql_mkr {
public String Orig_by_ttl(byte[] ttl) {return String_.Format("SELECT * FROM wiki_orig WHERE orig_ttl = '{0}';", ttl);}
public String Thm_by_id(int id) {return String_.Format("SELECT * FROM fsdb_xtn_thm WHERE thm_owner_id = {0};", id);}
public static final Fsdb_sql_mkr I = new Fsdb_sql_mkr__v1(); Fsdb_sql_mkr__v1() {}
}
class Fsdb_sql_mkr__v2 extends Fsdb_sql_mkr__base implements Fsdb_sql_mkr {
public String Orig_by_ttl(byte[] ttl) {return String_.Format("SELECT * FROM orig_reg WHERE orig_ttl = '{0}';", ttl);}
public String Thm_by_id(int id) {return String_.Format("SELECT * FROM fsdb_thm WHERE thm_owner_id = {0};", id);}
public static final Fsdb_sql_mkr I = new Fsdb_sql_mkr__v2(); Fsdb_sql_mkr__v2() {}
}

View File

@@ -0,0 +1,59 @@
/*
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.specials.xowa.diags; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*; import gplx.xowa.specials.xowa.*;
import gplx.ios.*;
import gplx.fsdb.meta.*;
class Xows_cmd__fs_check {
public void Exec(Bry_bfr bfr, Xoa_app app, Xoa_url url, Xoa_url_arg_hash arg_hash) {
byte[] dir_bry = arg_hash.Get_val_bry_or(Arg_dir, null);
if (dir_bry != null) {
Write_dir(bfr, Io_url_.new_dir_(String_.new_u8(dir_bry)));
return;
}
byte[] wiki_bry = arg_hash.Get_val_bry_or(Arg_wiki, null); if (wiki_bry == null) {Xoa_app_.Usr_dlg().Warn_many("", "", "special.cmd; no wiki: url=~{0}", url.Raw()); return;}
Xow_wiki wiki = app.Wiki_mgri().Get_by_key_or_make_init_y(wiki_bry);
Io_url wiki_dir = wiki.Fsys_mgr().Root_dir();
Io_url file_dir = wiki.Fsys_mgr().File_dir();
Write_dir(bfr, wiki_dir);
Write_dir(bfr, file_dir);
Write_dir(bfr, file_dir.GenSubDir(Fsm_mnt_tbl.Mnt_name_main));
Write_dir(bfr, file_dir.GenSubDir(Fsm_mnt_tbl.Mnt_name_user));
Write_dir(bfr, file_dir.GenSubDir("fsdb.update_00"));
}
private void Write_dir(Bry_bfr bfr, Io_url dir_url) {
bfr.Add_byte_nl().Add_str_a7("scanning: ").Add_str_u8(dir_url.Raw()).Add_byte_nl();
if (!Io_mgr.I.ExistsDir(dir_url)) return;
IoItmDir dir_itm = Io_mgr.I.QueryDir_args(dir_url).Recur_(false).DirInclude_(true).ExecAsDir();
IoItmList sub_itms = dir_itm.SubDirs(); int len = sub_itms.Count();
for (int i = 0; i < len; ++i) {
try {
IoItmDir sub_itm = (IoItmDir)sub_itms.Get_at(i);
bfr.Add_str_a7("dir").Add_byte_pipe().Add_str_u8(sub_itm.Name()).Add_byte_nl();
} catch (Exception e) {bfr.Add_str_u8(Err_.Message_gplx(e));}
}
sub_itms = dir_itm.SubFils(); len = sub_itms.Count();
for (int i = 0; i < len; ++i) {
try {
IoItmFil sub_itm = (IoItmFil)sub_itms.Get_at(i);
bfr.Add_str_a7("fil").Add_byte_pipe().Add_str_u8(sub_itm.Name()).Add_byte_pipe().Add_long_variable(sub_itm.Size()).Add_byte_pipe().Add_dte(sub_itm.ModifiedTime()).Add_byte_nl();
} catch (Exception e) {bfr.Add_str_u8(Err_.Message_gplx(e));}
}
}
public static final Xows_cmd__fs_check I = new Xows_cmd__fs_check(); Xows_cmd__fs_check() {}
private static final byte[] Arg_wiki = Bry_.new_a7("wiki"), Arg_dir = Bry_.new_a7("dir");
}

View File

@@ -0,0 +1,51 @@
/*
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.specials.xowa.diags; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*; import gplx.xowa.specials.xowa.*;
import gplx.ios.*; import gplx.core.primitives.*;
import gplx.dbs.*;
import gplx.fsdb.meta.*;
class Xows_cmd__sql_dump {
public void Exec(Bry_bfr bfr, Xoa_app app, Xoa_url url, Xoa_url_arg_hash arg_hash) {
Db_conn conn = null;
byte[] sql_bry = arg_hash.Get_val_bry_or(Arg_sql, null); if (sql_bry == null) {Xoa_app_.Usr_dlg().Warn_many("", "", "special.cmd; no sql: url=~{0}", url.Raw()); return;}
byte[] wiki_bry = arg_hash.Get_val_bry_or(Arg_wiki, null);
if (wiki_bry == null) {
byte[] db_file_bry = arg_hash.Get_val_bry_or(Arg_db_file, null); if (db_file_bry == null) {Xoa_app_.Usr_dlg().Warn_many("", "", "special.cmd; no db_type: url=~{0}", url.Raw()); return;}
conn = Db_conn_bldr.I.Get(Io_url_.new_fil_(String_.new_u8(db_file_bry)));
}
else {
byte[] db_type_bry = arg_hash.Get_val_bry_or(Arg_db_type, null); if (db_type_bry == null) {Xoa_app_.Usr_dlg().Warn_many("", "", "special.cmd; no db_type: url=~{0}", url.Raw()); return;}
Xow_wiki wiki = app.Wiki_mgri().Get_by_key_or_make_init_y(wiki_bry);
Byte_obj_val db_type_val = (Byte_obj_val)db_type_hash.Get_by_bry(db_type_bry); if (db_type_val == null) {Xoa_app_.Usr_dlg().Warn_many("", "", "special.cmd; bad db_type: url=~{0}", url.Raw()); return;}
switch (db_type_val.Val()) {
case Db_type_wiki_core: conn = wiki.Data__core_mgr().Db__core().Conn(); break;
case Db_type_fsdb_abc: conn = wiki.File__fsdb_core().File__abc_file__at(Fsm_mnt_mgr.Mnt_idx_main).Conn(); break;
case Db_type_fsdb_atr: conn = wiki.File__fsdb_core().File__atr_file__at(Fsm_mnt_mgr.Mnt_idx_main).Conn(); break;
}
}
Db_rdr_utl.Load_and_write(conn, String_.new_u8(sql_bry), bfr);
}
public static final Xows_cmd__sql_dump I = new Xows_cmd__sql_dump(); Xows_cmd__sql_dump() {}
private static final byte[] Arg_wiki = Bry_.new_a7("wiki"), Arg_db_file = Bry_.new_a7("db_file"), Arg_db_type = Bry_.new_a7("db_type"), Arg_sql = Bry_.new_a7("sql");
private static final byte Db_type_fsdb_abc = 1, Db_type_fsdb_atr = 2, Db_type_wiki_core = 3;
private static final Hash_adp_bry db_type_hash = Hash_adp_bry.cs_()
.Add_str_byte("fsdb.abc" , Db_type_fsdb_abc)
.Add_str_byte("fsdb.atr" , Db_type_fsdb_atr)
.Add_str_byte("wiki.core" , Db_type_wiki_core)
;
}

View File

@@ -0,0 +1,44 @@
/*
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.specials.xowa.diags; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*; import gplx.xowa.specials.xowa.*;
import gplx.core.primitives.*;
public class Xows_diag_page implements Xows_page {
private Xoa_url_arg_hash arg_hash = new Xoa_url_arg_hash();
public Xows_special_meta Special_meta() {return Xows_special_meta_.Itm__diag;}
public void Special_gen(Xowe_wiki wiki, Xoae_page page, Xoa_url url, Xoa_ttl ttl) {
arg_hash.Load(url);
byte[] cmd_type_bry = arg_hash.Get_val_bry_or(Arg_type, null); if (cmd_type_bry == null) {Xoa_app_.Usr_dlg().Warn_many("", "", "special.cmd; no type: url=~{0}", url.Raw()); return;}
Byte_obj_val cmd_type_val = (Byte_obj_val)type_hash.Get_by_bry(cmd_type_bry); if (cmd_type_val == null) {Xoa_app_.Usr_dlg().Warn_many("", "", "special.cmd; bad type: url=~{0}", url.Raw()); return;}
Bry_bfr bfr = wiki.Utl__bfr_mkr().Get_m001();
bfr.Add_str_a7("<pre>\n");
switch (cmd_type_val.Val()) {
case Type_file_check: Xows_cmd__file_check.I.Exec(bfr, wiki.App(), url, arg_hash); break;
case Type_fs_check: Xows_cmd__fs_check.I.Exec(bfr, wiki.App(), url, arg_hash); break;
case Type_sql_dump: Xows_cmd__sql_dump.I.Exec(bfr, wiki.App(), url, arg_hash); break;
}
bfr.Add_str_a7("</pre>\n");
page.Data_raw_(bfr.Xto_bry_and_clear());
}
private static final byte[] Arg_type = Bry_.new_a7("type");
private static final byte Type_file_check = 1, Type_fs_check = 2, Type_sql_dump = 3;
private static final Hash_adp_bry type_hash = Hash_adp_bry.cs_()
.Add_str_byte("file.check" , Type_file_check)
.Add_str_byte("fs.check" , Type_fs_check)
.Add_str_byte("sql.dump" , Type_sql_dump)
;
}

View File

@@ -0,0 +1,72 @@
/*
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.specials.xowa.file_browsers; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*; import gplx.xowa.specials.xowa.*;
import gplx.core.primitives.*;
class Xoa_url_arg_mgr {
private final Hash_adp_bry hash = Hash_adp_bry.cs_();
private final Xoa_url_enum_mgr enm_mgr;
public Xoa_url_arg_mgr(Xoa_url_enum_mgr enm_mgr) {this.enm_mgr = enm_mgr;}
public void Init(Gfo_url_arg[] args) {
hash.Clear();
int len = args.length;
for (int i = 0; i < len; ++i) {
Gfo_url_arg arg = args[i];
hash.Add_bry_obj(arg.Key_bry(), arg);
}
}
public int Read_enm_or_neg1(byte[] key) {
Xoa_url_enum_itm enm = enm_mgr.Get(key); if (enm == null) return -1;
Gfo_url_arg arg = (Gfo_url_arg)hash.Get_by_bry(key); if (arg == null) return -1;
return enm.Get_as_int_or(arg.Val_bry(), -1);
}
public byte[] Read_bry_or_empty(byte[] key) {return Read_bry_or(key, Bry_.Empty);}
public byte[] Read_bry_or_null(byte[] key) {return Read_bry_or(key, null);}
public byte[] Read_bry_or(byte[] key, byte[] or) {
Gfo_url_arg arg = (Gfo_url_arg)hash.Get_by_bry(key);
return arg == null ? or : arg.Val_bry();
}
public String Read_str_or_null(String key) {return Read_str_or_null(Bry_.new_u8(key));}
public String Read_str_or_null(byte[] key) {
Gfo_url_arg arg = (Gfo_url_arg)hash.Get_by_bry(key);
return arg == null ? null : String_.new_u8(arg.Val_bry());
}
}
class Xoa_url_enum_mgr {
private final Hash_adp_bry hash = Hash_adp_bry.cs_();
public Xoa_url_enum_mgr(Xoa_url_enum_itm... ary) {
int len = ary.length;
for (int i = 0; i < len; ++i) {
Xoa_url_enum_itm itm = ary[i];
hash.Add_bry_obj(itm.Key(), itm);
}
}
public Xoa_url_enum_itm Get(byte[] key) {return (Xoa_url_enum_itm)hash.Get_by_bry(key);}
}
class Xoa_url_enum_itm {
private final Hash_adp_bry hash = Hash_adp_bry.cs_();
public Xoa_url_enum_itm(byte[] key) {this.key = key;}
public byte[] Key() {return key;} private final byte[] key;
public Xoa_url_enum_itm Add(String key, int val) {
hash.Add_bry_obj(Bry_.new_u8(key), Int_obj_val.new_(val));
return this;
}
public int Get_as_int_or(byte[] val, int or) {
Int_obj_val rv = (Int_obj_val)hash.Get_by_bry(val);
return rv == null ? or : rv.Val();
}
}

View File

@@ -0,0 +1,216 @@
/*
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.specials.xowa.file_browsers; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*; import gplx.xowa.specials.xowa.*;
import gplx.ios.*; import gplx.xowa2.apps.*; import gplx.xowa2.wikis.*;
interface Xosp_fbrow_cmd {
Xosp_fbrow_cmd Make_new();
Xosp_fbrow_rslt Write_html(Xoa_url_arg_mgr arg_mgr, GfoInvkAble select_invkable);
}
abstract class Xosp_fbrow_cmd__base implements Xosp_fbrow_cmd {
public abstract Xosp_fbrow_cmd Make_new();
public Xosp_fbrow_rslt Write_html(Xoa_url_arg_mgr arg_mgr, GfoInvkAble select_invkable) {
// app.I18n_mgr_Get_txt_many("xowa.specials.file_browsers.errs.unknown_path", url.Raw());
Url_encoder encoder = Url_encoder.new_html_href_mw_();
Xosp_fbrow_html html_wtr = new Xosp_fbrow_html(encoder);
Bry_bfr tmp_bfr = Bry_bfr.reset_(255);
String selected_str = arg_mgr.Read_str_or_null("selected");
if (selected_str == null) {
String path_str = arg_mgr.Read_str_or_null("path"); if (path_str == null) return Xosp_fbrow_rslt.err_("url has unknown path");
// if (Op_sys.Cur().Tid_is_wnt()) path_str = String_.Replace(path_str, "/", "\\");
Io_url path_url = Io_url_.new_any_(path_str);
IoItmDir dir = Io_mgr.I.QueryDir_args(path_url).DirInclude_(true).ExecAsDir();
dir.SubDirs().Sort(); dir.SubFils().Sort();
Xosp_fbrow_data_dir dir_itm = Xosp_fbrow_data_dir.new_(dir);
Process_itms(dir_itm);
String url_enc = String_.Replace(path_url.Raw(), "\\", "\\\\");
byte[] cmd_src = this.Cmd_src();
byte[] cmd_row = Html_body_cmd_row.Bld_bry_many(tmp_bfr, url_enc, cmd_src, this.Cmd_gui());
html_wtr.Write(tmp_bfr, cmd_src, cmd_row, dir_itm);
return new Xosp_fbrow_rslt(Html_head_default, tmp_bfr.Xto_bry_and_clear());
}
else
return Write_html_selected(arg_mgr, selected_str, select_invkable);
}
private void Process_itms(Xosp_fbrow_data_dir dir_itm) {
int len = dir_itm.Count();
for (int i = 0; i < len; ++i) {
Xosp_fbrow_data_sub itm = dir_itm.Get_at(i);
this.Process_itm(itm);
}
}
protected abstract byte[] Cmd_src();
protected abstract String Cmd_gui();
protected abstract Xosp_fbrow_rslt Write_html_selected(Xoa_url_arg_mgr arg_mgr, String selected, GfoInvkAble select_invkable);
protected abstract void Process_itm(Xosp_fbrow_data_sub itm);
private static final byte[] Html_head_default = Bry_.new_a7(String_.Concat_lines_nl_skip_last
( " <style type='text/css'>"
, " .fsys_tb {border: 1px solid #AAAAAA;}"
, " .fsys_tb td {padding: 0 1em 0 1em;}"
, " .fsys_td_size {text-align:right;}"
, " </style>"
, " <script type='text/javascript'>"
, " function get_selected_chk(url_base, chk_prefix) {"
, " var list = document.getElementsByTagName('input');"
, " var list_len = list.length;"
, " var selected = '';"
, " var chk_prefix_len = chk_prefix.length;"
, " for (var i = 0; i < list_len; ++i) {"
, " var chk = list[i];"
, " if (chk.id.indexOf(chk_prefix) == 0 && chk.checked == true) {"
, " selected = selected + chk.id.substring(chk_prefix_len) + ';';"
, " }"
, " }"
, " window.location.href = url_base + selected;"
, " }"
, " </script>"
))
;
private static final Bry_fmtr Html_body_cmd_row = Bry_fmtr.new_(String_.Concat_lines_nl_skip_last
( ""
, " <tr>"
, " <td>"
, " <table width='100%'>"
, " <tr>"
, " <td align='left'><a href='javascript:get_selected_chk(\"/wiki/Special:XowaFileBrowser?cmd=~{cmd_src}&amp;path=~{url_enc}&amp;selected=\", \"chk_\");'>~{cmd_gui}</a>"
, " </td>"
, " </tr>"
, " </table>"
, " </td>"
, " </tr>"
), "url_enc", "cmd_src", "cmd_gui")
;
}
class Xosp_fbrow_html implements Bry_fmtr_arg {
private final Url_encoder encoder; private Xosp_fbrow_data_dir dir; private byte[] cmd_src;
public Xosp_fbrow_html(Url_encoder encoder) {this.encoder = encoder;}
public void Write(Bry_bfr bfr, byte[] cmd_src, byte[] cmd_row, Xosp_fbrow_data_dir dir) {
this.dir = dir; this.cmd_src = cmd_src;
// app.I18n_mgr_Get_txt_none("xowa.specials.file_browsers.html.hdr.name");
// i18n.Get_txt_none("html.hdrs.name");
fmtr_hdr.Bld_bfr_many(bfr
, cmd_src, cmd_row
, "name", "size", "modified"
, dir.Url().Raw(), String_.Replace(dir.Url().Raw(), "\\", "\\\\"), encoder.Encode_str(dir.Url().OwnerDir().Raw())
, this
);
}
public void XferAry(Bry_bfr bfr, int idx) {
int len = dir.Count();
for (int i = 0; i < len; ++i) {
Xosp_fbrow_data_sub itm = (Xosp_fbrow_data_sub)dir.Get_at(i);
String selected_html = itm.Selectable() ? ("<input type='checkbox' id='chk_" + itm.Url().NameAndExt_noDirSpr() + "'/>") : "&nbsp;&nbsp;&nbsp;";
if (itm.Tid_is_dir())
fmtr_row_dir.Bld_bfr_many(bfr, selected_html, encoder.Encode_str(itm.Url().Raw()), itm.Url().NameOnly(), cmd_src);
else {
fmtr_row_fil.Bld_bfr_many(bfr, selected_html, encoder.Encode_str(itm.Url().Raw()), itm.Url().NameAndExt()
, Io_size_.To_str(itm.Size(), 1, "#,###", " ", Bool_.Y), itm.Modified().XtoStr_fmt_yyyy_MM_dd_HH_mm_ss());
}
}
}
private static Bry_fmtr
fmtr_hdr = Bry_fmtr.new_(String_.Concat_lines_nl_skip_last
( "<table>~{cmd_row}"
, " <tr>"
, " <td style='width:100%;border:1px solid #AAAAAA;'>~{dir_url_raw}"
, " </td>"
, " </tr>"
, " <tr>"
, " <td>"
, " <table class='sortable fsys_tb'>"
, " <tr>"
, " <th><!--selected--></th>"
, " <th>~{hdr_name}</th>"
, " <th>~{hdr_size}</th>"
, " <th>~{hdr_modified}</th>"
, " </tr>"
, " <tr>"
, " <td></td>"
, " <td><a href='/wiki/Special:XowaFileBrowser?cmd=~{cmd_src}&amp;path=~{owner_url_enc}'>..</a></td>"
, " <td></td>"
, " <td></td>"
, " </tr>~{itms}"
, " </table>"
, " </td>"
, " </tr>"
, "</table>"
), "cmd_src", "cmd_row", "hdr_name", "hdr_size", "hdr_modified", "dir_url_raw", "dir_url_enc", "owner_url_enc", "itms"
)
, fmtr_row_dir = Bry_fmtr.new_(String_.Concat_lines_nl_skip_last
( ""
, " <tr>"
, " <td>~{selected_html}</td>"
, " <td><a href='/wiki/Special:XowaFileBrowser?cmd=~{cmd_src}&amp;path=~{path_enc}'>~{name}</a></td>"
, " <td></td>"
, " <td></td>"
, " </tr>"
), "selected_html", "path_enc", "name", "cmd_src"
)
, fmtr_row_fil = Bry_fmtr.new_(String_.Concat_lines_nl_skip_last
( ""
, " <tr>"
, " <td>~{selected_html}</td>"
, " <td>~{name}</td>"
, " <td class='fsys_td_size'>~{size}</td>"
, " <td>~{modified}</td>"
, " </tr>"
), "selected_html", "path_enc", "name", "size", "modified"
);
}
class Xosp_fbrow_cmd__err implements Xosp_fbrow_cmd {
public Xosp_fbrow_cmd Make_new() {return this;}
public Xosp_fbrow_rslt Write_html(Xoa_url_arg_mgr arg_mgr, GfoInvkAble select_invkable) {return Rslt;}
private static final Xosp_fbrow_rslt Rslt = new Xosp_fbrow_rslt(Bry_.Empty, Bry_.new_u8("url has unknown cmd"));
public static final Xosp_fbrow_cmd__err I = new Xosp_fbrow_cmd__err(); Xosp_fbrow_cmd__err() {}
}
class Xosp_fbrow_cmd__wiki_add extends Xosp_fbrow_cmd__base {
@Override protected byte[] Cmd_src() {return Regy_key;}
@Override protected String Cmd_gui() {return "import";}
@Override public Xosp_fbrow_cmd Make_new() {return new Xosp_fbrow_cmd__wiki_add();}
@Override protected void Process_itm(Xosp_fbrow_data_sub itm) {
byte[] url_bry = itm.Url().RawBry();
if (!Bry_.Has_at_end(url_bry, Ext_xowa)) itm.Selectable_(false);
}
@Override protected Xosp_fbrow_rslt Write_html_selected(Xoa_url_arg_mgr arg_mgr, String selected, GfoInvkAble select_invkable) {
String[] wikis = String_.Split(selected, ";");
String path_str = arg_mgr.Read_str_or_null("path");
Xowv_wiki wiki = (Xowv_wiki)GfoInvkAble_.InvkCmd_val(select_invkable, Xoav_wiki_mgr.Invk_import_by_fil, path_str + wikis[0]);
Bry_bfr bfr = Bry_bfr.reset_(255);
done_fmtr.Bld_bfr_many(bfr, wiki.Domain_str());
return new Xosp_fbrow_rslt(Bry_.Empty, bfr.Xto_bry_and_clear());
}
private static final Bry_fmtr done_fmtr = Bry_fmtr.new_(String_.Concat_lines_nl_skip_last
( "<a href='/site/~{domain}/wiki/Earth'>~{domain} Main Page</a>"
)
, "domain");
private static final byte[] Ext_xowa = Bry_.new_a7(".xowa");
public static final byte[] Regy_key = Bry_.new_a7("xowa.wiki.add");
public static final Xosp_fbrow_cmd__wiki_add I = new Xosp_fbrow_cmd__wiki_add();
}
class Xosp_fbrow_cmd__root_set extends Xosp_fbrow_cmd__base {
@Override protected byte[] Cmd_src() {return Regy_key;}
@Override protected String Cmd_gui() {return "set root dir";}
@Override public Xosp_fbrow_cmd Make_new() {return new Xosp_fbrow_cmd__root_set();}
@Override protected void Process_itm(Xosp_fbrow_data_sub itm) {
if (itm.Url().Type_fil()) itm.Selectable_(false);
}
@Override protected Xosp_fbrow_rslt Write_html_selected(Xoa_url_arg_mgr arg_mgr, String selected, GfoInvkAble select_invkable) {
return new Xosp_fbrow_rslt(Bry_.Empty, Bry_.new_u8(selected));
}
public static final byte[] Regy_key = Bry_.new_a7("xowa.fsys.root_");
public static final Xosp_fbrow_cmd__root_set I = new Xosp_fbrow_cmd__root_set();
}

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.specials.xowa.file_browsers; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*; import gplx.xowa.specials.xowa.*;
import gplx.ios.*;
class Xosp_fbrow_data_dir {
private final Ordered_hash hash = Ordered_hash_.new_();
public Xosp_fbrow_data_dir(Io_url url) {this.url = url;}
public Io_url Url() {return url;} private final Io_url url;
public int Count() {return hash.Count();}
public Xosp_fbrow_data_sub Get_at(int i) {return (Xosp_fbrow_data_sub)hash.Get_at(i);}
public void Add(Xosp_fbrow_data_sub itm) {hash.Add(itm.Url().NameAndExt(), itm);}
public static Xosp_fbrow_data_dir new_(IoItmDir owner) {
Xosp_fbrow_data_dir rv = new Xosp_fbrow_data_dir(owner.Url());
new_subs(rv, Bool_.Y, owner.SubDirs());
new_subs(rv, Bool_.N, owner.SubFils());
return rv;
}
private static void new_subs(Xosp_fbrow_data_dir owner, boolean dir, IoItmList itms) {
int len = itms.Count();
for (int i = 0; i < len; ++i) {
IoItm_base src = (IoItm_base)itms.Get_at(i);
Io_url src_url = src.Url();
if (String_.Has_at_bgn(src_url.NameAndExt(), ".")) continue; // ignore hidden "." files; NameAndExt() b/c ".ext" has NameOnly of ""; EX: "/dir/.hidden"
Xosp_fbrow_data_sub trg = null;
if (dir)
trg = new Xosp_fbrow_data_sub(src_url, -1, null);
else {
IoItmFil fil = (IoItmFil)src;
trg = new Xosp_fbrow_data_sub(src_url, fil.Size(), fil.ModifiedTime());
}
owner.Add(trg);
}
}
}
class Xosp_fbrow_data_sub {
public Xosp_fbrow_data_sub(Io_url url, long size, DateAdp modified) {
this.url = url; this.size = size; this.modified = modified;
this.tid_is_dir = url.Type_dir();
}
public boolean Selectable() {return selectable;} public void Selectable_(boolean v) {selectable = v;} private boolean selectable = true;
public String Selectable_style() {return selectable ? "" : "none";}
public boolean Tid_is_dir() {return tid_is_dir;} private final boolean tid_is_dir;
public Io_url Url() {return url;} private final Io_url url;
public long Size() {return size;} private final long size;
public DateAdp Modified() {return modified;} private final DateAdp modified;
}

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.specials.xowa.file_browsers; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*; import gplx.xowa.specials.xowa.*;
public class Xosp_fbrow_rslt {
public Xosp_fbrow_rslt(byte[] html_head, byte[] html_body) {this.html_head = html_head; this.html_body = html_body;}
public byte[] Html_head() {return html_head;} private final byte[] html_head;
public byte[] Html_body() {return html_body;} private final byte[] html_body;
public static Xosp_fbrow_rslt err_(String msg) {return new Xosp_fbrow_rslt(Bry_.Empty, Bry_.new_u8(msg));}
}

View File

@@ -0,0 +1,40 @@
/*
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.specials.xowa.file_browsers; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*; import gplx.xowa.specials.xowa.*;
import gplx.xowa.specials.*; import gplx.ios.*;
public class Xosp_fbrow_special implements Xows_page {
private static final Xoa_url_arg_mgr url_args = new Xoa_url_arg_mgr(null);
public Xows_special_meta Special_meta() {return Xows_special_meta_.Itm__file_browser;}
public void Special_gen(Xowe_wiki wiki, Xoae_page page, Xoa_url url, Xoa_ttl ttl) {
Xosp_fbrow_rslt rslt = Gen(url.Args(), GfoInvkAble_.Null);
page.Html_data().Html_restricted_n_();
page.Html_data().Custom_head_end_concat(rslt.Html_head());
page.Data_raw_(rslt.Html_body());
}
public static Xosp_fbrow_rslt Gen(Gfo_url_arg[] args, GfoInvkAble select_invkable) {
url_args.Init(args);
byte[] cmd_bry = url_args.Read_bry_or_empty(Arg_cmd);
Xosp_fbrow_cmd cmd = (Xosp_fbrow_cmd)cmd_regy.Get_by_bry(cmd_bry); if (cmd == null) cmd = Xosp_fbrow_cmd__err.I;
return cmd.Make_new().Write_html(url_args, select_invkable);
}
private static final byte[] Arg_cmd = Bry_.new_a7("cmd");
private static final Hash_adp_bry cmd_regy = Hash_adp_bry.cs_()
.Add_bry_obj(Xosp_fbrow_cmd__wiki_add.Regy_key, Xosp_fbrow_cmd__wiki_add.I)
.Add_bry_obj(Xosp_fbrow_cmd__root_set.Regy_key, Xosp_fbrow_cmd__root_set.I)
;
}

View File

@@ -0,0 +1,145 @@
/*
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.specials.xowa.file_browsers; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*; import gplx.xowa.specials.xowa.*;
import org.junit.*; import gplx.ios.*;
public class Xosp_fbrow_special_tst {
@Before public void init() {fxt.Clear();} private Xosp_fbrow_special_fxt fxt = new Xosp_fbrow_special_fxt();
@Test public void Basic() {
fxt.Init_dir(fxt.Make_dir());
fxt.Test_nav("mem/root/dir/", String_.Concat_lines_nl_skip_last
( "<table>"
, " <tr>"
, " <td>"
, " <table width='100%'>"
, " <tr>"
, " <td align='left'><a href='javascript:get_selected_chk(\"/wiki/Special:XowaFileBrowser?cmd=xowa.wiki.add&amp;path=mem/root/dir/&amp;selected=\", \"chk_\");'>import</a>"
, " </td>"
, " </tr>"
, " </table>"
, " </td>"
, " </tr>"
, " <tr>"
, " <td style='width:100%;border:1px solid #AAAAAA;'>mem/root/dir/"
, " </td>"
, " </tr>"
, " <tr>"
, " <td>"
, " <table class='sortable fsys_tb'>"
, " <tr>"
, " <th><!--selected--></th>"
, " <th>name</th>"
, " <th>size</th>"
, " <th>modified</th>"
, " </tr>"
, " <tr>"
, " <td></td>"
, " <td><a href='/wiki/Special:XowaFileBrowser?cmd=xowa.wiki.add&amp;path=mem/root/'>..</a></td>"
, " <td></td>"
, " <td></td>"
, " </tr>"
, " <tr>"
, " <td>&nbsp;&nbsp;&nbsp;</td>"
, " <td><a href='/wiki/Special:XowaFileBrowser?cmd=xowa.wiki.add&amp;path=mem/root/dir/a/'>a</a></td>"
, " <td></td>"
, " <td></td>"
, " </tr>"
, " <tr>"
, " <td>&nbsp;&nbsp;&nbsp;</td>"
, " <td><a href='/wiki/Special:XowaFileBrowser?cmd=xowa.wiki.add&amp;path=mem/root/dir/b/'>b</a></td>"
, " <td></td>"
, " <td></td>"
, " </tr>"
, " <tr>"
, " <td>&nbsp;&nbsp;&nbsp;</td>"
, " <td>1.txt</td>"
, " <td class='fsys_td_size'>1 KB</td>"
, " <td>2001-01-01 00:00:00</td>"
, " </tr>"
, " <tr>"
, " <td>&nbsp;&nbsp;&nbsp;</td>"
, " <td>2.txt</td>"
, " <td class='fsys_td_size'>1 KB</td>"
, " <td>2004-01-02 00:00:00</td>"
, " </tr>"
, " <tr>"
, " <td><input type='checkbox' id='chk_3.xowa'/></td>"
, " <td>3.xowa</td>"
, " <td class='fsys_td_size'>1 KB</td>"
, " <td>2004-01-03 00:00:00</td>"
, " </tr>"
, " </table>"
, " </td>"
, " </tr>"
, "</table>"
));
}
}
class Io_itm_bldr {
public IoItmDir Root(Io_url url, IoItm_base... subs) {
IoItmDir rv = IoItmDir_.top_(url);
Init_dir(rv, url.NameAndExt(), subs);
return rv;
}
public IoItmDir Dir(String name, IoItm_base... subs) {
IoItmDir rv = IoItmDir_.sub_(name);
Init_dir(rv, name, subs);
return rv;
}
public IoItmFil Fil(String name, int size, String date) {return IoItmFil_.sub_(name, size, DateAdp_.parse_iso8561(date));}
private void Init_dir(IoItmDir rv, String name, IoItm_base... subs) {
int len = subs.length;
for (int i = 0; i < len; ++i) {
IoItm_base sub = subs[i];
IoItmList sub_list = sub.Type_fil() ? rv.SubFils() : rv.SubDirs();
sub.OwnerDir_set(rv);
sub_list.Add(sub);
}
}
}
class Xosp_fbrow_special_fxt {
private Io_itm_bldr bldr = new Io_itm_bldr();
public void Clear() {}
public IoItmDir Make_dir() {
return bldr.Root(Io_url_.mem_dir_("mem/root/dir/")
, bldr.Dir("a"
, bldr.Fil("a1.txt", 11, "2011-01-01")
, bldr.Fil("a2.txt", 12, "2011-01-02")
, bldr.Fil("a3.txt", 13, "2011-01-03")
)
, bldr.Dir("b"
, bldr.Fil("b1.txt", 21, "2011-02-01")
, bldr.Fil("b2.txt", 22, "2011-02-02")
, bldr.Fil("b3.txt", 23, "2011-02-03")
)
, bldr.Fil("1.txt", 1, "2001-01-01")
, bldr.Fil("2.txt", 2, "2004-01-02")
, bldr.Fil("3.xowa", 3, "2004-01-03")
);
}
public void Init_dir(IoItmDir dir) {
IoItmDir_.Make(dir);
}
public void Test_nav(String path, String expd) {
Xoa_url_arg_mgr args_mgr = new Xoa_url_arg_mgr(null);
Xoa_url url = Xoa_url.new_(Bry_.Empty, Bry_.Empty).Args_(Gfo_url_arg.Ary("cmd", "xowa.wiki.add", "mode", "view", "path", path));
args_mgr.Init(url.Args());
Xosp_fbrow_cmd__wiki_add cmd = new Xosp_fbrow_cmd__wiki_add();
byte[] actl = cmd.Write_html(args_mgr, GfoInvkAble_.Null).Html_body();
Tfds.Eq_str_lines(expd, String_.new_u8(actl));
}
}

View File

@@ -0,0 +1,40 @@
/*
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.specials.xowa.popup_history; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*; import gplx.xowa.specials.xowa.*;
import gplx.xowa.html.modules.popups.*;
public class Popup_history_page implements Xows_page {
public Xows_special_meta Special_meta() {return Xows_special_meta_.Itm__popup_history;}
public void Special_gen(Xowe_wiki wiki, Xoae_page page, Xoa_url url, Xoa_ttl ttl) {
Xoae_page cur_page = wiki.Appe().Gui_mgr().Browser_win().Active_page(); if (cur_page == null) return;
Ordered_hash hash = cur_page.Popup_mgr().Itms();
int len = hash.Count();
Bry_bfr bfr = wiki.Utl__bfr_mkr().Get_k004();
for (int i = len - 1; i > -1; --i) {
Xow_popup_itm itm = (Xow_popup_itm)hash.Get_at(i);
if (Ttl_chk(itm.Page_ttl())) continue;
fmtr_main.Bld_bfr_many(bfr, itm.Page_href(), itm.Page_ttl().Full_txt());
}
page.Data_raw_(bfr.Trim_end(Byte_ascii.Nl).To_bry_and_rls());
page.Html_data().Html_restricted_n_();
}
private Bry_fmtr fmtr_main = Bry_fmtr.new_("<a href='~{href}'>~{ttl}</a>\n\n", "href", "ttl"); // NOTE: need to use anchor (as opposed to lnki or lnke) b/c xwiki will not work on all wikis
public static boolean Ttl_chk(Xoa_ttl ttl) {
return ttl.Ns().Id_special()
&& Bry_.Eq(ttl.Page_db(), Xows_special_meta_.Itm__popup_history.Key_bry());
}
}

View File

@@ -0,0 +1,63 @@
/*
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.specials.xowa.system_data; import gplx.*; import gplx.xowa.*; import gplx.xowa.specials.*; import gplx.xowa.specials.xowa.*;
import gplx.core.primitives.*;
public class System_data_page implements Xows_page {
private Xoa_url_arg_hash arg_hash = new Xoa_url_arg_hash();
public Xows_special_meta Special_meta() {return Xows_special_meta_.Itm__system_data;}
public void Special_gen(Xowe_wiki wiki, Xoae_page page, Xoa_url url, Xoa_ttl ttl) {
arg_hash.Load(url);
byte[] file_type = arg_hash.Get_val_bry_or(Arg_type, null); if (file_type == null) return;
Byte_obj_val type_val = (Byte_obj_val)type_hash.Get_by_bry(file_type); if (type_val == null) return;
Io_url file_url = Path_from_type(wiki, type_val.Val()); if (file_url == null) return;
Bry_bfr tmp_bfr = wiki.Utl__bfr_mkr().Get_m001();
byte[] file_txt = Io_mgr.I.LoadFilBry(file_url);
file_txt = gplx.html.Html_utl.Escape_html_as_bry(file_txt, true, false, false, false, false); // escape < or "</pre>" in messages will cause pre to break
fmtr_all.Bld_bfr_many(tmp_bfr, file_url.Raw(), file_txt);
page.Data_raw_(tmp_bfr.To_bry_and_rls());
}
private static Io_url Path_from_type(Xowe_wiki wiki, byte type) {
Xoae_app app = wiki.Appe();
switch (type) {
case Type_log_session: return app.Log_wtr().Session_fil();
case Type_cfg_app: return app.Fsys_mgr().Root_dir().GenSubFil("xowa.gfs");
case Type_cfg_lang: return Xol_lang_.xo_lang_fil_(app.Fsys_mgr(), wiki.Lang().Key_str());
case Type_cfg_user: return app.Usere().Fsys_mgr().App_data_cfg_user_fil();
case Type_cfg_custom: return app.Usere().Fsys_mgr().App_data_cfg_custom_fil();
case Type_usr_history: return app.Usere().Fsys_mgr().App_data_history_fil();
default: return null;
}
}
private static final byte[] Arg_type = Bry_.new_a7("type");
private static final byte Type_log_session = 1, Type_cfg_app = 2, Type_cfg_lang = 3, Type_cfg_user = 4, Type_cfg_custom = 5, Type_usr_history = 6;
private static final Hash_adp_bry type_hash = Hash_adp_bry.cs_()
.Add_str_byte("log_session" , Type_log_session)
.Add_str_byte("cfg_app" , Type_cfg_app)
.Add_str_byte("cfg_lang" , Type_cfg_lang)
.Add_str_byte("cfg_user" , Type_cfg_user)
.Add_str_byte("cfg_custom" , Type_cfg_custom)
.Add_str_byte("usr_history" , Type_usr_history)
;
private Bry_fmtr fmtr_all = Bry_fmtr.new_(String_.Concat_lines_nl_skip_last
( "<p><b>Path</b>: <code>~{path}</code>"
, "</p>"
, "<pre style='overflow:auto;'>"
, "~{text}</pre>"
), "path", "text");
}