JsonConfig: Add Localize function for tabular data

pull/620/head
gnosygnu 6 years ago
parent 8967ca810a
commit 54d74b0acd

@ -40,6 +40,10 @@ public class Bry_find_ {
if (src[i] == lkp) return i;
return Bry_find_.Not_found;
}
public static int Find_bwd_or(byte[] src, byte lkp, int cur, int end, int or) {
int rv = Find_bwd(src, lkp, cur, end);
return rv == Bry_find_.Not_found ? or : rv;
}
public static int Move_fwd(byte[] src, byte lkp, int cur, int end) {
int rv = Find_fwd(src, lkp, cur, src.length);
return rv == Bry_find_.Not_found ? rv : rv + 1;

@ -30,6 +30,15 @@ public class Object_ {
rv[i] = rhs[i - lhs_len];
return rv;
}
public static Object[] Ary_add_one(Object[] lhs, Object rhs) {
int lhs_len = lhs.length, rhs_len = 1;
int rv_len = lhs_len + rhs_len;
Object[] rv = new Object[rv_len];
for (int i = 0; i < lhs_len; ++i)
rv[i] = lhs[i];
rv[rv_len - 1] = rhs;
return rv;
}
public static boolean Eq(Object lhs, Object rhs) {
if (lhs == null && rhs == null) return true;
else if (lhs == null || rhs == null) return false;

@ -30,6 +30,7 @@ public class Type_ids_ {//RF:2017-10-08
, Id__bry = 11
, Id__date = 12
, Id__decimal = 13
, Id__array = 14
;
public static int To_id_by_obj(Object o) {

@ -30,8 +30,8 @@ public class Xoa_app_ {
}
}
public static final String Name = "xowa";
public static final int Version_id = 540;
public static final String Version = "4.5.18.1711";
public static final int Version_id = 542;
public static final String Version = "4.5.20.1801";
public static String Build_date = "2012-12-30 00:00:00";
public static String Build_date_fmt = "yyyy-MM-dd HH:mm:ss";
public static String Op_sys_str;

@ -18,7 +18,7 @@ import gplx.core.btries.*;
import gplx.langs.htmls.*; import gplx.xowa.langs.kwds.*; import gplx.langs.htmls.entitys.*;
import gplx.xowa.htmls.core.wkrs.hdrs.*; import gplx.xowa.htmls.core.wkrs.lnkes.*;
import gplx.xowa.wikis.domains.*;
import gplx.xowa.parsers.*; import gplx.xowa.parsers.apos.*; import gplx.xowa.parsers.amps.*; import gplx.xowa.parsers.lnkes.*; import gplx.xowa.parsers.lists.*; import gplx.xowa.htmls.core.wkrs.lnkis.htmls.*; import gplx.xowa.parsers.tblws.*; import gplx.xowa.parsers.paras.*; import gplx.xowa.parsers.xndes.*; import gplx.xowa.parsers.lnkis.*; import gplx.xowa.parsers.miscs.*; import gplx.xowa.parsers.htmls.*;
import gplx.xowa.parsers.*; import gplx.xowa.parsers.apos.*; import gplx.xowa.parsers.amps.*; import gplx.xowa.parsers.lnkes.*; import gplx.xowa.parsers.lists.*; import gplx.xowa.htmls.core.wkrs.lnkis.htmls.*; import gplx.xowa.parsers.tblws.*; import gplx.xowa.parsers.paras.*; import gplx.xowa.parsers.xndes.*; import gplx.xowa.parsers.lnkis.*; import gplx.xowa.parsers.miscs.*; import gplx.xowa.parsers.htmls.*; import gplx.xowa.parsers.uniqs.*;
import gplx.xowa.xtns.*; import gplx.xowa.xtns.cites.*; import gplx.xowa.parsers.hdrs.*;
public class Xoh_html_wtr {
private final Xoae_app app; private final Xowe_wiki wiki; private final Xow_html_mgr html_mgr; private final Xop_xatr_whitelist_mgr whitelist_mgr;
@ -90,6 +90,7 @@ public class Xoh_html_wtr {
case Xop_tkn_itm_.Tid_tblw_tc: Tblw (bfr, ctx, hctx, src, (Xop_tblw_tkn)tkn, Gfh_tag_.Caption_lhs_bgn , Gfh_tag_.Caption_rhs, false); break;
case Xop_tkn_itm_.Tid_newLine: New_line (bfr, ctx, hctx, src, (Xop_nl_tkn)tkn); break;
case Xop_tkn_itm_.Tid_bry: Bry (bfr, ctx, hctx, src, (Xop_bry_tkn)tkn); break;
case Xop_tkn_itm_.Tid_uniq: Uniq (bfr, ctx, hctx, src, (Xop_uniq_tkn)tkn); break;
case Xop_tkn_itm_.Tid_lnki: lnki_wtr.Write_lnki(bfr, hctx, src, (Xop_lnki_tkn)tkn); break;
case Xop_tkn_itm_.Tid_lnke: wkr__lnke.Write_html(bfr, html_mgr, this, hctx, ctx, src, (Xop_lnke_tkn)tkn); break;
case Xop_tkn_itm_.Tid_hdr: wkr__hdr.Write_html(bfr, this, wiki, page, ctx, hctx, cfg, grp, sub_idx, src, (Xop_hdr_tkn)tkn); break;
@ -232,6 +233,10 @@ public class Xoh_html_wtr {
private void Bry(Bry_bfr bfr, Xop_ctx ctx, Xoh_wtr_ctx hctx, byte[] src, Xop_bry_tkn bry) {
bfr.Add(bry.Val());
}
private void Uniq(Bry_bfr bfr, Xop_ctx ctx, Xoh_wtr_ctx hctx, byte[] src, Xop_uniq_tkn tkn) {
byte[] val = wiki.Parser_mgr().Uniq_mgr().Get(tkn.Key());
Xoh_html_wtr_escaper.Escape(app.Parser_amp_mgr(), bfr, val, 0, val.length, true, false);
}
private void Under(Bry_bfr bfr, Xop_ctx ctx, Xoh_wtr_ctx hctx, byte[] src, Xop_under_tkn under) {
if (hctx.Mode_is_alt()) return;
switch (under.Under_tid()) {
@ -436,7 +441,7 @@ public class Xoh_html_wtr {
for (int i = 0; i < ary_len; i++) {
Mwh_atr_itm atr = ary[i];
if (atr.Invalid()) continue;
if (!whitelist_mgr.Chk(tag_id, src, atr)) continue;
if (!whitelist_mgr.Chk(tag_id, atr)) continue;
Xnde_atr_write(bfr, app, hctx, src, atr);
}
}
@ -463,7 +468,7 @@ public class Xoh_html_wtr {
}
else {
if (atr.Val_bry() == null)
bfr.Add_mid(src, atr.Val_bgn(), atr.Val_end());
bfr.Add_mid(atr.Src(), atr.Val_bgn(), atr.Val_end());
else
bfr.Add(atr.Val_bry());
}

@ -29,7 +29,7 @@ public class Xoh_hdr_html {
// register hdr with TOC
byte[] hdr_text_bry = Bld_hdr_html(hdr_text_bfr, wtr, page, ctx, hctx, src, hdr);
hdr_text_bry = wiki.Parser_mgr().Uniq_mgr().Convert(hdr_text_bry); // need for math; DATE:2016-12-09
hdr_text_bry = wiki.Parser_mgr().Uniq_mgr().Parse(hdr_text_bry); // need for math; DATE:2016-12-09
Xoh_toc_itm toc_itm = hdr_is_valid && hdr_text_bry.length > 0
? page.Html_data().Toc_mgr().Add(hdr_num, hdr_text_bry)
: invalid_toc_itm;

@ -59,9 +59,13 @@ public class Xol_lang_itm implements Gfo_invk {
public Xol_lang_itm Fallback_bry_(byte[] v) {
fallback_bry = v;
fallback_bry_ary = Fallbacy_bry_ary__bld(v);
for (byte[] key : fallback_bry_ary) {
fallback_hash.Add_as_key_and_val(String_.new_u8(key));
}
return this;
} private byte[] fallback_bry;
public byte[][] Fallback_bry_ary() {return fallback_bry_ary;} private byte[][] fallback_bry_ary = Bry_.Ary_empty;
public Ordered_hash Fallback_hash() {return fallback_hash;} private final Ordered_hash fallback_hash = Ordered_hash_.New();
public boolean Dir_ltr() {return dir_ltr;} private boolean dir_ltr = true;
public void Dir_ltr_(boolean v) {
dir_ltr = v;

@ -20,6 +20,6 @@ public class Xop_lxr_ {
, Tid_list = 10, Tid_hdr = 11, Tid_hr = 12, Tid_xnde = 13, Tid_lnke_bgn = 14, Tid_lnke_end = 15, Tid_tblw = 16, Tid_pre = 17, Tid_under = 18, Tid_comment = 19
, Tid_eq = 20, Tid_curly_bgn = 21, Tid_curly_end = 22, Tid_brack_bgn = 23, Tid_brack_end = 24, Tid_poem = 25
, Tid_tvar = 26, Tid_vnt_bgn = 27, Tid_vnt_end = 28, Tid_vnt_eqgt = 29, Tid_vnt_tmpl_bgn = 30, Tid_word = 31, Tid_nl_poem = 32, Tid_cr = 33
, Tid_brack_end_lnki = 34, Tid_nl_tab = 35, Tid_escape = 36
, Tid_brack_end_lnki = 34, Tid_nl_tab = 35, Tid_escape = 36, Tid_uniq = 37
;
}

@ -16,7 +16,7 @@ Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
package gplx.xowa.parsers; import gplx.*; import gplx.xowa.*;
import gplx.core.btries.*;
import gplx.xowa.langs.*;
import gplx.xowa.parsers.apos.*; import gplx.xowa.parsers.amps.*; import gplx.xowa.parsers.lnkes.*; import gplx.xowa.parsers.hdrs.*; import gplx.xowa.parsers.lists.*; import gplx.xowa.parsers.tblws.*; import gplx.xowa.parsers.paras.*; import gplx.xowa.parsers.xndes.*; import gplx.xowa.parsers.lnkis.*; import gplx.xowa.parsers.tmpls.*; import gplx.xowa.parsers.miscs.*;
import gplx.xowa.parsers.apos.*; import gplx.xowa.parsers.amps.*; import gplx.xowa.parsers.lnkes.*; import gplx.xowa.parsers.hdrs.*; import gplx.xowa.parsers.lists.*; import gplx.xowa.parsers.tblws.*; import gplx.xowa.parsers.paras.*; import gplx.xowa.parsers.xndes.*; import gplx.xowa.parsers.lnkis.*; import gplx.xowa.parsers.tmpls.*; import gplx.xowa.parsers.miscs.*; import gplx.xowa.parsers.uniqs.*;
public class Xop_lxr_mgr {
private final Xop_lxr[] ary;
private final List_adp page_lxr_list = List_adp_.New();
@ -77,6 +77,7 @@ public class Xop_lxr_mgr {
, Xop_pre_lxr.Instance, Xop_nl_tab_lxr.Instance
, Xop_comm_lxr.Instance
, Xop_under_lxr.Instance
// , Xop_uniq_lxr.Instance // NOWIKI;DATE:2018-01-16
});
}
public static Xop_lxr_mgr new_anchor_encoder() {

@ -15,7 +15,7 @@ Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.parsers; import gplx.*; import gplx.xowa.*;
public class Xop_tkn_itm_ {
public static final Xop_tkn_itm[] Ary_empty = new Xop_tkn_itm[0];
public static final Xop_tkn_itm[] Ary_empty = new Xop_tkn_itm[0];
public static final byte
Tid_null = 0
, Tid_root = 1
@ -69,8 +69,9 @@ public class Xop_tkn_itm_ {
, Tid_vnt_eqgt = 49
, Tid_cr = 50
, Tid_escape = 51
, Tid_uniq = 52
;
public static final String[] Tid__names
public static final String[] Tid__names
= new String[]
{ "null"
, "root"
@ -124,5 +125,6 @@ public static final String[] Tid__names
, "vnt_eqgt"
, "cr"
, "escape"
, "uniq"
};
}

@ -104,7 +104,7 @@ class Xop_section_list implements Xomw_heading_cbk {
key = wiki.Parser_mgr().Main().Parse_text_to_html(wiki.Parser_mgr().Ctx(), key);
// handle math; EX: "== <math>\delta</math> =="
key = wiki.Parser_mgr().Uniq_mgr().Convert(key);
key = wiki.Parser_mgr().Uniq_mgr().Parse(key);
// convert key to toc_text to handle (a) XML ("<i>a</i>" -> "a"); (b) dupes ("text" -> "text_2")
int num = wkr.Hdr_num();

@ -71,7 +71,7 @@ public class Xop_section_mgr implements Gfo_invk {
this.fmt__edit_hint.Fmt_(String_.new_u8(wiki.Msg_mgr().Val_by_key_obj("editsectionhint")));
}
section_key = wiki.Parser_mgr().Uniq_mgr().Convert(section_key); // need to swap out uniqs for Math; DATE:2016-12-09
section_key = wiki.Parser_mgr().Uniq_mgr().Parse(section_key); // need to swap out uniqs for Math; DATE:2016-12-09
byte[] edit_hint = fmt__edit_hint.Bld_many_to_bry(tmp_bfr, section_hint);
fmt__section_editable.Bld_many(bfr, page_ttl, section_key, edit_hint, bry__edit_text);
}

@ -28,22 +28,22 @@ public class Mwh_atr_itm {
this.val_bgn = val_bgn; this.val_end = val_end; this.val_bry = val_bry;
this.eql_pos = eql_pos; this.qte_tid = qte_tid;
}
public byte[] Src() {return src;} private final byte[] src;
public boolean Valid() {return valid;} private final boolean valid;
public boolean Key_exists() {return key_exists;} private final boolean key_exists;
public boolean Repeated() {return repeated;} private final boolean repeated;
public byte[] Src() {return src;} private final byte[] src;
public boolean Valid() {return valid;} private final boolean valid;
public boolean Key_exists() {return key_exists;} private final boolean key_exists;
public boolean Repeated() {return repeated;} private final boolean repeated;
public boolean Invalid() {return repeated || !valid;}
public int Atr_bgn() {return atr_bgn;} private int atr_bgn;
public int Atr_end() {return atr_end;} private int atr_end;
public int Key_bgn() {return key_bgn;} private final int key_bgn;
public int Key_end() {return key_end;} private final int key_end;
public int Key_bgn() {return key_bgn;} private final int key_bgn;
public int Key_end() {return key_end;} private final int key_end;
public byte[] Key_bry() {return key_bry;} private byte[] key_bry;
public byte Key_tid() {return key_tid;} public Mwh_atr_itm Key_tid_(byte v) {key_tid = v; return this;} private byte key_tid;
public int Val_bgn() {return val_bgn;} private final int val_bgn;
public int Val_end() {return val_end;} private final int val_end;
public int Val_bgn() {return val_bgn;} private final int val_bgn;
public int Val_end() {return val_end;} private final int val_end;
public byte[] Val_bry() {return val_bry;} private byte[] val_bry;
public int Eql_pos() {return eql_pos;} private final int eql_pos;
public int Qte_tid() {return qte_tid;} private final int qte_tid;
public int Eql_pos() {return eql_pos;} private final int eql_pos;
public int Qte_tid() {return qte_tid;} private final int qte_tid;
public byte Qte_byte() {
switch (qte_tid) {
case Mwh_atr_itm_.Qte_tid__none: return Byte_ascii.Null;
@ -53,7 +53,6 @@ public class Mwh_atr_itm {
}
}
public Mwh_atr_itm Atr_rng(int bgn, int end) {this.atr_bgn = bgn; this.atr_end = end; return this;}
public void Key_bry_(byte[] v) {this.key_bry = v;}
public void Val_bry_(byte[] v) {this.val_bry = v;}
public String Val_as_str() {return String_.new_u8(Val_as_bry());}
public byte[] Val_as_bry() {if (val_bry == null) val_bry = Bry_.Mid(src, val_bgn, val_end); return val_bry;} // NOTE: val_bry is cached

@ -493,6 +493,9 @@ public class Xop_tblw_wkr implements Xop_ctx_wkr {
atrs_bgn = Bry_find_.Find_fwd_while(src, atrs_bgn, src.length, Byte_ascii.Dash);
prv_tblw.Atrs_rng_set(atrs_bgn, atrs_end);
if (ctx.Parse_tid() == Xop_parser_tid_.Tid__wtxt && atrs_bgn != -1) {
// NOWIKI;DATE:2018-01-16
// byte[] converted = ctx.Wiki().Parser_mgr().Uniq_mgr().Parse(Bool_.N, Bry_.Mid(src, atrs_bgn, atrs_end));
// Mwh_atr_itm[] atrs = ctx.App().Parser_mgr().Xnde__parse_atrs(converted, 0, converted.length);
Mwh_atr_itm[] atrs = ctx.App().Parser_mgr().Xnde__parse_atrs_for_tblw(src, atrs_bgn, atrs_end);
prv_tblw.Atrs_ary_as_tblw_(atrs);
}

@ -16,7 +16,7 @@ Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
package gplx.xowa.parsers.tblws; import gplx.*; import gplx.xowa.*; import gplx.xowa.parsers.*;
import org.junit.*;
public class Xop_tblw_wkr__uncommon_tst {
@Before public void init() {fxt.Reset(); fxt.Init_para_y_();} private final Xop_fxt fxt = new Xop_fxt();
@Before public void init() {fxt.Reset(); fxt.Init_para_y_();} private final Xop_fxt fxt = new Xop_fxt();
@After public void term() {fxt.Init_para_n_();}
@Test public void Tr_pops_entire_stack() { // PURPOSE: in strange cases, tr will pop entire stack; PAGE:en.w:Turks_in_Denmark; DATE:2014-03-02
fxt.Test_parse_page_all_str(String_.Concat_lines_nl_skip_last

@ -62,8 +62,12 @@ public class Xot_tmpl_wtr {
if (xnde.Tag_close_bgn() == Int_.Min_value)
rslt_bfr.Add_mid(src, tkn.Src_bgn(), tkn.Src_end()); // write src from bgn/end
else { // NOTE: if nowiki then "deactivate" all xndes by swapping out < for &lt; nowiki_xnde_frag; DATE:2013-01-27
Bry_bfr tmp_bfr = ctx.Wiki().Utl__bfr_mkr().Get_k004();
// NOWIKI;DATE:2018-01-16
// byte[] uniq = ctx.Wiki().Parser_mgr().Uniq_mgr().Add(Bool_.N, Bry_.Empty, Bry_.Mid(src, xnde.Tag_open_end(), xnde.Tag_close_bgn()));
// rslt_bfr.Add(uniq);
int nowiki_content_bgn = xnde.Tag_open_end(), nowiki_content_end = xnde.Tag_close_bgn();
Bry_bfr tmp_bfr = ctx.Wiki().Utl__bfr_mkr().Get_k004();
boolean escaped = gplx.xowa.parsers.tmpls.Nowiki_escape_itm.Escape(tmp_bfr, src, nowiki_content_bgn, nowiki_content_end);
rslt_bfr.Add_bfr_or_mid(escaped, tmp_bfr, src, nowiki_content_bgn, nowiki_content_end);
tmp_bfr.Mkr_rls();

@ -0,0 +1,30 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.parsers.uniqs; import gplx.*; import gplx.xowa.*; import gplx.xowa.parsers.*;
class Xop_uniq_itm {
public Xop_uniq_itm(boolean expand_after_template_parsing, byte[] type, int idx, byte[] key, byte[] val) {
this.expand_after_template_parsing = expand_after_template_parsing;
this.type = type;
this.idx = idx;
this.key = key;
this.val = val;
}
public boolean Expand_after_template_parsing() {return expand_after_template_parsing;} private final boolean expand_after_template_parsing;
public byte[] Type() {return type;} private final byte[] type;
public int Idx() {return idx;} private final int idx;
public byte[] Key() {return key;} private final byte[] key;
public byte[] Val() {return val;} private final byte[] val;
}

@ -0,0 +1,41 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.parsers.uniqs; import gplx.*; import gplx.xowa.*; import gplx.xowa.parsers.*;
import gplx.core.btries.*; import gplx.xowa.langs.*;
// EX: "\u007fUNIQ-item-1-QINU\u007f"
public class Xop_uniq_lxr implements Xop_lxr {
public int Lxr_tid() {return Xop_lxr_.Tid_uniq;}
public void Init_by_wiki(Xowe_wiki wiki, Btrie_fast_mgr core_trie) {
core_trie.Add(Xop_uniq_mgr.Bry__uniq__bgn_w_dash, this);
}
public void Init_by_lang(Xol_lang_itm lang, Btrie_fast_mgr core_trie) {}
public void Term(Btrie_fast_mgr core_trie) {}
public int Make_tkn(Xop_ctx ctx, Xop_tkn_mkr tkn_mkr, Xop_root_tkn root, byte[] src, int src_len, int bgn_pos, int cur_pos) {
// find end
int rhs_bgn = Bry_find_.Find_fwd(src, Xop_uniq_mgr.Bry__uniq__add__end, cur_pos);
if (rhs_bgn == Bry_find_.Not_found) {
Gfo_usr_dlg_.Instance.Warn_many("", "", "uniq_mgr:unable to find uniq; src=~{0}", src);
return ctx.Lxr_make_txt_(cur_pos);
}
int rhs_end = rhs_bgn + Xop_uniq_mgr.Bry__uniq__add__end.length;
byte[] key = Bry_.Mid(src, bgn_pos, rhs_end);
Xop_uniq_tkn uniq_tkn = new Xop_uniq_tkn(bgn_pos, rhs_end, key);
ctx.Subs_add(root, uniq_tkn);
return rhs_end;
}
public static final Xop_uniq_lxr Instance = new Xop_uniq_lxr(); Xop_uniq_lxr() {}
}

@ -17,88 +17,73 @@ package gplx.xowa.parsers.uniqs; import gplx.*; import gplx.xowa.*; import gplx.
import gplx.core.btries.*;
public class Xop_uniq_mgr { // REF.MW:/parser/StripState.php
private final Btrie_slim_mgr general_trie = Btrie_slim_mgr.cs(); private final Btrie_rv trv = new Btrie_rv();
private final Bry_bfr key_bfr = Bry_bfr_.New_w_size(32);
private int idx = -1;
public void Clear() {idx = -1; general_trie.Clear();}
public byte[] Get(byte[] key) {return (byte[])general_trie.Match_exact(key, 0, key.length);}
public byte[] Add(byte[] type, byte[] val) {// "<b>" -> "\u007fUNIQ-item-1--QINU\u007f"
byte[] key = key_bfr
.Add(Bry__uniq__bgn_w_dash)
.Add(type).Add_byte(Byte_ascii.Dash) // EX: "ref-"
.Add_int_variable(++idx)
.Add(Bry__uniq__add__end).To_bry_and_clear();
general_trie.Add_bry_bry(key, val);
return key;
private final Bry_bfr tmp_bfr = Bry_bfr_.New_w_size(32);
private int nxt_idx = -1;
public void Clear() {
nxt_idx = -1;
general_trie.Clear();
}
public byte[] Convert(byte[] src) {
if (general_trie.Count() == 0) return src;
Bry_bfr dirty_bfr = null;
int cur = 0;
int len = src.length;
while (cur < len) {
// find "\u007fUNIQ-"
int uniq_bgn = Bry_find_.Find_fwd(src, Bry__uniq__bgn_w_dash, cur);
if (uniq_bgn == Bry_find_.Not_found) break;
// find "-"; EX: ref-
int tmp_pos = uniq_bgn;
tmp_pos = Bry_find_.Find_fwd(src, Byte_ascii.Dash, tmp_pos, len);
if (tmp_pos == Bry_find_.Not_found) {
Gfo_usr_dlg_.Instance.Warn_many("", "", "uniq_mgr:unable to find 2nd dash; src=~{0}", src);
return src;
}
// find end
int uniq_end = Bry_find_.Find_fwd(src, Bry__uniq__add__end, tmp_pos);
if (uniq_end == Bry_find_.Not_found) {
Gfo_usr_dlg_.Instance.Warn_many("", "", "uniq_mgr:unable to convert uniq; src=~{0}", src);
return src;
}
uniq_end += Bry__uniq__add__end.length;
// add to bfr
if (dirty_bfr == null) dirty_bfr = key_bfr;
dirty_bfr.Add_mid(src, cur, uniq_bgn);
dirty_bfr.Add((byte[])general_trie.Match_exact(src, uniq_bgn, uniq_end));
cur = uniq_end;
}
if (dirty_bfr != null) {
dirty_bfr.Add_mid(src, cur, len);
}
return dirty_bfr == null ? src : dirty_bfr.To_bry_and_clear();
public byte[] Get(byte[] key) {
Xop_uniq_itm itm = (Xop_uniq_itm)general_trie.Match_exact(key, 0, key.length);
return itm.Val();
}
public byte[] Add(boolean expand_after_template_parsing, byte[] type, byte[] val) {// "<b>" -> "\u007fUNIQ-item-1-QINU\u007f"
int idx = ++nxt_idx;
byte[] key = tmp_bfr
.Add(Bry__uniq__bgn_w_dash) // "\u007f'\"`UNIQ-"
.Add(type).Add_byte(Byte_ascii.Dash) // "ref-"
.Add_int_variable(idx) // "1"
.Add(Bry__uniq__add__end) // "-QINU`\"'\u007f"
.To_bry_and_clear();
Xop_uniq_itm itm = new Xop_uniq_itm(expand_after_template_parsing, type, idx, key, val);
general_trie.Add_obj(key, itm);
return key;
}
public void Parse(Bry_bfr bfr) {
if (general_trie.Count() == 0) return;
byte[] rv = Parse(key_bfr, general_trie, bfr.To_bry_and_clear());
byte[] rv = Parse_recurse(Bool_.Y, tmp_bfr, bfr.To_bry_and_clear());
bfr.Add(rv);
}
public byte[] Parse(byte[] src) {return Parse(key_bfr, general_trie, src);}
private byte[] Parse(Bry_bfr bfr, Btrie_slim_mgr trie, byte[] src) {
public byte[] Parse(boolean template_parsing, byte[] src) {return Parse_recurse(template_parsing, tmp_bfr, src);}
public byte[] Parse(byte[] src) {return Parse_recurse(Bool_.Y, tmp_bfr, src);}
private byte[] Parse_recurse(boolean template_parsing, Bry_bfr bfr, byte[] src) {
int src_len = src.length;
int pos = 0;
int mark_bgn = 0;
int prv_bgn = 0;
boolean dirty = false;
while (true) {
boolean is_last = pos == src_len;
byte b = is_last ? Byte_ascii.Null : src[pos];
Object o = trie.Match_at_w_b0(trv, b, src, pos, src_len);
Object o = general_trie.Match_at_w_b0(trv, b, src, pos, src_len);
// match not found for "\x7fUNIQ"; move on to next
if (o == null)
++pos;
pos++;
// match found
else {
byte[] val = (byte[])o;
int new_pos = trv.Pos(); // NOTE: since trie is reused, must capture pos here
val = Parse(Bry_bfr_.New(), trie, val);
Xop_uniq_itm itm = (Xop_uniq_itm)o;
int itm_end = trv.Pos(); // NOTE: must capture pos since trv is reused in the recursive call below
// skip if template_parsing
if (template_parsing
&& !itm.Expand_after_template_parsing()) {
pos = itm_end;
continue;
}
// add everything from prv_bgn up to UNIQ
bfr.Add_mid(src, prv_bgn, pos);
// expand UNIQ (can be recursive)
byte[] val = Parse_recurse(template_parsing, Bry_bfr_.New(), itm.Val());
// val = gplx.xowa.parsers.xndes.Xop_xnde_tkn.Hack_ctx.Wiki().Parser_mgr().Main().Parse_text_to_html(gplx.xowa.parsers.xndes.Xop_xnde_tkn.Hack_ctx, val); // CHART
bfr.Add_mid(src, mark_bgn, pos);
bfr.Add(val);
dirty = true;
pos = mark_bgn = new_pos;
pos = prv_bgn = itm_end;
}
if (is_last) {
if (dirty)
bfr.Add_mid(src, mark_bgn, src_len);
bfr.Add_mid(src, prv_bgn, src_len);
break;
}
}
@ -111,19 +96,19 @@ public class Xop_uniq_mgr { // REF.MW:/parser/StripState.php
}
public void Random_int_ary_(int... v) {random_int_ary = v;} private int[] random_int_ary; // TEST:
public byte[] Random_bry_new(int len) {
Bry_bfr key_bfr = Bry_bfr_.New();
Bry_bfr tmp_bfr = Bry_bfr_.New();
RandomAdp random_gen = RandomAdp_.new_();
for (int i = 0; i < len; i += 7) {
int rand = random_int_ary == null ? random_gen.Next(Int_.Max_value) : random_int_ary[i / 7];
String rand_str = Int_.To_str_hex(Bool_.N, Bool_.Y, rand & 0xfffffff); // limits value to 268435455
key_bfr.Add_str_a7(rand_str);
tmp_bfr.Add_str_a7(rand_str);
}
byte[] rv = key_bfr.To_bry(0, len);
key_bfr.Clear();
byte[] rv = tmp_bfr.To_bry(0, len);
tmp_bfr.Clear();
return rv;
}
private static final byte[]
public static final byte[]
Bry__uniq__bgn = Bry_.new_a7("\u007f'\"`UNIQ-")
, Bry__uniq__bgn_w_dash = Bry_.Add(Bry__uniq__bgn, Byte_ascii.Dash_bry)
, Bry__uniq__add__end = Bry_.new_a7("-QINU`\"'\u007f")

@ -65,7 +65,7 @@ class Xop_uniq_mgr__fxt {
Gftest.Eq__str(expd, String_.new_a7(mgr.Uniq_bry_new()), "unique_bry");
}
public void Test__add(String raw, String expd) {
Gftest.Eq__str(expd, String_.new_a7(mgr.Add(Bry_.new_a7("item"), Bry_.new_a7(raw))), "add");
Gftest.Eq__str(expd, String_.new_a7(mgr.Add(Bool_.Y, Bry_.new_a7("item"), Bry_.new_a7(raw))), "add");
}
public void Test__get(String key, String expd) {
Gftest.Eq__str(expd, String_.new_a7(mgr.Get(Bry_.new_a7(key))), "get");
@ -74,6 +74,6 @@ class Xop_uniq_mgr__fxt {
Gftest.Eq__str(expd, String_.new_a7(mgr.Parse(Bry_.new_a7(raw))), "parse");
}
public void Test__convert(String raw, String expd) {
Gftest.Eq__str(expd, String_.new_a7(mgr.Convert(Bry_.new_a7(raw))), "convert");
Gftest.Eq__str(expd, String_.new_a7(mgr.Parse(Bry_.new_a7(raw))), "convert");
}
}

@ -0,0 +1,26 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.parsers.uniqs; import gplx.*; import gplx.xowa.*; import gplx.xowa.parsers.*;
import gplx.langs.htmls.entitys.*;
// EX: "\u007fUNIQ-item-1--QINU\u007f"
public class Xop_uniq_tkn extends Xop_tkn_itm_base {
public Xop_uniq_tkn(int bgn, int end, byte[] key) {
this.Tkn_ini_pos(false, bgn, end);
this.key = key;
}
@Override public byte Tkn_tid() {return Xop_tkn_itm_.Tid_uniq;}
public byte[] Key() {return key;} private final byte[] key;
}

@ -18,7 +18,8 @@ import gplx.core.primitives.*; import gplx.core.btries.*; import gplx.xowa.parse
public class Xop_xatr_whitelist_mgr {
private final Hash_adp_bry grp_hash = Hash_adp_bry.cs();
private final Btrie_rv trv = new Btrie_rv();
public boolean Chk(int tag_id, byte[] src, Mwh_atr_itm xatr) {
public boolean Chk(int tag_id, Mwh_atr_itm xatr) {
byte[] src = xatr.Src();
byte[] key_bry = xatr.Key_bry();
byte[] chk_bry; int chk_bgn, chk_end;
if (key_bry == null) {

@ -16,7 +16,7 @@ Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
package gplx.xowa.parsers.xndes; import gplx.*; import gplx.xowa.*; import gplx.xowa.parsers.*;
import org.junit.*; import gplx.xowa.parsers.htmls.*;
public class Xop_xatr_whitelist_mgr_tst {
private final Xop_xatr_whitelist_fxt fxt = new Xop_xatr_whitelist_fxt();
private final Xop_xatr_whitelist_fxt fxt = new Xop_xatr_whitelist_fxt();
@Before public void init() {fxt.Clear();}
@Test public void Basic() {
fxt.Whitelist(Xop_xnde_tag_.Tid__div , "style" , true);
@ -45,29 +45,29 @@ public class Xop_xatr_whitelist_mgr_tst {
}
class Xop_xatr_whitelist_fxt {
private Xop_xatr_whitelist_mgr whitelist_mgr;
private Mwh_atr_itm atr_itm = new Mwh_atr_itm(null, false, false, false, -1, -1, -1, -1, null, -1, -1, null, -1, 0);
public void Clear() {
if (whitelist_mgr == null) whitelist_mgr = new Xop_xatr_whitelist_mgr().Ini();
}
public void Whitelist(int tag_id, String key_str, boolean expd) {
byte[] key_bry = Bry_.new_a7(key_str);
// atr_itm.Key_rng_(0, key_bry.length);
atr_itm.Key_bry_(key_bry);
Tfds.Eq(expd, whitelist_mgr.Chk(tag_id, key_bry, atr_itm), key_str);
Mwh_atr_itm atr_itm = New_atr_itm(key_str, null);
Tfds.Eq(expd, whitelist_mgr.Chk(tag_id, atr_itm), key_str);
}
public void Whitelist(int tag_id, String key_str, String val_str, boolean expd) {
byte[] key_bry = Bry_.new_a7(key_str);
// atr_itm.Key_rng_(0, key_bry.length);
atr_itm.Key_bry_(key_bry);
atr_itm.Val_bry_(Bry_.new_a7(val_str));
Tfds.Eq(expd, whitelist_mgr.Chk(tag_id, key_bry, atr_itm), key_str);
Mwh_atr_itm atr_itm = New_atr_itm(key_str, val_str);
Tfds.Eq(expd, whitelist_mgr.Chk(tag_id, atr_itm), key_str);
}
public void Scrub_style_pass(String style_val_str) {Scrub_style(style_val_str, style_val_str);}
public void Scrub_style_fail(String val_str) {Scrub_style(val_str, "");}
public void Scrub_style(String val_str, String expd) {
byte[] val_bry = Bry_.new_a7(val_str);
atr_itm.Val_bry_(val_bry);
Mwh_atr_itm atr_itm = New_atr_itm(null, val_str);
whitelist_mgr.Scrub_style(atr_itm, val_bry);
Tfds.Eq(expd, String_.new_a7(atr_itm.Val_bry()));
}
private static Mwh_atr_itm New_atr_itm(String key_str, String val_str) {
byte[] key_bry = key_str == null ? null : Bry_.new_u8(key_str);
byte[] val_bry = val_str == null ? null : Bry_.new_u8(val_str);
Mwh_atr_itm rv = new Mwh_atr_itm(key_bry, false, false, false, -1, -1, -1, -1, key_bry, -1, -1, val_bry, -1, 0);
return rv;
}
}

@ -132,7 +132,7 @@ public class Xop_xnde_tkn extends Xop_tkn_itm_base implements Xop_tblw_tkn {
// UNIQ; DATE:2017-03-31
if (is_tmpl_mode) {
byte[] val = cur_bfr.To_bry_and_clear();
byte[] key = ctx.Wiki().Parser_mgr().Uniq_mgr().Add(tag.Name_bry(), val);
byte[] key = ctx.Wiki().Parser_mgr().Uniq_mgr().Add(Bool_.Y, tag.Name_bry(), val);
bfr.Add(key);
}
}

@ -302,6 +302,13 @@ public class Xop_xnde_wkr implements Xop_ctx_wkr {
}
Mwh_atr_itm[] atrs = null;
if (ctx.Parse_tid() == Xop_parser_tid_.Tid__wtxt) {
// NOWIKI;DATE:2018-01-16
// if (atrs_bgn < atrs_end) {
// byte[] converted = ctx.Wiki().Parser_mgr().Uniq_mgr().Parse(Bool_.N, Bry_.Mid(src, atrs_bgn, atrs_end));
// atrs = ctx.App().Parser_mgr().Xnde__parse_atrs(converted, 0, converted.length);
// }
// else
// atrs = ctx.App().Parser_mgr().Xnde__parse_atrs(src, atrs_bgn, atrs_end);
atrs = ctx.App().Parser_mgr().Xnde__parse_atrs(src, atrs_bgn, atrs_end);
}
if (( ( tag.Xtn()

@ -16,7 +16,7 @@ Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
package gplx.xowa.parsers.xndes; import gplx.*; import gplx.xowa.*; import gplx.xowa.parsers.*;
import org.junit.*;
public class Xop_xnde_wkr__nowiki_tst {
private final Xop_fxt fxt = new Xop_fxt();
private final Xop_fxt fxt = new Xop_fxt();
@After public void term() {fxt.Init_para_n_();}
@Test public void Basic() {
fxt.Test_parse_page_wiki_str

@ -175,7 +175,7 @@ public class Gallery_mgr_wtr {
int len = xatr_list.Count();
for (int i = 0; i < len; i++) {
Mwh_atr_itm xatr = (Mwh_atr_itm)xatr_list.Get_at(i);
if (!whitelist_mgr.Chk(Xop_xnde_tag_.Tid__ul, src, xatr)) continue;
if (!whitelist_mgr.Chk(Xop_xnde_tag_.Tid__ul, xatr)) continue;
byte[] key = xatr.Key_bry();
byte[] val = xatr.Val_as_bry();
Gfh_wtr.Write_atr_bry(bfr, key, val);

@ -0,0 +1,151 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.xtns.jsonConfigs.scribunto; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.jsonConfigs.*;
import gplx.xowa.langs.*;
class Jscfg_localizer {
public Keyval[] Localize(Xol_lang_itm lang, byte[] page, Keyval[] root) {
if (lang == null) return root; // if no lang, return original
int len = root.length;
for (int i = 0; i < len; i++) {
Keyval nde = root[i];
String nde_key = nde.Key();
if (String_.Eq(nde_key, Id__root__license)) {
}
else if (String_.Eq(nde_key, Id__root__description)) {
root[i] = pickLocalizedString(lang, page, nde);
}
else if (String_.Eq(nde_key, Id__root__schema)) {
nde = Localize_schema(lang, page, nde);
}
else if (String_.Eq(nde_key, Id__root__data)) {
nde = Localize_data(lang, page, nde);
}
}
return root;
}
private Keyval Localize_schema(Xol_lang_itm lang, byte[] page, Keyval schema) {
Keyval[] schemas = Cast_to_kvary_or_null(page, schema) ; if (schemas == null) return schema;
Keyval[] fields = Cast_to_kvary_or_null(page, schemas[0]); if (fields == null) return schema;
for (Keyval field : fields) {
Keyval[] atrs = (Keyval[])field.Val();
int atrs_len = atrs.length;
for (int i = 0; i < atrs_len; i++) {
Keyval atr = atrs[i];
if (String_.Eq(atr.Key(), Id__fld__title)) {
atrs[i] = pickLocalizedString(lang, page, atr);
}
}
}
return schema;
}
private Keyval Localize_data(Xol_lang_itm lang, byte[] page, Keyval data) {
Keyval[] rows = Cast_to_kvary_or_null(page, data); if (rows == null) return data;
for (Keyval row : rows) {
Object[] vals = (Object[])row.Val();
int len = vals.length;
for (int i = 0; i < len; i++) {
Object val = vals[i];
if (Type_.Eq_by_obj(val, Keyval[].class)) {
Keyval val_as_kv = pickLocalizedString(lang, Int_.To_str(i), (Keyval[])val);
vals[i] = val_as_kv.Val();
}
}
}
return data;
}
private static Keyval pickLocalizedString(Xol_lang_itm lang, byte[] page, Keyval kv) {
Keyval[] kvs = Cast_to_kvary_or_null(page, kv.Key(), kv.Val());
Keyval rv = pickLocalizedString(lang, kv.Key(), kvs);
return rv == null ? kv : rv;
}
public static Keyval pickLocalizedString(Xol_lang_itm lang, String key, Keyval[] ary) {
// local vars for conditional logic
Object val_lang = null, val_en = null, val_1st = null;
Object[] val_fallbacks = null;
// local vars for lang
String langCode = lang.Key_str();
Ordered_hash fallback_hash = lang.Fallback_hash();
// loop ary to populate local vars
for (Keyval itm : ary) {
String itm_key = itm.Key();
Object itm_val = itm.Val();
if (val_1st == null) {
val_1st = itm_val;
}
if (String_.Eq(itm_key, langCode)) {
val_lang = itm_val;
}
else if (fallback_hash.Has(itm_key)) {
if (val_fallbacks == null) {
val_fallbacks = new Object[fallback_hash.Len()];
}
int idx = fallback_hash.Idx_of(itm_key);
val_fallbacks[idx] = itm_val;
}
else if (String_.Eq(itm_key, "en")) {
val_en = itm_val;
}
}
if (val_lang != null) {
return Keyval_.new_(key, val_lang);
}
if (val_fallbacks != null) {
for (Object v : val_fallbacks) {
if (v != null)
return Keyval_.new_(key, v);
}
}
// If fallbacks fail, check if english is defined
if (val_en != null) {
return Keyval_.new_(key, val_en);
}
// We have a custom default, return that
// if (defaultValue != null) {
// return null;
// }
// Return first available value, or an empty String
// There might be a better way to get the first value from an Object
Object val = val_1st == null ? "" : val_1st;
return Keyval_.new_(key, val);
}
private static Keyval[] Cast_to_kvary_or_null(byte[] page, Keyval kv) {return Cast_to_kvary_or_null(page, kv.Key(), kv.Val());}
private static Keyval[] Cast_to_kvary_or_null(byte[] page, String key, Object val) {
if (Type_.Eq_by_obj(val, Keyval[].class)) {
return (Keyval[])val;
}
else {
Gfo_usr_dlg_.Instance.Warn_many("", "", "could not cast to kvary; page=~{0} key=~{1}", key);
return null;
}
}
private static final String
Id__root__schema = "schema"
, Id__root__data = "data"
, Id__root__description = "description"
, Id__root__license = "license"
, Id__fld__title = "title"
;
}

@ -18,6 +18,7 @@ import gplx.xowa.xtns.scribunto.*; import gplx.xowa.xtns.scribunto.libs.*; impor
import gplx.xowa.wikis.domains.*;
public class Jscfg_scrib_lib implements Scrib_lib {
private final Scrib_lib_text__json_util json_util = new Scrib_lib_text__json_util();
private final Jscfg_localizer localizer = new Jscfg_localizer();
private Scrib_core core;
public Scrib_lua_mod Mod() {return mod;} private Scrib_lua_mod mod;
public Scrib_lib Init() {procs.Init_by_lib(this, Proc_names); return this;}
@ -57,6 +58,8 @@ public class Jscfg_scrib_lib implements Scrib_lib {
throw Err_.new_wo_type("bad argument #1 to 'get' (not a valid title) " + String_.new_u8(ttl_bry));
}
return Scrib_lib_text.JsonDecodeStatic(args, rslt, core, json_util, page, Scrib_lib_text__json_util.Opt__force_assoc, Scrib_lib_text__json_util.Flag__none);
Keyval[] rv = Scrib_lib_text.JsonDecodeStatic(args, core, json_util, page, Scrib_lib_text__json_util.Opt__force_assoc, Scrib_lib_text__json_util.Flag__none);
rv = localizer.Localize(core.Wiki().Lang(), page, rv);
return rslt.Init_obj(rv);
}
}

@ -14,18 +14,14 @@ GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.xtns.jsonConfigs.scribunto; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.jsonConfigs.*;
import org.junit.*;
import org.junit.*; import gplx.core.tests.*;
import gplx.xowa.xtns.scribunto.*; import gplx.xowa.xtns.scribunto.libs.*;
import gplx.xowa.langs.*;
import gplx.langs.jsons.*;
public class Jscfg_scrib_lib_tst {
@Before public void init() {
fxt.Clear_for_lib();
lib = new Jscfg_scrib_lib();
lib.Init();
lib.Core_(fxt.Core());
} private Scrib_invoke_func_fxt fxt = new Scrib_invoke_func_fxt(); private Jscfg_scrib_lib lib;
private final Jscfg_scrib_lib_fxt fxt = new Jscfg_scrib_lib_fxt();
@Test public void Get() {
Xowe_wiki commons_wiki = fxt.Parser_fxt().Wiki().Appe().Wiki_mgr().Get_by_or_make(gplx.xowa.wikis.domains.Xow_domain_itm_.Bry__commons).Init_assert();
fxt.Parser_fxt().Init_page_create(commons_wiki, "Data:Test.tab", gplx.langs.jsons.Json_doc.Make_str_by_apos
fxt.Init__page("Data:Test.tab", Json_doc.Make_str_by_apos
( "{"
, " 'data':"
, " ["
@ -41,7 +37,7 @@ public class Jscfg_scrib_lib_tst {
, " ]"
, "}"
));
fxt.Test_scrib_proc_str_ary(lib, Jscfg_scrib_lib.Invk_get, Keyval_.Ary(Keyval_.int_(1, "Test.tab")), String_.Concat_lines_nl_skip_last
fxt.Test__get("Test.tab", String_.Concat_lines_nl_skip_last
( "1="
, " data="
, " 1="
@ -52,4 +48,126 @@ public class Jscfg_scrib_lib_tst {
, " 2=Data:Q2"
));
}
@Test public void Get_localize() {
fxt.Init__page("Data:Test_localize.tab", Json_doc.Make_str_by_apos
( "{"
, " 'license': 'CC0-1.0',"
, " 'description': {"
, " 'de': 'Objekttabelle',"
, " 'en': 'Object table'"
, " },"
, " 'sources': 'Objects in Data:Data.tab completed by [https://www.wikidata.org Wikidata]',"
, " 'schema': {"
, " 'fields': ["
, " {"
, " 'name': 'wikidataID',"
, " 'type': 'String',"
, " 'title': {"
, " 'de': 'Wikidata-Item',"
, " 'en': 'Wikidata item'"
, " }"
, " },"
, " {"
, " 'name': 'wikidataLabel',"
, " 'type': 'localized',"
, " 'title': {"
, " 'de': 'Wikidata-Label',"
, " 'en': 'Wikidata label'"
, " }"
, " }"
, " ]"
, " },"
, " 'data': ["
, " ["
, " 'Q183',"
, " {"
, " 'de': 'Deutschland',"
, " 'en': 'Germany'"
, " }"
, " ],"
, " ["
, " 'Q61912',"
, " {"
, " 'de': 'Wertheim',"
, " 'en': 'Wertheim am Main'"
, " }"
, " ]"
, " ]"
, "}"
));
fxt.Test__get( "Test_localize.tab", String_.Concat_lines_nl_skip_last
( "1="
, " license=CC0-1.0"
, " description=Object table"
, " sources=Objects in Data:Data.tab completed by [https://www.wikidata.org Wikidata]"
, " schema="
, " fields="
, " 1="
, " name=wikidataID"
, " type=String"
, " title=Wikidata item"
, " 2="
, " name=wikidataLabel"
, " type=localized"
, " title=Wikidata label"
, " data="
, " 1="
, " 1=Q183"
, " 2=Germany"
, " 2="
, " 1=Q61912"
, " 2=Wertheim am Main"
));
}
@Test public void pickLocalizedString() {
Xol_lang_itm lang = fxt.Init__lang("zh-cn", "zh1,zh0");
// match key
fxt.Test__pickLocalizedString(lang, fxt.Init__picklocalizedStringKvs("fr", "zh-cn"), "zh-cn");
// match fallback; note that zh1 is higher in fallback list, but lower in kvs
fxt.Test__pickLocalizedString(lang, fxt.Init__picklocalizedStringKvs("zh0", "zh1"), "zh1");
// match en if no key or fallbacks
fxt.Test__pickLocalizedString(lang, fxt.Init__picklocalizedStringKvs("fr", "en"), "en");
// pick 1st if no match
fxt.Test__pickLocalizedString(lang, fxt.Init__picklocalizedStringKvs("fr", "de"), "fr");
}
}
class Jscfg_scrib_lib_fxt {
private final Scrib_invoke_func_fxt fxt = new Scrib_invoke_func_fxt();
private final Jscfg_scrib_lib lib;
private final Xowe_wiki commons_wiki;
public Jscfg_scrib_lib_fxt() {
fxt.Clear_for_lib();
lib = new Jscfg_scrib_lib();
lib.Init();
lib.Core_(fxt.Core());
this.commons_wiki = fxt.Parser_fxt().Wiki().Appe().Wiki_mgr().Get_by_or_make(gplx.xowa.wikis.domains.Xow_domain_itm_.Bry__commons).Init_assert();
}
public void Init__page(String page, String text) {
fxt.Parser_fxt().Init_page_create(commons_wiki, page, text);
}
public Xol_lang_itm Init__lang(String key, String fallbacks) {
Xol_lang_itm lang = new Xol_lang_itm(fxt.Core().App().Lang_mgr(), Bry_.new_u8(key));
lang.Fallback_bry_(Bry_.new_a7(fallbacks));
return lang;
}
public Keyval[] Init__picklocalizedStringKvs(String... vals) {
int len = vals.length;
Keyval[] rv = new Keyval[len];
for (int i = 0; i < len; i++) {
String val = vals[i];
rv[i] = Keyval_.new_(val, val);
}
return rv;
}
public void Test__get(String page, String expd) {
fxt.Test_scrib_proc_str_ary(lib, Jscfg_scrib_lib.Invk_get, Keyval_.Ary(Keyval_.int_(1, page)), expd);
}
public void Test__pickLocalizedString(Xol_lang_itm lang, Keyval[] kv_ary, String expd) {
Keyval actl_kv = Jscfg_localizer.pickLocalizedString(lang, "key", kv_ary);
Gftest.Eq__obj_or_null(expd, actl_kv.Val());
}
}

@ -15,11 +15,23 @@ Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.xtns.jsonConfigs.scribunto; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.jsonConfigs.*;
import gplx.xowa.xtns.scribunto.*;
import gplx.xowa.mediawiki.*;
public class Jscfg_xtn_mgr extends Xox_mgr_base {
@Override public byte[] Xtn_key() {return XTN_KEY;} public static final byte[] XTN_KEY = Bry_.new_a7("JsonConfig");
@Override public void Xtn_init_by_wiki(Xowe_wiki wiki) {
Scrib_xtn_mgr scrib_xtn = (Scrib_xtn_mgr)wiki.Xtn_mgr().Get_or_fail(Scrib_xtn_mgr.XTN_KEY);
scrib_xtn.Lib_mgr().Add(new Jscfg_scrib_lib());
}
/*
@Override public void Xtn_ctor_by_app(Xoae_app app) {
Init_xtn();
}
public void Init_xtn() {
JCSingleton singleton = new JCSingleton();
singleton.ConfigModels().Add(JCTabularContent.Model_id, JCTabularContent.Model_id);
XophpEnv.Instance.Singletons().Add(JCSingleton.Singleton_Id, singleton);
XophpEnv.Instance.ClassBldrs().Add(JCTabularContent.Model_id, new JCTabularContentFactory());
}
*/
@Override public Xox_mgr Xtn_clone_new() {return new Jscfg_xtn_mgr();}
}

@ -67,7 +67,7 @@ class Xomath_html_wtr {
}
// write html: <span>math_expr</math>
byte[] unique_bry = wiki.Parser_mgr().Uniq_mgr().Add(Bry__math, math_bry);
byte[] unique_bry = wiki.Parser_mgr().Uniq_mgr().Add(Bool_.Y, Bry__math, math_bry);
Bry_fmt fmt = is_latex ? fmt__latex : fmt__mathjax;
fmt.Bld_many(tmp_bfr, uid, unique_bry);
bfr.Add_bfr_and_clear(tmp_bfr);

@ -52,7 +52,7 @@ public class Pfunc_tag extends Pf_func_base {// REF:CoreParserFunctions.php
// add to UNIQ hash; DATE:2017-03-31
byte[] val = tmp_bfr.To_bry_and_clear();
byte[] key = ctx.Wiki().Parser_mgr().Uniq_mgr().Add(tag_name, val);
byte[] key = ctx.Wiki().Parser_mgr().Uniq_mgr().Add(Bool_.Y, tag_name, val);
bfr.Add(key);
}
finally {tmp_bfr.Mkr_rls();}

@ -14,12 +14,18 @@ GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
import gplx.core.bits.*;
import gplx.core.bits.*; import gplx.core.btries.*;
import gplx.xowa.langs.msgs.*;
import gplx.xowa.xtns.scribunto.procs.*;
public class Scrib_lib_text implements Scrib_lib {
private final Scrib_lib_text__json_util json_util = new Scrib_lib_text__json_util();
public Scrib_lib_text(Scrib_core core) {this.core = core;} private Scrib_core core;
private final Scrib_lib_text__nowiki_util nowiki_util = new Scrib_lib_text__nowiki_util();
private final Scrib_core core;
private final Btrie_slim_mgr trie;
public Scrib_lib_text(Scrib_core core) {
this.core = core;
this.trie = nowiki_util.Make_trie(gplx.xowa.parsers.xndes.Xop_xnde_tag_.Tag__nowiki.Name_bry());
}
public Scrib_lua_mod Mod() {return mod;} private Scrib_lua_mod mod;
public Scrib_lib Init() {procs.Init_by_lib(this, Proc_names); return this;}
public Scrib_lib Clone_lib(Scrib_core core) {return new Scrib_lib_text(core);}
@ -47,7 +53,11 @@ public class Scrib_lib_text implements Scrib_lib {
, Invk_init_text_for_wiki = "init_text_for_wiki", Invk_jsonEncode = "jsonEncode", Invk_jsonDecode = "jsonDecode";
private static final String[] Proc_names = String_.Ary(Invk_unstrip, Invk_unstripNoWiki, Invk_killMarkers, Invk_getEntityTable, Invk_init_text_for_wiki, Invk_jsonEncode, Invk_jsonDecode);
public boolean Unstrip(Scrib_proc_args args, Scrib_proc_rslt rslt) {return rslt.Init_obj(args.Pull_str(0));} // NOTE: XOWA does not use MediaWiki strip markers; just return original; DATE:2015-01-20
public boolean UnstripNoWiki(Scrib_proc_args args, Scrib_proc_rslt rslt) {return rslt.Init_obj(args.Pull_str(0));} // NOTE: XOWA does not use MediaWiki strip markers; just return original; DATE:2015-01-20
public boolean UnstripNoWiki(Scrib_proc_args args, Scrib_proc_rslt rslt) {
// NOTE: XOWA does not use MediaWiki strip markers; just return original; DATE:2015-01-20
byte[] src = args.Pull_bry(0);
return rslt.Init_obj(nowiki_util.Strip_tag(core.Page().Url_bry_safe(), src, trie));
}
public boolean KillMarkers(Scrib_proc_args args, Scrib_proc_rslt rslt) {return rslt.Init_obj(args.Pull_str(0));} // NOTE: XOWA does not use MediaWiki strip markers; just return original; DATE:2015-01-20
public boolean GetEntityTable(Scrib_proc_args args, Scrib_proc_rslt rslt) {
if (html_entities == null) html_entities = Scrib_lib_text_html_entities.new_();
@ -108,10 +118,11 @@ public class Scrib_lib_text implements Scrib_lib {
if (Bitmask_.Has_int(flags, Scrib_lib_text__json_util.Flag__try_fixing))
opts = Bitmask_.Add_int(opts, Scrib_lib_text__json_util.Flag__try_fixing);
return JsonDecodeStatic(args, rslt, core, json_util, json, opts, flags);
Keyval[] rv = JsonDecodeStatic(args, core, json_util, json, opts, flags);
return rslt.Init_obj(rv);
}
public static boolean JsonDecodeStatic
( Scrib_proc_args args, Scrib_proc_rslt rslt, Scrib_core core, Scrib_lib_text__json_util json_util
public static Keyval[] JsonDecodeStatic
( Scrib_proc_args args, Scrib_core core, Scrib_lib_text__json_util json_util
, byte[] json, int opts, int flags) {
// decode json to Object; note that Bool_.Y means ary and Bool_.N means ary
byte rv_tid = json_util.Decode(core.App().Utl__json_parser(), json, opts);
@ -125,10 +136,10 @@ public class Scrib_lib_text implements Scrib_lib {
json_util.Reindex_arrays(reindex_data, rv_as_kvy, false);
rv_as_kvy = reindex_data.Rv_is_kvy() ? (Keyval[])reindex_data.Rv_as_kvy() : (Keyval[])reindex_data.Rv_as_ary();
}
return rslt.Init_obj(rv_as_kvy);
return rv_as_kvy;
}
else
return rslt.Init_obj(json_util.Decode_rslt_as_ary());
return json_util.Decode_rslt_as_ary();
}
public void Notify_wiki_changed() {if (notify_wiki_changed_fnc != null) core.Interpreter().CallFunction(notify_wiki_changed_fnc.Id(), Keyval_.Ary_empty);}

@ -0,0 +1,90 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
import gplx.core.btries.*;
import gplx.core.primitives.*;
public class Scrib_lib_text__nowiki_util {
public Btrie_slim_mgr Make_trie(byte[] tag) {
Bry_bfr tmp = Bry_bfr_.New();
Btrie_slim_mgr rv = Btrie_slim_mgr.ci_u8();
byte[] lhs_bry = tmp.Add_bry_many(Byte_ascii.Angle_bgn_bry, tag, Byte_ascii.Angle_end_bry).To_bry_and_clear();
byte[] rhs_bry = tmp.Add_bry_many(Byte_ascii.Angle_bgn_bry, Byte_ascii.Slash_bry, tag, Byte_ascii.Angle_end_bry).To_bry_and_clear();
rv.Add_obj(lhs_bry, Bool_obj_val.True);
rv.Add_obj(rhs_bry, Bool_obj_val.False);
return rv;
}
public byte[] Strip_tag(byte[] page, byte[] src, Btrie_slim_mgr trie) {
Btrie_rv trv = new Btrie_rv();
Bry_bfr tmp = null;
int bgn = 0;
int end = src.length;
// main loop
boolean lhs_found = false;
int pos = bgn;
int rhs_end = pos, lhs_bgn = pos, lhs_end = pos;
while (pos < end) {
// check byte against trie
Object o = trie.Match_at_w_b0(trv, src[pos], src, pos, end);
// no match; increment and continue;
if (o == null) {
pos++;
continue;
}
// match found
Bool_obj_val tag_marker = (Bool_obj_val)o;
// match is open tag; EX: <tag>
if (tag_marker.Val()) {
// set lhs_bgn and lhs_end; note that if there are multiple open tags, it will only keep the first
if (!lhs_found) {
lhs_found = true;
lhs_bgn = pos;
lhs_end = trv.Pos();
}
}
// match is close tag; EX: </tag>
else {
// only splice if open tag exists; avoids dangling rhs; EX: "a</tag>b"
if (lhs_found) {
lhs_found = false;
if (tmp == null) tmp = Bry_bfr_.New();
// add text from previous </tag> to current <tag>;
tmp.Add_mid(src, rhs_end, lhs_bgn);
// add text between <tag> and </tag>;
tmp.Add_mid(src, lhs_end, pos);
// update </tag> pos
rhs_end = trv.Pos();
}
}
// update pos to after match
pos = trv.Pos();
}
// add remaining text to bfr
if (tmp != null) {
tmp.Add_mid(src, rhs_end, end);
}
return tmp == null ? src : tmp.To_bry_and_clear();
}
}

@ -0,0 +1,55 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
import org.junit.*; import gplx.core.tests.*;
import gplx.core.btries.*;
import gplx.xowa.parsers.xndes.*;
public class Scrib_lib_text__nowiki_util_tst {
private final Scrib_lib_text__nowiki_util_fxt fxt = new Scrib_lib_text__nowiki_util_fxt();
@Test public void Basic() {
// noop
fxt.Test__Strip_tag("abc", "abc");
// one
fxt.Test__Strip_tag("a<nowiki>b</nowiki>c", "abc");
// mixed case
fxt.Test__Strip_tag("a<NOwiki>b</noWIKI>c", "abc");
// multiple: consecutive
fxt.Test__Strip_tag("a<nowiki>b</nowiki>c<nowiki>d</nowiki>e", "abcde");
// dangling: left
fxt.Test__Strip_tag("a<nowiki>b<nowiki>c</nowiki>d", "ab<nowiki>cd");
// dangling: right
fxt.Test__Strip_tag( "a<nowiki>b</nowiki>c</nowiki>d", "abc</nowiki>d");
// nested
fxt.Test__Strip_tag("a<nowiki>b<nowiki>c</nowiki>d</nowiki>e", "ab<nowiki>cd</nowiki>e");
}
}
class Scrib_lib_text__nowiki_util_fxt {
private final Scrib_lib_text__nowiki_util util = new Scrib_lib_text__nowiki_util();
private final Btrie_slim_mgr trie;
public Scrib_lib_text__nowiki_util_fxt() {
this.trie = util.Make_trie(Xop_xnde_tag_.Tag__nowiki.Name_bry());
}
public void Test__Strip_tag(String src, String expd) {
byte[] actl = util.Strip_tag(Bry_.new_a7("Page"), Bry_.new_u8(src), trie);
Gftest.Eq__str(expd, actl);
}
}

@ -25,6 +25,9 @@ public class Scrib_lib_text_tst {
@Test public void Unstrip() {
fxt.Test_scrib_proc_str(lib, Scrib_lib_text.Invk_unstrip, Object_.Ary("a"), "a");
}
@Test public void UnstripNoWiki() {
fxt.Test_scrib_proc_str(lib, Scrib_lib_text.Invk_unstripNoWiki, Object_.Ary("a<nowiki>b</nowiki>c"), "abc");
}
@Test public void GetEntityTable() {
Keyval[] actl = fxt.Test_scrib_proc_rv_as_kv_ary(lib, Scrib_lib_text.Invk_getEntityTable, Object_.Ary());
Tfds.Eq(1510, actl.length); // large result; only test # of entries

@ -15,31 +15,10 @@ Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.mediawiki; import gplx.*; import gplx.xowa.*;
public class XophpArray {
public static boolean popBoolOrN(List_adp list) {return Bool_.Cast(List_adp_.Pop_or(list, false));}
public static byte[] popBryOrNull(List_adp list) {return (byte[])List_adp_.Pop_or(list, null);}
public static String[] array_keys_str(Ordered_hash array) {
int len = array.Len();
String[] rv = new String[len];
for (int i = 0; i < len; i++) {
rv[i] = (String)array.Get_at(i);
}
return rv;
}
public static byte[][] array_keys_bry(Ordered_hash array) {
int len = array.Len();
byte[][] rv = new byte[len][];
for (int i = 0; i < len; i++) {
rv[i] = (byte[])array.Get_at(i);
}
return rv;
}
public static boolean array_key_exists(int key, Ordered_hash array) {return array.Has(key);}
public static boolean array_key_exists(String key, Ordered_hash array) {return array.Has(key);}
public static boolean array_key_exists(byte[] key, Ordered_hash array) {return array.Has(key);}
public static boolean array_is_empty(Ordered_hash array) {
return array.Len() == 0;
}
public static void unset(Ordered_hash array, Object key) {
array.Del(key);
public static boolean in_array(String needle, String[] haystack) {
for (String hay : haystack)
if (String_.Eq(hay, needle))
return true;
return false;
}
}

@ -0,0 +1,54 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.mediawiki; import gplx.*; import gplx.xowa.*;
public class XophpArrayUtl {
public static boolean popBoolOrN(List_adp list) {return Bool_.Cast(List_adp_.Pop_or(list, false));}
public static byte[] popBryOrNull(List_adp list) {return (byte[])List_adp_.Pop_or(list, null);}
public static String[] array_keys_str(Ordered_hash array) {
int len = array.Len();
String[] rv = new String[len];
for (int i = 0; i < len; i++) {
rv[i] = (String)array.Get_at(i);
}
return rv;
}
public static byte[][] array_keys_bry(Ordered_hash array) {
int len = array.Len();
byte[][] rv = new byte[len][];
for (int i = 0; i < len; i++) {
rv[i] = (byte[])array.Get_at(i);
}
return rv;
}
public static boolean array_key_exists(int key, Ordered_hash array) {return array.Has(key);}
public static boolean array_key_exists(String key, Ordered_hash array) {return array.Has(key);}
public static boolean array_key_exists(byte[] key, Ordered_hash array) {return array.Has(key);}
public static boolean array_is_empty(Ordered_hash array) {
return array.Len() == 0;
}
public static void unset(Ordered_hash array, Object key) {
array.Del(key);
}
public static Object[] unset_by_idx(Object[] ary, int idx) {
int ary_len = ary.length;
Object[] rv = new Object[ary_len];
for (int i = 0; i < idx; i++)
rv[i] = ary[i];
for (int i = idx + 1; i < ary_len; i++)
rv[i - 1] = ary[i];
return rv;
}
}

@ -0,0 +1,20 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.mediawiki; import gplx.*; import gplx.xowa.*;
public interface XophpClassBldr {
String Id();
Object Make(Object... args);
}

@ -0,0 +1,25 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.mediawiki; import gplx.*; import gplx.xowa.*;
public class XophpClassBldrs {
private final Ordered_hash hash = Ordered_hash_.New();
public void Add(String id, XophpClassBldr bldr) {
hash.Add(id, bldr);
}
public XophpClassBldr Get_by_or_null(String id) {
return (XophpClassBldr)hash.Get_by(id);
}
}

@ -0,0 +1,22 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.mediawiki; import gplx.*; import gplx.xowa.*;
public class XophpEnv {
public XophpClassBldrs ClassBldrs() {return classBldrs;} private final XophpClassBldrs classBldrs = new XophpClassBldrs();
public Ordered_hash Singletons() {return singletons;} private final Ordered_hash singletons = Ordered_hash_.New();
public static final XophpEnv Instance = new XophpEnv();
}

@ -0,0 +1,81 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.mediawiki; import gplx.*; import gplx.xowa.*;
public class XophpStdClass {
private final List_adp list = List_adp_.New();
private final Ordered_hash hash = Ordered_hash_.New();
public int Len() {return list.Len();}
public boolean Has(String key) {return hash.Has(key);}
public void Add_at_as_itm(XophpStdClass itm) {
list.Add(itm);
}
public void Add_by_as_obj(String key, Object itm) {
list.Add(itm);
hash.Add(key, itm);
}
public XophpStdClass Get_at_as_itm(int idx) {return (XophpStdClass)list.Get_at(idx);}
public Object Get_by_as_obj(String key) {return hash.Get_by(key);}
public XophpStdClass Get_by_as_itm(String key) {return (XophpStdClass)hash.Get_by(key);}
public String Get_by_as_str(String key) {return (String)hash.Get_by(key);}
public String Get_at_as_str(int idx) {return (String)list.Get_at(idx);}
public XophpStdClass Get_by_ary_as_itm(String... keys) {
return (XophpStdClass)Get_by_ary_or_null(false, keys, keys.length - 1, 0);
}
public boolean Comp_str(String key, String expd) {
String actl = Get_by_as_str(key);
return String_.Eq(expd, actl);
}
public void Set_by_as_itm(String key, XophpStdClass itm) {
hash.Add_if_dupe_use_nth(key, itm);
}
public void Set_by_as_itm(String[] keys, XophpStdClass rv) {
int keys_last_idx = keys.length - 1;
XophpStdClass itm = (XophpStdClass)Get_by_ary_or_null(true, keys, keys_last_idx - 1, 0);
itm.Set_by_as_itm(keys[keys_last_idx], rv);
}
public void Set_by_as_str(String key, String val) {
hash.Add_if_dupe_use_nth(key, val);
}
public void Set_at_as_str(int idx, String val) {
list.Del_at(idx);
list.Add_at(idx, val);
}
public void Del_by(String key) {
Object itm = hash.Get_by(key);
hash.Del(key);
list.Del(itm);
}
private Object Get_by_ary_or_null(boolean create, String[] keys, int keys_idx_last, int keys_idx) {
if (keys_idx == keys_idx_last) {
return hash.Get_by(keys[keys_idx_last]);
}
String key = keys[keys_idx];
XophpStdClass itm = Get_by_as_itm(key);
if (itm == null) {
// set
if (create) {
itm = new XophpStdClass();
Set_by_as_itm(key, itm);
}
// get
else {
return null;
}
}
return itm.Get_by_ary_or_null(create, keys, keys_idx_last, keys_idx + 1);
}
}

@ -0,0 +1,90 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.mediawiki; import gplx.*; import gplx.xowa.*;
import gplx.core.brys.*;
public class Xophp_ary implements Bry_bfr_able {
private final Ordered_hash hash = Ordered_hash_.New();
private int nxt_idx;
public Xophp_ary Add(Object val) {
int key = nxt_idx++;
Xophp_ary_itm itm = Xophp_ary_itm.New(key, val);
hash.Add_if_dupe_use_nth(key, itm);
return this;
}
public Xophp_ary Add(int key, Object val) {
nxt_idx = key + 1;
Xophp_ary_itm itm = Xophp_ary_itm.New(key, val);
hash.Add_if_dupe_use_nth(key, itm);
return this;
}
public Xophp_ary Add(double key, Object val) {
int key_as_int = (int)key;
nxt_idx = key_as_int + 1;
Xophp_ary_itm itm = Xophp_ary_itm.New(key_as_int, val);
hash.Add_if_dupe_use_nth(key_as_int, itm);
return this;
}
public Xophp_ary Add(boolean key, Object val) {
int key_as_int = key ? 1 : 0;
nxt_idx = key_as_int + 1;
Xophp_ary_itm itm = Xophp_ary_itm.New(key_as_int, val);
hash.Add_if_dupe_use_nth(key_as_int, itm);
return this;
}
public Xophp_ary Add(String key, Object val) {
Xophp_ary_itm itm = null;
int key_as_int = Int_.Parse_or(key, Int_.Min_value);
if (key_as_int != Int_.Min_value) {
itm = Xophp_ary_itm.New(key_as_int, val);
nxt_idx = key_as_int + 1;
hash.Add_if_dupe_use_nth(key_as_int, itm);
}
else {
itm = Xophp_ary_itm.New(key, val);
hash.Add_if_dupe_use_nth(key, itm);
}
return this;
}
public Object Get(Object key) {
Xophp_ary_itm itm = (Xophp_ary_itm)hash.Get_by(key);
return itm.Val();
}
public void Unset(Object key) {
hash.Del(key);
}
public boolean Has(Object key) {
return hash.Has(key);
}
public Xophp_ary Values() {
Xophp_ary rv = new Xophp_ary();
int len = hash.Len();
for (int i = 0; i < len; i++) {
Xophp_ary_itm old_itm = (Xophp_ary_itm)hash.Get_at(i);
rv.Add(i, old_itm.Val());
}
return rv;
}
public Xophp_ary_itm[] To_ary() {
return (Xophp_ary_itm[])hash.To_ary(Xophp_ary_itm.class);
}
public void To_bfr(Bry_bfr bfr) {
Xophp_ary_itm[] itms = To_ary();
for (Xophp_ary_itm itm : itms) {
itm.To_bfr(bfr);
}
}
public static Xophp_ary New() {return new Xophp_ary();}
}

@ -0,0 +1,43 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.mediawiki; import gplx.*; import gplx.xowa.*;
import gplx.core.brys.*;
public class Xophp_ary_itm implements Bry_bfr_able {
public Xophp_ary_itm(int key_as_int, String key_as_str, Object val) {
this.key_as_int = key_as_int;
this.key_as_str = key_as_str;
this.val = val;
}
public int Key_as_int() {return key_as_int;} private final int key_as_int;
public String Key_as_str() {return key_as_str;} private final String key_as_str;
public Object Val() {return val;} private final Object val;
public void To_bfr(Bry_bfr bfr) {
String key = key_as_str == null ? Int_.To_str(key_as_int) : key_as_str;
bfr.Add_str_u8(key).Add_byte_eq();
if (Type_.Type_by_obj(val) == Xophp_ary.class) {
Xophp_ary sub_ary = (Xophp_ary)val;
bfr.Add_byte_nl();
sub_ary.To_bfr(bfr);
}
else {
bfr.Add_obj(val);
}
}
public static Xophp_ary_itm New(int key, Object val) {return new Xophp_ary_itm(key, null, val);}
public static Xophp_ary_itm New(String key, Object val) {return new Xophp_ary_itm(-1 , key , val);}
}

@ -0,0 +1,137 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.mediawiki; import gplx.*; import gplx.xowa.*;
import org.junit.*; import gplx.core.tests.*;
public class Xophp_ary_tst { // REF: http://php.net/manual/en/language.types.array.php
private final XophpArray_fxt fxt = new XophpArray_fxt();
@Test public void array__kvs() {
// $array = array("foo" => "bar", "bar" => "foo",);
fxt.Test__array
( Xophp_ary.New()
. Add("foo", "bar")
. Add("bar", "foo")
, Xophp_ary_itm.New("foo", "bar")
, Xophp_ary_itm.New("bar", "foo")
);
}
@Test public void array__casting() {
// $array = array(1 => "a", "1" => "b", 1.5 => "c", true => "d",);
fxt.Test__array
( Xophp_ary.New()
. Add(1 , "a")
. Add("1" , "b")
. Add(1.5 , "c")
. Add(true, "d")
, Xophp_ary_itm.New(1, "d"));
}
@Test public void array__mixed() {
// $array = array("foo" => "bar", "bar" => "foo", 100 => -100, -100 => 100);
fxt.Test__array
( Xophp_ary.New()
. Add("foo", "bar")
. Add("bar", "foo")
. Add(100, -100)
. Add(-100, 100)
, Xophp_ary_itm.New("foo", "bar")
, Xophp_ary_itm.New("bar", "foo")
, Xophp_ary_itm.New(100, -100)
, Xophp_ary_itm.New(-100, 100)
);
}
@Test public void array__objs() {
// $array = array("foo", "bar", "hello", "world");
fxt.Test__array
( Xophp_ary.New()
. Add("foo")
. Add("bar")
. Add("hello")
. Add("world")
, Xophp_ary_itm.New(0, "foo")
, Xophp_ary_itm.New(1, "bar")
, Xophp_ary_itm.New(2, "hello")
, Xophp_ary_itm.New(3, "world")
);
}
@Test public void array__unkeyed() {
// $array = array("a", "b", 6 => "c", "d");
fxt.Test__array
( Xophp_ary.New()
. Add("a")
. Add("b")
. Add(6, "c")
. Add("d")
, Xophp_ary_itm.New(0, "a")
, Xophp_ary_itm.New(1, "b")
, Xophp_ary_itm.New(6, "c")
, Xophp_ary_itm.New(7, "d")
);
}
@Test public void array__multidimensional() {
/*
$array = array(
"foo" => "bar",
42 => 24,
"multi" => array(
"dimensional" => array(
"array" => "foo"
)
)
);
*/
fxt.Test__array
( Xophp_ary.New()
. Add("foo" , "bar")
. Add(42 , 24)
. Add("multi" , Xophp_ary.New()
. Add("dimensional", Xophp_ary.New()
. Add("array", "foo")
))
, Xophp_ary_itm.New("foo", "bar")
, Xophp_ary_itm.New(42, "24")
, Xophp_ary_itm.New("multi", Xophp_ary.New()
. Add("dimensional", Xophp_ary.New()
. Add("array", "foo")
))
);
}
@Test public void array__unset() {
Xophp_ary ary = Xophp_ary.New();
ary.Add(0, "a").Add(1, "b");
// delete all
ary.Unset(0);
ary.Unset(1);
fxt.Test__array(ary);
// add new and assert idx is 2
ary.Add("c");
fxt.Test__array(ary, Xophp_ary_itm.New(2, "c"));
ary = ary.Values();
ary.Add("d");
fxt.Test__array(ary, Xophp_ary_itm.New(0, "c"), Xophp_ary_itm.New(1, "d"));
}
}
class XophpArray_fxt {
public void Test__array(Xophp_ary ary, Xophp_ary_itm... expd) {
Xophp_ary_itm[] actl = ary.To_ary();
Gftest.Eq__ary(expd, actl);
}
public void Test__unset(Xophp_ary ary, int idx, Xophp_ary_itm... expd) {
Xophp_ary_itm[] actl = ary.To_ary();
Gftest.Eq__ary(expd, actl);
}
}

@ -0,0 +1,226 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.mediawiki.extensions.JsonConfig.includes; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.extensions.*; import gplx.xowa.mediawiki.extensions.JsonConfig.*;
import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.includes.content.*;
public class JCContent extends TextContent { /** @var array */
private Object rawData = null;
/** @var stdClass|array */
protected XophpStdClass data = null;
/** @var Status */
private XomwStatus status;
/** @var boolean */
private boolean thoroughVar;
/** @var JCContentView|null contains an instance of the view class */
// private Object view = null;
/**
* @param String text Json configuration. If null, default content will be inserted instead
* @param String $modelId
* @param boolean thorough True if extra validation should be performed
*/
public void __construct(byte[] text, String modelId, boolean thorough) {
if (text == null) {
// text = this.getView($modelId).getDefault($modelId);
}
super.__construct(text, modelId);
this.thoroughVar = thorough;
this.status = new XomwStatus();
this.parse();
}
/**
* Get validated data
* @return stdClass|stdClass[]
*/
public XophpStdClass getData() {
return this.data;
}
/**
* Returns data after sanitization, suitable for third-party use
*
* @param stdClass|stdClass[] data
* @return stdClass|stdClass[]
*/
public XophpStdClass getSafeData(XophpStdClass data) {
return data;
}
/**
* Returns JSON Object as resulted from parsing initial text,
* before any validation/modifications took place
* @return mixed
*/
public Object getRawData() {
return this.rawData;
}
/**
* Get content status Object
* @return Status
*/
public XomwStatus getStatus() {
return this.status;
}
/**
* @return boolean False if this configuration has parsing or validation errors
*/
public boolean isValid() {
return this.status.isGood();
}
private static final byte[] Bry__ary__empty = Bry_.new_a7("{}");
public boolean isEmpty() {
byte[] text = Bry_.Trim(this.getNativeData());
return Bry_.Len_eq_0(text) || Bry_.Eq(text, Bry__ary__empty);
}
/**
* Determines whether this content should be considered a "page" for statistics
* In our case, just making sure it's not empty or a redirect
* @param boolean $hasLinks
* @return boolean
*/
public boolean isCountable(boolean hasLinks) {
return !this.isEmpty() && !this.isRedirect();
}
/**
* Returns true if the text is in JSON format.
* @return boolean
*/
public boolean isValidJson() {
return this.rawData != null;
}
/**
* @return boolean true if thorough validation may be needed -
* e.g. rendering HTML or saving new value
*/
public boolean thorough() {
return this.thoroughVar;
}
/**
* Override this method to perform additional data validation
* @param mixed data
* @return mixed
*/
public XophpStdClass validate(XophpStdClass data) {
return data;
}
/**
* Perform initial json parsing and validation
*/
private void parse() {
// String rawText = this.getNativeData();
// parseOpts = FormatJson::STRIP_COMMENTS + FormatJson::TRY_FIXING;
// status = FormatJson::parse(rawText, parseOpts);
// if (!status.isOK()) {
// this.status = status;
// return;
// }
// data = status.getValue();
// // @fixme: HACK - need a deep clone of the data
// // @fixme: but doing (Object)(array)data will re-encode empty [] as {}
// // @performance: re-encoding is likely faster than stripping comments in PHP twice
//// this.rawData = FormatJson::decode(
//// FormatJson::encode(data, FormatJson::ALL_OK), true
//// );
// this.data = this.validate(data);
}
// /**
// * Beautifies JSON prior to save.
// * @param Title $title Title
// * @param \User $user User
// * @param \ParserOptions $popts
// * @return JCContent
// */
// public function preSaveTransform(Title $title, \User $user, \ParserOptions $popts) {
// if (!this.isValidJson()) {
// return this; // Invalid JSON - can't do anything with it
// }
// $formatted = FormatJson::encode(this.getData(), false, FormatJson::ALL_OK);
// if (this.getNativeData() !== $formatted) {
// return new static($formatted, this.getModel(), this.thorough());
// }
// return this;
// }
//
// protected function fillParserOutput(Title $title, $revId, ParserOptions $options,
// $generateHtml, ParserOutput &$output) {
// if (!$generateHtml) {
// return;
// }
//
// status = this.getStatus();
// if (!status.isGood()) {
// // Use user's language, and split parser cache. This should not have a big
// // impact because data namespace is rarely viewed, but viewing it localized
// // will be valuable
// $lang = $options.getUserLangObj();
// $html = status.getHTML(false, false, $lang);
// } else {
// $html = '';
// }
//
// if (status.isOK()) {
// $html .= this
// .getView(this.getModel())
// .valueToHtml(this, $title, $revId, $options, $generateHtml, $output);
// }
//
// $output.setText($html);
// }
//
// /**
// * Get a view Object for this content Object
// * @param String $modelId is required here because parent ctor might not have ran yet
// * @return JCContentView
// */
// protected function getView($modelId) {
// global $wgJsonConfigModels;
// view = this.view;
// if (view === null) {
// $configModels = \ExtensionRegistry::getInstance().getAttribute('JsonConfigModels')
// + $wgJsonConfigModels;
// if (array_key_exists($modelId, $configModels)) {
// $value = $configModels[$modelId];
// if (is_array($value) && array_key_exists('view', $value)) {
// $class = $value['view'];
// view = new $class();
// }
// }
// if (view === null) {
// view = this.createDefaultView();
// }
// this.view = view;
// }
// return view;
// }
//
// /**
// * In case view is not associated with the model for this class, this function will instantiate
// * a default. Override may instantiate a more appropriate view
// * @return JCContentView
// */
// protected function createDefaultView() {
// return new JCDefaultContentView();
// }
}

@ -0,0 +1,138 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.mediawiki.extensions.JsonConfig.includes; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.extensions.*; import gplx.xowa.mediawiki.extensions.JsonConfig.*;
import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.includes.*; import gplx.xowa.mediawiki.includes.content.*;
class JCContentHandler extends TextContentHandler { /**
* Internal format to force pretty-printed json serialization
*/
private static final String CONTENT_FORMAT_JSON_PRETTY = "application/json+pretty";
private JCSingleton singleton;
/**
* @param String $modelId
*/
public void __construct(String modelId, JCSingleton singleton) {
super.__construct(modelId, XomwDefines.CONTENT_FORMAT_JSON, CONTENT_FORMAT_JSON_PRETTY);
this.singleton = singleton;
}
// /**
// * Returns the content's text as-is.
// *
// * @param \Content|JCContent $content This is actually a Content Object
// * @param String|null $format
// * @return mixed
// */
// public function serializeContent(\Content $content, $format = null) {
// this.checkFormat($format);
// $status = $content->getStatus();
// if ($status->isGood()) {
// $data = $content->getData(); // There are no errors, normalize data
// } elseif ($status->isOK()) {
// $data = $content->getRawData(); // JSON is valid, but the data has errors
// } else {
// return $content->getNativeData(); // Invalid JSON - can't do anything with it
// }
//
// return FormatJson::encode($data, $format === self::CONTENT_FORMAT_JSON_PRETTY,
// FormatJson::ALL_OK);
// }
//
// /**
// * @param \Content|JCContent $oldContent
// * @param \Content|JCContent $myContent
// * @param \Content|JCContent $yourContent
// * @return boolean|JCContent
// */
// public function merge3(\Content $oldContent, \Content $myContent, \Content $yourContent) {
// // Almost identical clone of the parent's merge3, except that we use pretty-printed merge,
// // thus allowing much more lenient line-based merging.
//
// this.checkModelID($oldContent->getModel());
// this.checkModelID($myContent->getModel());
// this.checkModelID($yourContent->getModel());
//
// $format = self::CONTENT_FORMAT_JSON_PRETTY;
//
// $old = this.serializeContent($oldContent, $format);
// $mine = this.serializeContent($myContent, $format);
// $yours = this.serializeContent($yourContent, $format);
//
// $ok = wfMerge($old, $mine, $yours, $result);
//
// if (!$ok) {
// return false;
// }
//
// if (!$result) {
// return this.makeEmptyContent();
// }
//
// $mergedContent = this.unserializeContent($result, $format);
//
// return $mergedContent;
// }
//
// /**
// * Returns the name of the diff engine to use.
// *
// * @since 1.21
// *
// * @return String
// */
// protected function getDiffEngineClass() {
// return JCJsonDifferenceEngine::class;
// }
//
/**
* Unserializes a JsonSchemaContent Object.
*
* @param String $text Serialized form of the content
* @param null|String $format The format used for serialization
* @param boolean $isSaving Perform extra validation
* @return JCContent the JsonSchemaContent Object wrapping $text
*/
public JCContent unserializeContent(byte[] text) {return unserializeContent(text, null, true);}
public JCContent unserializeContent(byte[] text, String format, boolean isSaving) {
this.checkFormat(format);
String modelId = this.getModelID();
XophpClassBldr factory = singleton.getContentClass(modelId);
return (JCContent)factory.Make(text, modelId, isSaving);
}
// /**
// * Returns the name of the associated Content class, to
// * be used when creating new objects. Override expected
// * by subclasses.
// *
// * @return String
// */
// protected function getContentClass() {
// $modelId = this.getModelID();
// return JCSingleton::getContentClass($modelId);
// }
//
// /**
// * Creates an empty JsonSchemaContent Object.
// *
// * @return JCContent
// */
// public function makeEmptyContent() {
// // Each model could have its own default JSON value
// // null notifies that default should be used
// return this.unserializeContent(null);
// }
}

@ -0,0 +1,150 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.mediawiki.extensions.JsonConfig.includes; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.extensions.*; import gplx.xowa.mediawiki.extensions.JsonConfig.*;
import gplx.xowa.mediawiki.*;
import gplx.xowa.langs.*; import gplx.xowa.langs.msgs.*;
public class JCDataContent extends JCObjContent { // /**
// * Derived classes must implement this method to perform custom validation
// * using the check(...) calls
// */
// public function validateContent() {
// if (!$this.thorough()) {
// // We are not doing any modifications to the original, so no need to validate it
// return;
// }
//
// $this.test('license', JCValidators::isStringLine(), self::isValidLicense());
// $this.testOptional('description', [ 'en' => '' ], JCValidators::isLocalizedString());
// $this.testOptional('sources', '', JCValidators::isString());
// }
//
// /** Returns a validator function to check if the value is a valid String
// * @return callable
// */
// public static function isValidLicense() {
// return function (JCValue $v, array $path) {
// global $wgJsonConfigAllowedLicenses, $wgLang;
// if (!in_array($v.getValue(), $wgJsonConfigAllowedLicenses, true)) {
// $v.error('jsonconfig-err-license', $path,
// $wgLang.commaList($wgJsonConfigAllowedLicenses));
// return false;
// }
// return true;
// };
// }
/**
* Get data as localized for the given language
* @param Language $lang
* @return mixed
*/
public XophpStdClass getLocalizedData(Xol_lang_itm lang) {
if (!this.isValid()) {
return null;
}
XophpStdClass result = new XophpStdClass();
this.localizeData(result, lang);
return result;
}
/**
* Resolve @Override any specific localizations, and add it to $result
* @param Object $result
* @param Language $lang
*/
@gplx.Virtual protected void localizeData(XophpStdClass result, Xol_lang_itm lang) {
XophpStdClass data = this.getData();
if (data.Has("description")) {
result.Set_by_as_str("description", JCUtils.pickLocalizedString(data.Get_by_as_itm("description"), lang));
}
XophpStdClass license = this.getLicenseObject();
if (license != null) {
// Xol_msg_itm msg = license.Get_by_as_obj("text");
// String text = msg.inLanguage($lang).plain();
// $result.license = (Object)[
// 'code' => $license['code'],
// 'text' => $text,
// 'url' => $license['url'].inLanguage($lang).plain(),
// ];
}
if (data.Has("sources")) {
result.Set_by_as_itm("sources", data.Get_by_as_itm("sources"));
}
}
//
// public function renderDescription( $lang ) {
// $description = $this->getField( 'description' );
//
// if ( $description && !$description->error() ) {
// $description = JCUtils::pickLocalizedString( $description->getValue(), $lang );
// $html = Html::element( 'p', [ 'class' => 'mw-jsonconfig-description' ], $description );
// } else {
// $html = '';
// }
//
// return $html;
// }
//
// /**
// * Renders license HTML, including optional "or later version" clause
// * <a href="...">Creative Commons 1.0</a>, or later version
// * @return String
// */
// public function renderLicense() {
// $license = $this->getLicenseObject();
// if ( $license ) {
// $text = Html::element( 'a', [
// 'href' => $license['url']->plain()
// ], $license['text']->plain() );
//
// $text = wfMessage( 'jsonconfig-license' )->rawParams( $text )->parse();
//
// $html = Html::rawElement( 'p', [ 'class' => 'mw-jsonconfig-license' ], $text );
// } else {
// $html = '';
// }
//
// return $html;
// }
private XophpStdClass getLicenseObject() {
// XophpStdClass license = this.getField("license");
// if ( $license && !$license->error() ) {
// $code = $license->getValue();
//
// return [
// 'code' => $code,
// 'text' => wfMessage( 'jsonconfig-license-name-' . $code ),
// 'url' => wfMessage( 'jsonconfig-license-url-' . $code ),
// ];
// }
return null;
}
// public function renderSources( Parser $parser, Title $title, $revId, ParserOptions $options ) {
// $sources = $this->getField( 'sources' );
//
// if ( $sources && !$sources->error() ) {
// $markup = $sources->getValue();
// $html = Html::rawElement( 'p', [ 'class' => 'mw-jsonconfig-sources' ],
// $parser->parse( $markup, $title, $options, true, true, $revId )->getRawText() );
// } else {
// $html = '';
// }
//
// return $html;
// }
}

@ -0,0 +1,566 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.mediawiki.extensions.JsonConfig.includes; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.extensions.*; import gplx.xowa.mediawiki.extensions.JsonConfig.*;
import gplx.xowa.mediawiki.*;
public class JCObjContent extends JCContent { // /**
// * @var boolean if false, prevents multiple fields from having identical names that differ
// * only by casing
// */
// protected $isCaseSensitive = false;
//
// /** @var boolean if false, ensure the root to be an stdClass, otherwise - an array */
// protected $isRootArray = false;
//
// /**
// * @var JCValue contains raw validation results. At first it is a parsed JSON value, with the
// * root element wrapped into JCValue. As validation progresses, all visited values become
// * wrapped with JCValue.
// */
// protected $validationData;
//
// /** @var mixed */
// protected $dataWithDefaults;
//
// /** @var boolean|null validation status - null=before, true=during, false=done */
// protected $isValidating = null;
//
// /**
// * Override default behavior to include defaults if validation succeeded.
// *
// * @return String|boolean The raw text, or false if the conversion failed.
// */
// public function getWikitextForTransclusion() {
// if ( !$this->getStatus()->isGood() ) {
// // If validation failed, return original text
// return parent::getWikitextForTransclusion();
// }
// if ( !$this->thorough() && $this->validationData !== null ) {
// // ensure that data is sorted in the right order
// self::markUnchecked( $this->validationData );
// }
// return \FormatJson::encode( $this->getDataWithDefaults(), true, \FormatJson::ALL_OK );
// }
//
// protected function createDefaultView() {
// return new JCDefaultObjContentView();
// }
//
// /**
// * Get configuration data with custom defaults
// * @throws \Exception in case validation is not complete
// * @return mixed
// */
// public function getDataWithDefaults() {
// if ( $this->isValidating !== false ) {
// throw new Exception( 'This method may only be called after validation is complete' );
// }
// if ( $this->dataWithDefaults === null ) {
// $this->dataWithDefaults = JCUtils::sanitize( $this->validationData );
// }
// return $this->dataWithDefaults;
// }
//
// /**
// * Get status array that recursively describes dataWithDefaults
// * @throws \Exception
// * @return JCValue
// */
// public function getValidationData() {
// if ( $this->isValidating === null ) {
// throw new Exception(
// 'This method may only be called during or after validation has started'
// );
// }
// return $this->validationData;
// }
//
// /**
// * Call this function before performing data validation inside the derived validate()
// * @param array|Object $data
// * @throws \Exception
// * @return boolean if true, validation should be performed, otherwise all checks will be ignored
// */
// protected function initValidation( $data ) {
// if ( $this->isValidating !== null ) {
// throw new Exception( 'This method may only be called before validation has started' );
// }
// $this->isValidating = true;
// if ( !$this->isRootArray && !is_object( $data ) ) {
// $this->getStatus()->fatal( 'jsonconfig-err-root-Object-expected' );
// } elseif ( $this->isRootArray && !is_array( $data ) ) {
// $this->getStatus()->fatal( 'jsonconfig-err-root-array-expected' );
// } else {
// $this->validationData = new JCValue( JCValue::UNCHECKED, $data );
// return true;
// }
// return false;
// }
//
// /**
// * Derived validate() must return the result of this function
// * @throws \Exception
// * @return array
// */
// protected function finishValidation() {
// if ( !$this->getStatus()->isGood() ) {
// return $this->getRawData(); // validation failed, do not modify
// }
// return null; // Data will be filter-cloned on demand inside self::getData()
// }
//
// /**
// * Populate this data on-demand for efficiency
// * @return array
// */
// public function getData() {
// if ( $this->data === null ) {
// $this->data = JCUtils::sanitize( $this->validationData, true );
// }
// return $this->data;
// }
//
// public function validate( $data ) {
// if ( $this->initValidation( $data ) ) {
// $this->validateContent();
// $data = $this->finishValidation();
// }
// if ( $this->thorough() && $this->validationData !== null ) {
// self::markUnchecked( $this->validationData );
// }
// $this->isValidating = false;
// return $data;
// }
//
// /**
// * Derived classes must implement this method to perform custom validation
// * using the test(...) calls
// */
// abstract public function validateContent();
//
// /**
// * Use this function to test a value, or if the value is missing, use the default value.
// * The value will be tested with validator(s) if provided, even if it was the default.
// * @param String|array $path name of the root field to check, or a path to the field in a nested
// * structure. Nested path should be in the form of
// * [ 'field-level1', 'field-level2', ... ]. For example, if client needs to check
// * validity of the 'value1' in the structure {'key':{'sub-key':['value0','value1']}},
// * $field should be set to [ 'key', 'sub-key', 1 ].
// * @param mixed $default value to be used in case field is not found. $default is passed to the
// * validator if validation fails. If validation of the default passes,
// * the value is considered optional.
// * @param callable $validator callback function as defined in JCValidators::run(). More than one
// * validator may be given. If validators are not provided, any value is accepted
// * @return boolean true if ok, false otherwise
// * @throws \Exception if $this->initValidation() was not called.
// */
// public function testOptional( $path, $default, $validator = null ) {
// $vld = self::convertValidators( $validator, func_get_args(), 2 );
// // first validator will replace missing with the default
// array_unshift( $vld, JCValidators::useDefault( $default ) );
// return $this->testInt( $path, $vld );
// }
//
// /**
// * Use this function to test a field in the data. If missing, the validator(s) will receive
// * JCMissing singleton as a value, and it will be up to the validator(s) to accept it or not.
// * @param String|array $path name of the root field to check, or a path to the field in a nested
// * structure. Nested path should be in the form of
// * [ 'field-level1', 'field-level2', ... ]. For example, if client needs to check
// * validity of the 'value1' in the structure {'key':{'sub-key':['value0','value1']}},
// * $field should be set to [ 'key', 'sub-key', 1 ].
// * @param callable $validator callback function as defined in JCValidators::run().
// * More than one validator may be given.
// * If validators are not provided, any value is accepted
// * @throws \Exception
// * @return boolean true if ok, false otherwise
// */
// public function test( $path, $validator /*...*/ ) {
// $vld = self::convertValidators( $validator, func_get_args(), 1 );
// return $this->testInt( $path, $vld );
// }
//
// /**
// * Use this function to test all values inside an array or an Object at a given path.
// * All validators will be called for each of the sub-values. If there is no value
// * at the given $path, or it is not a container, no action will be taken and no errors reported
// * @param String|array $path path to the container field in a nested structure.
// * Nested path should be in the form of [ 'field-level1', 'field-level2', ... ].
// * For example, if client needs to check validity of the 'value1' in the structure
// * {'key':{'sub-key':['value0','value1']}},
// * $field should be set to [ 'key', 'sub-key', 1 ].
// * @param callable $validator callback function as defined in JCValidators::run().
// * More than one validator may be given.
// * If validators are not provided, any value is accepted
// * @throws \Exception
// * @return boolean true if all values tested ok, false otherwise
// */
// public function testEach( $path, $validator = null /*...*/ ) {
// $vld = self::convertValidators( $validator, func_get_args(), 1 );
// $isOk = true;
// $path = (array)$path;
// $containerField = $this->getField( $path );
// if ( $containerField ) {
// $container = $containerField->getValue();
// if ( is_array( $container ) || is_object( $container ) ) {
// $lastIdx = count( $path );
// if ( is_object( $container ) ) {
// $container = get_object_vars( $container );
// }
// foreach ( array_keys( $container ) as $k ) {
// $path[$lastIdx] = $k;
// $isOk &= $this->testInt( $path, $vld );
// }
// }
// }
// return $isOk;
// }
//
// /**
// * @param array|String $path
// * @param array $validators
// * @return boolean
// * @throws \Exception
// */
// private function testInt( $path, $validators ) {
// if ( !$this->getStatus()->isOK() ) {
// return false; // skip all validation in case of a fatal error
// }
// if ( $this->isValidating !== true ) {
// throw new Exception(
// 'This function should only be called inside the validateContent() override'
// );
// }
// return $this->testRecursive( (array)$path, [], $this->validationData, $validators );
// }
//
// /**
// * @param array $path
// * @param array $fldPath For error reporting, path to the current field
// * @param JCValue $jcv
// * @param mixed $validators
// * @throws \Exception
// * @@gplx.Internal protected param JCValue $status
// * @return boolean
// */
// private function testRecursive( array $path, array $fldPath, JCValue $jcv, $validators ) {
// // Go recursively through all fields in path until empty, and validate last
// if ( !$path ) {
// // keep this branch here since we allow validation of the whole Object ($path==[])
// return $this->testValue( $fldPath, $jcv, $validators );
// }
// $fld = array_shift( $path );
// if ( is_array( $jcv->getValue() ) && ctype_digit( $fld ) ) {
// $fld = (int)$fld;
// }
// if ( !is_int( $fld ) && !is_string( $fld ) ) {
// throw new Exception( 'Unexpected field type, only strings and integers are allowed' );
// }
// $fldPath[] = $fld;
//
// $subJcv = $this->getField( $fld, $jcv );
// if ( $subJcv === null ) {
// $msg =
// is_int( $fld ) && !is_array( $jcv->getValue() ) ? 'jsonconfig-err-array-expected'
// : 'jsonconfig-err-Object-expected';
// $this->addValidationError( wfMessage( $msg, JCUtils::fieldPathToString( $fldPath ) ) );
// return false;
// }
//
// /** @var boolean $reposition - should the field be deleted and re-added at the end
// * this is only needed for viewing and saving */
// $reposition = $this->thorough() && is_string( $fld ) && $subJcv !== false;
// if ( $subJcv === false || $subJcv->isUnchecked() ) {
// // We never went down this path before
// // Check that field exists, and is not case-duplicated
// if ( is_int( $fld ) ) {
// if ( count( $jcv->getValue() ) < $fld ) {
// // Allow existing index or index+1 for appending last item
// throw new Exception( "List index is too large at '" .
// JCUtils::fieldPathToString( $fldPath ) .
// "'. Index may not exceed list size." );
// }
// } elseif ( !$this->isCaseSensitive ) {
// // if we didn't find it before, it could have been misnamed
// $norm = $this->normalizeField( $jcv, $fld, $fldPath );
// if ( $norm === null ) {
// return false;
// } elseif ( $norm ) {
// $subJcv = $this->getField( $fld, $jcv );
// $reposition = false; // normalization already does that
// }
// }
// if ( $subJcv === null ) {
// throw new Exception( 'Logic error - subJcv must be valid here' );
// } elseif ( $subJcv === false ) {
// // field does not exist
// $initValue = !$path ? null : ( is_string( $path[0] ) ? new stdClass() : [] );
// $subJcv = new JCValue( JCValue::MISSING, $initValue );
// }
// }
// $isOk = $this->testRecursive( $path, $fldPath, $subJcv, $validators );
//
// // Always remove and re-append the field
// if ( $subJcv->isMissing() ) {
// $jcv->deleteField( $fld );
// } else {
// if ( $reposition ) {
// $jcv->deleteField( $fld );
// }
// $jcv->setField( $fld, $subJcv );
// if ( $jcv->isMissing() || $jcv->isUnchecked() ) {
// $jcv->status( JCValue::VISITED );
// }
// }
// return $isOk;
// }
//
// /**
// * @param array $fldPath
// * @param JCValue $jcv
// * @param array $validators
// * @return boolean
// */
// private function testValue( array $fldPath, JCValue $jcv, $validators ) {
// // We have reached the last level of the path, test the actual value
// if ( $validators !== null ) {
// $isRequired = $jcv->defaultUsed();
// JCValidators::run( $validators, $jcv, $fldPath, $this );
// $err = $jcv->error();
// if ( $err ) {
// if ( is_object( $err ) ) {
// // if ( !$isRequired ) {
// // // User supplied value, so we don't know if the value is required or not
// // // if $default passes validation, original value was optional
// // $isRequired = !JCValidators::run(
// // $validators, $fldPath, JCValue::getMissing(), $this
// // );
// // }
// $this->addValidationError( $err, !$isRequired );
// }
// return false;
// } elseif ( $jcv->isUnchecked() ) {
// $jcv->status( JCValue::CHECKED );
// }
// }
// // if ( $this->thorough() && $jcv->status() === JCValue::CHECKED ) {
// // // Check if the value is the same as default - use a cast to array
// // // hack to compare objects
// // $isRequired = (boolean)JCValidators::run( $validators, $fldPath, JCMissing::get(), $this );
// // if ( ( is_object( $jcv ) && is_object( $default ) && (array)$jcv === (array)$default )
// // || ( !is_object( $default ) && $jcv === $default )
// // ) {
// // $newStatus = JCValue::SAME_AS_DEFAULT;
// // }
// // }
// return true;
// }
//
// /**
// * Recursively reorder all sub-elements - checked first, followed by unchecked.
// * Also, convert all sub-elements to JCValue(UNCHECKED) if at least one of them was JCValue
// * This is useful for HTML rendering to indicate unchecked items
// * @param JCValue $data
// */
// private static function markUnchecked( JCValue $data ) {
// $val = $data->getValue();
// $isObject = is_object( $val );
// if ( !$isObject && !is_array( $val ) ) {
// return;
// }
// $result = null;
// $firstPass = true;
// $hasJcv = false;
// // Two pass loop - first pass moves all checked values to the result,
// // second pass moves the rest of of the values, possibly converting them to JCValue
// while ( true ) {
// foreach ( $val as $key => $subVal ) {
// /** @var JCValue|mixed $subVal */
// $isJcv = is_a( $subVal, '\JsonConfig\JCValue' );
// if ( $firstPass && $isJcv ) {
// // On the first pass, recursively process subelements if they were visited
// self::markUnchecked( $subVal );
// $move = $isObject && !$subVal->isUnchecked();
// $hasJcv = true;
// } else {
// $move = false;
// }
// if ( $move || !$firstPass ) {
// if ( !$isJcv ) {
// $subVal = new JCValue( JCValue::UNCHECKED, $subVal );
// }
// if ( $result === null ) {
// $result = $isObject ? new stdClass() : [];
// }
// if ( $isObject ) {
// $result->$key = $subVal;
// unset( $val->$key );
// } else {
// // No need to unset - all values in an array are moved in the second pass
// $result[] = $subVal;
// }
// }
// }
//
// if ( ( $result === null && !$hasJcv ) || !$firstPass ) {
// // either nothing was found, or we are done with the second pass
// if ( $result !== null ) {
// $data->setValue( $result );
// }
// return;
// }
// $firstPass = false;
// }
// }
//
// /**
// * @param Message $error
// * @param boolean $isOptional
// */
// public function addValidationError( Message $error, $isOptional = false ) {
// $text = $error->plain();
// // @TODO fixme - need to re-enable optional field detection & reporting
// // if ( $isOptional ) {
// // $text .= ' ' . wfMessage( 'jsonconfig-optional-field' )->plain();
// // }
// $this->getStatus()->error( $text );
// }
/** Get field from data Object/array
* @param String|int|array $field
* @param stdClass|array|JCValue $data
* @throws \Exception
* @return false|null|JCValue search result:
* false if not found
* null if error (argument type does not match storage)
* JCValue if the value is found
*/
public JCValue getField(int field) {return getFieldWkr(field, null, null, null);}
public JCValue getField(int field, Object data) {return getFieldWkr(field, null, null, data);}
public JCValue getField(String field) {return getFieldWkr(-1, field, null, null);}
public JCValue getField(String field, Object data) {return getFieldWkr(-1, field, null, data);}
public JCValue getField(String[] fields) {return getFieldWkr(-1, null, fields, null);}
public JCValue getField(String[] fields, Object data) {return getFieldWkr(-1, null, fields, data);}
public JCValue getFieldWkr(int fldInt, String fldStr, String[] fldAry, Object data) {
if (data == null) {
// data = this.getValidationData();
}
if (fldAry == null) {
data = getFieldByItem(fldInt, fldStr, data);
if (data == null)
return null;
}
else {
for (String fld : fldAry) {
data = getFieldByItem(-1, fld, data);
if (data == null)
return null;
}
}
if (Type_.Eq_by_obj(data, JCValue.class)) {
return (JCValue)data;
} else {
// return new JCValue(JCValue.UNCHECKED, data);
return null;
}
}
private Object getFieldByItem(int fldInt, String fldStr, Object data) {
if (fldInt == -1 && fldStr == null) {
throw Err_.new_wo_type("Field must be either int or String");
}
if (Type_.Eq_by_obj(data, JCValue.class)) {
data = ((JCValue)data).getValue();
}
int typeId = XomwTypeUtl.To_type_id(data);
boolean isObject = typeId == Type_ids_.Id__obj;
boolean isArray = typeId == Type_ids_.Id__array;
if (fldStr != null ? !(isObject || isArray) : !isArray) {
return null;
}
if (isObject) {
XophpStdClass dataAsMap = (XophpStdClass)data;
return dataAsMap.Get_by_as_itm(fldStr);
} else if (isArray) {
Object dataAsAry = Array_.cast(data);
if (fldInt < Array_.Len(dataAsAry))
return Array_.Get_at(dataAsAry, fldInt);
}
return null;
}
// /**
// * @param JCValue $jcv
// * @param int|String $fld
// * @param array $fldPath
// * @throws \Exception
// * @return boolean|null true if renamed, false if not found or original unchanged,
// * null if duplicate (error)
// */
// private function normalizeField( JCValue $jcv, $fld, array $fldPath ) {
// $valueRef = $jcv->getValue();
// $foundFld = false;
// $isError = false;
// foreach ( $valueRef as $k => $v ) {
// if ( 0 === strcasecmp( $k, $fld ) ) {
// if ( $foundFld !== false ) {
// $isError = true;
// break;
// }
// $foundFld = $k;
// }
// }
// if ( $isError ) {
// $this->addValidationError( wfMessage( 'jsonconfig-duplicate-field',
// JCUtils::fieldPathToString( $fldPath ) ) );
// if ( $this->thorough() ) {
// // Mark all duplicate fields as errors
// foreach ( $valueRef as $k => $v ) {
// if ( 0 === strcasecmp( $k, $fld ) ) {
// if ( !is_a( $v, '\JsonConfig\JCValue' ) ) {
// $v = new JCValue( JCValue::UNCHECKED, $v );
// $jcv->setField( $k, $v );
// }
// $v->error( true );
// }
// }
// }
// return null;
// } elseif ( $foundFld !== false && $foundFld !== $fld ) {
// // key had different casing, rename it to canonical
// $jcv->setField( $fld, $jcv->deleteField( $foundFld ) );
// return true;
// }
// return false;
// }
//
// /**
// * @param null|callable|array $param first validator parameter
// * @param array $funcArgs result of func_get_args() call
// * @param int $skipArgs how many non-validator arguments to remove
// * from the beginning of the $funcArgs
// * @return array of validators
// */
// private static function convertValidators( $param, $funcArgs, $skipArgs ) {
// if ( $param === null ) {
// return []; // no validators given
// } elseif ( is_array( $param ) && !is_callable( $param, true ) ) {
// return $param; // first argument is an array of validators
// } else {
// return array_slice( $funcArgs, $skipArgs ); // remove fixed params from the beginning
// }
// }
}

@ -0,0 +1,995 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.mediawiki.extensions.JsonConfig.includes; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.extensions.*; import gplx.xowa.mediawiki.extensions.JsonConfig.*;
import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.includes.*;
public class JCSingleton {
// /**
// * @var array describes how a title should be handled by JsonConfig extension.
// * The structure is an array of array of ...:
// * { int_namespace => { name => { allows-sub-namespaces => configuration_array } } }
// */
// public static $titleMap = [];
//
// /**
// * @var String[]|false[] containing all the namespaces handled by JsonConfig
// * Maps namespace id (int) => namespace name (String).
// * If false, presumes the namespace has been registered by core or another extension
// */
// public static $namespaces = [];
//
// /**
// * @var MapCacheLRU[] contains a cache of recently resolved JCTitle's
// * as namespace => MapCacheLRU
// */
// public static $titleMapCacheLru = [];
/**
* @var MapCacheLRU[] contains a cache of recently requested content objects
* as namespace => MapCacheLRU
*/
private final Ordered_hash mapCacheLru = Ordered_hash_.New();
public Xomw_page_fetcher Store() {return store;} public void Store_(Xomw_page_fetcher v) {this.store = v;} private Xomw_page_fetcher store;
public Xophp_ary ConfigModels() {return configModels;} private final Xophp_ary configModels = new Xophp_ary();
// /**
// * @var TitleParser cached invariant title parser
// */
// public static $titleParser;
//
// /**
// * Initializes singleton state by parsing $wgJsonConfig* values
// * @throws Exception
// */
// private static function init() {
// static $isInitialized = false;
// if ($isInitialized) {
// return;
// }
// $isInitialized = true;
// global $wgNamespaceContentModels, $wgContentHandlers, $wgJsonConfigs, $wgJsonConfigModels;
// list(self::$titleMap, self::$namespaces) = self::parseConfiguration(
// $wgNamespaceContentModels,
// $wgContentHandlers,
// array_replace_recursive(
// \ExtensionRegistry::getInstance()->getAttribute('JsonConfigs'), $wgJsonConfigs
// ),
// array_replace_recursive(
// \ExtensionRegistry::getInstance()->getAttribute('JsonConfigModels'),
// $wgJsonConfigModels
// )
// );
// }
//
// /**
// * @param array $namespaceContentModels $wgNamespaceContentModels
// * @param array $contentHandlers $wgContentHandlers
// * @param array $configs $wgJsonConfigs
// * @param array $models $wgJsonConfigModels
// * @param boolean $warn if true, calls wfLogWarning() for all errors
// * @return array [ $titleMap, $namespaces ]
// */
// public static function parseConfiguration(
// array $namespaceContentModels, array $contentHandlers,
// array $configs, array $models, $warn = true
// ) {
// $defaultModelId = 'JsonConfig';
// // @codingStandardsIgnoreStart - T154789
// $warnFunc = $warn ? 'wfLogWarning' : function() {};
// // @codingStandardsIgnoreEnd
//
// $namespaces = [];
// $titleMap = [];
// foreach ($configs as $confId => &$conf) {
// if (!is_string($confId)) {
// $warnFunc(
// "JsonConfig: Invalid \$wgJsonConfigs['$confId'], the key must be a String"
// );
// continue;
// }
// if (null == self::getConfObject($warnFunc, $conf, $confId)) {
// continue; // warned inside the function
// }
//
// $modelId = property_exists($conf, 'model')
// ? ($conf->model ? : $defaultModelId) : $confId;
// if (!array_key_exists($modelId, $models)) {
// if ($modelId == $defaultModelId) {
// $models[$defaultModelId] = null;
// } else {
// $warnFunc("JsonConfig: Invalid \$wgJsonConfigs['$confId']: " .
// "Model '$modelId' is not defined in \$wgJsonConfigModels");
// continue;
// }
// }
// if (array_key_exists($modelId, $contentHandlers)) {
// $warnFunc("JsonConfig: Invalid \$wgJsonConfigs['$confId']: Model '$modelId' is " .
// "already registered in \$contentHandlers to {$contentHandlers[$modelId]}");
// continue;
// }
// $conf->model = $modelId;
//
// $ns = self::getConfVal($conf, 'namespace', NS_CONFIG);
// if (!is_int($ns) || $ns % 2 !== 0) {
// $warnFunc("JsonConfig: Invalid \$wgJsonConfigs['$confId']: " .
// "Namespace $ns should be an even number");
// continue;
// }
// // Even though we might be able to override default content model for namespace,
// // lets keep things clean
// if (array_key_exists($ns, $namespaceContentModels)) {
// $warnFunc("JsonConfig: Invalid \$wgJsonConfigs['$confId']: Namespace $ns is " .
// "already set to handle model '$namespaceContentModels[$ns]'");
// continue;
// }
//
// // nsName & nsTalk are handled later
// self::getConfVal($conf, 'pattern', '');
// self::getConfVal($conf, 'cacheExp', 24 * 60 * 60);
// self::getConfVal($conf, 'cacheKey', '');
// self::getConfVal($conf, 'flaggedRevs', false);
// self::getConfVal($conf, 'license', false);
// $islocal = self::getConfVal($conf, 'isLocal', true);
//
// // Decide if matching configs should be stored on this wiki
// $storeHere = $islocal || property_exists($conf, 'store');
// if (!$storeHere) {
// // 'store' does not exist, use it as a flag to indicate remote storage
// $conf->store = false;
// $remote = self::getConfObject($warnFunc, $conf, 'remote', $confId, 'url');
// if (null == $remote) {
// continue; // warned inside the function
// }
// if (self::getConfVal($remote, 'url', '') == '') {
// $warnFunc("JsonConfig: Invalid \$wgJsonConfigs['$confId']['remote']['url']: " .
// "API URL is not set, and this config is not being stored locally");
// continue;
// }
// self::getConfVal($remote, 'username', '');
// self::getConfVal($remote, 'password', '');
// } else {
// if (property_exists($conf, 'remote')) {
// // non-fatal -- simply ignore the 'remote' setting
// $warnFunc("JsonConfig: In \$wgJsonConfigs['$confId']['remote'] is set for " .
// "the config that will be stored on this wiki. " .
// "'remote' parameter will be ignored."
// );
// }
// $conf->remote = null;
// $store = self::getConfObject($warnFunc, $conf, 'store', $confId);
// if (null == $store) {
// continue; // warned inside the function
// }
// self::getConfVal($store, 'cacheNewValue', true);
// self::getConfVal($store, 'notifyUrl', '');
// self::getConfVal($store, 'notifyUsername', '');
// self::getConfVal($store, 'notifyPassword', '');
// }
//
// // Too lazy to write proper error messages for all parameters.
// if ((isset($conf->nsTalk) && !is_string($conf->nsTalk)) ||
// !is_string($conf->pattern) ||
// !is_bool($islocal) || !is_int($conf->cacheExp) || !is_string($conf->cacheKey)
// || !is_bool($conf->flaggedRevs)
// ) {
// $warnFunc("JsonConfig: Invalid type of one of the parameters in " .
// "\$wgJsonConfigs['$confId'], please check documentation");
// continue;
// }
// if (isset($remote)) {
// if (!is_string($remote->url) || !is_string($remote->username) ||
// !is_string($remote->password)
// ) {
// $warnFunc("JsonConfig: Invalid type of one of the parameters in " .
// "\$wgJsonConfigs['$confId']['remote'], please check documentation");
// continue;
// }
// }
// if (isset($store)) {
// if (!is_bool($store->cacheNewValue) || !is_string($store->notifyUrl) ||
// !is_string($store->notifyUsername) || !is_string($store->notifyPassword)
// ) {
// $warnFunc("JsonConfig: Invalid type of one of the parameters in " .
// " \$wgJsonConfigs['$confId']['store'], please check documentation");
// continue;
// }
// }
// if ($storeHere) {
// // If nsName is given, add it to the list, together with the talk page
// // Otherwise, create a placeholder for it
// if (property_exists($conf, 'nsName')) {
// if ($conf->nsName == false) {
// // Non JC-specific namespace, don't register it
// if (!array_key_exists($ns, $namespaces)) {
// $namespaces[$ns] = false;
// }
// } elseif ($ns == NS_CONFIG) {
// $warnFunc("JsonConfig: Parameter 'nsName' in \$wgJsonConfigs['$confId'] " .
// "is not supported for namespace == NS_CONFIG ($ns)");
// } else {
// $nsName = $conf->nsName;
// $nsTalk = isset($conf->nsTalk) ? $conf->nsTalk : ($nsName . '_talk');
// if (!is_string($nsName) || $nsName == '') {
// $warnFunc("JsonConfig: Invalid \$wgJsonConfigs['$confId']: " .
// "if given, nsName must be a String");
// continue;
// } elseif (array_key_exists($ns, $namespaces) &&
// $namespaces[$ns] !== null
// ) {
// if ($namespaces[$ns] !== $nsName ||
// $namespaces[$ns + 1] !== $nsTalk
// ) {
// $warnFunc("JsonConfig: \$wgJsonConfigs['$confId'] - " .
// "nsName has already been set for namespace $ns");
// }
// } else {
// $namespaces[$ns] = $nsName;
// $namespaces[$ns + 1] =
// isset($conf->nsTalk) ? $conf->nsTalk : ($nsName . '_talk');
// }
// }
// } elseif (!array_key_exists($ns, $namespaces) || $namespaces[$ns] == false) {
// $namespaces[$ns] = null;
// }
// }
//
// if (!array_key_exists($ns, $titleMap)) {
// $titleMap[$ns] = [ $conf ];
// } else {
// $titleMap[$ns][] = $conf;
// }
// }
//
// // Add all undeclared namespaces
// $missingNs = 1;
// foreach ($namespaces as $ns => $nsName) {
// if ($nsName == null) {
// $nsName = 'Config';
// if ($ns !== NS_CONFIG) {
// $nsName .= $missingNs;
// $warnFunc(
// "JsonConfig: Namespace $ns does not have 'nsName' defined, using '$nsName'"
// );
// $missingNs += 1;
// }
// $namespaces[$ns] = $nsName;
// $namespaces[$ns + 1] = $nsName . '_talk';
// }
// }
//
// return [ $titleMap, $namespaces ];
// }
//
// /**
// * Helper function to check if configuration has a field set, and if not, set it to default
// * @param stdClass $conf
// * @param String $field
// * @param mixed $default
// * @return mixed
// */
// private static function getConfVal(& $conf, $field, $default) {
// if (property_exists($conf, $field)) {
// return $conf->$field;
// }
// $conf->$field = $default;
// return $default;
// }
//
// /**
// * Helper function to check if configuration has a field set, and if not, set it to default
// * @param $warnFunc
// * @param $value
// * @param String $field
// * @param String $confId
// * @param String $treatAsField
// * @return null|Object|stdClass
// */
// private static function getConfObject(
// $warnFunc, & $value, $field, $confId = null, $treatAsField = null
// ) {
// if (!$confId) {
// $val = & $value;
// } else {
// if (!property_exists($value, $field)) {
// $value->$field = null;
// }
// $val = & $value->$field;
// }
// if ($val == null || $val == true) {
// $val = new stdClass();
// } elseif (is_array($val)) {
// $val = (Object)$val;
// } elseif (is_string($val) && $treatAsField !== null) {
// // treating this String value as a sub-field
// $val = (Object)[ $treatAsField => $val ];
// } elseif (!is_object($val)) {
// $warnFunc("JsonConfig: Invalid \$wgJsonConfigs" . ($confId ? "['$confId']" : "") .
// "['$field'], the value must be either an array or an Object");
// return null;
// }
// return $val;
// }
/**
* Get content Object from the local LRU cache, or null if doesn't exist
* @param TitleValue $titleValue
* @return null|JCContent
*/
public JCContent getContentFromLocalCache(String wiki, String ns, String page) {
// Some of the titleValues are remote, and their namespace might not be declared
// in the current wiki. Since TitleValue is a content Object, it does not validate
// the existence of namespace, hence we use it as a simple storage.
// Producing an artificial String key by appending (namespaceID . ':' . titleDbKey)
// seems wasteful and redundant, plus most of the time there will be just a single
// namespace declared, so this structure seems efficient and easy enough.
String mapCacheLruKey = String_.Concat(wiki, "|", ns);
Ordered_hash cache = (Ordered_hash)mapCacheLru.Get_by(mapCacheLruKey);
if (cache == null) {
cache = Ordered_hash_.New();
mapCacheLru.Add(mapCacheLruKey, cache);
}
return (JCContent)cache.Get_by(page);
}
/**
* Get content Object for the given title.
* Namespace ID does not need to be defined in the current wiki,
* as long as it is defined in $wgJsonConfigs.
* @param TitleValue|JCTitle $titleValue
* @return boolean|JCContent Returns false if the title is not handled by the settings
*/
public JCContent getContent(String wiki, String ns, String page) {
JCContent content = getContentFromLocalCache(wiki, ns, page);
if (content == null) {
byte[] content_bry = store.Get_wtxt(Bry_.new_u8(wiki), Bry_.new_u8(page));
if (content_bry != null) {
JCContentHandler handler = new JCContentHandler();
handler.__construct(JCTabularContent.Model_id, this);
content = handler.unserializeContent(content_bry, null, false);
}
// $jct = self::parseTitle($titleValue);
// if ($jct) {
// $store = new JCCache($jct);
// $content = $store->get();
// if (is_string($content)) {
// // Convert String to the content Object if needed
// $handler = new JCContentHandler($jct->getConfig()->model);
// $content = $handler->unserializeContent($content, null, false);
// }
// } else {
// $content = false;
// }
// self::mapCacheLru[$titleValue->getNamespace()]
// ->set($titleValue->getDBkey(), $content);
}
return content;
}
// /**
// * Parse json text into a content Object for the given title.
// * Namespace ID does not need to be defined in the current wiki,
// * as long as it is defined in $wgJsonConfigs.
// * @param TitleValue $titleValue
// * @param String $jsonText json content
// * @param boolean $isSaving if true, performs extensive validation during unserialization
// * @return boolean|JCContent Returns false if the title is not handled by the settings
// * @throws Exception
// */
// public static function parseContent(TitleValue $titleValue, $jsonText, $isSaving = false) {
// $jct = self::parseTitle($titleValue);
// if ($jct) {
// $handler = new JCContentHandler($jct->getConfig()->model);
// return $handler->unserializeContent($jsonText, null, $isSaving);
// }
//
// return false;
// }
//
// /**
// * Mostly for debugging purposes, this function returns initialized @gplx.Internal protected JsonConfig settings
// * @return array[] map of namespaceIDs to list of configurations
// */
// public static function getTitleMap() {
// self::init();
// return self::$titleMap;
// }
/**
* Get the name of the class for a given content model
* @param String $modelId
* @return null|String
*/
public XophpClassBldr getContentClass(String modelId) {
// global $wgJsonConfigModels;
// $configModels = array_replace_recursive(
// \ExtensionRegistry::getInstance()->getAttribute('JsonConfigModels'),
// $wgJsonConfigModels
// );
String clz = null;
if (configModels.Has(modelId)) {
Object val = configModels.Get(modelId);
if (Type_.Type_by_obj(val) == Xophp_ary.class) {
Xophp_ary val_as_ary = (Xophp_ary)val;
if (val_as_ary.Has("class")) {
Gfo_usr_dlg_.Instance.Warn_many("", "", "JsonConfig: Invalid +$wgJsonConfigModels['modelId'] array " + "value, 'cl"+ "ass' not found");
} else {
clz = (String)val_as_ary.Get("class");
}
} else {
clz = (String)val;
}
}
if (clz == null) {
clz = "JCContent"; // __NAMESPACE__ . '\JCContent';
}
return XophpEnv.Instance.ClassBldrs().Get_by_or_null(clz);
}
// /**
// * Given a title (either a user-given String, or as an Object), return JCTitle
// * @param Title|TitleValue|String $value
// * @param int|null $namespace Only used when title is a String
// * @return JCTitle|null|false false if unrecognized namespace,
// * and null if namespace is handled but does not match this title
// * @throws Exception
// */
// public static function parseTitle($value, $namespace = null) {
// if ($value == null || $value == '' || $value == false) {
// // In some weird cases $value is null
// return false;
// } elseif ($value instanceof JCTitle) {
// // Nothing to do
// return $value;
// } elseif ($namespace !== null && !is_integer($namespace)) {
// throw new Exception('$namespace parameter must be either null or an integer');
// }
//
// // figure out the namespace ID (int) - we don't need to parse the String if ns is unknown
// if ($value instanceof LinkTarget) {
// if ($namespace == null) {
// $namespace = $value->getNamespace();
// }
// } elseif (is_string($value)) {
// if ($namespace == null) {
// throw new Exception('$namespace parameter is missing for String $value');
// }
// } else {
// wfLogWarning('Unexpected title param type ' . gettype($value));
// return false;
// }
//
// // Search title map for the matching configuration
// $map = self::getTitleMap();
// if (array_key_exists($namespace, $map)) {
// // Get appropriate LRU cache Object
// if (!array_key_exists($namespace, self::$titleMapCacheLru)) {
// self::$titleMapCacheLru[$namespace] = $cache = new MapCacheLRU(20);
// } else {
// $cache = self::$titleMapCacheLru[$namespace];
// }
//
// // Parse String if needed
// // TODO: should the String parsing also be cached?
// if (is_string($value)) {
// $language = Language::factory('en');
// if (!self::$titleParser) {
// self::$titleParser =
// new MediaWikiTitleCodec(
// $language,
// new GenderCache(),
// [],
// new FauxInterwikiLookup());
// }
// // Interwiki prefixes are a special case for title parsing:
// // first letter is not capitalized, namespaces are not resolved, etc.
// // So we prepend an interwiki prefix to fool title codec, and later remove it.
// try {
// $value = FauxInterwikiLookup::INTERWIKI_PREFIX . ':' . $value;
// $parts = self::$titleParser->splitTitleString($value);
//
// // Defensive coding - ensure the parsing has proceeded as expected
// if ($parts['dbkey'] == '' || $parts['namespace'] !== 0 ||
// $parts['fragment'] !== '' || $parts['local_interwiki'] !== false ||
// $parts['interwiki'] !== FauxInterwikiLookup::INTERWIKI_PREFIX
// ) {
// return null;
// }
// } catch (MalformedTitleException $e) {
// return null;
// }
//
// // At this point, only support wiki namespaces that capitalize title's first char,
// // but do not enable sub-pages.
// // This way data can already be stored on Mediawiki namespace everywhere, or
// // places like commons and zerowiki.
// // Another implicit limitation: there might be an issue if data is stored on a wiki
// // with the non-default ucfirst(), e.g. az, kaa, kk, tr -- they convert "i" to "I"
// $dbKey = $language->ucfirst($parts['dbkey']);
// } else {
// $dbKey = $value->getDBkey();
// }
//
// // A bit weird here: cache will store JCTitle objects or false if the namespace
// // is known to JsonConfig but the dbkey does not match. But in case the title is not
// // handled, this function returns null instead of false if the namespace is known,
// // and false otherwise
// $result = $cache->get($dbKey);
// if ($result == null) {
// $result = false;
// foreach ($map[$namespace] as $conf) {
// $re = $conf->pattern;
// if (!$re || preg_match($re, $dbKey)) {
// $result = new JCTitle($namespace, $dbKey, $conf);
// break;
// }
// }
//
// $cache->set($dbKey, $result);
// }
//
// // return null if the given namespace is mentioned in the config,
// // but title doesn't match
// return $result ?: null;
//
// } else {
// // return false if JC doesn't know anything about this namespace
// return false;
// }
// }
//
// /**
// * Returns an array with settings if the $titleValue Object is handled by the JsonConfig
// * extension, false if unrecognized namespace,
// * and null if namespace is handled but not this title
// * @param TitleValue $titleValue
// * @return stdClass|false|null
// * @deprecated use JCSingleton::parseTitle() instead
// */
// public static function getMetadata($titleValue) {
// $jct = self::parseTitle($titleValue);
// return $jct ? $jct->getConfig() : $jct;
// }
//
// /**
// * Only register NS_CONFIG if running on the MediaWiki instance which houses
// * the JSON configs (i.e. META)
// * @TODO FIXME: Always return true
// * @param array &$namespaces
// * @return true|void
// */
// public static function onCanonicalNamespaces(array &$namespaces) {
// if (!self::jsonConfigIsStorage()) {
// return true;
// }
//
// self::init();
// foreach (self::$namespaces as $ns => $name) {
// if ($name == false) { // must be already declared
// if (!array_key_exists($ns, $namespaces)) {
// wfLogWarning("JsonConfig: Invalid \$wgJsonConfigs: Namespace $ns " .
// "has not been declared by core or other extensions");
// }
// } elseif (array_key_exists($ns, $namespaces)) {
// wfLogWarning("JsonConfig: Invalid \$wgJsonConfigs: Namespace $ns => '$name' " .
// "is already declared as '$namespaces[$ns]'");
// } else {
// $key = array_search($name, $namespaces);
// if ($key !== false) {
// wfLogWarning("JsonConfig: Invalid \$wgJsonConfigs: Namespace $ns => '$name' " .
// "has identical name with the namespace #$key");
// } else {
// $namespaces[$ns] = $name;
// }
// }
// }
// }
//
// /**
// * Initialize state
// * @param Title $title
// * @param String &$modelId
// * @return boolean
// */
// public static function onContentHandlerDefaultModelFor($title, &$modelId) {
// if (!self::jsonConfigIsStorage()) {
// return true;
// }
//
// $jct = self::parseTitle($title);
// if ($jct) {
// $modelId = $jct->getConfig()->model;
// return false;
// }
// return true;
// }
//
// /**
// * Instantiate JCContentHandler if we can handle this modelId
// * @param String $modelId
// * @param \ContentHandler &$handler
// * @return boolean
// */
// public static function onContentHandlerForModelID($modelId, &$handler) {
// global $wgJsonConfigModels;
// if (!self::jsonConfigIsStorage()) {
// return true;
// }
//
// self::init();
// $models = array_replace_recursive(
// \ExtensionRegistry::getInstance()->getAttribute('JsonConfigModels'),
// $wgJsonConfigModels
// );
// if (array_key_exists($modelId, $models)) {
// // This is one of our model IDs
// $handler = new JCContentHandler($modelId);
// return false;
// }
// return true;
// }
//
// /**
// * CustomEditor hook handler
// * @see https://www.mediawiki.org/wiki/Manual:Hooks/CustomEditor
// *
// * @param Article $article
// * @param User $user
// * @return boolean
// */
// public static function onCustomEditor($article, $user) {
// if (!$article || !self::jsonConfigIsStorage()) {
// return true;
// }
// $jct = self::parseTitle($article->getTitle());
// if (!$jct) {
// return true;
// }
//
// $editor = new \EditPage($article);
// $editor->contentFormat = JCContentHandler::CONTENT_FORMAT_JSON_PRETTY;
// $editor->edit();
//
// return false;
// }
//
// /**
// * Declares JSON as the code editor language for Config: pages.
// * This hook only runs if the CodeEditor extension is enabled.
// * @param Title $title
// * @param String &$lang Page language.
// * @return boolean
// */
// public static function onCodeEditorGetPageLanguage($title, &$lang) {
// if (!self::jsonConfigIsStorage()) {
// return true;
// }
//
// // todo/fixme? We should probably add 'json' lang to only those pages that pass parseTitle()
// $handler = ContentHandler::getForModelID($title->getContentModel());
// if ($handler->getDefaultFormat() == CONTENT_FORMAT_JSON || self::parseTitle($title)) {
// $lang = 'json';
// }
// return true;
// }
//
// /**
// * Validates that the revised contents are valid JSON.
// * If not valid, rejects edit with error message.
// * @param \IContextSource $context
// * @param JCContent $content
// * @param \Status $status
// * @param String $summary Edit summary provided for edit.
// * @param \User $user
// * @param boolean $minoredit
// * @return boolean
// */
// public static function onEditFilterMergedContent(
// /** @noinspection PhpUnusedParameterInspection */
// $context, $content, $status, $summary, $user, $minoredit
// ) {
// if (!self::jsonConfigIsStorage()) {
// return true;
// }
//
// if (is_a($content, 'JsonConfig\JCContent')) {
// $status->merge($content->getStatus());
// if (!$status->isGood()) {
// $status->setResult(false, $status->getValue());
// }
// }
// return true;
// }
//
// /**
// * Override a per-page specific edit page copyright warning
// *
// * @param Title $title
// * @param String[] &$msg
// *
// * @return boolean
// */
// public static function onEditPageCopyrightWarning($title, &$msg) {
// if (self::jsonConfigIsStorage()) {
// $jct = self::parseTitle($title);
// if ($jct) {
// $code = $jct->getConfig()->license;
// if ($code) {
// $msg = [ 'jsonconfig-license-copyrightwarning-' . $code ];
// return false; // Do not allow any other hook handler to override this
// }
// }
// }
// return true;
// }
//
// /**
// * Display a page-specific edit notice
// *
// * @param Title $title
// * @param int $oldid
// * @param array &$notices
// * @return boolean
// */
// public static function onTitleGetEditNotices(Title $title, $oldid, array &$notices) {
// if (self::jsonConfigIsStorage()) {
// $jct = self::parseTitle($title);
// if ($jct) {
// $code = $jct->getConfig()->license;
// if ($code) {
// $noticeText = wfMessage('jsonconfig-license-notice-' . $code)->parse();
// $notices['jsonconfig'] =
// wfMessage('jsonconfig-license-notice-box-' . $code)
// ->rawParams($noticeText)
// ->parseAsBlock();
// }
// }
// }
// return true;
// }
//
// /**
// * Override with per-page specific copyright message
// *
// * @param Title $title
// * @param String $type
// * @param String &$msg
// * @param String &$link
// *
// * @return boolean
// */
// public static function onSkinCopyrightFooter($title, $type, &$msg, &$link) {
// if (self::jsonConfigIsStorage()) {
// $jct = self::parseTitle($title);
// if ($jct) {
// $code = $jct->getConfig()->license;
// if ($code) {
// $msg = 'jsonconfig-license';
// $link = Html::element('a', [
// 'href' => wfMessage('jsonconfig-license-url-' . $code)->plain()
// ], wfMessage('jsonconfig-license-name-' . $code)->plain());
// return false;
// }
// }
// }
// return true;
// }
//
// /**
// * Adds CSS for pretty-printing configuration on NS_CONFIG pages.
// * @param \OutputPage &$out
// * @param \Skin &$skin
// * @return boolean
// */
// public static function onBeforePageDisplay(
// /** @noinspection PhpUnusedParameterInspection */ &$out, &$skin
// ) {
// if (!self::jsonConfigIsStorage()) {
// return true;
// }
//
// $title = $out->getTitle();
// // todo/fixme? We should probably add ext.jsonConfig style to only those pages
// // that pass parseTitle()
// $handler = ContentHandler::getForModelID($title->getContentModel());
// if ($handler->getDefaultFormat() == CONTENT_FORMAT_JSON ||
// self::parseTitle($title)
// ) {
// $out->addModuleStyles('ext.jsonConfig');
// }
// return true;
// }
//
// public static function onMovePageIsValidMove(
// Title $oldTitle, Title $newTitle, Status $status
// ) {
// if (!self::jsonConfigIsStorage()) {
// return true;
// }
//
// $jctOld = self::parseTitle($oldTitle);
// if ($jctOld) {
// $jctNew = self::parseTitle($newTitle);
// if (!$jctNew) {
// $status->fatal('jsonconfig-move-aborted-ns');
// return false;
// } elseif ($jctOld->getConfig()->model !== $jctNew->getConfig()->model) {
// $status->fatal('jsonconfig-move-aborted-model', $jctOld->getConfig()->model,
// $jctNew->getConfig()->model);
// return false;
// }
// }
//
// return true;
// }
//
// public static function onAbortMove(
// /** @noinspection PhpUnusedParameterInspection */
// Title $title, Title $newTitle, $wgUser, &$err, $reason
// ) {
// if (!self::jsonConfigIsStorage()) {
// return true;
// }
//
// $status = new \Status();
// self::onMovePageIsValidMove($title, $newTitle, $status);
// if (!$status->isOK()) {
// $err = $status->getHTML();
// return false;
// }
//
// return true;
// }
//
// /**
// * Conditionally load API module 'jsondata' depending on whether or not
// * this wiki stores any jsonconfig data
// *
// * @param ApiModuleManager $moduleManager Module manager instance
// * @return boolean
// */
// public static function onApiMainModuleManager(ApiModuleManager $moduleManager) {
// global $wgJsonConfigEnableLuaSupport;
// if ($wgJsonConfigEnableLuaSupport) {
// $moduleManager->addModule('jsondata', 'action', 'JsonConfig\\JCDataApi');
// }
// return true;
// }
//
// public static function onPageContentSaveComplete(
// /** @noinspection PhpUnusedParameterInspection */
// \WikiPage $wikiPage, $user, $content, $summary, $isMinor, $isWatch,
// $section, $flags, $revision, $status, $baseRevId
// ) {
// return self::onArticleChangeComplete($wikiPage, $content);
// }
//
// public static function onArticleDeleteComplete(
// /** @noinspection PhpUnusedParameterInspection */
// $article, &$user, $reason, $id, $content, $logEntry
// ) {
// return self::onArticleChangeComplete($article);
// }
//
// public static function onArticleUndelete(
// /** @noinspection PhpUnusedParameterInspection */
// $title, $created, $comment, $oldPageId
// ) {
// return self::onArticleChangeComplete($title);
// }
//
// public static function onTitleMoveComplete(
// /** @noinspection PhpUnusedParameterInspection */
// $title, $newTitle, $wgUser, $pageid, $redirid, $reason
// ) {
// return self::onArticleChangeComplete($title) ||
// self::onArticleChangeComplete($newTitle);
// }
//
// /**
// * Prohibit creation of the pages that are part of our namespaces but have not been explicitly
// * allowed. Bad capitalization is due to "userCan" hook name
// * @param Title &$title
// * @param User &$user
// * @param String $action
// * @param null &$result
// * @return boolean
// */
// public static function onuserCan(
// /** @noinspection PhpUnusedParameterInspection */
// &$title, &$user, $action, &$result = null
// ) {
// if (!self::jsonConfigIsStorage()) {
// return true;
// }
//
// if ($action == 'create' && self::parseTitle($title) == null) {
// // prohibit creation of the pages for the namespace that we handle,
// // if the title is not matching declared rules
// $result = false;
// return false;
// }
// return true;
// }
//
// /**
// * @param Object $value
// * @param JCContent $content
// * @return boolean
// */
// private static function onArticleChangeComplete($value, $content = null) {
// if (!self::jsonConfigIsStorage()) {
// return true;
// }
//
// if ($value && (!$content || is_a($content, 'JsonConfig\JCContent'))) {
// if (method_exists($value, 'getTitle')) {
// $value = $value->getTitle();
// }
// $jct = self::parseTitle($value);
// if ($jct && $jct->getConfig()->store) {
// $store = new JCCache($jct, $content);
// $store->resetCache();
//
// // Handle remote site notification
// $store = $jct->getConfig()->store;
// if ($store->notifyUrl) {
// $req =
// JCUtils::initApiRequestObj($store->notifyUrl, $store->notifyUsername,
// $store->notifyPassword);
// if ($req) {
// $query = [
// 'format' => 'json',
// 'action' => 'jsonconfig',
// 'command' => 'reload',
// 'title' => $jct->getNamespace() . ':' . $jct->getDBkey(),
// ];
// JCUtils::callApi($req, $query, 'notify remote JsonConfig client');
// }
// }
// }
// }
// return true;
// }
//
// /**
// * Quick check if the current wiki will store any configurations.
// * Faster than doing a full parsing of the $wgJsonConfigs in the JCSingleton::init()
// * @return boolean
// */
// private static function jsonConfigIsStorage() {
// static $isStorage = null;
// if ($isStorage == null) {
// global $wgJsonConfigs;
// $isStorage = false;
// $configs = array_replace_recursive(
// \ExtensionRegistry::getInstance()->getAttribute('JsonConfigs'),
// $wgJsonConfigs
// );
// foreach ($configs as $jc) {
// if ((!array_key_exists('isLocal', $jc) || $jc['isLocal']) ||
// (array_key_exists('store', $jc))
// ) {
// $isStorage = true;
// break;
// }
// }
// }
// return $isStorage;
// }
public static String Singleton_Id = "JCSingleton";
}

@ -0,0 +1,66 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
//namespace gplx.xowa.mediawiki.extensions.JsonConfig.includes {
// import org.junit.*;
// using gplx.langs.jsons;
// using gplx.xowa.mediawiki;
// using gplx.xowa.xtns.jsonConfigs.scribunto;
// public class JCSingleton_tst {
// private final JCSingleton_fxt fxt = new JCSingleton_fxt();
// @Test public void Get() {
// fxt.Init__store("en.wikipedia.org", "Page1"
// , Json_doc.Make_str_by_apos
// ( "{"
// , " 'data':"
// , " ["
// , " ["
// , " 'Q1'"
// , " , 'Data:Q1'"
// , " ]"
// , " ,"
// , " ["
// , " 'Q2'"
// , " , 'Data:Q2'"
// , " ]"
// , " ]"
// , "}"
// ));
// JCContent actl = fxt.Exec__getContent("en.wikipedia.org", "Page1");
// Object o = ((JCTabularContent)actl).getField("data");
// Tfds.Write(o);
// /*
// fxt.Test__get(actl, "data", "Q1")
// */
// }
// }
// class JCSingleton_fxt {
// private final JCSingleton singleton;
// private final Xomw_page_fetcher__mock store = new Xomw_page_fetcher__mock();
// public JCSingleton_fxt() {
// Jscfg_xtn_mgr xtn_mgr = new Jscfg_xtn_mgr();
// xtn_mgr.Init_xtn();
//
// singleton = (JCSingleton)XophpEnv.Instance.Singletons().Get_by(JCSingleton.Singleton_Id);
// singleton.Store_(store);
// }
// public void Init__store(String wiki, String page, String json) {
// store.Set_wtxt(Bry_.new_u8(wiki), Bry_.new_u8(page), Bry_.new_u8(json));
// }
// public JCContent Exec__getContent(String wiki, String page) {
// return singleton.getContent(wiki, "unknown_ns", page);
// }
// }
//}

@ -0,0 +1,209 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.mediawiki.extensions.JsonConfig.includes; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.extensions.*; import gplx.xowa.mediawiki.extensions.JsonConfig.*;
import gplx.core.primitives.*;
import gplx.xowa.mediawiki.*;
import gplx.xowa.langs.*;
public class JCTabularContent extends JCDataContent {// protected function createDefaultView() {
// return new JCTabularContentView();
// }
// /**
// * Returns wiki-table representation of the tabular data
// *
// * @return String|boolean The raw text, or false if the conversion failed.
// */
// public function getWikitextForTransclusion() {
// $toWiki = function ( $value ) {
// if ( is_object( $value ) ) {
// global $wgLang;
// $value = JCUtils::pickLocalizedString( $value, $wgLang );
// }
// if ( preg_match( '/^[ .\pL\pN]*$/i', $value ) ) {
// // Optimization: spaces, letters, numbers, and dots are returned without <nowiki>
// return $value;
// }
// return '<nowiki>' . htmlspecialchars( $value ) . '</nowiki>';
// };
//
// $data = $this->getData();
// $result = "{| class='wikitable sortable'\n";
//
// // Create header
// $result .= '!' . implode( "!!",
// array_map(
// function ( $field ) use ( $toWiki ) {
// return $toWiki( $field->title ? : $field->name );
// },
// $data->schema->fields
// )
// ) . "\n";
//
// // Create table content
// foreach ( $data->data as $row ) {
// $result .= "|-\n|" . implode( '||', array_map( $toWiki, $row ) ) . "\n";
// }
//
// $result .= "\n|}\n";
//
// return $result;
// }
/**
* Derived classes must implement this method to perform custom validation
* using the check(...) calls
*/
public void validateContent() {
// parent::validateContent();
//
// $validators = [ JCValidators::isList() ];
// $typeValidators = [];
// $fieldsPath = [ 'schema', 'fields' ];
// if ( $this->test( 'schema', JCValidators::isDictionary() ) &&
// $this->test( $fieldsPath, JCValidators::isList() ) &&
// $this->testEach( $fieldsPath, JCValidators::isDictionary() )
// ) {
// $hasError = false;
// $allHeaders = [];
// $fieldCount = count( $this->getField( $fieldsPath )->getValue() );
// for ( $idx = 0; $idx < $fieldCount; $idx++ ) {
// $header = false;
// $hasError |= !$this->test( [ 'schema', 'fields', $idx, 'name' ],
// JCValidators::isHeaderString( $allHeaders ),
// function ( JCValue $jcv ) use ( &$header ) {
// $header = $jcv->getValue();
// return true;
// } );
// $hasError |= !$this->test( [ 'schema', 'fields', $idx, 'type' ],
// JCValidators::validateDataType( $typeValidators ) );
// if ( $header ) {
// $hasError |= !$this->testOptional( [ 'schema', 'fields', $idx, 'title' ],
// function () use ( $header ) {
// return (Object)[ 'en' => $header ];
// }, JCValidators::isLocalizedString() );
// }
// }
// $countValidator = JCValidators::checkListSize( $fieldCount, 'schema/fields' );
// $validators[] = $countValidator;
//
// if ( !$hasError ) {
// $this->testEach( $fieldsPath, JCValidators::noExtraValues() );
// }
// }
// $this->test( 'schema', JCValidators::noExtraValues() );
//
// if ( !$this->thorough() ) {
// // We are not doing any modifications to the data, so no need to validate it
// return;
// }
//
// $this->test( 'data', JCValidators::isList() );
// $this->test( [], JCValidators::noExtraValues() );
// $this->testEach( 'data', $validators );
// if ( $typeValidators ) {
// /** @noinspection PhpUnusedParameterInspection */
// $this->testEach( 'data', function ( JCValue $v, array $path ) use ( $typeValidators ) {
// $isOk = true;
// $lastIdx = count( $path );
// foreach ( array_keys( $typeValidators ) as $k ) {
// $path[$lastIdx] = $k;
// $isOk &= $this->test( $path, $typeValidators[$k] );
// }
// return $isOk;
// } );
// }
}
/**
* Resolve @Override any specific localizations, and add it to $result
* @param Object $result
* @param Language $lang
*/
@Override protected void localizeData(XophpStdClass result, Xol_lang_itm lang) {
super.localizeData(result, lang);
XophpStdClass data = this.getData();
JCLocalizeItmFunc localize = new JCLocalizeItmFunc(lang);
Int_list isLocalized = new Int_list();
result.Set_by_as_itm("schema", new XophpStdClass());
XophpStdClass result_schema_flds = new XophpStdClass();
result.Set_by_as_itm(String_.Ary("schema", "fields"), result_schema_flds);
XophpStdClass flds = data.Get_by_ary_as_itm("schema", "fields");
int flds_len = flds.Len();
for (int ind = 0; ind < flds_len; ind++) {
XophpStdClass fld = flds.Get_at_as_itm(ind);
if (fld.Comp_str("type", "localized")) {
isLocalized.Add(ind);
}
XophpStdClass rslt_fld = new XophpStdClass();
rslt_fld.Set_by_as_str("name", fld.Get_by_as_str("name"));
rslt_fld.Set_by_as_str("type", fld.Get_by_as_str("type"));
rslt_fld.Set_by_as_str("title", fld.Has("title") ? localize.Localize(fld.Get_by_as_itm("title")) : fld.Get_by_as_str("name"));
result_schema_flds.Add_at_as_itm(rslt_fld);
}
if (isLocalized.Len() == 0) {
// There are no localized strings in the data, optimize
result.Set_by_as_itm("data", data.Get_by_as_itm("data"));
}
else {
JCArrayFunc array_map_func = new JCArrayFunc();
result.Set_by_as_itm("data", array_map_func.Array_map(new JCLocalizeAryFunc(localize, isLocalized), data.Get_by_as_itm("data")));
}
}
public static final String Model_id = "JCTabularContent";
}
class JCArrayFunc {
public XophpStdClass Array_map(JCLocalizeAryFunc func, XophpStdClass src) {
XophpStdClass trg = new XophpStdClass();
int len = src.Len();
for (int i = 0; i < len; i++) {
XophpStdClass src_sub = src.Get_at_as_itm(i);
XophpStdClass trg_sub = func.Array_map(src_sub);
trg.Add_at_as_itm(trg_sub);
}
return trg;
}
}
class JCLocalizeAryFunc {
private final JCLocalizeItmFunc localize;
private final Int_list isLocalized;
public JCLocalizeAryFunc(JCLocalizeItmFunc localize, Int_list isLocalized) {
this.localize = localize;
this.isLocalized = isLocalized;
}
public XophpStdClass Array_map(XophpStdClass row) {
int len = isLocalized.Len();
for (int ind = 0; ind < len; ind++) {
XophpStdClass val = row.Get_at_as_itm(ind);
if (val != null) {
row.Set_at_as_str(ind, localize.Localize(val)); // NOTE: will reduce a map to a String; EX: name={en='a',fr='b'} => name={'a'}
}
}
return row;
}
}
class JCLocalizeItmFunc {
private final Xol_lang_itm lang;
public JCLocalizeItmFunc(Xol_lang_itm lang) {
this.lang = lang;
}
public String Localize(XophpStdClass val) {
return JCUtils.pickLocalizedString(val, lang);
}
}

@ -0,0 +1,28 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.mediawiki.extensions.JsonConfig.includes; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.extensions.*; import gplx.xowa.mediawiki.extensions.JsonConfig.*;
import gplx.xowa.mediawiki.*;
public class JCTabularContentFactory implements XophpClassBldr {
public String Id() {return JCTabularContent.Model_id;}
public Object Make(Object... args) {
JCTabularContent rv = new JCTabularContent();
byte[] text = (byte[])args[0];
String modelId = (String)args[1];
boolean thorough = Bool_.Cast(args[2]);
rv.__construct(text, modelId, thorough);
return rv;
}
}

@ -0,0 +1,56 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.mediawiki.extensions.JsonConfig.includes; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.extensions.*; import gplx.xowa.mediawiki.extensions.JsonConfig.*;
import gplx.xowa.langs.*;
import gplx.xowa.mediawiki.*;
class JCUtils {
/**
* Find a message in a dictionary for the given language,
* or use language fallbacks if message is not defined.
* @param stdClass map Dictionary of languageCode => String
* @param Language|StubUserLang lang language Object
* @param boolean|String $defaultValue if non-false, use this value in case no fallback and no 'en'
* @return String message from the dictionary or "" if nothing found
*/
public static String pickLocalizedString(XophpStdClass map, Xol_lang_itm lang) {return pickLocalizedString(map, lang, null);}
public static String pickLocalizedString(XophpStdClass map, Xol_lang_itm lang, String defaultValue) {
String langCode = lang.Key_str();
if (map.Has(langCode)) {
return map.Get_by_as_str(langCode);
}
/*
for+each (lang.getFallbackLanguages() as l) {
if (property_exists(map, l)) {
return map.l;
}
}
*/
// If fallbacks fail, check if english is defined
if (map.Has("en") ) {
return map.Get_by_as_str("en");
}
// We have a custom default, return that
if (defaultValue != null) {
return null;
}
// Return first available value, or an empty String
// There might be a better way to get the first value from an Object
return map.Len() == 0 ? "" : map.Get_at_as_str(0);
}
}

@ -0,0 +1,252 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.mediawiki.extensions.JsonConfig.includes; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.extensions.*; import gplx.xowa.mediawiki.extensions.JsonConfig.*;
import gplx.xowa.xtns.scribunto.*;
import gplx.xowa.mediawiki.*;
public class JCValue {
private Ordered_hash value = Ordered_hash_.New();
private int statusVal;
private XophpStdClass value_as_obj;
private Xophp_ary value_as_ary;
private Object value_as_prim;
private int value_tid;
private boolean sameAsDefaultVal = false;
private boolean defaultUsedVal = false;
private Object errorVal = null;
private static final int NULL = -1;
/** Value has not been checked */
public static final int UNCHECKED = 0;
/** Value was explicitly checked (might be an error) */
// private static final int CHECKED = 1;
/** field is missing in the data, but is being explicitly tested for.
* This value should never be stored in JCObjContent::validationData.
* Setting this value for any field in validator will delete it. */
private static final int MISSING = 2;
/** field was not explicitly tested, but it was listed as a parent of one of the tested fields */
// private static final int VISITED = 3;
private static final int Value_tid__obj = 1, Value_tid__ary = 2, Value_tid__prim = 3;
/** @param int status
* @param mixed value
*/
public JCValue(int status, XophpStdClass value_as_obj, Xophp_ary value_as_ary, Object value_as_prim) {
this.statusVal = status;
this.value_as_obj = value_as_obj;
this.value_as_ary = value_as_ary;
this.value_as_prim = value_as_prim;
if (value_as_obj != null) {
value_tid = Value_tid__obj;
}
else if (value_as_ary != null) {
value_tid = Value_tid__ary;
}
else {
value_tid = Value_tid__prim;
}
}
/** @return mixed */
public Object getValue() {
switch (value_tid) {
case Value_tid__obj:
return value_as_obj;
case Value_tid__ary:
return value_as_ary;
case Value_tid__prim:
return value_as_prim;
default:
throw Err_.new_unhandled_default(value_tid);
}
}
public void setValue(Ordered_hash value) {this.setValue(value, NULL);}
public void setValue(Ordered_hash value, int status) {
this.value = value;
if (status != NULL) {
this.status(status);
} else if (this.isMissing()) {
// Convenience - if we are setting a new value, assume we are setting a default
this.status(JCValue.UNCHECKED);
this.defaultUsed(true);
}
}
public int status() {return status(NULL);}
public int status(int o) {
int val = this.statusVal;
if (o != NULL) {
this.statusVal = o;
}
return val;
}
public boolean sameAsDefault() {return sameAsDefault(null);}
public boolean sameAsDefault(Object o) {
boolean val = this.sameAsDefaultVal;
if (o != null) {
this.sameAsDefaultVal = Bool_.Cast(o);
}
return val;
}
public boolean defaultUsed() {return defaultUsed(null);}
public boolean defaultUsed(Object o) {
boolean val = this.defaultUsedVal;
if (o != null) {
this.defaultUsedVal = Bool_.Cast(o);
}
return val;
}
public boolean isMissing() {
return this.statusVal == JCValue.MISSING;
}
public boolean isUnchecked() {
return this.statusVal == JCValue.UNCHECKED;
}
/** Helper function - same arguments as wfMessage, or true if message was already added.
* false clears this message status, and null returns current state without changing it
* @param null|boolean|String $key message id, or if boolean, sets/removes error status
* @param array $fieldPath path to the erroneous field. Will be converted to a a/b/c[0]/d style
* @return boolean|Message
*/
// public String error($key = null, $fieldPath = null /*...*/)
public Object error(Object key, String... fieldPath) {
if (Type_.Type_by_obj(key) == Bool_.Cls_ref_type) {
this.errorVal = Bool_.Cast(key);
}
else if (key != null) {
// $args = func_get_args();
// if (is_array($fieldPath)) {
// // Convert field path to a printable String
// $args[1] = JCUtils::fieldPathToString($fieldPath);
// }
// $this.errorVal = call_user_func_array('wfMessage', $args);
}
return this.errorVal;
}
/**
* @param String|int $fld
* @param mixed value
* @throws Exception
*/
public void setField(Object fld, Object o) {
int fld_type = To_type_id(fld);
if (value_tid == Value_tid__obj && fld_type == Type_ids_.Id__str) {
value_as_obj.Add_by_as_obj((String)fld, o);
}
else if (value_tid == Value_tid__ary && (fld_type == Type_ids_.Id__str || fld_type == Type_ids_.Id__int)) {
if (fld_type == Type_ids_.Id__str)
value_as_ary.Add((String)fld, o);
else
value_as_ary.Add(Int_.Cast(fld), o);
}
else {
throw Err_.new_wo_type("Type mismatch for field " + fld);
}
}
/**
* @param String|int $fld
* @throws \Exception
* @return mixed
*/
public Object deleteField(Object fld) {
int fld_type = To_type_id(fld);
Object tmp = null;
if (value_tid == Value_tid__obj && fld_type == Type_ids_.Id__str) {
String key = (String)fld;
tmp = value_as_obj.Get_by_as_obj(key);
value_as_obj.Del_by(key);
}
else if (value_tid == Value_tid__ary && (fld_type == Type_ids_.Id__str || fld_type == Type_ids_.Id__int)) {
tmp = value_as_ary.Get(fld);
if (fld_type == Type_ids_.Id__str)
value_as_ary.Unset((String)fld);
else
value_as_ary.Unset(Int_.Cast(fld));
value.Del(fld);
}
else {
throw Err_.new_wo_type("Type mismatch for field " + fld);
}
return tmp;
}
/**
* @param String|int $fld
* @throws \Exception
* @return boolean
*/
public boolean fieldExists(Object fld) {
int fld_type = To_type_id(fld);
if (value_tid == Value_tid__obj && fld_type == Type_ids_.Id__str) {
return value_as_obj.Has((String)fld);
}
else if (value_tid == Value_tid__ary && (fld_type == Type_ids_.Id__str || fld_type == Type_ids_.Id__int)) {
return value_as_ary.Has(fld);
}
throw Err_.new_wo_type("Type mismatch for field " + fld);
}
/**
* @param String|int $fld
* @throws \Exception
* @return mixed
*/
public Object getField(Object fld) {
int fld_type = To_type_id(fld);
if (value_tid == Value_tid__obj && fld_type == Type_ids_.Id__str) {
return value_as_obj.Get_by_as_obj((String)fld);
}
else if (value_tid == Value_tid__ary && (fld_type == Type_ids_.Id__str || fld_type == Type_ids_.Id__int)) {
return value_as_ary.Get(fld);
}
throw Err_.new_wo_type("Type mismatch for field " + fld);
}
public static int To_type_id(Object o) {
Class<?> type = Type_.Type_by_obj(o);
if (Type_.Eq(type, String.class))
return Type_ids_.Id__str;
else if (Type_.Eq(type, int.class))
return Type_ids_.Id__int;
else
return Type_ids_.Id__null;
}
}
class XomwTypeUtl {
public static int To_type_id(Object o) {
if (o == null)
return Type_ids_.Id__null;
Class<?> type = Type_.Type_by_obj(o);
if (Type_.Eq(type, String.class))
return Type_ids_.Id__str;
else if (Type_.Eq(type, int.class))
return Type_ids_.Id__int;
else if (Type_.Is_array(type))
return Type_ids_.Id__array;
else
return Type_ids_.Id__obj;
}
}

@ -0,0 +1,21 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.mediawiki.extensions.JsonConfig.includes; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.extensions.*; import gplx.xowa.mediawiki.extensions.JsonConfig.*;
public class XomwStatus {
public boolean isGood() {
return false;
}
}

@ -0,0 +1,31 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.mediawiki.extensions.JsonConfig.includes; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.extensions.*; import gplx.xowa.mediawiki.extensions.JsonConfig.*;
public interface Xomw_page_fetcher {
byte[] Get_wtxt(byte[] wiki, byte[] page);
}
class Xomw_page_fetcher__mock implements Xomw_page_fetcher {
private final Ordered_hash hash = Ordered_hash_.New_bry();
public void Set_wtxt(byte[] wiki, byte[] page, byte[] wtxt) {
hash.Add(Make_key(wiki, page), wtxt);
}
public byte[] Get_wtxt(byte[] wiki, byte[] page) {
return (byte[])hash.Get_by(Make_key(wiki, page));
}
private static byte[] Make_key(byte[] wiki, byte[] page) {
return Bry_.Add(wiki, Byte_ascii.Pipe_bry, page);
}
}

@ -261,20 +261,20 @@ public class XomwDefines {
// define( 'PROTO_INTERNAL', 2 );
// /**@}*/
//
// /**@{
// * Content model ids, used by Content and ContentHandler.
// * These IDs will be exposed in the API and XML dumps.
// *
// * Extensions that define their own content model IDs should take
// * care to avoid conflicts. Using the extension name as a prefix is recommended,
// * for example 'myextension-somecontent'.
// */
// define( 'CONTENT_MODEL_WIKITEXT', 'wikitext' );
// define( 'CONTENT_MODEL_JAVASCRIPT', 'javascript' );
// define( 'CONTENT_MODEL_CSS', 'css' );
// define( 'CONTENT_MODEL_TEXT', 'text' );
// define( 'CONTENT_MODEL_JSON', 'json' );
// /**@}*/
/**@{
* Content model ids, used by Content and ContentHandler.
* These IDs will be exposed in the API and XML dumps.
*
* Extensions that define their own content model IDs should take
* care to avoid conflicts. Using the extension name as a prefix is recommended,
* for example 'myextension-somecontent'.
*/
public static final String CONTENT_MODEL_WIKITEXT = "wikitext";
public static final String CONTENT_MODEL_JAVASCRIPT = "javascript";
public static final String CONTENT_MODEL_CSS = "css";
public static final String CONTENT_MODEL_TEXT = "text";
public static final String CONTENT_MODEL_JSON = "json";
/**@}*/
/**@{
* Content formats, used by Content and ContentHandler.

@ -0,0 +1,321 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.mediawiki.includes.content; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.includes.*;
public class TextContent {
// AbstractContent
/**
* @since 1.21
*
* @return boolean
*
* @see Content::isRedirect
*/
// public function isRedirect() {
// return $this->getRedirectTarget() !== null;
// }
public boolean isRedirect() {
return false;
}
private byte[] mText;
/**
* @param String $text
* @param String $model_id
* @throws MWException
*/
public void __construct(byte[] text, String model_id) { // = CONTENT_MODEL_TEXT
// parent::__construct( $model_id );
//
// if ( $text === null || $text === false ) {
// wfWarn( "TextContent constructed with \$text = " . var_export( $text, true ) . "! "
// . "This may indicate an error in the caller's scope.", 2 );
//
// $text = '';
// }
//
// if ( !is_string( $text ) ) {
// throw new MWException( "TextContent expects a String in the constructor." );
// }
//
this.mText = text;
}
//
// /**
// * @note Mutable subclasses MUST override this to return a copy!
// *
// * @return Content this
// */
// public function copy() {
// return this; # NOTE: this is ok since TextContent are immutable.
// }
//
// public function getTextForSummary( $maxlength = 250 ) {
// global $wgContLang;
//
// $text = this.getNativeData();
//
// $truncatedtext = $wgContLang.truncate(
// preg_replace( "/[\n\r]/", ' ', $text ),
// max( 0, $maxlength ) );
//
// return $truncatedtext;
// }
//
// /**
// * Returns the text's size in bytes.
// *
// * @return int
// */
// public function getSize() {
// $text = this.getNativeData();
//
// return strlen( $text );
// }
//
// /**
// * Returns true if this content is not a redirect, and $wgArticleCountMethod
// * is "any".
// *
// * @param boolean|null $hasLinks If it is known whether this content contains links,
// * provide this information here, to avoid redundant parsing to find out.
// *
// * @return boolean
// */
// public function isCountable( $hasLinks = null ) {
// global $wgArticleCountMethod;
//
// if ( this.isRedirect() ) {
// return false;
// }
//
// if ( $wgArticleCountMethod === 'any' ) {
// return true;
// }
//
// return false;
// }
/**
* Returns the text represented by this Content Object, as a String.
*
* @return String The raw text.
*/
public byte[] getNativeData() {
return this.mText;
}
// /**
// * Returns the text represented by this Content Object, as a String.
// *
// * @return String The raw text.
// */
// public function getTextForSearchIndex() {
// return this.getNativeData();
// }
//
// /**
// * Returns attempts to convert this content Object to wikitext,
// * and then returns the text String. The conversion may be lossy.
// *
// * @note this allows any text-based content to be transcluded as if it was wikitext.
// *
// * @return String|boolean The raw text, or false if the conversion failed.
// */
// public function getWikitextForTransclusion() {
// $wikitext = this.convert( CONTENT_MODEL_WIKITEXT, 'lossy' );
//
// if ( $wikitext ) {
// return $wikitext.getNativeData();
// } else {
// return false;
// }
// }
//
// /**
// * Do a "\r\n" . "\n" and "\r" . "\n" transformation
// * as well as trim trailing whitespace
// *
// * This was formerly part of Parser::preSaveTransform, but
// * for non-wikitext content models they probably still want
// * to normalize line endings without all of the other PST
// * changes.
// *
// * @since 1.28
// * @param $text
// * @return String
// */
// public static function normalizeLineEndings( $text ) {
// return str_replace( [ "\r\n", "\r" ], "\n", rtrim( $text ) );
// }
//
// /**
// * Returns a Content Object with pre-save transformations applied.
// *
// * At a minimum, subclasses should make sure to call TextContent::normalizeLineEndings()
// * either directly or part of Parser::preSaveTransform().
// *
// * @param Title $title
// * @param User $user
// * @param ParserOptions $popts
// *
// * @return Content
// */
// public function preSaveTransform( Title $title, User $user, ParserOptions $popts ) {
// $text = this.getNativeData();
// $pst = self::normalizeLineEndings( $text );
//
// return ( $text === $pst ) ? this : new static( $pst, this.getModel() );
// }
//
// /**
// * Diff this content Object with another content Object.
// *
// * @since 1.21
// *
// * @param Content $that The other content Object to compare this content Object to.
// * @param Language $lang The language Object to use for text segmentation.
// * If not given, $wgContentLang is used.
// *
// * @return Diff A diff representing the changes that would have to be
// * made to this content Object to make it equal to $that.
// */
// public function diff( Content $that, Language $lang = null ) {
// global $wgContLang;
//
// this.checkModelID( $that.getModel() );
//
// // @todo could implement this in DifferenceEngine and just delegate here?
//
// if ( !$lang ) {
// $lang = $wgContLang;
// }
//
// $otext = this.getNativeData();
// $ntext = $that.getNativeData();
//
// # Note: Use native PHP diff, external engines don't give us abstract output
// $ota = explode( "\n", $lang.segmentForDiff( $otext ) );
// $nta = explode( "\n", $lang.segmentForDiff( $ntext ) );
//
// $diff = new Diff( $ota, $nta );
//
// return $diff;
// }
//
// /**
// * Fills the provided ParserOutput Object with information derived from the content.
// * Unless $generateHtml was false, this includes an HTML representation of the content
// * provided by getHtml().
// *
// * For content models listed in $wgTextModelsToParse, this method will call the MediaWiki
// * wikitext parser on the text to extract any (wikitext) links, magic words, etc.
// *
// * Subclasses may override this to provide custom content processing.
// * For custom HTML generation alone, it is sufficient to override getHtml().
// *
// * @param Title $title Context title for parsing
// * @param int $revId Revision ID (for {{REVISIONID}})
// * @param ParserOptions $options Parser options
// * @param boolean $generateHtml Whether or not to generate HTML
// * @param ParserOutput $output The output Object to fill (reference).
// */
// protected function fillParserOutput( Title $title, $revId,
// ParserOptions $options, $generateHtml, ParserOutput &$output
// ) {
// global $wgParser, $wgTextModelsToParse;
//
// if ( in_array( this.getModel(), $wgTextModelsToParse ) ) {
// // parse just to get links etc into the database, HTML is replaced below.
// $output = $wgParser.parse( this.getNativeData(), $title, $options, true, true, $revId );
// }
//
// if ( $generateHtml ) {
// $html = this.getHtml();
// } else {
// $html = '';
// }
//
// $output.setText( $html );
// }
//
// /**
// * Generates an HTML version of the content, for display. Used by
// * fillParserOutput() to provide HTML for the ParserOutput Object.
// *
// * Subclasses may override this to provide a custom HTML rendering.
// * If further information is to be derived from the content (such as
// * categories), the fillParserOutput() method can be overridden instead.
// *
// * For backwards-compatibility, this default implementation just calls
// * getHighlightHtml().
// *
// * @return String An HTML representation of the content
// */
// protected function getHtml() {
// return this.getHighlightHtml();
// }
//
// /**
// * Generates an HTML version of the content, for display.
// *
// * This default implementation returns an HTML-escaped version
// * of the raw text content.
// *
// * @note The functionality of this method should really be implemented
// * in getHtml(), and subclasses should override getHtml() if needed.
// * getHighlightHtml() is kept around for backward compatibility with
// * extensions that already override it.
// *
// * @deprecated since 1.24. Use getHtml() instead. In particular, subclasses overriding
// * getHighlightHtml() should override getHtml() instead.
// *
// * @return String An HTML representation of the content
// */
// protected function getHighlightHtml() {
// return htmlspecialchars( this.getNativeData() );
// }
//
// /**
// * This implementation provides lossless conversion between content models based
// * on TextContent.
// *
// * @param String $toModel The desired content model, use the CONTENT_MODEL_XXX flags.
// * @param String $lossy Flag, set to "lossy" to allow lossy conversion. If lossy conversion is not
// * allowed, full round-trip conversion is expected to work without losing information.
// *
// * @return Content|boolean A content Object with the content model $toModel, or false if that
// * conversion is not supported.
// *
// * @see Content::convert()
// */
// public function convert( $toModel, $lossy = '' ) {
// $converted = parent::convert( $toModel, $lossy );
//
// if ( $converted !== false ) {
// return $converted;
// }
//
// $toHandler = ContentHandler::getForModelID( $toModel );
//
// if ( $toHandler instanceof TextContentHandler ) {
// // NOTE: ignore content serialization format - it's just text anyway.
// $text = this.getNativeData();
// $converted = $toHandler.unserializeContent( $text );
// }
//
// return $converted;
// }
}

@ -0,0 +1,145 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.mediawiki.includes.content; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.includes.*;
public class TextContentHandler extends ContentHandler { // @codingStandardsIgnoreStart bug 57585
public void __construct() {this.__construct(XomwDefines.CONTENT_MODEL_TEXT, XomwDefines.CONTENT_FORMAT_TEXT);}
@Override public void __construct(String modelId, String... formats) {
super.__construct(modelId, formats);
}
// @codingStandardsIgnoreEnd
//
// /**
// * Returns the content's text as-is.
// *
// * @param Content $content
// * @param String $format The serialization format to check
// *
// * @return mixed
// */
// public function serializeContent(Content $content, $format = null) {
// $this->checkFormat($format);
//
// return $content->getNativeData();
// }
//
// /**
// * Attempts to merge differences between three versions. Returns a new
// * Content Object for a clean merge and false for failure or a conflict.
// *
// * All three Content objects passed as parameters must have the same
// * content model.
// *
// * This text-based implementation uses wfMerge().
// *
// * @param Content $oldContent The page's previous content.
// * @param Content $myContent One of the page's conflicting contents.
// * @param Content $yourContent One of the page's conflicting contents.
// *
// * @return Content|boolean
// */
// public function merge3(Content $oldContent, Content $myContent, Content $yourContent) {
// $this->checkModelID($oldContent->getModel());
// $this->checkModelID($myContent->getModel());
// $this->checkModelID($yourContent->getModel());
//
// $format = $this->getDefaultFormat();
//
// $old = $this->serializeContent($oldContent, $format);
// $mine = $this->serializeContent($myContent, $format);
// $yours = $this->serializeContent($yourContent, $format);
//
// $ok = wfMerge($old, $mine, $yours, $result);
//
// if (!$ok) {
// return false;
// }
//
// if (!$result) {
// return $this->makeEmptyContent();
// }
//
// $mergedContent = $this->unserializeContent($result, $format);
//
// return $mergedContent;
// }
//
// /**
// * Returns the name of the associated Content class, to
// * be used when creating new objects. Override expected
// * by subclasses.
// *
// * @since 1.24
// *
// * @return String
// */
// protected function getContentClass() {
// return TextContent::class;
// }
//
// /**
// * Unserializes a Content Object of the type supported by this ContentHandler.
// *
// * @since 1.21
// *
// * @param String $text Serialized form of the content
// * @param String $format The format used for serialization
// *
// * @return Content The TextContent Object wrapping $text
// */
// public function unserializeContent($text, $format = null) {
// $this->checkFormat($format);
//
// $class = $this->getContentClass();
// return new $class($text);
// }
//
// /**
// * Creates an empty TextContent Object.
// *
// * @since 1.21
// *
// * @return Content A new TextContent Object with empty text.
// */
// public function makeEmptyContent() {
// $class = $this->getContentClass();
// return new $class('');
// }
//
// /**
// * @see ContentHandler::supportsDirectEditing
// *
// * @return boolean Default is true for TextContent and derivatives.
// */
// public function supportsDirectEditing() {
// return true;
// }
//
// public function getFieldsForSearchIndex(SearchEngine $engine) {
// $fields = parent::getFieldsForSearchIndex($engine);
// $fields['language'] =
// $engine->makeSearchFieldMapping('language', SearchIndexField::INDEX_TYPE_KEYWORD);
//
// return $fields;
// }
//
// public function getDataForSearchIndex(WikiPage $page, ParserOutput $output,
// SearchEngine $engine) {
// $fields = parent::getDataForSearchIndex($page, $output, $engine);
// $fields['language'] =
// $this->getPageLanguage($page->getTitle(), $page->getContent())->getCode();
// return $fields;
// }
}

@ -41,7 +41,7 @@ public class XomwInterwikiLookupAdapter implements XomwInterwikiLookup {
* @return boolean Whether it exists
*/
public boolean isValidInterwiki(byte[] prefix) {
return XophpArray.array_key_exists(prefix, this.getInterwikiMap());
return XophpArrayUtl.array_key_exists(prefix, this.getInterwikiMap());
}
/**
@ -71,7 +71,7 @@ public class XomwInterwikiLookupAdapter implements XomwInterwikiLookup {
*/
public byte[][] getAllPrefixes(boolean local) {
if (!local) {
XophpArray.array_keys_bry(this.getInterwikiMap());
XophpArrayUtl.array_keys_bry(this.getInterwikiMap());
}
List_adp res = List_adp_.New();
Ordered_hash hash = this.getInterwikiMap();

@ -48,13 +48,13 @@ public class Xomw_table_wkr implements gplx.core.brys.Bry_split_wkr {// THREAD.U
// Closing open td, tr && table
while (td_history.Len() > 0) {
if (XophpArray.popBoolOrN(td_history)) {
if (XophpArrayUtl.popBoolOrN(td_history)) {
bfr.Add_str_a7("</td>\n");
}
if (XophpArray.popBoolOrN(tr_history)) {
if (XophpArrayUtl.popBoolOrN(tr_history)) {
bfr.Add_str_a7("</tr>\n");
}
if (!XophpArray.popBoolOrN(has_opened_tr)) {
if (!XophpArrayUtl.popBoolOrN(has_opened_tr)) {
bfr.Add_str_a7("<tr><td></td></tr>\n");
}
bfr.Add_str_a7("</table>\n");
@ -123,20 +123,20 @@ public class Xomw_table_wkr implements gplx.core.brys.Bry_split_wkr {// THREAD.U
else if (Bry_.Eq(first_2, Wtxt__tb__end)) {
// We are ending a table
line = tmp.Add_str_a7("</table>").Add_mid(line, 2, line.length).To_bry_and_clear();
byte[] last_tag = XophpArray.popBryOrNull(last_tag_history);
byte[] last_tag = XophpArrayUtl.popBryOrNull(last_tag_history);
if (!XophpArray.popBoolOrN(has_opened_tr)) {
if (!XophpArrayUtl.popBoolOrN(has_opened_tr)) {
line = tmp.Add_str_a7("<tr><td></td></tr>").Add(line).To_bry_and_clear();
}
if (XophpArray.popBoolOrN(tr_history)) {
if (XophpArrayUtl.popBoolOrN(tr_history)) {
line = tmp.Add_str_a7("</tr>").Add(line).To_bry_and_clear();
}
if (XophpArray.popBoolOrN(td_history)) {
if (XophpArrayUtl.popBoolOrN(td_history)) {
line = tmp.Add_str_a7("</").Add(last_tag).Add_byte(Byte_ascii.Angle_end).Add(line).To_bry_and_clear();
}
XophpArray.popBryOrNull(tr_attributes);
XophpArrayUtl.popBryOrNull(tr_attributes);
// PORTED:$outLine = $line . str_repeat( '</dd></dl>', $indent_level );
tmp.Add(line);
for (int j = 0; j < indent_level; j++)
@ -152,19 +152,19 @@ public class Xomw_table_wkr implements gplx.core.brys.Bry_split_wkr {// THREAD.U
sanitizer.fixTagAttributes(tmp, Name__tr, atrs);
atrs = tmp.To_bry_and_clear();
XophpArray.popBryOrNull(tr_attributes);
XophpArrayUtl.popBryOrNull(tr_attributes);
tr_attributes.Add(atrs);
line = Bry_.Empty;
byte[] last_tag = XophpArray.popBryOrNull(last_tag_history);
XophpArray.popBoolOrN(has_opened_tr);
byte[] last_tag = XophpArrayUtl.popBryOrNull(last_tag_history);
XophpArrayUtl.popBoolOrN(has_opened_tr);
has_opened_tr.Add(true);
if (XophpArray.popBoolOrN(tr_history)) {
if (XophpArrayUtl.popBoolOrN(tr_history)) {
line = Html__tr__end;
}
if (XophpArray.popBoolOrN(td_history)) {
if (XophpArrayUtl.popBoolOrN(td_history)) {
line = tmp.Add_str_a7("</").Add(last_tag).Add_byte(Byte_ascii.Gt).Add(line).To_bry_and_clear();
}
@ -205,19 +205,19 @@ public class Xomw_table_wkr implements gplx.core.brys.Bry_split_wkr {// THREAD.U
byte[] cell = cells[j];
previous = Bry_.Empty;
if (first_char != Byte_ascii.Plus) {
byte[] tr_after = XophpArray.popBryOrNull(tr_attributes);
if (!XophpArray.popBoolOrN(tr_history)) {
byte[] tr_after = XophpArrayUtl.popBryOrNull(tr_attributes);
if (!XophpArrayUtl.popBoolOrN(tr_history)) {
previous = tmp.Add_str_a7("<tr").Add(tr_after).Add_str_a7(">\n").To_bry_and_clear();
}
tr_history.Add(true);
tr_attributes.Add(Bry_.Empty);
XophpArray.popBoolOrN(has_opened_tr);
XophpArrayUtl.popBoolOrN(has_opened_tr);
has_opened_tr.Add(true);
}
byte[] last_tag = XophpArray.popBryOrNull(last_tag_history);
byte[] last_tag = XophpArrayUtl.popBryOrNull(last_tag_history);
if (XophpArray.popBoolOrN(td_history)) {
if (XophpArrayUtl.popBoolOrN(td_history)) {
previous = tmp.Add_str_a7("</").Add(last_tag).Add_str_a7(">\n").Add(previous).To_bry_and_clear();
}

@ -103,14 +103,14 @@ public class XomwSiteList extends XomwGenericArrayObject { public int Len() {ret
*/
XomwSite site = (XomwSite)this.offsetGet(index);
XophpArray.unset(this.byGlobalId, site.getGlobalId());
XophpArray.unset(this.byInternalId, site.getInternalId());
XophpArrayUtl.unset(this.byGlobalId, site.getGlobalId());
XophpArrayUtl.unset(this.byInternalId, site.getInternalId());
Ordered_hash ids = site.getNavigationIds();
int len = ids.Len();
for (int i = 0; i < len; i++) {
int navId = Int_.Cast(ids.Get_at(i));
XophpArray.unset(this.byNavigationId, navId);
XophpArrayUtl.unset(this.byNavigationId, navId);
}
}
@ -126,7 +126,7 @@ public class XomwSiteList extends XomwGenericArrayObject { public int Len() {ret
* @return array
*/
public String[] getGlobalIdentifiers() {
return XophpArray.array_keys_str(this.byGlobalId);
return XophpArrayUtl.array_keys_str(this.byGlobalId);
}
/**
@ -137,7 +137,7 @@ public class XomwSiteList extends XomwGenericArrayObject { public int Len() {ret
* @return boolean
*/
public boolean hasSite(String globalSiteId) {
return XophpArray.array_key_exists(globalSiteId, this.byGlobalId);
return XophpArrayUtl.array_key_exists(globalSiteId, this.byGlobalId);
}
/**
@ -174,7 +174,7 @@ public class XomwSiteList extends XomwGenericArrayObject { public int Len() {ret
* @return boolean
*/
@Override public boolean isEmpty() {
return XophpArray.array_is_empty(this.byGlobalId);
return XophpArrayUtl.array_is_empty(this.byGlobalId);
}
/**
@ -185,7 +185,7 @@ public class XomwSiteList extends XomwGenericArrayObject { public int Len() {ret
* @return boolean
*/
public boolean hasInternalId(int id) {
return XophpArray.array_key_exists(id, this.byInternalId);
return XophpArrayUtl.array_key_exists(id, this.byInternalId);
}
/**
@ -222,7 +222,7 @@ public class XomwSiteList extends XomwGenericArrayObject { public int Len() {ret
* @return boolean
*/
public boolean hasNavigationId(String id) {
return XophpArray.array_key_exists(id, this.byNavigationId);
return XophpArrayUtl.array_key_exists(id, this.byNavigationId);
}
/**

@ -1 +1 @@
wikidata
v4.5.19.1801

Loading…
Cancel
Save