1
0
mirror of https://github.com/gnosygnu/xowa.git synced 2026-03-02 03:49:30 +00:00

uca category support and other changes

This commit is contained in:
gnosygnu
2016-10-12 08:57:22 -04:00
parent e3b393650d
commit 3fc2e0741f
187 changed files with 3486 additions and 2984 deletions

View File

@@ -19,12 +19,10 @@ package gplx.xowa.addons.wikis.ctgs.bldrs; import gplx.*; import gplx.xowa.*; im
import gplx.dbs.*; import gplx.xowa.addons.wikis.ctgs.dbs.*;
import gplx.xowa.addons.wikis.ctgs.enums.*;
import gplx.xowa.wikis.data.*; import gplx.xowa.wikis.data.tbls.*;
import gplx.xowa.addons.wikis.ctgs.bldrs.ucas.*;
class Xob_catlink_mgr {
private Xowe_wiki wiki;
private Xodb_tmp_cat_db tmp_db; private Db_conn tmp_conn; private Xodb_tmp_cat_link_tbl tmp_link_tbl;
private final Xoctg_collation_enum collation_enum = new Xoctg_collation_enum(); private final Xoctg_type_enum type_enum = new Xoctg_type_enum();
private Uca_trie trie; private final Bry_bfr uca_bfr = Bry_bfr_.New();
private int rows = 0;
public void On_cmd_bgn(Xowe_wiki wiki) {
this.wiki = wiki;
@@ -42,17 +40,13 @@ class Xob_catlink_mgr {
byte collation_id = collation_enum.To_tid_or_fail(collation_bry);
byte type_id = type_enum.To_tid_or_fail(type_bry);
// sortkey; handle \n
// sortkey
byte[] sortkey_actl = sortkey_orig;
int nl_pos = Bry_find_.Find_fwd(sortkey_actl, Byte_ascii.Nl);
if (nl_pos != Bry_find_.Not_found) // some sortkeys have format of "sortkey\ntitle"; discard 2nd to conserve hard-disk space; EX: "WALES, JIMMY\nJIMMY WALES"
sortkey_actl = Bry_.Mid(sortkey_actl, 0, nl_pos); // NOTE: some sortkeys have space which will sort under " "; EX: ' \nART' -> " "; SEE: s.w:Category:Art
// sortkey; handle uca
if (collation_id == Xoctg_collation_enum.Tid__uca) {
if (trie == null) trie = new Uca_trie();
trie.Decode(uca_bfr, sortkey_actl, 0, sortkey_actl.length);
sortkey_actl = uca_bfr.Len() == 0 ? Byte_ascii.Space_bry : uca_bfr.To_bry_and_clear();
if (collation_id != Xoctg_collation_enum.Tid__uca) {
// sortkey; handle \n
int nl_pos = Bry_find_.Find_fwd(sortkey_actl, Byte_ascii.Nl);
if (nl_pos != Bry_find_.Not_found) // some sortkeys have format of "sortkey\ntitle"; discard 2nd to conserve hard-disk space; EX: "WALES, JIMMY\nJIMMY WALES"
sortkey_actl = Bry_.Mid(sortkey_actl, 0, nl_pos); // NOTE: some sortkeys have space which will sort under " "; EX: ' \nART' -> " "; SEE: s.w:Category:Art
}
// insert to tmp; notify; commit
@@ -76,12 +70,12 @@ class Xob_catlink_mgr {
}
// create tbl
Xodb_cat_sort_tbl cat_sort_tbl = new Xodb_cat_sort_tbl(cat_core_conn);
cat_core_conn.Meta_tbl_remake(cat_sort_tbl);
cat_sort_tbl.Insert_by_select(tmp_conn);
// Xodb_cat_sort_tbl cat_sort_tbl = new Xodb_cat_sort_tbl(cat_core_conn);
// cat_core_conn.Meta_tbl_remake(cat_sort_tbl);
// cat_sort_tbl.Insert_by_select(tmp_conn);
// make catlink_dbs
cat_sort_tbl.Create_idx__key(); // index will be needed for join
// cat_sort_tbl.Create_idx__key(); // index will be needed for join
tmp_link_tbl.Create_idx__to_ttl(); // index will be needed for join
Db_conn page_conn = wiki.Data__core_mgr().Db__core().Conn();
Xob_catlink_wkr wkr = new Xob_catlink_wkr();
@@ -92,7 +86,7 @@ class Xob_catlink_mgr {
wkr.Update_page_cat_db_id(wiki, page_conn);
// cleanup
cat_sort_tbl.Delete_idx__key(); // remove idx
// cat_sort_tbl.Delete_idx__key(); // remove idx
tmp_db.Delete();
}
}

View File

@@ -26,16 +26,16 @@ class Xob_catlink_wkr {
( "SELECT tcl.cl_from"
, ", p.page_id"
, ", tcl.cl_type_id"
, ", cs.cs_id"
, ", tcl.cl_timestamp"
, ", tcl.cl_sortkey"
, ", tcl.cl_sortkey_prefix"
, "FROM <temp_db>tmp_cat_link tcl"
, " JOIN <cat_db>cat_sort cs ON tcl.cl_sortkey = cs.cs_key"
, " JOIN page p ON p.page_namespace = 14 AND tcl.cl_to_ttl = p.page_title"
, " JOIN page p ON p.page_namespace = 14 AND tcl.cl_to_ttl = p.page_title"
, "ORDER BY 1" // NOTE: must sort by page_id to keep all cats for page in one db
));
attach_mgr.Attach();
// select from tmp_db and insert insert into cat_link
// select from tmp_db and insert into cat_link
Xodb_cat_link_tbl cat_link_tbl = Make_cat_link_tbl(wiki, null);
Db_rdr rdr = attach_mgr.Conn_main().Stmt_sql(sql).Exec_select__rls_auto();
try {
@@ -46,7 +46,9 @@ class Xob_catlink_wkr {
while (rdr.Move_next()) {
// check if row can fit in db; else update db_size
int page_id_cur = rdr.Read_int("cl_from");
long db_size_new = db_size_cur + 46;// 46 = 3 ints (12) + 1 long (8) + 1 byte (2?) + 2 index (24?) + 9 fudge factor (?); DATE:2016-09-06
byte[] sortkey = rdr.Read_bry("cl_sortkey");
byte[] sortkey_prefix = rdr.Read_bry_by_str("cl_sortkey_prefix");
long db_size_new = db_size_cur + 48 + (sortkey.length * 2) + sortkey_prefix.length;// 46 = 3 ints (12) + 1 long (8) + 1 byte (2?) + 2 index (24?) + 11 fudge factor (?); DATE:2016-09-06
if ( db_size_cur > db_size_max // size exceeded
&& page_id_cur != page_id_prv) { // and page_id is diff; keeps all page_ids in one db
cat_link_tbl = Make_cat_link_tbl(wiki, cat_link_tbl);
@@ -56,7 +58,7 @@ class Xob_catlink_wkr {
page_id_prv = page_id_cur;
// insert; notify;
cat_link_tbl.Insert_cmd_by_batch(page_id_prv, rdr.Read_int("page_id"), rdr.Read_byte("cl_type_id"), rdr.Read_int("cs_id"), rdr.Read_long("cl_timestamp"));
cat_link_tbl.Insert_cmd_by_batch(page_id_prv, rdr.Read_int("page_id"), rdr.Read_byte("cl_type_id"), rdr.Read_long("cl_timestamp"), sortkey, sortkey_prefix);
if (++rows % 100000 == 0)
Gfo_usr_dlg_.Instance.Prog_many("", "", "inserting cat_link row: ~{0}", Int_.To_str_fmt(rows, "#,##0"));
}
@@ -82,8 +84,8 @@ class Xob_catlink_wkr {
private static void Term_cat_link_tbl(Xodb_cat_link_tbl cat_link_tbl) {
if (cat_link_tbl == null) return;
cat_link_tbl.Insert_end();
cat_link_tbl.Create_idx__from();
cat_link_tbl.Create_idx__to_id();
cat_link_tbl.Create_idx__catbox();
cat_link_tbl.Create_idx__catpage();
}
public void Make_catcore_tbl(Xowe_wiki wiki, Db_conn tmp_conn, Db_conn page_conn, Db_conn cat_core_conn) {
Db_attach_mgr attach_mgr = new Db_attach_mgr(cat_core_conn, new Db_attach_itm("temp_db", tmp_conn), new Db_attach_itm("page_db", page_conn));

View File

@@ -1,45 +0,0 @@
/*
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.addons.wikis.ctgs.bldrs.ucas; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.wikis.*; import gplx.xowa.addons.wikis.ctgs.*; import gplx.xowa.addons.wikis.ctgs.bldrs.*;
import org.junit.*; import gplx.xowa.bldrs.*;
public class Uca_trie_tst {
@Before public void init() {fxt.Clear();} private Xob_base_fxt fxt = new Xob_base_fxt();
@Test public void Basic() {
Uca_trie_fxt fxt = new Uca_trie_fxt();
fxt.Clear();
fxt.Init_trie_itm("a", Bry_.New_by_ints(10, 11));
fxt.Init_trie_itm("b", Bry_.New_by_ints(20, 21));
fxt.Init_trie_itm("c", Bry_.New_by_ints(30, 31));
fxt.Test_decode(Bry_.New_by_ints(10, 11), "a");
fxt.Test_decode(Bry_.New_by_ints(10, 11, 20, 21, 30, 31), "abc");
}
}
class Uca_trie_fxt {
public void Clear() {
if (trie == null) {
trie = new Uca_trie();
bfr = Bry_bfr_.New();
}
trie.Clear();
} Uca_trie trie; Bry_bfr bfr;
public void Init_trie_itm(String charAsStr, byte[] uca) {trie.Init_itm(gplx.core.intls.Utf16_.Decode_to_int(Bry_.new_u8(charAsStr), 0), uca);}
public void Test_decode(byte[] bry, String expd) {
trie.Decode(bfr, bry, 0, bry.length);
Tfds.Eq(expd, bfr.To_str_and_clear());
}
}

View File

@@ -20,32 +20,34 @@ import gplx.dbs.*;
import gplx.xowa.addons.wikis.ctgs.htmls.pageboxs.*;
public class Xodb_cat_link_tbl implements Db_tbl {
private final Dbmeta_fld_list flds = new Dbmeta_fld_list();
private final String fld_from, fld_to_id, fld_type_id, fld_sortkey_id, fld_timestamp_unix;
private final String fld__from, fld__to_id, fld__type_id, fld__timestamp_unix, fld__sortkey, fld__sortkey_prefix;
private Db_stmt stmt_insert;
public Xodb_cat_link_tbl(Db_conn conn) {
this.conn = conn;
this.tbl_name = "cat_link";
this.fld_from = flds.Add_int ("cl_from");
this.fld_to_id = flds.Add_int ("cl_to_id");
this.fld_type_id = flds.Add_byte ("cl_type_id");
this.fld_sortkey_id = flds.Add_int ("cl_sortkey_id");
this.fld_timestamp_unix = flds.Add_long ("cl_timestamp_unix");
this.fld__from = flds.Add_int ("cl_from");
this.fld__to_id = flds.Add_int ("cl_to_id");
this.fld__type_id = flds.Add_byte ("cl_type_id");
this.fld__timestamp_unix = flds.Add_long ("cl_timestamp_unix");
this.fld__sortkey = flds.Add_bry ("cl_sortkey");
this.fld__sortkey_prefix = flds.Add_str ("cl_sortkey_prefix", 255);
conn.Rls_reg(this);
}
public Db_conn Conn() {return conn;} private final Db_conn conn;
public String Tbl_name() {return tbl_name;} private final String tbl_name;
public void Create_tbl() {conn.Meta_tbl_create(Dbmeta_tbl_itm.New(tbl_name, flds));}
public void Create_idx__from() {conn.Meta_idx_create(Dbmeta_idx_itm.new_normal_by_tbl(tbl_name, fld_from, fld_from));}
public void Create_idx__to_id() {conn.Meta_idx_create(Dbmeta_idx_itm.new_normal_by_tbl(tbl_name, fld_to_id, fld_to_id));}
public void Create_idx__catbox() {conn.Meta_idx_create(Dbmeta_idx_itm.new_normal_by_tbl(tbl_name, "catbox", fld__from));}
public void Create_idx__catpage() {conn.Meta_idx_create(Dbmeta_idx_itm.new_normal_by_tbl(tbl_name, "catpage", fld__to_id, fld__type_id, fld__sortkey));}
public void Insert_bgn() {conn.Txn_bgn("cl__insert"); stmt_insert = conn.Stmt_insert(tbl_name, flds);}
public void Insert_end() {conn.Txn_end(); stmt_insert = Db_stmt_.Rls(stmt_insert);}
public void Insert_cmd_by_batch(int from, int to_id, byte type_id, int sortkey_id, long timestamp_unix) {
public void Insert_cmd_by_batch(int from, int to_id, byte type_id, long timestamp_unix, byte[] sortkey, byte[] sortkey_prefix) {
stmt_insert.Clear()
.Val_int(fld_from , from)
.Val_int(fld_to_id , to_id)
.Val_byte(fld_type_id , type_id)
.Val_int(fld_sortkey_id , sortkey_id)
.Val_long(fld_timestamp_unix , timestamp_unix)
.Val_int(fld__from , from)
.Val_int(fld__to_id , to_id)
.Val_byte(fld__type_id , type_id)
.Val_long(fld__timestamp_unix , timestamp_unix)
.Val_bry(fld__sortkey , sortkey)
.Val_bry_as_str(fld__sortkey_prefix , sortkey_prefix)
.Exec_insert();
}
public void Rls() {

View File

@@ -26,7 +26,7 @@ public class Xodb_tmp_cat_link_tbl implements Db_tbl {
this.tbl_name = "tmp_cat_link";
this.fld_from = flds.Add_int ("cl_from");
this.fld_to_ttl = flds.Add_str ("cl_to_ttl", 255);
this.fld_sortkey = flds.Add_str ("cl_sortkey", 230);
this.fld_sortkey = flds.Add_bry ("cl_sortkey");
this.fld_timestamp = flds.Add_long ("cl_timestamp");
this.fld_sortkey_prefix = flds.Add_str ("cl_sortkey_prefix", 230);
this.fld_collation_id = flds.Add_byte ("cl_collation_id");
@@ -43,7 +43,7 @@ public class Xodb_tmp_cat_link_tbl implements Db_tbl {
stmt_insert.Clear()
.Val_int(fld_from , page_id)
.Val_bry_as_str(fld_to_ttl , ctg_ttl)
.Val_bry_as_str(fld_sortkey , sortkey)
.Val_bry(fld_sortkey , sortkey)
.Val_long(fld_timestamp , timestamp)
.Val_bry_as_str(fld_sortkey_prefix , sortkey_prefix)
.Val_byte(fld_collation_id , collation_id)

View File

@@ -17,14 +17,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.wikis.ctgs.htmls.catpages; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.wikis.*; import gplx.xowa.addons.wikis.ctgs.*; import gplx.xowa.addons.wikis.ctgs.htmls.*;
import gplx.xowa.wikis.dbs.*; import gplx.xowa.wikis.data.tbls.*;
import gplx.xowa.langs.*; import gplx.xowa.langs.msgs.*; import gplx.xowa.htmls.core.htmls.*;
import gplx.xowa.langs.*; import gplx.xowa.langs.msgs.*; import gplx.xowa.htmls.core.htmls.*; import gplx.core.intls.ucas.*;
import gplx.xowa.wikis.nss.*;
import gplx.xowa.addons.wikis.ctgs.htmls.catpages.doms.*; import gplx.xowa.addons.wikis.ctgs.htmls.catpages.fmts.*; import gplx.xowa.addons.wikis.ctgs.htmls.catpages.utls.*; import gplx.xowa.addons.wikis.ctgs.htmls.catpages.urls.*;
public class Xoctg_catpage_mgr {
import gplx.xowa.addons.wikis.ctgs.htmls.catpages.doms.*; import gplx.xowa.addons.wikis.ctgs.htmls.catpages.fmts.*; import gplx.xowa.addons.wikis.ctgs.htmls.catpages.dbs.*; import gplx.xowa.addons.wikis.ctgs.htmls.catpages.urls.*; import gplx.xowa.addons.wikis.ctgs.htmls.catpages.langs.*;
public class Xoctg_catpage_mgr implements Gfo_invk {
private final Xow_wiki wiki;
private final Hash_adp_bry cache = Hash_adp_bry.cs();
private final Xoctg_catpage_loader loader = new Xoctg_catpage_loader();
private final Xoctg_fmt_grp fmt_subcs = Xoctg_fmt_grp.New__subc(), fmt_pages = Xoctg_fmt_grp.New__page(), fmt_files = Xoctg_fmt_grp.New__file();
private final Uca_ltr_extractor ltr_extractor = new Uca_ltr_extractor(true);
public int Grp_max() {return grp_max;} private int grp_max = Grp_max_dflt;
public Xoctg_catpage_mgr(Xow_wiki wiki) {
this.wiki = wiki;
this.collation_mgr = new Xoctg_collation_mgr(wiki);
}
public Xoctg_collation_mgr Collation_mgr() {return collation_mgr;} private Xoctg_collation_mgr collation_mgr;
public Xoctg_fmt_grp Fmt(byte tid) {
switch (tid) {
case Xoa_ctg_mgr.Tid__subc: return fmt_subcs;
@@ -34,32 +41,33 @@ public class Xoctg_catpage_mgr {
}
}
public void Free_mem_all() {cache.Clear();}
public Xoctg_catpage_ctg Get_or_load_or_null(Xow_wiki wiki, Xoa_ttl cat_ttl) {
public Xoctg_catpage_ctg Get_or_load_or_null(Xoctg_catpage_url catpage_url, Xoa_ttl cat_ttl, int limit) {
// load categories from cat dbs; exit if not found
Xoctg_catpage_ctg ctg = (Xoctg_catpage_ctg)cache.Get_by(cat_ttl.Full_db());
if (ctg == null) {
if (gplx.core.envs.Env_.Mode_testing()) return null; // needed for dpl test
ctg = loader.Load_by_ttl_or_null(wiki, cat_ttl);
synchronized (thread_lock) { // LOCK:used by multiple wrks; DATE:2016-09-12
ctg = loader.Load_ctg_or_null(wiki, this, catpage_url, cat_ttl, limit);
}
if (ctg == null) return null; // not in cache or db; exit
cache.Add(cat_ttl.Full_db(), ctg);
// cache.Add(cat_ttl.Full_db(), ctg);
}
return ctg;
}
public void Write_catpage(Bry_bfr bfr, Xow_wiki wiki, Xoa_page page, Xoh_wtr_ctx hctx) {
public void Write_catpage(Bry_bfr bfr, Xoa_page page, Xoh_wtr_ctx hctx) {
try {
// load categories from cat dbs; exit if not found
Xoctg_catpage_ctg ctg = Get_or_load_or_null(wiki, page.Ttl());
if (ctg == null) return;
// filter subs; need for large categories like de.w:Category:Mann
// get catpage_url
Xoctg_catpage_url catpage_url = Xoctg_catpage_url_parser.Parse(page.Url());
Xoctg_catpage_filter.Filter(grp_max, catpage_url, ctg);
// load categories from cat dbs; exit if not found
Xoctg_catpage_ctg ctg = Get_or_load_or_null(catpage_url, page.Ttl(), grp_max);
if (ctg == null) return;
// write html
Xol_lang_itm lang = page.Lang();
fmt_subcs.Write_catpage_grp(bfr, wiki, lang, ctg, grp_max);
fmt_pages.Write_catpage_grp(bfr, wiki, lang, ctg, grp_max);
fmt_files.Write_catpage_grp(bfr, wiki, lang, ctg, grp_max);
fmt_subcs.Write_catpage_grp(bfr, wiki, lang, ltr_extractor, ctg, grp_max);
fmt_pages.Write_catpage_grp(bfr, wiki, lang, ltr_extractor, ctg, grp_max);
fmt_files.Write_catpage_grp(bfr, wiki, lang, ltr_extractor, ctg, grp_max);
}
catch (Exception e) {
Xoa_app_.Usr_dlg().Warn_many("", "", "failed to generate category: title=~{0} err=~{1}", page.Url_bry_safe(), Err_.Message_gplx_log(e));
@@ -70,5 +78,12 @@ public class Xoctg_catpage_mgr {
cache.Add(ttl, ctg);
}
public void Grp_max_(int v) {grp_max = v;} // TEST:
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk__collation_)) collation_mgr.Collation_name_(m.ReadStr("v"));
else return Gfo_invk_.Rv_unhandled;
return this;
} private static final String Invk__collation_ = "collation_";
public static int Grp_max_dflt = 200;
private static final Object thread_lock = new Object();
}

View File

@@ -16,25 +16,27 @@ 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.addons.wikis.ctgs.htmls.catpages; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.wikis.*; import gplx.xowa.addons.wikis.ctgs.*; import gplx.xowa.addons.wikis.ctgs.htmls.*;
import org.junit.*; import gplx.xowa.htmls.core.htmls.*;
import org.junit.*; import gplx.xowa.htmls.core.htmls.*; import gplx.core.intls.ucas.*;
import gplx.xowa.addons.wikis.ctgs.htmls.catpages.doms.*; import gplx.xowa.addons.wikis.ctgs.htmls.catpages.fmts.*;
public class Xoctg_catpage_mgr__basic__tst {
@Before public void init() {fxt.Clear();} private Xoctg_catpage_mgr_fxt fxt = new Xoctg_catpage_mgr_fxt();
@Test public void Page_itm() {
fxt .Init_itms__pages("A1")
.Test__html__page(Xoa_ctg_mgr.Tid__page, Byte_ascii.Ltr_A, "\n <li><a href=\"/wiki/A1\" title=\"A1\">A1</a></li>");
.Test__html__page(Xoa_ctg_mgr.Tid__page, Byte_ascii.Ltr_A, "\n <li><a href=\"/wiki/A1\" title=\"A1\">A1</a><!----></li>");
}
@Test public void Page_itm_missing() {
fxt .Init_itms__pages("A1");
fxt .Ctg().Grp_by_tid(Xoa_ctg_mgr.Tid__page).Itms__get_at(0).Missing_y_();
fxt .Test__html__page(Xoa_ctg_mgr.Tid__page, Byte_ascii.Ltr_A, "\n <li class=\"xowa-missing-category-entry\"><span title=\"id not found: #0 might be talk/user page\">A1 (missing)</li>");
fxt.Init_itms__pages("A1");
Xoctg_catpage_itm itm = fxt.Ctg().Grp_by_tid(Xoa_ctg_mgr.Tid__page).Itms__get_at(0);
itm.Page_ttl_(Xoa_ttl.Null);
itm.Sortkey_handle_make(Bry_bfr_.New(), Bry_.Empty);
fxt.Test__html__page(Xoa_ctg_mgr.Tid__page, Byte_ascii.Ltr_A, "\n <li class=\"xowa-missing-category-entry\"><span title=\"id not found: #0 might be talk/user page\">A1 (missing)</li>");
}
@Test public void Visited_doesnt_work_for_space() {// PURPOSE: xowa-visited not inserted for pages with space
byte[] page_bry = Bry_.new_a7("A 1");
Xoa_url url = Xoa_url.New(Bry_.new_a7("en.wikipedia.org"), page_bry);
Xoa_ttl ttl = Xoa_ttl.Parse(fxt.Wiki(), page_bry);
fxt.Wiki().Appe().Usere().History_mgr().Add(url, ttl, page_bry);
fxt .Init_itms__pages("A_1").Init_grp__pages(0, 1)
fxt .Init_itms__pages("A_1")
.Test__html__all(Xoa_ctg_mgr.Tid__page, String_.Concat_lines_nl_skip_last
( ""
, "<div id=\"mw-pages\">"
@@ -46,7 +48,7 @@ public class Xoctg_catpage_mgr__basic__tst {
, " <td style=\"width: 33%;\">"
, " <h3>A</h3>"
, " <ul>"
, " <li><a href=\"/wiki/A_1\" class=\"xowa-visited\" title=\"A 1\">A 1</a></li>"
, " <li><a href=\"/wiki/A_1\" class=\"xowa-visited\" title=\"A 1\">A 1</a><!----></li>"
, " </ul>"
, " </td>"
, " </tr>"
@@ -56,7 +58,7 @@ public class Xoctg_catpage_mgr__basic__tst {
));
}
@Test public void Page_all() {
fxt .Init_itms__pages("A1").Init_grp__pages(0, 1)
fxt .Init_itms__pages("A1")
.Test__html__all(Xoa_ctg_mgr.Tid__page, String_.Concat_lines_nl_skip_last
( ""
, "<div id=\"mw-pages\">"
@@ -68,7 +70,7 @@ public class Xoctg_catpage_mgr__basic__tst {
, " <td style=\"width: 33%;\">"
, " <h3>A</h3>"
, " <ul>"
, " <li><a href=\"/wiki/A1\" title=\"A1\">A1</a></li>"
, " <li><a href=\"/wiki/A1\" title=\"A1\">A1</a><!----></li>"
, " </ul>"
, " </td>"
, " </tr>"
@@ -78,7 +80,7 @@ public class Xoctg_catpage_mgr__basic__tst {
));
}
@Test public void File_all() {
fxt .Init_itms__files("File:A1.png").Init_grp__files(0, 1)
fxt .Init_itms__files("File:A1.png")
.Test__html__all(Xoa_ctg_mgr.Tid__file, String_.Concat_lines_nl_skip_last
( ""
, "<div id=\"mw-category-media\">"
@@ -90,7 +92,7 @@ public class Xoctg_catpage_mgr__basic__tst {
, " <td style=\"width: 33%;\">"
, " <h3>A</h3>"
, " <ul>"
, " <li><a href=\"/wiki/File:A1.png\" title=\"File:A1.png\">File:A1.png</a></li>"
, " <li><a href=\"/wiki/File:A1.png\" title=\"File:A1.png\">File:A1.png</a><!----></li>"
, " </ul>"
, " </td>"
, " </tr>"
@@ -98,25 +100,9 @@ public class Xoctg_catpage_mgr__basic__tst {
, " </div>"
, "</div>"
));
// , " <ul id=\"xowa_gallery_ul_0\" class=\"gallery\">"
// , " <li class=\"gallerybox\" style=\"width:155px;\">"
// , " <div style=\"width:155px;\">"
// , " <div class=\"thumb\" style=\"width:155px;\">"
// , " <div id=\"xowa_gallery_div3_-1\" style=\"margin:15px auto;\">"
// , " <a href=\"/wiki/File:A1.png\" class=\"image\">"
// , " <img id=\"xoimg_-1\" alt=\"A1.png\" src=\"\" width=\"-1\" height=\"-1\" />"
// , " </a>"
// , " </div>"
// , " </div>"
// , " <div class=\"gallerytext\">A1.png"
// , " </div>"
// , " </div>"
// , " </li>"
// , ""
// , " </ul>"
}
@Test public void Subc_all() {
fxt .Init_itms__subcs("Category:Subc_1").Init_grp__files(0, 1)
fxt .Init_itms__subcs("Category:Subc_1")
.Test__html__all(Xoa_ctg_mgr.Tid__subc, String_.Concat_lines_nl_skip_last
( ""
, "<div id=\"mw-subcategories\">"
@@ -152,46 +138,82 @@ public class Xoctg_catpage_mgr__basic__tst {
));
}
@Test public void Page_all_cols() {
fxt .Init_itms__pages("A1", "A2", "A3", "B1", "C1").Init_grp__pages(0, 5)
.Test__html__all(Xoa_ctg_mgr.Tid__page, String_.Concat_lines_nl_skip_last
( ""
, "<div id=\"mw-pages\">"
, " <h2>Pages in category \"Ctg_1\"</h2>"
, " <p>The following 5 pages are in this category, out of 5 total.</p>"
, " <div lang=\"en\" dir=\"ltr\" class=\"mw-content-ltr\">"
, " <table style=\"width: 100%;\">"
, " <tr style=\"vertical-align: top;\">"
, " <td style=\"width: 33%;\">"
, " <h3>A</h3>"
, " <ul>"
, " <li><a href=\"/wiki/A1\" title=\"A1\">A1</a></li>"
, " <li><a href=\"/wiki/A2\" title=\"A2\">A2</a></li>"
, " </ul>"
, " </td>"
, " <td style=\"width: 33%;\">"
, " <h3>A cont.</h3>"
, " <ul>"
, " <li><a href=\"/wiki/A3\" title=\"A3\">A3</a></li>"
, " </ul>"
, " <h3>B</h3>"
, " <ul>"
, " <li><a href=\"/wiki/B1\" title=\"B1\">B1</a></li>"
, " </ul>"
, " </td>"
, " <td style=\"width: 33%;\">"
, " <h3>C</h3>"
, " <ul>"
, " <li><a href=\"/wiki/C1\" title=\"C1\">C1</a></li>"
, " </ul>"
, " </td>"
, " </tr>"
, " </table>"
, " </div>"
, "</div>"
));
fxt.Init_itms__pages("A1", "A2", "A3", "B1", "C1");
fxt.Init__grp_max_(6);
fxt.Test__html__all(Xoa_ctg_mgr.Tid__page, String_.Concat_lines_nl_skip_last
( ""
, "<div id=\"mw-pages\">"
, " <h2>Pages in category \"Ctg_1\"</h2>"
, " <p>The following 5 pages are in this category, out of 5 total.</p>"
, " <div lang=\"en\" dir=\"ltr\" class=\"mw-content-ltr\">"
, " <table style=\"width: 100%;\">"
, " <tr style=\"vertical-align: top;\">"
, " <td style=\"width: 33%;\">"
, " <h3>A</h3>"
, " <ul>"
, " <li><a href=\"/wiki/A1\" title=\"A1\">A1</a><!----></li>"
, " <li><a href=\"/wiki/A2\" title=\"A2\">A2</a><!----></li>"
, " </ul>"
, " </td>"
, " <td style=\"width: 33%;\">"
, " <h3>A cont.</h3>"
, " <ul>"
, " <li><a href=\"/wiki/A3\" title=\"A3\">A3</a><!----></li>"
, " </ul>"
, " <h3>B</h3>"
, " <ul>"
, " <li><a href=\"/wiki/B1\" title=\"B1\">B1</a><!----></li>"
, " </ul>"
, " </td>"
, " <td style=\"width: 33%;\">"
, " <h3>C</h3>"
, " <ul>"
, " <li><a href=\"/wiki/C1\" title=\"C1\">C1</a><!----></li>"
, " </ul>"
, " </td>"
, " </tr>"
, " </table>"
, " </div>"
, "</div>"
));
}
@Test public void Page__numeric() { // PURPOSE: check numeric sorting; 0, 9, 10; not 0, 10, 9; DATE:2016-10-09
fxt.Init_itms__pages("0", "9", "10");
fxt.Init__grp_max_(6);
fxt.Test__html__all(Xoa_ctg_mgr.Tid__page, String_.Concat_lines_nl_skip_last
( ""
, "<div id=\"mw-pages\">"
, " <h2>Pages in category \"Ctg_1\"</h2>"
, " <p>The following 3 pages are in this category, out of 3 total.</p>"
, " <div lang=\"en\" dir=\"ltr\" class=\"mw-content-ltr\">"
, " <table style=\"width: 100%;\">"
, " <tr style=\"vertical-align: top;\">"
, " <td style=\"width: 33%;\">"
, " <h3>0-9</h3>"
, " <ul>"
, " <li><a href=\"/wiki/0\" title=\"0\">0</a><!----></li>"
, " </ul>"
, " </td>"
, " <td style=\"width: 33%;\">"
, " <h3>0-9 cont.</h3>"
, " <ul>"
, " <li><a href=\"/wiki/9\" title=\"9\">9</a><!----></li>"
, " </ul>"
, " </td>"
, " <td style=\"width: 33%;\">"
, " <h3>0-9 cont.</h3>"
, " <ul>"
, " <li><a href=\"/wiki/10\" title=\"10\">10</a><!----></li>"
, " </ul>"
, " </td>"
, " </tr>"
, " </table>"
, " </div>"
, "</div>"
));
}
@Test public void Title__escape_quotes() {// PURPOSE: quotes in title should be escaped; DATE:2015-12-28
fxt .Init_itms__pages("A\"1").Init_grp__pages(0, 1)
fxt .Init_itms__pages("A\"1")
.Test__html__all(Xoa_ctg_mgr.Tid__page, String_.Concat_lines_nl_skip_last
( ""
, "<div id=\"mw-pages\">"
@@ -203,7 +225,7 @@ public class Xoctg_catpage_mgr__basic__tst {
, " <td style=\"width: 33%;\">"
, " <h3>A</h3>"
, " <ul>"
, " <li><a href=\"/wiki/A%221\" title=\"A&quot;1\">A&quot;1</a></li>"
, " <li><a href=\"/wiki/A%221\" title=\"A&quot;1\">A&quot;1</a><!----></li>"
, " </ul>"
, " </td>"
, " </tr>"
@@ -226,44 +248,49 @@ public class Xoctg_catpage_mgr__basic__tst {
}
class Xoctg_catpage_mgr_fxt {
private int grp_max;
private Uca_ltr_extractor ltr_extractor = new Uca_ltr_extractor(true);
public Xoctg_catpage_mgr_fxt Clear() {
if (app == null) {
app = Xoa_app_fxt.Make__app__edit();
wiki = Xoa_app_fxt.Make__wiki__edit(app);
ctg_html = wiki.Html_mgr().Catpage_mgr();
ctg_html = wiki.Ctg__catpage_mgr();
}
ctg = new Xoctg_catpage_ctg(Bry_.new_a7("Ctg_1"));
grp_max = Xoctg_catpage_mgr.Grp_max_dflt;
ctg = new Xoctg_catpage_ctg(1, Bry_.new_a7("Ctg_1"));
grp_max = 3; // default to 3 paer page
return this;
} private Xoae_app app; private Xoctg_catpage_mgr ctg_html;
public void Test__calc_col_len(int grp_len, int col_idx, int expd) {Tfds.Eq(expd, Xoctg_fmt_itm_base.Calc_col_len(grp_len, col_idx, 3));}
public Xowe_wiki Wiki() {return wiki;} private Xowe_wiki wiki;
public Xoctg_catpage_ctg Ctg() {return ctg;} private Xoctg_catpage_ctg ctg;
public void Init__grp_max_(int v) {this.grp_max = v;}
public void Init__prev_hide_y_(byte tid) {ctg.Grp_by_tid(tid).Prev_disable_(true);}
public void Init__next_sortkey_(byte tid, String v) {ctg.Grp_by_tid(tid).Next_sortkey_(Bry_.new_u8(v));}
public void Test__navlink(boolean next, String ctg_str, String expd) {
byte[] actl = ctg_html.Fmt(Xoa_ctg_mgr.Tid__page).Bld_bwd_fwd(wiki, Xoa_ttl.Parse(wiki, Bry_.new_a7(ctg_str)), ctg.Grp_by_tid(Xoa_ctg_mgr.Tid__page), grp_max);
Tfds.Eq_str_lines(expd, String_.new_u8(actl));
}
public Xoctg_catpage_mgr_fxt Init_grp_max(int v) {this.grp_max = v; return this;}
public Xoctg_catpage_mgr_fxt Init_grp__pages(int bgn, int count) {ctg.Pages().Rng_(bgn, count); return this;}
public Xoctg_catpage_mgr_fxt Init_grp__files(int bgn, int count) {ctg.Files().Rng_(bgn, count); return this;}
public Xoctg_catpage_mgr_fxt Init_itms__pages(String... titles) {return Init_itms(Xoa_ctg_mgr.Tid__page, titles);}
public Xoctg_catpage_mgr_fxt Init_itms__files(String... titles) {return Init_itms(Xoa_ctg_mgr.Tid__file, titles);}
public Xoctg_catpage_mgr_fxt Init_itms__subcs(String... titles) {return Init_itms(Xoa_ctg_mgr.Tid__subc, titles);}
private Xoctg_catpage_mgr_fxt Init_itms(byte tid, String[] ttls) {
int len = ttls.length;
Xoctg_catpage_tmp tmp = new Xoctg_catpage_tmp();
Xoctg_catpage_grp grp = ctg.Grp_by_tid(tid);
grp.Count_all_(len);
for (int i = 0; i < len; ++i) {
Xoa_ttl ttl = Xoa_ttl.Parse(wiki, Bry_.new_u8(ttls[i]));
grp.Itms__add(new Xoctg_catpage_itm(i, ttl, ttl.Page_txt()));
byte[] page_ttl_bry = Bry_.new_u8(ttls[i]);
Xoa_ttl ttl = Xoa_ttl.Parse(wiki, page_ttl_bry);
Xoctg_catpage_itm itm = Xoctg_catpage_itm.New_by_ttl(tid, i, ttl);
tmp.Add(itm);
}
grp.Itms__make();
tmp.Make_by_grp(grp);
return this;
}
public void Test__html__page(byte tid, byte grp_char_0, String expd) {
Xoctg_fmt_grp list_mgr = ctg_html.Fmt(tid);
Xoctg_fmt_itm_base itm_fmt = list_mgr.Itm_fmt();
Xoctg_catpage_grp list = ctg.Grp_by_tid(tid);
itm_fmt.Init_from_ltr(wiki, list);
itm_fmt.Init_from_ltr(wiki, list, ltr_extractor);
itm_fmt.Set_ltr_and_bgn(new byte[] {grp_char_0}, 0);
itm_fmt.Col_end_(0, 0);
Bry_bfr bfr = wiki.Utl__bfr_mkr().Get_b512();
@@ -273,14 +300,14 @@ class Xoctg_catpage_mgr_fxt {
public void Test__html_grp(byte tid, String expd) {
Xoctg_fmt_grp list_mgr = ctg_html.Fmt(tid);
Xoctg_fmt_ltr fmtr_grp = new Xoctg_fmt_ltr(list_mgr.Itm_fmt());
fmtr_grp.Init_from_grp(wiki, ctg.Grp_by_tid(tid));
fmtr_grp.Init_from_grp(wiki, ctg.Grp_by_tid(tid), ltr_extractor);
Bry_bfr bfr = wiki.Utl__bfr_mkr().Get_b512();
fmtr_grp.Bfr_arg__add(bfr);
Tfds.Eq_str_lines(expd, bfr.To_str_and_rls());
}
public void Test__html__all(byte tid, String expd) {
Bry_bfr bfr = wiki.Utl__bfr_mkr().Get_b512();
ctg_html.Fmt(tid).Write_catpage_grp(bfr, wiki, wiki.Lang(), ctg, grp_max);
ctg_html.Fmt(tid).Write_catpage_grp(bfr, wiki, wiki.Lang(), ltr_extractor, ctg, grp_max);
Tfds.Eq_str_lines(expd, bfr.To_str_and_rls());
}
}

View File

@@ -21,43 +21,39 @@ import gplx.xowa.addons.wikis.ctgs.htmls.catpages.doms.*; import gplx.xowa.addon
public class Xoctg_catpage_mgr__navlink__tst {
@Before public void init() {fxt.Clear();} private Xoctg_catpage_mgr_fxt fxt = new Xoctg_catpage_mgr_fxt();
@Test public void Navlink__basic() {
fxt .Init_itms__pages("A1", "A2", "A3").Init_grp_max(1).Init_grp__pages(1, 2)
.Test__navlink(Bool_.Y, "Category:Ctg_1", String_.Concat_lines_nl
fxt.Init_itms__pages("A2", "A3", "A4");
fxt.Init__next_sortkey_(Xoa_ctg_mgr.Tid__page, "A5");
fxt.Test__navlink(Bool_.Y, "Category:Ctg_1", String_.Concat_lines_nl
( ""
, "(<a href=\"/wiki/Category:Ctg_1?pageuntil=A2#mw-pages\" class=\"xowa_nav\" title=\"Category:Ctg_1\">previous 1</a>)"
, "(<a href=\"/wiki/Category:Ctg_1?pagefrom=A3#mw-pages\" class=\"xowa_nav\" title=\"Category:Ctg_1\">next 1</a>)"
, "(<a href=\"/wiki/Category:Ctg_1?pageuntil=A2%0AA2#mw-pages\" class=\"xowa_nav\" title=\"Category:Ctg_1\">previous 3</a>)"
, "(<a href=\"/wiki/Category:Ctg_1?pagefrom=A5#mw-pages\" class=\"xowa_nav\" title=\"Category:Ctg_1\">next 3</a>)"
));
}
@Test public void Navlink__encoded() { // escape quotes and spaces; DATE:2016-01-11
fxt .Init_itms__pages("A\" 1", "A\" 2", "A\" 3").Init_grp_max(1).Init_grp__pages(1, 2)
.Test__navlink(Bool_.Y, "Category:Ctg_1", String_.Concat_lines_nl
fxt.Init_itms__pages("A\" 2", "A\" 3", "A\" 4");
fxt.Init__next_sortkey_(Xoa_ctg_mgr.Tid__page, "A\" 5");
fxt.Test__navlink(Bool_.Y, "Category:Ctg_1", String_.Concat_lines_nl
( ""
, "(<a href=\"/wiki/Category:Ctg_1?pageuntil=A%22+2#mw-pages\" class=\"xowa_nav\" title=\"Category:Ctg_1\">previous 1</a>)"
, "(<a href=\"/wiki/Category:Ctg_1?pagefrom=A%22+3#mw-pages\" class=\"xowa_nav\" title=\"Category:Ctg_1\">next 1</a>)"
, "(<a href=\"/wiki/Category:Ctg_1?pageuntil=A%22+2%0AA%22+2#mw-pages\" class=\"xowa_nav\" title=\"Category:Ctg_1\">previous 3</a>)"
, "(<a href=\"/wiki/Category:Ctg_1?pagefrom=A%22+5#mw-pages\" class=\"xowa_nav\" title=\"Category:Ctg_1\">next 3</a>)"
));
}
@Test public void Navlink__bos() {
fxt .Init_itms__pages("A1", "A2", "A3").Init_grp_max(1).Init_grp__pages(0, 1)
.Test__navlink(Bool_.Y, "Category:Ctg_1", String_.Concat_lines_nl
fxt.Init_itms__pages("A2", "A3", "A4");
fxt.Init__prev_hide_y_(Xoa_ctg_mgr.Tid__page);
fxt.Init__next_sortkey_(Xoa_ctg_mgr.Tid__page, "A5");
fxt.Test__navlink(Bool_.Y, "Category:Ctg_1", String_.Concat_lines_nl
( ""
, "(previous 1)"
, "(<a href=\"/wiki/Category:Ctg_1?pagefrom=A2#mw-pages\" class=\"xowa_nav\" title=\"Category:Ctg_1\">next 1</a>)"
, "(previous 3)"
, "(<a href=\"/wiki/Category:Ctg_1?pagefrom=A5#mw-pages\" class=\"xowa_nav\" title=\"Category:Ctg_1\">next 3</a>)"
));
}
@Test public void Navlink__eos() {
fxt .Init_itms__pages("A1", "A2", "A3").Init_grp_max(2).Init_grp__pages(2, 3)
.Test__navlink(Bool_.Y, "Category:Ctg_1", String_.Concat_lines_nl
fxt.Init_itms__pages("A2", "A3", "A4");
fxt.Test__navlink(Bool_.Y, "Category:Ctg_1", String_.Concat_lines_nl
( ""
, "(<a href=\"/wiki/Category:Ctg_1?pageuntil=A3#mw-pages\" class=\"xowa_nav\" title=\"Category:Ctg_1\">previous 2</a>)"
, "(next 2)"
));
}
@Test public void Navlink__eos__2() { // PURPOSE.fix: do not suppress next page on penultimate page; DATE:2016-09-25
fxt .Init_itms__pages("A1", "A2", "A3", "A4").Init_grp_max(2).Init_grp__pages(2, 3)
.Test__navlink(Bool_.Y, "Category:Ctg_1", String_.Concat_lines_nl
( ""
, "(<a href=\"/wiki/Category:Ctg_1?pageuntil=A3#mw-pages\" class=\"xowa_nav\" title=\"Category:Ctg_1\">previous 2</a>)"
, "(<a href=\"/wiki/Category:Ctg_1?pagefrom=A4#mw-pages\" class=\"xowa_nav\" title=\"Category:Ctg_1\">next 2</a>)"
, "(<a href=\"/wiki/Category:Ctg_1?pageuntil=A2%0AA2#mw-pages\" class=\"xowa_nav\" title=\"Category:Ctg_1\">previous 3</a>)"
, "(next 3)"
));
}
}

View File

@@ -0,0 +1,182 @@
/*
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.addons.wikis.ctgs.htmls.catpages.dbs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.wikis.*; import gplx.xowa.addons.wikis.ctgs.*; import gplx.xowa.addons.wikis.ctgs.htmls.*; import gplx.xowa.addons.wikis.ctgs.htmls.catpages.*;
import gplx.dbs.*; import gplx.xowa.wikis.data.*; import gplx.xowa.wikis.data.tbls.*;
import gplx.xowa.addons.wikis.ctgs.htmls.catpages.doms.*; import gplx.xowa.addons.wikis.ctgs.htmls.catpages.langs.*;
class Xoctg_catlink_loader {
private byte version;
private int link_dbs_len;
private Db_attach_mgr attach_mgr;
private final Bry_bfr sortkey_val_bfr = Bry_bfr_.New();
public void Run(Xoctg_catpage_ctg rv, Xow_wiki wiki, Xoctg_catpage_mgr catpage_mgr, Xowd_page_tbl page_tbl, int cat_id, byte grp_tid, boolean url_is_from, byte[] url_sortkey, int limit) {
String sql = Bld_sql(catpage_mgr, cat_id, grp_tid, url_is_from, url_sortkey, limit);
Load_catlinks(rv, wiki, page_tbl, rv.Grp_by_tid(grp_tid), sql, url_is_from, limit);
}
public void Make_attach_mgr__v2(Xow_db_mgr db_mgr, int cat_link_db_idx) {
this.version = 2;
this.link_dbs_len = 1;
Xow_db_file cat_link_db = db_mgr.Dbs__get_by_id_or_fail(cat_link_db_idx);
this.attach_mgr = new Db_attach_mgr(cat_link_db.Conn(), new Db_attach_itm("link_db_1", cat_link_db.Conn()));
}
public void Make_attach_mgr__v3_v4(Xow_db_mgr db_mgr, Db_conn cat_core_conn) {
// init db vars
List_adp db_list = List_adp_.New();
Db_conn db_1st = null;
int db_idx = 0;
// fill db_list by looping over each db unless (a) cat_link_db or (b) core_db (if all or few)
int len = db_mgr.Dbs__len();
for (int i = 0; i < len; ++i) {
Xow_db_file cl_db = db_mgr.Dbs__get_at(i);
switch (cl_db.Tid()) {
case Xow_db_file_.Tid__cat_link: // always use cat_link db
break;
case Xow_db_file_.Tid__core: // only use core if all or few
if (db_mgr.Props().Layout_text().Tid_is_lot())
continue;
else
break;
default: // skip all other files
continue;
}
// add to db_list
if (db_1st == null) db_1st = cl_db.Conn();
db_list.Add(new Db_attach_itm("link_db_" + ++db_idx, cl_db.Conn()));
}
// make attach_mgr
this.version = 4;
this.link_dbs_len = db_list.Len();
if (cat_core_conn.Meta_tbl_exists("cat_sort")) {
version = 3;
db_1st = cat_core_conn;
}
this.attach_mgr = new Db_attach_mgr(db_1st, (Db_attach_itm[])db_list.To_ary_and_clear(Db_attach_itm.class));
}
private String Bld_sql (Xoctg_catpage_mgr catpage_mgr, int cat_id, byte grp_tid, boolean url_is_from, byte[] url_sortkey, int limit) {
Bry_bfr bfr = Bry_bfr_.New();
for (int i = 0; i < link_dbs_len; ++i)
Bld_sql_by_db(catpage_mgr, cat_id, grp_tid, url_is_from, url_sortkey, i + List_adp_.Base1, bfr);
bfr.Add_str_u8_fmt
( "\nORDER BY cl_to_id, cl_type_id, cl_sortkey {0}"
+ "\nLIMIT {1}"
, url_is_from ? "ASC" : "DESC", limit + 1);
return bfr.To_str_and_clear();
}
private void Bld_sql_by_db (Xoctg_catpage_mgr catpage_mgr, int cat_id, byte grp_tid, boolean url_is_from, byte[] url_sortkey, int link_db_id, Bry_bfr bfr) {
if (link_db_id != List_adp_.Base1) bfr.Add_str_a7("\nUNION\n");
// change sortkey vars per version; note that v3 differs from v2 and v4 b/c of cat_sort tbl
String sortkey_col = "cl_sortkey";
String sortkey_join = "";
if (version == 3) { // NOTE: version 3 takes sortkey from cat_sort
sortkey_col = "cs.cs_key";
sortkey_join = "\n JOIN cat_sort cs ON cl.cl_sortkey_id = cs.cs_id";
}
// sortkey_val
byte[] sortkey_val = null;
String sortkey_prefix_fld = version == 4 ? "cl_sortkey_prefix" : "''";
sortkey_val = Build_sortkey_val(sortkey_val_bfr, version, catpage_mgr.Collation_mgr(), url_sortkey);
// bld sql; NOTE: building sql with args embedded b/c (a) UNION requires multiple Crt_arg for each ?; (EX: 4 unions, 3 ? require 12 .Crt_arg); (b) easier to debug
String sql = Db_sql_.Make_by_fmt(String_.Ary
( "SELECT cl_to_id"
, ", cl_from"
, ", cl_type_id"
, ", {3} AS cl_sortkey"
, ", {7} AS cl_sortkey_prefix"
, "FROM <link_db_{0}>cat_link cl{6}"
, "WHERE cl_to_id = {1}"
, "AND cl_type_id = {2}"
, "AND {3} {4} {5}"
), link_db_id, cat_id, grp_tid, sortkey_col, url_is_from ? ">=" : "<", sortkey_val, sortkey_join, sortkey_prefix_fld);
bfr.Add_str_u8(sql);
}
private void Load_catlinks(Xoctg_catpage_ctg rv, Xow_wiki wiki, Xowd_page_tbl page_tbl, Xoctg_catpage_grp grp, String sql, boolean url_is_from, int limit) {
// init; prep sql
Xoctg_page_loader catlink_loader = new Xoctg_page_loader(wiki);
Ordered_hash hash = catlink_loader.Hash();
sql = attach_mgr.Resolve_sql(sql);
// run sql and create itms based on cat_link
Xoctg_catpage_itm itm_zth = null;
Db_rdr rdr = Db_rdr_.Empty;
int row_idx = 0;
try {
attach_mgr.Attach();
rdr = attach_mgr.Conn_main().Stmt_sql(sql).Exec_select__rls_auto();
while (rdr.Move_next()) {
Xoctg_catpage_itm itm = Xoctg_catpage_itm.New_by_rdr(rdr, version);
if (row_idx++ < limit) // row_idx >= limit for last row; EX: 200 < 200
hash.Add(itm.Page_id(), itm);
else { // last row; EX: 201
if (url_is_from) // from=some_key; 201st row is sort_key for "(Next 200)"
itm_zth = itm;
else // until=some_key; 201st row means that 200th row is not 1st row; show prev link
grp.Prev_disable_(false);
}
}
}
finally {
rdr.Rls();
attach_mgr.Detach();
}
// load ns / ttl from page
page_tbl.Select_in__id(catlink_loader);
grp.Itms_((Xoctg_catpage_itm[])hash.To_ary_and_clear(Xoctg_catpage_itm.class));
// set data for Next 200 / Previous 200
if (itm_zth != null) {
if (version == 4) {
Xowd_page_itm tmp_pg = new Xowd_page_itm();
page_tbl.Select_by_id(tmp_pg, itm_zth.Page_id());
Xoa_ttl zth_ttl = wiki.Ttl_parse(tmp_pg.Ns_id(), tmp_pg.Ttl_page_db());
itm_zth.Page_ttl_(zth_ttl);
itm_zth.Sortkey_handle_make(Bry_bfr_.New(), grp.Itms__get_at(grp.Itms__len() - 1).Sortkey_handle());
grp.Next_sortkey_(itm_zth.Sortkey_handle());
}
else
grp.Next_sortkey_(itm_zth.Sortkey_handle());
}
}
public static byte[] Build_sortkey_val(Bry_bfr sortkey_val_bfr, byte version, Xoctg_collation_mgr collation_mgr, byte[] url_sortkey) {
// find \n and ignore everything after it; needed else "< 'A\nA'" will pull up "A"; NOTE: can't find logic in MediaWiki CategoryViewer.php; DATE:2016-10-11
// ALSO: needed for v2 else SQL will literally have WHERE cl_sortkey = 'A\nA';
byte[] tmp_sortkey = url_sortkey;
int nl_pos = Bry_find_.Find_fwd(tmp_sortkey, Byte_ascii.Nl);
if (nl_pos != Bry_find_.Not_found)
tmp_sortkey = Bry_.Mid(tmp_sortkey, 0, nl_pos);
if (version == 4) {
if (Bry_.Len_gt_0(url_sortkey)) {
// make sortkey_val
sortkey_val_bfr.Add_byte(Byte_ascii.Ltr_x).Add_byte_apos();
gplx.core.encoders.Hex_utl_.Encode_bfr(sortkey_val_bfr, collation_mgr.Get_sortkey(tmp_sortkey));
sortkey_val_bfr.Add_byte_apos();
}
else
sortkey_val_bfr.Add_byte_apos().Add_byte_apos();
}
else
sortkey_val_bfr.Add_byte_apos().Add(Db_sql_.Escape_arg(tmp_sortkey)).Add_byte_apos();
return sortkey_val_bfr.To_bry_and_clear();
}
}

View File

@@ -0,0 +1,39 @@
/*
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.addons.wikis.ctgs.htmls.catpages.dbs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.wikis.*; import gplx.xowa.addons.wikis.ctgs.*; import gplx.xowa.addons.wikis.ctgs.htmls.*; import gplx.xowa.addons.wikis.ctgs.htmls.catpages.*;
import org.junit.*; import gplx.core.tests.*; import gplx.xowa.apps.urls.*;
import gplx.xowa.langs.*; import gplx.xowa.addons.wikis.ctgs.htmls.catpages.langs.*;
public class Xoctg_catlink_loader__tst {
private final Xoctg_catlink_loader__fxt fxt = new Xoctg_catlink_loader__fxt();
@Test public void Build_sortkey_val__v4() { // PURPOSE: remove "\n" and afterwards else will omit 1 record
fxt.Test__build_sortkey_sql(4, "A\nA", "x'41'"); // fails if "x'410a41'"
}
@Test public void Build_sortkey_val__v2() { // PURPOSE: remove "\n" and afterwards else SQL will be malformed
fxt.Test__build_sortkey_sql(2, "A\nA", "'A'"); // fails if "'A\nA'"
}
}
class Xoctg_catlink_loader__fxt {
public void Test__build_sortkey_sql(int version, String sortkey, String expd) {
Xoae_app app = Xoa_app_fxt.Make__app__edit();
Xowe_wiki wiki = Xoa_app_fxt.Make__wiki__edit(app, "de.wikipedia.org"); // use "de.wikipedia.org" for simple "uppercase" collation
Xoctg_collation_mgr collation_mgr = new Xoctg_collation_mgr(wiki);
Bry_bfr bfr = Bry_bfr_.New();
Gftest.Eq__str(expd, Xoctg_catlink_loader.Build_sortkey_val(bfr, Byte_.By_int(version), collation_mgr, Bry_.new_u8(sortkey)));
}
}

View File

@@ -0,0 +1,71 @@
/*
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.addons.wikis.ctgs.htmls.catpages.dbs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.wikis.*; import gplx.xowa.addons.wikis.ctgs.*; import gplx.xowa.addons.wikis.ctgs.htmls.*; import gplx.xowa.addons.wikis.ctgs.htmls.catpages.*;
import gplx.dbs.*; import gplx.xowa.wikis.data.*; import gplx.xowa.wikis.data.tbls.*; import gplx.xowa.addons.wikis.ctgs.dbs.*;
import gplx.xowa.addons.wikis.ctgs.htmls.catpages.doms.*; import gplx.xowa.addons.wikis.ctgs.htmls.catpages.urls.*; import gplx.xowa.addons.wikis.ctgs.htmls.catpages.dbs.*;
public class Xoctg_catpage_loader {
public Xoctg_catpage_ctg Load_ctg_or_null(Xow_wiki wiki, Xoctg_catpage_mgr catpage_mgr, Xoctg_catpage_url cat_url, Xoa_ttl cat_ttl, int limit) {
// get cat_id from page_tbl
Xow_db_mgr db_mgr = wiki.Data__core_mgr();
Xowd_page_tbl page_tbl = db_mgr.Db__core().Tbl__page();
Xowd_page_itm page_itm = page_tbl.Select_by_ttl_as_itm_or_null(cat_ttl);
if (page_itm == null) {
Gfo_usr_dlg_.Instance.Warn_many("", "", "category does not exist in page table; ttl=~{0}", cat_ttl.Full_db());
return null;
}
int cat_id = page_itm.Id();
// get cat_core_itm from cat_core_tbl
Xowd_cat_core_tbl cat_core_tbl = Xodb_cat_db_.Get_cat_core_or_fail(db_mgr);
Xowd_category_itm cat_core_itm = cat_core_tbl.Select(cat_id);
if (cat_core_itm == Xowd_category_itm.Null) {
Gfo_usr_dlg_.Instance.Log_many("", "", "category does not exist in cat_core table; ttl=~{0}", cat_ttl.Full_db()); // NOTE: this is not rare as Category pages can be created as deliberately empty, or as redirects; fr.w:Catégorie:Utilisateur_hess-4; DATE:2016-09-12
return null;
}
// load itms from cat_link_db for each grp_tid
Xoctg_catpage_ctg rv = new Xoctg_catpage_ctg(cat_id, cat_ttl.Page_txt());
for (byte grp_tid = Xoa_ctg_mgr.Tid__subc; grp_tid < Xoa_ctg_mgr.Tid___max; ++grp_tid) {
Xoctg_catpage_grp grp = rv.Grp_by_tid(grp_tid);
grp.Count_all_(cat_core_itm.Count_by_tid(grp_tid)); // set total counts per grp based on cat_core_itm;
// init url_vars
boolean url_is_from = cat_url.Grp_fwds()[grp_tid]; // EX: "pagefrom=A"; "pageuntil=B"
byte[] url_sortkey = cat_url.Grp_keys()[grp_tid];
// set prev / next props to dflt values
if (url_is_from) { // url is from; EX: from=A
if (Bry_.Len_eq_0(url_sortkey)) // no sortkey specified for group, so group always starts with 1st itm -> disable previous link
grp.Prev_disable_(true);
}
else { // url is until; EX: until=A
grp.Prev_disable_(true); // default prev link to disabled; loader will load 201 items and set to false if 201st found
grp.Next_sortkey_(url_sortkey); // next sortkey is always sortkey of until url arg;
}
// load links
Xoctg_catlink_loader loader = new Xoctg_catlink_loader();
if (cat_core_itm.File_idx() == -1) // v3 or v4: loop over all cat_link dbs {
loader.Make_attach_mgr__v3_v4 (db_mgr, cat_core_tbl.Conn());
else // v2: use cat_link_db
loader.Make_attach_mgr__v2 (db_mgr, cat_core_itm.File_idx());
loader.Run(rv, wiki, catpage_mgr, page_tbl, cat_id, grp_tid, url_is_from, url_sortkey, limit);
}
return rv;
}
}

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.addons.wikis.ctgs.htmls.catpages.dbs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.wikis.*; import gplx.xowa.addons.wikis.ctgs.*; import gplx.xowa.addons.wikis.ctgs.htmls.*; import gplx.xowa.addons.wikis.ctgs.htmls.catpages.*;
import gplx.dbs.*; import gplx.xowa.wikis.data.tbls.*;
import gplx.xowa.addons.wikis.ctgs.htmls.catpages.doms.*;
public class Xoctg_page_loader implements Select_in_cbk {
private final Xow_wiki wiki;
private final Ordered_hash hash = Ordered_hash_.New();
public Xoctg_page_loader(Xow_wiki wiki) {this.wiki = wiki;}
public Ordered_hash Hash() {return hash;}
public int Hash_max() {return hash.Len();}
public void Write_sql(Bry_bfr bfr, int idx) {
Xoctg_catpage_itm itm = (Xoctg_catpage_itm)hash.Get_at(idx);
bfr.Add_int_variable(itm.Page_id());
}
public void Read_data(Db_rdr rdr) {
// read values from page_tbl
int page_id = rdr.Read_int("page_id");
int page_ns = rdr.Read_int("page_namespace");
byte[] page_ttl = rdr.Read_bry_by_str("page_title");
// get itm and set data
Xoctg_catpage_itm itm = (Xoctg_catpage_itm)hash.Get_by(page_id);
if (itm == null) return; // NOTE: itms can exist in cat_links_tbl, but not in page_tbl; EX:User:Any_page
itm.Page_ttl_(wiki.Ttl_parse(page_ns, page_ttl));
}
}

View File

@@ -17,12 +17,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.wikis.ctgs.htmls.catpages.doms; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.wikis.*; import gplx.xowa.addons.wikis.ctgs.*; import gplx.xowa.addons.wikis.ctgs.htmls.*; import gplx.xowa.addons.wikis.ctgs.htmls.catpages.*;
public class Xoctg_catpage_ctg {
public Xoctg_catpage_ctg(byte[] name) {this.name = name;}
public byte[] Name() {return name;} private final byte[] name;
public Xoctg_catpage_grp Subcs() {return subcs;} private final Xoctg_catpage_grp subcs = new Xoctg_catpage_grp(Xoa_ctg_mgr.Tid__subc);
public Xoctg_catpage_grp Pages() {return pages;} private final Xoctg_catpage_grp pages = new Xoctg_catpage_grp(Xoa_ctg_mgr.Tid__page);
public Xoctg_catpage_grp Files() {return files;} private final Xoctg_catpage_grp files = new Xoctg_catpage_grp(Xoa_ctg_mgr.Tid__file);
public int Total() {return subcs.Itms__len() + pages.Itms__len() + files.Itms__len();}
public Xoctg_catpage_ctg(int id, byte[] name) {
this.id = id; this.name = name;
}
public int Id() {return id;} private final int id;
public byte[] Name() {return name;} private final byte[] name;
public Xoctg_catpage_grp Subcs() {return subcs;} private final Xoctg_catpage_grp subcs = new Xoctg_catpage_grp(Xoa_ctg_mgr.Tid__subc);
public Xoctg_catpage_grp Pages() {return pages;} private final Xoctg_catpage_grp pages = new Xoctg_catpage_grp(Xoa_ctg_mgr.Tid__page);
public Xoctg_catpage_grp Files() {return files;} private final Xoctg_catpage_grp files = new Xoctg_catpage_grp(Xoa_ctg_mgr.Tid__file);
public int Total() {return subcs.Count_all() + pages.Count_all() + files.Count_all();}
public Xoctg_catpage_grp Grp_by_tid(byte tid) {
switch (tid) {
case Xoa_ctg_mgr.Tid__subc: return subcs;
@@ -31,10 +34,4 @@ public class Xoctg_catpage_ctg {
default: throw Err_.new_unhandled(tid);
}
}
public void Make_itms() {
for (byte i = 0; i < Xoa_ctg_mgr.Tid___max; ++i) {
Xoctg_catpage_grp grp = Grp_by_tid(i);
grp.Itms__make();
}
}
}

View File

@@ -17,27 +17,38 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.wikis.ctgs.htmls.catpages.doms; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.wikis.*; import gplx.xowa.addons.wikis.ctgs.*; import gplx.xowa.addons.wikis.ctgs.htmls.*; import gplx.xowa.addons.wikis.ctgs.htmls.catpages.*;
public class Xoctg_catpage_grp {
private final List_adp tmp_list = List_adp_.New();
private Xoctg_catpage_itm[] itms = Xoctg_catpage_itm.Ary_empty;
private byte[] next_sortkey = Bry_.Empty;
public Xoctg_catpage_grp(byte tid) {this.tid = tid;}
public byte Tid() {return tid;} private byte tid; // subc|page|file
public int Bgn() {return bgn;} private int bgn; // idx of 1st item; EX: 200
public int End() {return end;} private int end; // idx of nth item + 1; EX: 399
public int Count_by_page() {return end - bgn;} // count of items on page; EX: 200
public int Itms__len() {return itms_len;} private int itms_len; // count of items in entire category; EX: 456
public Xoctg_catpage_itm[] Itms() {return itms;} private Xoctg_catpage_itm[] itms = Xoctg_catpage_itm.Ary_empty;
public Xoctg_catpage_itm Itms__get_at(int i) {
if (i < 0 || i >= itms.length) throw Err_.new_wo_type("catpage: i is out of bounds", "i", i, "len", itms.length, "tid", tid);
Xoctg_catpage_itm rv = itms[i]; if (rv == null) throw Err_.new_wo_type("ctg.view: itm is null", "i", i, "len", itms.length, "tid", tid);
return rv;
public byte Tid() {return tid;} private byte tid; // subc|page|file
public int Count_all() {return count_all;} private int count_all; // count of items in entire category; EX: 456
public boolean Prev_disable() {return prev_disable;} private boolean prev_disable; // prev_link: disable link
public byte[] Next_sortkey() {return next_sortkey;} // next_link: set sortkey
public int Itms__len() {return itms.length;}
public Xoctg_catpage_itm Itms__get_at(int i) {return itms[i];}
public void Count_all_(int v) {this.count_all = v;}
public void Prev_disable_(boolean v) {this.prev_disable = v;}
public void Next_sortkey_(byte[] v) {this.next_sortkey = v;}
public void Itms_(Xoctg_catpage_itm[] v) {
this.itms = v;
Array_.Sort(itms, new Xoctg_catpage_itm_sorter()); // NOTE: need to reorder for page_until b/c ORDER BY DESC
// make sortkey_handle
Bry_bfr tmp_bfr = Bry_bfr_.New();
int itms_len = itms.length;
byte[] prv_sortkey_handle = Bry_.Empty;
for (int i = 0; i < itms_len; ++i) {
Xoctg_catpage_itm itm = itms[i];
prv_sortkey_handle = itm.Sortkey_handle_make(tmp_bfr, prv_sortkey_handle);
}
}
public void Itms__add(Xoctg_catpage_itm sub) {tmp_list.Add(sub);}
public void Itms__make() {
tmp_list.Sort_by(Xoctg_catpage_itm_sorter__sort_key.Sorter);
itms = (Xoctg_catpage_itm[])tmp_list.To_ary_and_clear(Xoctg_catpage_itm.class);
bgn = 0;
end = itms_len = itms.length;
}
public void Rng_(int bgn, int end) {
this.bgn = bgn; this.end = end;
}
class Xoctg_catpage_itm_sorter implements gplx.core.lists.ComparerAble {
public int compare(Object lhsObj, Object rhsObj) {
Xoctg_catpage_itm lhs = (Xoctg_catpage_itm)lhsObj;
Xoctg_catpage_itm rhs = (Xoctg_catpage_itm)rhsObj;
return Bry_.Compare(lhs.Sortkey_binary(), rhs.Sortkey_binary());
}
}

View File

@@ -16,17 +16,86 @@ 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.addons.wikis.ctgs.htmls.catpages.doms; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.wikis.*; import gplx.xowa.addons.wikis.ctgs.*; import gplx.xowa.addons.wikis.ctgs.htmls.*; import gplx.xowa.addons.wikis.ctgs.htmls.catpages.*;
import gplx.dbs.*; import gplx.xowa.wikis.nss.*;
public class Xoctg_catpage_itm {
public Xoctg_catpage_itm(int page_id, Xoa_ttl page_ttl, byte[] sort_key) {
private byte version;
Xoctg_catpage_itm(byte version, byte grp_tid, int page_id, byte[] sortkey_prefix, byte[] sortkey_binary) {
this.version = version;
this.grp_tid = grp_tid;
this.page_id = page_id;
this.page_ttl = page_ttl;
this.sort_key = sort_key.length == 0 ? page_ttl.Page_db() : sort_key; // v1 will not have sortkey data; PAGE:s.w:Category:Computer_science DATE:2015-11-22
this.page_ttl = Xoa_ttl.Null;
this.sortkey_prefix = sortkey_prefix;
this.sortkey_handle = sortkey_prefix; // default handle to sortkey_prefix;
this.sortkey_binary = sortkey_binary;
}
public byte Grp_tid() {return grp_tid;} private final byte grp_tid; // v2-v4:cl_type_id; subc,page,file
public int Page_id() {return page_id;} private final int page_id; // v2-v4:cl_from
public byte[] Sortkey_prefix() {return sortkey_prefix;} private byte[] sortkey_prefix; // v2-v3:cl_sortkey; v4:cl_sortkey_prefix
public byte[] Sortkey_handle() {return sortkey_handle;} private byte[] sortkey_handle; // v2-v3:cl_sortkey; v4:cl_sortkey_prefix\nttl_txt; never "cl_sortkey" which is binary ICU value;
public byte[] Sortkey_binary() {return sortkey_binary;} private byte[] sortkey_binary; // v2-v4:cl_sortkey; note that v4 is binary icu value
public Xoa_ttl Page_ttl() {return page_ttl;} private Xoa_ttl page_ttl;
public void Page_ttl_(Xoa_ttl ttl) {
this.page_ttl = ttl;
// sortkey_prefix will be blank for v2; use page_ttl; PAGE:s.w:Category:Computer_science DATE:2015-11-22
if (version == Version__2 && Bry_.Len_eq_0(sortkey_prefix))
sortkey_prefix = page_ttl.Page_txt();
// sortkey_binary will be blank for v2,v3; use page_ttl; PAGE:fr.w:Article_contenant_un_appel_à_traduction_en_anglais; DATE:2016-10-11
if (version != Version__4 && Bry_.Len_eq_0(sortkey_binary)) sortkey_binary = page_ttl.Page_txt();
}
public byte[] Sortkey_handle_make(Bry_bfr tmp_bfr, byte[] prv_sortkey_handle) {
// page.tbl missing even though in cat_link.tbl; happens for "User:" namespace pages;
if (page_ttl == Xoa_ttl.Null) {
// sortkey_prefix exists; happens for [[Category:A]] as opposed to [[Category:A|some_sortkey_prefix]]
if (Bry_.Len_gt_0(sortkey_prefix)) {
sortkey_handle = sortkey_prefix;
return sortkey_handle; // set sortkey_prefix as new prv_sortkey_handle;
}
else {
// set sortkey_handle to "prv_sortkey" + "page_id"; needed for multiple "missing" catlinks which span 200 page boundaries
tmp_bfr.Add(prv_sortkey_handle);
tmp_bfr.Add_byte_nl();
tmp_bfr.Add_int_variable(page_id);
sortkey_handle = tmp_bfr.To_bry_and_clear();
return prv_sortkey_handle;
}
}
// page.tbl exists
else {
// "In UCA, tab is the only character that can sort above LF so we strip both of them from the original prefix."; Title.php|getCategorySortKey
if (sortkey_prefix.length == 0) {
sortkey_handle = page_ttl.Page_txt();
}
else {
byte[] sortkey_normalized = Bry_.Replace(sortkey_prefix, Sortkey_prefix_replace__src, Sortkey_prefix_replace__trg);
tmp_bfr.Add(sortkey_normalized);
tmp_bfr.Add_byte_nl().Add(page_ttl.Page_txt()); // "$prefix\n$unprefixed";
sortkey_handle = tmp_bfr.To_bry_and_clear();
}
return sortkey_handle;
}
}
public int Page_id() {return page_id;} private int page_id;
public Xoa_ttl Page_ttl() {return page_ttl;} private Xoa_ttl page_ttl;
public byte[] Sort_key() {return sort_key;} private byte[] sort_key;
public boolean Missing() {return missing;} private boolean missing; // not used; remove?;
public void Missing_y_() {missing = true;}
public static final Xoctg_catpage_itm[] Ary_empty = new Xoctg_catpage_itm[0];
public static Xoctg_catpage_itm New_by_rdr(Db_rdr rdr, byte version) {
byte[] sortkey_binary = Bry_.Empty;
byte[] sortkey_prefix = Bry_.Empty;
if (version == Version__4) {
sortkey_binary = rdr.Read_bry("cl_sortkey");
sortkey_prefix = rdr.Read_bry_by_str("cl_sortkey_prefix");
}
else {
sortkey_binary = Bry_.Empty;
sortkey_prefix = rdr.Read_bry_by_str("cl_sortkey");
}
return new Xoctg_catpage_itm(version, rdr.Read_byte("cl_type_id"), rdr.Read_int("cl_from"), sortkey_prefix, sortkey_binary);
}
public static Xoctg_catpage_itm New_by_ttl(byte grp_tid, int page_id, Xoa_ttl ttl) { // TEST
Xoctg_catpage_itm rv = new Xoctg_catpage_itm(Version__4, grp_tid, page_id, ttl.Page_txt(), Bry_.Empty);
rv.Page_ttl_(ttl);
return rv;
}
private static final byte Version__2 = 2, Version__4 = 4;
private static final byte[] Sortkey_prefix_replace__src = Bry_.new_a7("\n\t"), Sortkey_prefix_replace__trg = Bry_.new_a7(" ");
}

View File

@@ -16,15 +16,28 @@ 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.addons.wikis.ctgs.htmls.catpages.doms; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.wikis.*; import gplx.xowa.addons.wikis.ctgs.*; import gplx.xowa.addons.wikis.ctgs.htmls.*; import gplx.xowa.addons.wikis.ctgs.htmls.catpages.*;
public class Xoctg_catpage_itm_sorter__sort_key implements gplx.core.lists.ComparerAble, gplx.core.lists.binary_searches.Binary_comparer {
public int compare(Object lhsObj, Object rhsObj) {
Xoctg_catpage_itm lhs = (Xoctg_catpage_itm)lhsObj;
Xoctg_catpage_itm rhs = (Xoctg_catpage_itm)rhsObj;
return Bry_.Compare(lhs.Sort_key(), rhs.Sort_key());
public class Xoctg_catpage_tmp {
private final List_adp subc_list = List_adp_.New(), page_list = List_adp_.New(), file_list = List_adp_.New();
public void Add(Xoctg_catpage_itm itm) {
List_adp list = Get_by_tid(itm.Grp_tid());
list.Add(itm);
}
public int Compare_val_to_obj(Object val, Object obj) {
Xoctg_catpage_itm itm = (Xoctg_catpage_itm)obj;
return Bry_.Compare((byte[])val, itm.Sort_key());
public void Make_by_ctg(Xoctg_catpage_ctg ctg) { // TEST:
for (byte tid = 0; tid < Xoa_ctg_mgr.Tid___max; ++tid)
Make_by_grp(ctg.Grp_by_tid(tid));
}
public void Make_by_grp(Xoctg_catpage_grp grp) {
byte tid = grp.Tid();
List_adp list = Get_by_tid(tid);
if (list.Len() == 0) return;
grp.Itms_((Xoctg_catpage_itm[])list.To_ary_and_clear(Xoctg_catpage_itm.class));
}
private List_adp Get_by_tid(byte tid) {
switch (tid) {
case Xoa_ctg_mgr.Tid__subc: return subc_list;
case Xoa_ctg_mgr.Tid__page: return page_list;
case Xoa_ctg_mgr.Tid__file: return file_list;
default: throw Err_.new_unhandled_default(tid);
}
}
public static final Xoctg_catpage_itm_sorter__sort_key Sorter = new Xoctg_catpage_itm_sorter__sort_key();
}

View File

@@ -16,7 +16,7 @@ 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.addons.wikis.ctgs.htmls.catpages.fmts; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.wikis.*; import gplx.xowa.addons.wikis.ctgs.*; import gplx.xowa.addons.wikis.ctgs.htmls.*; import gplx.xowa.addons.wikis.ctgs.htmls.catpages.*;
import gplx.xowa.langs.*; import gplx.xowa.langs.msgs.*; import gplx.xowa.htmls.core.htmls.*; import gplx.langs.htmls.encoders.*;
import gplx.xowa.langs.*; import gplx.xowa.langs.msgs.*; import gplx.xowa.htmls.core.htmls.*; import gplx.langs.htmls.encoders.*; import gplx.core.intls.ucas.*;
import gplx.xowa.wikis.nss.*;
import gplx.xowa.addons.wikis.ctgs.htmls.catpages.doms.*; import gplx.xowa.addons.wikis.ctgs.htmls.catpages.urls.*;
public class Xoctg_fmt_grp { // subc|page|file
@@ -32,47 +32,43 @@ public class Xoctg_fmt_grp { // subc|page|file
this.url_arg_bgn = url_arg_bgn; this.url_arg_end = url_arg_end; this.div_id = div_id;
}
public Xoctg_fmt_itm_base Itm_fmt() {return itm_fmt;} private final Xoctg_fmt_itm_base itm_fmt;
public void Write_catpage_grp(Bry_bfr bfr, Xow_wiki wiki, Xol_lang_itm lang, Xoctg_catpage_ctg dom_ctg, int grp_max) { // TEST:
public void Write_catpage_grp(Bry_bfr bfr, Xow_wiki wiki, Xol_lang_itm lang, Uca_ltr_extractor ltr_extractor, Xoctg_catpage_ctg dom_ctg, int grp_max) { // TEST:
Xoctg_catpage_grp dom_grp = dom_ctg.Grp_by_tid(tid);
if (dom_grp.Itms__len() == 0) return; // no items in grp; EX: 0 items in File
if (dom_grp.Count_all() == 0) return; // no items in grp; EX: 0 items in File
// get msgs
Xow_msg_mgr msg_mgr = wiki.Msg_mgr();
byte[] msg_label_bry = msg_mgr.Val_by_id_args(msg_label_id, dom_ctg.Name());
byte[] msg_stats_bry = msg_mgr.Val_by_id_args(msg_stats_id, dom_grp.Count_by_page(), dom_grp.Itms__len());
byte[] msg_stats_bry = msg_mgr.Val_by_id_args(msg_stats_id, dom_grp.Itms__len(), dom_grp.Count_all());
// get nav html; next / previous 200
Xoa_ttl ctg_ttl = wiki.Ttl_parse(Xow_ns_.Tid__category, dom_ctg.Name());
byte[] nav_html = this.Bld_bwd_fwd(wiki, ctg_ttl, dom_grp, grp_max);
// init grp; write
itms_fmt.Init_from_grp(wiki, dom_grp);
itms_fmt.Init_from_grp(wiki, dom_grp, ltr_extractor);
Fmt__ctg.Bld_many(bfr, div_id, msg_label_bry, msg_stats_bry, nav_html, lang.Key_bry(), lang.Dir_ltr_bry(), itms_fmt);
}
public byte[] Bld_bwd_fwd(Xow_wiki wiki, Xoa_ttl ttl, Xoctg_catpage_grp view_grp, int grp_max) { // TEST:
if (view_grp.Itms__len() < grp_max) return Bry_.Empty; // < 200; never show;
if (view_grp.Count_all() < grp_max) return Bry_.Empty; // < 200; never show;
Bry_bfr bfr = wiki.Utl__bfr_mkr().Get_k004();
Html_nav_bry(bfr, wiki, ttl, view_grp, grp_max, Bool_.N);
Html_nav_bry(bfr, wiki, ttl, view_grp, grp_max, Bool_.Y);
return bfr.To_bry_and_rls();
}
private void Html_nav_bry(Bry_bfr bfr, Xow_wiki wiki, Xoa_ttl ttl, Xoctg_catpage_grp grp, int grp_max, boolean type_is_next) {
private void Html_nav_bry(Bry_bfr bfr, Xow_wiki wiki, Xoa_ttl ttl, Xoctg_catpage_grp grp, int grp_max, boolean url_is_from) {
Bry_bfr href_bfr = wiki.Utl__bfr_mkr().Get_b512();
// get nav_href; EX:href="/wiki/Category:Ctg_1?pageuntil=A1#mw-pages"
wiki.Html__href_wtr().Build_to_bfr(href_bfr, wiki.App(), Xoh_wtr_ctx.Basic, wiki.Domain_bry(), ttl);
byte[] arg_idx_lbl = null; byte[] arg_sortkey = null;
if (type_is_next) {
if (url_is_from) {
arg_idx_lbl = url_arg_bgn;
// get next category after last one on page; needed for "Next 200 (href=Cat_201)"
int nxt_idx = grp.End();
if (nxt_idx == grp.Itms__len()) --nxt_idx; // if last item, then grp.End() does not exist; just use last one
arg_sortkey = grp.Itms__get_at(nxt_idx).Sort_key();
arg_sortkey = grp.Next_sortkey();
}
else {
arg_idx_lbl = url_arg_end;
arg_sortkey = grp.Itms__get_at(grp.Bgn()).Sort_key(); // use 1st item as sortkey for "until" args
arg_sortkey = grp.Itms__get_at(0).Sortkey_handle(); // use 1st item as sortkey for "until" args
}
href_bfr.Add_byte(Byte_ascii.Question).Add(arg_idx_lbl).Add_byte(Byte_ascii.Eq); // filefrom=
Gfo_url_encoder_.Http_url.Encode(href_bfr, arg_sortkey); // Abc
@@ -80,12 +76,12 @@ public class Xoctg_fmt_grp { // subc|page|file
byte[] nav_href = href_bfr.To_bry_and_rls();
// get nav_text
int nav_text_id = type_is_next ? Xol_msg_itm_.Id_next_results : Xol_msg_itm_.Id_prev_results;
int nav_text_id = url_is_from ? Xol_msg_itm_.Id_next_results : Xol_msg_itm_.Id_prev_results;
byte[] nav_text = wiki.Msg_mgr().Val_by_id_args(nav_text_id, grp_max); // next 200 / previous 200
// print text if 1st / zth page; else, print html
if ( ( type_is_next && grp.Bgn() + grp_max > grp.Itms__len())
|| (!type_is_next && grp.Bgn() - grp_max < 0)
if ( ( url_is_from && Bry_.Len_eq_0(grp.Next_sortkey()))
|| (!url_is_from && grp.Prev_disable())
)
Fmt__nav__text.Bld_many(bfr, nav_text);
else

View File

@@ -17,27 +17,32 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.wikis.ctgs.htmls.catpages.fmts; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.wikis.*; import gplx.xowa.addons.wikis.ctgs.*; import gplx.xowa.addons.wikis.ctgs.htmls.*; import gplx.xowa.addons.wikis.ctgs.htmls.catpages.*;
import gplx.langs.htmls.*; import gplx.xowa.htmls.*; import gplx.xowa.htmls.hrefs.*; import gplx.xowa.htmls.core.wkrs.lnkis.htmls.*; import gplx.xowa.htmls.core.htmls.*;
import gplx.xowa.langs.*; import gplx.xowa.langs.msgs.*;
import gplx.xowa.langs.*; import gplx.xowa.langs.msgs.*; import gplx.core.intls.ucas.*;
import gplx.xowa.users.history.*;
import gplx.xowa.addons.wikis.ctgs.htmls.catpages.*; import gplx.xowa.addons.wikis.ctgs.htmls.catpages.doms.*;
public abstract class Xoctg_fmt_itm_base implements gplx.core.brys.Bfr_arg {
private final Bry_bfr tmp_bfr = Bry_bfr_.New();
private Xow_wiki wiki;
private Xoctg_catpage_grp grp;
private Uca_ltr_extractor ltr_extractor;
private byte[] ltr_cur; private int loop_bgn; private int col_end;
public int Loop_end_idx() {return loop_end_idx;} private int loop_end_idx;
public boolean Loop_ends_at_col() {return loop_ends_at_col;} private boolean loop_ends_at_col;
public void Col_end_(int col_bgn, int col_idx) {
this.col_end = col_bgn + Calc_col_len(grp.Count_by_page(), col_idx, Cols_max);
this.col_end = col_bgn + Calc_col_len(grp.Itms__len(), col_idx, Cols_max);
}
public void Init_from_ltr(Xow_wiki wiki, Xoctg_catpage_grp grp, Uca_ltr_extractor ltr_extractor) {
this.wiki = wiki;
this.grp = grp;
this.ltr_extractor = ltr_extractor;
}
public void Init_from_ltr(Xow_wiki wiki, Xoctg_catpage_grp grp) {this.wiki = wiki; this.grp = grp;}
public void Set_ltr_and_bgn(byte[] ltr_cur, int loop_bgn) {this.ltr_cur = ltr_cur; this.loop_bgn = loop_bgn;}
public void Bfr_arg__add(Bry_bfr bfr) {
// init vars
Xoh_href_parser href_parser = wiki.App().Html__href_parser();
Xou_history_mgr history_mgr = wiki.App().User().History_mgr();
int grp_end = grp.End();
int grp_end = grp.Itms__len();
// loop over itms;
for (int i = loop_bgn; i < grp_end; i++) {
@@ -50,28 +55,30 @@ public abstract class Xoctg_fmt_itm_base implements gplx.core.brys.Bfr_arg {
// get sortkey
Xoctg_catpage_itm itm = grp.Itms__get_at(i);
byte[] itm_sortkey = itm.Sort_key();
byte[] itm_sortkey = itm.Sortkey_handle();
// reached end of ltr; exit
if (!Bry_.Has_at_bgn(itm_sortkey, ltr_cur, 0, itm_sortkey.length)) {
byte[] ltr_1st = ltr_extractor.Get_1st_ltr(itm_sortkey);
if (!Bry_.Has_at_bgn(ltr_1st, ltr_cur, 0, ltr_1st.length)) {
loop_end_idx = i;
loop_ends_at_col = i == col_end;
return;
}
Bld_html(bfr, wiki, history_mgr, href_parser, itm, itm.Page_ttl());
Xoa_ttl itm_ttl = itm.Page_ttl();
Bld_html(bfr, wiki, history_mgr, href_parser, itm, itm_ttl);
}
loop_end_idx = grp_end;
loop_ends_at_col = true;
}
@gplx.Virtual public void Bld_html(Bry_bfr bfr, Xow_wiki wiki, Xou_history_mgr history_mgr, Xoh_href_parser href_parser, Xoctg_catpage_itm itm, Xoa_ttl ttl) {
byte[] itm_full_ttl = Gfh_utl.Escape_html_as_bry(tmp_bfr, ttl.Full_txt_w_ttl_case());// NOTE: ttl.Full_txt() to get full ns; EX: Template:A instead of just "A"
if (itm.Missing())
fmt_missing.Bld_many(bfr, itm.Page_id(), itm_full_ttl);
if (ttl == Xoa_ttl.Null)
fmt_missing.Bld_many(bfr, itm.Page_id(), itm.Sortkey_handle());
else {
byte[] itm_full_ttl = Gfh_utl.Escape_html_as_bry(tmp_bfr, ttl.Full_txt_w_ttl_case());// NOTE: ttl.Full_txt() to get full ns; EX: Template:A instead of just "A"
byte[] itm_href = wiki.Html__href_wtr().Build_to_bry(wiki, ttl);
byte[] itm_atr_cls = Xoh_lnki_wtr.Lnki_cls_visited(history_mgr, wiki.Domain_bry(), ttl.Page_txt()); // NOTE: must be ttl.Page_txt() in order to match Xou_history_mgr.Add
fmt_exists.Bld_many(bfr, itm_href, itm_atr_cls, itm_full_ttl, itm_full_ttl);
fmt_exists.Bld_many(bfr, itm_href, itm_atr_cls, itm_full_ttl, itm_full_ttl, gplx.core.encoders.Hex_utl_.Encode_bry(itm.Sortkey_binary()));
}
}
private static final Bry_fmt
@@ -81,7 +88,7 @@ public abstract class Xoctg_fmt_itm_base implements gplx.core.brys.Bfr_arg {
)
, fmt_exists = Bry_fmt.Auto_nl_skip_last
( ""
, " <li><a href=\"~{itm_href}\"~{itm_atr_cls} title=\"~{itm_title}\">~{itm_text}</a></li>"
, " <li><a href=\"~{itm_href}\"~{itm_atr_cls} title=\"~{itm_title}\">~{itm_text}</a><!--~{itm_sortkey}--></li>"
)
;
public static final int Cols_max = 3;

View File

@@ -17,23 +17,25 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.addons.wikis.ctgs.htmls.catpages.fmts; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.wikis.*; import gplx.xowa.addons.wikis.ctgs.*; import gplx.xowa.addons.wikis.ctgs.htmls.*; import gplx.xowa.addons.wikis.ctgs.htmls.catpages.*;
import gplx.xowa.htmls.core.htmls.*;
import gplx.xowa.langs.*; import gplx.xowa.langs.msgs.*;
import gplx.xowa.addons.wikis.ctgs.htmls.catpages.*; import gplx.xowa.addons.wikis.ctgs.htmls.catpages.doms.*;
import gplx.xowa.langs.*; import gplx.xowa.langs.msgs.*; import gplx.core.intls.ucas.*;
import gplx.xowa.addons.wikis.ctgs.htmls.catpages.*; import gplx.xowa.addons.wikis.ctgs.htmls.catpages.doms.*;
public class Xoctg_fmt_ltr implements gplx.core.brys.Bfr_arg { // "A", "B", "C cont."
private final Xoctg_fmt_itm_base itm_fmt;
private Xoctg_catpage_grp grp;
private byte[] msg__list_continues;
private Uca_ltr_extractor ltr_extractor;
public Xoctg_fmt_ltr(Xoctg_fmt_itm_base itm_fmt) {
this.itm_fmt = itm_fmt;
}
public void Init_from_grp(Xow_wiki wiki, Xoctg_catpage_grp grp) {
public void Init_from_grp(Xow_wiki wiki, Xoctg_catpage_grp grp, Uca_ltr_extractor ltr_extractor) {
this.grp = grp;
this.msg__list_continues = wiki.Msg_mgr().Val_by_id(Xol_msg_itm_.Id_list_continues);
itm_fmt.Init_from_ltr(wiki, grp);
this.ltr_extractor = ltr_extractor;
itm_fmt.Init_from_ltr(wiki, grp, ltr_extractor);
}
public void Bfr_arg__add(Bry_bfr bfr) {
int itm_idx = grp.Bgn(); // itm idx; EX: idx=201 in len=500
int itm_end = grp.End();
int itm_idx = 0;
int itm_end = grp.Itms__len();
int itms_len = itm_end - itm_idx; if (itms_len == 0) return; // no items; exit
int col_idx = 0; // col idx; EX: 3 cols; idx = 0, 1, 2
@@ -45,8 +47,9 @@ public class Xoctg_fmt_ltr implements gplx.core.brys.Bfr_arg { // "A", "B", "C c
Xoctg_catpage_itm itm = grp.Itms__get_at(itm_idx);
// get ltr_head; EX: "C" or "C cont."
byte[] itm_sortkey = itm.Sort_key();
byte[] ltr_cur = gplx.core.intls.Utf8_.Get_char_at_pos_as_bry(itm_sortkey, 0);
byte[] itm_sortkey = itm.Sortkey_handle();
// byte[] ltr_cur = gplx.core.intls.Utf8_.Get_char_at_pos_as_bry(itm_sortkey, 0);
byte[] ltr_cur = ltr_extractor.Get_1st_ltr(itm_sortkey);
byte[] ltr_head = Bry_.Eq(ltr_prv, ltr_cur)
? Bry_.Add(ltr_prv, Byte_ascii.Space_bry, msg__list_continues) // new col uses same ltr as last itm in old col; add "cont."; EX: "C cont."
: ltr_cur; // else, just use ltr; EX: "C"

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.addons.wikis.ctgs.htmls.catpages.langs; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.wikis.*; import gplx.xowa.addons.wikis.ctgs.*; import gplx.xowa.addons.wikis.ctgs.htmls.*; import gplx.xowa.addons.wikis.ctgs.htmls.catpages.*;
import gplx.core.intls.ucas.*;
public class Xoctg_collation_mgr {
private final Xow_wiki wiki;
private Uca_collator collator;
private String collation_name = "uppercase"; // REF:https://noc.wikimedia.org/conf/InitialiseSettings.php.txt|wgCategoryCollation|default
public Xoctg_collation_mgr(Xow_wiki wiki) {
this.wiki = wiki;
if (String_.Eq(wiki.Domain_str(), "en.wikipedia.org"))
collation_name = "uca-default-kn";
}
public void Collation_name_(String v) {
this.collation_name = v;
}
public byte[] Get_sortkey(byte[] src) {
if (String_.Eq(collation_name, "uppercase")) {
return wiki.Lang().Case_mgr().Case_build_upper(src);
}
else {
if (collator == null) collator = Uca_collator_.New(collation_name, true);
return collator.Get_sortkey(String_.new_u8(src));
}
}
}

View File

@@ -20,4 +20,16 @@ public class Xoctg_catpage_url {
public Xoctg_catpage_url(byte[][] keys, boolean[] fwds) {this.keys = keys; this.fwds = fwds;}
public byte[][] Grp_keys() {return keys;} private final byte[][] keys;
public boolean[] Grp_fwds() {return fwds;} private final boolean[] fwds;
public static Xoctg_catpage_url New__blank() {
byte[][] keys = new byte[Xoa_ctg_mgr.Tid___max][];
boolean[] fwds = new boolean[Xoa_ctg_mgr.Tid___max];
// for blank url, all fwds are true; EX: "Category:A" -> keys {"", "", ""}, fwds {true, true, true}
for (int i = 0; i < Xoa_ctg_mgr.Tid___max; ++i) {
fwds[i] = Bool_.Y;
keys[i] = Bry_.Empty;
}
return new Xoctg_catpage_url(keys, fwds);
}
}

View File

@@ -21,15 +21,20 @@ import gplx.langs.htmls.encoders.*;
public class Xoctg_catpage_url_parser {
public static Xoctg_catpage_url Parse(Xoa_url url) {
Gfo_qarg_itm[] args = url.Qargs_ary();
if (args == null) return null;
if (args == null) return Xoctg_catpage_url.New__blank();
int len = args.length;
if (len == 0) return Xoctg_catpage_url.New__blank();
// init caturl structs
byte[][] keys = new byte[Xoa_ctg_mgr.Tid___max][];
boolean[] fwds = new boolean[Xoa_ctg_mgr.Tid___max];
for (int i = 0; i < Xoa_ctg_mgr.Tid___max; ++i) {
fwds[i] = Bool_.Y;
keys[i] = Bry_.Empty;
}
Bry_bfr tmp_bfr = Bry_bfr_.New();
// loop qargs; EX: "?subcatfrom=B&filefrom=C&pagefrom=D"
int len = args.length;
for (int i = 0; i < len; ++i) {
Gfo_qarg_itm arg = args[i];

View File

@@ -1,62 +0,0 @@
/*
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.addons.wikis.ctgs.htmls.catpages.utls; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.wikis.*; import gplx.xowa.addons.wikis.ctgs.*; import gplx.xowa.addons.wikis.ctgs.htmls.*; import gplx.xowa.addons.wikis.ctgs.htmls.catpages.*;
import gplx.core.lists.binary_searches.*;
import gplx.xowa.addons.wikis.ctgs.htmls.catpages.doms.*; import gplx.xowa.addons.wikis.ctgs.htmls.catpages.urls.*;
public class Xoctg_catpage_filter {
public static void Filter(int limit, Xoctg_catpage_url cat_url, Xoctg_catpage_ctg ctg) {
int len = Xoa_ctg_mgr.Tid___max;
for (byte i = 0; i < len; ++i) {
Filter_by_grp(limit, cat_url, ctg.Grp_by_tid(i));
}
}
private static void Filter_by_grp(int grp_len, Xoctg_catpage_url cat_url, Xoctg_catpage_grp grp) {
byte grp_tid = grp.Tid();
byte[] grp_key = cat_url.Grp_keys()[grp_tid];
// dflt to bos; EX: grp_bgn=0 grp_end=200
int grp_bgn = 0;
int grp_end = grp_bgn + grp_len;
// key specified; calc new grp_bgn, grp_end
if (grp_key != null) {
// get idx of key
int key_idx = Binary_search_.Search(grp.Itms(), Xoctg_catpage_itm_sorter__sort_key.Sorter, grp_key);
// if fwd, set grp_bgn to key_idx, and add grp_len
if (cat_url.Grp_fwds()[grp_tid]) {
grp_bgn = key_idx;
grp_end = grp_bgn + grp_len;
}
// if bwd, set grp_end to key_idx, and subtract grp_len
else {
grp_end = key_idx;
grp_bgn = grp_end - grp_len;
// assert new grp_bgn is not negative
if (grp_bgn < 0) grp_bgn = 0;
}
}
// assert new grp_end is not > grp_max; note that this needs to be specified for when grp_key is null and not null
int grp_max = grp.Itms__len();
if (grp_end > grp_max)
grp_end = grp_max;
grp.Rng_(grp_bgn, grp_end);
}
}

View File

@@ -1,107 +0,0 @@
/*
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.addons.wikis.ctgs.htmls.catpages.utls; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.wikis.*; import gplx.xowa.addons.wikis.ctgs.*; import gplx.xowa.addons.wikis.ctgs.htmls.*; import gplx.xowa.addons.wikis.ctgs.htmls.catpages.*;
import org.junit.*; import gplx.core.tests.*;
import gplx.xowa.apps.urls.*;
import gplx.xowa.addons.wikis.ctgs.htmls.catpages.doms.*; import gplx.xowa.addons.wikis.ctgs.htmls.catpages.urls.*;
public class Xoctg_catpage_filter__tst {
private final Xoctg_catpage_filter__fxt fxt = new Xoctg_catpage_filter__fxt();
private Xoctg_catpage_ctg ctg;
@Before public void init() {
this.ctg = fxt.Make__ctg(25, 25, 25);
}
@Test public void Initial() {
fxt.Exec__filter(5, "A", ctg);
fxt.Test__cat_grp(ctg, Xoa_ctg_mgr.Tid__subc, 0, 5);
fxt.Test__cat_grp(ctg, Xoa_ctg_mgr.Tid__page, 0, 5);
fxt.Test__cat_grp(ctg, Xoa_ctg_mgr.Tid__file, 0, 5);
}
@Test public void Fwd__page__05() {
fxt.Exec__filter(5, "A?pagefrom=05", ctg);
fxt.Test__cat_grp(ctg, Xoa_ctg_mgr.Tid__page, 5, 10);
fxt.Test__cat_grp(ctg, Xoa_ctg_mgr.Tid__subc, 0, 5);
fxt.Test__cat_grp(ctg, Xoa_ctg_mgr.Tid__file, 0, 5);
}
@Test public void Fwd__page__10() {
fxt.Exec__filter(5, "A?pagefrom=10", ctg);
fxt.Test__cat_grp(ctg, Xoa_ctg_mgr.Tid__page, 10, 15);
fxt.Test__cat_grp(ctg, Xoa_ctg_mgr.Tid__subc, 0, 5);
fxt.Test__cat_grp(ctg, Xoa_ctg_mgr.Tid__file, 0, 5);
}
@Test public void Fwd__page__23() {
fxt.Exec__filter(5, "A?pagefrom=23", ctg);
fxt.Test__cat_grp(ctg, Xoa_ctg_mgr.Tid__page, 23, 25);
fxt.Test__cat_grp(ctg, Xoa_ctg_mgr.Tid__subc, 0, 5);
fxt.Test__cat_grp(ctg, Xoa_ctg_mgr.Tid__file, 0, 5);
}
@Test public void Fwd__full__06() {
fxt.Exec__filter(5, "A?from=06", ctg);
fxt.Test__cat_grp(ctg, Xoa_ctg_mgr.Tid__page, 6, 11);
fxt.Test__cat_grp(ctg, Xoa_ctg_mgr.Tid__subc, 6, 11);
fxt.Test__cat_grp(ctg, Xoa_ctg_mgr.Tid__file, 6, 11);
}
@Test public void Bwd__page__20() {
fxt.Exec__filter(5, "A?pageuntil=20", ctg);
fxt.Test__cat_grp(ctg, Xoa_ctg_mgr.Tid__page, 15, 20);
fxt.Test__cat_grp(ctg, Xoa_ctg_mgr.Tid__subc, 0, 5);
fxt.Test__cat_grp(ctg, Xoa_ctg_mgr.Tid__file, 0, 5);
}
@Test public void Bwd__page__2() {
fxt.Exec__filter(5, "A?pageuntil=01", ctg);
fxt.Test__cat_grp(ctg, Xoa_ctg_mgr.Tid__page, 0, 1);
fxt.Test__cat_grp(ctg, Xoa_ctg_mgr.Tid__subc, 0, 5);
fxt.Test__cat_grp(ctg, Xoa_ctg_mgr.Tid__file, 0, 5);
}
@Test public void Bwd__full__11() {
fxt.Exec__filter(5, "A?until=11", ctg);
fxt.Test__cat_grp(ctg, Xoa_ctg_mgr.Tid__page, 6, 11);
fxt.Test__cat_grp(ctg, Xoa_ctg_mgr.Tid__subc, 6, 11);
fxt.Test__cat_grp(ctg, Xoa_ctg_mgr.Tid__file, 6, 11);
}
}
class Xoctg_catpage_filter__fxt {
private Xow_url_parser url_parser;
public Xoctg_catpage_filter__fxt() {
Xoa_app app = Xoa_app_fxt.Make__app__edit();
this.url_parser = app.User().Wikii().Utl__url_parser();
}
public Xoctg_catpage_ctg Make__ctg(int subc, int page, int file) {
Xoctg_catpage_ctg ctg = new Xoctg_catpage_ctg(Bry_.new_a7("A"));
Make__ctg_grp(ctg, Xoa_ctg_mgr.Tid__subc, subc);
Make__ctg_grp(ctg, Xoa_ctg_mgr.Tid__page, page);
Make__ctg_grp(ctg, Xoa_ctg_mgr.Tid__file, file);
return ctg;
}
private void Make__ctg_grp(Xoctg_catpage_ctg ctg, byte tid, int count) {
Xoctg_catpage_grp grp = ctg.Grp_by_tid(tid);
for (int i = 0; i < count; ++i) {
Xoctg_catpage_itm itm = new Xoctg_catpage_itm(i * tid, Xoa_ttl.Null, Bry_.new_a7(Int_.To_str_pad_bgn_zero(i, 2)));
grp.Itms__add(itm);
}
grp.Itms__make();
}
public void Exec__filter(int limit, String cat_url_str, Xoctg_catpage_ctg ctg) {
Xoctg_catpage_url cat_url = Xoctg_catpage_url_parser.Parse(url_parser.Parse(Bry_.new_a7(cat_url_str)));
Xoctg_catpage_filter.Filter(limit, cat_url, ctg);
}
public void Test__cat_grp(Xoctg_catpage_ctg ctg, byte tid, int expd_bgn, int expd_end) {
Xoctg_catpage_grp grp = ctg.Grp_by_tid(tid);
Gftest.Eq__int(expd_bgn, grp.Bgn(), "bgn failed; tid={0}", tid);
Gftest.Eq__int(expd_end, grp.End(), "end failed; tid={0}", tid);
}
}

View File

@@ -1,120 +0,0 @@
/*
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.addons.wikis.ctgs.htmls.catpages.utls; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.wikis.*; import gplx.xowa.addons.wikis.ctgs.*; import gplx.xowa.addons.wikis.ctgs.htmls.*; import gplx.xowa.addons.wikis.ctgs.htmls.catpages.*;
import gplx.dbs.*; import gplx.xowa.wikis.data.*; import gplx.xowa.wikis.data.tbls.*; import gplx.xowa.addons.wikis.ctgs.dbs.*;
import gplx.xowa.addons.wikis.ctgs.htmls.catpages.doms.*;
public class Xoctg_catpage_loader {
private static final Object thread_lock = new Object();
public Xoctg_catpage_ctg Load_by_ttl_or_null(Xow_wiki wiki, Xoa_ttl cat_ttl) {
// get cat_id for cat_ttl from page_tbl
Xow_db_mgr db_mgr = wiki.Data__core_mgr();
Xowd_page_tbl page_tbl = db_mgr.Db__core().Tbl__page();
Xowd_page_itm page_itm = page_tbl.Select_by_ttl_as_itm_or_null(cat_ttl);
if (page_itm == null) {
Gfo_usr_dlg_.Instance.Warn_many("", "", "category does not exist in page table; ttl=~{0}", cat_ttl.Full_db());
return null;
}
// get cat_link db from cat_core_tbl
Xowd_cat_core_tbl cat_core_tbl = Xodb_cat_db_.Get_cat_core_or_fail(db_mgr);
int cat_id = page_itm.Id();
Xowd_category_itm cat_core_itm = cat_core_tbl.Select(cat_id);
if (cat_core_itm == Xowd_category_itm.Null) {
Gfo_usr_dlg_.Instance.Log_many("", "", "category does not exist in cat_core table; ttl=~{0}", cat_ttl.Full_db()); // NOTE: this is not rare as Category pages can be created as deliberately empty, or as redirects; fr.w:Catégorie:Utilisateur_hess-4; DATE:2016-09-12
return null;
}
// load itms from cat_link_db
Xoctg_catpage_ctg rv = new Xoctg_catpage_ctg(cat_ttl.Page_txt());
if (cat_core_itm.File_idx() == -1) // new v3: loop over all cat_link dbs
Search_cat_core_tbls_for_cat_id(rv, wiki, db_mgr, page_tbl.Conn(), cat_core_tbl.Conn(), cat_id);
else { // old v2: use cat_link_db
Xow_db_file cat_link_db = db_mgr.Dbs__get_by_id_or_fail(cat_core_itm.File_idx());
Select_by_cat_id(rv, wiki, page_tbl.Conn(), cat_core_tbl.Conn(), cat_link_db.Conn(), cat_id, Sql_for_v2(cat_id));
}
rv.Make_itms();
return rv;
}
private static void Search_cat_core_tbls_for_cat_id(Xoctg_catpage_ctg rv, Xow_wiki wiki, Xow_db_mgr db_mgr, Db_conn page_conn, Db_conn cat_core_conn, int cat_id) {
// loop over each db unless (a) cat_link_db; (b) core_db (if all or few)
int len = db_mgr.Dbs__len();
for (int i = 0; i < len; ++i) {
Xow_db_file db_file = db_mgr.Dbs__get_at(i);
switch (db_file.Tid()) {
case Xow_db_file_.Tid__cat_link: // always use cat_link db
break;
case Xow_db_file_.Tid__core: // only use core if all or few
if (db_mgr.Props().Layout_text().Tid_is_lot())
continue;
else
break;
default: // else ignore all other files
continue;
}
Select_by_cat_id(rv, wiki, page_conn, cat_core_conn, db_file.Conn(), cat_id, Sql_for_v3(cat_id));
}
}
private static void Select_by_cat_id(Xoctg_catpage_ctg rv, Xow_wiki wiki, Db_conn page_conn, Db_conn cat_core_conn, Db_conn cat_link_conn, int cat_id, String sql) {
// prep sql
Db_attach_mgr attach_mgr = new Db_attach_mgr(cat_link_conn, new Db_attach_itm("page_db", page_conn), new Db_attach_itm("cat_core_db", cat_core_conn));
sql = attach_mgr.Resolve_sql(sql);
// run sql and create itms based on cat_link
Db_rdr rdr = Db_rdr_.Empty;
synchronized (thread_lock) { // LOCK:used by multiple wrks; DATE:2016-09-12
try {
attach_mgr.Attach();
rdr = cat_link_conn.Stmt_sql(sql).Exec_select__rls_auto();
while (rdr.Move_next()) {
Xoa_ttl page_ttl = wiki.Ttl_parse(rdr.Read_int("page_namespace"), rdr.Read_bry_by_str("page_title"));
Xoctg_catpage_itm itm = new Xoctg_catpage_itm(rdr.Read_int("cl_from"), page_ttl, Bry_.new_u8(rdr.Read_str("cl_sortkey")));
rv.Grp_by_tid(rdr.Read_byte("cl_type_id")).Itms__add(itm);
}
}
finally {
rdr.Rls();
attach_mgr.Detach();
}
}
}
private static String Sql_for_v3(int cat_id) {
return String_.Concat_lines_nl_skip_last // ANSI.Y
( "SELECT cl.cl_from"
, ", cl.cl_type_id"
, ", p.page_namespace"
, ", p.page_title"
, ", cs.cs_key AS cl_sortkey"
, "FROM cat_link cl"
, " JOIN <page_db>page p ON cl.cl_from = p.page_id"
, " JOIN <cat_core_db>cat_sort cs ON cl.cl_sortkey_id = cs.cs_id"
, "WHERE cl.cl_to_id = " + Int_.To_str(cat_id)
);
}
private static String Sql_for_v2(int cat_id) { // NOTE: main difference is cl_sortkey is on cat_link, not in cat_sort
return String_.Concat_lines_nl_skip_last // ANSI.Y
( "SELECT cl.cl_from"
, ", cl.cl_type_id"
, ", p.page_namespace"
, ", p.page_title"
, ", cl.cl_sortkey"
, "FROM cat_link cl"
, " JOIN <page_db>page p ON cl.cl_from = p.page_id"
, "WHERE cl.cl_to_id = " + Int_.To_str(cat_id)
);
}
}

View File

@@ -31,7 +31,7 @@ class Xoctg_pagebox_loader implements Select_in_cbk {
int cat_id = rdr.Read_int("cat_id");
Xoctg_pagebox_itm page = (Xoctg_pagebox_itm)hash.Get_by_id(cat_id);
if (page == null) {// unlikely, but possible for itms to exist in cat_links, but not in cat_core; log and return;
Gfo_usr_dlg_.Instance.Warn_many("", "", "cat_id in cat_link but not in cat_core; page=~{0} cat_id=~{0}", page_url, cat_id);
Gfo_usr_dlg_.Instance.Warn_many("", "", "cat_id in cat_link but not in cat_core; page=~{0} cat_id=~{1}", page_url, cat_id);
}
page.Load_by_cat_core(rdr.Read_bool_by_byte("cat_hidden"), rdr.Read_int("cat_pages"), rdr.Read_int("cat_subcats"), rdr.Read_int("cat_files"));
}

View File

@@ -46,7 +46,7 @@ public class Xoctg_pagebox_wtr {
Xoctg_pagebox_loader select_cbk = new Xoctg_pagebox_loader(hash, page.Url_bry_safe());
// get cat_db_id from page
boolean exists = wiki.Data__core_mgr().Tbl__page().Select_by_ttl(tmp_page_itm, page.Ttl().Ns(), page.Ttl().Page_txt());
boolean exists = wiki.Data__core_mgr().Tbl__page().Select_by_ttl(tmp_page_itm, page.Ttl().Ns(), page.Ttl().Page_db());
int cat_db_id = tmp_page_itm.Cat_db_id();
if (exists && cat_db_id != -1) {// note that wtxt_dbs can have 0 ctgs but will have cat_db_id == -1
Xow_db_file cat_link_db = wiki.Data__core_mgr().Dbs__get_by_id_or_null(cat_db_id);

View File

@@ -35,9 +35,9 @@ public class Xoctg_double_box implements Bfr_arg {
int len = ary.length;
for (int i = 0; i < len; ++i) {
Xoctg_pagebox_itm ctg = ary[i];
Xoctg_double_grp list = ctg.Hidden() ? grp_hidden : grp_normal;
list.Itms().Itms__add(ctg);
Xoctg_pagebox_itm itm = ary[i];
Xoctg_double_grp list = itm.Hidden() ? grp_hidden : grp_normal;
list.Itms().Itms__add(itm);
}
this.Bfr_arg__add(bfr);
}

View File

@@ -31,7 +31,7 @@ public class Xowd_html_tbl_mgr {
byte[] content_sub = null;
byte[] sidebar_div = null;
db.Conn().Meta_tbl_assert(tbl);
tbl.Upsert(page_id, Xopg_module_mgr.Tid_null, Io_stream_.Tid_raw, Xoh_hzip_dict_.Hzip__plain, display_ttl, content_sub, sidebar_div, src);
tbl.Upsert(page_id, Xopg_module_mgr.Tid_null, Io_stream_tid_.Tid__raw, Xoh_hzip_dict_.Hzip__plain, display_ttl, content_sub, sidebar_div, src);
wiki.Data__core_mgr().Db__core().Tbl__page().Update__html_db_id(page_id, db.Id());
}

View File

@@ -38,8 +38,7 @@ public class Srch_search_cfg implements Gfo_invk {
public void Args_default_str_(String v) {
this.args_default_str = v;
byte[] bry = Bry_.new_a7("http://x.org/a?" + v);
Gfo_url tmp_url = new Gfo_url();
app.User().Wikii().Utl__url_parser().Url_parser().Parse(tmp_url, bry, 0, bry.length);
Gfo_url tmp_url = app.User().Wikii().Utl__url_parser().Url_parser().Parse(bry, 0, bry.length);
args_default = tmp_url.Qargs();
}
private Srch_search_addon addon;