mirror of https://github.com/gnosygnu/xowa
parent
8967ca810a
commit
54d74b0acd
@ -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() {}
|
||||
}
|
@ -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;
|
||||
}
|
@ -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"
|
||||
;
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
// }
|
||||
}
|
@ -1 +1 @@
|
||||
wikidata
|
||||
v4.5.19.1801
|
||||
|
Loading…
Reference in new issue