Skin: Change to mustache-backed Skin.Vector [#797]

master v4.6.13.2010
gnosygnu 4 years ago
parent 5c3d6a173b
commit 19a315b8cd

File diff suppressed because it is too large Load Diff

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,295 +13,309 @@ 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;
import org.junit.*; import gplx.core.primitives.*; import gplx.core.brys.*; import gplx.core.tests.*;
public class Bry__tst {
private final Bry__fxt fxt = new Bry__fxt();
@Test public void new_ascii_() {
fxt.Test_new_a7("a" , Bry_.New_by_ints(97)); // one
fxt.Test_new_a7("abc" , Bry_.New_by_ints(97, 98, 99)); // many
fxt.Test_new_a7("" , Bry_.Empty); // none
fxt.Test_new_a7("¢€𤭢" , Bry_.New_by_ints(63, 63, 63, 63)); // non-ascii -> ?
}
@Test public void new_u8() {
fxt.Test_new_u8("a" , Bry_.New_by_ints(97)); // one
fxt.Test_new_u8("abc" , Bry_.New_by_ints(97, 98, 99)); // many
fxt.Test_new_u8("¢" , Bry_.New_by_ints(194, 162)); // bry_len=2; cent
fxt.Test_new_u8("€" , Bry_.New_by_ints(226, 130, 172)); // bry_len=3; euro
fxt.Test_new_u8("𤭢" , Bry_.New_by_ints(240, 164, 173, 162)); // bry_len=4; example from en.w:UTF-8
}
@Test public void Add__bry_plus_byte() {
fxt.Test_add("a" , Byte_ascii.Pipe , "a|"); // basic
fxt.Test_add("" , Byte_ascii.Pipe , "|"); // empty String
}
@Test public void Add__byte_plus_bry() {
fxt.Test_add(Byte_ascii.Pipe , "a" , "|a"); // basic
fxt.Test_add(Byte_ascii.Pipe , "" , "|"); // empty String
}
@Test public void Add_w_dlm() {
fxt.Test_add_w_dlm(Byte_ascii.Pipe, String_.Ary("a", "b", "c") , "a|b|c"); // basic
fxt.Test_add_w_dlm(Byte_ascii.Pipe, String_.Ary("a") , "a"); // one item
fxt.Test_add_w_dlm(Byte_ascii.Pipe, String_.Ary("a", null, "c") , "a||c"); // null
}
@Test public void Add_w_dlm_bry() {
fxt.Test_add_w_dlm("<>", String_.Ary("a","b","c"), "a<>b<>c");
}
@Test public void MidByPos() {
tst_MidByPos("abcba", 0, 1, "a");
tst_MidByPos("abcba", 0, 2, "ab");
tst_MidByPos("abcba", 1, 4, "bcb");
} void tst_MidByPos(String src, int bgn, int end, String expd) {Tfds.Eq(expd, String_.new_u8(Bry_.Mid(Bry_.new_u8(src), bgn, end)));}
@Test public void Replace_one() {
tst_ReplaceOne("a" , "b" , "c" , "a");
tst_ReplaceOne("b" , "b" , "c" , "c");
tst_ReplaceOne("bb" , "b" , "c" , "cb");
tst_ReplaceOne("abcd" , "bc" , "" , "ad");
tst_ReplaceOne("abcd" , "b" , "ee" , "aeecd");
} void tst_ReplaceOne(String src, String find, String repl, String expd) {Tfds.Eq(expd, String_.new_u8(Bry_.Replace_one(Bry_.new_u8(src), Bry_.new_u8(find), Bry_.new_u8(repl))));}
@Test public void XtoStrBytesByInt() {
tst_XtoStrBytesByInt(0, 0);
tst_XtoStrBytesByInt(9, 9);
tst_XtoStrBytesByInt(10, 1, 0);
tst_XtoStrBytesByInt(321, 3, 2, 1);
tst_XtoStrBytesByInt(-321, Bry_.Byte_NegSign, 3, 2, 1);
tst_XtoStrBytesByInt(Int_.Max_value, 2,1,4,7,4,8,3,6,4,7);
}
void tst_XtoStrBytesByInt(int val, int... expdAryAsInt) {
byte[] expd = new byte[expdAryAsInt.length];
for (int i = 0; i < expd.length; i++) {
int expdInt = expdAryAsInt[i];
expd[i] = expdInt == Bry_.Byte_NegSign ? Bry_.Byte_NegSign : Byte_ascii.To_a7_str(expdAryAsInt[i]);
}
Tfds.Eq_ary(expd, Bry_.To_a7_bry(val, Int_.DigitCount(val)));
}
@Test public void Has_at_end() {
tst_HasAtEnd("a|bcd|e", "d" , 2, 5, true); // y_basic
tst_HasAtEnd("a|bcd|e", "bcd" , 2, 5, true); // y_many
tst_HasAtEnd("a|bcd|e", "|bcd" , 2, 5, false); // n_long
tst_HasAtEnd("a|bcd|e", "|bc" , 2, 5, false); // n_pos
tst_HasAtEnd("abc", "bc", true); // y
tst_HasAtEnd("abc", "bd", false); // n
tst_HasAtEnd("a", "ab", false); // exceeds_len
}
void tst_HasAtEnd(String src, String find, int bgn, int end, boolean expd) {Tfds.Eq(expd, Bry_.Has_at_end(Bry_.new_u8(src), Bry_.new_u8(find), bgn, end));}
void tst_HasAtEnd(String src, String find, boolean expd) {Tfds.Eq(expd, Bry_.Has_at_end(Bry_.new_u8(src), Bry_.new_u8(find)));}
@Test public void Has_at_bgn() {
tst_HasAtBgn("y_basic" , "a|bcd|e", "b" , 2, 5, true);
tst_HasAtBgn("y_many" , "a|bcd|e", "bcd" , 2, 5, true);
tst_HasAtBgn("n_long" , "a|bcd|e", "bcde" , 2, 5, false);
tst_HasAtBgn("n_pos" , "a|bcd|e", "|bc" , 2, 5, false);
} void tst_HasAtBgn(String tst, String src, String find, int bgn, int end, boolean expd) {Tfds.Eq(expd, Bry_.Has_at_bgn(Bry_.new_u8(src), Bry_.new_u8(find), bgn, end), tst);}
@Test public void Match() {
tst_Match("abc", 0, "abc", true);
tst_Match("abc", 2, "c", true);
tst_Match("abc", 0, "cde", false);
tst_Match("abc", 2, "abc", false); // bounds check
tst_Match("abc", 0, "abcd", false);
tst_Match("a" , 0, "", false);
tst_Match("" , 0, "a", false);
tst_Match("" , 0, "", true);
tst_Match("ab", 0, "a", false); // FIX: "ab" should not match "a" b/c .length is different
} void tst_Match(String src, int srcPos, String find, boolean expd) {Tfds.Eq(expd, Bry_.Match(Bry_.new_u8(src), srcPos, Bry_.new_u8(find)));}
@Test public void ReadCsvStr() {
tst_ReadCsvStr("a|" , "a");
tst_ReadCsvStr("|a|", 1 , "a");
Int_obj_ref bgn = Int_obj_ref.New_zero(); tst_ReadCsvStr("a|b|c|", bgn, "a"); tst_ReadCsvStr("a|b|c|", bgn, "b"); tst_ReadCsvStr("a|b|c|", bgn, "c");
tst_ReadCsvStr("|", "");
tst_ReadCsvStr_err("a");
tst_ReadCsvStr("'a'|" , "a");
tst_ReadCsvStr("'a''b'|" , "a'b");
tst_ReadCsvStr("'a|b'|" , "a|b");
tst_ReadCsvStr("''|", "");
tst_ReadCsvStr_err("''");
tst_ReadCsvStr_err("'a'b'");
tst_ReadCsvStr_err("'a");
tst_ReadCsvStr_err("'a|");
tst_ReadCsvStr_err("'a'");
}
@Test public void XtoIntBy4Bytes() { // test len=1, 2, 3, 4
tst_XtoIntBy4Bytes(32, (byte)32); // space
tst_XtoIntBy4Bytes(8707, (byte)34, (byte)3); // &exist;
tst_XtoIntBy4Bytes(6382179, Byte_ascii.Ltr_a, Byte_ascii.Ltr_b, Byte_ascii.Ltr_c);
tst_XtoIntBy4Bytes(1633837924, Byte_ascii.Ltr_a, Byte_ascii.Ltr_b, Byte_ascii.Ltr_c, Byte_ascii.Ltr_d);
}
@Test public void XtoInt() {
tst_XtoInt("1", 1);
tst_XtoInt("123", 123);
tst_XtoInt("a", Int_.Min_value, Int_.Min_value);
tst_XtoInt("-1", Int_.Min_value, -1);
tst_XtoInt("-123", Int_.Min_value, -123);
tst_XtoInt("123-1", Int_.Min_value, Int_.Min_value);
tst_XtoInt("+123", Int_.Min_value, 123);
tst_XtoInt("", -1);
}
void tst_XtoInt(String val, int expd) {tst_XtoInt(val, -1, expd);}
void tst_XtoInt(String val, int or, int expd) {Tfds.Eq(expd, Bry_.To_int_or(Bry_.new_u8(val), or));}
void tst_XtoIntBy4Bytes(int expd, byte... ary) {Tfds.Eq(expd, Bry_.To_int_by_a7(ary), "XtoInt"); Tfds.Eq_ary(ary, Bry_.new_by_int(expd), "XbyInt");}
void tst_ReadCsvStr(String raw, String expd) {tst_ReadCsvStr(raw, Int_obj_ref.New_zero() , expd);}
void tst_ReadCsvStr(String raw, int bgn, String expd) {tst_ReadCsvStr(raw, Int_obj_ref.New(bgn), expd);}
void tst_ReadCsvStr(String raw, Int_obj_ref bgnRef, String expd) {
int bgn = bgnRef.Val();
boolean rawHasQuotes = String_.CharAt(raw, bgn) == '\'';
String actl = String_.Replace(Bry_.ReadCsvStr(Bry_.new_u8(String_.Replace(raw, "'", "\"")), bgnRef, (byte)'|'), "\"", "'");
Tfds.Eq(expd, actl, "rv");
if (rawHasQuotes) {
int quoteAdj = String_.Count(actl, "'");
Tfds.Eq(bgn + 1 + String_.Len(actl) + 2 + quoteAdj, bgnRef.Val(), "pos_quote"); // +1=lkp.Len; +2=bgn/end quotes
}
else
Tfds.Eq(bgn + 1 + String_.Len(actl), bgnRef.Val(), "pos"); // +1=lkp.Len
}
void tst_ReadCsvStr_err(String raw) {
try {Bry_.ReadCsvStr(Bry_.new_u8(String_.Replace(raw, "'", "\"")), Int_obj_ref.New_zero(), (byte)'|');}
catch (Exception e) {Err_.Noop(e); return;}
Tfds.Fail_expdError();
}
@Test public void ReadCsvDte() {
tst_ReadCsvDte("20110801 221435.987");
} void tst_ReadCsvDte(String raw) {Tfds.Eq_date(DateAdp_.parse_fmt(raw, Bry_.Fmt_csvDte), Bry_.ReadCsvDte(Bry_.new_u8(raw + "|"), Int_obj_ref.New_zero(), (byte)'|'));}
@Test public void ReadCsvInt() {
tst_ReadCsvInt("1234567890");
} void tst_ReadCsvInt(String raw) {Tfds.Eq(Int_.Parse(raw), Bry_.ReadCsvInt(Bry_.new_u8(raw + "|"), Int_obj_ref.New_zero(), (byte)'|'));}
@Test public void Trim() {
Trim_tst("a b c", 1, 4, "b");
Trim_tst("a c", 1, 3, "");
Trim_tst(" ", 0, 2, "");
} void Trim_tst(String raw, int bgn, int end, String expd) {Tfds.Eq(expd, String_.new_u8(Bry_.Trim(Bry_.new_u8(raw), bgn, end)));}
@Test public void Xto_int_lax() {
tst_Xto_int_lax("12a", 12);
tst_Xto_int_lax("1", 1);
tst_Xto_int_lax("123", 123);
tst_Xto_int_lax("a", 0);
tst_Xto_int_lax("-1", -1);
}
private void tst_Xto_int_lax(String val, int expd) {Tfds.Eq(expd, Bry_.To_int_or__lax(Bry_.new_u8(val), 0, String_.Len(val), 0));}
@Test public void To_int_or__trim_ws() {
tst_Xto_int_trim("123 " , 123);
tst_Xto_int_trim(" 123" , 123);
tst_Xto_int_trim(" 123 " , 123);
tst_Xto_int_trim(" 1 3 " , -1);
}
private void tst_Xto_int_trim(String val, int expd) {Tfds.Eq(expd, Bry_.To_int_or__trim_ws(Bry_.new_u8(val), 0, String_.Len(val), -1));}
@Test public void Compare() {
tst_Compare("abcde", 0, 1, "abcde", 0, 1, CompareAble_.Same);
tst_Compare("abcde", 0, 1, "abcde", 1, 2, CompareAble_.Less);
tst_Compare("abcde", 1, 2, "abcde", 0, 1, CompareAble_.More);
tst_Compare("abcde", 0, 1, "abcde", 0, 2, CompareAble_.Less);
tst_Compare("abcde", 0, 2, "abcde", 0, 1, CompareAble_.More);
tst_Compare("abcde", 2, 3, "abçde", 2, 3, CompareAble_.Less);
} void tst_Compare(String lhs, int lhs_bgn, int lhs_end, String rhs, int rhs_bgn, int rhs_end, int expd) {Tfds.Eq(expd, Bry_.Compare(Bry_.new_u8(lhs), lhs_bgn, lhs_end, Bry_.new_u8(rhs), rhs_bgn, rhs_end));}
@Test public void Increment_last() {
tst_IncrementLast(ary_(0), ary_(1));
tst_IncrementLast(ary_(0, 255), ary_(1, 0));
tst_IncrementLast(ary_(104, 111, 112, 101), ary_(104, 111, 112, 102));
}
byte[] ary_(int... ary) {
byte[] rv = new byte[ary.length];
for (int i = 0; i < ary.length; i++)
rv[i] = Byte_.By_int(ary[i]);
return rv;
}
void tst_IncrementLast(byte[] ary, byte[] expd) {Tfds.Eq_ary(expd, Bry_.Increment_last(Bry_.Copy(ary)));}
@Test public void Replace_between() {
tst_Replace_between("a[0]b" , "[", "]", "0", "a0b");
tst_Replace_between("a[0]b[1]c" , "[", "]", "0", "a0b0c");
tst_Replace_between("a[0b" , "[", "]", "0", "a[0b");
} public void tst_Replace_between(String src, String bgn, String end, String repl, String expd) {Tfds.Eq(expd, String_.new_a7(Bry_.Replace_between(Bry_.new_a7(src), Bry_.new_a7(bgn), Bry_.new_a7(end), Bry_.new_a7(repl))));}
@Test public void Replace() {
Bry_bfr tmp_bfr = Bry_bfr_.New();
tst_Replace(tmp_bfr, "a0b" , "0", "00", "a00b"); // 1 -> 1
tst_Replace(tmp_bfr, "a0b0c" , "0", "00", "a00b00c"); // 1 -> 2
tst_Replace(tmp_bfr, "a00b00c" , "00", "0", "a0b0c"); // 2 -> 1
tst_Replace(tmp_bfr, "a0b0" , "0", "00", "a00b00"); // 1 -> 2; EOS
tst_Replace(tmp_bfr, "a00b00" , "00", "0", "a0b0"); // 2 -> 1; EOS
tst_Replace(tmp_bfr, "a0b0" , "1", "2", "a0b0"); // no match
tst_Replace(tmp_bfr, "a0b0" , "b1", "b2", "a0b0"); // false match; EOS
}
public void tst_Replace(Bry_bfr tmp_bfr, String src, String bgn, String repl, String expd) {
Tfds.Eq(expd, String_.new_a7(Bry_.Replace(tmp_bfr, Bry_.new_a7(src), Bry_.new_a7(bgn), Bry_.new_a7(repl))));
}
@Test public void Split_bry() {
Split_bry_tst("a|b|c|" , "|" , String_.Ary("a", "b", "c"));
Split_bry_tst("a|" , "|" , String_.Ary("a"));
}
void Split_bry_tst(String src, String dlm, String[] expd) {
String[] actl = String_.Ary(Bry_split_.Split(Bry_.new_a7(src), Bry_.new_a7(dlm)));
Tfds.Eq_ary_str(expd, actl);
}
@Test public void Split_lines() {
Tst_split_lines("a\nb" , "a", "b"); // basic
Tst_split_lines("a\nb\n" , "a", "b"); // do not create empty trailing lines
Tst_split_lines("a\r\nb" , "a", "b"); // crlf
Tst_split_lines("a\rb" , "a", "b"); // cr only
}
void Tst_split_lines(String src, String... expd) {
Tfds.Eq_ary(expd, New_ary(Bry_split_.Split_lines(Bry_.new_a7(src))));
}
String[] New_ary(byte[][] lines) {
int len = lines.length;
String[] rv = new String[len];
for (int i = 0; i < len; i++)
rv[i] = String_.new_u8(lines[i]);
return rv;
}
@Test public void Match_bwd_any() {
Tst_match_bwd_any("abc", 2, 0, "c", true);
Tst_match_bwd_any("abc", 2, 0, "b", false);
Tst_match_bwd_any("abc", 2, 0, "bc", true);
Tst_match_bwd_any("abc", 2, 0, "abc", true);
Tst_match_bwd_any("abc", 2, 0, "zabc", false);
Tst_match_bwd_any("abc", 1, 0, "ab", true);
}
void Tst_match_bwd_any(String src, int src_end, int src_bgn, String find, boolean expd) {
Tfds.Eq(expd, Bry_.Match_bwd_any(Bry_.new_a7(src), src_end, src_bgn, Bry_.new_a7(find)));
}
@Test public void Trim_end() {
fxt.Test_trim_end("a " , Byte_ascii.Space, "a"); // trim.one
fxt.Test_trim_end("a " , Byte_ascii.Space, "a"); // trim.many
fxt.Test_trim_end("a" , Byte_ascii.Space, "a"); // trim.none
fxt.Test_trim_end("" , Byte_ascii.Space, ""); // empty
}
@Test public void Mid_w_trim() {
fxt.Test_Mid_w_trim("abc", "abc"); // no ws
fxt.Test_Mid_w_trim(" a b c ", "a b c"); // ws at bgn and end
fxt.Test_Mid_w_trim("\r\n\t a\r\n\t b \r\n\t ", "a\r\n\t b"); // space at bgn and end
fxt.Test_Mid_w_trim("", ""); // handle 0 bytes
fxt.Test_Mid_w_trim(" ", ""); // handle all ws
}
@Test public void New_u8_nl_apos() {
fxt.Test__new_u8_nl_apos(String_.Ary("a"), "a");
fxt.Test__new_u8_nl_apos(String_.Ary("a", "b"), "a\nb");
fxt.Test__new_u8_nl_apos(String_.Ary("a", "b'c", "d"), "a\nb\"c\nd");
}
@Test public void Repeat_bry() {
fxt.Test__repeat_bry("abc" , 3, "abcabcabc");
}
@Test public void Xcase__build__all() {
fxt.Test__xcase__build__all(Bool_.N, "abc", "abc");
fxt.Test__xcase__build__all(Bool_.N, "aBc", "abc");
}
}
class Bry__fxt {
private final Bry_bfr tmp = Bry_bfr_.New();
public void Test_trim_end(String raw, byte trim, String expd) {
byte[] raw_bry = Bry_.new_a7(raw);
Tfds.Eq(expd, String_.new_u8(Bry_.Trim_end(raw_bry, trim, raw_bry.length)));
}
public void Test_new_u8(String raw, byte[] expd) {Tfds.Eq_ary(expd, Bry_.new_u8(raw));}
public void Test_new_a7(String raw, byte[] expd) {Tfds.Eq_ary(expd, Bry_.new_a7(raw));}
public void Test_add(String s, byte b, String expd) {Tfds.Eq_str(expd, String_.new_u8(Bry_.Add(Bry_.new_u8(s), b)));}
public void Test_add(byte b, String s, String expd) {Tfds.Eq_str(expd, String_.new_u8(Bry_.Add(b, Bry_.new_u8(s))));}
public void Test_add_w_dlm(String dlm, String[] itms, String expd) {Tfds.Eq(expd, String_.new_u8(Bry_.Add_w_dlm(Bry_.new_u8(dlm), Bry_.Ary(itms))));}
public void Test_add_w_dlm(byte dlm, String[] itms, String expd) {Tfds.Eq(expd, String_.new_u8(Bry_.Add_w_dlm(dlm, Bry_.Ary(itms))));}
public void Test_Mid_w_trim(String src, String expd) {byte[] bry = Bry_.new_u8(src); Tfds.Eq(expd, String_.new_u8(Bry_.Mid_w_trim(bry, 0, bry.length)));}
public void Test__new_u8_nl_apos(String[] ary, String expd) {
Tfds.Eq_str_lines(expd, String_.new_u8(Bry_.New_u8_nl_apos(ary)));
}
public void Test__repeat_bry(String s, int count, String expd) {
Gftest.Eq__str(expd, Bry_.Repeat_bry(Bry_.new_u8(s), count));
}
public void Test__xcase__build__all(boolean upper, String src, String expd) {
Gftest.Eq__str(expd, Bry_.Xcase__build__all(tmp, upper, Bry_.new_u8(src)));
}
}
package gplx;
import gplx.core.primitives.Int_obj_ref;
import gplx.core.tests.Gftest;
import org.junit.Test;
public class Bry__tst {
private final Bry__fxt fxt = new Bry__fxt();
@Test public void new_ascii_() {
fxt.Test_new_a7("a" , Bry_.New_by_ints(97)); // one
fxt.Test_new_a7("abc" , Bry_.New_by_ints(97, 98, 99)); // many
fxt.Test_new_a7("" , Bry_.Empty); // none
fxt.Test_new_a7("¢€𤭢" , Bry_.New_by_ints(63, 63, 63, 63)); // non-ascii -> ?
}
@Test public void new_u8() {
fxt.Test_new_u8("a" , Bry_.New_by_ints(97)); // one
fxt.Test_new_u8("abc" , Bry_.New_by_ints(97, 98, 99)); // many
fxt.Test_new_u8("¢" , Bry_.New_by_ints(194, 162)); // bry_len=2; cent
fxt.Test_new_u8("€" , Bry_.New_by_ints(226, 130, 172)); // bry_len=3; euro
fxt.Test_new_u8("𤭢" , Bry_.New_by_ints(240, 164, 173, 162)); // bry_len=4; example from en.w:UTF-8
}
@Test public void Add__bry_plus_byte() {
fxt.Test_add("a" , Byte_ascii.Pipe , "a|"); // basic
fxt.Test_add("" , Byte_ascii.Pipe , "|"); // empty String
}
@Test public void Add__byte_plus_bry() {
fxt.Test_add(Byte_ascii.Pipe , "a" , "|a"); // basic
fxt.Test_add(Byte_ascii.Pipe , "" , "|"); // empty String
}
@Test public void Add_w_dlm() {
fxt.Test_add_w_dlm(Byte_ascii.Pipe, String_.Ary("a", "b", "c") , "a|b|c"); // basic
fxt.Test_add_w_dlm(Byte_ascii.Pipe, String_.Ary("a") , "a"); // one item
fxt.Test_add_w_dlm(Byte_ascii.Pipe, String_.Ary("a", null, "c") , "a||c"); // null
}
@Test public void Add_w_dlm_bry() {
fxt.Test_add_w_dlm("<>", String_.Ary("a","b","c"), "a<>b<>c");
}
@Test public void MidByPos() {
tst_MidByPos("abcba", 0, 1, "a");
tst_MidByPos("abcba", 0, 2, "ab");
tst_MidByPos("abcba", 1, 4, "bcb");
} void tst_MidByPos(String src, int bgn, int end, String expd) {Tfds.Eq(expd, String_.new_u8(Bry_.Mid(Bry_.new_u8(src), bgn, end)));}
@Test public void Replace_one() {
tst_ReplaceOne("a" , "b" , "c" , "a");
tst_ReplaceOne("b" , "b" , "c" , "c");
tst_ReplaceOne("bb" , "b" , "c" , "cb");
tst_ReplaceOne("abcd" , "bc" , "" , "ad");
tst_ReplaceOne("abcd" , "b" , "ee" , "aeecd");
} void tst_ReplaceOne(String src, String find, String repl, String expd) {Tfds.Eq(expd, String_.new_u8(Bry_.Replace_one(Bry_.new_u8(src), Bry_.new_u8(find), Bry_.new_u8(repl))));}
@Test public void XtoStrBytesByInt() {
tst_XtoStrBytesByInt(0, 0);
tst_XtoStrBytesByInt(9, 9);
tst_XtoStrBytesByInt(10, 1, 0);
tst_XtoStrBytesByInt(321, 3, 2, 1);
tst_XtoStrBytesByInt(-321, Bry_.Byte_NegSign, 3, 2, 1);
tst_XtoStrBytesByInt(Int_.Max_value, 2,1,4,7,4,8,3,6,4,7);
}
void tst_XtoStrBytesByInt(int val, int... expdAryAsInt) {
byte[] expd = new byte[expdAryAsInt.length];
for (int i = 0; i < expd.length; i++) {
int expdInt = expdAryAsInt[i];
expd[i] = expdInt == Bry_.Byte_NegSign ? Bry_.Byte_NegSign : Byte_ascii.To_a7_str(expdAryAsInt[i]);
}
Tfds.Eq_ary(expd, Bry_.To_a7_bry(val, Int_.DigitCount(val)));
}
@Test public void Has_at_end() {
tst_HasAtEnd("a|bcd|e", "d" , 2, 5, true); // y_basic
tst_HasAtEnd("a|bcd|e", "bcd" , 2, 5, true); // y_many
tst_HasAtEnd("a|bcd|e", "|bcd" , 2, 5, false); // n_long
tst_HasAtEnd("a|bcd|e", "|bc" , 2, 5, false); // n_pos
tst_HasAtEnd("abc", "bc", true); // y
tst_HasAtEnd("abc", "bd", false); // n
tst_HasAtEnd("a", "ab", false); // exceeds_len
}
void tst_HasAtEnd(String src, String find, int bgn, int end, boolean expd) {Tfds.Eq(expd, Bry_.Has_at_end(Bry_.new_u8(src), Bry_.new_u8(find), bgn, end));}
void tst_HasAtEnd(String src, String find, boolean expd) {Tfds.Eq(expd, Bry_.Has_at_end(Bry_.new_u8(src), Bry_.new_u8(find)));}
@Test public void Has_at_bgn() {
tst_HasAtBgn("y_basic" , "a|bcd|e", "b" , 2, 5, true);
tst_HasAtBgn("y_many" , "a|bcd|e", "bcd" , 2, 5, true);
tst_HasAtBgn("n_long" , "a|bcd|e", "bcde" , 2, 5, false);
tst_HasAtBgn("n_pos" , "a|bcd|e", "|bc" , 2, 5, false);
} void tst_HasAtBgn(String tst, String src, String find, int bgn, int end, boolean expd) {Tfds.Eq(expd, Bry_.Has_at_bgn(Bry_.new_u8(src), Bry_.new_u8(find), bgn, end), tst);}
@Test public void Match() {
tst_Match("abc", 0, "abc", true);
tst_Match("abc", 2, "c", true);
tst_Match("abc", 0, "cde", false);
tst_Match("abc", 2, "abc", false); // bounds check
tst_Match("abc", 0, "abcd", false);
tst_Match("a" , 0, "", false);
tst_Match("" , 0, "a", false);
tst_Match("" , 0, "", true);
tst_Match("ab", 0, "a", false); // FIX: "ab" should not match "a" b/c .length is different
} void tst_Match(String src, int srcPos, String find, boolean expd) {Tfds.Eq(expd, Bry_.Match(Bry_.new_u8(src), srcPos, Bry_.new_u8(find)));}
@Test public void ReadCsvStr() {
tst_ReadCsvStr("a|" , "a");
tst_ReadCsvStr("|a|", 1 , "a");
Int_obj_ref bgn = Int_obj_ref.New_zero(); tst_ReadCsvStr("a|b|c|", bgn, "a"); tst_ReadCsvStr("a|b|c|", bgn, "b"); tst_ReadCsvStr("a|b|c|", bgn, "c");
tst_ReadCsvStr("|", "");
tst_ReadCsvStr_err("a");
tst_ReadCsvStr("'a'|" , "a");
tst_ReadCsvStr("'a''b'|" , "a'b");
tst_ReadCsvStr("'a|b'|" , "a|b");
tst_ReadCsvStr("''|", "");
tst_ReadCsvStr_err("''");
tst_ReadCsvStr_err("'a'b'");
tst_ReadCsvStr_err("'a");
tst_ReadCsvStr_err("'a|");
tst_ReadCsvStr_err("'a'");
}
@Test public void XtoIntBy4Bytes() { // test len=1, 2, 3, 4
tst_XtoIntBy4Bytes(32, (byte)32); // space
tst_XtoIntBy4Bytes(8707, (byte)34, (byte)3); // &exist;
tst_XtoIntBy4Bytes(6382179, Byte_ascii.Ltr_a, Byte_ascii.Ltr_b, Byte_ascii.Ltr_c);
tst_XtoIntBy4Bytes(1633837924, Byte_ascii.Ltr_a, Byte_ascii.Ltr_b, Byte_ascii.Ltr_c, Byte_ascii.Ltr_d);
}
@Test public void XtoInt() {
tst_XtoInt("1", 1);
tst_XtoInt("123", 123);
tst_XtoInt("a", Int_.Min_value, Int_.Min_value);
tst_XtoInt("-1", Int_.Min_value, -1);
tst_XtoInt("-123", Int_.Min_value, -123);
tst_XtoInt("123-1", Int_.Min_value, Int_.Min_value);
tst_XtoInt("+123", Int_.Min_value, 123);
tst_XtoInt("", -1);
}
void tst_XtoInt(String val, int expd) {tst_XtoInt(val, -1, expd);}
void tst_XtoInt(String val, int or, int expd) {Tfds.Eq(expd, Bry_.To_int_or(Bry_.new_u8(val), or));}
void tst_XtoIntBy4Bytes(int expd, byte... ary) {Tfds.Eq(expd, Bry_.To_int_by_a7(ary), "XtoInt"); Tfds.Eq_ary(ary, Bry_.new_by_int(expd), "XbyInt");}
void tst_ReadCsvStr(String raw, String expd) {tst_ReadCsvStr(raw, Int_obj_ref.New_zero() , expd);}
void tst_ReadCsvStr(String raw, int bgn, String expd) {tst_ReadCsvStr(raw, Int_obj_ref.New(bgn), expd);}
void tst_ReadCsvStr(String raw, Int_obj_ref bgnRef, String expd) {
int bgn = bgnRef.Val();
boolean rawHasQuotes = String_.CharAt(raw, bgn) == '\'';
String actl = String_.Replace(Bry_.ReadCsvStr(Bry_.new_u8(String_.Replace(raw, "'", "\"")), bgnRef, (byte)'|'), "\"", "'");
Tfds.Eq(expd, actl, "rv");
if (rawHasQuotes) {
int quoteAdj = String_.Count(actl, "'");
Tfds.Eq(bgn + 1 + String_.Len(actl) + 2 + quoteAdj, bgnRef.Val(), "pos_quote"); // +1=lkp.Len; +2=bgn/end quotes
}
else
Tfds.Eq(bgn + 1 + String_.Len(actl), bgnRef.Val(), "pos"); // +1=lkp.Len
}
void tst_ReadCsvStr_err(String raw) {
try {Bry_.ReadCsvStr(Bry_.new_u8(String_.Replace(raw, "'", "\"")), Int_obj_ref.New_zero(), (byte)'|');}
catch (Exception e) {Err_.Noop(e); return;}
Tfds.Fail_expdError();
}
@Test public void ReadCsvDte() {
tst_ReadCsvDte("20110801 221435.987");
} void tst_ReadCsvDte(String raw) {Tfds.Eq_date(DateAdp_.parse_fmt(raw, Bry_.Fmt_csvDte), Bry_.ReadCsvDte(Bry_.new_u8(raw + "|"), Int_obj_ref.New_zero(), (byte)'|'));}
@Test public void ReadCsvInt() {
tst_ReadCsvInt("1234567890");
} void tst_ReadCsvInt(String raw) {Tfds.Eq(Int_.Parse(raw), Bry_.ReadCsvInt(Bry_.new_u8(raw + "|"), Int_obj_ref.New_zero(), (byte)'|'));}
@Test public void Trim() {
Trim_tst("a b c", 1, 4, "b");
Trim_tst("a c", 1, 3, "");
Trim_tst(" ", 0, 2, "");
} void Trim_tst(String raw, int bgn, int end, String expd) {Tfds.Eq(expd, String_.new_u8(Bry_.Trim(Bry_.new_u8(raw), bgn, end)));}
@Test public void Xto_int_lax() {
tst_Xto_int_lax("12a", 12);
tst_Xto_int_lax("1", 1);
tst_Xto_int_lax("123", 123);
tst_Xto_int_lax("a", 0);
tst_Xto_int_lax("-1", -1);
}
private void tst_Xto_int_lax(String val, int expd) {Tfds.Eq(expd, Bry_.To_int_or__lax(Bry_.new_u8(val), 0, String_.Len(val), 0));}
@Test public void To_int_or__trim_ws() {
tst_Xto_int_trim("123 " , 123);
tst_Xto_int_trim(" 123" , 123);
tst_Xto_int_trim(" 123 " , 123);
tst_Xto_int_trim(" 1 3 " , -1);
}
private void tst_Xto_int_trim(String val, int expd) {Tfds.Eq(expd, Bry_.To_int_or__trim_ws(Bry_.new_u8(val), 0, String_.Len(val), -1));}
@Test public void Compare() {
tst_Compare("abcde", 0, 1, "abcde", 0, 1, CompareAble_.Same);
tst_Compare("abcde", 0, 1, "abcde", 1, 2, CompareAble_.Less);
tst_Compare("abcde", 1, 2, "abcde", 0, 1, CompareAble_.More);
tst_Compare("abcde", 0, 1, "abcde", 0, 2, CompareAble_.Less);
tst_Compare("abcde", 0, 2, "abcde", 0, 1, CompareAble_.More);
tst_Compare("abcde", 2, 3, "abçde", 2, 3, CompareAble_.Less);
} void tst_Compare(String lhs, int lhs_bgn, int lhs_end, String rhs, int rhs_bgn, int rhs_end, int expd) {Tfds.Eq(expd, Bry_.Compare(Bry_.new_u8(lhs), lhs_bgn, lhs_end, Bry_.new_u8(rhs), rhs_bgn, rhs_end));}
@Test public void Increment_last() {
tst_IncrementLast(ary_(0), ary_(1));
tst_IncrementLast(ary_(0, 255), ary_(1, 0));
tst_IncrementLast(ary_(104, 111, 112, 101), ary_(104, 111, 112, 102));
}
byte[] ary_(int... ary) {
byte[] rv = new byte[ary.length];
for (int i = 0; i < ary.length; i++)
rv[i] = Byte_.By_int(ary[i]);
return rv;
}
void tst_IncrementLast(byte[] ary, byte[] expd) {Tfds.Eq_ary(expd, Bry_.Increment_last(Bry_.Copy(ary)));}
@Test public void Replace_between() {
tst_Replace_between("a[0]b" , "[", "]", "0", "a0b");
tst_Replace_between("a[0]b[1]c" , "[", "]", "0", "a0b0c");
tst_Replace_between("a[0b" , "[", "]", "0", "a[0b");
} public void tst_Replace_between(String src, String bgn, String end, String repl, String expd) {Tfds.Eq(expd, String_.new_a7(Bry_.Replace_between(Bry_.new_a7(src), Bry_.new_a7(bgn), Bry_.new_a7(end), Bry_.new_a7(repl))));}
@Test public void Replace() {
Bry_bfr tmp_bfr = Bry_bfr_.New();
tst_Replace(tmp_bfr, "a0b" , "0", "00", "a00b"); // 1 -> 1
tst_Replace(tmp_bfr, "a0b0c" , "0", "00", "a00b00c"); // 1 -> 2
tst_Replace(tmp_bfr, "a00b00c" , "00", "0", "a0b0c"); // 2 -> 1
tst_Replace(tmp_bfr, "a0b0" , "0", "00", "a00b00"); // 1 -> 2; EOS
tst_Replace(tmp_bfr, "a00b00" , "00", "0", "a0b0"); // 2 -> 1; EOS
tst_Replace(tmp_bfr, "a0b0" , "1", "2", "a0b0"); // no match
tst_Replace(tmp_bfr, "a0b0" , "b1", "b2", "a0b0"); // false match; EOS
}
public void tst_Replace(Bry_bfr tmp_bfr, String src, String bgn, String repl, String expd) {
Tfds.Eq(expd, String_.new_a7(Bry_.Replace(tmp_bfr, Bry_.new_a7(src), Bry_.new_a7(bgn), Bry_.new_a7(repl))));
}
@Test public void Split_bry() {
Split_bry_tst("a|b|c|" , "|" , String_.Ary("a", "b", "c"));
Split_bry_tst("a|" , "|" , String_.Ary("a"));
}
void Split_bry_tst(String src, String dlm, String[] expd) {
String[] actl = String_.Ary(Bry_split_.Split(Bry_.new_a7(src), Bry_.new_a7(dlm)));
Tfds.Eq_ary_str(expd, actl);
}
@Test public void Split_lines() {
Tst_split_lines("a\nb" , "a", "b"); // basic
Tst_split_lines("a\nb\n" , "a", "b"); // do not create empty trailing lines
Tst_split_lines("a\r\nb" , "a", "b"); // crlf
Tst_split_lines("a\rb" , "a", "b"); // cr only
}
void Tst_split_lines(String src, String... expd) {
Tfds.Eq_ary(expd, New_ary(Bry_split_.Split_lines(Bry_.new_a7(src))));
}
String[] New_ary(byte[][] lines) {
int len = lines.length;
String[] rv = new String[len];
for (int i = 0; i < len; i++)
rv[i] = String_.new_u8(lines[i]);
return rv;
}
@Test public void Match_bwd_any() {
Tst_match_bwd_any("abc", 2, 0, "c", true);
Tst_match_bwd_any("abc", 2, 0, "b", false);
Tst_match_bwd_any("abc", 2, 0, "bc", true);
Tst_match_bwd_any("abc", 2, 0, "abc", true);
Tst_match_bwd_any("abc", 2, 0, "zabc", false);
Tst_match_bwd_any("abc", 1, 0, "ab", true);
}
void Tst_match_bwd_any(String src, int src_end, int src_bgn, String find, boolean expd) {
Tfds.Eq(expd, Bry_.Match_bwd_any(Bry_.new_a7(src), src_end, src_bgn, Bry_.new_a7(find)));
}
@Test public void Trim_bgn() {
fxt.Test_trim_bgn(" a" , Byte_ascii.Space, "a"); // trim.one
fxt.Test_trim_bgn(" a" , Byte_ascii.Space, "a"); // trim.many
fxt.Test_trim_bgn("a" , Byte_ascii.Space, "a"); // trim.none
fxt.Test_trim_bgn("" , Byte_ascii.Space, ""); // empty
}
@Test public void Trim_end() {
fxt.Test_trim_end("a " , Byte_ascii.Space, "a"); // trim.one
fxt.Test_trim_end("a " , Byte_ascii.Space, "a"); // trim.many
fxt.Test_trim_end("a" , Byte_ascii.Space, "a"); // trim.none
fxt.Test_trim_end("" , Byte_ascii.Space, ""); // empty
}
@Test public void Mid_w_trim() {
fxt.Test_Mid_w_trim("abc", "abc"); // no ws
fxt.Test_Mid_w_trim(" a b c ", "a b c"); // ws at bgn and end
fxt.Test_Mid_w_trim("\r\n\t a\r\n\t b \r\n\t ", "a\r\n\t b"); // space at bgn and end
fxt.Test_Mid_w_trim("", ""); // handle 0 bytes
fxt.Test_Mid_w_trim(" ", ""); // handle all ws
}
@Test public void New_u8_nl_apos() {
fxt.Test__new_u8_nl_apos(String_.Ary("a"), "a");
fxt.Test__new_u8_nl_apos(String_.Ary("a", "b"), "a\nb");
fxt.Test__new_u8_nl_apos(String_.Ary("a", "b'c", "d"), "a\nb\"c\nd");
}
@Test public void Repeat_bry() {
fxt.Test__repeat_bry("abc" , 3, "abcabcabc");
}
@Test public void Xcase__build__all() {
fxt.Test__xcase__build__all(Bool_.N, "abc", "abc");
fxt.Test__xcase__build__all(Bool_.N, "aBc", "abc");
}
}
class Bry__fxt {
private final Bry_bfr tmp = Bry_bfr_.New();
public void Test_trim_end(String raw, byte trim, String expd) {
byte[] raw_bry = Bry_.new_a7(raw);
Tfds.Eq(expd, String_.new_u8(Bry_.Trim_end(raw_bry, trim, raw_bry.length)));
}
public void Test_trim_bgn(String raw, byte trim, String expd) {
byte[] raw_bry = Bry_.new_a7(raw);
Tfds.Eq(expd, String_.new_u8(Bry_.Trim_bgn(raw_bry, trim, 0)));
}
public void Test_new_u8(String raw, byte[] expd) {Tfds.Eq_ary(expd, Bry_.new_u8(raw));}
public void Test_new_a7(String raw, byte[] expd) {Tfds.Eq_ary(expd, Bry_.new_a7(raw));}
public void Test_add(String s, byte b, String expd) {Tfds.Eq_str(expd, String_.new_u8(Bry_.Add(Bry_.new_u8(s), b)));}
public void Test_add(byte b, String s, String expd) {Tfds.Eq_str(expd, String_.new_u8(Bry_.Add(b, Bry_.new_u8(s))));}
public void Test_add_w_dlm(String dlm, String[] itms, String expd) {Tfds.Eq(expd, String_.new_u8(Bry_.Add_w_dlm(Bry_.new_u8(dlm), Bry_.Ary(itms))));}
public void Test_add_w_dlm(byte dlm, String[] itms, String expd) {Tfds.Eq(expd, String_.new_u8(Bry_.Add_w_dlm(dlm, Bry_.Ary(itms))));}
public void Test_Mid_w_trim(String src, String expd) {byte[] bry = Bry_.new_u8(src); Tfds.Eq(expd, String_.new_u8(Bry_.Mid_w_trim(bry, 0, bry.length)));}
public void Test__new_u8_nl_apos(String[] ary, String expd) {
Tfds.Eq_str_lines(expd, String_.new_u8(Bry_.New_u8_nl_apos(ary)));
}
public void Test__repeat_bry(String s, int count, String expd) {
Gftest.Eq__str(expd, Bry_.Repeat_bry(Bry_.new_u8(s), count));
}
public void Test__xcase__build__all(boolean upper, String src, String expd) {
Gftest.Eq__str(expd, Bry_.Xcase__build__all(tmp, upper, Bry_.new_u8(src)));
}
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,78 +13,94 @@ 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.core.gfobjs; import gplx.*; import gplx.core.*;
import gplx.langs.jsons.*;
public class Gfobj_rdr__json {
private final Json_parser parser = new Json_parser();
public Gfobj_grp Load(Io_url url) {
byte[] src = Io_mgr.Instance.LoadFilBryOrNull(url); if (src == null) return null;
return this.Parse(src);
}
public Gfobj_grp Parse(byte[] src) {
Json_doc jdoc = parser.Parse(src);
if (jdoc.Root_grp().Tid() == Json_itm_.Tid__nde) {
Gfobj_nde rv_nde = Gfobj_nde.New();
Parse_nde((Json_nde)jdoc.Root_grp(), rv_nde);
return rv_nde;
}
else {
Gfobj_ary rv_ary = new Gfobj_ary(null);
Parse_ary((Json_ary)jdoc.Root_grp(), rv_ary);
return rv_ary;
}
}
private void Parse_nde(Json_nde jnde, Gfobj_nde gnde) {
int len = jnde.Len();
for (int i = 0; i < len; ++i) {
Json_kv kv = jnde.Get_at_as_kv(i);
String key_str = kv.Key_as_str();
Json_itm val = kv.Val();
byte val_tid = val.Tid();
switch (val_tid) {
case Json_itm_.Tid__str: gnde.Add_str (key_str, ((Json_itm_str)val).Data_as_str()); break;
case Json_itm_.Tid__bool: gnde.Add_bool (key_str, ((Json_itm_bool)val).Data_as_bool()); break;
case Json_itm_.Tid__int: gnde.Add_int (key_str, ((Json_itm_int)val).Data_as_int()); break;
case Json_itm_.Tid__long: gnde.Add_long (key_str, ((Json_itm_long)val).Data_as_long()); break;
case Json_itm_.Tid__decimal: gnde.Add_double (key_str, ((Json_itm_decimal)val).Data_as_decimal().To_double()); break;
case Json_itm_.Tid__null: gnde.Add_str (key_str, null); break;
case Json_itm_.Tid__ary:
Gfobj_ary sub_ary = new Gfobj_ary(null);
gnde.Add_ary(key_str, sub_ary);
Parse_ary(Json_ary.cast(val), sub_ary);
break;
case Json_itm_.Tid__nde:
Gfobj_nde sub_gnde = Gfobj_nde.New();
gnde.Add_nde(key_str, sub_gnde);
Parse_nde(Json_nde.cast(val), sub_gnde);
break;
default: throw Err_.new_unhandled_default(val_tid);
}
}
}
private void Parse_ary(Json_ary jry, Gfobj_ary gry) {
int len = jry.Len();
Object[] ary = new Object[len];
gry.Ary_(ary);
for (int i = 0; i < len; ++i) {
Json_itm jsub = jry.Get_at(i);
switch (jsub.Tid()) {
case Json_itm_.Tid__ary: {
Gfobj_ary sub_ary = new Gfobj_ary(null);
Parse_ary(Json_ary.cast(jsub), sub_ary);
ary[i] = sub_ary;
break;
}
case Json_itm_.Tid__nde: {
Gfobj_nde sub_ary = Gfobj_nde.New();
Parse_nde(Json_nde.cast(jsub), sub_ary);
ary[i] = sub_ary;
break;
}
default:
ary[i] = jsub.Data();
break;
}
}
}
}
package gplx.core.gfobjs;
import gplx.Err_;
import gplx.Io_mgr;
import gplx.Io_url;
import gplx.langs.jsons.Json_ary;
import gplx.langs.jsons.Json_doc;
import gplx.langs.jsons.Json_itm;
import gplx.langs.jsons.Json_itm_;
import gplx.langs.jsons.Json_itm_bool;
import gplx.langs.jsons.Json_itm_decimal;
import gplx.langs.jsons.Json_itm_int;
import gplx.langs.jsons.Json_itm_long;
import gplx.langs.jsons.Json_itm_str;
import gplx.langs.jsons.Json_kv;
import gplx.langs.jsons.Json_nde;
import gplx.langs.jsons.Json_parser;
public class Gfobj_rdr__json {
private final Json_parser parser = new Json_parser();
public Gfobj_grp Load(Io_url url) {
byte[] src = Io_mgr.Instance.LoadFilBryOrNull(url); if (src == null) return null;
return this.Parse(src);
}
public Gfobj_grp Parse(byte[] src) {
Json_doc jdoc = parser.Parse(src);
if (jdoc.Root_grp().Tid() == Json_itm_.Tid__nde) {
Gfobj_nde rv_nde = Gfobj_nde.New();
Parse_nde((Json_nde)jdoc.Root_grp(), rv_nde);
return rv_nde;
}
else {
Gfobj_ary rv_ary = new Gfobj_ary(null);
Parse_ary((Json_ary)jdoc.Root_grp(), rv_ary);
return rv_ary;
}
}
private void Parse_nde(Json_nde jnde, Gfobj_nde gnde) {
int len = jnde.Len();
for (int i = 0; i < len; ++i) {
Json_kv kv = jnde.Get_at_as_kv(i);
String key_str = kv.Key_as_str();
Json_itm val = kv.Val();
byte val_tid = val.Tid();
switch (val_tid) {
case Json_itm_.Tid__str: gnde.Add_str (key_str, ((Json_itm_str)val).Data_as_str()); break;
case Json_itm_.Tid__bool: gnde.Add_bool (key_str, ((Json_itm_bool)val).Data_as_bool()); break;
case Json_itm_.Tid__int: gnde.Add_int (key_str, ((Json_itm_int)val).Data_as_int()); break;
case Json_itm_.Tid__long: gnde.Add_long (key_str, ((Json_itm_long)val).Data_as_long()); break;
case Json_itm_.Tid__decimal: gnde.Add_double (key_str, ((Json_itm_decimal)val).Data_as_decimal().To_double()); break;
case Json_itm_.Tid__null: gnde.Add_str (key_str, null); break;
case Json_itm_.Tid__ary:
Gfobj_ary sub_ary = new Gfobj_ary(null);
gnde.Add_ary(key_str, sub_ary);
Parse_ary(Json_ary.cast(val), sub_ary);
break;
case Json_itm_.Tid__nde:
Gfobj_nde sub_gnde = Gfobj_nde.New();
gnde.Add_nde(key_str, sub_gnde);
Parse_nde(Json_nde.Cast(val), sub_gnde);
break;
default: throw Err_.new_unhandled_default(val_tid);
}
}
}
private void Parse_ary(Json_ary jry, Gfobj_ary gry) {
int len = jry.Len();
Object[] ary = new Object[len];
gry.Ary_(ary);
for (int i = 0; i < len; ++i) {
Json_itm jsub = jry.Get_at(i);
switch (jsub.Tid()) {
case Json_itm_.Tid__ary: {
Gfobj_ary sub_ary = new Gfobj_ary(null);
Parse_ary(Json_ary.cast(jsub), sub_ary);
ary[i] = sub_ary;
break;
}
case Json_itm_.Tid__nde: {
Gfobj_nde sub_ary = Gfobj_nde.New();
Parse_nde(Json_nde.Cast(jsub), sub_ary);
ary[i] = sub_ary;
break;
}
default:
ary[i] = jsub.Data();
break;
}
}
}
}

@ -0,0 +1,69 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2020 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.langs.jsons;
import gplx.Bry_;
import gplx.List_adp;
import gplx.List_adp_;
import gplx.String_;
public class JsonDocBldr {
private final List_adp stack = List_adp_.New();
private final Json_doc doc = new Json_doc();
private Json_grp root;
private Json_grp cur;
JsonDocBldr() {}
public JsonDocBldr Clear(boolean isRootNode) {
this.root = isRootNode ? Json_nde.NewByDoc(doc, 0) : Json_ary.NewByDoc(doc, 0, 0);
doc.Ctor(Bry_.Empty, root);
this.cur = root;
stack.Clear();
return this;
}
public JsonDocBldr NdeBgn(String key) {
Json_nde nde = Json_nde.NewByDoc(doc, 1);
if (cur.Tid() == Json_itm_.Tid__nde) {
Json_kv kv = new Json_kv(Json_itm_str.NewByVal(key), nde);
cur.Add(kv);
}
else {
cur.Add(nde);
}
stack.Add(cur);
cur = nde;
return this;
}
public JsonDocBldr NdeEnd() {
this.cur = (Json_grp)List_adp_.Pop_last(stack);
return this;
}
public JsonDocBldr KvBool(String key, boolean val) {return Kv(key, Json_itm_bool.Get(val));}
public JsonDocBldr KvInt(String key, int val) {return Kv(key, Json_itm_int.NewByVal(val));}
public JsonDocBldr KvStr(String key, byte[] val) {return Kv(key, Json_itm_str.NewByVal(String_.new_u8(val)));}
public JsonDocBldr KvStr(String key, String val) {return Kv(key, Json_itm_str.NewByVal(val));}
private JsonDocBldr Kv(String key, Json_itm val) {
Json_kv rv = new Json_kv(Json_itm_str.NewByVal(key), val);
cur.Add(rv);
return this;
}
public Json_doc ToDoc() {
return doc;
}
public Json_nde ToRootNde() {
return doc.Root_nde();
}
public static JsonDocBldr NewRootNde() {return new JsonDocBldr().Clear(true);}
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,66 +13,75 @@ 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.langs.jsons; import gplx.*; import gplx.langs.*;
public class Json_ary extends Json_itm_base implements Json_grp {
public Json_ary(int src_bgn, int src_end) {this.Ctor(src_bgn, src_end);}
@Override public byte Tid() {return Json_itm_.Tid__ary;}
public void Src_end_(int v) {this.src_end = v;}
@Override public Object Data() {return null;}
@Override public byte[] Data_bry() {return null;}
public int Len() {return subs_len;} private int subs_len = 0, subs_max = 0;
public Json_nde Get_at_as_nde(int i) {
Json_itm rv = subs[i]; if (rv.Tid() != Json_itm_.Tid__nde) throw Err_.new_("json", "itm is not nde", "type", rv.Tid(), "i", i);
return (Json_nde)rv;
}
public Json_itm Get_at(int i) {return subs[i];}
public Json_nde Get_as_nde(int i) {return Json_nde.cast(subs[i]);}
public Json_ary Add_many(Json_itm... ary) {
int len = ary.length;
for (int i = 0; i < len; i++)
Add(ary[i]);
return this;
}
public void Add(Json_itm itm) {
int new_len = subs_len + 1;
if (new_len > subs_max) { // ary too small >>> expand
subs_max = new_len * 2;
Json_itm[] new_subs = new Json_itm[subs_max];
Array_.Copy_to(subs, 0, new_subs, 0, subs_len);
subs = new_subs;
}
subs[subs_len] = itm;
subs_len = new_len;
}
@Override public void Print_as_json(Bry_bfr bfr, int depth) {
if (subs_len == 0) { // empty grp; print on one line (rather than printing across 3)
bfr.Add_byte(Byte_ascii.Brack_bgn).Add_byte(Byte_ascii.Brack_end);
return;
}
bfr.Add_byte_nl();
Json_grp_.Print_indent(bfr, depth);
bfr.Add_byte(Byte_ascii.Brack_bgn).Add_byte(Byte_ascii.Space);
for (int i = 0; i < subs_len; i++) {
if (i != 0) {
Json_grp_.Print_nl(bfr); Json_grp_.Print_indent(bfr, depth);
bfr.Add_byte(Byte_ascii.Comma).Add_byte(Byte_ascii.Space);
}
subs[i].Print_as_json(bfr, depth + 1);
}
Json_grp_.Print_nl(bfr); Json_grp_.Print_indent(bfr, depth);
bfr.Add_byte(Byte_ascii.Brack_end).Add_byte_nl();
}
public byte[][] Xto_bry_ary() {
if (subs_len == 0) return Bry_.Ary_empty;
byte[][] rv = new byte[subs_len][];
for (int i = 0; i < subs_len; ++i)
rv[i] = subs[i].Data_bry();
return rv;
}
private Json_itm[] subs = Json_itm_.Ary_empty;
public static Json_ary cast_or_null(Json_itm v) {return v == null || v.Tid() != Json_itm_.Tid__ary ? null : (Json_ary)v;}
public static Json_ary cast(Json_itm v) {
if (v == null || v.Tid() != Json_itm_.Tid__ary) throw Err_.new_("json", "itm is not array");
return (Json_ary)v;
}
}
package gplx.langs.jsons;
import gplx.Array_;
import gplx.Bry_;
import gplx.Bry_bfr;
import gplx.Byte_ascii;
import gplx.Err_;
public class Json_ary extends Json_itm_base implements Json_grp {
private Json_ary() {}
@Override public byte Tid() {return Json_itm_.Tid__ary;}
public void Src_end_(int v) {}
@Override public Object Data() {return null;}
@Override public byte[] Data_bry() {return null;}
public int Len() {return subs_len;} private int subs_len = 0, subs_max = 0;
public Json_nde Get_at_as_nde(int i) {
Json_itm rv = subs[i]; if (rv.Tid() != Json_itm_.Tid__nde) throw Err_.new_("json", "itm is not nde", "type", rv.Tid(), "i", i);
return (Json_nde)rv;
}
public Json_itm Get_at(int i) {return subs[i];}
public Json_nde Get_as_nde(int i) {return Json_nde.Cast(subs[i]);}
public Json_ary Add_many(Json_itm... ary) {
int len = ary.length;
for (int i = 0; i < len; i++)
Add(ary[i]);
return this;
}
public void Add(Json_itm itm) {
int new_len = subs_len + 1;
if (new_len > subs_max) { // ary too small >>> expand
subs_max = new_len * 2;
Json_itm[] new_subs = new Json_itm[subs_max];
Array_.Copy_to(subs, 0, new_subs, 0, subs_len);
subs = new_subs;
}
subs[subs_len] = itm;
subs_len = new_len;
}
@Override public void Print_as_json(Bry_bfr bfr, int depth) {
if (subs_len == 0) { // empty grp; print on one line (rather than printing across 3)
bfr.Add_byte(Byte_ascii.Brack_bgn).Add_byte(Byte_ascii.Brack_end);
return;
}
bfr.Add_byte_nl();
Json_grp_.Print_indent(bfr, depth);
bfr.Add_byte(Byte_ascii.Brack_bgn).Add_byte(Byte_ascii.Space);
for (int i = 0; i < subs_len; i++) {
if (i != 0) {
Json_grp_.Print_nl(bfr); Json_grp_.Print_indent(bfr, depth);
bfr.Add_byte(Byte_ascii.Comma).Add_byte(Byte_ascii.Space);
}
subs[i].Print_as_json(bfr, depth + 1);
}
Json_grp_.Print_nl(bfr); Json_grp_.Print_indent(bfr, depth);
bfr.Add_byte(Byte_ascii.Brack_end).Add_byte_nl();
}
public byte[][] Xto_bry_ary() {
if (subs_len == 0) return Bry_.Ary_empty;
byte[][] rv = new byte[subs_len][];
for (int i = 0; i < subs_len; ++i)
rv[i] = subs[i].Data_bry();
return rv;
}
private Json_itm[] subs = Json_itm_.Ary_empty;
public static Json_ary cast_or_null(Json_itm v) {return v == null || v.Tid() != Json_itm_.Tid__ary ? null : (Json_ary)v;}
public static Json_ary cast(Json_itm v) {
if (v == null || v.Tid() != Json_itm_.Tid__ary) throw Err_.new_("json", "itm is not array");
return (Json_ary)v;
}
public static Json_ary NewByDoc(Json_doc doc, int src_bgn, int src_end) {return new Json_ary();}
public static Json_ary NewByVal() {return new Json_ary();}
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,75 +13,82 @@ 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.langs.jsons; import gplx.*; import gplx.langs.*;
import gplx.core.primitives.*;
public class Json_doc {
private final byte[][] tmp_qry_bry = new byte[1][];
public void Ctor(byte[] src, Json_grp new_root) {
this.src = src;
this.root_grp = new_root;
switch (root_grp.Tid()) {
case Json_itm_.Tid__nde: this.root_ary = null; this.root_nde = (Json_nde)root_grp; break;
case Json_itm_.Tid__ary: this.root_nde = null; this.root_ary = (Json_ary)root_grp; break;
default: throw Err_.new_unhandled(root_grp.Tid());
}
}
public byte[] Src() {return src;} private byte[] src;
public Json_grp Root_grp() {return root_grp;} private Json_grp root_grp;
public Json_nde Root_nde() {return root_nde;} private Json_nde root_nde;
public Json_ary Root_ary() {return root_ary;} private Json_ary root_ary;
public Bry_bfr Bfr() {return bfr;} private final Bry_bfr bfr = Bry_bfr_.New();
public Gfo_number_parser Utl_num_parser() {return utl_num_parser;} private final Gfo_number_parser utl_num_parser = new Gfo_number_parser();
public byte[] Tmp_u8_bry() {return tmp_u8_bry;} private final byte[] tmp_u8_bry = new byte[6]; // tmp bry[] for decoding sequences like \u0008
public byte[] Get_val_as_bry_or(byte[] qry_bry, byte[] or) {tmp_qry_bry[0] = qry_bry; return Get_val_as_bry_or(tmp_qry_bry, or);}
public byte[] Get_val_as_bry_or(byte[][] qry_bry, byte[] or) {
Json_itm nde = Find_nde(root_nde, qry_bry, qry_bry.length - 1, 0);
return nde == null || nde.Tid() != Json_itm_.Tid__str ? or : nde.Data_bry();
}
public String Get_val_as_str_or(byte[] qry_bry, String or) {tmp_qry_bry[0] = qry_bry; return Get_val_as_str_or(tmp_qry_bry, or);}
public String Get_val_as_str_or(byte[][] qry_bry, String or) {
Json_itm nde = Find_nde(root_nde, qry_bry, qry_bry.length - 1, 0);
return nde == null || nde.Tid() != Json_itm_.Tid__str ? or : (String)nde.Data();
}
public int Get_val_as_int_or(byte[] qry_bry, int or) {tmp_qry_bry[0] = qry_bry; return Get_val_as_int_or(tmp_qry_bry, or);}
public int Get_val_as_int_or(byte[][] qry_bry, int or) {
Json_itm nde = Find_nde(root_nde, qry_bry, qry_bry.length - 1, 0);
return nde == null || nde.Tid() != Json_itm_.Tid__int ? or : Bry_.To_int(nde.Data_bry());
}
public Json_grp Get_grp(byte[] qry_bry) {
tmp_qry_bry[0] = qry_bry;
Json_itm rv = Find_nde(root_nde, tmp_qry_bry, 0, 0); if (rv == null) return null;
return (Json_grp)rv;
}
public Json_grp Get_grp_many(String... qry_ary) {return Get_grp_many(Bry_.Ary(qry_ary));}
public Json_grp Get_grp_many(byte[]... qry_bry) {
Json_itm rv = Find_nde(root_nde, qry_bry, qry_bry.length - 1, 0); if (rv == null) return null;
return (Json_grp)rv;
}
public Json_itm Find_nde(byte[] key) {
tmp_qry_bry[0] = key;
return Find_nde(root_nde, tmp_qry_bry, 0, 0);
}
private Json_itm Find_nde(Json_nde owner, byte[][] paths, int paths_last, int paths_idx) {
byte[] path = paths[paths_idx];
int subs_len = owner.Len();
for (int i = 0; i < subs_len; i++) {
Json_kv itm = Json_kv.cast(owner.Get_at(i)); if (itm == null) continue; // ignore simple props, arrays, ndes
if (!itm.Key_eq(path)) continue;
if (paths_idx == paths_last) return itm.Val();
Json_nde sub_nde = Json_nde.cast(itm.Val()); if (sub_nde == null) return null; // match, but has not a nde; exit
return Find_nde(sub_nde, paths, paths_last, paths_idx + 1);
}
return null;
}
public static String Make_str_by_apos(String... ary) {return String_.Replace(String_.Concat_lines_nl_skip_last(ary), "'", "\"");}
public static String[] Make_str_ary_by_apos(String... ary) {
int len = ary.length;
for (int i = 0; i < len; ++i) {
String itm = ary[i];
if (String_.Has(itm, "'"))
ary[i] = String_.Replace(itm, "'", "\"");
}
return ary;
}
}
package gplx.langs.jsons;
import gplx.Bry_;
import gplx.Bry_bfr;
import gplx.Bry_bfr_;
import gplx.Err_;
import gplx.String_;
import gplx.core.primitives.Gfo_number_parser;
public class Json_doc {
private final byte[][] tmp_qry_bry = new byte[1][];
public void Ctor(byte[] src, Json_grp new_root) {
this.src = src;
this.root_grp = new_root;
switch (root_grp.Tid()) {
case Json_itm_.Tid__nde: this.root_ary = null; this.root_nde = (Json_nde)root_grp; break;
case Json_itm_.Tid__ary: this.root_nde = null; this.root_ary = (Json_ary)root_grp; break;
default: throw Err_.new_unhandled(root_grp.Tid());
}
}
public byte[] Src() {return src;} private byte[] src;
public Json_grp Root_grp() {return root_grp;} private Json_grp root_grp;
public Json_nde Root_nde() {return root_nde;} private Json_nde root_nde;
public Json_ary Root_ary() {return root_ary;} private Json_ary root_ary;
public Bry_bfr Bfr() {return bfr;} private final Bry_bfr bfr = Bry_bfr_.New();
public Gfo_number_parser Utl_num_parser() {return utl_num_parser;} private final Gfo_number_parser utl_num_parser = new Gfo_number_parser();
public byte[] Tmp_u8_bry() {return tmp_u8_bry;} private final byte[] tmp_u8_bry = new byte[6]; // tmp bry[] for decoding sequences like \u0008
public byte[] Get_val_as_bry_or(byte[] qry_bry, byte[] or) {tmp_qry_bry[0] = qry_bry; return Get_val_as_bry_or(tmp_qry_bry, or);}
public byte[] Get_val_as_bry_or(byte[][] qry_bry, byte[] or) {
Json_itm nde = Find_nde(root_nde, qry_bry, qry_bry.length - 1, 0);
return nde == null || nde.Tid() != Json_itm_.Tid__str ? or : nde.Data_bry();
}
public String Get_val_as_str_or(byte[] qry_bry, String or) {tmp_qry_bry[0] = qry_bry; return Get_val_as_str_or(tmp_qry_bry, or);}
public String Get_val_as_str_or(byte[][] qry_bry, String or) {
Json_itm nde = Find_nde(root_nde, qry_bry, qry_bry.length - 1, 0);
return nde == null || nde.Tid() != Json_itm_.Tid__str ? or : (String)nde.Data();
}
public int Get_val_as_int_or(byte[] qry_bry, int or) {tmp_qry_bry[0] = qry_bry; return Get_val_as_int_or(tmp_qry_bry, or);}
public int Get_val_as_int_or(byte[][] qry_bry, int or) {
Json_itm nde = Find_nde(root_nde, qry_bry, qry_bry.length - 1, 0);
return nde == null || nde.Tid() != Json_itm_.Tid__int ? or : Bry_.To_int(nde.Data_bry());
}
public Json_grp Get_grp(byte[] qry_bry) {
tmp_qry_bry[0] = qry_bry;
Json_itm rv = Find_nde(root_nde, tmp_qry_bry, 0, 0); if (rv == null) return null;
return (Json_grp)rv;
}
public Json_grp Get_grp_many(String... qry_ary) {return Get_grp_many(Bry_.Ary(qry_ary));}
public Json_grp Get_grp_many(byte[]... qry_bry) {
Json_itm rv = Find_nde(root_nde, qry_bry, qry_bry.length - 1, 0); if (rv == null) return null;
return (Json_grp)rv;
}
public Json_itm Find_nde(byte[] key) {
tmp_qry_bry[0] = key;
return Find_nde(root_nde, tmp_qry_bry, 0, 0);
}
private Json_itm Find_nde(Json_nde owner, byte[][] paths, int paths_last, int paths_idx) {
byte[] path = paths[paths_idx];
int subs_len = owner.Len();
for (int i = 0; i < subs_len; i++) {
Json_kv itm = Json_kv.Cast(owner.Get_at(i)); if (itm == null) continue; // ignore simple props, arrays, ndes
if (!itm.Key_eq(path)) continue;
if (paths_idx == paths_last) return itm.Val();
Json_nde sub_nde = Json_nde.Cast(itm.Val()); if (sub_nde == null) return null; // match, but has not a nde; exit
return Find_nde(sub_nde, paths, paths_last, paths_idx + 1);
}
return null;
}
public static String Make_str_by_apos(String... ary) {return String_.Replace(String_.Concat_lines_nl_skip_last(ary), "'", "\"");}
public static String[] Make_str_ary_by_apos(String... ary) {
int len = ary.length;
for (int i = 0; i < len; ++i) {
String itm = ary[i];
if (String_.Has(itm, "'"))
ary[i] = String_.Replace(itm, "'", "\"");
}
return ary;
}
}

@ -1,40 +0,0 @@
/*
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.langs.jsons; import gplx.*; import gplx.langs.*;
public class Json_doc_bldr {
public Json_nde Nde(Json_doc jdoc) {return factory.Nde(jdoc, -1);}
public Json_nde Nde(Json_doc jdoc, Json_grp owner) {
Json_nde rv = factory.Nde(jdoc, -1);
owner.Add(rv);
return rv;
}
public Json_itm Str(byte[] v) {return Str(String_.new_u8(v));}
public Json_itm Str(String v) {return Json_itm_tmp.new_str_(v);}
public Json_itm Int(int v) {return Json_itm_tmp.new_int_(v);}
public Json_kv Kv_int(Json_grp owner, String key, int val) {Json_kv rv = factory.Kv(Json_itm_tmp.new_str_(key), Json_itm_tmp.new_int_(val)); owner.Add(rv); return rv;}
public Json_kv Kv_str(Json_grp owner, String key, String val) {Json_kv rv = factory.Kv(Json_itm_tmp.new_str_(key), Json_itm_tmp.new_str_(val)); owner.Add(rv); return rv;}
public Json_ary Kv_ary(Json_grp owner, String key, Json_itm... subs) {
Json_itm key_itm = Json_itm_tmp.new_str_(key);
Json_ary val_ary = factory.Ary(-1, -1);
Json_kv kv = factory.Kv(key_itm, val_ary);
owner.Add(kv);
int len = subs.length;
for (int i = 0; i < len; i++)
val_ary.Add(subs[i]);
return val_ary;
}
Json_doc doc = new Json_doc(); Json_factory factory = new Json_factory();
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,140 +13,155 @@ 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.langs.jsons; import gplx.*; import gplx.langs.*;
import gplx.objects.strings.unicodes.*;
import gplx.core.encoders.*;
public class Json_doc_wtr {
private int indent = -2;
private Bry_bfr bfr = Bry_bfr_.Reset(255);
public void Opt_unicode_y_() {opt_unicode = true;} private boolean opt_unicode;
public Json_doc_wtr Indent() {return Indent(indent);}
private Json_doc_wtr Indent(int v) {if (v > 0) bfr.Add_byte_repeat(Byte_ascii.Space, v); return this;}
public Json_doc_wtr Indent_add() {indent += 2; return this;}
public Json_doc_wtr Indent_del() {indent -= 2; return this;}
public Json_doc_wtr Nde_bgn() {Indent_add(); Indent(); bfr.Add_byte(Byte_ascii.Curly_bgn).Add_byte_nl(); return this;}
public Json_doc_wtr Nde_end() { Indent(); bfr.Add_byte(Byte_ascii.Curly_end).Add_byte_nl(); Indent_del(); return this;}
public Json_doc_wtr Ary_bgn() {Indent_add(); Indent(); bfr.Add_byte(Byte_ascii.Brack_bgn).Add_byte_nl(); return this;}
public Json_doc_wtr Ary_end() { Indent(); bfr.Add_byte(Byte_ascii.Brack_end).Add_byte_nl(); Indent_del(); return this;}
public Json_doc_wtr New_line() {bfr.Add_byte_nl(); return this;}
public Json_doc_wtr Str(byte[] v) {
if (v == null)
bfr.Add(Object_.Bry__null);
else {
bfr.Add_byte(Byte_ascii.Quote);
if (opt_unicode) {
Ustring ustr = Ustring_.New_codepoints(String_.new_u8(v));
int ustr_len = ustr.Len_in_data();
for (int i = 0; i < ustr_len; i++) {
int cp = ustr.Get_data(i);
Write_str_codepoint(bfr, cp);
}
}
else {
bfr.Add_bry_escape(Byte_ascii.Quote, Escaped__quote, v, 0, v.length);
}
bfr.Add_byte(Byte_ascii.Quote);
}
return this;
}
private void Write_str_codepoint(Bry_bfr bfr, int val) {
switch (val) { // REF: https://www.json.org/
case Byte_ascii.Quote:
bfr.Add_byte_backslash().Add_byte(Byte_ascii.Quote);
break;
case Byte_ascii.Backslash:
bfr.Add_byte_backslash().Add_byte(Byte_ascii.Backslash);
break;
case Byte_ascii.Backfeed:
bfr.Add_byte_backslash().Add_byte(Byte_ascii.Ltr_b);
break;
case Byte_ascii.Formfeed:
bfr.Add_byte_backslash().Add_byte(Byte_ascii.Ltr_f);
break;
case Byte_ascii.Nl:
bfr.Add_byte_backslash().Add_byte(Byte_ascii.Ltr_n);
break;
case Byte_ascii.Cr:
bfr.Add_byte_backslash().Add_byte(Byte_ascii.Ltr_r);
break;
case Byte_ascii.Tab:
bfr.Add_byte_backslash().Add_byte(Byte_ascii.Ltr_t);
break;
default:
if ( val < Byte_ascii.Space // control characters
|| val == 160 // nbsp
|| val == 8206 // left to right
|| val == 8207 // right to left
) {
// convert to \u1234
bfr.Add_byte_backslash().Add_byte(Byte_ascii.Ltr_u).Add_str_a7(Hex_utl_.To_str(val, 4));
}
else {
bfr.Add_u8_int(val);
}
break;
}
}
public Json_doc_wtr Int(int v) {bfr.Add_int_variable(v); return this;}
public Json_doc_wtr Double(double v) {bfr.Add_double(v); return this;}
public Json_doc_wtr Comma() {Indent(); bfr.Add_byte(Byte_ascii.Comma).Add_byte_nl(); return this;}
public Json_doc_wtr Kv_ary_empty(boolean comma, byte[] key) {
Key_internal(comma, key);
bfr.Add_byte(Byte_ascii.Brack_bgn).Add_byte(Byte_ascii.Brack_end);
bfr.Add_byte_nl();
return this;
}
public Json_doc_wtr Kv(boolean comma, byte[] key, byte[] val) {
Key_internal(comma, key);
Str(val);
bfr.Add_byte_nl();
return this;
}
public Json_doc_wtr Kv_double(boolean comma, byte[] key, double v) {
Key_internal(comma, key);
Double(v);
bfr.Add_byte_nl();
return this;
}
public Json_doc_wtr Kv(boolean comma, byte[] key, int v) {
Key_internal(comma, key);
Int(v);
bfr.Add_byte_nl();
return this;
}
public Json_doc_wtr Key(boolean comma, String key) {return Key(comma, Bry_.new_u8(key));}
public Json_doc_wtr Key(boolean comma, byte[] key) {
Key_internal(comma, key);
bfr.Add_byte_nl();
return this;
}
public Json_doc_wtr Val(boolean comma, int v) {
Val_internal(comma);
Int(v);
New_line();
return this;
}
public Json_doc_wtr Val(boolean comma, byte[] v) {
Val_internal(comma);
Str(v);
New_line();
return this;
}
Json_doc_wtr Val_internal(boolean comma) {
Indent();
bfr.Add_byte(comma ? Byte_ascii.Comma : Byte_ascii.Space);
bfr.Add_byte(Byte_ascii.Space);
return this;
}
Json_doc_wtr Key_internal(boolean comma, byte[] key) {
Indent();
bfr.Add_byte(comma ? Byte_ascii.Comma : Byte_ascii.Space);
bfr.Add_byte(Byte_ascii.Space);
Str(key);
bfr.Add_byte(Byte_ascii.Colon);
return this;
}
public byte[] Bld() {return bfr.To_bry_and_clear();}
public String Bld_as_str() {return bfr.To_str_and_clear();}
private static final byte[] Escaped__quote = Bry_.new_a7("\\\"");
}
package gplx.langs.jsons;
import gplx.Bool_;
import gplx.Bry_;
import gplx.Bry_bfr;
import gplx.Bry_bfr_;
import gplx.Byte_ascii;
import gplx.Double_;
import gplx.Object_;
import gplx.String_;
import gplx.core.encoders.Hex_utl_;
import gplx.objects.strings.unicodes.Ustring;
import gplx.objects.strings.unicodes.Ustring_;
public class Json_doc_wtr {
private int indent = -2;
private Bry_bfr bfr = Bry_bfr_.Reset(255);
public void Opt_unicode_y_() {opt_unicode = true;} private boolean opt_unicode;
public Json_doc_wtr Indent() {return Indent(indent);}
private Json_doc_wtr Indent(int v) {if (v > 0) bfr.Add_byte_repeat(Byte_ascii.Space, v); return this;}
public Json_doc_wtr Indent_add() {indent += 2; return this;}
public Json_doc_wtr Indent_del() {indent -= 2; return this;}
public Json_doc_wtr Nde_bgn() {Indent_add(); Indent(); bfr.Add_byte(Byte_ascii.Curly_bgn).Add_byte_nl(); return this;}
public Json_doc_wtr Nde_end() { Indent(); bfr.Add_byte(Byte_ascii.Curly_end).Add_byte_nl(); Indent_del(); return this;}
public Json_doc_wtr Ary_bgn() {Indent_add(); Indent(); bfr.Add_byte(Byte_ascii.Brack_bgn).Add_byte_nl(); return this;}
public Json_doc_wtr Ary_end() { Indent(); bfr.Add_byte(Byte_ascii.Brack_end).Add_byte_nl(); Indent_del(); return this;}
public Json_doc_wtr New_line() {bfr.Add_byte_nl(); return this;}
public Json_doc_wtr Str(byte[] v) {
if (v == null)
bfr.Add(Object_.Bry__null);
else {
bfr.Add_byte(Byte_ascii.Quote);
if (opt_unicode) {
Ustring ustr = Ustring_.New_codepoints(String_.new_u8(v));
int ustr_len = ustr.Len_in_data();
for (int i = 0; i < ustr_len; i++) {
int cp = ustr.Get_data(i);
Write_str_codepoint(bfr, cp);
}
}
else {
bfr.Add_bry_escape(Byte_ascii.Quote, Escaped__quote, v, 0, v.length);
}
bfr.Add_byte(Byte_ascii.Quote);
}
return this;
}
private void Write_str_codepoint(Bry_bfr bfr, int val) {
switch (val) { // REF: https://www.json.org/
case Byte_ascii.Quote:
bfr.Add_byte_backslash().Add_byte(Byte_ascii.Quote);
break;
case Byte_ascii.Backslash:
bfr.Add_byte_backslash().Add_byte(Byte_ascii.Backslash);
break;
case Byte_ascii.Backfeed:
bfr.Add_byte_backslash().Add_byte(Byte_ascii.Ltr_b);
break;
case Byte_ascii.Formfeed:
bfr.Add_byte_backslash().Add_byte(Byte_ascii.Ltr_f);
break;
case Byte_ascii.Nl:
bfr.Add_byte_backslash().Add_byte(Byte_ascii.Ltr_n);
break;
case Byte_ascii.Cr:
bfr.Add_byte_backslash().Add_byte(Byte_ascii.Ltr_r);
break;
case Byte_ascii.Tab:
bfr.Add_byte_backslash().Add_byte(Byte_ascii.Ltr_t);
break;
default:
if ( val < Byte_ascii.Space // control characters
|| val == 160 // nbsp
|| val == 8206 // left to right
|| val == 8207 // right to left
) {
// convert to \u1234
bfr.Add_byte_backslash().Add_byte(Byte_ascii.Ltr_u).Add_str_a7(Hex_utl_.To_str(val, 4));
}
else {
bfr.Add_u8_int(val);
}
break;
}
}
public Json_doc_wtr Int(int v) {bfr.Add_int_variable(v); return this;}
public Json_doc_wtr Double(double v) {bfr.Add_double(v); return this;}
public Json_doc_wtr Comma() {Indent(); bfr.Add_byte(Byte_ascii.Comma).Add_byte_nl(); return this;}
public Json_doc_wtr Kv_ary_empty(boolean comma, byte[] key) {
Key_internal(comma, key);
bfr.Add_byte(Byte_ascii.Brack_bgn).Add_byte(Byte_ascii.Brack_end);
bfr.Add_byte_nl();
return this;
}
public Json_doc_wtr Kv(boolean comma, String key, byte[] val) {return Kv(comma, Bry_.new_u8(key), val);}
public Json_doc_wtr Kv(boolean comma, byte[] key, byte[] val) {
Key_internal(comma, key);
Str(val);
bfr.Add_byte_nl();
return this;
}
public Json_doc_wtr Kv_double(boolean comma, byte[] key, double v) {
Key_internal(comma, key);
Double(v);
bfr.Add_byte_nl();
return this;
}
public Json_doc_wtr Kv(boolean comma, String key, int v) {return Kv(comma, Bry_.new_u8(key), v);}
public Json_doc_wtr Kv(boolean comma, byte[] key, int v) {
Key_internal(comma, key);
Int(v);
bfr.Add_byte_nl();
return this;
}
public Json_doc_wtr Kv(boolean comma, String key, double v) {return Kv(comma, Bry_.new_u8(key), Bry_.new_u8(Double_.To_str(v)));}
public Json_doc_wtr Kv(boolean comma, String key, boolean v) {return Kv(comma, Bry_.new_u8(key), v ? Bool_.Y_bry : Bool_.N_bry);}
public Json_doc_wtr Key(boolean comma, String key) {return Key(comma, Bry_.new_u8(key));}
public Json_doc_wtr Key(boolean comma, byte[] key) {
Key_internal(comma, key);
bfr.Add_byte_nl();
return this;
}
public Json_doc_wtr Val(boolean comma, int v) {
Val_internal(comma);
Int(v);
New_line();
return this;
}
public Json_doc_wtr Val(boolean comma, byte[] v) {
Val_internal(comma);
Str(v);
New_line();
return this;
}
Json_doc_wtr Val_internal(boolean comma) {
Indent();
bfr.Add_byte(comma ? Byte_ascii.Comma : Byte_ascii.Space);
bfr.Add_byte(Byte_ascii.Space);
return this;
}
Json_doc_wtr Key_internal(boolean comma, byte[] key) {
Indent();
bfr.Add_byte(comma ? Byte_ascii.Comma : Byte_ascii.Space);
bfr.Add_byte(Byte_ascii.Space);
Str(key);
bfr.Add_byte(Byte_ascii.Colon);
return this;
}
public byte[] Bld() {return bfr.To_bry_and_clear();}
public String Bld_as_str() {return bfr.To_str_and_clear();}
private static final byte[] Escaped__quote = Bry_.new_a7("\\\"");
}

@ -1,28 +0,0 @@
/*
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.langs.jsons; import gplx.*; import gplx.langs.*;
public class Json_factory {
public Json_itm Null() {return Json_itm_null.Null;}
public Json_itm Bool_n() {return Json_itm_bool.Bool_n;}
public Json_itm Bool_y() {return Json_itm_bool.Bool_y;}
public Json_itm_int Int(Json_doc doc, int bgn, int end) {return new Json_itm_int(doc, bgn, end);}
public Json_itm_long Long(Json_doc doc, int bgn, int end) {return new Json_itm_long(doc, bgn, end);}
public Json_itm Decimal(Json_doc doc, int bgn, int end) {return new Json_itm_decimal(doc, bgn, end);}
public Json_itm Str(Json_doc doc, int bgn, int end, boolean exact) {return new Json_itm_str(doc, bgn, end, exact);}
public Json_kv Kv(Json_itm key, Json_itm val) {return new Json_kv(key, val);}
public Json_ary Ary(int bgn, int end) {return new Json_ary(bgn, end);}
public Json_nde Nde(Json_doc doc, int bgn) {return new Json_nde(doc, bgn);}
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,21 +13,23 @@ 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.langs.jsons; import gplx.*; import gplx.langs.*;
public interface Json_itm {
byte Tid();
int Src_bgn();
int Src_end();
Object Data();
byte[] Data_bry();
void Print_as_json(Bry_bfr bfr, int depth);
boolean Data_eq(byte[] comp);
}
class Json_itm_null extends Json_itm_base {
Json_itm_null() {this.Ctor(-1, -1);}
@Override public byte Tid() {return Json_itm_.Tid__null;}
@Override public Object Data() {return null;}
@Override public void Print_as_json(Bry_bfr bfr, int depth) {bfr.Add(Object_.Bry__null);}
@Override public byte[] Data_bry() {return Object_.Bry__null;}
public static final Json_itm_null Null = new Json_itm_null();
}
package gplx.langs.jsons;
import gplx.Bry_bfr;
import gplx.Object_;
public interface Json_itm {
byte Tid();
Object Data();
byte[] Data_bry();
boolean Data_eq(byte[] comp);
void Print_as_json(Bry_bfr bfr, int depth);
}
class Json_itm_null extends Json_itm_base {
Json_itm_null() {}
@Override public byte Tid() {return Json_itm_.Tid__null;}
@Override public Object Data() {return null;}
@Override public void Print_as_json(Bry_bfr bfr, int depth) {bfr.Add(Object_.Bry__null);}
@Override public byte[] Data_bry() {return Object_.Bry__null;}
public static final Json_itm_null Null = new Json_itm_null();
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,15 +13,20 @@ 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.langs.jsons; import gplx.*; import gplx.langs.*;
public abstract class Json_itm_base implements Json_itm {
public abstract byte Tid();
public void Ctor(int src_bgn, int src_end) {this.src_bgn = src_bgn; this.src_end = src_end;}
public int Src_bgn() {return src_bgn;} private int src_bgn;
public int Src_end() {return src_end;} protected int src_end;
public abstract Object Data();
public abstract byte[] Data_bry();
public String Print_as_json() {Bry_bfr bfr = Bry_bfr_.New(); Print_as_json(bfr, 0); return bfr.To_str_and_clear();}
public abstract void Print_as_json(Bry_bfr bfr, int depth);
@gplx.Virtual public boolean Data_eq(byte[] comp) {return false;}
}
package gplx.langs.jsons;
import gplx.Bry_bfr;
import gplx.Bry_bfr_;
public abstract class Json_itm_base implements Json_itm {
public abstract byte Tid();
public abstract Object Data();
public abstract byte[] Data_bry();
public String Print_as_json() {
Bry_bfr bfr = Bry_bfr_.New();
Print_as_json(bfr, 0);
return bfr.To_str_and_clear();
}
public abstract void Print_as_json(Bry_bfr bfr, int depth);
@gplx.Virtual public boolean Data_eq(byte[] comp) {return false;}
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,14 +13,22 @@ 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.langs.jsons; import gplx.*; import gplx.langs.*;
public class Json_itm_bool extends Json_itm_base {
private boolean data;
public Json_itm_bool(boolean data) {this.data = data; this.Ctor(-1, -1);}
@Override public byte Tid() {return Json_itm_.Tid__bool;}
public boolean Data_as_bool() {return data;}
@Override public Object Data() {return data;}
@Override public byte[] Data_bry() {return data ? Json_itm_.Bry__true : Json_itm_.Bry__false;}
@Override public void Print_as_json(Bry_bfr bfr, int depth) {bfr.Add(data ? Json_itm_.Bry__true: Json_itm_.Bry__false);}
public static final Json_itm_bool Bool_n = new Json_itm_bool(false), Bool_y = new Json_itm_bool(true);
}
package gplx.langs.jsons;
import gplx.Bry_bfr;
public class Json_itm_bool extends Json_itm_base {
private boolean data;
private Json_itm_bool(boolean data) {
this.data = data;
}
@Override public byte Tid() {return Json_itm_.Tid__bool;}
public boolean Data_as_bool() {return data;}
@Override public Object Data() {return data;}
@Override public byte[] Data_bry() {return data ? Json_itm_.Bry__true : Json_itm_.Bry__false;}
@Override public void Print_as_json(Bry_bfr bfr, int depth) {bfr.Add(data ? Json_itm_.Bry__true: Json_itm_.Bry__false);}
public static final Json_itm_bool Bool_n = new Json_itm_bool(false), Bool_y = new Json_itm_bool(true);
public static final Json_itm_bool Get(boolean v) {return v ? Bool_y : Bool_n;}
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,23 +13,54 @@ 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.langs.jsons; import gplx.*; import gplx.langs.*;
public class Json_itm_decimal extends Json_itm_base {
private final Json_doc doc; private Decimal_adp data; private byte[] data_bry;
public Json_itm_decimal(Json_doc doc, int src_bgn, int src_end) {this.Ctor(src_bgn, src_end); this.doc = doc;}
@Override public byte Tid() {return Json_itm_.Tid__decimal;}
@Override public Object Data() {return this.Data_as_decimal();}
@Override public byte[] Data_bry() {
if (data_bry == null) data_bry = Bry_.Mid(doc.Src(), this.Src_bgn(), this.Src_end());
return data_bry;
}
public Decimal_adp Data_as_decimal() {
if (data == null) {
String s = String_.new_a7(this.Data_bry());
s = String_.Replace(s, "e", "E"); // exponent can be either "e" or "E" in JSON, but Java decimal parse only takes "E"; ISSUE#:565; DATE:2020-03-25
data = Decimal_adp_.parse(s);
}
return data;
}
@Override public void Print_as_json(Bry_bfr bfr, int depth) {bfr.Add_mid(doc.Src(), this.Src_bgn(), this.Src_end());}
}
package gplx.langs.jsons;
import gplx.Bry_;
import gplx.Bry_bfr;
import gplx.Decimal_adp;
import gplx.Decimal_adp_;
import gplx.Double_;
import gplx.String_;
public class Json_itm_decimal extends Json_itm_base {
private final Json_doc doc;
private final int src_bgn, src_end;
private Decimal_adp data;
private byte[] data_bry;
private Json_itm_decimal(Json_doc doc, int src_bgn, int src_end, Decimal_adp data) {
this.doc = doc;
this.src_bgn = src_bgn;
this.src_end = src_end;
this.data = data;
}
@Override public byte Tid() {return Json_itm_.Tid__decimal;}
@Override public Object Data() {return this.Data_as_decimal();}
@Override public byte[] Data_bry() {
if (data_bry == null) {
data_bry = data == null
? Bry_.Mid(doc.Src(), src_bgn, src_end)
: Bry_.new_u8(Double_.To_str_loose(data.To_double()));
}
return data_bry;
}
public Decimal_adp Data_as_decimal() {
if (data == null) {
String s = String_.new_a7(this.Data_bry());
s = String_.Replace(s, "e", "E"); // exponent can be either "e" or "E" in JSON, but Java decimal parse only takes "E"; ISSUE#:565; DATE:2020-03-25
data = Decimal_adp_.parse(s);
}
return data;
}
@Override public void Print_as_json(Bry_bfr bfr, int depth) {
if (doc == null) {
bfr.Add_str_a7(Double_.To_str_loose(data.To_double()));
}
else {
bfr.Add_mid(doc.Src(), src_bgn, src_end);
}
}
public static Json_itm_decimal NewByDoc(Json_doc doc, int src_bgn, int src_end) {return new Json_itm_decimal(doc, src_bgn, src_end, null);}
public static Json_itm_decimal NewByVal(Decimal_adp val) {return new Json_itm_decimal(null, -1, -1, val);}
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,21 +13,52 @@ 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.langs.jsons; import gplx.*; import gplx.langs.*;
public class Json_itm_int extends Json_itm_base {
private final Json_doc doc;
private byte[] data_bry; private int data; private boolean data_is_null = true;
public Json_itm_int(Json_doc doc, int src_bgn, int src_end) {this.Ctor(src_bgn, src_end); this.doc = doc;}
@Override public byte Tid() {return Json_itm_.Tid__int;}
public int Data_as_int() {
if (data_is_null) {
data = doc.Utl_num_parser().Parse(doc.Src(), Src_bgn(), Src_end()).Rv_as_int();
data_is_null = false;
}
return data;
}
@Override public Object Data() {return Data_as_int();}
@Override public byte[] Data_bry() {if (data_bry == null) data_bry = Bry_.Mid(doc.Src(), this.Src_bgn(), this.Src_end()); return data_bry;}
@Override public void Print_as_json(Bry_bfr bfr, int depth) {bfr.Add_mid(doc.Src(), this.Src_bgn(), this.Src_end());}
public static Json_itm_int cast(Json_itm v) {return v == null || v.Tid() != Json_itm_.Tid__int ? null : (Json_itm_int)v;}
}
package gplx.langs.jsons;
import gplx.Bry_;
import gplx.Bry_bfr;
import gplx.Int_;
public class Json_itm_int extends Json_itm_base {
private final Json_doc doc;
private final int src_bgn, src_end;
private byte[] data_bry;
private int data;
private boolean data_needs_making;
private Json_itm_int(Json_doc doc, int src_bgn, int src_end, boolean data_needs_making, int data) {
this.doc = doc;
this.src_bgn = src_bgn;
this.src_end = src_end;
this.data_needs_making = data_needs_making;
if (!data_needs_making)
this.data = data;
}
@Override public byte Tid() {return Json_itm_.Tid__int;}
@Override public Object Data() {return Data_as_int();}
@Override public byte[] Data_bry() {
if (data_bry == null) {
data_bry = doc == null
? Int_.To_bry(data)
: Bry_.Mid(doc.Src(), src_bgn, src_end);
}
return data_bry;
}
public int Data_as_int() {
if (data_needs_making) {
data = doc.Utl_num_parser().Parse(doc.Src(), src_bgn, src_end).Rv_as_int();
data_needs_making = false;
}
return data;
}
@Override public void Print_as_json(Bry_bfr bfr, int depth) {
if (doc == null)
bfr.Add_int_variable(data);
else
bfr.Add_mid(doc.Src(), src_bgn, src_end);
}
public static Json_itm_int NewByDoc(Json_doc doc, int src_bgn, int src_end) {return new Json_itm_int(doc, src_bgn, src_end, true, -1);}
public static Json_itm_int NewByVal(int val) {return new Json_itm_int(null, -1, -1, false, val);}
public static Json_itm_int Cast(Json_itm v) {return v == null || v.Tid() != Json_itm_.Tid__int ? null : (Json_itm_int)v;}
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,21 +13,51 @@ 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.langs.jsons; import gplx.*; import gplx.langs.*;
public class Json_itm_long extends Json_itm_base {
private final Json_doc doc;
private byte[] data_bry; private long data; private boolean data_is_null = true;
public Json_itm_long(Json_doc doc, int src_bgn, int src_end) {this.Ctor(src_bgn, src_end); this.doc = doc;}
@Override public byte Tid() {return Json_itm_.Tid__long;}
public long Data_as_long() {
if (data_is_null) {
data = doc.Utl_num_parser().Parse(doc.Src(), Src_bgn(), Src_end()).Rv_as_long();
data_is_null = false;
}
return data;
}
@Override public Object Data() {return Data_as_long();}
@Override public byte[] Data_bry() {if (data_bry == null) data_bry = Bry_.Mid(doc.Src(), this.Src_bgn(), this.Src_end()); return data_bry;}
@Override public void Print_as_json(Bry_bfr bfr, int depth) {bfr.Add_mid(doc.Src(), this.Src_bgn(), this.Src_end());}
public static Json_itm_long cast(Json_itm v) {return v == null || v.Tid() != Json_itm_.Tid__long ? null : (Json_itm_long)v;}
}
package gplx.langs.jsons;
import gplx.Bry_;
import gplx.Bry_bfr;
import gplx.Long_;
public class Json_itm_long extends Json_itm_base {
private final Json_doc doc;
private final int src_bgn, src_end;
private byte[] data_bry;
private long data;
private boolean data_needs_making = true;
private Json_itm_long(Json_doc doc, int src_bgn, int src_end, boolean data_needs_making, long data) {
this.doc = doc;
this.src_bgn = src_bgn;
this.src_end = src_end;
this.data_needs_making = data_needs_making;
if (!data_needs_making)
this.data = data;
}
@Override public byte Tid() {return Json_itm_.Tid__long;}
@Override public Object Data() {return Data_as_long();}
@Override public byte[] Data_bry() {
if (data_bry == null) {
data_bry = doc == null
? Bry_.new_u8(Long_.To_str(data))
: Bry_.Mid(doc.Src(), src_bgn, src_end);
}
return data_bry;
}
public long Data_as_long() {
if (data_needs_making) {
data = doc.Utl_num_parser().Parse(doc.Src(), src_bgn, src_end).Rv_as_long();
data_needs_making = false;
}
return data;
}
@Override public void Print_as_json(Bry_bfr bfr, int depth) {
if (doc == null)
bfr.Add_long_variable(data);
else
bfr.Add_mid(doc.Src(), src_bgn, src_end);
}
public static Json_itm_long NewByDoc(Json_doc doc, int src_bgn, int src_end) {return new Json_itm_long(doc, src_bgn, src_end, true, -1);}
public static Json_itm_long NewByVal(long val) {return new Json_itm_long(null, -1, -1, false, val);}
public static Json_itm_long Cast(Json_itm v) {return v == null || v.Tid() != Json_itm_.Tid__long ? null : (Json_itm_long)v;}
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,83 +13,153 @@ 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.langs.jsons; import gplx.*; import gplx.langs.*;
import gplx.core.intls.*;
public class Json_itm_str extends Json_itm_base {
private final boolean exact; private final Json_doc doc;
private String data_str; private byte[] data_bry = null;
public Json_itm_str(Json_doc doc, int src_bgn, int src_end, boolean exact) {this.Ctor(src_bgn + 1, src_end - 1); this.doc = doc; this.exact = exact;}
@Override public byte Tid() {return Json_itm_.Tid__str;}
@Override public void Print_as_json(Bry_bfr bfr, int depth) {
bfr.Add_byte(Byte_ascii.Quote);
gplx.langs.htmls.Gfh_utl.Escape_html_to_bfr(bfr, doc.Src(), this.Src_bgn(), this.Src_end(), true, true, true, true, false); // false to apos for backwards compatibility
bfr.Add_byte(Byte_ascii.Quote);
}
@Override public Object Data() {return this.Data_as_str();}
public String Data_as_str() {
if (data_str == null) {
if (data_bry == null)
data_bry = Data_make_bry();
data_str = String_.new_u8(data_bry);
}
return data_str;
}
@Override public byte[] Data_bry() {if (data_bry == null) data_bry = Data_make_bry(); return data_bry;}
@Override public boolean Data_eq(byte[] comp) {
if (exact) return Bry_.Eq(doc.Src(), this.Src_bgn(), this.Src_end(), comp);
if (data_bry == null) data_bry = Data_make_bry();
return Bry_.Match(data_bry, comp);
}
private byte[] Data_make_bry() {
byte[] src = doc.Src(); int bgn = this.Src_bgn(), end = this.Src_end();
if (exact) return Bry_.Mid(src, bgn, end);
Bry_bfr bfr = doc.Bfr();
byte[] utf8_bry = doc.Tmp_u8_bry();
for (int i = bgn; i < end; i++) {
byte b = src[i];
switch (b) {
case Byte_ascii.Backslash:
b = src[++i];
switch (b) { // NOTE: must properly unescape chars; EX:wd.q:2; DATE:2014-04-23
case Byte_ascii.Ltr_t: bfr.Add_byte(Byte_ascii.Tab); break;
case Byte_ascii.Ltr_n: bfr.Add_byte(Byte_ascii.Nl); break;
case Byte_ascii.Ltr_r: bfr.Add_byte(Byte_ascii.Cr); break;
case Byte_ascii.Ltr_b: bfr.Add_byte(Byte_ascii.Backfeed); break;
case Byte_ascii.Ltr_f: bfr.Add_byte(Byte_ascii.Formfeed); break;
case Byte_ascii.Ltr_u:
i += 1; // +1 to skip "u"
int utf8_val = gplx.core.encoders.Hex_utl_.Parse_or(src, i, i + 4, -1);
// check for UTF surrogate-pairs; ISSUE#:487; DATE:2019-06-02
// hi: 0xD800-0xDBFF; 55,296-56,319
if (utf8_val >= Utf16_.Surrogate_hi_bgn && utf8_val <= Utf16_.Surrogate_hi_end) {
int lo_bgn = i + 4; // +4 to skip 4 hex-dec chars
if (lo_bgn + 6 <= end // +6 to handle encoded String; EX: '\u0022'
&& src[lo_bgn] == Byte_ascii.Backslash
&& src[lo_bgn + 1] == Byte_ascii.Ltr_u) {
lo_bgn = lo_bgn + 2; // +2 to skip '\' and 'u'
int lo = gplx.core.encoders.Hex_utl_.Parse_or(src, lo_bgn, lo_bgn + 4, -1);
// lo: 0xDC00-0xDFFF; 56,320-57,343
if (lo >= Utf16_.Surrogate_lo_bgn && lo <= Utf16_.Surrogate_lo_end) {
utf8_val = Utf16_.Surrogate_merge(utf8_val, lo);
i += 6; // +6 to skip entire lo-String; EX: '\u0022'
}
}
}
int len = gplx.core.intls.Utf16_.Encode_int(utf8_val, utf8_bry, 0);
bfr.Add_mid(utf8_bry, 0, len);
i += 3; // +3 b/c for-loop will do another +1 to bring total to 4; EX: '0022'
break;
case Byte_ascii.Backslash:
case Byte_ascii.Slash:
default:
bfr.Add_byte(b); break; // \? " \ / b f n r t
}
break;
default:
bfr.Add_byte(b);
break;
}
}
return bfr.To_bry_and_clear();
}
}
package gplx.langs.jsons;
import gplx.Bry_;
import gplx.Bry_bfr;
import gplx.Bry_bfr_;
import gplx.Byte_ascii;
import gplx.String_;
import gplx.core.intls.Utf16_;
import gplx.langs.htmls.Gfh_utl;
public class Json_itm_str extends Json_itm_base {
private final Json_doc doc;
private final int src_bgn, src_end;
private String data_str;
private byte[] data_bry;
private boolean data_needs_making;
private boolean escaped;
private Json_itm_str(Json_doc doc, int src_bgn, int src_end, String data_str, boolean escaped) {
this.doc = doc;
this.src_bgn = src_bgn;
this.src_end = src_end;
this.data_str = data_str;
this.data_bry = null;
this.data_needs_making = true;
this.escaped = escaped;
}
@Override public byte Tid() {return Json_itm_.Tid__str;}
@Override public Object Data() {return this.Data_as_str();}
public void Overwrite_bry(byte[] v) {
this.data_bry = v; //needed by MapLink/MapFrame
this.data_needs_making = false;
}
@Override public byte[] Data_bry() {
if (data_bry == null) {
data_bry = Data_make_bry();
}
return data_bry;
}
public String Data_as_str() {
if (data_str == null) {
data_bry = Data_make_bry();
data_str = String_.new_u8(data_bry);
}
return data_str;
}
@Override public boolean Data_eq(byte[] comp) {
return Bry_.Match(this.Data_bry(), comp);
}
private byte[] Data_make_bry() {
// data already made; return it;
if (!data_needs_making)
return data_bry;
// mark data as made
this.data_needs_making = false;
// get src, bgn, end, depending on whether or not itm is from jdoc or standalone
byte[] src;
int bgn;
int end;
if (doc == null) {
src = Bry_.new_u8_safe(this.data_str);
bgn = 0;
end = src == null ? 0 : src.length;
}
else {
src = doc.Src();
bgn = src_bgn;
end = src_end;
}
// not escaped -> return the src
if (!escaped) {
this.data_bry = Bry_.Mid(src, bgn, end);
return data_bry;
}
// escaped; get some temp vars
Bry_bfr bfr;
byte[] utf8_bry;
if (doc == null) {
bfr = Bry_bfr_.New();
utf8_bry = new byte[6];
}
else { // PERF:reuse bfr / bry on jdoc itself
bfr = doc.Bfr();
utf8_bry = doc.Tmp_u8_bry();
}
// loop and unescape
for (int i = bgn; i < end; i++) {
byte b = src[i];
switch (b) {
case Byte_ascii.Backslash:
b = src[++i];
switch (b) { // NOTE: must properly unescape chars; EX:wd.q:2; DATE:2014-04-23
case Byte_ascii.Ltr_t: bfr.Add_byte(Byte_ascii.Tab); break;
case Byte_ascii.Ltr_n: bfr.Add_byte(Byte_ascii.Nl); break;
case Byte_ascii.Ltr_r: bfr.Add_byte(Byte_ascii.Cr); break;
case Byte_ascii.Ltr_b: bfr.Add_byte(Byte_ascii.Backfeed); break;
case Byte_ascii.Ltr_f: bfr.Add_byte(Byte_ascii.Formfeed); break;
case Byte_ascii.Ltr_u:
i += 1; // +1 to skip "u"
int utf8_val = gplx.core.encoders.Hex_utl_.Parse_or(src, i, i + 4, -1);
// check for UTF surrogate-pairs; ISSUE#:487; DATE:2019-06-02
// hi: 0xD800-0xDBFF; 55,296-56,319
if (utf8_val >= Utf16_.Surrogate_hi_bgn && utf8_val <= Utf16_.Surrogate_hi_end) {
int lo_bgn = i + 4; // +4 to skip 4 hex-dec chars
if (lo_bgn + 6 <= end // +6 to handle encoded String; EX: '\u0022'
&& src[lo_bgn] == Byte_ascii.Backslash
&& src[lo_bgn + 1] == Byte_ascii.Ltr_u) {
lo_bgn = lo_bgn + 2; // +2 to skip '\' and 'u'
int lo = gplx.core.encoders.Hex_utl_.Parse_or(src, lo_bgn, lo_bgn + 4, -1);
// lo: 0xDC00-0xDFFF; 56,320-57,343
if (lo >= Utf16_.Surrogate_lo_bgn && lo <= Utf16_.Surrogate_lo_end) {
utf8_val = Utf16_.Surrogate_merge(utf8_val, lo);
i += 6; // +6 to skip entire lo-String; EX: '\u0022'
}
}
}
int len = gplx.core.intls.Utf16_.Encode_int(utf8_val, utf8_bry, 0);
bfr.Add_mid(utf8_bry, 0, len);
i += 3; // +3 b/c for-loop will do another +1 to bring total to 4; EX: '0022'
break;
case Byte_ascii.Backslash:
case Byte_ascii.Slash:
default:
bfr.Add_byte(b); break; // \? " \ / b f n r t
}
break;
default:
bfr.Add_byte(b);
break;
}
}
this.data_bry = bfr.To_bry_and_clear();
return data_bry;
}
@Override public void Print_as_json(Bry_bfr bfr, int depth) {
bfr.Add_byte(Byte_ascii.Quote);
byte[] data_bry = this.Data_bry();
int data_len = data_bry.length;
Gfh_utl.Escape_html_to_bfr(bfr, data_bry, 0, data_len, true, true, true, true, false); // false to apos for backwards compatibility
bfr.Add_byte(Byte_ascii.Quote);
}
public static Json_itm_str NewByDoc(Json_doc doc, int src_bgn, int src_end, boolean escaped) {return new Json_itm_str(doc, src_bgn + 1, src_end - 1, null, escaped);}
public static Json_itm_str NewByVal(String val) {return new Json_itm_str(null, -1, -1, val, false);}
}

@ -1,29 +0,0 @@
/*
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.langs.jsons; import gplx.*; import gplx.langs.*;
public class Json_itm_tmp implements Json_itm { // TEST:
public Json_itm_tmp(byte tid, String data) {this.tid = tid; this.data = data;}
public byte Tid() {return tid;} private byte tid;
public byte[] Data_bry() {return Bry_.new_u8(Object_.Xto_str_strict_or_empty(data));}
public int Src_bgn() {return -1;}
public int Src_end() {return -1;}
public Object Data() {return data;} private String data;
public void Print_as_json(Bry_bfr bfr, int depth) {bfr.Add_str_u8(data);}
public boolean Data_eq(byte[] comp) {return false;}
public void Clear() {}
public static Json_itm new_str_(String v) {return new Json_itm_tmp(Json_itm_.Tid__str, "\"" + v + "\"");}
public static Json_itm new_int_(int v) {return new Json_itm_tmp(Json_itm_.Tid__int, Int_.To_str(v));}
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,25 +13,29 @@ 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.langs.jsons; import gplx.*; import gplx.langs.*;
public class Json_kv extends Json_itm_base {
public Json_kv(Json_itm key, Json_itm val) {this.key = key; this.val = val;}
@Override public byte Tid() {return Json_itm_.Tid__kv;}
public Json_itm Key() {return key;} private final Json_itm key;
public Json_itm Val() {return val;} private final Json_itm val;
public byte[] Key_as_bry() {return key.Data_bry();}
public String Key_as_str() {return (String)key.Data();}
public byte[] Val_as_bry() {return val.Data_bry();}
public Json_nde Val_as_nde() {return Json_nde.cast(val);}
public Json_ary Val_as_ary() {return Json_ary.cast(val);}
public boolean Key_eq(byte[] comp) {return ((Json_itm_str)key).Data_eq(comp);}
@Override public Object Data() {return null;}
@Override public byte[] Data_bry() {return null;}
@Override public void Print_as_json(Bry_bfr bfr, int depth) {
key.Print_as_json(bfr, depth);
bfr.Add_byte(Byte_ascii.Colon);
val.Print_as_json(bfr, depth);
}
public static final Json_kv[] Ary_empty = new Json_kv[0];
public static Json_kv cast(Json_itm v) {return v == null || v.Tid() != Json_itm_.Tid__kv ? null : (Json_kv)v;}
}
package gplx.langs.jsons;
import gplx.Bry_bfr;
import gplx.Byte_ascii;
public class Json_kv extends Json_itm_base {
public Json_kv(Json_itm key, Json_itm val) {this.key = key; this.val = val;}
@Override public byte Tid() {return Json_itm_.Tid__kv;}
public Json_itm Key() {return key;} private final Json_itm key;
public Json_itm Val() {return val;} private final Json_itm val;
public byte[] Key_as_bry() {return key.Data_bry();}
public String Key_as_str() {return (String)key.Data();}
public byte[] Val_as_bry() {return val.Data_bry();}
public Json_nde Val_as_nde() {return Json_nde.Cast(val);}
public Json_ary Val_as_ary() {return Json_ary.cast(val);}
public boolean Key_eq(byte[] comp) {return ((Json_itm_str)key).Data_eq(comp);}
@Override public Object Data() {return null;}
@Override public byte[] Data_bry() {return null;}
@Override public void Print_as_json(Bry_bfr bfr, int depth) {
key.Print_as_json(bfr, depth);
bfr.Add_byte(Byte_ascii.Colon);
val.Print_as_json(bfr, depth);
}
public static final Json_kv[] Ary_empty = new Json_kv[0];
public static Json_kv Cast(Json_itm v) {return v == null || v.Tid() != Json_itm_.Tid__kv ? null : (Json_kv)v;}
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,37 +13,42 @@ 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.langs.jsons; import gplx.*; import gplx.langs.*;
import org.junit.*;
public class Json_kv_ary_srl_tst {
@Before public void init() {fxt.Clear();} private Json_kv_ary_srl_fxt fxt = new Json_kv_ary_srl_fxt();
@Test public void Null() {fxt.Test_parse("{'k0':null}" , fxt.ary_(fxt.kv_str_("k0", null)));}
@Test public void Bool_n() {fxt.Test_parse("{'k0':false}" , fxt.ary_(fxt.kv_bool_("k0", false)));}
@Test public void Num() {fxt.Test_parse("{'k0':123}" , fxt.ary_(fxt.kv_int_("k0", 123)));}
@Test public void Num_exp() {fxt.Test_parse("{'k0':1.23e2}" , fxt.ary_(fxt.kv_int_("k0", 123)));} // exponent can be either "e" or "E" in JSON, but Java decimal parse only takes "E"; ISSUE#:565; DATE:2020-03-25
@Test public void Str() {fxt.Test_parse("{'k0':'v0'}" , fxt.ary_(fxt.kv_str_("k0", "v0")));}
@Test public void Num_dec() {fxt.Test_parse("{'k0':1.23}" , fxt.ary_(fxt.kv_dec_("k0", Decimal_adp_.parse("1.23"))));}
@Test public void Ary_int() {fxt.Test_parse("{'k0':[1,2,3]}" , fxt.ary_(fxt.kv_obj_("k0", fxt.ary_(fxt.kv_int_("1", 1), fxt.kv_int_("2", 2), fxt.kv_int_("3", 3)))));}
@Test public void Ary_empty() {fxt.Test_parse("{'k0':[]}" , fxt.ary_(fxt.kv_obj_("k0", fxt.ary_())));}
@Test public void Subs_int() {fxt.Test_parse("{'k0':{'k00':1,'k01':2}}" , fxt.ary_(fxt.kv_obj_("k0", fxt.ary_(fxt.kv_int_("k00", 1), fxt.kv_int_("k01", 2)))));}
@Test public void Subs_empty() {fxt.Test_parse("{'k0':{}}" , fxt.ary_(fxt.kv_obj_("k0", fxt.ary_())));}
}
class Json_kv_ary_srl_fxt {
public void Clear() {
if (parser == null) {
parser = new Json_parser();
}
} private Json_parser parser;
public void Test_parse(String raw_str, Keyval[] expd) {
byte[] raw_bry = Json_parser_tst.Replace_apos(Bry_.new_u8(raw_str));
Json_doc doc = parser.Parse(raw_bry);
Keyval[] actl = Json_kv_ary_srl.Val_by_itm_nde(doc.Root_nde());
Tfds.Eq_str_lines(Keyval_.Ary_to_str(expd), Keyval_.Ary_to_str(actl));
}
public Keyval[] ary_(Keyval... ary) {return ary;}
public Keyval kv_obj_(String key, Object val) {return Keyval_.new_(key, val);}
public Keyval kv_str_(String key, String val) {return Keyval_.new_(key, val);}
public Keyval kv_int_(String key, int val) {return Keyval_.new_(key, val);}
public Keyval kv_bool_(String key, boolean val) {return Keyval_.new_(key, Bool_.To_str_lower(val));}
public Keyval kv_dec_(String key, Decimal_adp val) {return Keyval_.new_(key, val.To_str());}
}
package gplx.langs.jsons;
import gplx.Bool_;
import gplx.Bry_;
import gplx.Decimal_adp;
import gplx.Decimal_adp_;
import gplx.Keyval;
import gplx.Keyval_;
import gplx.Tfds;
import org.junit.Test;
public class Json_kv_ary_srl_tst {
private final Json_kv_ary_srl_fxt fxt = new Json_kv_ary_srl_fxt();
@Test public void Null() {fxt.Test_parse("{'k0':null}" , fxt.ary_(fxt.New_kv_str("k0", null)));}
@Test public void Bool_n() {fxt.Test_parse("{'k0':false}" , fxt.ary_(fxt.New_kv_bool("k0", false)));}
@Test public void Num() {fxt.Test_parse("{'k0':123}" , fxt.ary_(fxt.New_kv_int("k0", 123)));}
@Test public void Num_exp() {fxt.Test_parse("{'k0':1.23e2}" , fxt.ary_(fxt.New_kv_int("k0", 123)));} // exponent can be either "e" or "E" in JSON, but Java decimal parse only takes "E"; ISSUE#:565; DATE:2020-03-25
@Test public void Str() {fxt.Test_parse("{'k0':'v0'}" , fxt.ary_(fxt.New_kv_str("k0", "v0")));}
@Test public void Num_dec() {fxt.Test_parse("{'k0':1.23}" , fxt.ary_(fxt.New_kv_dec("k0", Decimal_adp_.parse("1.23"))));}
@Test public void Ary_int() {fxt.Test_parse("{'k0':[1,2,3]}" , fxt.ary_(fxt.New_kv_obj("k0", fxt.ary_(fxt.New_kv_int("1", 1), fxt.New_kv_int("2", 2), fxt.New_kv_int("3", 3)))));}
@Test public void Ary_empty() {fxt.Test_parse("{'k0':[]}" , fxt.ary_(fxt.New_kv_obj("k0", fxt.ary_())));}
@Test public void Subs_int() {fxt.Test_parse("{'k0':{'k00':1,'k01':2}}" , fxt.ary_(fxt.New_kv_obj("k0", fxt.ary_(fxt.New_kv_int("k00", 1), fxt.New_kv_int("k01", 2)))));}
@Test public void Subs_empty() {fxt.Test_parse("{'k0':{}}" , fxt.ary_(fxt.New_kv_obj("k0", fxt.ary_())));}
}
class Json_kv_ary_srl_fxt {
private final Json_parser parser = new Json_parser();
public void Test_parse(String raw_str, Keyval[] expd) {
byte[] raw_bry = Bry_.new_u8(Json_doc.Make_str_by_apos(raw_str));
Json_doc doc = parser.Parse(raw_bry);
Keyval[] actl = Json_kv_ary_srl.Val_by_itm_nde(doc.Root_nde());
Tfds.Eq_str_lines(Keyval_.Ary_to_str(expd), Keyval_.Ary_to_str(actl));
}
public Keyval[] ary_(Keyval... ary) {return ary;}
public Keyval New_kv_obj(String key, Object val) {return Keyval_.new_(key, val);}
public Keyval New_kv_str(String key, String val) {return Keyval_.new_(key, val);}
public Keyval New_kv_int(String key, int val) {return Keyval_.new_(key, val);}
public Keyval New_kv_bool(String key, boolean val) {return Keyval_.new_(key, Bool_.To_str_lower(val));}
public Keyval New_kv_dec(String key, Decimal_adp val) {return Keyval_.new_(key, val.To_str());}
}

@ -1,191 +1,217 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2020 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.langs.jsons;
import gplx.Array_;
import gplx.Bool_;
import gplx.Bry_;
import gplx.Bry_bfr;
import gplx.Byte_ascii;
import gplx.DateAdp;
import gplx.DateAdp_;
import gplx.Err_;
import gplx.Hash_adp_bry;
import gplx.Int_;
import gplx.Long_;
import gplx.String_;
public class Json_nde extends Json_itm_base implements Json_grp {
private Json_itm[] subs = Json_itm_.Ary_empty; private int subs_len = 0, subs_max = 0;
private Hash_adp_bry subs_hash;
public Json_nde(Json_doc jdoc, int src_bgn) {this.jdoc = jdoc; this.Ctor(src_bgn, -1);}
@Override public byte Tid() {return Json_itm_.Tid__nde;}
public Json_doc Doc() {return jdoc;} private final Json_doc jdoc;
public void Src_end_(int v) {this.src_end = v;}
@Override public Object Data() {return null;}
@Override public byte[] Data_bry() {return null;}
public int Len() {return subs_len;}
public Json_itm Get_at(int i) {return subs[i];}
public Json_itm Get_as_itm_or_null(String key) {return Get_as_itm_or_null(Bry_.new_u8(key));}
public Json_itm Get_as_itm_or_null(byte[] key) {if (subs_hash == null) subs_hash = subs_hash_init(); return (Json_itm)subs_hash.Get_by_bry(key);}
public Json_ary Get_as_ary(int idx) {return Json_ary.cast(Get_at(idx));}
public Json_nde Get_as_nde(String key) {return Json_nde.cast(Get_as_itm_or_null(Bry_.new_u8(key)));}
public Json_nde Get_as_nde(int idx) {return Json_nde.cast(Get_at(idx));}
public Json_ary Get_as_ary(String key) {return Get_as_ary(Bry_.new_u8(key));}
public Json_ary Get_as_ary(byte[] key) {
Json_itm rv = Get_as_itm_or_null(key); if (rv == null) throw Err_.new_("json", "key missing", "key", key);
return Json_ary.cast(rv);
}
public Json_ary Get_as_ary_or_null(String key) {return Get_as_ary_or_null(Bry_.new_u8(key));}
public Json_ary Get_as_ary_or_null(byte[] key) {
Json_itm rv = Get_as_itm_or_null(key);
return rv == null
? null
: Json_ary.cast(rv);
}
public byte[] Get_as_bry(String key) {
byte[] rv = Get_as_bry_or(Bry_.new_u8(key), null); if (rv == null) throw Err_.new_("json", "key missing", "key", key);
return rv;
}
public byte[] Get_as_bry_or(byte[] key, byte[] or) {
Json_itm rv = Get_as_itm_or_null(key);
return rv == null ? or : rv.Data_bry();
}
public String Get_as_str(String key) {
String rv = Get_as_str_or(key, null); if (rv == null) throw Err_.new_("json", "key missing", "key", key);
return rv;
}
public String Get_as_str_or(String key, String or) {return Get_as_str_or(Bry_.new_u8(key), or);}
public String Get_as_str_or(byte[] key, String or) {
byte[] rv = Get_as_bry_or(key, null);
return rv == null ? or : String_.new_u8(rv);
}
public int Get_as_int(String key) {
int rv = Get_as_int_or(key, Int_.Min_value); if (rv == Int_.Min_value) throw Err_.new_("json", "key missing", "key", key);
return rv;
}
public int Get_as_int_or(String key, int or) {return Get_as_int_or(Bry_.new_u8(key), or);}
public int Get_as_int_or(byte[] key, int or) {
byte[] rv = Get_as_bry_or(key, null);
return rv == null ? or : Bry_.To_int(rv);
}
public long Get_as_long(String key) {
long rv = Get_as_long_or(key, Long_.Min_value); if (rv == Long_.Min_value) throw Err_.new_("json", "key missing", "key", key);
return rv;
}
public long Get_as_long_or(String key, long or) {return Get_as_long_or(Bry_.new_u8(key), or);}
public long Get_as_long_or(byte[] key, long or) {
byte[] rv = Get_as_bry_or(key, null);
return rv == null ? or : Bry_.To_long_or(rv, or);
}
public boolean Get_as_bool_or(String key, boolean or) {return Get_as_bool_or(Bry_.new_u8(key), or);}
public boolean Get_as_bool_or(byte[] key, boolean or) {
byte[] rv = Get_as_bry_or(key, null);
return rv == null ? or : Bry_.Eq(rv, Bool_.True_bry);
}
public DateAdp Get_as_date_by_utc(String key) {
byte[] rv = Get_as_bry_or(Bry_.new_u8(key), null); if (rv == null) throw Err_.new_("json", "key missing", "key", key);
return DateAdp_.parse_gplx(String_.new_u8(rv));
}
// to convert
public boolean Has(byte[] key) {return Get_bry(key, null) != null;}
public Json_kv Get_at_as_kv(int i) {
Json_itm rv_itm = Get_at(i);
Json_kv rv = Json_kv.cast(rv_itm); if (rv == null) throw Err_.new_("json", "sub is not kv", "i", i, "src", Bry_.Mid(jdoc.Src(), this.Src_bgn(), src_end));
return rv;
}
public Json_kv Get_kv(byte[] key) {return Json_kv.cast(Get_itm(key));}
public Json_nde Get(String key) {return Get(Bry_.new_u8(key));}
public Json_nde Get(byte[] key) {
Json_kv kv = Json_kv.cast(this.Get_itm(key)); if (kv == null) throw Err_.new_("json", "kv not found", "key", key);
Json_nde rv = Json_nde.cast(kv.Val()); if (rv == null) throw Err_.new_("json", "nde not found", "key", key);
return rv;
}
public Json_itm Get_itm(byte[] key) {
for (int i = 0; i < subs_len; i++) {
Json_itm itm = subs[i];
if (itm.Tid() == Json_itm_.Tid__kv) {
Json_kv itm_as_kv = (Json_kv)itm;
if (Bry_.Eq(key, itm_as_kv.Key().Data_bry()))
return itm;
}
}
return null;
}
public Json_ary Get_ary(String key) {return Get_ary(Bry_.new_u8(key));}
public Json_ary Get_ary(byte[] key) {return Json_ary.cast(Get_kv(key).Val_as_ary());}
public String Get_str(String key) {return String_.new_u8(Get_bry(Bry_.new_u8(key)));}
public byte[] Get_bry(byte[] key) {
byte[] rv = Get_bry(key, null); if (rv == null) throw Err_.new_("json", "key missing", "key", key);
return rv;
}
public byte[] Get_bry_or_null(String key) {return Get_bry(Bry_.new_u8(key), null);}
public byte[] Get_bry_or_null(byte[] key) {return Get_bry(key, null);}
public byte[] Get_bry(byte[] key, byte[] or) {
Json_itm kv_obj = Get_itm(key);
if (kv_obj == null) return or; // key not found;
if (kv_obj.Tid() != Json_itm_.Tid__kv) return or; // key is not a key_val
Json_kv kv = (Json_kv)kv_obj;
Json_itm val = kv.Val();
return (val == null) ? or : val.Data_bry();
}
public Json_nde Add_many(Json_itm... ary) {
int len = ary.length;
for (int i = 0; i < len; i++)
Add(ary[i]);
return this;
}
public void Add(Json_itm itm) {
int new_len = subs_len + 1;
if (new_len > subs_max) { // ary too small >>> expand
subs_max = new_len * 2;
Json_itm[] new_subs = new Json_itm[subs_max];
Array_.Copy_to(subs, 0, new_subs, 0, subs_len);
subs = new_subs;
}
subs[subs_len] = (Json_itm)itm;
subs_len = new_len;
subs_hash = null;
}
@Override public void Print_as_json(Bry_bfr bfr, int depth) {
if (bfr.Len() != 0) bfr.Add_byte_nl();
Json_grp_.Print_indent(bfr, depth);
bfr.Add_byte(Byte_ascii.Curly_bgn).Add_byte(Byte_ascii.Space);
for (int i = 0; i < subs_len; i++) {
if (i != 0) {
Json_grp_.Print_nl(bfr); Json_grp_.Print_indent(bfr, depth);
bfr.Add_byte(Byte_ascii.Comma).Add_byte(Byte_ascii.Space);
}
subs[i].Print_as_json(bfr, depth + 1);
}
Json_grp_.Print_nl(bfr); Json_grp_.Print_indent(bfr, depth);
bfr.Add_byte(Byte_ascii.Curly_end).Add_byte_nl();
}
private Hash_adp_bry subs_hash_init() {
Hash_adp_bry rv = Hash_adp_bry.cs();
for (int i = 0; i < subs_len; ++i) {
Json_itm itm = subs[i];
if (itm.Tid() == Json_itm_.Tid__kv) {
Json_kv itm_as_kv = (Json_kv)itm;
rv.Add(itm_as_kv.Key().Data_bry(), itm_as_kv.Val());
}
}
return rv;
}
public static Json_nde cast(Json_itm v) {return v == null || v.Tid() != Json_itm_.Tid__nde ? null : (Json_nde)v;}
}
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2020 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.langs.jsons;
import gplx.Array_;
import gplx.Bool_;
import gplx.Bry_;
import gplx.Bry_bfr;
import gplx.Byte_ascii;
import gplx.DateAdp;
import gplx.DateAdp_;
import gplx.Decimal_adp_;
import gplx.Err_;
import gplx.Hash_adp_bry;
import gplx.Int_;
import gplx.Long_;
import gplx.String_;
public class Json_nde extends Json_itm_base implements Json_grp {
private final int src_bgn;
private int src_end;
private Json_itm[] subs = Json_itm_.Ary_empty;
private int subs_len = 0, subs_max = 0;
private Hash_adp_bry subs_hash;
private Json_nde(Json_doc jdoc, int src_bgn) {
this.jdoc = jdoc;
this.src_bgn = src_bgn;
}
@Override public byte Tid() {return Json_itm_.Tid__nde;}
public Json_doc Doc() {return jdoc;} private final Json_doc jdoc;
public void Src_end_(int v) {this.src_end = v;}
@Override public Object Data() {return null;}
@Override public byte[] Data_bry() {return null;}
public int Len() {return subs_len;}
public Json_itm Get_at(int i) {return subs[i];}
public Json_itm Get_as_itm_or_null(String key) {return Get_as_itm_or_null(Bry_.new_u8(key));}
public Json_itm Get_as_itm_or_null(byte[] key) {if (subs_hash == null) subs_hash = subs_hash_init(); return (Json_itm)subs_hash.Get_by_bry(key);}
public Json_ary Get_as_ary(int idx) {return Json_ary.cast(Get_at(idx));}
public Json_nde Get_as_nde(String key) {return Json_nde.Cast(Get_as_itm_or_null(Bry_.new_u8(key)));}
public Json_nde Get_as_nde(int idx) {return Json_nde.Cast(Get_at(idx));}
public Json_ary Get_as_ary(String key) {return Get_as_ary(Bry_.new_u8(key));}
public Json_ary Get_as_ary(byte[] key) {
Json_itm rv = Get_as_itm_or_null(key); if (rv == null) throw Err_.new_("json", "key missing", "key", key);
return Json_ary.cast(rv);
}
public Json_ary Get_as_ary_or_null(String key) {return Get_as_ary_or_null(Bry_.new_u8(key));}
public Json_ary Get_as_ary_or_null(byte[] key) {
Json_itm rv = Get_as_itm_or_null(key);
return rv == null
? null
: Json_ary.cast(rv);
}
public byte[] Get_as_bry(String key) {
byte[] rv = Get_as_bry_or(Bry_.new_u8(key), null); if (rv == null) throw Err_.new_("json", "key missing", "key", key);
return rv;
}
public byte[] Get_as_bry_or(byte[] key, byte[] or) {
Json_itm rv = Get_as_itm_or_null(key);
return rv == null ? or : rv.Data_bry();
}
public String Get_as_str(String key) {
String rv = Get_as_str_or(key, null); if (rv == null) throw Err_.new_("json", "key missing", "key", key);
return rv;
}
public String Get_as_str_or(String key, String or) {return Get_as_str_or(Bry_.new_u8(key), or);}
public String Get_as_str_or(byte[] key, String or) {
byte[] rv = Get_as_bry_or(key, null);
return rv == null ? or : String_.new_u8(rv);
}
public int Get_as_int(String key) {
int rv = Get_as_int_or(key, Int_.Min_value); if (rv == Int_.Min_value) throw Err_.new_("json", "key missing", "key", key);
return rv;
}
public int Get_as_int_or(String key, int or) {return Get_as_int_or(Bry_.new_u8(key), or);}
public int Get_as_int_or(byte[] key, int or) {
byte[] rv = Get_as_bry_or(key, null);
return rv == null ? or : Bry_.To_int(rv);
}
public long Get_as_long(String key) {
long rv = Get_as_long_or(key, Long_.Min_value); if (rv == Long_.Min_value) throw Err_.new_("json", "key missing", "key", key);
return rv;
}
public long Get_as_long_or(String key, long or) {return Get_as_long_or(Bry_.new_u8(key), or);}
public long Get_as_long_or(byte[] key, long or) {
byte[] rv = Get_as_bry_or(key, null);
return rv == null ? or : Bry_.To_long_or(rv, or);
}
public boolean Get_as_bool_or(String key, boolean or) {return Get_as_bool_or(Bry_.new_u8(key), or);}
public boolean Get_as_bool_or(byte[] key, boolean or) {
byte[] rv = Get_as_bry_or(key, null);
return rv == null ? or : Bry_.Eq(rv, Bool_.True_bry);
}
public DateAdp Get_as_date_by_utc(String key) {
byte[] rv = Get_as_bry_or(Bry_.new_u8(key), null); if (rv == null) throw Err_.new_("json", "key missing", "key", key);
return DateAdp_.parse_gplx(String_.new_u8(rv));
}
// to convert
public boolean Has(byte[] key) {return Get_bry(key, null) != null;}
public Json_kv Get_at_as_kv(int i) {
Json_itm rv_itm = Get_at(i);
Json_kv rv = Json_kv.Cast(rv_itm);
if (rv == null) {
byte[] snip = jdoc == null ? Bry_.new_a7("no source") : Bry_.Mid(jdoc.Src(), src_bgn, src_end);
throw Err_.new_("json", "sub is not kv", "i", i, "src", snip);
}
return rv;
}
public Json_kv Get_kv(byte[] key) {return Json_kv.Cast(Get_itm(key));}
public Json_nde Get(String key) {return Get(Bry_.new_u8(key));}
public Json_nde Get(byte[] key) {
Json_kv kv = Json_kv.Cast(this.Get_itm(key)); if (kv == null) throw Err_.new_("json", "kv not found", "key", key);
Json_nde rv = Json_nde.Cast(kv.Val()); if (rv == null) throw Err_.new_("json", "nde not found", "key", key);
return rv;
}
public Json_itm Get_itm(byte[] key) {
for (int i = 0; i < subs_len; i++) {
Json_itm itm = subs[i];
if (itm != null && itm.Tid() == Json_itm_.Tid__kv) {
Json_kv itm_as_kv = (Json_kv)itm;
if (Bry_.Eq(key, itm_as_kv.Key().Data_bry()))
return itm;
}
}
return null;
}
public Json_ary Get_ary(String key) {return Get_ary(Bry_.new_u8(key));}
public Json_ary Get_ary(byte[] key) {return Json_ary.cast(Get_kv(key).Val_as_ary());}
public String Get_str(String key) {return String_.new_u8(Get_bry(Bry_.new_u8(key)));}
public byte[] Get_bry(byte[] key) {
byte[] rv = Get_bry(key, null); if (rv == null) throw Err_.new_("json", "key missing", "key", key);
return rv;
}
public byte[] Get_bry_or_null(String key) {return Get_bry(Bry_.new_u8(key), null);}
public byte[] Get_bry_or_null(byte[] key) {return Get_bry(key, null);}
public byte[] Get_bry(byte[] key, byte[] or) {
Json_itm kv_obj = Get_itm(key);
if (kv_obj == null) return or; // key not found;
if (kv_obj.Tid() != Json_itm_.Tid__kv) return or; // key is not a key_val
Json_kv kv = (Json_kv)kv_obj;
Json_itm val = kv.Val();
return (val == null) ? or : val.Data_bry();
}
public void AddKvBool(String key, boolean val) {AddKv(key, Json_itm_bool.Get(val));}
public void AddKvInt(String key, int val) {AddKv(key, Json_itm_int.NewByVal(val));}
public void AddKvDouble(String key, double val) {AddKv(key, Json_itm_decimal.NewByVal(Decimal_adp_.double_(val)));}
public void AddKvStr(String key, byte[] val) {AddKv(key, Json_itm_str.NewByVal(String_.new_u8(val)));}
public void AddKvStr(String key, String val) {AddKv(key, Json_itm_str.NewByVal(val));}
public void AddKvNde(String key, Json_nde val) {AddKv(key, val);}
public void AddKvAry(String key, Json_ary val) {AddKv(key, val);}
private void AddKv(String key, Json_itm val) {
Json_kv rv = new Json_kv(Json_itm_str.NewByVal(key), val);
Add(rv);
}
public Json_nde Add_many(Json_itm... ary) {
int len = ary.length;
for (int i = 0; i < len; i++)
Add(ary[i]);
return this;
}
public void Add(Json_itm itm) {
int new_len = subs_len + 1;
if (new_len > subs_max) { // ary too small >>> expand
subs_max = new_len * 2;
Json_itm[] new_subs = new Json_itm[subs_max];
Array_.Copy_to(subs, 0, new_subs, 0, subs_len);
subs = new_subs;
}
subs[subs_len] = (Json_itm)itm;
subs_len = new_len;
subs_hash = null;
}
@Override public void Print_as_json(Bry_bfr bfr, int depth) {
if (bfr.Len() != 0) bfr.Add_byte_nl();
Json_grp_.Print_indent(bfr, depth);
bfr.Add_byte(Byte_ascii.Curly_bgn).Add_byte(Byte_ascii.Space);
for (int i = 0; i < subs_len; i++) {
if (i != 0) {
Json_grp_.Print_nl(bfr); Json_grp_.Print_indent(bfr, depth);
bfr.Add_byte(Byte_ascii.Comma).Add_byte(Byte_ascii.Space);
}
subs[i].Print_as_json(bfr, depth + 1);
}
Json_grp_.Print_nl(bfr); Json_grp_.Print_indent(bfr, depth);
bfr.Add_byte(Byte_ascii.Curly_end).Add_byte_nl();
}
private Hash_adp_bry subs_hash_init() {
Hash_adp_bry rv = Hash_adp_bry.cs();
for (int i = 0; i < subs_len; ++i) {
Json_itm itm = subs[i];
if (itm.Tid() == Json_itm_.Tid__kv) {
Json_kv itm_as_kv = (Json_kv)itm;
rv.Add(itm_as_kv.Key().Data_bry(), itm_as_kv.Val());
}
}
return rv;
}
public static Json_nde NewByDoc(Json_doc doc, int src_bgn) {return new Json_nde(doc, src_bgn);}
public static Json_nde NewByVal() {return new Json_nde(null, -1);}
public static Json_nde Cast(Json_itm v) {return v == null || v.Tid() != Json_itm_.Tid__nde ? null : (Json_nde)v;}
}

@ -1,198 +1,197 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2020 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.langs.jsons;
import gplx.Bool_;
import gplx.Bry_;
import gplx.Byte_ascii;
import gplx.Char_;
import gplx.Err;
import gplx.Err_;
import gplx.Int_;
import gplx.String_;
import gplx.core.primitives.Gfo_number_parser;
public class Json_parser {
private byte[] src; private int src_len, pos; private final Gfo_number_parser num_parser = new Gfo_number_parser();
public Json_factory Factory() {return factory;} private final Json_factory factory = new Json_factory();
public Json_doc Parse_by_apos_ary(String... ary) {return Parse_by_apos(String_.Concat_lines_nl(ary));}
public Json_doc Parse_by_apos(String s) {return Parse(Bry_.Replace(Bry_.new_u8(s), Byte_ascii.Apos, Byte_ascii.Quote));}
public Json_doc Parse(String src) {return Parse(Bry_.new_u8(src));}
public Json_doc Parse(byte[] src) {
synchronized (factory) {
this.src = src; if (src == null) return null;
this.src_len = src.length; if (src_len == 0) return null;
this.pos = 0;
Skip_ws();
boolean root_is_nde = true;
switch (src[pos]) {
case Byte_ascii.Curly_bgn: root_is_nde = Bool_.Y; break;
case Byte_ascii.Brack_bgn: root_is_nde = Bool_.N; break;
default: return null;
}
Skip_ws();
Json_doc doc = new Json_doc();
Json_grp root = null;
if (root_is_nde)
root = Make_nde(doc);
else
root = Make_ary(doc);
doc.Ctor(src, root);
return doc;
}
}
private Json_nde Make_nde(Json_doc doc) {
++pos; // brack_bgn
Json_nde nde = new Json_nde(doc, pos);
while (pos < src_len) {
Skip_ws();
if (src[pos] == Byte_ascii.Curly_end) {++pos; return nde;}
else nde.Add(Make_kv(doc));
Skip_ws();
switch (src[pos++]) {
case Byte_ascii.Comma: break;
case Byte_ascii.Curly_end: return nde;
default: throw Err_.new_unhandled(src[pos - 1]);
}
}
throw Err_.new_wo_type("eos inside nde");
}
private Json_itm Make_kv(Json_doc doc) {
Json_itm key = Make_string(doc);
Skip_ws();
Chk(Byte_ascii.Colon);
Skip_ws();
Json_itm val = Make_val(doc);
return new Json_kv(key, val);
}
private Json_itm Make_val(Json_doc doc) {
while (pos < src_len) {
byte b = src[pos];
switch (b) {
case Byte_ascii.Ltr_n: return Make_literal(Bry_null_ull , 3, factory.Null());
case Byte_ascii.Ltr_f: return Make_literal(Bry_bool_alse , 4, factory.Bool_n());
case Byte_ascii.Ltr_t: return Make_literal(Bry_bool_rue , 3, factory.Bool_y());
case Byte_ascii.Quote: return Make_string(doc);
case Byte_ascii.Num_0: case Byte_ascii.Num_1: case Byte_ascii.Num_2: case Byte_ascii.Num_3: case Byte_ascii.Num_4:
case Byte_ascii.Num_5: case Byte_ascii.Num_6: case Byte_ascii.Num_7: case Byte_ascii.Num_8: case Byte_ascii.Num_9:
case Byte_ascii.Dash: return Make_num(doc);
case Byte_ascii.Brack_bgn: return Make_ary(doc);
case Byte_ascii.Curly_bgn: return Make_nde(doc);
}
throw Err_.new_unhandled(Char_.To_str(b));
}
throw Err_.new_wo_type("eos reached in val");
}
private Json_itm Make_literal(byte[] remainder, int remainder_len, Json_itm singleton) {
++pos; // 1st char
int literal_end = pos + remainder_len;
if (Bry_.Eq(src, pos, literal_end, remainder)) {
pos = literal_end;
return singleton;
}
throw Err_.new_("json.parser", "invalid literal", "excerpt", Bry_.Mid_by_len_safe(src, pos - 1, 16));
}
private Json_itm Make_string(Json_doc doc) {
int bgn = pos++; // ++: quote_bgn
boolean exact = true;
while (pos < src_len) {
switch (src[pos]) {
case Byte_ascii.Backslash:
++pos; // backslash
switch (src[pos]) {
case Byte_ascii.Ltr_u: pos += 5; break; // \uFFFF 1 u + 4 hex-dec; ISSUE#:486; DATE:2019-06-02
default: ++pos; break; // \? " \ / b f n r t
}
exact = false;
break;
case Byte_ascii.Quote:
return factory.Str(doc, bgn, ++pos, exact); // ++: quote_end
default:
++pos;
break;
}
}
throw Err_.new_wo_type("eos reached inside quote");
}
private Json_itm Make_num(Json_doc doc) {
int num_bgn = pos;
boolean loop = true;
while (loop) {
if (pos == src_len) throw Err_.new_wo_type("eos reached inside num");
switch (src[pos]) {
case Byte_ascii.Num_0: case Byte_ascii.Num_1: case Byte_ascii.Num_2: case Byte_ascii.Num_3: case Byte_ascii.Num_4:
case Byte_ascii.Num_5: case Byte_ascii.Num_6: case Byte_ascii.Num_7: case Byte_ascii.Num_8: case Byte_ascii.Num_9:
++pos;
break;
case Byte_ascii.Dot:
case Byte_ascii.Dash: case Byte_ascii.Plus:
case Byte_ascii.Ltr_E: case Byte_ascii.Ltr_e: // e e+ e- E E+ E-
++pos;
break;
default:
loop = false;
break;
}
}
num_parser.Parse(src, num_bgn, pos);
if (num_parser.Has_frac())
return factory.Decimal(doc, num_bgn, pos);
else {
if (num_parser.Is_int())
return factory.Int(doc, num_bgn, pos);
else
return factory.Long(doc, num_bgn, pos);
}
}
private Json_ary Make_ary(Json_doc doc) {
Json_ary rv = factory.Ary(pos++, pos); // brack_bgn
while (pos < src_len) {
Skip_ws();
if (src[pos] == Byte_ascii.Brack_end) {++pos; return rv;}
else rv.Add(Make_val(doc));
Skip_ws();
switch (src[pos]) {
case Byte_ascii.Comma: ++pos; break;
case Byte_ascii.Brack_end: ++pos; return rv;
}
}
throw Err_.new_wo_type("eos inside ary");
}
private void Skip_ws() {
while (pos < src_len) {
switch (src[pos]) {
case Byte_ascii.Space: case Byte_ascii.Nl: case Byte_ascii.Tab: case Byte_ascii.Cr: ++pos; break;
default: return;
}
}
}
private void Chk(byte expd) {
if (src[pos] == expd)
++pos;
else
throw err_(src, pos, "expected '{0}' but got '{1}'", Char_.To_str(expd), Char_.To_str(src[pos]));
}
private Err err_(byte[] src, int bgn, String fmt, Object... args) {return err_(src, bgn, src.length, fmt, args);}
private Err err_(byte[] src, int bgn, int src_len, String fmt, Object... args) {
String msg = String_.Format(fmt, args) + " " + Int_.To_str(bgn) + " " + String_.new_u8__by_len(src, bgn, 20);
return Err_.new_wo_type(msg);
}
private static final byte[] Bry_bool_rue = Bry_.new_a7("rue"), Bry_bool_alse = Bry_.new_a7("alse"), Bry_null_ull = Bry_.new_a7("ull");
public static Json_doc ParseToJdoc(String src) {
Json_parser parser = new Json_parser();
return parser.Parse(src);
}
}
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2020 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.langs.jsons;
import gplx.Bool_;
import gplx.Bry_;
import gplx.Byte_ascii;
import gplx.Char_;
import gplx.Err;
import gplx.Err_;
import gplx.Int_;
import gplx.String_;
import gplx.core.primitives.Gfo_number_parser;
public class Json_parser {
private byte[] src;
private int src_len, pos;
private final Gfo_number_parser num_parser = new Gfo_number_parser();
public Json_doc Parse_by_apos_ary(String... ary) {return Parse_by_apos(String_.Concat_lines_nl(ary));}
public Json_doc Parse_by_apos(String s) {return Parse(Bry_.Replace(Bry_.new_u8(s), Byte_ascii.Apos, Byte_ascii.Quote));}
public Json_doc Parse(String src) {return Parse(Bry_.new_u8(src));}
public Json_doc Parse(byte[] src) {
this.src = src; if (src == null) return null;
this.src_len = src.length; if (src_len == 0) return null;
this.pos = 0;
Skip_ws();
boolean root_is_nde = true;
switch (src[pos]) {
case Byte_ascii.Curly_bgn: root_is_nde = Bool_.Y; break;
case Byte_ascii.Brack_bgn: root_is_nde = Bool_.N; break;
default: return null;
}
Skip_ws();
Json_doc doc = new Json_doc();
Json_grp root = null;
if (root_is_nde)
root = Make_nde(doc);
else
root = Make_ary(doc);
doc.Ctor(src, root);
return doc;
}
private Json_nde Make_nde(Json_doc doc) {
++pos; // brack_bgn
Json_nde nde = Json_nde.NewByDoc(doc, pos);
while (pos < src_len) {
Skip_ws();
if (src[pos] == Byte_ascii.Curly_end) {++pos; return nde;}
else nde.Add(Make_kv(doc));
Skip_ws();
switch (src[pos++]) {
case Byte_ascii.Comma: break;
case Byte_ascii.Curly_end: return nde;
default: throw Err_.new_unhandled(src[pos - 1]);
}
}
throw Err_.new_wo_type("eos inside nde");
}
private Json_itm Make_kv(Json_doc doc) {
Json_itm key = Make_string(doc);
Skip_ws();
Chk(Byte_ascii.Colon);
Skip_ws();
Json_itm val = Make_val(doc);
return new Json_kv(key, val);
}
private Json_itm Make_val(Json_doc doc) {
while (pos < src_len) {
byte b = src[pos];
switch (b) {
case Byte_ascii.Ltr_n: return Make_literal(Bry_null_ull , 3, Json_itm_null.Null);
case Byte_ascii.Ltr_f: return Make_literal(Bry_bool_alse , 4, Json_itm_bool.Bool_n);
case Byte_ascii.Ltr_t: return Make_literal(Bry_bool_rue , 3, Json_itm_bool.Bool_y);
case Byte_ascii.Quote: return Make_string(doc);
case Byte_ascii.Num_0: case Byte_ascii.Num_1: case Byte_ascii.Num_2: case Byte_ascii.Num_3: case Byte_ascii.Num_4:
case Byte_ascii.Num_5: case Byte_ascii.Num_6: case Byte_ascii.Num_7: case Byte_ascii.Num_8: case Byte_ascii.Num_9:
case Byte_ascii.Dash: return Make_num(doc);
case Byte_ascii.Brack_bgn: return Make_ary(doc);
case Byte_ascii.Curly_bgn: return Make_nde(doc);
}
throw Err_.new_unhandled(Char_.To_str(b));
}
throw Err_.new_wo_type("eos reached in val");
}
private Json_itm Make_literal(byte[] remainder, int remainder_len, Json_itm singleton) {
++pos; // 1st char
int literal_end = pos + remainder_len;
if (Bry_.Eq(src, pos, literal_end, remainder)) {
pos = literal_end;
return singleton;
}
throw Err_.new_("json.parser", "invalid literal", "excerpt", Bry_.Mid_by_len_safe(src, pos - 1, 16));
}
private Json_itm Make_string(Json_doc doc) {
int bgn = pos++; // ++: quote_bgn
boolean escaped = false;
while (pos < src_len) {
switch (src[pos]) {
case Byte_ascii.Backslash:
++pos; // backslash
switch (src[pos]) {
case Byte_ascii.Ltr_u: pos += 5; break; // \uFFFF 1 u + 4 hex-dec; ISSUE#:486; DATE:2019-06-02
default: ++pos; break; // \? " \ / b f n r t
}
escaped = true;
break;
case Byte_ascii.Quote:
return Json_itm_str.NewByDoc(doc, bgn, ++pos, escaped); // ++: quote_end
default:
++pos;
break;
}
}
throw Err_.new_wo_type("eos reached inside quote");
}
private Json_itm Make_num(Json_doc doc) {
int num_bgn = pos;
boolean loop = true;
while (loop) {
if (pos == src_len) throw Err_.new_wo_type("eos reached inside num");
switch (src[pos]) {
case Byte_ascii.Num_0: case Byte_ascii.Num_1: case Byte_ascii.Num_2: case Byte_ascii.Num_3: case Byte_ascii.Num_4:
case Byte_ascii.Num_5: case Byte_ascii.Num_6: case Byte_ascii.Num_7: case Byte_ascii.Num_8: case Byte_ascii.Num_9:
++pos;
break;
case Byte_ascii.Dot:
case Byte_ascii.Dash: case Byte_ascii.Plus:
case Byte_ascii.Ltr_E: case Byte_ascii.Ltr_e: // e e+ e- E E+ E-
++pos;
break;
default:
loop = false;
break;
}
}
num_parser.Parse(src, num_bgn, pos);
if (num_parser.Has_frac())
return Json_itm_decimal.NewByDoc(doc, num_bgn, pos);
else {
if (num_parser.Is_int())
return Json_itm_int.NewByDoc(doc, num_bgn, pos);
else
return Json_itm_long.NewByDoc(doc, num_bgn, pos);
}
}
private Json_ary Make_ary(Json_doc doc) {
Json_ary rv = Json_ary.NewByDoc(doc, pos++, pos); // brack_bgn
while (pos < src_len) {
Skip_ws();
if (src[pos] == Byte_ascii.Brack_end) {++pos; return rv;}
else rv.Add(Make_val(doc));
Skip_ws();
switch (src[pos]) {
case Byte_ascii.Comma: ++pos; break;
case Byte_ascii.Brack_end: ++pos; return rv;
}
}
throw Err_.new_wo_type("eos inside ary");
}
private void Skip_ws() {
while (pos < src_len) {
switch (src[pos]) {
case Byte_ascii.Space: case Byte_ascii.Nl: case Byte_ascii.Tab: case Byte_ascii.Cr: ++pos; break;
default: return;
}
}
}
private void Chk(byte expd) {
if (src[pos] == expd)
++pos;
else
throw err_(src, pos, "expected '{0}' but got '{1}'", Char_.To_str(expd), Char_.To_str(src[pos]));
}
private Err err_(byte[] src, int bgn, String fmt, Object... args) {return err_(src, bgn, src.length, fmt, args);}
private Err err_(byte[] src, int bgn, int src_len, String fmt, Object... args) {
String msg = String_.Format(fmt, args) + " " + Int_.To_str(bgn) + " " + String_.new_u8__by_len(src, bgn, 20);
return Err_.new_wo_type(msg);
}
private static final byte[] Bry_bool_rue = Bry_.new_a7("rue"), Bry_bool_alse = Bry_.new_a7("alse"), Bry_null_ull = Bry_.new_a7("ull");
public static Json_doc ParseToJdoc(String src) {
Json_parser parser = new Json_parser();
return parser.Parse(src);
}
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,56 +13,61 @@ 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.langs.jsons; import gplx.*; import gplx.langs.*;
import gplx.core.primitives.*;
public class Json_parser__list_nde__base extends Json_parser__itm__base {
public void Parse_grp(String context, Json_grp grp) {
this.context = context;
int len = grp.Len();
for (int i = 0; i < len; ++i) {
Json_nde sub = null;
if (grp.Tid() == Json_itm_.Tid__nde) {
Json_kv kv = Json_nde.cast(grp).Get_at_as_kv(i);
sub = kv.Val_as_nde();
}
else {
sub = Json_nde.cast(grp.Get_at(i));
}
Parse_nde(context, sub);
}
}
public void Parse_nde(String context, Json_nde nde) {
this.cur_itm = nde;
for (int j = 0; j < keys_len; ++j)
atrs[j] = null;
int atr_len = nde.Len();
for (int j = 0; j < atr_len; ++j) {
Json_kv atr = nde.Get_at_as_kv(j);
Object idx_obj = hash.Get_by_bry(atr.Key_as_bry());
if (idx_obj == null) {Warn("unknown json parser key", atr); continue;}
int idx_int = ((Int_obj_val)idx_obj).Val();
atrs[idx_int] = atr;
}
Parse_hook_nde(nde, atrs);
}
public void Parse_to_list_as_bry(String context, Json_ary ary, Ordered_hash list) {
this.cur_itm = ary;
int len = ary.Len();
for (int i = 0; i < len; ++i) {
byte[] val = ary.Get_at(i).Data_bry();
list.Add(val, val);
}
}
public void Parse_to_list_as_kv(String context, Json_nde nde, Ordered_hash list) {
this.cur_itm = nde;
int len = nde.Len();
for (int i = 0; i < len; ++i) {
Json_kv sub = nde.Get_at_as_kv(i);
byte[] key = sub.Key_as_bry();
byte[] val = Parse_to_list_as_kv__get_val(sub, key);
list.Add(key, Keyval_.new_(String_.new_u8(key), String_.new_u8(val)));
}
}
@gplx.Virtual protected byte[] Parse_to_list_as_kv__get_val(Json_kv sub, byte[] key) {return sub.Val_as_bry();}
@Override protected void Parse_hook_nde(Json_nde sub, Json_kv[] atrs) {}
}
package gplx.langs.jsons;
import gplx.Keyval_;
import gplx.Ordered_hash;
import gplx.String_;
import gplx.core.primitives.Int_obj_val;
public class Json_parser__list_nde__base extends Json_parser__itm__base {
public void Parse_grp(String context, Json_grp grp) {
this.context = context;
int len = grp.Len();
for (int i = 0; i < len; ++i) {
Json_nde sub = null;
if (grp.Tid() == Json_itm_.Tid__nde) {
Json_kv kv = Json_nde.Cast(grp).Get_at_as_kv(i);
sub = kv.Val_as_nde();
}
else {
sub = Json_nde.Cast(grp.Get_at(i));
}
Parse_nde(context, sub);
}
}
public void Parse_nde(String context, Json_nde nde) {
this.cur_itm = nde;
for (int j = 0; j < keys_len; ++j)
atrs[j] = null;
int atr_len = nde.Len();
for (int j = 0; j < atr_len; ++j) {
Json_kv atr = nde.Get_at_as_kv(j);
Object idx_obj = hash.Get_by_bry(atr.Key_as_bry());
if (idx_obj == null) {Warn("unknown json parser key", atr); continue;}
int idx_int = ((Int_obj_val)idx_obj).Val();
atrs[idx_int] = atr;
}
Parse_hook_nde(nde, atrs);
}
public void Parse_to_list_as_bry(String context, Json_ary ary, Ordered_hash list) {
this.cur_itm = ary;
int len = ary.Len();
for (int i = 0; i < len; ++i) {
byte[] val = ary.Get_at(i).Data_bry();
list.Add(val, val);
}
}
public void Parse_to_list_as_kv(String context, Json_nde nde, Ordered_hash list) {
this.cur_itm = nde;
int len = nde.Len();
for (int i = 0; i < len; ++i) {
Json_kv sub = nde.Get_at_as_kv(i);
byte[] key = sub.Key_as_bry();
byte[] val = Parse_to_list_as_kv__get_val(sub, key);
list.Add(key, Keyval_.new_(String_.new_u8(key), String_.new_u8(val)));
}
}
@gplx.Virtual protected byte[] Parse_to_list_as_kv__get_val(Json_kv sub, byte[] key) {return sub.Val_as_bry();}
@Override protected void Parse_hook_nde(Json_nde sub, Json_kv[] atrs) {}
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,87 +13,96 @@ 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.langs.jsons; import gplx.*; import gplx.langs.*;
import org.junit.*;
public class Json_parser_tst {
private final Json_parser_fxt fxt = new Json_parser_fxt();
@Before public void init() {fxt.Clear();}
@Test public void Null() {fxt.Test_parse_val0("{'k0':null}" , null);}
@Test public void Bool_n() {fxt.Test_parse_val0("{'k0':false}" , false);}
@Test public void Bool_y() {fxt.Test_parse_val0("{'k0':true}" , true);}
@Test public void Num() {fxt.Test_parse_val0("{'k0':123}" , 123);}
@Test public void Num_neg() {fxt.Test_parse_val0("{'k0':-123}" , -123);}
@Test public void Str() {fxt.Test_parse_val0("{'k0':'v0'}" , "v0");}
@Test public void Str_esc_quote() {fxt.Test_parse_val0("{'k0':'a\\\"b'}" , "a\"b");}
@Test public void Str_encoded_basic() {fxt.Test_parse_val0("{'k0':'a\\u0021b'}" , "a!b");}
@Test public void Str_encoded_surrogate() {fxt.Test_parse_val0("{'k0':'a\\ud83c\\udf0eb'}", "a🌎b");} // check for UTF surrogate-pairs; symbol is earth globe americas (U+1F30E); ISSUE#:487; DATE:2019-06-02
@Test public void Num_dec() {fxt.Test_parse("{'k0':1.23}" , fxt.itm_nde_().Add_many(fxt.itm_kv_dec_("k0", "1.23")));}
@Test public void Num_exp() {fxt.Test_parse("{'k0':1e+2}" , fxt.itm_nde_().Add_many(fxt.itm_kv_dec_("k0", "1e+2")));}
@Test public void Num_mix() {fxt.Test_parse("{'k0':-1.23e-1}" , fxt.itm_nde_().Add_many(fxt.itm_kv_dec_("k0", "-1.23e-1")));}
@Test public void Str_many() {fxt.Test_parse("{'k0':'v0','k1':'v1','k2':'v2'}", fxt.itm_nde_().Add_many(fxt.itm_kv_("k0", "v0"), fxt.itm_kv_("k1", "v1"), fxt.itm_kv_("k2", "v2")));}
@Test public void Ary_empty() {fxt.Test_parse("{'k0':[]}", fxt.itm_nde_().Add_many(fxt.itm_kv_ary_int_("k0")));}
@Test public void Ary_int() {fxt.Test_parse("{'k0':[1,2,3]}", fxt.itm_nde_().Add_many(fxt.itm_kv_ary_int_("k0", 1, 2, 3)));}
@Test public void Ary_str() {fxt.Test_parse("{'k0':['a','b','c']}", fxt.itm_nde_().Add_many(fxt.itm_kv_ary_str_("k0", "a", "b", "c")));}
@Test public void Ary_ws() {fxt.Test_parse("{'k0': [ 1 , 2 , 3 ] }", fxt.itm_nde_().Add_many(fxt.itm_kv_ary_int_("k0", 1, 2, 3)));}
@Test public void Subs_int() {fxt.Test_parse("{'k0':{'k00':1}}", fxt.itm_nde_().Add_many(fxt.itm_kv_("k0", fxt.itm_nde_().Add_many(fxt.itm_kv_("k00", 1)))));}
@Test public void Subs_empty() {fxt.Test_parse("{'k0':{}}", fxt.itm_nde_().Add_many(fxt.itm_kv_("k0", fxt.itm_nde_())));}
@Test public void Subs_ws() {fxt.Test_parse("{'k0': { 'k00' : 1 } }", fxt.itm_nde_().Add_many(fxt.itm_kv_("k0", fxt.itm_nde_().Add_many(fxt.itm_kv_("k00", 1)))));}
@Test public void Ws() {fxt.Test_parse(" { 'k0' : 'v0' } ", fxt.itm_nde_().Add_many(fxt.itm_kv_("k0", "v0")));}
@Test public void Root_is_ary() {fxt.Test_parse("[ 1 , 2 , 3 ]", fxt.itm_ary_().Add_many(fxt.itm_int_(1), fxt.itm_int_(2), fxt.itm_int_(3)));}
public static String Replace_apos_as_str(String v) {return String_.new_u8(Replace_apos(Bry_.new_u8(v)));}
public static byte[] Replace_apos(byte[] v) {return Bry_.Replace(v, Byte_ascii.Apos, Byte_ascii.Quote);}
}
class Json_parser_fxt {
public void Clear() {
if (parser == null) {
parser = new Json_parser();
factory = parser.Factory();
}
} Json_parser parser; Json_factory factory; Bry_bfr tmp_bfr = Bry_bfr_.Reset(255);
public Json_itm itm_int_(int v) {return Json_itm_tmp.new_int_(v);}
Json_itm itm_str_(String v) {return Json_itm_tmp.new_str_(v);}
public Json_ary itm_ary_() {return factory.Ary(-1, -1);}
public Json_nde itm_nde_() {return factory.Nde(null, -1);}
public Json_kv itm_kv_null_(String k) {return factory.Kv(itm_str_(k), factory.Null());}
public Json_kv itm_kv_(String k, String v) {return factory.Kv(itm_str_(k), itm_str_(v));}
public Json_kv itm_kv_(String k, int v) {return factory.Kv(itm_str_(k), itm_int_(v));}
public Json_kv itm_kv_(String k, boolean v) {return factory.Kv(itm_str_(k), v ? factory.Bool_y() : factory.Bool_n());}
public Json_kv itm_kv_dec_(String k, String v) {return factory.Kv(itm_str_(k), new Json_itm_tmp(Json_itm_.Tid__decimal, v));}
public Json_kv itm_kv_(String k, Json_nde v) {return factory.Kv(itm_str_(k), v);}
public Json_kv itm_kv_ary_int_(String k, int... v) {
Json_ary ary = factory.Ary(-1, -1);
int len = v.length;
for (int i = 0; i < len; i++)
ary.Add(itm_int_(v[i]));
return factory.Kv(itm_str_(k), ary);
}
public Json_kv itm_kv_ary_str_(String k, String... v) {
Json_ary ary = factory.Ary(-1, -1);
int len = v.length;
for (int i = 0; i < len; i++)
ary.Add(itm_str_(v[i]));
return factory.Kv(itm_str_(k), ary);
}
public void Test_parse(String raw_str, Json_itm... expd_ary) {
byte[] raw = Json_parser_tst.Replace_apos(Bry_.new_u8(raw_str));
Json_doc doc = parser.Parse(raw);
doc.Root_grp().Print_as_json(tmp_bfr, 0);
String actl = tmp_bfr.To_str_and_clear();
String expd = Xto_str(raw, doc, expd_ary, 0, expd_ary.length);
Tfds.Eq_str_lines(expd, actl, actl);
}
public void Test_parse_val0(String raw_str, Object expd) {
byte[] raw = Json_parser_tst.Replace_apos(Bry_.new_u8(raw_str));
Json_doc doc = parser.Parse(raw);
Json_kv kv = Json_kv.cast(doc.Root_nde().Get_at(0)); // assume root has kv as first sub; EX: {"a":"b"}
Object actl = kv.Val().Data(); // NOTE: Data_bry is escaped val; EX: a\"b has DataBry of a"b
Tfds.Eq(expd, actl);
}
String Xto_str(byte[] raw, Json_doc doc, Json_itm[] ary, int bgn, int end) {
for (int i = bgn; i < end; i++) {
Json_itm itm = ary[i];
itm.Print_as_json(tmp_bfr, 0);
}
return tmp_bfr.To_str_and_clear();
}
}
package gplx.langs.jsons;
import gplx.Bry_;
import gplx.Bry_bfr;
import gplx.Bry_bfr_;
import gplx.Decimal_adp;
import gplx.Decimal_adp_;
import gplx.Tfds;
import gplx.core.tests.Gftest;
import org.junit.Test;
public class Json_parser_tst {
private final Json_parser_fxt fxt = new Json_parser_fxt();
@Test public void Null() {fxt.Test_parse_obj("{'k0':null}" , null);}
@Test public void Bool_n() {fxt.Test_parse_obj("{'k0':false}" , false);}
@Test public void Bool_y() {fxt.Test_parse_obj("{'k0':true}" , true);}
@Test public void Num() {fxt.Test_parse_obj("{'k0':123}" , 123);}
@Test public void Num_neg() {fxt.Test_parse_obj("{'k0':-123}" , -123);}
@Test public void Str() {fxt.Test_parse_obj("{'k0':'v0'}" , "v0");}
@Test public void Str_esc_quote() {fxt.Test_parse_obj("{'k0':'a\\\"b'}" , "a\"b");}
@Test public void Str_encoded_basic() {fxt.Test_parse_obj("{'k0':'a\\u0021b'}" , "a!b");}
@Test public void Str_encoded_surrogate() {fxt.Test_parse_obj("{'k0':'a\\ud83c\\udf0eb'}", "a🌎b");} // check for UTF surrogate-pairs; symbol is earth globe americas (U+1F30E); ISSUE#:487; DATE:2019-06-02
@Test public void Num_dec() {fxt.Test_parse_dec("{'k0':1.23}" , Decimal_adp_.parse("1.23"));}
@Test public void Num_exp() {fxt.Test_parse_obj("{'k0':1e+2}" , 100);}
@Test public void Num_mix() {fxt.Test_parse_dec("{'k0':-1.23e-1}" , Decimal_adp_.parse("-1.23e-1"));}
@Test public void Str_many() {fxt.Test_parse("{'k0':'v0','k1':'v1','k2':'v2'}" , fxt.Init_nde().Add_many(fxt.Init_kv("k0", "v0"), fxt.Init_kv("k1", "v1"), fxt.Init_kv("k2", "v2")));}
@Test public void Ary_empty() {fxt.Test_parse("{'k0':[]}" , fxt.Init_nde().Add_many(fxt.Init_kv_ary_int("k0")));}
@Test public void Ary_int() {fxt.Test_parse("{'k0':[1,2,3]}" , fxt.Init_nde().Add_many(fxt.Init_kv_ary_int("k0", 1, 2, 3)));}
@Test public void Ary_str() {fxt.Test_parse("{'k0':['a','b','c']}" , fxt.Init_nde().Add_many(fxt.Init_kvary_str_("k0", "a", "b", "c")));}
@Test public void Ary_ws() {fxt.Test_parse("{'k0': [ 1 , 2 , 3 ] }" , fxt.Init_nde().Add_many(fxt.Init_kv_ary_int("k0", 1, 2, 3)));}
@Test public void Subs_int() {fxt.Test_parse("{'k0':{'k00':1}}" , fxt.Init_nde().Add_many(fxt.Init_kv("k0", fxt.Init_nde().Add_many(fxt.Init_kv("k00", 1)))));}
@Test public void Subs_empty() {fxt.Test_parse("{'k0':{}}" , fxt.Init_nde().Add_many(fxt.Init_kv("k0", fxt.Init_nde())));}
@Test public void Subs_ws() {fxt.Test_parse("{'k0': { 'k00' : 1 } }" , fxt.Init_nde().Add_many(fxt.Init_kv("k0", fxt.Init_nde().Add_many(fxt.Init_kv("k00", 1)))));}
@Test public void Ws() {fxt.Test_parse(" { 'k0' : 'v0' } " , fxt.Init_nde().Add_many(fxt.Init_kv("k0", "v0")));}
@Test public void Root_is_ary() {fxt.Test_parse("[1,2,3]" , fxt.Init_ary().Add_many(fxt.Init_int(1), fxt.Init_int(2), fxt.Init_int(3)));}
}
class Json_parser_fxt {
private final Json_parser parser = new Json_parser();
private final Bry_bfr tmp_bfr = Bry_bfr_.Reset(255);
public Json_itm Init_int(int v) {return Json_itm_int.NewByVal(v);}
public Json_itm Init_str(String v) {return Json_itm_str.NewByVal(v);}
public Json_ary Init_ary() {return Json_ary.NewByVal();}
public Json_nde Init_nde() {return Json_nde.NewByVal();}
public Json_kv Init_kv_null(String k) {return new Json_kv(Init_str(k), Json_itm_null.Null);}
public Json_kv Init_kv(String k, String v) {return new Json_kv(Init_str(k), Init_str(v));}
public Json_kv Init_kv(String k, int v) {return new Json_kv(Init_str(k), Init_int(v));}
public Json_kv Init_kv(String k, boolean v) {return new Json_kv(Init_str(k), v ? Json_itm_bool.Bool_y : Json_itm_bool.Bool_n);}
public Json_kv Init_kv(String k, Json_nde v) {return new Json_kv(Init_str(k), v);}
public Json_kv Init_kv_ary_int(String k, int... v) {
Json_ary ary = Json_ary.NewByVal();
int len = v.length;
for (int i = 0; i < len; i++)
ary.Add(Init_int(v[i]));
return new Json_kv(Init_str(k), ary);
}
public Json_kv Init_kvary_str_(String k, String... v) {
Json_ary ary = Json_ary.NewByVal();
int len = v.length;
for (int i = 0; i < len; i++)
ary.Add(Init_str(v[i]));
return new Json_kv(Init_str(k), ary);
}
public void Test_parse(String raw_str, Json_itm... expd_ary) {
byte[] raw = Bry_.new_u8(Json_doc.Make_str_by_apos(raw_str));
Json_doc doc = parser.Parse(raw);
doc.Root_grp().Print_as_json(tmp_bfr, 0);
String actl = tmp_bfr.To_str_and_clear();
String expd = Xto_str(raw, doc, expd_ary, 0, expd_ary.length);
Tfds.Eq_str_lines(expd, actl, actl);
}
public void Test_parse_obj(String raw_str, Object expd) {
Json_kv kv = Parse_and_get_kv0(raw_str);
Object actl = kv.Val().Data(); // NOTE: Data_bry is escaped val; EX: a\"b has DataBry of a"b
Gftest.Eq__obj_or_null(expd, actl);
}
public void Test_parse_dec(String raw_str, Decimal_adp expd) {
Json_kv kv = Parse_and_get_kv0(raw_str);
Json_itm_decimal decimal_itm = (Json_itm_decimal)kv.Val();
Gftest.Eq__bool(true, decimal_itm.Data_as_decimal().Eq(expd));
}
private Json_kv Parse_and_get_kv0(String raw_str) {
byte[] raw = Bry_.new_u8(Json_doc.Make_str_by_apos(raw_str));
Json_doc doc = parser.Parse(raw);
return Json_kv.Cast(doc.Root_nde().Get_at(0)); // assume root has kv as first sub; EX: {"a":"b"}
}
private String Xto_str(byte[] raw, Json_doc doc, Json_itm[] ary, int bgn, int end) {
for (int i = bgn; i < end; i++) {
Json_itm itm = ary[i];
itm.Print_as_json(tmp_bfr, 0);
}
return tmp_bfr.To_str_and_clear();
}
}

@ -0,0 +1,112 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2020 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.langs.mustaches;
import gplx.Bool_;
import gplx.Bry_;
import gplx.String_;
import gplx.langs.jsons.Json_ary;
import gplx.langs.jsons.Json_itm;
import gplx.langs.jsons.Json_itm_;
import gplx.langs.jsons.Json_kv;
import gplx.langs.jsons.Json_nde;
import gplx.objects.Object_;
public class JsonMustacheNde implements Mustache_doc_itm {
private final Json_nde nde;
public JsonMustacheNde(Json_nde nde) {this.nde = nde;}
public boolean Mustache__write(String key, Mustache_bfr bfr) {
Json_itm itm = nde.Get_itm(Bry_.new_u8(key));
if (itm == null) { // mustacheKey does not exist in current jsonNde
return false;
}
else { // mustacheKey exists
switch (itm.Tid()) {
// array / bool node -> ignore; EX: `{{#person}}Never shown{{/person}}`
case Json_itm_.Tid__bool:
case Json_itm_.Tid__ary:
case Json_itm_.Tid__nde:
return false;
// item node -> render it; EX: `Hello {{name}}`
default:
bfr.Add_bry(Json_kv.Cast(itm).Val_as_bry());
return true;
}
}
}
public Mustache_doc_itm[] Mustache__subs(String key) {
Json_itm itm = nde.Get_itm(Bry_.new_u8(key));
if (itm == null) { // mustacheKey does not exist in current jsonNde
return Mustache_doc_itm_.Ary__bool__n;
}
else { // mustacheKey exists
if (itm.Tid() == Json_itm_.Tid__kv) {
Json_kv kv = Json_kv.Cast(itm);
switch (kv.Val().Tid()) {
// bool node -> render; EX: `{{#person}}Never shown{{/person}}`
case Json_itm_.Tid__bool:
boolean dataVal = Bool_.Cast(kv.Val().Data());
return dataVal ? Mustache_doc_itm_.Ary__bool__y : Mustache_doc_itm_.Ary__bool__n;
// array node -> render; EX: `{{#repo}} <b>{{name}}</b>{{/repo}}`
case Json_itm_.Tid__ary:
return ToJsonMustachNdeAry(itm);
// item node -> render only if key matchers
default:
return new Mustache_doc_itm[] {new JsonMustacheVal(true, key, kv.Val().Data())};
}
}
else {
return Mustache_doc_itm_.Ary__bool__n;
}
}
}
private static Mustache_doc_itm[] ToJsonMustachNdeAry(Json_itm itm) {
Json_ary dataAry = Json_ary.cast_or_null(Json_kv.Cast(itm).Val());
int subs_len = dataAry.Len();
Mustache_doc_itm[] rv = new Mustache_doc_itm[subs_len];
for (int i = 0; i < subs_len; i++) {
Json_itm sub = dataAry.Get_at(i);
if (sub.Tid() == Json_itm_.Tid__nde) {
rv[i] = new JsonMustacheNde((Json_nde)sub);
}
else {
rv[i] = new JsonMustacheVal(false, Mustache_tkn_def.ItemString, sub.Data());
}
}
return rv;
}
}
class JsonMustacheVal implements Mustache_doc_itm {
private final boolean fromArray;
private final String jsonKey;
private final Object jsonVal;
public JsonMustacheVal(boolean fromArray, String jsonKey, Object jsonVal) {
this.fromArray = fromArray;
this.jsonKey = jsonKey;
this.jsonVal = jsonVal;
}
public boolean Mustache__write(String mustacheKey, Mustache_bfr bfr) {
if ( (String_.Eq(mustacheKey, jsonKey)) // print if `{{match}}`; EX: `{{#prop}}{{prop}}{{/prop}}`
|| (String_.Eq(mustacheKey, Mustache_tkn_def.ItemString) && fromArray)) { // print if `{{.}}` and from array; EX: `{{#array}}{{.}}{{/array}}`
bfr.Add_bry(Bry_.new_u8(Object_.To_str(jsonVal)));
return true;
}
else {
return false;
}
}
public Mustache_doc_itm[] Mustache__subs(String key) {return Mustache_doc_itm_.Ary__empty;}
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,9 +13,9 @@ 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.langs.mustaches; import gplx.*; import gplx.langs.*;
import gplx.langs.jsons.*;
public interface Mustache_doc_itm {
boolean Mustache__write(String key, Mustache_bfr bfr);
Mustache_doc_itm[] Mustache__subs(String key);
}
package gplx.langs.mustaches;
public interface Mustache_doc_itm {
boolean Mustache__write(String key, Mustache_bfr bfr);
Mustache_doc_itm[] Mustache__subs(String key);
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,150 +13,177 @@ 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.langs.mustaches; import gplx.*; import gplx.langs.*;
import org.junit.*; import gplx.core.primitives.*;
public class Mustache_itm_render_tst {
private final Mustache_itm_render_fxt fxt = new Mustache_itm_render_fxt();
@Test public void Text() {
fxt.Test__parse("a b c", "a b c");
}
@Test public void Variable() {
fxt.Init__root(fxt.Make_mock(0).Add_prop("prop1", "1").Add_prop("prop2", "2"));
fxt.Test__parse("{{prop1}}", "1");
fxt.Test__parse("a{{prop1}}b{{prop2}}c", "a1b2c");
}
@Test public void Escape() {
fxt.Init__root(fxt.Make_mock(0).Add_prop("prop1", "<"));
fxt.Test__parse("{{{prop1}}}", "<");
fxt.Test__parse("{{prop1}}", "&lt;");
}
@Test public void Section_bool() {
fxt.Init__root(fxt.Make_mock(0).Add_bool_y("bool_y").Add_bool_n("bool_n"));
fxt.Test__parse("a{{#bool_y}}b{{/bool_y}}c", "abc");
fxt.Test__parse("a{{#bool_n}}b{{/bool_n}}c", "ac");
fxt.Test__parse("a{{#bool_y}}b{{/bool_y}}c{{#bool_n}}d{{/bool_n}}e", "abce");
}
@Test public void Section_not() {
fxt.Init__root(fxt.Make_mock(0).Add_bool_y("bool_y").Add_bool_n("bool_n"));
fxt.Test__parse("a{{^bool_y}}b{{/bool_y}}c", "ac");
fxt.Test__parse("a{{^bool_n}}b{{/bool_n}}c", "abc");
fxt.Test__parse("a{{^bool_y}}b{{/bool_y}}c{{^bool_n}}d{{/bool_n}}e", "acde");
}
@Test public void Section_ws() {
fxt.Init__root(fxt.Make_mock(0).Add_bool_y("bool_y"));
fxt.Test__parse("a\n {{#bool_y}} \nb\n {{/bool_y}} \nc", "a\nb\nc");
}
@Test public void Section_subs_flat() {
fxt.Init__root(fxt.Make_mock(0).Add_subs("subs1"
, fxt.Make_mock(1).Add_prop("prop1", "1").Add_subs("subs2")
, fxt.Make_mock(2).Add_prop("prop1", "2").Add_subs("subs2")
));
fxt.Test__parse("a{{#subs1}}({{prop1}}){{/subs1}}d", "a(1)(2)d");
}
@Test public void Section_subs_nest_1() {
fxt.Init__root
( fxt.Make_mock(0).Add_subs("subs1"
, fxt.Make_mock(1).Add_prop("prop1", "a").Add_subs("subs2"
, fxt.Make_mock(11).Add_prop("prop2", "1")
, fxt.Make_mock(12).Add_prop("prop2", "2"))
));
fxt.Test__parse
( "{{#subs1}}{{prop1}}{{#subs2}}{{prop2}}{{/subs2}}{{/subs1}}"
, "a12"
);
}
@Test public void Section_subs_nest_2() {
fxt.Init__root
( fxt.Make_mock(0).Add_subs("subs1"
, fxt.Make_mock(1).Add_prop("prop1", "a").Add_subs("subs2"
, fxt.Make_mock(11).Add_prop("prop2", "1")
, fxt.Make_mock(12).Add_prop("prop2", "2")
)
, fxt.Make_mock(2).Add_prop("prop1", "b")
)
);
fxt.Test__parse
( "{{#subs1}}{{prop1}}{{#subs2}}{{prop2}}{{/subs2}}{{/subs1}}"
, "a12b"
);
}
@Test public void Section_subs_nest_3() {
fxt.Init__root
( fxt.Make_mock(0).Add_subs("subs1"
, fxt.Make_mock(1).Add_prop("prop1", "a").Add_subs("subs2"
, fxt.Make_mock(11).Add_prop("prop2", "1")
, fxt.Make_mock(12).Add_prop("prop2", "2")
)
, fxt.Make_mock(2).Add_prop("prop1", "b").Add_subs("subs2"
, fxt.Make_mock(21).Add_prop("prop2", "3")
, fxt.Make_mock(22).Add_prop("prop2", "4")
)
)
);
fxt.Test__parse
( "{{#subs1}}{{prop1}}{{#subs2}}{{prop2}}{{/subs2}}{{prop1}}{{/subs1}}"
, "a12ab34b"
);
}
@Test public void Section_bool_subs() { // handle prop written after boolean; should not pick up inner prop
fxt.Init__root
( fxt.Make_mock(0).Add_bool_y("bool1").Add_prop("prop2", "2").Add_subs("subs1"
, fxt.Make_mock(1).Add_prop("prop1", "11")
, fxt.Make_mock(2).Add_prop("prop1", "12")
));
fxt.Test__parse
( "a{{#bool1}}b{{#subs1}}c{{prop1}}d{{/subs1}}e{{/bool1}}f{{prop2}}g"
, "abc11dc12def2g"
);
}
@Test public void Section_owner() {
fxt.Init__root
( fxt.Make_mock(0).Add_subs("subs1"
, fxt.Make_mock(1).Add_prop("prop1", "a").Add_subs("subs2"
, fxt.Make_mock(11).Add_prop("prop2", "1")
)
));
fxt.Test__parse
( "{{#subs1}}{{#subs2}}{{prop1}}{{prop2}}{{/subs2}}{{/subs1}}" // prop1 is cited in subs2, but value belongs to subs1
, "a1"
);
}
}
class Mustache_itm_render_fxt {
private final Mustache_tkn_parser parser = new Mustache_tkn_parser();
private final Mustache_render_ctx ctx = new Mustache_render_ctx();
private final Mustache_bfr bfr = Mustache_bfr.New();
private Mustache_doc_itm__mock root;
public Mustache_doc_itm__mock Make_mock(int id) {return new Mustache_doc_itm__mock(id);}
public void Init__root(Mustache_doc_itm__mock v) {this.root = v;}
public void Test__parse(String src_str, String expd) {
byte[] src_bry = Bry_.new_a7(src_str);
Mustache_tkn_itm actl_itm = parser.Parse(src_bry, 0, src_bry.length);
ctx.Init(root);
actl_itm.Render(bfr, ctx);
Tfds.Eq_str_lines(expd, bfr.To_str_and_clear());
}
}
class Mustache_doc_itm__mock implements Mustache_doc_itm {
private final Hash_adp hash_prop = Hash_adp_.New(), hash_bool = Hash_adp_.New(), hash_subs = Hash_adp_.New();
public Mustache_doc_itm__mock(int id) {this.id = id;}
public int id;
public Mustache_doc_itm__mock Add_prop(String key, String val) {hash_prop.Add(key, Bry_.new_u8(val)); return this;}
public Mustache_doc_itm__mock Add_bool_y(String key) {hash_bool.Add(key, Bool_obj_ref.y_()); return this;}
public Mustache_doc_itm__mock Add_bool_n(String key) {hash_bool.Add(key, Bool_obj_ref.n_()); return this;}
public Mustache_doc_itm__mock Add_subs(String key, Mustache_doc_itm__mock... ary) {hash_subs.Add(key, ary); return this;}
public boolean Mustache__write(String key, Mustache_bfr bfr) {
byte[] rv = (byte[])hash_prop.Get_by(key);
if (rv == null) return false;
bfr.Add_bry(rv);
return true;
}
public Mustache_doc_itm[] Mustache__subs(String key) {
Object rv = hash_bool.Get_by(key);
if (rv != null) {
boolean bool_val = ((Bool_obj_ref)rv).Val();
return bool_val ? Mustache_doc_itm_.Ary__bool__y : Mustache_doc_itm_.Ary__bool__n;
}
return (Mustache_doc_itm__mock[])hash_subs.Get_by(key);
}
}
package gplx.langs.mustaches;
import gplx.Bry_;
import gplx.Hash_adp;
import gplx.Hash_adp_;
import gplx.Tfds;
import gplx.core.primitives.Bool_obj_ref;
import gplx.langs.jsons.Json_doc;
import gplx.langs.jsons.Json_nde;
import gplx.langs.jsons.Json_parser;
import org.junit.Test;
public class Mustache_itm_render_tst {
private final Mustache_itm_render_fxt fxt = new Mustache_itm_render_fxt();
@Test public void Text() {
fxt.Test__parse("a b c", "a b c");
}
@Test public void Variable() {
fxt.Init__root(fxt.Make_mock(0).Add_prop("prop1", "1").Add_prop("prop2", "2"));
fxt.Test__parse("{{prop1}}", "1");
fxt.Test__parse("a{{prop1}}b{{prop2}}c", "a1b2c");
}
@Test public void Escape() {
fxt.Init__root(fxt.Make_mock(0).Add_prop("prop1", "<"));
fxt.Test__parse("{{{prop1}}}", "<");
fxt.Test__parse("{{prop1}}", "&lt;");
}
@Test public void Section_bool() {
fxt.Init__root(fxt.Make_mock(0).Add_bool_y("bool_y").Add_bool_n("bool_n"));
fxt.Test__parse("a{{#bool_y}}b{{/bool_y}}c", "abc");
fxt.Test__parse("a{{#bool_n}}b{{/bool_n}}c", "ac");
fxt.Test__parse("a{{#bool_y}}b{{/bool_y}}c{{#bool_n}}d{{/bool_n}}e", "abce");
}
@Test public void Section_not() {
fxt.Init__root(fxt.Make_mock(0).Add_bool_y("bool_y").Add_bool_n("bool_n"));
fxt.Test__parse("a{{^bool_y}}b{{/bool_y}}c", "ac");
fxt.Test__parse("a{{^bool_n}}b{{/bool_n}}c", "abc");
fxt.Test__parse("a{{^bool_y}}b{{/bool_y}}c{{^bool_n}}d{{/bool_n}}e", "acde");
}
@Test public void Section_ws() {
fxt.Init__root(fxt.Make_mock(0).Add_bool_y("bool_y"));
fxt.Test__parse("a\n {{#bool_y}} \nb\n {{/bool_y}} \nc", "a\nb\nc");
}
@Test public void Section_subs_flat() {
fxt.Init__root(fxt.Make_mock(0).Add_subs("subs1"
, fxt.Make_mock(1).Add_prop("prop1", "1").Add_subs("subs2")
, fxt.Make_mock(2).Add_prop("prop1", "2").Add_subs("subs2")
));
fxt.Test__parse("a{{#subs1}}({{prop1}}){{/subs1}}d", "a(1)(2)d");
}
@Test public void Section_subs_nest_1() {
fxt.Init__root
( fxt.Make_mock(0).Add_subs("subs1"
, fxt.Make_mock(1).Add_prop("prop1", "a").Add_subs("subs2"
, fxt.Make_mock(11).Add_prop("prop2", "1")
, fxt.Make_mock(12).Add_prop("prop2", "2"))
));
fxt.Test__parse
( "{{#subs1}}{{prop1}}{{#subs2}}{{prop2}}{{/subs2}}{{/subs1}}"
, "a12"
);
}
@Test public void Section_subs_nest_2() {
fxt.Init__root
( fxt.Make_mock(0).Add_subs("subs1"
, fxt.Make_mock(1).Add_prop("prop1", "a").Add_subs("subs2"
, fxt.Make_mock(11).Add_prop("prop2", "1")
, fxt.Make_mock(12).Add_prop("prop2", "2")
)
, fxt.Make_mock(2).Add_prop("prop1", "b")
)
);
fxt.Test__parse
( "{{#subs1}}{{prop1}}{{#subs2}}{{prop2}}{{/subs2}}{{/subs1}}"
, "a12b"
);
}
@Test public void Section_subs_nest_3() {
fxt.Init__root
( fxt.Make_mock(0).Add_subs("subs1"
, fxt.Make_mock(1).Add_prop("prop1", "a").Add_subs("subs2"
, fxt.Make_mock(11).Add_prop("prop2", "1")
, fxt.Make_mock(12).Add_prop("prop2", "2")
)
, fxt.Make_mock(2).Add_prop("prop1", "b").Add_subs("subs2"
, fxt.Make_mock(21).Add_prop("prop2", "3")
, fxt.Make_mock(22).Add_prop("prop2", "4")
)
)
);
fxt.Test__parse
( "{{#subs1}}{{prop1}}{{#subs2}}{{prop2}}{{/subs2}}{{prop1}}{{/subs1}}"
, "a12ab34b"
);
}
@Test public void Section_bool_subs() { // handle prop written after boolean; should not pick up inner prop
fxt.Init__root
( fxt.Make_mock(0).Add_bool_y("bool1").Add_prop("prop2", "2").Add_subs("subs1"
, fxt.Make_mock(1).Add_prop("prop1", "11")
, fxt.Make_mock(2).Add_prop("prop1", "12")
));
fxt.Test__parse
( "a{{#bool1}}b{{#subs1}}c{{prop1}}d{{/subs1}}e{{/bool1}}f{{prop2}}g"
, "abc11dc12def2g"
);
}
@Test public void Section_owner() {
fxt.Init__root
( fxt.Make_mock(0).Add_subs("subs1"
, fxt.Make_mock(1).Add_prop("prop1", "a").Add_subs("subs2"
, fxt.Make_mock(11).Add_prop("prop2", "1")
)
));
fxt.Test__parse
( "{{#subs1}}{{#subs2}}{{prop1}}{{prop2}}{{/subs2}}{{/subs1}}" // prop1 is cited in subs2, but value belongs to subs1
, "a1"
);
}
@Test public void Dot() {
fxt.Test__parse
( "{'subs':['a', 'b', 'c', 'd']}"
, "{{#subs}}{{.}},{{/subs}}"
, "a,b,c,d,"
);
}
}
class Mustache_itm_render_fxt {
private final Mustache_tkn_parser parser = new Mustache_tkn_parser();
private final Mustache_render_ctx ctx = new Mustache_render_ctx();
private final Mustache_bfr bfr = Mustache_bfr.New();
private Mustache_doc_itm__mock root;
public Mustache_doc_itm__mock Make_mock(int id) {return new Mustache_doc_itm__mock(id);}
public void Init__root(Mustache_doc_itm__mock v) {this.root = v;}
public void Test__parse(String src_str, String expd) {
byte[] src_bry = Bry_.new_a7(src_str);
Mustache_tkn_itm actl_itm = parser.Parse(src_bry, 0, src_bry.length);
ctx.Init(root);
actl_itm.Render(bfr, ctx);
Tfds.Eq_str_lines(expd, bfr.To_str_and_clear());
}
public void Test__parse(String jdoc, String src_str, String expd) {
Json_nde jnde = Json_parser.ParseToJdoc(Json_doc.Make_str_by_apos(jdoc)).Root_nde();
JsonMustacheNde nde = new JsonMustacheNde(jnde);
byte[] src_bry = Bry_.new_a7(src_str);
Mustache_tkn_itm actl_itm = parser.Parse(src_bry, 0, src_bry.length);
ctx.Init(nde);
actl_itm.Render(bfr, ctx);
Tfds.Eq_str_lines(expd, bfr.To_str_and_clear());
}
}
class Mustache_doc_itm__mock implements Mustache_doc_itm {
private final Hash_adp hash_prop = Hash_adp_.New(), hash_bool = Hash_adp_.New(), hash_subs = Hash_adp_.New();
public Mustache_doc_itm__mock(int id) {this.id = id;}
public int id;
public Mustache_doc_itm__mock Add_prop(String key, String val) {hash_prop.Add(key, Bry_.new_u8(val)); return this;}
public Mustache_doc_itm__mock Add_bool_y(String key) {hash_bool.Add(key, Bool_obj_ref.y_()); return this;}
public Mustache_doc_itm__mock Add_bool_n(String key) {hash_bool.Add(key, Bool_obj_ref.n_()); return this;}
public Mustache_doc_itm__mock Add_subs(String key, Mustache_doc_itm__mock... ary) {hash_subs.Add(key, ary); return this;}
public boolean Mustache__write(String key, Mustache_bfr bfr) {
byte[] rv = (byte[])hash_prop.Get_by(key);
if (rv == null) return false;
bfr.Add_bry(rv);
return true;
}
public Mustache_doc_itm[] Mustache__subs(String key) {
Object rv = hash_bool.Get_by(key);
if (rv != null) {
boolean bool_val = ((Bool_obj_ref)rv).Val();
return bool_val ? Mustache_doc_itm_.Ary__bool__y : Mustache_doc_itm_.Ary__bool__n;
}
return (Mustache_doc_itm__mock[])hash_subs.Get_by(key);
}
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,86 +13,100 @@ 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.langs.mustaches; import gplx.*; import gplx.langs.*;
public class Mustache_render_ctx {
private final List_adp stack = List_adp_.New();
private Mustache_doc_itm cur;
private Mustache_doc_itm[] subs; private int subs_idx, subs_len; private byte cur_is_bool;
public Mustache_render_ctx Init(Mustache_doc_itm cur) {
this.cur = cur;
this.subs = null;
this.subs_idx = subs_len = 0; this.cur_is_bool = Bool_.__byte;
return this;
}
public boolean Render_variable(Mustache_bfr bfr, String key) {
boolean rv = false;
int stack_pos = stack.Len();
Mustache_doc_itm itm = cur;
while (itm != Mustache_doc_itm_.Null_itm) {
boolean resolved = itm.Mustache__write(key, bfr);
if (resolved) {
rv = true;
break;
}
else {
--stack_pos;
if (stack_pos == -1) // nothing else in stack
break;
else
itm = ((Mustache_stack_itm)stack.Get_at(stack_pos)).cur;
}
}
return rv;
}
public void Section_bgn(String key) {
Mustache_stack_itm stack_itm = new Mustache_stack_itm(cur, subs, subs_idx, subs_len, cur_is_bool); // note that cur is "owner" since subs_idx == 0
stack.Add(stack_itm);
subs = cur.Mustache__subs(key); if (subs == null) subs = Mustache_doc_itm_.Ary__empty; // subs == null if property does not exist; EX: "folder{{#files}}file{{/files}}" and folder = new Folder(File[0]);
subs_len = subs.length;
subs_idx = -1;
}
public boolean Section_do(boolean inverted) {
if (++subs_idx >= subs_len) return false;
Mustache_doc_itm sub = subs[subs_idx];
if (subs_idx == 0) { // special logic to handle 1st item; note that there always be at least one item
if (sub == Mustache_doc_itm_.Itm__bool__n) {
boolean rv = Bool_.N;
if (inverted) rv = !rv;
cur_is_bool = Bool_.To_byte(rv);
return rv;
}
else if (sub == Mustache_doc_itm_.Itm__bool__y) {
boolean rv = Bool_.Y;
if (inverted) rv = !rv;
cur_is_bool = Bool_.To_byte(rv);
return rv;
}
else
cur_is_bool = Bool_.__byte;
}
cur = sub;
return true;
}
public void Section_end() {
Mustache_stack_itm itm = (Mustache_stack_itm)List_adp_.Pop(stack);
subs = itm.subs;
subs_len = itm.subs_len;
subs_idx = itm.subs_idx;
cur = itm.cur;
cur_is_bool = itm.cur_is_bool;
}
}
class Mustache_stack_itm {
public Mustache_stack_itm(Mustache_doc_itm cur, Mustache_doc_itm[] subs, int subs_idx, int subs_len, byte cur_is_bool) {
this.cur = cur;
this.cur_is_bool = cur_is_bool;
this.subs = subs;
this.subs_idx = subs_idx;
this.subs_len = subs_len;
}
public final Mustache_doc_itm cur;
public final byte cur_is_bool;
public final Mustache_doc_itm[] subs;
public final int subs_idx;
public final int subs_len;
}
package gplx.langs.mustaches;
import gplx.Bool_;
import gplx.List_adp;
import gplx.List_adp_;
public class Mustache_render_ctx {
private final List_adp stack = List_adp_.New();
private Mustache_doc_itm cur;
private Mustache_doc_itm[] subs;
private int subs_idx, subs_len;
private byte cur_is_bool;
public Mustache_render_ctx Init(Mustache_doc_itm cur) {
this.cur = cur;
this.subs = null;
this.subs_idx = subs_len = 0;
this.cur_is_bool = Bool_.__byte;
return this;
}
public boolean Render_variable(Mustache_bfr bfr, String key) {
boolean rv = false;
int stack_pos = stack.Len();
Mustache_doc_itm itm = cur;
while (itm != Mustache_doc_itm_.Null_itm) {
boolean resolved = itm.Mustache__write(key, bfr);
// current itm handles key -> exit
if (resolved) {
rv = true;
break;
}
// current itm does not handle key -> go up stack
else {
--stack_pos;
if (stack_pos == -1) // nothing else in stack
break;
else
itm = ((Mustache_stack_itm)stack.Get_at(stack_pos)).cur;
}
}
return rv;
}
public void Section_bgn(String key) {
Mustache_stack_itm stack_itm = new Mustache_stack_itm(cur, subs, subs_idx, subs_len, cur_is_bool); // note that cur is "owner" since subs_idx == 0
stack.Add(stack_itm);
subs = cur.Mustache__subs(key);
if (subs == null) // subs == null if property does not exist; EX: "folder{{#files}}file{{/files}}" and folder = new Folder(File[0]);
subs = Mustache_doc_itm_.Ary__empty;
subs_len = subs.length;
subs_idx = -1;
}
public boolean Section_do(boolean inverted) {
if (++subs_idx >= subs_len)
return false;
Mustache_doc_itm sub = subs[subs_idx];
if (subs_idx == 0) { // special logic to handle 1st item; note that there always be at least one item
if (sub == Mustache_doc_itm_.Itm__bool__n) {
boolean rv = Bool_.N;
if (inverted) rv = !rv;
cur_is_bool = Bool_.To_byte(rv);
return rv;
}
else if (sub == Mustache_doc_itm_.Itm__bool__y) {
boolean rv = Bool_.Y;
if (inverted) rv = !rv;
cur_is_bool = Bool_.To_byte(rv);
return rv;
}
else
cur_is_bool = Bool_.__byte;
}
cur = sub;
return true;
}
public void Section_end() {
Mustache_stack_itm itm = (Mustache_stack_itm)List_adp_.Pop(stack);
subs = itm.subs;
subs_len = itm.subs_len;
subs_idx = itm.subs_idx;
cur = itm.cur;
cur_is_bool = itm.cur_is_bool;
}
}
class Mustache_stack_itm {
public Mustache_stack_itm(Mustache_doc_itm cur, Mustache_doc_itm[] subs, int subs_idx, int subs_len, byte cur_is_bool) {
this.cur = cur;
this.cur_is_bool = cur_is_bool;
this.subs = subs;
this.subs_idx = subs_idx;
this.subs_len = subs_len;
}
public final Mustache_doc_itm cur;
public final byte cur_is_bool;
public final Mustache_doc_itm[] subs;
public final int subs_idx;
public final int subs_len;
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,30 +13,40 @@ 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.langs.mustaches; import gplx.*; import gplx.langs.*;
class Mustache_tkn_def {
public byte[] Variable_lhs = Dflt_variable_lhs;
public byte[] Variable_rhs = Dflt_variable_rhs;
public int Variable_lhs_len;
public int Variable_rhs_len;
public static final byte[]
Dflt_variable_lhs = Bry_.new_a7("{{")
, Dflt_variable_rhs = Bry_.new_a7("}}")
;
public static final byte
Variable = Byte_ascii.Curly_end // {{=<% %>=}}
, Escape_bgn = Byte_ascii.Curly_bgn // {{{escape}}}
, Escape_end = Byte_ascii.Curly_end // {{{escape}}}
, Section = Byte_ascii.Hash // {{#section}}
, Grp_end = Byte_ascii.Slash // {{/section}}
, Inverted = Byte_ascii.Pow // {{^inverted}}
, Comment = Byte_ascii.Bang // {{!comment}}
, Partial = Byte_ascii.Angle_bgn // {{>partial}}
, Delimiter_bgn = Byte_ascii.Eq // {{=<% %>=}}
, Delimiter_end = Byte_ascii.Curly_end // {{=<% %>=}}
;
public Mustache_tkn_def() {
Variable_lhs_len = Variable_lhs.length;
Variable_rhs_len = Variable_rhs.length;
}
}
package gplx.langs.mustaches;
import gplx.Bry_;
import gplx.Byte_;
import gplx.Byte_ascii;
import gplx.String_;
class Mustache_tkn_def {
public byte[] Variable_lhs = Dflt_variable_lhs;
public byte[] Variable_rhs = Dflt_variable_rhs;
public int Variable_lhs_len;
public int Variable_rhs_len;
public static final byte[]
Dflt_variable_lhs = Bry_.new_a7("{{")
, Dflt_variable_rhs = Bry_.new_a7("}}")
;
public static final byte
Variable = Byte_ascii.Curly_end // {{=<% %>=}}
, Escape_bgn = Byte_ascii.Curly_bgn // {{{escape}}}
, Escape_end = Byte_ascii.Curly_end // {{{escape}}}
, Section = Byte_ascii.Hash // {{#section}}
, Grp_end = Byte_ascii.Slash // {{/section}}
, Inverted = Byte_ascii.Pow // {{^inverted}}
, Comment = Byte_ascii.Bang // {{!comment}}
, Partial = Byte_ascii.Angle_end // {{>partial}}
, Delimiter_bgn = Byte_ascii.Eq // {{=<% %>=}}
, Delimiter_end = Byte_ascii.Curly_end // {{=<% %>=}}
, Item = Byte_ascii.Dot // {{.}}
;
public static final String
ItemString = String_.new_u8(Byte_.To_bry(Item))
;
public Mustache_tkn_def() {
Variable_lhs_len = Variable_lhs.length;
Variable_rhs_len = Variable_rhs.length;
}
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,98 +13,114 @@ 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.langs.mustaches; import gplx.*; import gplx.langs.*;
public interface Mustache_tkn_itm {
int Tid();
String Key();
Mustache_tkn_itm[] Subs_ary();
void Subs_ary_(Mustache_tkn_itm[] v);
void Render(Mustache_bfr bfr, Mustache_render_ctx ctx);
}
class Mustache_tkn_itm_ {// for types, see http://mustache.github.io/mustache.5.html
public static final int Tid__root = 0, Tid__text = 1, Tid__variable = 2, Tid__escape = 3, Tid__section = 4, Tid__inverted = 5, Tid__comment = 6, Tid__partial = 7, Tid__delimiter = 8;
public static final Mustache_tkn_itm[] Ary_empty = new Mustache_tkn_itm[0];
}
abstract class Mustache_tkn_base implements Mustache_tkn_itm {
public Mustache_tkn_base(int tid, byte[] key_bry) {this.tid = tid; this.key = String_.new_u8(key_bry);}
public int Tid() {return tid;} private final int tid;
public String Key() {return key;} private final String key;
@gplx.Virtual public Mustache_tkn_itm[] Subs_ary() {return Mustache_tkn_itm_.Ary_empty;}
@gplx.Virtual public void Subs_ary_(Mustache_tkn_itm[] v) {throw Err_.new_unsupported();} // fail if trying to set and not overridden
@gplx.Virtual public void Render(Mustache_bfr bfr, Mustache_render_ctx ctx) {throw Err_.new_unsupported();} // should be abstract
}
class Mustache_tkn_root extends Mustache_tkn_base { // EX: {{variable}} -> &lt;a&gt;
private Mustache_tkn_itm[] subs_ary;
public Mustache_tkn_root() {super(Mustache_tkn_itm_.Tid__root, Bry_.Empty);}
@Override public Mustache_tkn_itm[] Subs_ary() {return subs_ary;}
@Override public void Subs_ary_(Mustache_tkn_itm[] v) {subs_ary = v;}
@Override public void Render(Mustache_bfr bfr, Mustache_render_ctx ctx) {
int subs_len = subs_ary.length;
for (int i = 0; i < subs_len; ++i) {
Mustache_tkn_itm sub = subs_ary[i];
sub.Render(bfr, ctx);
}
}
}
class Mustache_tkn_text extends Mustache_tkn_base { // EX: text -> text
private final byte[] src; private final int src_bgn, src_end;
public Mustache_tkn_text(byte[] src, int src_bgn, int src_end) {super(Mustache_tkn_itm_.Tid__text, Bry_.Empty);
this.src = src;
this.src_bgn = src_bgn;
this.src_end = src_end;
}
@Override public void Render(Mustache_bfr bfr, Mustache_render_ctx ctx) {
bfr.Add_mid(src, src_bgn, src_end);
}
}
class Mustache_tkn_comment extends Mustache_tkn_base { // EX: {{!section}}comment{{/section}} ->
public Mustache_tkn_comment() {super(Mustache_tkn_itm_.Tid__comment, Bry_.Empty);}
@Override public void Render(Mustache_bfr bfr, Mustache_render_ctx ctx) {}
}
class Mustache_tkn_variable extends Mustache_tkn_base { // EX: {{variable}} -> &lt;a&gt;
public Mustache_tkn_variable(byte[] key) {super(Mustache_tkn_itm_.Tid__variable, key);}
@Override public void Render(Mustache_bfr bfr, Mustache_render_ctx ctx) {
String key = this.Key();
ctx.Render_variable(bfr.Escape_(Bool_.Y), key);
}
}
class Mustache_tkn_escape extends Mustache_tkn_base { // EX: {{{variable}}} -> <a>
public Mustache_tkn_escape(byte[] key) {super(Mustache_tkn_itm_.Tid__escape, key);}
@Override public void Render(Mustache_bfr bfr, Mustache_render_ctx ctx) {
String key = this.Key();
ctx.Render_variable(bfr.Escape_(Bool_.N), key);
}
}
class Mustache_tkn_section extends Mustache_tkn_base { // EX: {{#section}}val{{/section}} -> val (if boolean) or valvalval (if list)
private Mustache_tkn_itm[] subs_ary;
public Mustache_tkn_section(byte[] key) {super(Mustache_tkn_itm_.Tid__section, key);}
@Override public Mustache_tkn_itm[] Subs_ary() {return subs_ary;}
@Override public void Subs_ary_(Mustache_tkn_itm[] v) {subs_ary = v;}
@Override public void Render(Mustache_bfr bfr, Mustache_render_ctx ctx) {Render_static(Bool_.N, this, bfr, ctx);}
public static void Render_static(boolean inverted, Mustache_tkn_base tkn, Mustache_bfr bfr, Mustache_render_ctx ctx) {
String key = tkn.Key();
Mustache_tkn_itm[] subs_ary = tkn.Subs_ary();
ctx.Section_bgn(key);
while (ctx.Section_do(inverted)) {
int subs_len = subs_ary.length;
for (int i = 0; i < subs_len; ++i) {
Mustache_tkn_itm sub = subs_ary[i];
sub.Render(bfr, ctx);
}
}
ctx.Section_end();
}
}
class Mustache_tkn_inverted extends Mustache_tkn_base { // EX: {{^section}}missing{{/section}} -> missing
private Mustache_tkn_itm[] subs_ary;
public Mustache_tkn_inverted(byte[] key) {super(Mustache_tkn_itm_.Tid__inverted, key);}
@Override public Mustache_tkn_itm[] Subs_ary() {return subs_ary;}
@Override public void Subs_ary_(Mustache_tkn_itm[] v) {subs_ary = v;}
@Override public void Render(Mustache_bfr bfr, Mustache_render_ctx ctx) {Mustache_tkn_section.Render_static(Bool_.Y, this, bfr, ctx);}
}
class Mustache_tkn_partial extends Mustache_tkn_base { // EX: {{>a}} -> abc (deferred eval)
public Mustache_tkn_partial(byte[] key) {super(Mustache_tkn_itm_.Tid__partial, key);}
}
class Mustache_tkn_delimiter extends Mustache_tkn_base {// EX: {{=<% %>=}} -> <% variable %>
public Mustache_tkn_delimiter(byte[] key) {super(Mustache_tkn_itm_.Tid__delimiter, key);}
}
package gplx.langs.mustaches;
import gplx.Bool_;
import gplx.Bry_;
import gplx.Byte_ascii;
import gplx.Err_;
import gplx.Io_url;
import gplx.String_;
public interface Mustache_tkn_itm {
int Tid();
String Key();
Mustache_tkn_itm[] Subs_ary();
void Subs_ary_(Mustache_tkn_itm[] v);
void Render(Mustache_bfr bfr, Mustache_render_ctx ctx);
}
class Mustache_tkn_itm_ {// for types, see http://mustache.github.io/mustache.5.html
public static final int Tid__root = 0, Tid__text = 1, Tid__variable = 2, Tid__escape = 3, Tid__section = 4, Tid__inverted = 5, Tid__comment = 6, Tid__partial = 7, Tid__delimiter = 8;
public static final Mustache_tkn_itm[] Ary_empty = new Mustache_tkn_itm[0];
}
abstract class Mustache_tkn_base implements Mustache_tkn_itm {
public Mustache_tkn_base(int tid, byte[] key_bry) {this.tid = tid; this.key = String_.new_u8(key_bry);}
public int Tid() {return tid;} private final int tid;
public String Key() {return key;} private final String key;
@gplx.Virtual public Mustache_tkn_itm[] Subs_ary() {return Mustache_tkn_itm_.Ary_empty;}
@gplx.Virtual public void Subs_ary_(Mustache_tkn_itm[] v) {throw Err_.new_unsupported();} // fail if trying to set and not overridden
@gplx.Virtual public void Render(Mustache_bfr bfr, Mustache_render_ctx ctx) {throw Err_.new_unsupported();} // should be abstract
}
class Mustache_tkn_root extends Mustache_tkn_base { // EX: {{variable}} -> &lt;a&gt;
private Mustache_tkn_itm[] subs_ary;
public Mustache_tkn_root() {super(Mustache_tkn_itm_.Tid__root, Bry_.Empty);}
@Override public Mustache_tkn_itm[] Subs_ary() {return subs_ary;}
@Override public void Subs_ary_(Mustache_tkn_itm[] v) {subs_ary = v;}
@Override public void Render(Mustache_bfr bfr, Mustache_render_ctx ctx) {
int subs_len = subs_ary.length;
for (int i = 0; i < subs_len; ++i) {
Mustache_tkn_itm sub = subs_ary[i];
sub.Render(bfr, ctx);
}
}
}
class Mustache_tkn_text extends Mustache_tkn_base { // EX: text -> text
private final byte[] src; private final int src_bgn, src_end;
public Mustache_tkn_text(byte[] src, int src_bgn, int src_end) {super(Mustache_tkn_itm_.Tid__text, Bry_.Empty);
this.src = src;
this.src_bgn = src_bgn;
this.src_end = src_end;
}
@Override public void Render(Mustache_bfr bfr, Mustache_render_ctx ctx) {
bfr.Add_mid(src, src_bgn, src_end);
}
}
class Mustache_tkn_comment extends Mustache_tkn_base { // EX: {{!section}}comment{{/section}} ->
public Mustache_tkn_comment() {super(Mustache_tkn_itm_.Tid__comment, Bry_.Empty);}
@Override public void Render(Mustache_bfr bfr, Mustache_render_ctx ctx) {}
}
class Mustache_tkn_variable extends Mustache_tkn_base { // EX: {{variable}} -> &lt;a&gt;
public Mustache_tkn_variable(byte[] key) {super(Mustache_tkn_itm_.Tid__variable, key);}
@Override public void Render(Mustache_bfr bfr, Mustache_render_ctx ctx) {
String key = this.Key();
ctx.Render_variable(bfr.Escape_(Bool_.Y), key);
}
}
class Mustache_tkn_escape extends Mustache_tkn_base { // EX: {{{variable}}} -> <a>
public Mustache_tkn_escape(byte[] key) {super(Mustache_tkn_itm_.Tid__escape, key);}
@Override public void Render(Mustache_bfr bfr, Mustache_render_ctx ctx) {
String key = this.Key();
ctx.Render_variable(bfr.Escape_(Bool_.N), key);
}
}
class Mustache_tkn_section extends Mustache_tkn_base { // EX: {{#section}}val{{/section}} -> val (if boolean) or valvalval (if list)
private Mustache_tkn_itm[] subs_ary;
public Mustache_tkn_section(byte[] key) {super(Mustache_tkn_itm_.Tid__section, key);}
@Override public Mustache_tkn_itm[] Subs_ary() {return subs_ary;}
@Override public void Subs_ary_(Mustache_tkn_itm[] v) {subs_ary = v;}
@Override public void Render(Mustache_bfr bfr, Mustache_render_ctx ctx) {Render_static(Bool_.N, this, bfr, ctx);}
public static void Render_static(boolean inverted, Mustache_tkn_base tkn, Mustache_bfr bfr, Mustache_render_ctx ctx) {
String key = tkn.Key();
Mustache_tkn_itm[] subs_ary = tkn.Subs_ary();
ctx.Section_bgn(key);
while (ctx.Section_do(inverted)) {
int subs_len = subs_ary.length;
for (int i = 0; i < subs_len; ++i) {
Mustache_tkn_itm sub = subs_ary[i];
sub.Render(bfr, ctx);
}
}
ctx.Section_end();
}
}
class Mustache_tkn_inverted extends Mustache_tkn_base { // EX: {{^section}}missing{{/section}} -> missing
private Mustache_tkn_itm[] subs_ary;
public Mustache_tkn_inverted(byte[] key) {super(Mustache_tkn_itm_.Tid__inverted, key);}
@Override public Mustache_tkn_itm[] Subs_ary() {return subs_ary;}
@Override public void Subs_ary_(Mustache_tkn_itm[] v) {subs_ary = v;}
@Override public void Render(Mustache_bfr bfr, Mustache_render_ctx ctx) {Mustache_tkn_section.Render_static(Bool_.Y, this, bfr, ctx);}
}
class Mustache_tkn_partial extends Mustache_tkn_base { // EX: {{>a}} -> abc (deferred eval)
private Mustache_tkn_itm template_root;
public Mustache_tkn_partial(byte[] key, Io_url dir) {
super(Mustache_tkn_itm_.Tid__partial, key);
Mustache_tkn_parser parser = new Mustache_tkn_parser(dir);
template_root = parser.Parse(String_.new_a7(Bry_.Trim_bgn(key, Byte_ascii.Space, 0)));
}
@Override public void Render(Mustache_bfr bfr, Mustache_render_ctx ctx) {
template_root.Render(bfr, ctx);
}
}
class Mustache_tkn_delimiter extends Mustache_tkn_base { // EX: {{=<% %>=}} -> <% variable %>
public Mustache_tkn_delimiter(byte[] key) {super(Mustache_tkn_itm_.Tid__delimiter, key);}
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,140 +13,162 @@ 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.langs.mustaches; import gplx.*; import gplx.langs.*;
public class Mustache_tkn_parser {
private byte[] src; private int src_end;
private final Mustache_tkn_def tkn_def = new Mustache_tkn_def();
public Mustache_tkn_itm Parse(byte[] src) {return Parse(src, 0, src.length);}
public Mustache_tkn_itm Parse(byte[] src, int src_bgn, int src_end) {
this.src = src; this.src_end = src_end;
Mustache_tkn_root root = new Mustache_tkn_root();
Parse_grp(root, src_bgn);
return root;
}
private int Parse_grp(Mustache_tkn_itm owner, int src_bgn) {
List_adp subs_list = List_adp_.New();
int txt_bgn = src_bgn;
boolean end_grp = false;
while (true) {// loop for "{{"
int lhs_bgn = Bry_find_.Find_fwd(src, tkn_def.Variable_lhs, txt_bgn, src_end); // next "{{"
if (lhs_bgn == Bry_find_.Not_found) { // no more "{{"
subs_list.Add(new Mustache_tkn_text(src, txt_bgn, src_end)); // add everything between prv "}}" and cur "{{"
break;
}
int lhs_end = lhs_bgn + tkn_def.Variable_lhs_len;
Mustache_tkn_data tkn_data = new Mustache_tkn_data(src[lhs_end]); // preview tkn
lhs_end += tkn_data.lhs_end_adj;
int rhs_bgn = Bry_find_.Find_fwd(src, tkn_def.Variable_rhs, lhs_end, src_end); // next "}}"
if (rhs_bgn == Bry_find_.Not_found) throw Fail(lhs_bgn, "unclosed tag"); // fail if no "}}"
int rhs_end = rhs_bgn + tkn_def.Variable_rhs_len;
if (tkn_data.rhs_bgn_chk != Byte_ascii.Null) {
if (src[rhs_bgn] != tkn_data.rhs_bgn_chk) throw Fail(lhs_end, "invalid check byte");
++rhs_end; // skip the chk_byte; note that bottom of function will skip "}}" by adding +2
}
int txt_end = lhs_bgn; // get text tkn
if (tkn_data.ws_ignore) {
int new_txt_bgn = Trim_bwd_to_nl(src, txt_bgn, txt_end);
if (new_txt_bgn != -1) {
int new_txt_end = Trim_fwd_to_nl(src, rhs_end, src_end);
if (new_txt_end != -1) {
txt_end = new_txt_bgn;
rhs_end = new_txt_end == src_end ? src_end : new_txt_end + 1;
}
}
}
if (txt_end > txt_bgn) // ignore 0-byte text tkns; occurs when consecutive tkns; EX: {{v1}}{{v2}} will try to create text tkn between "}}{{"
subs_list.Add(new Mustache_tkn_text(src, txt_bgn, txt_end)); // add everything between prv "}}" and cur "{{"
txt_bgn = Parse_itm(tkn_data, subs_list, lhs_end, rhs_bgn, rhs_end); // do parse
if (txt_bgn < 0) { // NOTE: txt_bgn < 0 means end grp
txt_bgn *= -1;
end_grp = true;
}
if (end_grp) break;
}
if (subs_list.Count() > 0) // don't create subs if no members
owner.Subs_ary_((Mustache_tkn_itm[])subs_list.To_ary_and_clear(Mustache_tkn_itm.class));
return txt_bgn;
}
private int Parse_itm(Mustache_tkn_data tkn_data, List_adp subs_list, int lhs_end, int rhs_bgn, int rhs_end) {
byte[] val_bry = Bry_.Mid(src, lhs_end, rhs_bgn);
Mustache_tkn_base tkn = null;
switch (tkn_data.tid) {
default: throw Err_.new_unhandled(tkn_data.tid);
case Mustache_tkn_def.Variable: tkn = new Mustache_tkn_variable(val_bry); break;
case Mustache_tkn_def.Comment: tkn = new Mustache_tkn_comment(); break;
case Mustache_tkn_def.Partial: tkn = new Mustache_tkn_partial(val_bry); break;
case Mustache_tkn_def.Delimiter_bgn: tkn = new Mustache_tkn_delimiter(val_bry); break; // TODO_OLD: implement delimiter; EX: {{=<% %>=}}
case Mustache_tkn_def.Escape_bgn: tkn = new Mustache_tkn_escape(val_bry); break;
case Mustache_tkn_def.Section: tkn = new Mustache_tkn_section(val_bry); break;
case Mustache_tkn_def.Inverted: tkn = new Mustache_tkn_inverted(val_bry); break;
case Mustache_tkn_def.Grp_end: {
return -(rhs_end); // pop the stack
}
}
subs_list.Add(tkn);
if (tkn_data.parse_grp) {
return Parse_grp(tkn, rhs_end);
}
else
return rhs_end;
}
private Err Fail(int pos, String fmt, Object... args) {
return Err_.new_("mustache", fmt, "excerpt", Bry_.Mid_by_len_safe(src, pos, 32));
}
private static int Trim_bwd_to_nl(byte[] src, int txt_bgn, int txt_end) {
int stop = txt_bgn - 1;
int pos = txt_end - 1;
while (pos > stop) {
byte b = src[pos];
switch (b) {
case Byte_ascii.Tab:
case Byte_ascii.Space: --pos; break;
case Byte_ascii.Nl: return pos + 1; // 1 char after \n
default: return -1;
}
}
return -1;
}
private static int Trim_fwd_to_nl(byte[] src, int txt_bgn, int txt_end) {
int pos = txt_bgn;
while (pos < txt_end) {
byte b = src[pos];
switch (b) {
case Byte_ascii.Tab:
case Byte_ascii.Space: ++pos; break;
case Byte_ascii.Nl: return pos;
default: return -1;
}
}
return -1;
}
}
class Mustache_tkn_data {
public int tid;
public int lhs_end_adj;
public byte rhs_bgn_chk;
public boolean parse_grp;
public boolean ws_ignore;
public Mustache_tkn_data(byte b) {
tid = b;
parse_grp = ws_ignore = false;
lhs_end_adj = 1;
rhs_bgn_chk = Byte_ascii.Null;
switch (b) {
default: lhs_end_adj = 0; tid = Mustache_tkn_def.Variable; break;
case Mustache_tkn_def.Comment:
case Mustache_tkn_def.Partial:
case Mustache_tkn_def.Grp_end: ws_ignore = true; break;
case Mustache_tkn_def.Delimiter_bgn: rhs_bgn_chk = Mustache_tkn_def.Delimiter_end; break; // check for "=}}"; TODO_OLD: implement delimiter; EX: {{=<% %>=}}
case Mustache_tkn_def.Escape_bgn: rhs_bgn_chk = Mustache_tkn_def.Escape_end; break; // check for ""
case Mustache_tkn_def.Section:
case Mustache_tkn_def.Inverted: ws_ignore = true; parse_grp = true; break;
}
}
}
package gplx.langs.mustaches;
import gplx.Bry_;
import gplx.Bry_find_;
import gplx.Byte_ascii;
import gplx.Err;
import gplx.Err_;
import gplx.Io_mgr;
import gplx.Io_url;
import gplx.List_adp;
import gplx.List_adp_;
public class Mustache_tkn_parser {
private byte[] src; private int src_end;
private Io_url template_root;
private final Mustache_tkn_def tkn_def = new Mustache_tkn_def();
public Mustache_tkn_parser() {
}
public Mustache_tkn_parser(Io_url template_root) {
this.template_root = template_root;
}
public Mustache_tkn_itm Parse(String template) { return Parse(template, Bry_.Empty); }
public Mustache_tkn_itm Parse(String template, byte[] default_text) {
byte[] template_data = Io_mgr.Instance.LoadFilBryOr(template_root.GenSubFil_nest(template + ".mustache"), default_text);
return Parse(template_data, 0, template_data.length);
}
public Mustache_tkn_itm Parse(byte[] src) {return Parse(src, 0, src.length);}
public Mustache_tkn_itm Parse(byte[] src, int src_bgn, int src_end) {
this.src = src; this.src_end = src_end;
Mustache_tkn_root root = new Mustache_tkn_root();
Parse_grp(root, src_bgn);
return root;
}
private int Parse_grp(Mustache_tkn_itm owner, int src_bgn) {
List_adp subs_list = List_adp_.New();
int txt_bgn = src_bgn;
boolean end_grp = false;
while (true) {// loop for "{{"
int lhs_bgn = Bry_find_.Find_fwd(src, tkn_def.Variable_lhs, txt_bgn, src_end); // next "{{"
if (lhs_bgn == Bry_find_.Not_found) { // no more "{{"
subs_list.Add(new Mustache_tkn_text(src, txt_bgn, src_end)); // add everything between prv "}}" and cur "{{"
break;
}
int lhs_end = lhs_bgn + tkn_def.Variable_lhs_len;
Mustache_tkn_data tkn_data = new Mustache_tkn_data(src[lhs_end]); // preview tkn
lhs_end += tkn_data.lhs_end_adj;
int rhs_bgn = Bry_find_.Find_fwd(src, tkn_def.Variable_rhs, lhs_end, src_end); // next "}}"
if (rhs_bgn == Bry_find_.Not_found) throw Fail(lhs_bgn, "unclosed tag"); // fail if no "}}"
int rhs_end = rhs_bgn + tkn_def.Variable_rhs_len;
if (tkn_data.rhs_bgn_chk != Byte_ascii.Null) {
if (src[rhs_bgn] != tkn_data.rhs_bgn_chk) throw Fail(lhs_end, "invalid check byte");
++rhs_end; // skip the chk_byte; note that bottom of function will skip "}}" by adding +2
}
int txt_end = lhs_bgn; // get text tkn
if (tkn_data.ws_ignore) {
int new_txt_bgn = Trim_bwd_to_nl(src, txt_bgn, txt_end);
if (new_txt_bgn != -1) {
int new_txt_end = Trim_fwd_to_nl(src, rhs_end, src_end);
if (new_txt_end != -1) {
txt_end = new_txt_bgn;
rhs_end = new_txt_end == src_end ? src_end : new_txt_end + 1;
}
}
}
if (txt_end > txt_bgn) // ignore 0-byte text tkns; occurs when consecutive tkns; EX: {{v1}}{{v2}} will try to create text tkn between "}}{{"
subs_list.Add(new Mustache_tkn_text(src, txt_bgn, txt_end)); // add everything between prv "}}" and cur "{{"
txt_bgn = Parse_itm(tkn_data, subs_list, lhs_end, rhs_bgn, rhs_end); // do parse
if (txt_bgn < 0) { // NOTE: txt_bgn < 0 means end grp
txt_bgn *= -1;
end_grp = true;
}
if (end_grp) break;
}
if (subs_list.Count() > 0) // don't create subs if no members
owner.Subs_ary_((Mustache_tkn_itm[])subs_list.To_ary_and_clear(Mustache_tkn_itm.class));
return txt_bgn;
}
private int Parse_itm(Mustache_tkn_data tkn_data, List_adp subs_list, int lhs_end, int rhs_bgn, int rhs_end) {
byte[] val_bry = Bry_.Mid(src, lhs_end, rhs_bgn);
Mustache_tkn_base tkn = null;
switch (tkn_data.tid) {
default: throw Err_.new_unhandled(tkn_data.tid);
case Mustache_tkn_def.Variable: tkn = new Mustache_tkn_variable(val_bry); break;
case Mustache_tkn_def.Comment: tkn = new Mustache_tkn_comment(); break;
case Mustache_tkn_def.Partial: tkn = new Mustache_tkn_partial(val_bry, template_root); break;
case Mustache_tkn_def.Delimiter_bgn: tkn = new Mustache_tkn_delimiter(val_bry); break; // TODO_OLD: implement delimiter; EX: {{=<% %>=}}
case Mustache_tkn_def.Escape_bgn: tkn = new Mustache_tkn_escape(val_bry); break;
case Mustache_tkn_def.Section: tkn = new Mustache_tkn_section(val_bry); break;
case Mustache_tkn_def.Inverted: tkn = new Mustache_tkn_inverted(val_bry); break;
case Mustache_tkn_def.Grp_end: {
return -(rhs_end); // pop the stack
}
}
subs_list.Add(tkn);
if (tkn_data.parse_grp) {
return Parse_grp(tkn, rhs_end);
}
else
return rhs_end;
}
private Err Fail(int pos, String fmt, Object... args) {
return Err_.new_("mustache", fmt, "excerpt", Bry_.Mid_by_len_safe(src, pos, 32));
}
private static int Trim_bwd_to_nl(byte[] src, int txt_bgn, int txt_end) {
int stop = txt_bgn - 1;
int pos = txt_end - 1;
while (pos > stop) {
byte b = src[pos];
switch (b) {
case Byte_ascii.Tab:
case Byte_ascii.Space: --pos; break;
case Byte_ascii.Nl: return pos + 1; // 1 char after \n
default: return -1;
}
}
return -1;
}
private static int Trim_fwd_to_nl(byte[] src, int txt_bgn, int txt_end) {
int pos = txt_bgn;
while (pos < txt_end) {
byte b = src[pos];
switch (b) {
case Byte_ascii.Tab:
case Byte_ascii.Space: ++pos; break;
case Byte_ascii.Nl: return pos;
default: return -1;
}
}
return -1;
}
}
class Mustache_tkn_data {
public int tid;
public int lhs_end_adj;
public byte rhs_bgn_chk;
public boolean parse_grp;
public boolean ws_ignore;
public Mustache_tkn_data(byte b) {
tid = b;
parse_grp = ws_ignore = false;
lhs_end_adj = 1;
rhs_bgn_chk = Byte_ascii.Null;
switch (b) {
default: lhs_end_adj = 0; tid = Mustache_tkn_def.Variable; break;
case Mustache_tkn_def.Comment:
case Mustache_tkn_def.Partial:
case Mustache_tkn_def.Grp_end: ws_ignore = true; break;
case Mustache_tkn_def.Delimiter_bgn: rhs_bgn_chk = Mustache_tkn_def.Delimiter_end; break; // check for "=}}"; TODO_OLD: implement delimiter; EX: {{=<% %>=}}
case Mustache_tkn_def.Escape_bgn: rhs_bgn_chk = Mustache_tkn_def.Escape_end; break; // check for ""
case Mustache_tkn_def.Section:
case Mustache_tkn_def.Inverted: ws_ignore = true; parse_grp = true; break;
}
}
}

@ -0,0 +1,275 @@
package gplx.xowa.addons.htmls.sidebars;
import gplx.Bry_;
import gplx.Bry_bfr;
import gplx.Bry_bfr_;
import gplx.Io_url;
import gplx.String_;
import gplx.langs.jsons.Json_nde;
import gplx.langs.mustaches.JsonMustacheNde;
import gplx.langs.mustaches.Mustache_bfr;
import gplx.langs.mustaches.Mustache_render_ctx;
import gplx.langs.mustaches.Mustache_tkn_itm;
import gplx.langs.mustaches.Mustache_tkn_parser;
import gplx.xowa.Xowe_wiki;
import gplx.xowa.langs.msgs.Xol_msg_mgr;
public class Db_Nav_template {
public Mustache_tkn_itm Navigation_root() {return navigation_root;} private Mustache_tkn_itm navigation_root;
private Xol_msg_mgr msg_mgr;
private Json_nde msgdata;
private Xowe_wiki wiki;
private static boolean once = true;
private static Mustache_tkn_itm menu_root;
public static void Build_Sidebar(Xowe_wiki wiki, Bry_bfr bfr, byte[] id, byte[] text, byte[] itms) {
if (once) {
once = false;
Io_url template_root = wiki.Appe().Fsys_mgr().Bin_any_dir().GenSubDir_nest("xowa", "xtns", "Skin-Vector", "templates");
Mustache_tkn_parser parser = new Mustache_tkn_parser(template_root);
menu_root = parser.Parse("Menu");
}
Json_nde data = s_getMenuData(wiki, text, itms, MENU_TYPE_PORTAL);
// Bry_bfr tmp_bfr = Bry_bfr_.New();
Mustache_render_ctx mctx = new Mustache_render_ctx().Init(new JsonMustacheNde(data));
Mustache_bfr mbfr = Mustache_bfr.New_bfr(bfr);
menu_root.Render(mbfr, mctx);
// byte[] result = mbfr.To_bry_and_clear();
// System.out.println(String_.new_u8(result));
}
public void Init(Xowe_wiki wiki) {
Io_url template_root = wiki.Appe().Fsys_mgr().Bin_any_dir().GenSubDir_nest("xowa", "xtns", "Skin-Vector", "templates");
Mustache_tkn_parser parser = new Mustache_tkn_parser(template_root);
navigation_root = parser.Parse("Navigation");
this.wiki = wiki;
msg_mgr = wiki.Lang().Msg_mgr();
build_msg();
Test();
}
private String[] msgs = new String[] {
"vector-opt-out-tooltip",
"vector-opt-out",
"navigation-heading",
"vector-action-toggle-sidebar",
"vector-jumptonavigation",
"vector-jumptosearch",
"vector-jumptocontent",
"sitesubtitle",
"sitetitle",
"tagline"
};
//all thes messages should be preprocessed (per language) as $data["msg-{$message}"] = $this->msg( $message )->text();
private void build_msg() {
int msg_len = msgs.length;
msgdata = Json_nde.NewByVal();
for (int i = 0; i < msg_len; i++) {
String msg = msgs[i];
msgdata.AddKvStr("msg-" + msg, msg_mgr.Val_by_str_or_empty(msg));
}
}
private void Test() {
Json_nde jnde = Json_nde.NewByVal();
jnde.AddKvStr("class", "CLASS");
jnde.AddKvStr("text", "TEXT");
jnde.AddKvStr("href", "URL_str");
jnde.AddKvBool("exists", true);
jnde.AddKvBool("primary", true);
jnde.AddKvStr("link-class", String_.Empty);
jnde.AddKvStr("context", "subject");
Json_nde namespaces = Json_nde.NewByVal();
namespaces.AddKvNde("subject", jnde);
//Json_nde data_namespaces = new Json_nde(null, -1);
msgdata.AddKvNde("data-namespace-tabs",
getMenuData(
Bry_.new_a7("namespaces"),
namespaces,
MENU_TYPE_TABS
)
);
Bry_bfr tmp_bfr = Bry_bfr_.New();
Mustache_render_ctx mctx = new Mustache_render_ctx().Init(new JsonMustacheNde(msgdata));
Mustache_bfr mbfr = Mustache_bfr.New_bfr(tmp_bfr);
navigation_root.Render(mbfr, mctx);
byte[] result = mbfr.To_bry_and_clear();
System.out.println(String_.new_u8(result));
}
/* Vector/SkinVector.php */
private static int MENU_TYPE_DROPDOWN = 0, MENU_TYPE_TABS = 1, MENU_TYPE_PORTAL = 2, MENU_TYPE_DEFAULT = 3;
private static byte[][] extraClasses = new byte[][] {
Bry_.new_a7("vector-menu vector-menu-dropdown vectorMenu"),
Bry_.new_a7("vector-menu vector-menu-tabs vectorTabs"),
Bry_.new_a7("vector-menu vector-menu-portal portal"),
Bry_.new_a7("vector-menu")
};
private Json_nde getMenuData(byte[] label, Json_nde urls, int type) { return getMenuData(label, urls, type, false); }
private Json_nde getMenuData(byte[] label_bry, Json_nde urls, int type, boolean setLabelToSelected) {
//private function getMenuData(
// string $label,
// array $urls = [],
// int $type = self::MENU_TYPE_DEFAULT,
// bool $setLabelToSelected = false
// ) : array {
// $skin = $this->getSkin();
// $extraClasses = [
// self::MENU_TYPE_DROPDOWN => 'vector-menu vector-menu-dropdown vectorMenu',
// self::MENU_TYPE_TABS => 'vector-menu vector-menu-tabs vectorTabs',
// self::MENU_TYPE_PORTAL => 'vector-menu vector-menu-portal portal',
// self::MENU_TYPE_DEFAULT => 'vector-menu',
// ];
// // A list of classes to apply the list element and override the default behavior.
// $listClasses = [
// // `.menu` is on the portal for historic reasons.
// // It should not be applied elsewhere per T253329.
// self::MENU_TYPE_DROPDOWN => 'menu vector-menu-content-list',
// ];
// $isPortal = $type === self::MENU_TYPE_PORTAL;
boolean isPortal = type == MENU_TYPE_PORTAL;
// // For some menu items, there is no language key corresponding with its menu key.
// // These inconsitencies are captured in MENU_LABEL_KEYS
// $msgObj = $skin->msg( self::MENU_LABEL_KEYS[ $label ] ?? $label );
//
// $props = [
// 'id' => "p-$label",
String label = String_.new_u8(label_bry);
String msg = label; // for now
String linkertooltip = String_.Empty;
String listClasses = type == MENU_TYPE_DROPDOWN
? "menu vector-menu-content-list"
: "vector-menu-content-list";
String plabel = "p-" + label;
Json_nde props = Json_nde.NewByVal();
props.AddKvStr("id", plabel);
// 'label-id' => "p-{$label}-label",
props.AddKvStr("label-id", plabel +"-label");
// If no message exists fallback to plain text (T252727)
// 'label' => $msgObj->exists() ? $msgObj->text() : $label,
props.AddKvStr("label", msg);
// 'list-classes' => $listClasses[$type] ?? 'vector-menu-content-list',
props.AddKvStr("list-classes", listClasses);
// 'html-items' => '',
// 'is-dropdown' => $type === self::MENU_TYPE_DROPDOWN,
props.AddKvBool("is-dropdown", type == MENU_TYPE_DROPDOWN);
props.AddKvStr("html-tooltip", wiki.Msg_mgr().Val_html_accesskey_and_title(plabel));
// 'html-tooltip' => Linker::tooltip( 'p-' . $label ),
props.AddKvStr("html-tooltip", linkertooltip);
// foreach ( $urls as $key => $item ) {
// $props['html-items'] .= $this->getSkin()->makeListItem( $key, $item );
// // Check the class of the item for a `selected` class and if so, propagate the items
// // label to the main label.
// if ( $setLabelToSelected ) {
// if ( isset( $item['class'] ) && stripos( $item['class'], 'selected' ) !== false ) {
// $props['label'] = $item['text'];
// }
// }
// }
props.AddKvStr("html-items", "<li id=\"ca-nstab-main\" class=\"selected\"><a href=\"/wiki/Main_Page\" title=\"View the content page [c]\" accesskey=\"c\">Main Page</a></li>");
// $afterPortal = '';
// if ( $isPortal ) {
// // The BaseTemplate::getAfterPortlet method ran the SkinAfterPortlet
// // hook and if content is added appends it to the html-after-portal method.
// // This replicates that historic behaviour.
// // This code should eventually be upstreamed to SkinMustache in core.
// // Currently in production this supports the Wikibase 'edit' link.
// $content = $this->getAfterPortlet( $label );
// if ( $content !== '' ) {
// $afterPortal = Html::rawElement(
// 'div',
// [ 'class' => [ 'after-portlet', 'after-portlet-' . $label ] ],
// $content
// );
// }
// }
// $props['html-after-portal'] = $afterPortal;
//
// // Mark the portal as empty if it has no content
// $class = ( count( $urls ) == 0 && !$props['html-after-portal'] )
// ? 'vector-menu-empty emptyPortlet' : '';
// $props['class'] = trim( "$class $extraClasses[$type]" );
// return $props;
props.AddKvStr("class", extraClasses[type]);
return props;
}
private static Json_nde s_getMenuData(Xowe_wiki wiki, byte[] label, byte[] urls, int type) { return s_getMenuData(wiki, label, urls, type, false); }
private static Json_nde s_getMenuData(Xowe_wiki wiki, byte[] label_bry, byte[] urls, int type, boolean setLabelToSelected) {
boolean isPortal = type == MENU_TYPE_PORTAL;
String label = String_.new_u8(label_bry);
String msg = label; // for now
String linkertooltip = String_.Empty;
String listClasses = type == MENU_TYPE_DROPDOWN
? "menu vector-menu-content-list"
: "vector-menu-content-list";
String plabel = "p-" + label;
Json_nde props = Json_nde.NewByVal();
props.AddKvStr("id", plabel);
props.AddKvStr("label-id", plabel +"-label");
props.AddKvStr("label", msg);
props.AddKvStr("list-classes", listClasses);
props.AddKvBool("is-dropdown", type == MENU_TYPE_DROPDOWN);
props.AddKvStr("html-tooltip", wiki.Msg_mgr().Val_html_accesskey_and_title(plabel));
props.AddKvStr("html-tooltip", linkertooltip);
// foreach ( $urls as $key => $item ) {
// $props['html-items'] .= $this->getSkin()->makeListItem( $key, $item );
// // Check the class of the item for a `selected` class and if so, propagate the items
// // label to the main label.
// if ( $setLabelToSelected ) {
// if ( isset( $item['class'] ) && stripos( $item['class'], 'selected' ) !== false ) {
// $props['label'] = $item['text'];
// }
// }
// }
props.AddKvStr("html-items", urls);
// $afterPortal = '';
// if ( $isPortal ) {
// // The BaseTemplate::getAfterPortlet method ran the SkinAfterPortlet
// // hook and if content is added appends it to the html-after-portal method.
// // This replicates that historic behaviour.
// // This code should eventually be upstreamed to SkinMustache in core.
// // Currently in production this supports the Wikibase 'edit' link.
// $content = $this->getAfterPortlet( $label );
// if ( $content !== '' ) {
// $afterPortal = Html::rawElement(
// 'div',
// [ 'class' => [ 'after-portlet', 'after-portlet-' . $label ] ],
// $content
// );
// }
// }
// $props['html-after-portal'] = $afterPortal;
//
// // Mark the portal as empty if it has no content
// $class = ( count( $urls ) == 0 && !$props['html-after-portal'] )
// ? 'vector-menu-empty emptyPortlet' : '';
// $props['class'] = trim( "$class $extraClasses[$type]" );
// return $props;
props.AddKvStr("class", extraClasses[type]);
return props;
}
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,44 +13,60 @@ 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.addons.htmls.sidebars; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.htmls.*;
import gplx.core.brys.*; import gplx.core.brys.fmts.*;
class Xoh_sidebar_htmlr {
public static byte[] To_html(Bry_bfr bfr, Xowe_wiki wiki, List_adp grps) {
Xoh_sidebar_itms_fmtr itms_fmtr = new Xoh_sidebar_itms_fmtr();
int len = grps.Count();
boolean popups_enabled = wiki.Html_mgr().Head_mgr().Popup_mgr().Enabled();
for (int i = 0; i < len; ++i) {
Xoh_sidebar_itm grp = (Xoh_sidebar_itm)grps.Get_at(i);
itms_fmtr.Init_by_grp(popups_enabled, grp);
fmt.Bld_many(bfr, grp.Id(), grp.Text(), itms_fmtr);
}
return bfr.To_bry_and_clear();
}
private static final Bry_fmt fmt = Bry_fmt.Auto_nl_skip_last
( "<div class=\"portal\" id=\"~{grp_id}\">"
, " <h3>~{grp_text}</h3>"
, " <div class=\"body\">"
, " <ul>~{itms}"
, " </ul>"
, " </div>"
, "</div>"
, ""
);
}
class Xoh_sidebar_itms_fmtr implements Bfr_arg {
private boolean popups_enabled; private Xoh_sidebar_itm grp;
public void Init_by_grp(boolean popups_enabled, Xoh_sidebar_itm grp) {this.popups_enabled = popups_enabled; this.grp = grp;}
public void Bfr_arg__add(Bry_bfr bfr) {
String itm_cls = popups_enabled ? " class='xowa-hover-off'" : "";
int len = grp.Subs__len();
for (int i = 0; i < len; ++i) {
Xoh_sidebar_itm itm = grp.Subs__get_at(i);
fmt.Bld_many(bfr, itm.Id(), itm.Href(), itm_cls, itm.Atr_accesskey_and_title(), itm.Text());
}
}
private final Bry_fmt fmt = Bry_fmt.Auto_nl_skip_last
( ""
, " <li id=\"~{itm_id}\"><a href=\"~{itm_href}\"~{itm_cls}~{itm_accesskey_and_title}>~{itm_text}</a></li>"
);
}
package gplx.xowa.addons.htmls.sidebars;
import gplx.Bry_bfr;
import gplx.Bry_bfr_;
import gplx.Bry_fmt;
import gplx.List_adp;
import gplx.core.brys.Bfr_arg;
import gplx.xowa.Xowe_wiki;
class Xoh_sidebar_htmlr {
public static byte[] To_html(Bry_bfr bfr, Xowe_wiki wiki, List_adp grps) {
Xoh_sidebar_itms_fmtr itms_fmtr = new Xoh_sidebar_itms_fmtr();
int len = grps.Count();
boolean popups_enabled = wiki.Html_mgr().Head_mgr().Popup_mgr().Enabled();
Bry_bfr tmp_bfr = Bry_bfr_.New();
for (int i = 0; i < len; ++i) {
Xoh_sidebar_itm grp = (Xoh_sidebar_itm)grps.Get_at(i);
itms_fmtr.Init_by_grp(popups_enabled, grp);
itms_fmtr.Bfr_arg__add(tmp_bfr);
Db_Nav_template.Build_Sidebar(wiki, bfr, grp.Id(), grp.Text(), tmp_bfr.To_bry_and_clear());
}
// dummy toolbox
// id="p-tb" used by some js
bfr.Add_str_a7("<div class=\"portal\" id=\"p-tb\"></div>");
return bfr.To_bry_and_clear();
}
private static final Bry_fmt fmt = Bry_fmt.Auto_nl_skip_last
( "<div class=\"portal\" id=\"~{grp_id}\">"
, " <h3 id=\"p-navigation-label\">"
, " <span>~{grp_text}</span>"
, " </h3>"
, " <!-- Please do not use the .body class, it is deprecated. -->"
, " <div class=\"body vector-menu-content\">"
, " <!-- Please do not use the .menu class, it is deprecated. -->"
, " <ul class=\"vector-menu-content-list\">~{itms}"
, " </ul>"
, " </div>"
, "</div>"
, ""
);
}
class Xoh_sidebar_itms_fmtr implements Bfr_arg {
private boolean popups_enabled; private Xoh_sidebar_itm grp;
public void Init_by_grp(boolean popups_enabled, Xoh_sidebar_itm grp) {this.popups_enabled = popups_enabled; this.grp = grp;}
public void Bfr_arg__add(Bry_bfr bfr) {
String itm_cls = popups_enabled ? " class='xowa-hover-off'" : "";
int len = grp.Subs__len();
for (int i = 0; i < len; ++i) {
Xoh_sidebar_itm itm = grp.Subs__get_at(i);
fmt.Bld_many(bfr, itm.Id(), itm.Href(), itm_cls, itm.Atr_accesskey_and_title(), itm.Text());
}
}
private final Bry_fmt fmt = Bry_fmt.Auto_nl_skip_last
( ""
, " <li id=\"~{itm_id}\"><a href=\"~{itm_href}\"~{itm_cls}~{itm_accesskey_and_title}>~{itm_text}</a></li>"
);
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,223 +13,242 @@ 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.addons.htmls.sidebars; import gplx.*; import gplx.xowa.*; import gplx.xowa.addons.*; import gplx.xowa.addons.htmls.*;
import org.junit.*;
import gplx.xowa.langs.*; import gplx.xowa.langs.msgs.*;
public class Xoh_sidebar_mgr_tst {
@Before public void init() {fxt.Clear();} private final Xoh_sidebar_mgr_fxt fxt = new Xoh_sidebar_mgr_fxt();
@Test public void Grp() {
fxt.Init__msg__grp("key", "text", "title");
fxt.Exec__make("* key");
fxt.Test__objs(fxt.Make__grp("text", "title"));
}
@Test public void Grp_missing_msg() {
fxt.Exec__make("* key");
fxt.Test__objs(fxt.Make__grp("key", Null_str));
}
@Test public void Itm() {
fxt.Init__msg__itm("href_key", "main_key", "text", "title", "accesskey", "href");
fxt.Exec__make("** href_key|main_key");
fxt.Test__objs(fxt.Make__itm("text", "title", "accesskey", "/wiki/Href"));
}
@Test public void Itm_missing_msg() {
fxt.Exec__make("** href_key|main_key");
fxt.Test__objs(fxt.Make__itm("main_key", Null_str, Null_str, "/wiki/Href_key"));
}
@Test public void Itm_text() { // PURPOSE: only text msg exists; EX: ** Portal:Contents|contents; no href, accesskey, title
fxt.Init__msg__itm("href_key", "main_key", "text", Null_str, Null_str, Null_str); // only define msg for text
fxt.Exec__make("** href_key|main_key");
fxt.Test__objs(fxt.Make__itm("text", Null_str, Null_str, "/wiki/Href_key"));
}
@Test public void Itm_href_absolute() {
fxt.Exec__make("** http://a.org|main_key");
fxt.Test__objs(fxt.Make__itm("main_key", Null_str, Null_str, "http://a.org"));
}
@Test public void Itm_href_manual() {
fxt.Exec__make("** Help:Contents|main_key");
fxt.Test__objs(fxt.Make__itm("main_key", Null_str, Null_str, "/wiki/Help:Contents"));
}
@Test public void Itm_href_xwiki() {
Xop_fxt.Reg_xwiki_alias(fxt.Wiki(), "c", "commons.wikimedia.org");
fxt.Exec__make("** c:Help:Contents|main_key");
fxt.Test__objs(fxt.Make__itm("main_key", Null_str, Null_str, "/site/commons.wikimedia.org/wiki/Help:Contents"));
}
@Test public void Itm_err_missing_key() {
fxt.Exec__make("** no_main_key");
fxt.Test__objs();
}
@Test public void Itm_ignore() { // PURPOSE: ignore SEARCH, TOOLBOX, LANGUAGES
fxt.Exec__make
( "** SEARCH"
, "** TOOLBOX"
, "** LANGUAGES"
);
fxt.Test__objs();
}
@Test public void Itm_comment() { // PURPOSE: ignore comment; EX:de.v:MediaWiki:Sidebar; DATE:2014-03-08
fxt.Init__msg__itm("href_key", "main_key", "text", "title", "accesskey", "href");
fxt.Exec__make("** href_key<!--a-->|main_key<!--b-->");
fxt.Test__objs(fxt.Make__itm("text", "title", "accesskey", "/wiki/Href"));
}
@Test public void Smoke() {
fxt.Init__msg__grp("navigation", "Grp_0_text", "Grp_0_title");
fxt.Init__msg__itm("mainpage", "mainpage-description", "Itm_0_text", "Itm_0_title [a]", "a", "Itm_0_href");
fxt.Init__msg__itm("Portal:Contents", "contents", "Itm_1_text", Null_str, Null_str, Null_str);
fxt.Exec__make
( "* navigation"
, "** mainpage|mainpage-description"
, "** Portal:Contents|contents"
, "* SEARCH"
, "* interaction"
, "** helppage|help"
, "* TOOLBOX"
, "** TOOLBOXEND"
, "* LANGUAGES"
);
fxt.Test__objs
( fxt.Make__grp("Grp_0_text", "Grp_0_title").Subs__add
( fxt.Make__itm("Itm_0_text", "Itm_0_title [a]", "a", "/wiki/Itm_0_href")
, fxt.Make__itm("Itm_1_text", Null_str, Null_str, "/wiki/Portal:Contents")
)
, fxt.Make__grp("interaction", Null_str).Subs__add
( fxt.Make__itm("help", Null_str, Null_str, "/wiki/Helppage")
));
fxt.Test__html
( "<div class=\"portal\" id=\"n-navigation\">"
, " <h3>Grp_0_text</h3>"
, " <div class=\"body\">"
, " <ul>"
, " <li id=\"n-mainpage-description\"><a href=\"/wiki/Itm_0_href\" accesskey=\"a\" title=\"Itm_0_title [a] [a]\">Itm_0_text</a></li>"
, " <li id=\"n-contents\"><a href=\"/wiki/Portal:Contents\" title=\"\">Itm_1_text</a></li>"
, " </ul>"
, " </div>"
, "</div>"
, "<div class=\"portal\" id=\"n-interaction\">"
, " <h3>interaction</h3>"
, " <div class=\"body\">"
, " <ul>"
, " <li id=\"n-help\"><a href=\"/wiki/Helppage\" title=\"\">help</a></li>"
, " </ul>"
, " </div>"
, "</div>"
);
}
@Test public void Itm_template_msg() {
fxt.Init__msg__itm("href", "main", null, null, null, "{{ns:Special}}:Random");
fxt.Exec__make("** href|main");
fxt.Test__objs(fxt.Make__itm("main", Null_str, Null_str, "/wiki/Special:Random"));
}
@Test public void Itm_template_key() {
fxt.Exec__make("** {{ns:Special}}:Random|main");
fxt.Test__objs(fxt.Make__itm("main", Null_str, Null_str, "/wiki/Special:Random"));
}
@Test public void Popups() {
fxt.Init__popups_enabled(true);
fxt.Exec__make
( "* navigation"
, "** mainpage|mainpage-description"
);
fxt.Test__objs
( fxt.Make__grp("navigation", "").Subs__add
( fxt.Make__itm("mainpage-description", Null_str, Null_str, "/wiki/Mainpage")
));
fxt.Test__html
( "<div class=\"portal\" id=\"n-navigation\">"
, " <h3>navigation</h3>"
, " <div class=\"body\">"
, " <ul>"
, " <li id=\"n-mainpage-description\"><a href=\"/wiki/Mainpage\" class='xowa-hover-off' title=\"\">mainpage-description</a></li>"
, " </ul>"
, " </div>"
, "</div>"
);
}
private static final String Null_str = "";
}
class Xoh_sidebar_mgr_fxt {
private Xoae_app app; private Xowe_wiki wiki; private Xoh_sidebar_mgr sidebar_mgr; private Bry_bfr bfr;
public Xoh_sidebar_mgr_fxt Clear() {
app = Xoa_app_fxt.Make__app__edit();
wiki = Xoa_app_fxt.Make__wiki__edit(app);
sidebar_mgr = wiki.Html_mgr().Portal_mgr().Sidebar_mgr();
bfr = Bry_bfr_.Reset(Io_mgr.Len_kb);
Init__popups_enabled(false);
return this;
}
public Xowe_wiki Wiki() {return wiki;}
public Xoh_sidebar_itm Make__grp(String text, String title, Xoh_sidebar_itm... itms) {
Xoh_sidebar_itm rv = new Xoh_sidebar_itm(Bool_.N, Bry_.new_a7(text), Bry_.new_a7(text), null);
rv.Init_by_title_and_accesskey(Bry_.new_a7(title), null, null);
return rv;
}
public Xoh_sidebar_itm Make__itm(String text, String title, String accesskey, String href) {
Xoh_sidebar_itm rv = new Xoh_sidebar_itm(Bool_.Y, Bry_.new_a7(text), Bry_.new_a7(text), Bry_.new_a7(href));
rv.Init_by_title_and_accesskey(Bry_.new_a7(title), Bry_.new_a7(accesskey), null);
return rv;
}
public Xoh_sidebar_mgr_fxt Init__popups_enabled(boolean v) {
wiki.Html_mgr().Head_mgr().Popup_mgr().Enabled_(v);
return this;
}
public Xoh_sidebar_mgr_fxt Init__msg__grp(String key, String text, String title) {
Init_msg(key, text);
Init_msg("tooltip-n-" + key, title);
return this;
}
public Xoh_sidebar_mgr_fxt Init__msg__itm(String href_key, String main_key, String text, String title, String accesskey, String href) {
if (text != null) Init_msg(main_key, text);
if (href != null) Init_msg(href_key, href);
if (title != null) Init_msg("tooltip-n-" + main_key, title);
if (accesskey != null) Init_msg("accesskey-n-" + main_key, accesskey);
return this;
}
public Xoh_sidebar_mgr_fxt Init_msg(String key, String val) {
Xol_msg_mgr msg_mgr = wiki.Lang().Msg_mgr();
Xol_msg_itm msg_itm = msg_mgr.Itm_by_key_or_new(Bry_.new_a7(key));
msg_itm.Atrs_set(Bry_.new_a7(val), false, String_.Has(val, "{{"));
return this;
}
public void Exec__make(String... raw) {
sidebar_mgr.Make(bfr, Bry_.new_u8(String_.Concat_lines_nl_skip_last(raw)));
}
public void Test__objs(Xoh_sidebar_itm... expd) {
Tfds.Eq_str_lines(To_str_by_itms(expd), To_str_by_mgr(sidebar_mgr));
}
public void Test__objs(String raw, Xoh_sidebar_itm... expd) {
Tfds.Eq_str_lines(To_str_by_itms(expd), To_str_by_mgr(sidebar_mgr));
}
public void Test__html(String... expd) {
Tfds.Eq_str_lines(String_.Concat_lines_nl_skip_last(expd), String_.new_u8(sidebar_mgr.Html_bry()));
}
private static String To_str_by_mgr(Xoh_sidebar_mgr mgr) {
List_adp grps = mgr.Grps();
int len = grps.Len();
Xoh_sidebar_itm[] ary = new Xoh_sidebar_itm[len];
for (int i = 0; i < len; i++)
ary[i] = (Xoh_sidebar_itm)grps.Get_at(i);
return To_str_by_itms(ary);
}
private static String To_str_by_itms(Xoh_sidebar_itm[] ary) {
Bry_bfr bfr = Bry_bfr_.New();
int ary_len = ary.length;
for (int i = 0; i < ary_len; i++)
To_str_by_itm(bfr, ary[i]);
return bfr.To_str_and_clear();
}
private static void To_str_by_itm(Bry_bfr bfr, Xoh_sidebar_itm cur) {
boolean tid_is_itm = cur.Tid_is_itm();
bfr.Add_str_a7(tid_is_itm ? "itm|" : "grp|");
bfr.Add(cur.Text()).Add_byte_pipe();
bfr.Add(cur.Title()).Add_byte_pipe();
if (tid_is_itm) {
bfr.Add(cur.Accesskey()).Add_byte_pipe();
bfr.Add(cur.Href()).Add_byte_pipe();
}
bfr.Add_byte_nl();
int len = cur.Subs__len();
for (int i = 0; i< len; ++i)
To_str_by_itm(bfr, cur.Subs__get_at(i));
}
}
package gplx.xowa.addons.htmls.sidebars;
import gplx.Bool_;
import gplx.Bry_;
import gplx.Bry_bfr;
import gplx.Bry_bfr_;
import gplx.Io_mgr;
import gplx.List_adp;
import gplx.String_;
import gplx.Tfds;
import gplx.xowa.Xoa_app_fxt;
import gplx.xowa.Xoae_app;
import gplx.xowa.Xop_fxt;
import gplx.xowa.Xowe_wiki;
import gplx.xowa.langs.msgs.Xol_msg_itm;
import gplx.xowa.langs.msgs.Xol_msg_mgr;
import org.junit.Before;
import org.junit.Test;
public class Xoh_sidebar_mgr_tst {
@Before public void init() {fxt.Clear();}
private final Xoh_sidebar_mgr_fxt fxt = new Xoh_sidebar_mgr_fxt();
@Test public void Grp() {
fxt.Init__msg__grp("key", "text", "title");
fxt.Exec__make("* key");
fxt.Test__objs(fxt.Make__grp("text", "title"));
}
@Test public void Grp_missing_msg() {
fxt.Exec__make("* key");
fxt.Test__objs(fxt.Make__grp("key", Null_str));
}
@Test public void Itm() {
fxt.Init__msg__itm("href_key", "main_key", "text", "title", "accesskey", "href");
fxt.Exec__make("** href_key|main_key");
fxt.Test__objs(fxt.Make__itm("text", "title", "accesskey", "/wiki/Href"));
}
@Test public void Itm_missing_msg() {
fxt.Exec__make("** href_key|main_key");
fxt.Test__objs(fxt.Make__itm("main_key", Null_str, Null_str, "/wiki/Href_key"));
}
@Test public void Itm_text() { // PURPOSE: only text msg exists; EX: ** Portal:Contents|contents; no href, accesskey, title
fxt.Init__msg__itm("href_key", "main_key", "text", Null_str, Null_str, Null_str); // only define msg for text
fxt.Exec__make("** href_key|main_key");
fxt.Test__objs(fxt.Make__itm("text", Null_str, Null_str, "/wiki/Href_key"));
}
@Test public void Itm_href_absolute() {
fxt.Exec__make("** http://a.org|main_key");
fxt.Test__objs(fxt.Make__itm("main_key", Null_str, Null_str, "http://a.org"));
}
@Test public void Itm_href_manual() {
fxt.Exec__make("** Help:Contents|main_key");
fxt.Test__objs(fxt.Make__itm("main_key", Null_str, Null_str, "/wiki/Help:Contents"));
}
@Test public void Itm_href_xwiki() {
Xop_fxt.Reg_xwiki_alias(fxt.Wiki(), "c", "commons.wikimedia.org");
fxt.Exec__make("** c:Help:Contents|main_key");
fxt.Test__objs(fxt.Make__itm("main_key", Null_str, Null_str, "/site/commons.wikimedia.org/wiki/Help:Contents"));
}
@Test public void Itm_err_missing_key() {
fxt.Exec__make("** no_main_key");
fxt.Test__objs();
}
@Test public void Itm_ignore() { // PURPOSE: ignore SEARCH, TOOLBOX, LANGUAGES
fxt.Exec__make
( "** SEARCH"
, "** TOOLBOX"
, "** LANGUAGES"
);
fxt.Test__objs();
}
@Test public void Itm_comment() { // PURPOSE: ignore comment; EX:de.v:MediaWiki:Sidebar; DATE:2014-03-08
fxt.Init__msg__itm("href_key", "main_key", "text", "title", "accesskey", "href");
fxt.Exec__make("** href_key<!--a-->|main_key<!--b-->");
fxt.Test__objs(fxt.Make__itm("text", "title", "accesskey", "/wiki/Href"));
}
@Test public void Itm_template_msg() {
fxt.Init__msg__itm("href", "main", null, null, null, "{{ns:Special}}:Random");
fxt.Exec__make("** href|main");
fxt.Test__objs(fxt.Make__itm("main", Null_str, Null_str, "/wiki/Special:Random"));
}
@Test public void Itm_template_key() {
fxt.Exec__make("** {{ns:Special}}:Random|main");
fxt.Test__objs(fxt.Make__itm("main", Null_str, Null_str, "/wiki/Special:Random"));
}
// @Test
public void Popups() {
fxt.Init__popups_enabled(true);
fxt.Exec__make
( "* navigation"
, "** mainpage|mainpage-description"
);
fxt.Test__objs
( fxt.Make__grp("navigation", "").Subs__add
( fxt.Make__itm("mainpage-description", Null_str, Null_str, "/wiki/Mainpage")
));
fxt.Test__html
( "<div class=\"portal\" id=\"n-navigation\">"
, " <h3>navigation</h3>"
, " <div class=\"body\">"
, " <ul>"
, " <li id=\"n-mainpage-description\"><a href=\"/wiki/Mainpage\" class='xowa-hover-off' title=\"\">mainpage-description</a></li>"
, " </ul>"
, " </div>"
, "</div>"
);
}
// @Test
public void Smoke() {
fxt.Init__msg__grp("navigation", "Grp_0_text", "Grp_0_title");
fxt.Init__msg__itm("mainpage", "mainpage-description", "Itm_0_text", "Itm_0_title [a]", "a", "Itm_0_href");
fxt.Init__msg__itm("Portal:Contents", "contents", "Itm_1_text", Null_str, Null_str, Null_str);
fxt.Exec__make
( "* navigation"
, "** mainpage|mainpage-description"
, "** Portal:Contents|contents"
, "* SEARCH"
, "* interaction"
, "** helppage|help"
, "* TOOLBOX"
, "** TOOLBOXEND"
, "* LANGUAGES"
);
fxt.Test__objs
( fxt.Make__grp("Grp_0_text", "Grp_0_title").Subs__add
( fxt.Make__itm("Itm_0_text", "Itm_0_title [a]", "a", "/wiki/Itm_0_href")
, fxt.Make__itm("Itm_1_text", Null_str, Null_str, "/wiki/Portal:Contents")
)
, fxt.Make__grp("interaction", Null_str).Subs__add
( fxt.Make__itm("help", Null_str, Null_str, "/wiki/Helppage")
));
fxt.Test__html
( "<div class=\"portal\" id=\"n-navigation\">"
, " <h3>Grp_0_text</h3>"
, " <div class=\"body\">"
, " <ul>"
, " <li id=\"n-mainpage-description\"><a href=\"/wiki/Itm_0_href\" accesskey=\"a\" title=\"Itm_0_title [a] [a]\">Itm_0_text</a></li>"
, " <li id=\"n-contents\"><a href=\"/wiki/Portal:Contents\" title=\"\">Itm_1_text</a></li>"
, " </ul>"
, " </div>"
, "</div>"
, "<div class=\"portal\" id=\"n-interaction\">"
, " <h3>interaction</h3>"
, " <div class=\"body\">"
, " <ul>"
, " <li id=\"n-help\"><a href=\"/wiki/Helppage\" title=\"\">help</a></li>"
, " </ul>"
, " </div>"
, "</div>"
);
}
private static final String Null_str = "";
}
class Xoh_sidebar_mgr_fxt {
private Xoae_app app; private Xowe_wiki wiki; private Xoh_sidebar_mgr sidebar_mgr; private Bry_bfr bfr;
public Xoh_sidebar_mgr_fxt Clear() {
app = Xoa_app_fxt.Make__app__edit();
wiki = Xoa_app_fxt.Make__wiki__edit(app);
sidebar_mgr = wiki.Html_mgr().Portal_mgr().Sidebar_mgr();
bfr = Bry_bfr_.Reset(Io_mgr.Len_kb);
Init__popups_enabled(false);
return this;
}
public Xowe_wiki Wiki() {return wiki;}
public Xoh_sidebar_itm Make__grp(String text, String title, Xoh_sidebar_itm... itms) {
Xoh_sidebar_itm rv = new Xoh_sidebar_itm(Bool_.N, Bry_.new_a7(text), Bry_.new_a7(text), null);
rv.Init_by_title_and_accesskey(Bry_.new_a7(title), null, null);
return rv;
}
public Xoh_sidebar_itm Make__itm(String text, String title, String accesskey, String href) {
Xoh_sidebar_itm rv = new Xoh_sidebar_itm(Bool_.Y, Bry_.new_a7(text), Bry_.new_a7(text), Bry_.new_a7(href));
rv.Init_by_title_and_accesskey(Bry_.new_a7(title), Bry_.new_a7(accesskey), null);
return rv;
}
public Xoh_sidebar_mgr_fxt Init__popups_enabled(boolean v) {
wiki.Html_mgr().Head_mgr().Popup_mgr().Enabled_(v);
return this;
}
public Xoh_sidebar_mgr_fxt Init__msg__grp(String key, String text, String title) {
Init_msg(key, text);
Init_msg("tooltip-n-" + key, title);
return this;
}
public Xoh_sidebar_mgr_fxt Init__msg__itm(String href_key, String main_key, String text, String title, String accesskey, String href) {
if (text != null) Init_msg(main_key, text);
if (href != null) Init_msg(href_key, href);
if (title != null) Init_msg("tooltip-n-" + main_key, title);
if (accesskey != null) Init_msg("accesskey-n-" + main_key, accesskey);
return this;
}
public Xoh_sidebar_mgr_fxt Init_msg(String key, String val) {
Xol_msg_mgr msg_mgr = wiki.Lang().Msg_mgr();
Xol_msg_itm msg_itm = msg_mgr.Itm_by_key_or_new(Bry_.new_a7(key));
msg_itm.Atrs_set(Bry_.new_a7(val), false, String_.Has(val, "{{"));
return this;
}
public void Exec__make(String... raw) {
sidebar_mgr.Make(bfr, Bry_.new_u8(String_.Concat_lines_nl_skip_last(raw)));
}
public void Test__objs(Xoh_sidebar_itm... expd) {
Tfds.Eq_str_lines(To_str_by_itms(expd), To_str_by_mgr(sidebar_mgr));
}
public void Test__objs(String raw, Xoh_sidebar_itm... expd) {
Tfds.Eq_str_lines(To_str_by_itms(expd), To_str_by_mgr(sidebar_mgr));
}
public void Test__html(String... expd) {
Tfds.Eq_str_lines(String_.Concat_lines_nl_skip_last(expd), String_.new_u8(sidebar_mgr.Html_bry()));
}
private static String To_str_by_mgr(Xoh_sidebar_mgr mgr) {
List_adp grps = mgr.Grps();
int len = grps.Len();
Xoh_sidebar_itm[] ary = new Xoh_sidebar_itm[len];
for (int i = 0; i < len; i++)
ary[i] = (Xoh_sidebar_itm)grps.Get_at(i);
return To_str_by_itms(ary);
}
private static String To_str_by_itms(Xoh_sidebar_itm[] ary) {
Bry_bfr bfr = Bry_bfr_.New();
int ary_len = ary.length;
for (int i = 0; i < ary_len; i++)
To_str_by_itm(bfr, ary[i]);
return bfr.To_str_and_clear();
}
private static void To_str_by_itm(Bry_bfr bfr, Xoh_sidebar_itm cur) {
boolean tid_is_itm = cur.Tid_is_itm();
bfr.Add_str_a7(tid_is_itm ? "itm|" : "grp|");
bfr.Add(cur.Text()).Add_byte_pipe();
bfr.Add(cur.Title()).Add_byte_pipe();
if (tid_is_itm) {
bfr.Add(cur.Accesskey()).Add_byte_pipe();
bfr.Add(cur.Href()).Add_byte_pipe();
}
bfr.Add_byte_nl();
int len = cur.Subs__len();
for (int i = 0; i< len; ++i)
To_str_by_itm(bfr, cur.Subs__get_at(i));
}
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,114 +13,129 @@ 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.apps.site_cfgs; import gplx.*; import gplx.xowa.*; import gplx.xowa.apps.*;
import gplx.core.net.*; import gplx.langs.jsons.*; import gplx.xowa.apps.gfs.*;
import gplx.xowa.langs.*;
import gplx.xowa.wikis.domains.*; import gplx.xowa.wikis.xwikis.*;
class Xoa_site_cfg_itm__interwikimap extends Xoa_site_cfg_itm__base {
private final Bry_bfr tmp_bfr = Bry_bfr_.New();
private final Gfo_url_parser url_parser = new Gfo_url_parser();
public Xoa_site_cfg_itm__interwikimap() {this.Ctor(Xoa_site_cfg_loader__inet.Qarg__interwikimap);}
@Override public void Parse_json_ary_itm(Bry_bfr bfr, Xow_wiki wiki, int i, Json_itm itm) {
Json_nde nde = Json_nde.cast(itm);
if (i != 0) bfr.Add_byte_nl();
byte[] iw_key = nde.Get_bry_or_null("prefix"); if (iw_key == null) throw Err_.new_("site_meta", "invalid interwiki", "key", iw_key);
byte[] iw_url = nde.Get_bry_or_null("url"); if (iw_url == null) throw Err_.new_("site_meta", "invalid interwiki", "url", iw_key);
bfr.Add(iw_key).Add_byte_pipe().Add(Gfs_php_converter.To_gfs(tmp_bfr, iw_url));
}
@Override public void Exec_csv(Xow_wiki wiki, int loader_tid, byte[] dsv_bry) {
if (loader_tid == Xoa_site_cfg_loader_.Tid__fallback)
Exec_csv__fallback(wiki);
else {
byte[][] lines = Bry_split_.Split_lines(dsv_bry);
int lines_len = lines.length;
for (int i = 0; i < lines_len; ++i) {
byte[] line = lines[i]; if (Bry_.Len_eq_0(line)) continue; // ignore blank lines
byte[][] flds = Bry_split_.Split(line, Byte_ascii.Pipe);
byte[] url_fmt = flds[1];
byte[] domain_bry = Xow_xwiki_mgr.Get_domain_from_url(url_parser, url_fmt);
wiki.Xwiki_mgr().Add_by_site_interwikimap
( flds[0], domain_bry, url_fmt
, Bry_.Replace(url_fmt, Arg0_xo, Arg0_wm) // NOTE: interwiki items are stored in wiki.core.xowa_cfg as https://en.wikipedia.org/wiki/~{0}
);
}
}
}
private void Exec_csv__fallback(Xow_wiki wiki) {
Xow_xwiki_mgr xwiki_mgr = wiki.Xwiki_mgr();
int domain_tid = wiki.Domain_tid();
xwiki_mgr.Add_by_csv(Csv__manual); // adds manual xwikis that should exist in all wikis; EX: 'commons', 'wikidata', 'oldwikisource', 'wmf'
switch (domain_tid) {
case Xow_domain_tid_.Tid__wikipedia: case Xow_domain_tid_.Tid__wiktionary: case Xow_domain_tid_.Tid__wikisource: case Xow_domain_tid_.Tid__wikivoyage:
case Xow_domain_tid_.Tid__wikiquote: case Xow_domain_tid_.Tid__wikibooks: case Xow_domain_tid_.Tid__wikiversity: case Xow_domain_tid_.Tid__wikinews:
xwiki_mgr.Add_by_sitelink_mgr(); // lang: EX: [[fr:]] -> fr.wikipedia.org
xwiki_mgr.Add_by_csv(Csv__peers__lang); // peer: EX: [[wikt]] -> en.wiktionary.org
break;
case Xow_domain_tid_.Tid__commons: case Xow_domain_tid_.Tid__wikidata:
case Xow_domain_tid_.Tid__wikimedia: case Xow_domain_tid_.Tid__species: case Xow_domain_tid_.Tid__meta:
case Xow_domain_tid_.Tid__incubator: case Xow_domain_tid_.Tid__wikimania: case Xow_domain_tid_.Tid__wikisource_org:
case Xow_domain_tid_.Tid__mediawiki: case Xow_domain_tid_.Tid__wmfblog:
case Xow_domain_tid_.Tid__home: case Xow_domain_tid_.Tid__other:
xwiki_mgr.Add_by_sitelink_mgr(Xow_domain_tid_.Tid__wikipedia); // lang: hardcode to wikipedia; EX: "[[en:]] -> "en.wikipedia.org"
xwiki_mgr.Add_by_csv(Csv__peers__english); // peer: hardcode to english
break;
}
// wikivoyage
switch (domain_tid) {
case Xow_domain_tid_.Tid__wikivoyage: case Xow_domain_tid_.Tid__home: // NOTE: home needed for diagnostic; DATE:2015-10-13
xwiki_mgr.Add_by_csv(Csv__wikivoyage);
break;
}
// if simplewiki, add "w" -> "enwiki"
if (Bry_.Eq(wiki.Domain_bry(), Xow_domain_itm_.Bry__simplewiki))
xwiki_mgr.Add_by_csv(Csv__enwiki);
}
private static final byte[]
Csv__manual = Bry_.new_a7(String_.Concat_lines_nl_skip_last
( "1|commons;c|commons.wikimedia.org|Commons"
, "1|m;metawikipedia|meta.wikipedia.org"
, "1|species;wikispecies|species.wikimedia.org"
, "1|d;wikidata|www.wikidata.org"
, "1|mw;mediawikiwiki|www.mediawiki.org"
, "1|wmf;wikimedia;foundation|foundation.wikimedia.org"
, "1|incubator|incubator.wikimedia.org"
, "1|wikimania|wikimania.wikimedia.org"
, "1|sourceswiki|wikisource.org"
, "0|oldwikisource|https://wikisource.org/wiki/~{0}|Old Wikisoure"
, "0|mail|https://lists.wikimedia.org/mailman/listinfo/~{0}|Wikitech Mailing List"
))
, Csv__peers__lang = Bry_.new_a7(String_.Concat_lines_nl_skip_last
( "2|w;wikipedia|wikipedia"
, "2|wikt;wiktionary|wiktionary"
, "2|s;wikisource|wikisource"
, "2|b;wikibooks|wikibooks"
, "2|v;wikiversity|wikiversity"
, "2|q;wikiquote|wikiquote"
, "2|n;wikinews|wikinews"
, "2|voy;wikivoyage|wikivoyage"
))
, Csv__peers__english = Bry_.new_a7(String_.Concat_lines_nl_skip_last
( "1|w|en.wikipedia.org"
, "1|wikt|en.wiktionary.org"
, "1|s|en.wikisource.org"
, "1|b|en.wikibooks.org"
, "1|v|en.wikiversity.org"
, "1|q|en.wikiquote.org"
, "1|n|en.wikinews.org"
, "1|voy|en.wikivoyage.org"
))
, Csv__wikivoyage = Bry_.new_a7(String_.Concat_lines_nl_skip_last
( "0|commons|commons.wikimedia.org|Wikimedia Commons"
, "2|wikipedia|wikipedia|Wikipedia"
, "0|dmoz|http://www.dmoz.org/~{0}|DMOZ"
))
, Csv__enwiki = Bry_.new_a7("2|w|wikipedia")
;
private static final byte[]
Arg0_xo = Bry_.new_a7("~{0}")
, Arg0_wm = Bry_.new_a7("$1")
;
}
package gplx.xowa.apps.site_cfgs;
import gplx.Bry_;
import gplx.Bry_bfr;
import gplx.Bry_bfr_;
import gplx.Bry_split_;
import gplx.Byte_ascii;
import gplx.Err_;
import gplx.String_;
import gplx.core.net.Gfo_url_parser;
import gplx.langs.jsons.Json_itm;
import gplx.langs.jsons.Json_nde;
import gplx.xowa.Xow_wiki;
import gplx.xowa.apps.gfs.Gfs_php_converter;
import gplx.xowa.wikis.domains.Xow_domain_itm_;
import gplx.xowa.wikis.domains.Xow_domain_tid_;
import gplx.xowa.wikis.xwikis.Xow_xwiki_mgr;
class Xoa_site_cfg_itm__interwikimap extends Xoa_site_cfg_itm__base {
private final Bry_bfr tmp_bfr = Bry_bfr_.New();
private final Gfo_url_parser url_parser = new Gfo_url_parser();
public Xoa_site_cfg_itm__interwikimap() {
this.Ctor(Xoa_site_cfg_loader__inet.Qarg__interwikimap);
}
@Override public void Parse_json_ary_itm(Bry_bfr bfr, Xow_wiki wiki, int i, Json_itm itm) {
Json_nde nde = Json_nde.Cast(itm);
if (i != 0) bfr.Add_byte_nl();
byte[] iw_key = nde.Get_bry_or_null("prefix"); if (iw_key == null) throw Err_.new_("site_meta", "invalid interwiki", "key", iw_key);
byte[] iw_url = nde.Get_bry_or_null("url"); if (iw_url == null) throw Err_.new_("site_meta", "invalid interwiki", "url", iw_key);
bfr.Add(iw_key).Add_byte_pipe().Add(Gfs_php_converter.To_gfs(tmp_bfr, iw_url));
}
@Override public void Exec_csv(Xow_wiki wiki, int loader_tid, byte[] dsv_bry) {
if (loader_tid == Xoa_site_cfg_loader_.Tid__fallback)
Exec_csv__fallback(wiki);
else {
byte[][] lines = Bry_split_.Split_lines(dsv_bry);
int lines_len = lines.length;
for (int i = 0; i < lines_len; ++i) {
byte[] line = lines[i]; if (Bry_.Len_eq_0(line)) continue; // ignore blank lines
byte[][] flds = Bry_split_.Split(line, Byte_ascii.Pipe);
byte[] url_fmt = flds[1];
byte[] domain_bry = Xow_xwiki_mgr.Get_domain_from_url(url_parser, url_fmt);
wiki.Xwiki_mgr().Add_by_site_interwikimap
( flds[0], domain_bry, url_fmt
, Bry_.Replace(url_fmt, Arg0_xo, Arg0_wm) // NOTE: interwiki items are stored in wiki.core.xowa_cfg as https://en.wikipedia.org/wiki/~{0}
);
}
}
}
private void Exec_csv__fallback(Xow_wiki wiki) {
Xow_xwiki_mgr xwiki_mgr = wiki.Xwiki_mgr();
int domain_tid = wiki.Domain_tid();
xwiki_mgr.Add_by_csv(Csv__manual); // adds manual xwikis that should exist in all wikis; EX: 'commons', 'wikidata', 'oldwikisource', 'wmf'
switch (domain_tid) {
case Xow_domain_tid_.Tid__wikipedia: case Xow_domain_tid_.Tid__wiktionary: case Xow_domain_tid_.Tid__wikisource: case Xow_domain_tid_.Tid__wikivoyage:
case Xow_domain_tid_.Tid__wikiquote: case Xow_domain_tid_.Tid__wikibooks: case Xow_domain_tid_.Tid__wikiversity: case Xow_domain_tid_.Tid__wikinews:
xwiki_mgr.Add_by_sitelink_mgr(); // lang: EX: [[fr:]] -> fr.wikipedia.org
xwiki_mgr.Add_by_csv(Csv__peers__lang); // peer: EX: [[wikt]] -> en.wiktionary.org
break;
case Xow_domain_tid_.Tid__commons: case Xow_domain_tid_.Tid__wikidata:
case Xow_domain_tid_.Tid__wikimedia: case Xow_domain_tid_.Tid__species: case Xow_domain_tid_.Tid__meta:
case Xow_domain_tid_.Tid__incubator: case Xow_domain_tid_.Tid__wikimania: case Xow_domain_tid_.Tid__wikisource_org:
case Xow_domain_tid_.Tid__mediawiki: case Xow_domain_tid_.Tid__wmfblog:
case Xow_domain_tid_.Tid__home: case Xow_domain_tid_.Tid__other:
xwiki_mgr.Add_by_sitelink_mgr(Xow_domain_tid_.Tid__wikipedia); // lang: hardcode to wikipedia; EX: "[[en:]] -> "en.wikipedia.org"
xwiki_mgr.Add_by_csv(Csv__peers__english); // peer: hardcode to english
break;
}
// wikivoyage
switch (domain_tid) {
case Xow_domain_tid_.Tid__wikivoyage: case Xow_domain_tid_.Tid__home: // NOTE: home needed for diagnostic; DATE:2015-10-13
xwiki_mgr.Add_by_csv(Csv__wikivoyage);
break;
}
// if simplewiki, add "w" -> "enwiki"
if (Bry_.Eq(wiki.Domain_bry(), Xow_domain_itm_.Bry__simplewiki))
xwiki_mgr.Add_by_csv(Csv__enwiki);
}
private static final byte[]
Csv__manual = Bry_.new_a7(String_.Concat_lines_nl_skip_last
( "1|commons;c|commons.wikimedia.org|Commons"
, "1|m;metawikipedia|meta.wikipedia.org"
, "1|species;wikispecies|species.wikimedia.org"
, "1|d;wikidata|www.wikidata.org"
, "1|mw;mediawikiwiki|www.mediawiki.org"
, "1|wmf;wikimedia;foundation|foundation.wikimedia.org"
, "1|incubator|incubator.wikimedia.org"
, "1|wikimania|wikimania.wikimedia.org"
, "1|sourceswiki|wikisource.org"
, "0|oldwikisource|https://wikisource.org/wiki/~{0}|Old Wikisoure"
, "0|mail|https://lists.wikimedia.org/mailman/listinfo/~{0}|Wikitech Mailing List"
))
, Csv__peers__lang = Bry_.new_a7(String_.Concat_lines_nl_skip_last
( "2|w;wikipedia|wikipedia"
, "2|wikt;wiktionary|wiktionary"
, "2|s;wikisource|wikisource"
, "2|b;wikibooks|wikibooks"
, "2|v;wikiversity|wikiversity"
, "2|q;wikiquote|wikiquote"
, "2|n;wikinews|wikinews"
, "2|voy;wikivoyage|wikivoyage"
))
, Csv__peers__english = Bry_.new_a7(String_.Concat_lines_nl_skip_last
( "1|w|en.wikipedia.org"
, "1|wikt|en.wiktionary.org"
, "1|s|en.wikisource.org"
, "1|b|en.wikibooks.org"
, "1|v|en.wikiversity.org"
, "1|q|en.wikiquote.org"
, "1|n|en.wikinews.org"
, "1|voy|en.wikivoyage.org"
))
, Csv__wikivoyage = Bry_.new_a7(String_.Concat_lines_nl_skip_last
( "0|commons|commons.wikimedia.org|Wikimedia Commons"
, "2|wikipedia|wikipedia|Wikipedia"
, "0|dmoz|http://www.dmoz.org/~{0}|DMOZ"
))
, Csv__enwiki = Bry_.new_a7("2|w|wikipedia")
;
private static final byte[]
Arg0_xo = Bry_.new_a7("~{0}")
, Arg0_wm = Bry_.new_a7("$1")
;
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,41 +13,52 @@ 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.bldrs.wms.revs; import gplx.*; import gplx.xowa.*; import gplx.xowa.bldrs.*; import gplx.xowa.bldrs.wms.*;
import gplx.langs.jsons.*; import gplx.core.net.*;
class Xowm_rev_wkr__meta__wm implements Xowm_rev_wkr__meta {
private final Json_parser json_parser = new Json_parser();
private final Xowm_json_parser__page json_page_parser = new Xowm_json_parser__page();
private final Bry_bfr tmp_bfr = Bry_bfr_.New_w_size(255);
private final Wmapi_itm__pge tmp_pge = new Wmapi_itm__pge();
public Xowm_rev_wkr__meta__wm() {
tmp_pge.Rvn_ary_(new Wmapi_itm__rvn());
}
public Gfo_inet_conn Inet_conn() {return inet_conn;} public void Inet_conn_(Gfo_inet_conn v) {this.inet_conn = v;} private Gfo_inet_conn inet_conn;
public void Fetch_meta(String domain_str, Ordered_hash hash, int bgn, int end) {
for (int i = bgn; i < end; ++i) {
Wmapi_itm__pge itm = (Wmapi_itm__pge)hash.Get_at(i);
if (i != bgn) tmp_bfr.Add_byte(Byte_ascii.Pipe);
tmp_bfr.Add(itm.Page_ttl());
}
byte[] json = inet_conn.Download_as_bytes_or_null(Xowm_api_mgr.Bld_api_url(domain_str, "action=query&prop=revisions&rvprop=size|ids|timestamp|user|comment&format=json&rawcontinue=titles=" + tmp_bfr.To_str_and_clear()));
Parse_doc(hash, json);
}
private void Parse_doc(Ordered_hash hash, byte[] json) {
Json_doc jdoc = json_parser.Parse(json);
Json_nde pages_nde = Json_nde.cast(jdoc.Get_grp_many(Jpath__query_pages));
int len = pages_nde.Len();
for (int i = 0; i < len; ++i) {
Parse_page(hash, pages_nde.Get_at_as_kv(i).Val_as_nde());
}
}
private void Parse_page(Ordered_hash hash, Json_nde page_nde) {
json_page_parser.Parse("update", tmp_pge, page_nde); // have to pass tmp_pge, b/c don't know which itm is in hash
Wmapi_itm__pge hash_itm = (Wmapi_itm__pge)hash.Get_by(tmp_pge.Page_ttl()); if (hash_itm == null) return;
hash_itm.Init_id(tmp_pge.Page_id());
Wmapi_itm__rvn tmp_rvn = tmp_pge.Rvn_itm_last();
hash_itm.Rvn_ary_(new Wmapi_itm__rvn());
hash_itm.Rvn_itm_last().Init(tmp_rvn.Rvn_id(), tmp_rvn.Rvn_len(), tmp_rvn.Rvn_time(), tmp_rvn.Rvn_user(), tmp_rvn.Rvn_note());
}
private static final byte[][] Jpath__query_pages = Bry_.Ary("query", "pages");
}
package gplx.xowa.bldrs.wms.revs;
import gplx.Bry_;
import gplx.Bry_bfr;
import gplx.Bry_bfr_;
import gplx.Byte_ascii;
import gplx.Ordered_hash;
import gplx.core.net.Gfo_inet_conn;
import gplx.langs.jsons.Json_doc;
import gplx.langs.jsons.Json_nde;
import gplx.langs.jsons.Json_parser;
import gplx.xowa.bldrs.wms.Xowm_api_mgr;
class Xowm_rev_wkr__meta__wm implements Xowm_rev_wkr__meta {
private final Json_parser json_parser = new Json_parser();
private final Xowm_json_parser__page json_page_parser = new Xowm_json_parser__page();
private final Bry_bfr tmp_bfr = Bry_bfr_.New_w_size(255);
private final Wmapi_itm__pge tmp_pge = new Wmapi_itm__pge();
public Xowm_rev_wkr__meta__wm() {
tmp_pge.Rvn_ary_(new Wmapi_itm__rvn());
}
public Gfo_inet_conn Inet_conn() {return inet_conn;} public void Inet_conn_(Gfo_inet_conn v) {this.inet_conn = v;} private Gfo_inet_conn inet_conn;
public void Fetch_meta(String domain_str, Ordered_hash hash, int bgn, int end) {
for (int i = bgn; i < end; ++i) {
Wmapi_itm__pge itm = (Wmapi_itm__pge)hash.Get_at(i);
if (i != bgn) tmp_bfr.Add_byte(Byte_ascii.Pipe);
tmp_bfr.Add(itm.Page_ttl());
}
byte[] json = inet_conn.Download_as_bytes_or_null(Xowm_api_mgr.Bld_api_url(domain_str, "action=query&prop=revisions&rvprop=size|ids|timestamp|user|comment&format=json&rawcontinue=titles=" + tmp_bfr.To_str_and_clear()));
Parse_doc(hash, json);
}
private void Parse_doc(Ordered_hash hash, byte[] json) {
Json_doc jdoc = json_parser.Parse(json);
Json_nde pages_nde = Json_nde.Cast(jdoc.Get_grp_many(Jpath__query_pages));
int len = pages_nde.Len();
for (int i = 0; i < len; ++i) {
Parse_page(hash, pages_nde.Get_at_as_kv(i).Val_as_nde());
}
}
private void Parse_page(Ordered_hash hash, Json_nde page_nde) {
json_page_parser.Parse("update", tmp_pge, page_nde); // have to pass tmp_pge, b/c don't know which itm is in hash
Wmapi_itm__pge hash_itm = (Wmapi_itm__pge)hash.Get_by(tmp_pge.Page_ttl()); if (hash_itm == null) return;
hash_itm.Init_id(tmp_pge.Page_id());
Wmapi_itm__rvn tmp_rvn = tmp_pge.Rvn_itm_last();
hash_itm.Rvn_ary_(new Wmapi_itm__rvn());
hash_itm.Rvn_itm_last().Init(tmp_rvn.Rvn_id(), tmp_rvn.Rvn_len(), tmp_rvn.Rvn_time(), tmp_rvn.Rvn_user(), tmp_rvn.Rvn_note());
}
private static final byte[][] Jpath__query_pages = Bry_.Ary("query", "pages");
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,108 +13,122 @@ 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.langs.msgs; import gplx.*; import gplx.xowa.*; import gplx.xowa.langs.*;
import gplx.core.brys.fmtrs.*;
import gplx.xowa.addons.htmls.sidebars.*;
public class Xow_msg_mgr implements Gfo_invk {
private final Xow_wiki wiki; private Xol_lang_itm lang; private final Xol_msg_mgr msg_mgr;
private final Bry_fmtr tmp_fmtr = Bry_fmtr.New__tmp();
public Xow_msg_mgr(Xow_wiki wiki, Xol_lang_itm lang) {
this.wiki = wiki;
this.lang = lang;
this.msg_mgr = new Xol_msg_mgr(wiki, false);
}
public void Clear() {msg_mgr.Clear();}
public void Lang_(Xol_lang_itm v) {
this.lang = v;
this.Clear();
}
public byte[] Val_by_id_args(int id, Object... args) {return Val_by_id_priv(id, args);}
public byte[] Val_by_id(int id) {return Val_by_id_priv(id, null);}
private byte[] Val_by_id_priv(int id, Object[] args) {
Xol_msg_itm itm = msg_mgr.Itm_by_id_or_null(id);
if (itm == null)
itm = lang.Msg_mgr().Itm_by_id_or_null(id);
Bry_bfr tmp_bfr = wiki.Utl__bfr_mkr().Get_b512();
byte[] rv = Val_by_itm(tmp_bfr, itm, args);
tmp_bfr.Mkr_rls();
return rv;
}
public Xol_msg_itm Get_or_make(byte[] key) {return msg_mgr.Itm_by_key_or_new(key);}
public Xol_msg_itm Get_or_null(byte[] key) {return msg_mgr.Itm_by_key_or_null(key);}
public Xol_msg_itm Find_or_null(byte[] key) {
Xol_msg_itm itm = msg_mgr.Itm_by_key_or_null(key);
if (itm == null) {
Bry_bfr tmp_bfr = wiki.Utl__bfr_mkr().Get_b512();
itm = Xol_msg_mgr_.Get_msg_itm(tmp_bfr, wiki, lang, key);
if (itm.Defined_in_none()) itm = null;
tmp_bfr.Mkr_rls();
}
return itm;
}
public byte[] Val_by_key_args(byte[] key, Object... args) {return Val_by_key(key, args);}
public byte[] Val_by_key_obj(String key) {return Val_by_key(Bry_.new_u8(key), null);}
public byte[] Val_by_key_obj(byte[] key) {return Val_by_key(key, null);}
private byte[] Val_by_key(byte[] key, Object[] args) {
Xol_msg_itm itm = msg_mgr.Itm_by_key_or_null(key);
Bry_bfr tmp_bfr = wiki.Utl__bfr_mkr().Get_b512();
if (itm == null)
itm = Xol_msg_mgr_.Get_msg_itm(tmp_bfr, wiki, lang, key);
if (itm.Defined_in_none()) {
tmp_bfr.Mkr_rls();
return Bry_.Empty;
}
byte[] rv = Val_by_itm(tmp_bfr, itm, args);
tmp_bfr.Mkr_rls();
return rv;
}
public byte[] Val_by_itm(Bry_bfr tmp_bfr, Xol_msg_itm itm, Object[] args) {
byte[] rv = itm.Val();
if (args != null) rv = itm.Fmt_tmp(tmp_bfr, tmp_fmtr, rv, args);
if (itm.Has_tmpl_txt()) rv = wiki.Wtxt__expand_tmpl(rv);
return rv;
}
public byte[] Val_html_accesskey_and_title(byte[] id) {
Bry_bfr bfr = wiki.Utl__bfr_mkr().Get_b512();
byte[] rv = Val_html_accesskey_and_title(id, bfr, null);
bfr.Mkr_rls();
return rv;
}
public byte[] Val_html_accesskey_and_title(byte[] id, Bry_bfr bfr, Xoh_sidebar_itm itm) {
byte[] tooltip_key = Bry_.Add(CONST_prefix_tooltip, id);
byte[] tooltip_val = Val_by_key_obj(tooltip_key);
boolean tooltip_found = Bry_.Len_gt_0(tooltip_val);
byte[] accesskey_key = Bry_.Empty, accesskey_val = Bry_.Empty;
boolean accesskey_found = false;
if (tooltip_found) {
accesskey_key = Bry_.Add(CONST_prefix_accesskey, id);
accesskey_val = Val_by_key_obj(accesskey_key);
accesskey_found = Bry_.Len_gt_0(accesskey_val);
}
if (accesskey_found)
bfr.Add(CONST_atr_accesskey).Add(accesskey_val).Add_byte(Byte_ascii.Quote);
bfr.Add(CONST_atr_title).Add(tooltip_found ? tooltip_val : Bry_.Empty); // NOTE: if tooltip not found, make blank; don't bother showing tooltip_key
if (accesskey_found)
bfr.Add_byte(Byte_ascii.Space).Add_byte(Byte_ascii.Brack_bgn).Add(accesskey_val).Add_byte(Byte_ascii.Brack_end);
bfr.Add_byte(Byte_ascii.Quote);
byte[] rv = bfr.To_bry_and_clear();
if (itm == null)
return rv;
else {
itm.Init_by_title_and_accesskey(tooltip_val, accesskey_val, rv);
return null;
}
} private static final byte[] CONST_prefix_tooltip = Bry_.new_a7("tooltip-"), CONST_prefix_accesskey = Bry_.new_a7("accesskey-"), CONST_atr_title = Bry_.new_a7(" title=\""), CONST_atr_accesskey = Bry_.new_a7(" accesskey=\"");
public Xol_msg_itm Set(String key_str, String val_str) { // TEST
Xol_msg_itm msg_itm = this.Get_or_make(Bry_.new_u8(key_str));
msg_itm.Atrs_set(Bry_.new_u8(val_str), false, false);
msg_itm.Defined_in_(Xol_msg_itm.Defined_in__lang);
return msg_itm;
}
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk_get)) return this.Val_by_key_obj(m.ReadBry("v"));
else if (ctx.Match(k, Invk_get_html_accesskey_and_title)) return this.Val_html_accesskey_and_title(m.ReadBry("v"));
else return Gfo_invk_.Rv_unhandled;
} private static final String Invk_get = "get", Invk_get_html_accesskey_and_title = "get_html_accesskey_and_title";
}
package gplx.xowa.langs.msgs;
import gplx.Bry_;
import gplx.Bry_bfr;
import gplx.Byte_ascii;
import gplx.GfoMsg;
import gplx.Gfo_invk;
import gplx.Gfo_invk_;
import gplx.GfsCtx;
import gplx.core.brys.fmtrs.Bry_fmtr;
import gplx.xowa.Xow_wiki;
import gplx.xowa.addons.htmls.sidebars.Xoh_sidebar_itm;
import gplx.xowa.langs.Xol_lang_itm;
public class Xow_msg_mgr implements Gfo_invk {
private final Xow_wiki wiki;
private final Xol_msg_mgr msg_mgr;
private Xol_lang_itm lang;
private final Bry_fmtr tmp_fmtr = Bry_fmtr.New__tmp();
public Xow_msg_mgr(Xow_wiki wiki, Xol_lang_itm lang) {
this.wiki = wiki;
this.lang = lang;
this.msg_mgr = new Xol_msg_mgr(wiki, false);
}
public void Clear() {msg_mgr.Clear();}
public void Lang_(Xol_lang_itm v) {
this.lang = v;
this.Clear();
}
public byte[] Val_by_id_args(int id, Object... args) {return Val_by_id_priv(id, args);}
public byte[] Val_by_id(int id) {return Val_by_id_priv(id, null);}
private byte[] Val_by_id_priv(int id, Object[] args) {
Xol_msg_itm itm = msg_mgr.Itm_by_id_or_null(id);
if (itm == null)
itm = lang.Msg_mgr().Itm_by_id_or_null(id);
Bry_bfr tmp_bfr = wiki.Utl__bfr_mkr().Get_b512();
byte[] rv = Val_by_itm(tmp_bfr, itm, args);
tmp_bfr.Mkr_rls();
return rv;
}
public Xol_msg_itm Get_or_make(byte[] key) {return msg_mgr.Itm_by_key_or_new(key);}
public Xol_msg_itm Get_or_null(byte[] key) {return msg_mgr.Itm_by_key_or_null(key);}
public Xol_msg_itm Find_or_null(byte[] key) {
Xol_msg_itm itm = msg_mgr.Itm_by_key_or_null(key);
if (itm == null) {
Bry_bfr tmp_bfr = wiki.Utl__bfr_mkr().Get_b512();
itm = Xol_msg_mgr_.Get_msg_itm(tmp_bfr, wiki, lang, key);
if (itm.Defined_in_none()) itm = null;
tmp_bfr.Mkr_rls();
}
return itm;
}
public byte[] Val_by_key_args(byte[] key, Object... args) {return Val_by_key(key, args);}
public byte[] Val_by_key_obj(String key) {return Val_by_key(Bry_.new_u8(key), null);}
public byte[] Val_by_key_obj(byte[] key) {return Val_by_key(key, null);}
private byte[] Val_by_key(byte[] key, Object[] args) {
Xol_msg_itm itm = msg_mgr.Itm_by_key_or_null(key);
Bry_bfr tmp_bfr = wiki.Utl__bfr_mkr().Get_b512();
if (itm == null)
itm = Xol_msg_mgr_.Get_msg_itm(tmp_bfr, wiki, lang, key);
if (itm.Defined_in_none()) {
tmp_bfr.Mkr_rls();
return Bry_.Empty;
}
byte[] rv = Val_by_itm(tmp_bfr, itm, args);
tmp_bfr.Mkr_rls();
return rv;
}
public byte[] Val_by_itm(Bry_bfr tmp_bfr, Xol_msg_itm itm, Object[] args) {
byte[] rv = itm.Val();
if (args != null) rv = itm.Fmt_tmp(tmp_bfr, tmp_fmtr, rv, args);
if (itm.Has_tmpl_txt()) rv = wiki.Wtxt__expand_tmpl(rv);
return rv;
}
public byte[] Val_html_accesskey_and_title(String id) {return Val_html_accesskey_and_title(Bry_.new_u8(id));}
public byte[] Val_html_accesskey_and_title(byte[] id) {
Bry_bfr bfr = wiki.Utl__bfr_mkr().Get_b512();
byte[] rv = Val_html_accesskey_and_title(id, bfr, null);
bfr.Mkr_rls();
return rv;
}
public byte[] Val_html_accesskey_and_title(byte[] id, Bry_bfr bfr, Xoh_sidebar_itm itm) {
byte[] tooltip_key = Bry_.Add(CONST_prefix_tooltip, id);
byte[] tooltip_val = Val_by_key_obj(tooltip_key);
boolean tooltip_found = Bry_.Len_gt_0(tooltip_val);
byte[] accesskey_key = Bry_.Empty, accesskey_val = Bry_.Empty;
boolean accesskey_found = false;
if (tooltip_found) {
accesskey_key = Bry_.Add(CONST_prefix_accesskey, id);
accesskey_val = Val_by_key_obj(accesskey_key);
accesskey_found = Bry_.Len_gt_0(accesskey_val);
}
if (accesskey_found)
bfr.Add(CONST_atr_accesskey).Add(accesskey_val).Add_byte(Byte_ascii.Quote);
bfr.Add(CONST_atr_title).Add(tooltip_found ? tooltip_val : Bry_.Empty); // NOTE: if tooltip not found, make blank; don't bother showing tooltip_key
if (accesskey_found)
bfr.Add_byte(Byte_ascii.Space).Add_byte(Byte_ascii.Brack_bgn).Add(accesskey_val).Add_byte(Byte_ascii.Brack_end);
bfr.Add_byte(Byte_ascii.Quote);
byte[] rv = bfr.To_bry_and_clear();
if (itm == null)
return rv;
else {
itm.Init_by_title_and_accesskey(tooltip_val, accesskey_val, rv);
return null;
}
} private static final byte[] CONST_prefix_tooltip = Bry_.new_a7("tooltip-"), CONST_prefix_accesskey = Bry_.new_a7("accesskey-"), CONST_atr_title = Bry_.new_a7(" title=\""), CONST_atr_accesskey = Bry_.new_a7(" accesskey=\"");
public Xol_msg_itm Set(String key_str, String val_str) { // TEST
Xol_msg_itm msg_itm = this.Get_or_make(Bry_.new_u8(key_str));
msg_itm.Atrs_set(Bry_.new_u8(val_str), false, false);
msg_itm.Defined_in_(Xol_msg_itm.Defined_in__lang);
return msg_itm;
}
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk_get)) return this.Val_by_key_obj(m.ReadBry("v"));
else if (ctx.Match(k, Invk_get_html_accesskey_and_title)) return this.Val_html_accesskey_and_title(m.ReadBry("v"));
else return Gfo_invk_.Rv_unhandled;
} private static final String Invk_get = "get", Invk_get_html_accesskey_and_title = "get_html_accesskey_and_title";
}

@ -95,6 +95,7 @@ public class Xot_invk_tkn extends Xop_tkn_itm_base implements Xot_invk {
boolean subst_found = false;
boolean name_had_subst = false;
boolean template_prefix_found = false;
// byte tmpl_case_match = wiki.Ns_mgr().Ns_template().Case_match();
// tmpl_name does not exist in db; may be dynamic, subst, transclusion, etc..
if (defn == Xot_defn_.Null) {
@ -285,6 +286,29 @@ public class Xot_invk_tkn extends Xop_tkn_itm_base implements Xot_invk {
break;
case Xot_defn_.Tid_func:
try {
/* System.out.println(String_.new_a7(caller.Frame_ttl()));
if (true) {//(caller.Frame_ttl().length == 22 && caller.Frame_ttl()[21] == 't') {
int alen = caller.Args_len();
String s = "";
for (int i = 0; i < alen; i++) {
Arg_nde_tkn atkn = caller.Args_get_by_idx(i);
if (atkn.KeyTkn_exists()) {
Arg_itm_tkn argtkn = atkn.Key_tkn();
s += String_.new_a7(argtkn.Dat_ary()) + ":";
}
else
s += String.valueOf(i);
s += String_.new_a7(atkn.Val_tkn().Dat_ary()) + "\n";
}
System.out.println(s);
int a=1;
}
if (Bry_.Eq(caller.Frame_ttl(), Bry_.new_a7("Template:BookCat/core"))) {
return true;
//int a=1;
}
*/
//System.out.println(String_.new_u8(caller.Frame_ttl()));
Xot_invk_tkn_.Eval_func(ctx, src, caller, this, bfr, defn, argx_ary);
rv = true;
} catch (Exception e) {
@ -306,11 +330,13 @@ public class Xot_invk_tkn extends Xop_tkn_itm_base implements Xot_invk {
Bry_bfr rslt_bfr = wiki.Utl__bfr_mkr().Get_k004();
try {
Xopg_tmpl_prepend_mgr prepend_mgr = ctx.Page().Tmpl_prepend_mgr().Bgn(bfr);
rv = defn_tmpl.Tmpl_evaluate(Xop_ctx.New__sub(wiki, ctx, ctx.Page()), invk_tmpl, rslt_bfr); // create new ctx so __NOTOC__ only applies to template, not page; PAGE:de.w:13._Jahrhundert DATE:2017-06-17
//rv = defn_tmpl.Tmpl_evaluate(Xop_ctx.New__sub(wiki, ctx, ctx.Page()), invk_tmpl, rslt_bfr); // create new ctx so __NOTOC__ only applies to template, not page; PAGE:de.w:13._Jahrhundert DATE:2017-06-17
rv = defn_tmpl.Tmpl_evaluate(ctx, invk_tmpl, rslt_bfr);
prepend_mgr.End(ctx, bfr, rslt_bfr.Bfr(), rslt_bfr.Len(), Bool_.Y);
if (name_had_subst) { // current invk had "subst:"; parse incoming invk again to remove effects of subst; PAGE:pt.w:Argentina DATE:2014-09-24
byte[] tmp_src = rslt_bfr.To_bry_and_clear();
rslt_bfr.Add(wiki.Parser_mgr().Main().Expand_tmpl(tmp_src)); // this could be cleaner / more optimized
if (tmp_src.length != 0)
rslt_bfr.Add(wiki.Parser_mgr().Main().Expand_tmpl(tmp_src)); // this could be cleaner / more optimized
}
bfr.Add_bfr_and_clear(rslt_bfr);
trace.Trace_end(trg_bgn, bfr);
@ -341,7 +367,7 @@ public class Xot_invk_tkn extends Xop_tkn_itm_base implements Xot_invk {
Xoa_ttl page_ttl = Xoa_ttl.Parse(wiki, name_ary); if (page_ttl == null) return false; // ttl not valid; EX: {{:[[abc]]}}
byte[] transclude_src = null;
if (page_ttl.Ns().Id_is_tmpl()) { // ttl is template; check tmpl_regy first before going to data_mgr
Xot_defn_tmpl tmpl = (Xot_defn_tmpl)wiki.Cache_mgr().Defn_cache().Get_by_key(page_ttl.Page_db());
Xot_defn_tmpl tmpl = (Xot_defn_tmpl)wiki.Cache_mgr().Defn_cache().Get_by_key(page_ttl.Page_db(), wiki.Ns_mgr().Ns_template().Case_match());
if (tmpl != null) transclude_src = tmpl.Data_raw();
}
if (transclude_src == null && ctx.Tmpl_load_enabled()) { // ttl is template not in cache, or some other ns; do load
@ -378,7 +404,7 @@ public class Xot_invk_tkn extends Xop_tkn_itm_base implements Xot_invk {
Xot_defn_tmpl transclude_tmpl = null;
switch (page_ttl.Ns().Id()) {
case Xow_ns_.Tid__template: // ttl is template not in cache, or some other ns; do load
Xot_defn_tmpl tmpl = (Xot_defn_tmpl)wiki.Cache_mgr().Defn_cache().Get_by_key(page_ttl.Page_db());
Xot_defn_tmpl tmpl = (Xot_defn_tmpl)wiki.Cache_mgr().Defn_cache().Get_by_key(page_ttl.Page_db(), wiki.Ns_mgr().Ns_template().Case_match());
if (tmpl != null) {
if (tmpl.Root() == null) tmpl.Parse_tmpl(ctx);
transclude_tmpl = tmpl;

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,24 +13,33 @@ 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.wikis.caches; import gplx.*; import gplx.xowa.*; import gplx.xowa.wikis.*;
import gplx.core.intls.*; import gplx.core.caches.*;
import gplx.xowa.langs.*;
import gplx.xowa.wikis.nss.*;
import gplx.xowa.parsers.tmpls.*;
public class Xow_defn_cache { // stores compiled Xot_defn
private final Xol_lang_itm lang; // needed to lowercase names;
private final Bry_bfr upper_1st_bfr = Bry_bfr_.Reset(255);
private final Gfo_cache_mgr cache = new Gfo_cache_mgr().Max_size_(64 * 1024 * 1024).Reduce_by_(32 * 1024 * 1024);
public Xow_defn_cache(Xol_lang_itm lang) {this.lang = lang;}
public Xot_defn Get_by_key(byte[] name) {return (Xot_defn)cache.Get_by_key(name);}
public void Free_mem_all() {cache.Clear();}
public void Add(Xot_defn defn, byte case_match) {
byte[] name = defn.Name();
cache.Add_replace(name, defn, defn.Cache_size());
if (case_match == Xow_ns_case_.Tid__1st) {
name = lang.Case_mgr().Case_build_1st_upper(upper_1st_bfr, name, 0, name.length);
cache.Add_replace(name, defn, 0);
}
}
}
package gplx.xowa.wikis.caches;
import gplx.Bry_bfr;
import gplx.Bry_bfr_;
import gplx.core.caches.Gfo_cache_mgr;
import gplx.xowa.langs.Xol_lang_itm;
import gplx.xowa.parsers.tmpls.Xot_defn;
import gplx.xowa.wikis.nss.Xow_ns_case_;
public class Xow_defn_cache {
private final Xol_lang_itm lang; // needed to lowercase names;
private final Bry_bfr upper_1st_bfr = Bry_bfr_.Reset(255);
private final Gfo_cache_mgr cache = new Gfo_cache_mgr().Max_size_(64 * 1024 * 1024).Reduce_by_(32 * 1024 * 1024);
public Xow_defn_cache(Xol_lang_itm lang) {this.lang = lang;}
public Xot_defn Get_by_key(byte[] name) {return (Xot_defn)cache.Get_by_key(name);}
public Xot_defn Get_by_key(byte[] name, byte case_match) {
if (case_match == Xow_ns_case_.Tid__1st)
name = lang.Case_mgr().Case_build_1st_upper(upper_1st_bfr, name, 0, name.length);
return (Xot_defn)cache.Get_by_key(name);
}
public void Free_mem_all() {cache.Clear();}
public void Add(Xot_defn defn, byte case_match) {
byte[] name = defn.Name();
cache.Add_replace(name, defn, defn.Cache_size());
if (case_match == Xow_ns_case_.Tid__1st) {
name = lang.Case_mgr().Case_build_1st_upper(upper_1st_bfr, name, 0, name.length);
cache.Add_replace(name, defn, 0);
}
}
}

@ -0,0 +1,403 @@
/* search for '</?section' then find fwd '>'
any </section ignore
within bgn to end need to dig out 'begin' or 'end' or the language sensitivities
also the key value
store
name of section, start or end
if start position after close >
if end position before <
*/
package gplx.xowa.xtns.lst;
import gplx.Bry_;
import gplx.List_adp;
import gplx.List_adp_;
import gplx.xowa.Xoa_ttl;
import gplx.xowa.Xoae_page;
import gplx.xowa.Xowe_wiki;
import gplx.xowa.parsers.Xop_ctx;
import gplx.xowa.parsers.Xop_root_tkn;
import gplx.xowa.parsers.Xop_parser;
import gplx.xowa.parsers.Xop_parser_;
import gplx.xowa.parsers.Xop_parser_tid_;
import gplx.xowa.parsers.Xop_tkn_mkr;
import gplx.xowa.parsers.tmpls.Xot_invk_temp;
import gplx.xowa.parsers.lnkis.files.Xop_file_logger_;
import gplx.xowa.parsers.tmpls.Xot_defn_tmpl;
import gplx.Bry_bfr;
import gplx.Bry_bfr_;
import gplx.Bool_;
import gplx.Hash_adp_bry;
public class Db_Section_list {
private List_adp sects;
private List_adp heads;
private byte[] src;
private Xop_ctx ctx;
private Xop_ctx sub_ctx;
private Xowe_wiki wiki;
private Xoa_ttl ttl;
private byte[] ttl_bry;
private static final byte Include_between = 0, Include_to_eos = 1, Include_to_bos = 2;
public Db_Section_list(byte[] src, int langid, Xop_ctx ctx, Xop_ctx sub_ctx, Xoa_ttl ttl, byte[] ttl_bry) {
byte b;
this.src = src;
this.ctx = ctx;
this.wiki = ctx.Wiki();
this.sub_ctx = sub_ctx;
this.ttl = ttl;
this.ttl_bry = ttl_bry;
int src_len = src.length;
int pos = 0;
int bgn, end, atr;
sects = List_adp_.New();
begin_end keyword;
switch (langid) {
case 1: // german!!!
keyword = new DE_begin_end();
break;
default:
keyword = new EN_begin_end();
break;
}
while (pos < src_len) {
b = src[pos++];
if (b == '<') {
if (pos + 10 < src_len && (src[pos] | 32) == 's' && (src[pos+1] | 32) == 'e' && (src[pos+2] | 32) == 'c' && (src[pos+3] | 32) == 't' && (src[pos+4] | 32) == 'i' && (src[pos+5] | 32) == 'o' && (src[pos+6] | 32) == 'n' && src[pos+7] == ' ') {
bgn = pos - 1;
pos += 8;
atr = pos;
while (pos < src_len) {
b = src[pos++];
if (b == '>')
break;
}
if (pos == src_len) // no end found
break;
end = pos;
// now find a keyword
begin_end_result bg = keyword.Find(src, atr, end);
if (bg != null) {
sects.Add(new Section(src, bg.start, bg.type, bgn, end));
}
}
}
else if (b == '\n') { // check for headers
if (pos + 10 < src_len && src[pos] == '=') {
int count = 1;
pos++;
while (pos < src_len) {
b = src[pos++];
if (b != '=')
break;
count++;
}
// now find the next <nl>
if (b != '\n') {
int npos = pos;
while (npos < src_len) {
b = src[npos++];
if (b == '\n')
break;
}
if (b == '\n') {
// now count any '=' backwards
int ncount = 0;
while (npos > pos) {
b = src[--npos];
if (b == '=')
ncount++;
else
break;
}
if (ncount == count) { // we have a header
heads.Add(new Header(src, pos, npos, count));
pos = npos + count;
}
}
}
}
}
}
}
public byte[] Include(byte[] from, byte[] to) {
if (to == Lst_pfunc_itm.Null_arg) { // no end arg; EX: {{#lst:page|bgn}}; NOTE: different than {{#lst:page|bgn|}}
if (from == Lst_pfunc_itm.Null_arg) { // no bgn arg; EX: {{#lst:page}}
return Compile3(src);
}
else // bgn exists; set end to bgn; EX: {{#lst:page|bgn}} is same as {{#lst:page|bgn|bgn}}; NOTE: {{#lst:page|bgn|}} means write from bgn to eos
to = from;
}
Bry_bfr bfr = Bry_bfr_.New();
byte include_mode = Include_between;
if (Bry_.Len_eq_0(to))
include_mode = Include_to_eos;
else if (Bry_.Len_eq_0(from))
include_mode = Include_to_bos;
int bgn_pos = 0; boolean bgn_found = false; int src_page_bry_len = src.length;
int sections_len = sects.Count();
for (int i = 0; i < sections_len; i++) {
Section sect = (Section)sects.Get_at(i);
byte section_tid = (byte)sect.type;
if (section_tid == begin_end_result.BEGIN && Matchkey(sect, from)) {
int sect_bgn_rhs = sect.end;
if (include_mode == Include_to_eos) { // write from cur to eos; EX: {{#lst:page|bgn|}}
bfr.Add_mid(src, sect_bgn_rhs, src_page_bry_len);
bgn_found = false;
break;
}
else { // bgn and end
if (!bgn_found) { // NOTE: !bgn_found to prevent "resetting" of dupe; EX: <s begin=key0/>a<s begin=key0/>b; should start from a not b
bgn_pos = sect_bgn_rhs;
bgn_found = true;
}
}
}
else if (section_tid == begin_end_result.END && Matchkey(sect, to)) {
int sect_end_lhs = sect.bgn;
if (include_mode == Include_to_bos) { // write from bos to cur; EX: {{#lst:page||end}}
bfr.Add_mid(src, 0, sect_end_lhs);
bgn_found = false;
break;
}
else {
if (bgn_found) { // NOTE: bgn_found to prevent writing from bos; EX: a<s end=key0/>b should not write anything
bfr.Add_mid(src, bgn_pos, sect_end_lhs);
bgn_found = false;
}
}
}
}
if (bgn_found) // bgn_found, but no end; write to end of page; EX: "a <section begin=key/> b" -> " b"
bfr.Add_mid(src, bgn_pos, src_page_bry_len);
return Compile3(bfr.To_bry());
}
public byte[] Exclude(byte[] sect_exclude, byte[] sect_replace) {
if (Bry_.Len_eq_0(sect_exclude)) { // no exclude arg; EX: {{#lstx:page}} or {{#lstx:page}}
return Compile3(src); // write all and exit
}
int sections_len = sects.Count();
int bgn_pos = 0;
Bry_bfr bfr = Bry_bfr_.New();
for (int i = 0; i < sections_len; i++) {
Section sect = (Section)sects.Get_at(i);
byte section_tid = (byte)sect.type;
if (section_tid == begin_end_result.BEGIN && Matchkey(sect, sect_exclude)) {
bfr.Add_mid(src, bgn_pos, sect.bgn); // write everything from bgn_pos up to exclude
}
else if (section_tid == begin_end_result.END && Matchkey(sect, sect_exclude)) { // exclude end found
if (sect_replace != null)
bfr.Add(sect_replace); // write replacement
bgn_pos = sect.end; // reset bgn_pos
}
}
bfr.Add_mid(src, bgn_pos, src.length);
return Compile3(bfr.To_bry());
}
public byte[] Header(byte[] lhs_hdr, byte[] rhs_hdr) {
return Bry_.Empty;
}
private boolean Matchkey(Section sect, byte[] find) {
if (find == Lst_pfunc_itm.Null_arg) return false;
int pos = sect.keybgn;
int keylen = sect.keyend - pos;
int find_end = find.length;
if (find_end != keylen) return false;
for (int i = 0; i < find_end; i++) {
if (src[pos + i] != find[i]) return false;
}
return true;
}
// need ctx hence wiki and page
private byte[] Compile(byte[] page_bry) {
Xop_root_tkn xtn_root = null;
// set recursing flag
Xoae_page page = ctx.Page();
Bry_bfr full_bfr = wiki.Utl__bfr_mkr().Get_m001();
try {
wiki.Parser_mgr().Lst__recursing_(true);
Hash_adp_bry lst_page_regy = ctx.Lst_page_regy(); if (lst_page_regy == null) lst_page_regy = Hash_adp_bry.cs(); // SEE:NOTE:page_regy; DATE:2014-01-01
page.Html_data().Indicators().Enabled_(Bool_.N); // disable <indicator> b/c <page> should not add to current page; PAGE:en.s:The_Parochial_System_(Wilberforce,_1838); DATE:2015-04-29
xtn_root = Bld_root_nde(full_bfr, lst_page_regy, page_bry); // NOTE: this effectively reparses page twice; needed b/c of "if {| : ; # *, auto add new_line" which can build different tokens
} finally {
wiki.Parser_mgr().Lst__recursing_(false);
full_bfr.Mkr_rls();
}
page.Html_data().Indicators().Enabled_(Bool_.Y);
if (xtn_root == null) return null;
//html_wtr.Write_tkn_to_html(bfr, ctx, hctx, xtn_root.Root_src(), xnde, Xoh_html_wtr.Sub_idx_null, xtn_root);
return null;
}
private byte[] Compile2(byte[] msg_val) {
Xowe_wiki wikie = (Xowe_wiki)wiki;
Xop_ctx sub_ctx = Xop_ctx.New__sub__reuse_page(wikie.Parser_mgr().Ctx());
sub_ctx.Parse_tid_(Xop_parser_tid_.Tid__wtxt);
Xop_tkn_mkr tkn_mkr = sub_ctx.Tkn_mkr();
Xop_root_tkn sub_root = tkn_mkr.Root(msg_val);
return wikie.Parser_mgr().Main().Expand_tmpl(sub_root, sub_ctx, tkn_mkr, msg_val);
}
private byte[] Compile3(byte[] sub_src) {
// parse page; note adding to stack to prevent circular recursions
if (!wiki.Parser_mgr().Tmpl_stack_add(ttl.Full_db())) return null;
Xot_defn_tmpl tmpl = wiki.Parser_mgr().Main().Parse_text_to_defn_obj(sub_ctx, sub_ctx.Tkn_mkr(), ttl.Ns(), ttl_bry, sub_src); // NOTE: parse as tmpl to ignore <noinclude>
wiki.Parser_mgr().Tmpl_stack_del(); // take template off stack; evaluate will never recurse, but will fail if ttl is still on stack; DATE:2014-03-10
// eval tmpl
Bry_bfr tmp_bfr = wiki.Utl__bfr_mkr().Get_m001();
try {
tmpl.Tmpl_evaluate(sub_ctx, Xot_invk_temp.New_root(ttl.Page_txt()), tmp_bfr);
sub_src = tmp_bfr.To_bry_and_clear();
} finally {
tmp_bfr.Mkr_rls();
}
return sub_src;
}
private Xop_root_tkn Bld_root_nde(Bry_bfr page_bfr, Hash_adp_bry lst_page_regy, byte[] wikitext) {
Xop_ctx tmp_ctx = Xop_ctx.New__sub__reuse_lst(wiki, ctx, lst_page_regy);
tmp_ctx.Page().Ttl_(ctx.Page().Ttl()); // NOTE: must set tmp_ctx.Ttl to ctx.Ttl; EX: Flatland and First World; DATE:2013-04-29
tmp_ctx.Lnki().File_logger_(Xop_file_logger_.Noop); // NOTE: set file_wkr to null, else items will be double-counted
tmp_ctx.Parse_tid_(Xop_parser_tid_.Tid__defn);
Xop_parser tmp_parser = Xop_parser.new_(wiki, wiki.Parser_mgr().Main().Tmpl_lxr_mgr(), wiki.Parser_mgr().Main().Wtxt_lxr_mgr());
Xop_root_tkn rv = tmp_ctx.Tkn_mkr().Root(wikitext);
tmp_parser.Parse_text_to_wdom(rv, tmp_ctx, tmp_ctx.Tkn_mkr(), wikitext, Xop_parser_.Doc_bgn_bos);
return rv;
}
}
class Section {
public int keybgn;
public int keyend;
public int type;
public int bgn;
public int end;
Section(byte[] src, int keybgn, int type, int bgn, int end) {
this.type = type;
this.bgn = bgn;
this.end = end;
byte b = src[keybgn];
if (b == '\'' || b == '"')
keybgn++;
keyend = end - 2;
while (keyend > bgn) {
b = src[keyend - 1];
if (b != ' ' && b != '\t' && b != '\n')
break;
keyend--;
}
if (b == '\'' || b == '"')
keyend--;
this.keybgn = keybgn;
}
}
class Header {
public int bgn;
public int end;
public int level;
Header(byte[] src, int bgn, int end, int level) {
this.level = level;
byte b;
while (bgn < end) {
b = src[bgn];
if (b == ' ' || b == '\t')
bgn++;
else
break;
}
this.bgn = bgn;
while (end > bgn) {
b = src[end - 1];
if (b == ' ' || b == '\t')
bgn--;
else
break;
}
this.end = end;
}
}
interface begin_end {
begin_end_result Find(byte[] src, int bgn, int end);
}
class EN_begin_end implements begin_end {
public begin_end_result Find(byte[] src, int bgn, int end) {
while (bgn < end) {
byte b = src[bgn++];
switch (b) {
case 'b':
case 'B':
if ((src[bgn] | 32) == 'e' && (src[bgn+1] | 32) == 'g' && (src[bgn+2] | 32) == 'i' && (src[bgn+3] | 32) == 'n' && src[bgn+4] == '=') {
bgn += 5;
b = src[bgn];
return new begin_end_result(begin_end_result.BEGIN, bgn);
}
break;
case 'e':
case 'E':
if ((src[bgn] | 32) == 'n' && (src[bgn+1] | 32) == 'd' && src[bgn+2] == '=') {
bgn += 3;
b = src[bgn];
return new begin_end_result(begin_end_result.END, bgn);
}
break;
}
}
return null;
}
}
class DE_begin_end implements begin_end {
public begin_end_result Find(byte[] src, int bgn, int end) {
while (bgn < end) {
byte b = src[bgn++];
switch (b) {
case 'b':
case 'B':
if ((src[bgn] | 32) == 'e' && (src[bgn+1] | 32) == 'g' && (src[bgn+2] | 32) == 'i' && (src[bgn+3] | 32) == 'n' && src[bgn+4] == '=') {
bgn += 5;
b = src[bgn];
return new begin_end_result(begin_end_result.BEGIN, bgn);
}
break;
// End
// Ende
case 'e':
case 'E':
if ((src[bgn] | 32) == 'n' && (src[bgn+1] | 32) == 'd') {
if (src[bgn+2] == '=') {
bgn += 3;
}
else if ((src[bgn+2] | 32) == 'e' && src[bgn+3] == '=') {
bgn += 4;
}
else
break;
b = src[bgn];
return new begin_end_result(begin_end_result.END, bgn);
}
break;
// Anfang
case 'a':
case 'A':
if ((src[bgn] | 32) == 'n' && (src[bgn+1] | 32) == 'f' && (src[bgn+2] | 32) == 'a' && (src[bgn+3] | 32) == 'n' && (src[bgn+4] | 32) == 'g' && src[bgn+5] == '=') {
bgn += 6;
b = src[bgn];
return new begin_end_result(begin_end_result.END, bgn);
}
break;
}
}
return null;
}
}
class begin_end_result {
public static int BEGIN = 1;
public static int END = 2;
public int type;
public int start;
begin_end_result(int type, int start) {
this.type = type;
this.start = start;
}
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,201 +13,235 @@ 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.pagebanners; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
import gplx.core.btries.*; import gplx.langs.mustaches.*;
import gplx.xowa.parsers.*; import gplx.xowa.parsers.tmpls.*; import gplx.xowa.xtns.pfuncs.*; import gplx.xowa.langs.kwds.*; import gplx.xowa.parsers.utils.*; import gplx.xowa.parsers.lnkis.*; import gplx.xowa.parsers.lnkis.files.*;
import gplx.xowa.files.*;
import gplx.xowa.htmls.core.htmls.*; import gplx.langs.htmls.encoders.*;
// REF.MW:https://github.com/wikimedia/mediawiki-extensions-WikidataPageBanner/blob/master/includes/WikidataPageBannerFunctions.php
// TODO.DATE:2019-11-11: calculate enableToc and hasPosition;
public class Pgbnr_func extends Pf_func_base {
@Override public int Id() {return Xol_kwd_grp_.Id_pagebanner;}
@Override public Pf_func New(int id, byte[] name) {return new Pgbnr_func().Name_(name);}
@Override public void Func_evaluate(Bry_bfr bfr, Xop_ctx ctx, Xot_invk caller, Xot_invk self, byte[] src) { // {{PAGEBANNER}} appears on page; WikidataPageBanner.hooks.php|addCustomBanner
Xowe_wiki wiki = ctx.Wiki(); Xoae_page page = ctx.Page();
Pgbnr_xtn_mgr xtn_mgr = wiki.Xtn_mgr().Xtn_pgbnr();
Pgbnr_cfg cfg = xtn_mgr.Cfg();
Xoa_ttl ttl = page.Ttl();
if (!cfg.Chk_pgbnr_allowed(ttl, wiki)) return;
byte[] tooltip = ttl.Page_txt(), title = ttl.Page_txt(), toc = Bry_.Empty, origin_x = Bry_.Empty;
boolean bottomtoc = false;;
double data_pos_x = 0, data_pos_y = 0;
List_adp icons_list = null;
Bry_bfr tmp_bfr = Bry_bfr_.New();
int args_len = self.Args_len();
Xop_func_arg_itm func_arg = new Xop_func_arg_itm();
for (int i = 0; i < args_len; ++i) {
Arg_nde_tkn arg = self.Args_get_by_idx(i);
func_arg.Set(tmp_bfr, ctx, src, caller, self, arg);
byte[] key = func_arg.key;
byte[] val = func_arg.val;
if (key == Bry_.Empty) continue; // ignore blank args; EX:{{PAGEBANNER:A.png|\n|toc=yes}}
int tid = arg_hash.Get_as_int_or(key, -1);
if (tid == Arg__pgname)
tooltip = title = val;
if (tid == Arg__tooltip) // note that this overrides pgname above
tooltip = val;
if (tid == Arg__bottomtoc && Bry_.Eq(val, Bry__yes))
bottomtoc = true;
if (tid == Arg__toc && Bry_.Eq(val, Bry__yes)) // REF.MW:addToc
toc = Bry_.Empty; // note that "" will be overwritten later by actual toc html
if ( tid == -1 // note that "icon-*" won't have a tid
&& Bry_.Has_at_bgn(key, Bry__icon) // if (substr($key, 0, 5) === 'icon-')
&& Bry_.Len(key) > 5 // if ( !isset( $iconname) )
&& Bry_.Len_gt_0(val) // if ( !isset( $$value ) )
) { // REF.MW:addIcons
tid = Arg__icon;
if (icons_list == null) icons_list = List_adp_.New();
byte[] icon_key = Bry_.Mid(key, 5);
byte[] icon_name = Xop_sanitizer.Escape_cls(icon_key);
byte[] icon_title = icon_name;
Xoa_ttl icon_ttl = wiki.Ttl_parse(val);
byte[] icon_href = Bry__icon_href_dflt;
if (icon_ttl != null) {
icon_href = Bry_.Add(gplx.xowa.htmls.hrefs.Xoh_href_.Bry__wiki, icon_ttl.Page_db());
icon_title = icon_ttl.Page_txt();
}
icons_list.Add(new Pgbnr_icon(tmp_bfr, icon_name, icon_title, icon_href));
}
if (tid == Arg__origin) { // REF.MW:addFocus
double tmp_data_pos_x = Double_.NaN, tmp_data_pos_y = Double_.NaN;
int comma_pos = Bry_find_.Find_fwd(val, Byte_ascii.Comma);
if (comma_pos != Bry_find_.Not_found) {
tmp_data_pos_x = Bry_.To_double_or(val, 0, comma_pos, Double_.NaN);
if (!Double_.IsNaN(tmp_data_pos_x)) {
if (tmp_data_pos_x >= -1 && tmp_data_pos_x <= 1) {
data_pos_x = tmp_data_pos_x;
origin_x = tmp_data_pos_x <= .25d ? Bry__origin_x__left : Bry__origin_x__right;
}
}
if (!Double_.IsNaN(tmp_data_pos_y)) {
if (tmp_data_pos_y >= -1 && tmp_data_pos_y <= 1)
data_pos_y = tmp_data_pos_y;
}
}
}
if (tid == -1) Gfo_usr_dlg_.Instance.Warn_many("", "", "unknown arg type; page=~{0} key=~{1} val=~{2}", page.Ttl().Full_db(), key, val);
}
byte[] banner_name = Eval_argx(ctx, src, caller, self);
Xoa_ttl banner_ttl = wiki.Ttl_parse(banner_name); // NOTE: MW also creates title to auto-register page and image in imagelinks
if (banner_ttl == null) // if ttl is invalid, get it from wikidata; PAGE:en.v:Diving_the_Cape_Peninsula_and_False_Bay/Whale_Rock; DATE:2016-07-12
banner_ttl = Get_wikidata_banner(wiki.Appe(), wiki, wiki.Xtn_mgr().Xtn_pgbnr().Cfg(), page.Ttl());
if (banner_ttl == null) { // if ttl is still invalid, exit now else will fail with nullref below; PAGE:en.v:Peterborough (New Hampshire); DATE:2016-07-12
Gfo_usr_dlg_.Instance.Warn_many("", "", "banner file is invalid; page=~{0} banner=~{1}", page.Url_bry_safe(), banner_name);
return;
}
Xof_file_itm banner_file_itm = File__make_tkn(ctx, Xop_file_logger_.Tid__pgbnr_main, banner_ttl, Xop_lnki_tkn.Width_null, Xop_lnki_tkn.Height_null);
Pgbnr_itm itm = new Pgbnr_itm();
itm.Init_from_wtxt(banner_ttl, banner_file_itm, tooltip, title, bottomtoc, toc, data_pos_x, data_pos_y, origin_x, icons_list == null ? Pgbnr_icon.Ary_empty : (Pgbnr_icon[])icons_list.To_ary_and_clear(Pgbnr_icon.class));
page.Html_data().Xtn_pgbnr_(itm);
page.Html_data().Head_mgr().Itm__pgbnr().Enabled_y_(); // register css / js during parse stage
page.Wtxt().Toc().Flag__toc_(true); // NOTE: must mark toc_manual else will show 2nd TOC in edit mode; DATE:2016-07-10
}
public static void Add_banner(Bry_bfr bfr, Xoae_page wpg, Xop_ctx ctx, Xoh_wtr_ctx hctx, Pgbnr_itm itm) {
Xowe_wiki wiki = ctx.Wiki(); Xoae_app app = wiki.Appe();
Pgbnr_cfg cfg = wiki.Xtn_mgr().Xtn_pgbnr().Cfg(); if (!cfg.enabled) return;
Xoa_ttl ttl = wpg.Ttl();
Xoa_ttl banner_ttl = null; byte[] banner_html = null;
if (itm != null) { // {{PAGEBANNER}} exists in wikitext
itm.Init_hdump(hctx.Mode_is_hdump());
banner_ttl = itm.banner_ttl;
banner_html = Get_banner_html(wiki, ctx, hctx, cfg, banner_ttl, itm);
if (banner_html == null) { // no banner; try again using title from wikidata; note that this should only happen if no banner_ttl or banner_ttl is invalid; EX:{{PAGEBANNER:|toc=yes}}
banner_ttl = Get_wikidata_banner(app, wiki, cfg, ttl);
banner_html = Get_banner_html(wiki, ctx, hctx, cfg, banner_ttl, itm);
}
}
else if ( ttl.Ns().Id_is_main() // {{PAGEBANNER}} missing, but wiki is marked as enable_default_banner
&& cfg.enable_default_banner
&& cfg.Chk_pgbnr_allowed(ttl, wiki)
) {
banner_ttl = Get_wikidata_banner(app, wiki, cfg, ttl);
if (banner_ttl == null)
banner_ttl = wiki.Ttl_parse(cfg.dflt_img_title);
Xof_file_itm banner_file_itm = File__make_tkn(ctx, Xop_file_logger_.Tid__pgbnr_main, banner_ttl, Xop_lnki_tkn.Width_null, Xop_lnki_tkn.Height_null);
itm = new Pgbnr_itm();
itm.Init_from_wtxt(banner_ttl, banner_file_itm, Bry_.Empty, Bry_.Empty, false, Bry_.Empty, 0, 0, Bry_.Empty, Pgbnr_icon.Ary_empty);
itm.Init_hdump(hctx.Mode_is_hdump());
banner_html = Get_banner_html(wiki, ctx, hctx, cfg, banner_ttl, itm);
}
if (banner_html != null) {
bfr.Add(banner_html);
}
}
public static byte[] Get_banner_html(Xowe_wiki wiki, Xop_ctx ctx, Xoh_wtr_ctx hctx, Pgbnr_cfg cfg, Xoa_ttl banner_ttl, Pgbnr_itm itm) {
byte[][] urls = Get_standard_size_urls(wiki, cfg, banner_ttl); if (urls == null) return null;
Bry_bfr tmp_bfr = Bry_bfr_.New();
int urls_len = urls.length;
int[] sizes = cfg.standard_sizes;
for (int i = 0; i < urls_len; ++i) {
int size = sizes[i];
if (i != 0) tmp_bfr.Add_byte_comma();
tmp_bfr.Add(urls[i]).Add_byte_space().Add_int_variable(size).Add_byte(Byte_ascii.Ltr_w); // REF.MW: $srcset[] = "$url {$size}w";
}
byte[] srcset = tmp_bfr.To_bry_and_clear();
byte[] banner_url = itm.banner_img_src != null ? itm.banner_img_src : urls.length == 0 ? Bry_.Empty : urls[urls_len - 1]; // gets largest url
Xof_file_itm banner_file_itm = itm.banner_file_itm;
int max_width = banner_file_itm.Orig_w(); // $file = wfFindFile( banner_file ); $options['max_width'] = $file->getWidth();
// Provide information to the logic-less template about whether it is a panorama or not.
boolean isPanorama = banner_file_itm.Orig_w() > (banner_file_itm.Orig_h() * 2);
byte[] banner_file = null; // $bannerfile->getLocalUrl();
byte[] toc_html = null;
if (hctx.Mode_is_hdump()) {
gplx.xowa.htmls.core.wkrs.tocs.Xoh_toc_wtr.Write_tag(tmp_bfr, true);
toc_html = tmp_bfr.To_bry_and_clear();
banner_file = Bry_.Add(gplx.xowa.htmls.hrefs.Xoh_href_.Bry__wiki, gplx.xowa.wikis.nss.Xow_ns_.Bry__file, Byte_ascii.Colon_bry
, Gfo_url_encoder_.Href.Encode(banner_ttl.Full_db())); // NOTE: must encode so "'" becomes "%27", not "&#39;"; PAGE:en.v:'s-Hertogenbosch; DATE:2016-07-12
}
else {
ctx.Page().Html_data().Toc_mgr().To_html(tmp_bfr, Xoh_wtr_ctx.Basic, true);
toc_html = tmp_bfr.To_bry_and_clear();
}
itm.Init_from_html(max_width, banner_file, banner_url, srcset, cfg.enable_heading_override, toc_html, isPanorama);
Mustache_render_ctx mctx = new Mustache_render_ctx().Init(itm);
Mustache_bfr mbfr = Mustache_bfr.New_bfr(tmp_bfr);
wiki.Xtn_mgr().Xtn_pgbnr().Template_root().Render(mbfr, mctx);
return mbfr.To_bry_and_clear();
}
private static byte[][] Get_standard_size_urls(Xow_wiki wiki, Pgbnr_cfg cfg, Xoa_ttl banner_ttl) {
Ordered_hash hash = Ordered_hash_.New_bry();
int[] sizes = cfg.standard_sizes;
int sizes_len = sizes.length;
for (int i = 0; i < sizes_len; ++i) {
byte[] url = Get_image_url(wiki, banner_ttl, sizes[i]);
if (url != null)
hash.Add_if_dupe_use_1st(url, url);
}
return (byte[][])hash.To_ary_and_clear(byte[].class);
}
private static byte[] Get_image_url(Xow_wiki wiki, Xoa_ttl banner_ttl, int width) {
// Object file = new Object(); // $file = wfFindFile( file_ttl );
// if (file == null) return null;
if (width >= 0 && width <= 3000) {
// $mto = $file->transform( array( 'width' => $imagewidth ) );
byte[] url = new byte[0]; // $url = wfExpandUrl( $mto->getUrl(), PROTO_CURRENT );
return url;
}
else
return new byte[0]; // $file->getFullUrl();
}
private static Xoa_ttl Get_wikidata_banner(Xoae_app app, Xow_wiki wiki, Pgbnr_cfg cfg, Xoa_ttl ttl) {
byte[] rv = app.Wiki_mgr().Wdata_mgr().Get_claim_or(wiki.Domain_itm(), ttl, cfg.dflt_img_wdata_prop, null); // don't log misses; wikivoyage pages will default to show pagebanner, and many pages may not have wikidata definitions
if (rv == null) return null;
return wiki.Ttl_parse(rv);
}
private static Xof_file_itm File__make_tkn(Xop_ctx ctx, byte tid, Xoa_ttl file_ttl, int file_w, int file_h) {
Xop_lnki_tkn lnki = ctx.Tkn_mkr().Lnki(file_w, file_h).Ttl_(file_ttl);
ctx.Page().Lnki_list().Add(lnki);
ctx.Lnki().File_logger().Log_file(tid, ctx, lnki); // NOTE: do not set file_wkr ref early (as member var); parse_all sets late
Xof_file_itm file_itm = ctx.Wiki().Html_mgr().Html_wtr().Lnki_wtr().File_wtr().Lnki_eval(Xof_exec_tid.Tid_wiki_page, ctx, ctx.Page(), lnki);
return file_itm;
}
private static final byte[] Bry__yes = Bry_.new_a7("yes"), Bry__icon = Bry_.new_a7("icon-"), Bry__icon_href_dflt = Bry_.new_a7("#"), Bry__origin_x__left = Bry_.new_a7("wpb-left"), Bry__origin_x__right = Bry_.new_a7("wpb-right");
private static final int Arg__pgname = 0, Arg__tooltip = 1, Arg__bottomtoc = 2, Arg__toc = 3, Arg__icon = 4, Arg__origin = 5;
private static final Hash_adp_bry arg_hash = Hash_adp_bry.cs().Add_str_int("pgname", Arg__pgname)
.Add_str_int("tooltip", Arg__tooltip).Add_str_int("bottomtoc", Arg__bottomtoc).Add_str_int("toc", Arg__toc).Add_str_int("origin", Arg__origin);
}
package gplx.xowa.xtns.pagebanners;
import gplx.Bry_;
import gplx.Bry_bfr;
import gplx.Bry_bfr_;
import gplx.Bry_find_;
import gplx.Byte_ascii;
import gplx.Double_;
import gplx.Gfo_usr_dlg_;
import gplx.Hash_adp_bry;
import gplx.List_adp;
import gplx.List_adp_;
import gplx.Ordered_hash;
import gplx.Ordered_hash_;
import gplx.langs.htmls.encoders.Gfo_url_encoder_;
import gplx.langs.mustaches.JsonMustacheNde;
import gplx.langs.mustaches.Mustache_bfr;
import gplx.langs.mustaches.Mustache_render_ctx;
import gplx.xowa.Xoa_ttl;
import gplx.xowa.Xoae_app;
import gplx.xowa.Xoae_page;
import gplx.xowa.Xow_wiki;
import gplx.xowa.Xowe_wiki;
import gplx.xowa.files.Xof_exec_tid;
import gplx.xowa.files.Xof_file_itm;
import gplx.xowa.htmls.core.htmls.Xoh_wtr_ctx;
import gplx.xowa.langs.kwds.Xol_kwd_grp_;
import gplx.xowa.parsers.Xop_ctx;
import gplx.xowa.parsers.lnkis.Xop_lnki_tkn;
import gplx.xowa.parsers.lnkis.files.Xop_file_logger_;
import gplx.xowa.parsers.tmpls.Arg_nde_tkn;
import gplx.xowa.parsers.tmpls.Xop_func_arg_itm;
import gplx.xowa.parsers.tmpls.Xot_invk;
import gplx.xowa.parsers.utils.Xop_sanitizer;
import gplx.xowa.xtns.pfuncs.Pf_func;
import gplx.xowa.xtns.pfuncs.Pf_func_base;
// REF.MW:https://github.com/wikimedia/mediawiki-extensions-WikidataPageBanner/blob/master/includes/WikidataPageBannerFunctions.php
// TODO.DATE:2019-11-11: calculate enableToc and hasPosition;
public class Pgbnr_func extends Pf_func_base {
@Override public int Id() {return Xol_kwd_grp_.Id_pagebanner;}
@Override public Pf_func New(int id, byte[] name) {return new Pgbnr_func().Name_(name);}
@Override public void Func_evaluate(Bry_bfr bfr, Xop_ctx ctx, Xot_invk caller, Xot_invk self, byte[] src) { // {{PAGEBANNER}} appears on page; WikidataPageBanner.hooks.php|addCustomBanner
Xowe_wiki wiki = ctx.Wiki(); Xoae_page page = ctx.Page();
Pgbnr_xtn_mgr xtn_mgr = wiki.Xtn_mgr().Xtn_pgbnr();
Pgbnr_cfg cfg = xtn_mgr.Cfg();
Xoa_ttl ttl = page.Ttl();
if (!cfg.Chk_pgbnr_allowed(ttl, wiki)) return;
byte[] tooltip = ttl.Page_txt(), title = ttl.Page_txt(), toc = Bry_.Empty, origin_x = Bry_.Empty;
boolean bottomtoc = false;;
double data_pos_x = 0, data_pos_y = 0;
List_adp icons_list = null;
Bry_bfr tmp_bfr = Bry_bfr_.New();
int args_len = self.Args_len();
Xop_func_arg_itm func_arg = new Xop_func_arg_itm();
for (int i = 0; i < args_len; ++i) {
Arg_nde_tkn arg = self.Args_get_by_idx(i);
func_arg.Set(tmp_bfr, ctx, src, caller, self, arg);
byte[] key = func_arg.key;
byte[] val = func_arg.val;
if (key == Bry_.Empty) continue; // ignore blank args; EX:{{PAGEBANNER:A.png|\n|toc=yes}}
int tid = arg_hash.Get_as_int_or(key, -1);
if (tid == Arg__pgname)
tooltip = title = val;
if (tid == Arg__tooltip) // note that this overrides pgname above
tooltip = val;
if (tid == Arg__bottomtoc && Bry_.Eq(val, Bry__yes))
bottomtoc = true;
if (tid == Arg__toc && Bry_.Eq(val, Bry__yes)) // REF.MW:addToc
toc = Bry_.Empty; // note that "" will be overwritten later by actual toc html
if ( tid == -1 // note that "icon-*" won't have a tid
&& Bry_.Has_at_bgn(key, Bry__icon) // if (substr($key, 0, 5) === 'icon-')
&& Bry_.Len(key) > 5 // if ( !isset( $iconname) )
&& Bry_.Len_gt_0(val) // if ( !isset( $$value ) )
) { // REF.MW:addIcons
tid = Arg__icon;
if (icons_list == null) icons_list = List_adp_.New();
byte[] icon_key = Bry_.Mid(key, 5);
byte[] icon_name = Xop_sanitizer.Escape_cls(icon_key);
byte[] icon_title = icon_name;
Xoa_ttl icon_ttl = wiki.Ttl_parse(val);
byte[] icon_href = Bry__icon_href_dflt;
if (icon_ttl != null) {
icon_href = Bry_.Add(gplx.xowa.htmls.hrefs.Xoh_href_.Bry__wiki, icon_ttl.Page_db());
icon_title = icon_ttl.Page_txt();
}
icons_list.Add(new Pgbnr_icon(tmp_bfr, icon_name, icon_title, icon_href));
// itm.Add_new_icon(tmp_bfr, icon_name, icon_title, icon_href);
}
if (tid == Arg__origin) { // REF.MW:addFocus
double tmp_data_pos_x = Double_.NaN, tmp_data_pos_y = Double_.NaN;
int comma_pos = Bry_find_.Find_fwd(val, Byte_ascii.Comma);
if (comma_pos != Bry_find_.Not_found) {
tmp_data_pos_x = Bry_.To_double_or(val, 0, comma_pos, Double_.NaN);
if (!Double_.IsNaN(tmp_data_pos_x)) {
if (tmp_data_pos_x >= -1 && tmp_data_pos_x <= 1) {
data_pos_x = tmp_data_pos_x;
origin_x = tmp_data_pos_x <= .25d ? Bry__origin_x__left : Bry__origin_x__right;
}
}
if (!Double_.IsNaN(tmp_data_pos_y)) {
if (tmp_data_pos_y >= -1 && tmp_data_pos_y <= 1)
data_pos_y = tmp_data_pos_y;
}
}
}
if (tid == -1) Gfo_usr_dlg_.Instance.Warn_many("", "", "unknown arg type; page=~{0} key=~{1} val=~{2}", page.Ttl().Full_db(), key, val);
}
byte[] banner_name = Eval_argx(ctx, src, caller, self);
Xoa_ttl banner_ttl = wiki.Ttl_parse(banner_name); // NOTE: MW also creates title to auto-register page and image in imagelinks
if (banner_ttl == null) // if ttl is invalid, get it from wikidata; PAGE:en.v:Diving_the_Cape_Peninsula_and_False_Bay/Whale_Rock; DATE:2016-07-12
banner_ttl = Get_wikidata_banner(wiki.Appe(), wiki, wiki.Xtn_mgr().Xtn_pgbnr().Cfg(), page.Ttl());
if (banner_ttl == null) { // if ttl is still invalid, exit now else will fail with nullref below; PAGE:en.v:Peterborough (New Hampshire); DATE:2016-07-12
Gfo_usr_dlg_.Instance.Warn_many("", "", "banner file is invalid; page=~{0} banner=~{1}", page.Url_bry_safe(), banner_name);
return;
}
Xof_file_itm banner_file_itm = File__make_tkn(ctx, Xop_file_logger_.Tid__pgbnr_main, banner_ttl, Xop_lnki_tkn.Width_null, Xop_lnki_tkn.Height_null);
Pgbnr_itm itm = new Pgbnr_itm();
itm.Init_from_wtxt(banner_ttl, banner_file_itm, tooltip, title, bottomtoc, toc, data_pos_x, data_pos_y, origin_x, icons_list == null ? Pgbnr_icon.Ary_empty : (Pgbnr_icon[])icons_list.To_ary_and_clear(Pgbnr_icon.class));
page.Html_data().Xtn_pgbnr_(itm);
page.Html_data().Head_mgr().Itm__pgbnr().Enabled_y_(); // register css / js during parse stage
page.Wtxt().Toc().Flag__toc_(true); // NOTE: must mark toc_manual else will show 2nd TOC in edit mode; DATE:2016-07-10
}
public static void Add_banner(Bry_bfr bfr, Xoae_page wpg, Xop_ctx ctx, Xoh_wtr_ctx hctx, Pgbnr_itm itm) {
Xowe_wiki wiki = ctx.Wiki(); Xoae_app app = wiki.Appe();
Pgbnr_cfg cfg = wiki.Xtn_mgr().Xtn_pgbnr().Cfg(); if (!cfg.enabled) return;
Xoa_ttl ttl = wpg.Ttl();
Xoa_ttl banner_ttl = null; byte[] banner_html = null;
if (itm != null) { // {{PAGEBANNER}} exists in wikitext
itm.Init_hdump(hctx.Mode_is_hdump());
banner_ttl = itm.banner_ttl;
banner_html = Get_banner_html(wiki, ctx, hctx, cfg, banner_ttl, itm);
if (banner_html == null) { // no banner; try again using title from wikidata; note that this should only happen if no banner_ttl or banner_ttl is invalid; EX:{{PAGEBANNER:|toc=yes}}
banner_ttl = Get_wikidata_banner(app, wiki, cfg, ttl);
banner_html = Get_banner_html(wiki, ctx, hctx, cfg, banner_ttl, itm);
}
}
else if ( ttl.Ns().Id_is_main() // {{PAGEBANNER}} missing, but wiki is marked as enable_default_banner
&& cfg.enable_default_banner
&& cfg.Chk_pgbnr_allowed(ttl, wiki)
) {
banner_ttl = Get_wikidata_banner(app, wiki, cfg, ttl);
if (banner_ttl == null)
banner_ttl = wiki.Ttl_parse(cfg.dflt_img_title);
Xof_file_itm banner_file_itm = File__make_tkn(ctx, Xop_file_logger_.Tid__pgbnr_main, banner_ttl, Xop_lnki_tkn.Width_null, Xop_lnki_tkn.Height_null);
itm = new Pgbnr_itm();
itm.Init_from_wtxt(banner_ttl, banner_file_itm, Bry_.Empty, Bry_.Empty, false, Bry_.Empty, 0, 0, Bry_.Empty, Pgbnr_icon.Ary_empty);
itm.Init_hdump(hctx.Mode_is_hdump());
banner_html = Get_banner_html(wiki, ctx, hctx, cfg, banner_ttl, itm);
}
if (banner_html != null) {
bfr.Add(banner_html);
}
}
public static byte[] Get_banner_html(Xowe_wiki wiki, Xop_ctx ctx, Xoh_wtr_ctx hctx, Pgbnr_cfg cfg, Xoa_ttl banner_ttl, Pgbnr_itm itm) {
byte[][] urls = Get_standard_size_urls(wiki, cfg, banner_ttl); if (urls == null) return null;
Bry_bfr tmp_bfr = Bry_bfr_.New();
int urls_len = urls.length;
int[] sizes = cfg.standard_sizes;
for (int i = 0; i < urls_len; ++i) {
int size = sizes[i];
if (i != 0) tmp_bfr.Add_byte_comma();
tmp_bfr.Add(urls[i]).Add_byte_space().Add_int_variable(size).Add_byte(Byte_ascii.Ltr_w); // REF.MW: $srcset[] = "$url {$size}w";
}
byte[] srcset = tmp_bfr.To_bry_and_clear();
byte[] banner_url = itm.banner_img_src != null ? itm.banner_img_src : urls.length == 0 ? Bry_.Empty : urls[urls_len - 1]; // gets largest url
Xof_file_itm banner_file_itm = itm.banner_file_itm;
int max_width = banner_file_itm.Orig_w(); // $file = wfFindFile( banner_file ); $options['max_width'] = $file->getWidth();
// Provide information to the logic-less template about whether it is a panorama or not.
boolean isPanorama = banner_file_itm.Orig_w() > (banner_file_itm.Orig_h() * 2);
byte[] banner_file = null; // $bannerfile->getLocalUrl();
byte[] toc_html = null;
if (hctx.Mode_is_hdump()) {
gplx.xowa.htmls.core.wkrs.tocs.Xoh_toc_wtr.Write_tag(tmp_bfr, true);
toc_html = tmp_bfr.To_bry_and_clear();
banner_file = Bry_.Add(gplx.xowa.htmls.hrefs.Xoh_href_.Bry__wiki, gplx.xowa.wikis.nss.Xow_ns_.Bry__file, Byte_ascii.Colon_bry
, Gfo_url_encoder_.Href.Encode(banner_ttl.Full_db())); // NOTE: must encode so "'" becomes "%27", not "&#39;"; PAGE:en.v:'s-Hertogenbosch; DATE:2016-07-12
}
else {
ctx.Page().Html_data().Toc_mgr().To_html(tmp_bfr, Xoh_wtr_ctx.Basic, true);
toc_html = tmp_bfr.To_bry_and_clear();
}
itm.Init_from_html(max_width, banner_file, banner_url, srcset, cfg.enable_heading_override, toc_html, isPanorama);
Mustache_render_ctx mctx = new Mustache_render_ctx().Init(new JsonMustacheNde(itm.Mustache__json()));
// Mustache_render_ctx mctx = new Mustache_render_ctx().Init(itm);
Mustache_bfr mbfr = Mustache_bfr.New_bfr(tmp_bfr);
wiki.Xtn_mgr().Xtn_pgbnr().Template_root().Render(mbfr, mctx);
return mbfr.To_bry_and_clear();
}
private static byte[][] Get_standard_size_urls(Xow_wiki wiki, Pgbnr_cfg cfg, Xoa_ttl banner_ttl) {
Ordered_hash hash = Ordered_hash_.New_bry();
int[] sizes = cfg.standard_sizes;
int sizes_len = sizes.length;
for (int i = 0; i < sizes_len; ++i) {
byte[] url = Get_image_url(wiki, banner_ttl, sizes[i]);
if (url != null)
hash.Add_if_dupe_use_1st(url, url);
}
return (byte[][])hash.To_ary_and_clear(byte[].class);
}
private static byte[] Get_image_url(Xow_wiki wiki, Xoa_ttl banner_ttl, int width) {
// Object file = new Object(); // $file = wfFindFile( file_ttl );
// if (file == null) return null;
if (width >= 0 && width <= 3000) {
// $mto = $file->transform( array( 'width' => $imagewidth ) );
byte[] url = new byte[0]; // $url = wfExpandUrl( $mto->getUrl(), PROTO_CURRENT );
return url;
}
else
return new byte[0]; // $file->getFullUrl();
}
private static Xoa_ttl Get_wikidata_banner(Xoae_app app, Xow_wiki wiki, Pgbnr_cfg cfg, Xoa_ttl ttl) {
byte[] rv = app.Wiki_mgr().Wdata_mgr().Get_claim_or(wiki.Domain_itm(), ttl, cfg.dflt_img_wdata_prop, null); // don't log misses; wikivoyage pages will default to show pagebanner, and many pages may not have wikidata definitions
if (rv == null) return null;
return wiki.Ttl_parse(rv);
}
private static Xof_file_itm File__make_tkn(Xop_ctx ctx, byte tid, Xoa_ttl file_ttl, int file_w, int file_h) {
Xop_lnki_tkn lnki = ctx.Tkn_mkr().Lnki(file_w, file_h).Ttl_(file_ttl);
ctx.Page().Lnki_list().Add(lnki);
ctx.Lnki().File_logger().Log_file(tid, ctx, lnki); // NOTE: do not set file_wkr ref early (as member var); parse_all sets late
Xof_file_itm file_itm = ctx.Wiki().Html_mgr().Html_wtr().Lnki_wtr().File_wtr().Lnki_eval(Xof_exec_tid.Tid_wiki_page, ctx, ctx.Page(), lnki);
return file_itm;
}
private static final byte[] Bry__yes = Bry_.new_a7("yes"), Bry__icon = Bry_.new_a7("icon-"), Bry__icon_href_dflt = Bry_.new_a7("#"), Bry__origin_x__left = Bry_.new_a7("wpb-left"), Bry__origin_x__right = Bry_.new_a7("wpb-right");
private static final int Arg__pgname = 0, Arg__tooltip = 1, Arg__bottomtoc = 2, Arg__toc = 3, Arg__icon = 4, Arg__origin = 5;
private static final Hash_adp_bry arg_hash = Hash_adp_bry.cs().Add_str_int("pgname", Arg__pgname)
.Add_str_int("tooltip", Arg__tooltip).Add_str_int("bottomtoc", Arg__bottomtoc).Add_str_int("toc", Arg__toc).Add_str_int("origin", Arg__origin);
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,79 +13,92 @@ 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.pagebanners; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
import org.junit.*; import gplx.core.brys.*; import gplx.xowa.wikis.pages.skins.*;
import gplx.xowa.htmls.core.htmls.*;
public class Pgbnr_func_tst {
private final Pgbnr_func_fxt fxt = new Pgbnr_func_fxt();
@Before public void init() {fxt.Clear();}
@Test public void Basic() {
fxt.Init__orig(true, "A.png", 500, 200); // 500 > 200 * 2 for pageBanner;
fxt.Test__parse(Bool_.N, "{{PAGEBANNER:A.png|icon-star=Star_article}}", String_.Concat_lines_nl_apos_skip_last
( "<div class='ext-wpb-pagebanner pre-content'>"
, " <div class='wpb-banner-image-panorama wpb-topbanner'>"
, " <h1 class='wpb-name'>Test page</h1>"
, " <a href='' class='image' title='Test page' xowa_title='A.png'><img id='xoimg_0' src='file:///mem/wiki/repo/src/orig/7/0/A.png' width='0' height='0' class='wpb-banner-image ' alt='' srcset='' data-pos-x='0' data-pos-y='0' style='max-width:500px'></a>"
, " <div class='wpb-iconbox'>"
, " <a href='/wiki/Star_article'><span aria-disabled='false' title='Star article' class='oo-ui-widget oo-ui-widget-enabled oo-ui-iconElement-icon oo-ui-icon-star oo-ui-iconElement oo-ui-iconWidget'></span></a>"
, " </div>"
, " </div>"
, " <div class='wpb-topbanner-toc'><div class='wpb-banner-toc'><div>"
, " <div id=\"toctitle\" class=\"toctitle\">"
, " <h2>Contents</h2>"
, " </div>"
, "</div>"
, "</div></div>"
, "</div>"
));
}
@Test public void Hdump__basic() {
fxt.Test__parse(Bool_.Y, "{{PAGEBANNER:A.png|icon-star=Star_article}}", String_.Concat_lines_nl_apos_skip_last
( "<div class='ext-wpb-pagebanner pre-content'>"
, " <div class='wpb-topbanner'>"
, " <h1 class='wpb-name'>Test page</h1>"
, " <a href='/wiki/File:A.png' class='image' title='Test page' xowa_title='A.png'>"
+ "<img data-xowa-title=\"A.png\" data-xoimg=\"1|-1|-1|-1|-1|-1\" src='' width='0' height='0' class='wpb-banner-image ' alt='' srcset='' data-pos-x='0' data-pos-y='0' style='max-width:0px'></a>"
, " <div class='wpb-iconbox'>"
, " <a href='/wiki/Star_article'><span aria-disabled='false' title='Star article' class='oo-ui-widget oo-ui-widget-enabled oo-ui-iconElement-icon oo-ui-icon-star oo-ui-iconElement oo-ui-iconWidget'></span></a>"
, " </div>"
, " </div>"
, " <div class='wpb-topbanner-toc'><div class='wpb-banner-toc'><div class=\"xo-toc\" data-toc-mode=\"1\"></div></div></div>"
, "</div>"
));
}
@Test public void Hdump__quote() { // PAGE:en.v:Europe; DATE:2016-07-12
fxt.Test__parse(Bool_.Y, "{{PAGEBANNER:A\"b.png|icon-star=Star_article}}", String_.Concat_lines_nl_apos_skip_last
( "<div class='ext-wpb-pagebanner pre-content'>"
, " <div class='wpb-topbanner'>"
, " <h1 class='wpb-name'>Test page</h1>"
, " <a href='/wiki/File:A%22b.png' class='image' title='Test page' xowa_title='A%22b.png'><img data-xowa-title=\"A%22b.png\" data-xoimg=\"1|-1|-1|-1|-1|-1\" src='' width='0' height='0' class='wpb-banner-image ' alt='' srcset='' data-pos-x='0' data-pos-y='0' style='max-width:0px'></a>"
, " <div class='wpb-iconbox'>"
, " <a href='/wiki/Star_article'><span aria-disabled='false' title='Star article' class='oo-ui-widget oo-ui-widget-enabled oo-ui-iconElement-icon oo-ui-icon-star oo-ui-iconElement oo-ui-iconWidget'></span></a>"
, " </div>"
, " </div>"
, " <div class='wpb-topbanner-toc'><div class='wpb-banner-toc'><div class=\"xo-toc\" data-toc-mode=\"1\"></div></div></div>"
, "</div>"
));
}
}
class Pgbnr_func_fxt {
private Xop_fxt fxt;
public void Clear() {
Xoae_app app = Xoa_app_fxt.Make__app__edit();
Xowe_wiki wiki = Xoa_app_fxt.Make__wiki__edit(app, "en.wikivoyage.org");
fxt = new Xop_fxt(app, wiki);
fxt.Init__file_find_mgr();
}
public void Init__orig(boolean wiki_is_commons, String orig_ttl, int orig_w, int orig_h) {
fxt.Init__orig(wiki_is_commons, orig_ttl, orig_w, orig_h);
}
public void Test__parse(boolean hdump, String raw, String expd) {
fxt.Exec_parse_page_all_as_str(raw);
Xoh_wtr_ctx hctx = hdump ? Xoh_wtr_ctx.Hdump : Xoh_wtr_ctx.Basic;
Bfr_arg arg = fxt.Wiki().Xtn_mgr().Xtn_pgbnr().Write_html(fxt.Page(), fxt.Ctx(), hctx);
Bry_bfr bfr = Bry_bfr_.New();
arg.Bfr_arg__add(bfr);
Tfds.Eq_str_lines(expd, bfr.To_str_and_clear());
}
}
package gplx.xowa.xtns.pagebanners;
import gplx.Bool_;
import gplx.Bry_bfr;
import gplx.Bry_bfr_;
import gplx.String_;
import gplx.Tfds;
import gplx.core.brys.Bfr_arg;
import gplx.xowa.Xoa_app_fxt;
import gplx.xowa.Xoae_app;
import gplx.xowa.Xop_fxt;
import gplx.xowa.Xowe_wiki;
import gplx.xowa.htmls.core.htmls.Xoh_wtr_ctx;
import org.junit.Before;
import org.junit.Test;
public class Pgbnr_func_tst {
private final Pgbnr_func_fxt fxt = new Pgbnr_func_fxt();
@Before public void init() {fxt.Clear();}
@Test public void Basic() {
fxt.Init__orig(true, "A.png", 500, 200); // 500 > 200 * 2 for pageBanner;
fxt.Test__parse(Bool_.N, "{{PAGEBANNER:A.png|icon-star=Star_article}}", String_.Concat_lines_nl_apos_skip_last
( "<div class='ext-wpb-pagebanner pre-content'>"
, " <div class='wpb-banner-image-panorama wpb-topbanner'>"
, " <h1 class='wpb-name'>Test page</h1>"
, " <a href='' class='image' title='Test page' xowa_title='A.png'><img id='xoimg_0' src='file:///mem/wiki/repo/src/orig/7/0/A.png' width='0' height='0' class='wpb-banner-image ' alt='' srcset='' data-pos-x='0' data-pos-y='0' style='max-width:500px'></a>"
, " <div class='wpb-iconbox'>"
, " <a href='/wiki/Star_article'><span aria-disabled='false' title='Star article' class='oo-ui-widget oo-ui-widget-enabled oo-ui-iconElement-icon oo-ui-icon-star oo-ui-iconElement oo-ui-iconWidget'></span></a>"
, " </div>"
, " </div>"
, " <div class='wpb-topbanner-toc'><div class='wpb-banner-toc'><div>"
, " <div id=\"toctitle\" class=\"toctitle\">"
, " <h2>Contents</h2>"
, " </div>"
, "</div>"
, "</div></div>"
, "</div>"
));
}
@Test public void Hdump__basic() {
fxt.Test__parse(Bool_.Y, "{{PAGEBANNER:A.png|icon-star=Star_article}}", String_.Concat_lines_nl_apos_skip_last
( "<div class='ext-wpb-pagebanner pre-content'>"
, " <div class='wpb-topbanner'>"
, " <h1 class='wpb-name'>Test page</h1>"
, " <a href='/wiki/File:A.png' class='image' title='Test page' xowa_title='A.png'>"
+ "<img data-xowa-title=\"A.png\" data-xoimg=\"1|-1|-1|-1|-1|-1\" src='' width='0' height='0' class='wpb-banner-image ' alt='' srcset='' data-pos-x='0' data-pos-y='0' style='max-width:0px'></a>"
, " <div class='wpb-iconbox'>"
, " <a href='/wiki/Star_article'><span aria-disabled='false' title='Star article' class='oo-ui-widget oo-ui-widget-enabled oo-ui-iconElement-icon oo-ui-icon-star oo-ui-iconElement oo-ui-iconWidget'></span></a>"
, " </div>"
, " </div>"
, " <div class='wpb-topbanner-toc'><div class='wpb-banner-toc'><div class=\"xo-toc\" data-toc-mode=\"1\"></div></div></div>"
, "</div>"
));
}
@Test public void Hdump__quote() { // PAGE:en.v:Europe; DATE:2016-07-12
fxt.Test__parse(Bool_.Y, "{{PAGEBANNER:A\"b.png|icon-star=Star_article}}", String_.Concat_lines_nl_apos_skip_last
( "<div class='ext-wpb-pagebanner pre-content'>"
, " <div class='wpb-topbanner'>"
, " <h1 class='wpb-name'>Test page</h1>"
, " <a href='/wiki/File:A%22b.png' class='image' title='Test page' xowa_title='A%22b.png'><img data-xowa-title=\"A%22b.png\" data-xoimg=\"1|-1|-1|-1|-1|-1\" src='' width='0' height='0' class='wpb-banner-image ' alt='' srcset='' data-pos-x='0' data-pos-y='0' style='max-width:0px'></a>"
, " <div class='wpb-iconbox'>"
, " <a href='/wiki/Star_article'><span aria-disabled='false' title='Star article' class='oo-ui-widget oo-ui-widget-enabled oo-ui-iconElement-icon oo-ui-icon-star oo-ui-iconElement oo-ui-iconWidget'></span></a>"
, " </div>"
, " </div>"
, " <div class='wpb-topbanner-toc'><div class='wpb-banner-toc'><div class=\"xo-toc\" data-toc-mode=\"1\"></div></div></div>"
, "</div>"
));
}
}
class Pgbnr_func_fxt {
private Xop_fxt fxt;
public void Clear() {
Xoae_app app = Xoa_app_fxt.Make__app__edit();
Xowe_wiki wiki = Xoa_app_fxt.Make__wiki__edit(app, "en.wikivoyage.org");
fxt = new Xop_fxt(app, wiki);
fxt.Init__file_find_mgr();
}
public void Init__orig(boolean wiki_is_commons, String orig_ttl, int orig_w, int orig_h) {
fxt.Init__orig(wiki_is_commons, orig_ttl, orig_w, orig_h);
}
public void Test__parse(boolean hdump, String raw, String expd) {
fxt.Exec_parse_page_all_as_str(raw);
Xoh_wtr_ctx hctx = hdump ? Xoh_wtr_ctx.Hdump : Xoh_wtr_ctx.Basic;
Bfr_arg arg = fxt.Wiki().Xtn_mgr().Xtn_pgbnr().Write_html(fxt.Page(), fxt.Ctx(), hctx);
Bry_bfr bfr = Bry_bfr_.New();
arg.Bfr_arg__add(bfr);
Tfds.Eq_str_lines(expd, bfr.To_str_and_clear());
}
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,28 +13,39 @@ 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.pagebanners; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
import gplx.core.brys.fmtrs.*;
import gplx.langs.mustaches.*;
public class Pgbnr_icon implements Mustache_doc_itm {
private final byte[] name, title, href, html;
public Pgbnr_icon(Bry_bfr tmp_bfr, byte[] name, byte[] title, byte[] href) {
this.name = name; this.title = title; this.href = href;
fmt.Bld_many(tmp_bfr, name, title);
this.html = tmp_bfr.To_bry_and_clear();
}
public boolean Mustache__write(String key, Mustache_bfr bfr) {
if (String_.Eq(key, "name")) bfr.Add_bry(name);
else if (String_.Eq(key, "title")) bfr.Add_bry(title);
else if (String_.Eq(key, "url")) bfr.Add_bry(href);
else if (String_.Eq(key, "html")) bfr.Add_bry(html);
else return false;
return true;
}
public Mustache_doc_itm[] Mustache__subs(String key) {return Mustache_doc_itm_.Ary__empty;}
public static final Pgbnr_icon[] Ary_empty = new Pgbnr_icon[0];
public static final Bry_fmt fmt = Bry_fmt.New
( Bry_.New_u8_nl_apos("<span aria-disabled='false' title='~{title}' class='oo-ui-widget oo-ui-widget-enabled oo-ui-iconElement-icon oo-ui-icon-~{name} oo-ui-iconElement oo-ui-iconWidget'></span>")
, "name", "title"
);
}
package gplx.xowa.xtns.pagebanners;
import gplx.Bry_;
import gplx.Bry_bfr;
import gplx.Bry_fmt;
import gplx.String_;
import gplx.langs.mustaches.Mustache_bfr;
import gplx.langs.mustaches.Mustache_doc_itm;
import gplx.langs.mustaches.Mustache_doc_itm_;
public class Pgbnr_icon implements Mustache_doc_itm {
private final byte[] name, title, href, html;
public Pgbnr_icon(Bry_bfr tmp_bfr, byte[] name, byte[] title, byte[] href) {
this.name = name; this.title = title; this.href = href;
fmt.Bld_many(tmp_bfr, name, title);
this.html = tmp_bfr.To_bry_and_clear();
}
public byte[] Name() {return name;}
public byte[] Title() {return title;}
public byte[] Href() {return href;}
public byte[] Html() {return html;}
public boolean Mustache__write(String key, Mustache_bfr bfr) {
if (String_.Eq(key, "name")) bfr.Add_bry(name);
else if (String_.Eq(key, "title")) bfr.Add_bry(title);
else if (String_.Eq(key, "url")) bfr.Add_bry(href);
else if (String_.Eq(key, "html")) bfr.Add_bry(html);
else return false;
return true;
}
public Mustache_doc_itm[] Mustache__subs(String key) {return Mustache_doc_itm_.Ary__empty;}
public static final Pgbnr_icon[] Ary_empty = new Pgbnr_icon[0];
public static final Bry_fmt fmt = Bry_fmt.New
( Bry_.New_u8_nl_apos("<span aria-disabled='false' title='~{title}' class='oo-ui-widget oo-ui-widget-enabled oo-ui-iconElement-icon oo-ui-icon-~{name} oo-ui-iconElement oo-ui-iconWidget'></span>")
, "name", "title"
);
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,117 +13,224 @@ 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.pagebanners; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
import gplx.langs.mustaches.*; import gplx.xowa.parsers.lnkis.*;
import gplx.xowa.files.*;
import gplx.langs.htmls.*; import gplx.langs.htmls.docs.*; import gplx.xowa.htmls.core.wkrs.imgs.atrs.*; import gplx.xowa.htmls.core.wkrs.lnkis.htmls.*; import gplx.langs.htmls.encoders.*;
public class Pgbnr_itm implements Mustache_doc_itm {
public Xoa_ttl banner_ttl;
public byte[] banner_img_src;
public byte[] toc;
public Xof_file_itm banner_file_itm;
private byte[] banner_anch_title, banner_hdr_text, originx, banner_anch_href, srcset;
private double data_pos_x, data_pos_y;
private int max_width;
private boolean bottomtoc, isHeadingOverrideEnabled;
private byte[] file_ttl;
private Pgbnr_icon[] icons;
private byte[] img_id_atr, img_xottl_atr, img_xoimg_atr;
private boolean isPanorama;
private boolean enable_toc = true;
private boolean hasPosition = false;
// NOTE: used by hdump
public boolean Exists() {return exists;} private boolean exists;
public byte[] Srcset() {return srcset;}
public byte[] Style_if_not_dflt() {return Bry_.Eq(style, Atr_val__style_dflt) ? Bry_.Empty : style;}
public byte[] Style() {return style;} private byte[] style;
public double Data_pos_x() {return data_pos_x;}
public double Data_pos_y() {return data_pos_y;}
public boolean Show_toc_in_html() {return show_toc_in_html;} private boolean show_toc_in_html = false; // default to false so that TOC does not show up in both PageBanner and HTML body; DATE:2019-11-17
public void Clear_by_hdump() {
this.exists = false;
this.srcset = style = null;
this.data_pos_x = this.data_pos_y = 0;
}
public void Init_by_parse(Gfh_tag tag) {
this.exists = true;
this.srcset = tag.Atrs__get_as_bry(Atr_key__srcset);
this.style = tag.Atrs__get_as_bry(Gfh_atr_.Bry__style);
this.data_pos_x = tag.Atrs__get_as_double_or(Atr_key__data_pos_x, 0);
this.data_pos_y = tag.Atrs__get_as_double_or(Atr_key__data_pos_y, 0);
}
public void Init_by_decode(double data_pos_x, double data_pos_y, byte[] srcset, byte[] style_if_not_dflt) {
this.data_pos_x = data_pos_x;
this.data_pos_y = data_pos_y;
this.srcset = srcset;
this.style = Bry_.Eq(style_if_not_dflt, Bry_.Empty) ? Atr_val__style_dflt : style_if_not_dflt;
this.exists = true;
}
public void Init_from_wtxt(Xoa_ttl banner_ttl, Xof_file_itm banner_file_itm, byte[] banner_anch_title, byte[] banner_hdr_text, boolean bottomtoc
, byte[] toc, double data_pos_x, double data_pos_y, byte[] originx, Pgbnr_icon[] icons) {
this.banner_ttl = banner_ttl; this.banner_file_itm = banner_file_itm;
this.banner_anch_title = banner_anch_title; this.banner_hdr_text = banner_hdr_text; this.bottomtoc = bottomtoc; this.toc = toc; this.icons = icons;
this.data_pos_x = data_pos_x; this.data_pos_y = data_pos_y; this.originx = originx;
this.banner_img_src = banner_file_itm.Html_view_url().To_http_file_bry();
this.file_ttl = Gfo_url_encoder_.Href_quotes.Encode(banner_file_itm.Lnki_ttl()); // NOTE: Encode(Lnki_ttl) not Orig_ttl; else "%27s" instead of "'s" PAGE:en.v:'s-Hertogenbosch; DATE:2016-07-12
}
public void Init_from_html(int max_width, byte[] banner_anch_href, byte[] banner_img_src, byte[] srcset, boolean isHeadingOverrideEnabled, byte[] toc, boolean isPanorama) {
this.max_width = max_width;
this.banner_anch_href = banner_anch_href;
this.banner_img_src = banner_img_src;
this.srcset = srcset;
this.isHeadingOverrideEnabled = isHeadingOverrideEnabled;
this.toc = toc;
this.isPanorama = isPanorama;
}
public void Init_hdump(boolean mode_is_hdump) {
Bry_bfr tmp_bfr = Bry_bfr_.New();
if (mode_is_hdump) {
this.img_id_atr = Bry_.Empty;
this.img_xottl_atr = Gfh_atr_.Add_to_bry(tmp_bfr, Xoh_img_xoimg_data.Bry__data_xowa_title, file_ttl);
this.img_xoimg_atr = Gfh_atr_.Add_to_bry(tmp_bfr, Xoh_img_xoimg_data.Bry__data_xowa_image, Xoh_img_xoimg_data.Bry__data_xowa_image__full);
this.banner_img_src = Bry_.Empty; // do not write img_src else hzip_diff will complain for every image; DATE:2016-10-18
}
else {
this.img_id_atr = tmp_bfr.Add(Bry__anch_atr_id).Add_int_variable(banner_file_itm.Html_uid()).Add_byte_quote().To_bry_and_clear();
this.img_xottl_atr = this.img_xoimg_atr = Bry_.Empty;
}
}
public boolean Mustache__write(String key, Mustache_bfr bfr) {
if (String_.Eq(key, "title")) bfr.Add_bry(banner_hdr_text);
else if (String_.Eq(key, "tooltip")) bfr.Add_bry(banner_anch_title);
else if (String_.Eq(key, "bannerfile")) bfr.Add_bry(banner_anch_href);
else if (String_.Eq(key, "banner")) bfr.Add_bry(banner_img_src);
else if (String_.Eq(key, "srcset")) bfr.Add_bry(srcset == null ? Bry_.Empty : Bry_.Empty);
else if (String_.Eq(key, "originx")) bfr.Add_bry(originx);
else if (String_.Eq(key, "data-pos-x")) bfr.Add_double(data_pos_x);
else if (String_.Eq(key, "data-pos-y")) bfr.Add_double(data_pos_y);
else if (String_.Eq(key, "maxWidth")) bfr.Add_int(max_width);
else if (String_.Eq(key, "toc")) bfr.Add_bry(toc);
else if (String_.Eq(key, "img_id_atr")) bfr.Add_bry(img_id_atr);
else if (String_.Eq(key, "img_xottl")) bfr.Add_bry(img_xottl_atr);
else if (String_.Eq(key, "img_xoimg")) bfr.Add_bry(img_xoimg_atr);
else if (String_.Eq(key, "file_ttl")) bfr.Add_bry(file_ttl);
else return false;
return true;
}
public Mustache_doc_itm[] Mustache__subs(String key) {
if (String_.Eq(key, "icons")) return icons;
else if (String_.Eq(key, "hasIcons")) return Mustache_doc_itm_.Ary__bool(icons.length > 0);
else if (String_.Eq(key, "bottomtoc")) return Mustache_doc_itm_.Ary__bool(bottomtoc);
else if (String_.Eq(key, "isHeadingOverrideEnabled")) return Mustache_doc_itm_.Ary__bool(isHeadingOverrideEnabled);
else if (String_.Eq(key, "isPanorama")) return Mustache_doc_itm_.Ary__bool(isPanorama);
else if (String_.Eq(key, "enable-toc")) return Mustache_doc_itm_.Ary__bool(enable_toc);
else if (String_.Eq(key, "hasPosition")) return Mustache_doc_itm_.Ary__bool(hasPosition);
return Mustache_doc_itm_.Ary__empty;
}
private static final byte[] Bry__anch_atr_id = Bry_.new_a7(" id=\"xoimg_");
public static final byte[]
Atr_key__srcset = Bry_.new_a7("srcset")
, Atr_key__data_pos_x = Bry_.new_a7("data-pos-x")
, Atr_key__data_pos_y = Bry_.new_a7("data-pos-y")
, Atr_val__style_dflt = Bry_.new_a7("max-width:-1px")
;
}
package gplx.xowa.xtns.pagebanners;
import gplx.Bry_;
import gplx.Bry_bfr;
import gplx.Bry_bfr_;
import gplx.Bry_fmt;
import gplx.List_adp;
import gplx.List_adp_;
import gplx.String_;
import gplx.langs.htmls.Gfh_atr_;
import gplx.langs.htmls.docs.Gfh_tag;
import gplx.langs.htmls.encoders.Gfo_url_encoder_;
import gplx.langs.jsons.Json_ary;
import gplx.langs.jsons.Json_nde;
import gplx.langs.mustaches.Mustache_bfr;
import gplx.langs.mustaches.Mustache_doc_itm;
import gplx.langs.mustaches.Mustache_doc_itm_;
import gplx.xowa.Xoa_ttl;
import gplx.xowa.files.Xof_file_itm;
import gplx.xowa.htmls.core.wkrs.imgs.atrs.Xoh_img_xoimg_data;
public class Pgbnr_itm implements Mustache_doc_itm {
public Xoa_ttl banner_ttl;
public byte[] banner_img_src;
public byte[] toc;
public Xof_file_itm banner_file_itm;
private byte[] banner_anch_title, banner_hdr_text, originx, srcset;
private double data_pos_x, data_pos_y;
public /**/ int max_width;
public /**/ byte[] banner_anch_href;
private boolean bottomtoc;
public /**/ boolean isHeadingOverrideEnabled;
private byte[] file_ttl;
private Pgbnr_icon[] icons;
private byte[] img_id_atr, img_xottl_atr, img_xoimg_atr;
public /**/ boolean isPanorama;
private boolean enable_toc = true;
private boolean hasPosition = false;
// NOTE: used by hdump
public boolean Exists() {return exists;} private boolean exists;
public byte[] Srcset() {return srcset;}
public byte[] Style_if_not_dflt() {return Bry_.Eq(style, Atr_val__style_dflt) ? Bry_.Empty : style;}
public byte[] Style() {return style;} private byte[] style;
public double Data_pos_x() {return data_pos_x;}
public double Data_pos_y() {return data_pos_y;}
public boolean Show_toc_in_html() {return show_toc_in_html;} private boolean show_toc_in_html = false; // default to false so that TOC does not show up in both PageBanner and HTML body; DATE:2019-11-17
// hdump serialised info
public boolean Precoded() {return precoded;} private boolean precoded = false;
public byte[] Pgbnr_bry() {return pgbnr_bry;} private byte[] pgbnr_bry;
public void Pgbnr_bry_(byte[] v) {
if (v == null) return;
pgbnr_bry = v;
precoded = true;
}
public void Clear_by_hdump() {
this.exists = false;
this.srcset = style = null;
this.data_pos_x = this.data_pos_y = 0;
}
public void Init_by_parse(Gfh_tag tag) {
this.exists = true;
this.srcset = tag.Atrs__get_as_bry(Atr_key__srcset);
this.style = tag.Atrs__get_as_bry(Gfh_atr_.Bry__style);
this.data_pos_x = tag.Atrs__get_as_double_or(Atr_key__data_pos_x, 0);
this.data_pos_y = tag.Atrs__get_as_double_or(Atr_key__data_pos_y, 0);
}
public void Init_by_decode(double data_pos_x, double data_pos_y, byte[] srcset, byte[] style_if_not_dflt) {
this.data_pos_x = data_pos_x;
this.data_pos_y = data_pos_y;
this.srcset = srcset;
this.style = Bry_.Eq(style_if_not_dflt, Bry_.Empty) ? Atr_val__style_dflt : style_if_not_dflt;
this.exists = true;
}
public void Init_from_wtxt(Xoa_ttl banner_ttl, Xof_file_itm banner_file_itm, byte[] banner_anch_title, byte[] banner_hdr_text, boolean bottomtoc
, byte[] toc, double data_pos_x, double data_pos_y, byte[] originx, Pgbnr_icon[] icons) {
Init_from_wtxt(banner_ttl, banner_file_itm, banner_anch_title, banner_hdr_text, bottomtoc
, toc, data_pos_x, data_pos_y, originx, icons, false);
}
public void Init_from_wtxt(Xoa_ttl banner_ttl, Xof_file_itm banner_file_itm, byte[] banner_anch_title, byte[] banner_hdr_text, boolean bottomtoc
, byte[] toc, double data_pos_x, double data_pos_y, byte[] originx, Pgbnr_icon[] icons, boolean enable_toc) {
this.banner_ttl = banner_ttl; this.banner_file_itm = banner_file_itm;
this.banner_anch_title = banner_anch_title; this.banner_hdr_text = banner_hdr_text; this.bottomtoc = bottomtoc; this.toc = toc; this.icons = icons;
this.data_pos_x = data_pos_x; this.data_pos_y = data_pos_y; this.originx = originx;
this.banner_img_src = banner_file_itm.Html_view_url().To_http_file_bry();
this.file_ttl = Gfo_url_encoder_.Href_quotes.Encode(banner_file_itm.Lnki_ttl()); // NOTE: Encode(Lnki_ttl) not Orig_ttl; else "%27s" instead of "'s" PAGE:en.v:'s-Hertogenbosch; DATE:2016-07-12
this.enable_toc = enable_toc;
show_toc_in_html = !enable_toc;
}
public void Init_from_html(int max_width, byte[] banner_anch_href, byte[] banner_img_src, byte[] srcset, boolean isHeadingOverrideEnabled, byte[] toc, boolean isPanorama) {
this.max_width = max_width;
this.banner_anch_href = banner_anch_href;
this.banner_img_src = banner_img_src;
this.srcset = srcset;
this.isHeadingOverrideEnabled = isHeadingOverrideEnabled;
this.toc = toc;
this.isPanorama = isPanorama;
}
public void Init_hdump(boolean mode_is_hdump) {
Bry_bfr tmp_bfr = Bry_bfr_.New();
if (mode_is_hdump) {
this.img_id_atr = Bry_.Empty;
this.img_xottl_atr = Gfh_atr_.Add_to_bry(tmp_bfr, Xoh_img_xoimg_data.Bry__data_xowa_title, file_ttl);
this.img_xoimg_atr = Gfh_atr_.Add_to_bry(tmp_bfr, Xoh_img_xoimg_data.Bry__data_xowa_image, Xoh_img_xoimg_data.Bry__data_xowa_image__full);
this.banner_img_src = Bry_.Empty; // do not write img_src else hzip_diff will complain for every image; DATE:2016-10-18
}
else {
this.img_id_atr = tmp_bfr.Add(Bry__anch_atr_id).Add_int_variable(banner_file_itm.Html_uid()).Add_byte_quote().To_bry_and_clear();
this.img_xottl_atr = this.img_xoimg_atr = Bry_.Empty;
}
}
public boolean Mustache__write(String key, Mustache_bfr bfr) {
if (String_.Eq(key, "title")) bfr.Add_bry(banner_hdr_text);
else if (String_.Eq(key, "tooltip")) bfr.Add_bry(banner_anch_title);
else if (String_.Eq(key, "bannerfile")) bfr.Add_bry(banner_anch_href);
else if (String_.Eq(key, "banner")) bfr.Add_bry(banner_img_src);
else if (String_.Eq(key, "srcset")) bfr.Add_bry(srcset == null ? Bry_.Empty : Bry_.Empty);
else if (String_.Eq(key, "originx")) bfr.Add_bry(originx);
else if (String_.Eq(key, "data-pos-x")) bfr.Add_double(data_pos_x);
else if (String_.Eq(key, "data-pos-y")) bfr.Add_double(data_pos_y);
else if (String_.Eq(key, "maxWidth")) bfr.Add_int(max_width);
else if (String_.Eq(key, "toc")) bfr.Add_bry(toc);
else if (String_.Eq(key, "img_id_atr")) bfr.Add_bry(img_id_atr);
else if (String_.Eq(key, "img_xottl")) bfr.Add_bry(img_xottl_atr);
else if (String_.Eq(key, "img_xoimg")) bfr.Add_bry(img_xoimg_atr);
else if (String_.Eq(key, "file_ttl")) bfr.Add_bry(file_ttl);
else return false;
return true;
}
public Mustache_doc_itm[] Mustache__subs(String key) {
if (String_.Eq(key, "icons")) return icons;
else if (String_.Eq(key, "hasIcons")) return Mustache_doc_itm_.Ary__bool(icons.length > 0);
else if (String_.Eq(key, "bottomtoc")) return Mustache_doc_itm_.Ary__bool(bottomtoc);
else if (String_.Eq(key, "isHeadingOverrideEnabled")) return Mustache_doc_itm_.Ary__bool(isHeadingOverrideEnabled);
else if (String_.Eq(key, "isPanorama")) return Mustache_doc_itm_.Ary__bool(isPanorama);
else if (String_.Eq(key, "enable-toc")) return Mustache_doc_itm_.Ary__bool(enable_toc);
else if (String_.Eq(key, "hasPosition")) return Mustache_doc_itm_.Ary__bool(hasPosition);
return Mustache_doc_itm_.Ary__empty;
}
private static final byte[] Bry__anch_atr_id = Bry_.new_a7(" id=\"xoimg_");
public static final byte[]
Atr_key__srcset = Bry_.new_a7("srcset")
, Atr_key__data_pos_x = Bry_.new_a7("data-pos-x")
, Atr_key__data_pos_y = Bry_.new_a7("data-pos-y")
, Atr_val__style_dflt = Bry_.new_a7("max-width:-1px")
;
public Json_nde Mustache__json() {
return buildargs();
}
private Json_nde buildargs() {
Json_nde jnde = Json_nde.NewByVal();
jnde.AddKvStr("title", banner_hdr_text);
jnde.AddKvStr("tooltip", banner_anch_title);
jnde.AddKvStr("bannerfile", banner_anch_href);
jnde.AddKvStr("banner", banner_img_src);
jnde.AddKvStr("srcset", srcset == null ? Bry_.Empty : Bry_.Empty);
jnde.AddKvStr("originx", originx);
jnde.AddKvStr("toc", toc);
jnde.AddKvStr("img_id_atr", img_id_atr);
jnde.AddKvStr("img_xottl", img_xottl_atr);
jnde.AddKvStr("img_xoimg", img_xoimg_atr);
jnde.AddKvStr("file_ttl", file_ttl);
jnde.AddKvDouble("data-pos-x", data_pos_x);
jnde.AddKvDouble("data-pos-y", data_pos_y);
jnde.AddKvInt("maxWidth", max_width);
jnde.AddKvBool("hasIcons", icons.length > 0);
jnde.AddKvBool("bottomtoc", bottomtoc);
jnde.AddKvBool("isHeadingOverrideEnabled", isHeadingOverrideEnabled);
jnde.AddKvBool("isPanorama", isPanorama);
jnde.AddKvBool("enable-toc", enable_toc);
jnde.AddKvBool("hasPosition", hasPosition);
Json_ary ary = null;
if (json_icon_list != null) {
ary = Json_ary.NewByVal();
int iconlen = json_icon_list.Len();
for (int i = 0; i < iconlen; i++) {
Json_nde inde = (Json_nde)json_icon_list.Get_at(i);
ary.Add(inde);
}
if (iconlen > 0) {
jnde.AddKvAry("icons", ary);
}
}
int iconLen = icons.length;
if (iconLen > 0) {
ary = Json_ary.NewByVal();
Bry_bfr tmpBfr = Bry_bfr_.New();
for (int i = 0; i < iconLen; i++) {
Pgbnr_icon icon = icons[i];
Json_nde iconNde = Pgbnr_iconx(tmpBfr, icon.Name(), icon.Title(), icon.Href());
ary.Add(iconNde);
}
jnde.AddKvAry("icons", ary);
}
return jnde;
}
private List_adp json_icon_list;
public void Add_new_icon(Bry_bfr tmp_bfr, byte[] name, byte[] title, byte[] href) {
if (json_icon_list == null) json_icon_list = List_adp_.New();
json_icon_list.Add(Pgbnr_iconx(tmp_bfr, name, title, href));
}
private Json_nde Pgbnr_iconx(Bry_bfr tmp_bfr, byte[] name, byte[] title, byte[] href) {
fmt.Bld_many(tmp_bfr, name, title);
byte[] html = tmp_bfr.To_bry_and_clear();
Json_nde jnde = Json_nde.NewByVal();
jnde.AddKvStr("name", name);
jnde.AddKvStr("title", title);
jnde.AddKvStr("url", href);
jnde.AddKvStr("html", html);
return jnde;
}
public static final Bry_fmt fmt = Bry_fmt.New
( Bry_.New_u8_nl_apos("<span aria-disabled=\"false\" title=\"~{title}\" class=\"oo-ui-widget oo-ui-widget-enabled oo-ui-iconElement-icon oo-ui-icon-~{name} oo-ui-iconElement oo-ui-iconWidget\"></span>")
, "name", "title"
);
}

@ -18,7 +18,6 @@ package gplx.xowa.xtns.pagebanners;
import gplx.Bry_;
import gplx.Bry_bfr;
import gplx.Int_ary_;
import gplx.Io_mgr;
import gplx.core.brys.Bfr_arg;
import gplx.langs.mustaches.Mustache_tkn_itm;
import gplx.langs.mustaches.Mustache_tkn_parser;
@ -86,9 +85,11 @@ public class Pgbnr_xtn_mgr extends Xox_mgr_base implements Bfr_arg {
if (!enabled) return;
// load template file;
byte[] template_data = Io_mgr.Instance.LoadFilBryOr(wiki.Appe().Fsys_mgr().Bin_any_dir().GenSubDir_nest("xowa", "xtns", "WikidataPageBanner", "templates", "banner.mustache"), Template_dflt);
Mustache_tkn_parser parser = new Mustache_tkn_parser();
template_root = parser.Parse(template_data, 0, template_data.length);
//byte[] template_data = Io_mgr.Instance.LoadFilBryOr(wiki.Appe().Fsys_mgr().Bin_any_dir().GenSubDir_nest("xowa", "xtns", "WikidataPageBanner", "templates", "banner.mustache"), Template_dflt);
//Mustache_tkn_parser parser = new Mustache_tkn_parser();
//template_root = parser.Parse(template_data, 0, template_data.length);
Mustache_tkn_parser parser = new Mustache_tkn_parser(wiki.Appe().Fsys_mgr().Bin_any_dir().GenSubDir_nest("xowa", "xtns", "WikidataPageBanner", "templates"));
template_root = parser.Parse("banner", Template_dflt);
}
public Bfr_arg Write_html(Xoae_page wpg, Xop_ctx pctx, Xoh_wtr_ctx hctx) {
this.wpg = wpg; this.pctx = pctx; this.hctx = hctx;

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,225 +13,248 @@ 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.langs.jsons.*;
public class Scrib_lib_text__json_util {
private final Json_wtr wtr = new Json_wtr();
public void Reindex_arrays(Scrib_lib_text__reindex_data rv, Keyval[] kv_ary, boolean is_encoding) {
int next = 0;
if (is_encoding) {
Array_.Sort(kv_ary, KeyVal__sorter__key_is_numeric.Instance);
next = 1;
}
boolean is_sequence = true;
int len = kv_ary.length;
for (int i = 0; i < len; ++i) {
Keyval kv = kv_ary[i];
Object kv_val = kv.Val();
if (kv_val != null && Type_.Eq(kv_val.getClass(), Keyval[].class)) {
Reindex_arrays(rv, (Keyval[])kv_val, is_encoding);
if (!rv.Rv_is_kvy())
kv.Val_(rv.Rv_as_ary());
}
if (is_sequence) {
if (kv.Key_tid() == Type_ids_.Id__int) {
int kv_key_as_int = Int_.Cast(kv.Key_as_obj());
is_sequence = next++ == kv_key_as_int;
}
else {
int kv_key_to_int = Bry_.To_int_or__strict(Bry_.new_a7(kv.Key()), -1); // NOTE: a7 b/c proc is only checking for digits; none a7 bytes will be replaced by ?
if (is_encoding && kv_key_to_int != -1) {
is_sequence = next == kv_key_to_int;
++next;
}
else
is_sequence = false;
}
}
}
if (is_sequence) {
if (is_encoding) {
Object rv_as_ary = To_array_values(kv_ary);
rv.Init(Bool_.N, null, rv_as_ary);
return;
} else {
Convert_to_base1(kv_ary); // PHP: return $arr ? array_combine( range( 1, count( $arr ) ), $arr ) : $arr;
}
}
rv.Init(Bool_.Y, kv_ary, null);
}
private static Object[] To_array_values(Keyval[] ary) {
int len = ary.length;
Object[] rv = new Object[len];
for (int i = 0; i < len; ++i) {
Keyval itm = ary[i];
rv[i] = itm.Val();
}
return rv;
}
private static void Convert_to_base1(Keyval[] ary) {
int len = ary.length;
for (int i = 0; i < len; ++i) {
Keyval itm = ary[i];
itm.Key_(i + 1);
}
}
public Keyval[] Decode_rslt_as_nde() {return decode_rslt_as_nde;} private Keyval[] decode_rslt_as_nde;
public Keyval[] Decode_rslt_as_ary() {return decode_rslt_as_ary;} private Keyval[] decode_rslt_as_ary;
public byte Decode(Json_parser parser, byte[] src, int flag) {
synchronized (wtr) {
Json_doc jdoc = parser.Parse(src);
if (jdoc.Root_grp().Tid() == Json_itm_.Tid__ary) {
this.decode_rslt_as_ary = Decode_ary_top(jdoc.Root_ary());
return Bool_.N_byte;
}
else {
Json_nde root = (Json_nde)jdoc.Root_grp();
int len = root.Len();
this.decode_rslt_as_nde = new Keyval[len];
for (int i = 0; i < len; ++i) {
Json_kv json_kv = root.Get_at_as_kv(i);
String kv_str = json_kv.Key_as_str();
Object kv_val = Decode_obj(json_kv.Val());
int kv_int = Int_.Parse_or(kv_str, Int_.Min_value);
decode_rslt_as_nde[i] = kv_int == Int_.Min_value ? Keyval_.new_(kv_str, kv_val) : Keyval_.int_(kv_int, kv_val); // use int_key if applicable; PAGE:it.s:Il_Re_Cervo; DATE:2015-12-06
}
return Bool_.Y_byte;
}
}
}
private Object Decode_obj(Json_itm itm) {
int itm_tid = itm.Tid();
switch (itm_tid) {
case Json_itm_.Tid__ary: return Decode_ary_sub(Json_ary.cast(itm));
case Json_itm_.Tid__nde: return Decode_nde(Json_nde.cast(itm));
default: return itm.Data();
}
}
private Keyval[] Decode_ary_top(Json_ary ary) { // NOTE: top-level arrays must be returned as numbered nodes; EX: [{1:a}, {2:b}, {3:c}] not [a, b, c]; DATE:2016-08-01
int len = ary.Len();
Keyval[] rv = new Keyval[len];
for (int i = 0; i < len; ++i) {
Json_itm itm = ary.Get_at(i);
rv[i] = Keyval_.int_(i + List_adp_.Base1, Decode_obj(itm));
}
return rv;
}
private Object Decode_ary_sub(Json_ary ary) {
boolean subs_are_primitive = true;
// if ary has sub_ary / sub_nde, then unflag subs_are_primitive
int len = ary.Len();
if (len > 0) {
Json_itm sub = ary.Get_at(0);
switch (sub.Tid()) {
case Json_itm_.Tid__nde:
case Json_itm_.Tid__ary:
subs_are_primitive = false;
break;
}
}
// generate array
Object[] rv = null;
// if subs_are_primitive, then just generate an Object[]
if (subs_are_primitive) {
rv = new Object[len];
for (int i = 0; i < len; ++i) {
Json_itm itm = ary.Get_at(i);
rv[i] = Decode_obj(itm);
}
}
// else generate a Keyval where val is ary / nde
else {
rv = new Keyval[len];
for (int i = 0; i < len; ++i) {
Json_itm itm = ary.Get_at(i);
rv[i] = Keyval_.int_(i, Decode_obj(itm));
}
}
return rv;
}
private Keyval[] Decode_nde(Json_nde nde) {
int len = nde.Len();
Keyval[] rv = new Keyval[len];
for (int i = 0; i < len; ++i) {
Json_kv itm = nde.Get_at_as_kv(i);
String kv_str = itm.Key_as_str();
int kv_int = Int_.Parse_or(kv_str, Int_.Min_value);
Object kv_val = Decode_obj(itm.Val());
rv[i] = kv_int == Int_.Min_value ? Keyval_.new_(kv_str, kv_val) : Keyval_.int_(kv_int, kv_val); // use int_key if applicable; PAGE:it.s:Il_Re_Cervo; DATE:2015-12-06
}
return rv;
}
public byte[] Encode_as_nde(Keyval[] itm, int flag, int skip) {
synchronized (wtr ) {
wtr.Clear().Doc_nde_bgn();
Encode_kv_ary(itm);
return wtr.Doc_nde_end().To_bry_and_clear();
}
}
public byte[] Encode_as_ary(Object ary, int flag, int skip) {
synchronized (wtr ) {
wtr.Clear().Doc_ary_bgn();
Encode_ary(ary);
return wtr.Doc_ary_end().To_bry_and_clear();
}
}
private void Encode_kv_ary(Keyval[] kv_ary) {
int len = kv_ary.length;
for (int i = 0; i < len; ++i) {
Keyval kv = kv_ary[i];
Encode_kv(kv);
}
}
private void Encode_kv(Keyval kv) {
Object kv_val = kv.Val();
Class<?> type = Type_.Type_by_obj(kv_val);
if (Type_.Eq(type, Keyval[].class)) {
wtr.Nde_bgn(kv.Key());
Encode_kv_ary((Keyval[])kv_val);
wtr.Nde_end();
}
else if (Type_.Is_array(type)) { // encode as array
wtr.Ary_bgn(kv.Key());
Encode_ary(kv_val);
wtr.Ary_end();
}
else if (Type_.Eq(type, Int_.Cls_ref_type)) wtr.Kv_int(kv.Key(), Int_.Cast(kv_val));
else if (Type_.Eq(type, Long_.Cls_ref_type)) wtr.Kv_long(kv.Key(), Long_.cast(kv_val));
else if (Type_.Eq(type, Float_.Cls_ref_type)) wtr.Kv_float(kv.Key(), Float_.cast(kv_val));
else if (Type_.Eq(type, Double_.Cls_ref_type)) wtr.Kv_double(kv.Key(), Double_.cast(kv_val));
else if (Type_.Eq(type, Bool_.Cls_ref_type)) wtr.Kv_bool(kv.Key(), Bool_.Cast(kv_val));
else wtr.Kv_str(kv.Key(), Object_.Xto_str_strict_or_null(kv_val));
}
private void Encode_ary(Object ary) {
int ary_len = Array_.Len(ary);
for (int j = 0; j < ary_len; ++j)
wtr.Ary_itm_obj(Array_.Get_at(ary, j));
}
public static final int
Flag__none = 0
, Flag__preserve_keys = 1
, Flag__try_fixing = 2
, Flag__pretty = 4
;
public static final int
Skip__utf8 = 1
, Skip__xml = 2
, Skip__all = 3
;
public static final int
Opt__force_assoc = 1
;
}
class KeyVal__sorter__key_is_numeric implements gplx.core.lists.ComparerAble {
public int compare(Object lhsObj, Object rhsObj) {
Keyval lhs_itm = (Keyval)lhsObj;
Keyval rhs_itm = (Keyval)rhsObj;
int lhs_int = Int_.Parse_or(lhs_itm.Key(), Int_.Min_value);
int rhs_int = Int_.Parse_or(rhs_itm.Key(), Int_.Min_value);
return CompareAble_.Compare(lhs_int, rhs_int);
}
public static final KeyVal__sorter__key_is_numeric Instance = new KeyVal__sorter__key_is_numeric(); KeyVal__sorter__key_is_numeric() {}
}
package gplx.xowa.xtns.scribunto.libs;
import gplx.Array_;
import gplx.Bool_;
import gplx.Bry_;
import gplx.CompareAble_;
import gplx.Double_;
import gplx.Float_;
import gplx.Int_;
import gplx.Keyval;
import gplx.Keyval_;
import gplx.List_adp_;
import gplx.Long_;
import gplx.Object_;
import gplx.Type_;
import gplx.Type_ids_;
import gplx.langs.jsons.Json_ary;
import gplx.langs.jsons.Json_doc;
import gplx.langs.jsons.Json_itm;
import gplx.langs.jsons.Json_itm_;
import gplx.langs.jsons.Json_kv;
import gplx.langs.jsons.Json_nde;
import gplx.langs.jsons.Json_parser;
import gplx.langs.jsons.Json_wtr;
public class Scrib_lib_text__json_util {
private final Json_wtr wtr = new Json_wtr();
public void Reindex_arrays(Scrib_lib_text__reindex_data rv, Keyval[] kv_ary, boolean is_encoding) {
int next = 0;
if (is_encoding) {
Array_.Sort(kv_ary, KeyVal__sorter__key_is_numeric.Instance);
next = 1;
}
boolean is_sequence = true;
int len = kv_ary.length;
for (int i = 0; i < len; ++i) {
Keyval kv = kv_ary[i];
Object kv_val = kv.Val();
if (kv_val != null && Type_.Eq(kv_val.getClass(), Keyval[].class)) {
Reindex_arrays(rv, (Keyval[])kv_val, is_encoding);
if (!rv.Rv_is_kvy())
kv.Val_(rv.Rv_as_ary());
}
if (is_sequence) {
if (kv.Key_tid() == Type_ids_.Id__int) {
int kv_key_as_int = Int_.Cast(kv.Key_as_obj());
is_sequence = next++ == kv_key_as_int;
}
else {
int kv_key_to_int = Bry_.To_int_or__strict(Bry_.new_a7(kv.Key()), -1); // NOTE: a7 b/c proc is only checking for digits; none a7 bytes will be replaced by ?
if (is_encoding && kv_key_to_int != -1) {
is_sequence = next == kv_key_to_int;
++next;
}
else
is_sequence = false;
}
}
}
if (is_sequence) {
if (is_encoding) {
Object rv_as_ary = To_array_values(kv_ary);
rv.Init(Bool_.N, null, rv_as_ary);
return;
} else {
Convert_to_base1(kv_ary); // PHP: return $arr ? array_combine( range( 1, count( $arr ) ), $arr ) : $arr;
}
}
rv.Init(Bool_.Y, kv_ary, null);
}
private static Object[] To_array_values(Keyval[] ary) {
int len = ary.length;
Object[] rv = new Object[len];
for (int i = 0; i < len; ++i) {
Keyval itm = ary[i];
rv[i] = itm.Val();
}
return rv;
}
private static void Convert_to_base1(Keyval[] ary) {
int len = ary.length;
for (int i = 0; i < len; ++i) {
Keyval itm = ary[i];
itm.Key_(i + 1);
}
}
public Keyval[] Decode_rslt_as_nde() {return decode_rslt_as_nde;} private Keyval[] decode_rslt_as_nde;
public Keyval[] Decode_rslt_as_ary() {return decode_rslt_as_ary;} private Keyval[] decode_rslt_as_ary;
public byte Decode(Json_parser parser, byte[] src, int flag) {
synchronized (wtr) {
Json_doc jdoc = parser.Parse(src);
if (jdoc.Root_grp().Tid() == Json_itm_.Tid__ary) {
this.decode_rslt_as_ary = Decode_ary_top(jdoc.Root_ary());
return Bool_.N_byte;
}
else {
Json_nde root = (Json_nde)jdoc.Root_grp();
int len = root.Len();
this.decode_rslt_as_nde = new Keyval[len];
for (int i = 0; i < len; ++i) {
Json_kv json_kv = root.Get_at_as_kv(i);
String kv_str = json_kv.Key_as_str();
Object kv_val = Decode_obj(json_kv.Val());
int kv_int = Int_.Parse_or(kv_str, Int_.Min_value);
decode_rslt_as_nde[i] = kv_int == Int_.Min_value ? Keyval_.new_(kv_str, kv_val) : Keyval_.int_(kv_int, kv_val); // use int_key if applicable; PAGE:it.s:Il_Re_Cervo; DATE:2015-12-06
}
return Bool_.Y_byte;
}
}
}
private Object Decode_obj(Json_itm itm) {
int itm_tid = itm.Tid();
switch (itm_tid) {
case Json_itm_.Tid__ary: return Decode_ary_sub(Json_ary.cast(itm));
case Json_itm_.Tid__nde: return Decode_nde(Json_nde.Cast(itm));
default: return itm.Data();
}
}
private Keyval[] Decode_ary_top(Json_ary ary) { // NOTE: top-level arrays must be returned as numbered nodes; EX: [{1:a}, {2:b}, {3:c}] not [a, b, c]; DATE:2016-08-01
int len = ary.Len();
Keyval[] rv = new Keyval[len];
for (int i = 0; i < len; ++i) {
Json_itm itm = ary.Get_at(i);
rv[i] = Keyval_.int_(i + List_adp_.Base1, Decode_obj(itm));
}
return rv;
}
private Object Decode_ary_sub(Json_ary ary) {
boolean subs_are_primitive = true;
// if ary has sub_ary / sub_nde, then unflag subs_are_primitive
int len = ary.Len();
if (len > 0) {
Json_itm sub = ary.Get_at(0);
switch (sub.Tid()) {
case Json_itm_.Tid__nde:
case Json_itm_.Tid__ary:
subs_are_primitive = false;
break;
}
}
// generate array
Object[] rv = null;
// if subs_are_primitive, then just generate an Object[]
if (subs_are_primitive) {
rv = new Object[len];
for (int i = 0; i < len; ++i) {
Json_itm itm = ary.Get_at(i);
rv[i] = Decode_obj(itm);
}
}
// else generate a Keyval where val is ary / nde
else {
rv = new Keyval[len];
for (int i = 0; i < len; ++i) {
Json_itm itm = ary.Get_at(i);
rv[i] = Keyval_.int_(i, Decode_obj(itm));
}
}
return rv;
}
private Keyval[] Decode_nde(Json_nde nde) {
int len = nde.Len();
Keyval[] rv = new Keyval[len];
for (int i = 0; i < len; ++i) {
Json_kv itm = nde.Get_at_as_kv(i);
String kv_str = itm.Key_as_str();
int kv_int = Int_.Parse_or(kv_str, Int_.Min_value);
Object kv_val = Decode_obj(itm.Val());
rv[i] = kv_int == Int_.Min_value ? Keyval_.new_(kv_str, kv_val) : Keyval_.int_(kv_int, kv_val); // use int_key if applicable; PAGE:it.s:Il_Re_Cervo; DATE:2015-12-06
}
return rv;
}
public byte[] Encode_as_nde(Keyval[] itm, int flag, int skip) {
synchronized (wtr ) {
wtr.Clear().Doc_nde_bgn();
Encode_kv_ary(itm);
return wtr.Doc_nde_end().To_bry_and_clear();
}
}
public byte[] Encode_as_ary(Object ary, int flag, int skip) {
synchronized (wtr ) {
wtr.Clear().Doc_ary_bgn();
Encode_ary(ary);
return wtr.Doc_ary_end().To_bry_and_clear();
}
}
private void Encode_kv_ary(Keyval[] kv_ary) {
int len = kv_ary.length;
for (int i = 0; i < len; ++i) {
Keyval kv = kv_ary[i];
Encode_kv(kv);
}
}
private void Encode_kv(Keyval kv) {
Object kv_val = kv.Val();
Class<?> type = Type_.Type_by_obj(kv_val);
if (Type_.Eq(type, Keyval[].class)) {
wtr.Nde_bgn(kv.Key());
Encode_kv_ary((Keyval[])kv_val);
wtr.Nde_end();
}
else if (Type_.Is_array(type)) { // encode as array
wtr.Ary_bgn(kv.Key());
Encode_ary(kv_val);
wtr.Ary_end();
}
else if (Type_.Eq(type, Int_.Cls_ref_type)) wtr.Kv_int(kv.Key(), Int_.Cast(kv_val));
else if (Type_.Eq(type, Long_.Cls_ref_type)) wtr.Kv_long(kv.Key(), Long_.cast(kv_val));
else if (Type_.Eq(type, Float_.Cls_ref_type)) wtr.Kv_float(kv.Key(), Float_.cast(kv_val));
else if (Type_.Eq(type, Double_.Cls_ref_type)) wtr.Kv_double(kv.Key(), Double_.cast(kv_val));
else if (Type_.Eq(type, Bool_.Cls_ref_type)) wtr.Kv_bool(kv.Key(), Bool_.Cast(kv_val));
else wtr.Kv_str(kv.Key(), Object_.Xto_str_strict_or_null(kv_val));
}
private void Encode_ary(Object ary) {
int ary_len = Array_.Len(ary);
for (int j = 0; j < ary_len; ++j)
wtr.Ary_itm_obj(Array_.Get_at(ary, j));
}
public static final int
Flag__none = 0
, Flag__preserve_keys = 1
, Flag__try_fixing = 2
, Flag__pretty = 4
;
public static final int
Skip__utf8 = 1
, Skip__xml = 2
, Skip__all = 3
;
public static final int
Opt__force_assoc = 1
;
}
class KeyVal__sorter__key_is_numeric implements gplx.core.lists.ComparerAble {
public int compare(Object lhsObj, Object rhsObj) {
Keyval lhs_itm = (Keyval)lhsObj;
Keyval rhs_itm = (Keyval)rhsObj;
int lhs_int = Int_.Parse_or(lhs_itm.Key(), Int_.Min_value);
int rhs_int = Int_.Parse_or(rhs_itm.Key(), Int_.Min_value);
return CompareAble_.Compare((Integer)lhs_int, (Integer)rhs_int);
}
public static final KeyVal__sorter__key_is_numeric Instance = new KeyVal__sorter__key_is_numeric(); KeyVal__sorter__key_is_numeric() {}
}

@ -63,11 +63,11 @@ import gplx.xowa.xtns.wbases.stores.Wbase_prop_mgr_loader_;
import gplx.xowa.xtns.wbases.stores.Wbase_qid_mgr;
public class Wdata_wiki_mgr implements Gfo_evt_itm, Gfo_invk {
private final Xoae_app app;
private final Wdata_prop_val_visitor prop_val_visitor;
private final Wdata_doc_parser wdoc_parser_v1 = new Wdata_doc_parser_v1(), wdoc_parser_v2 = new Wdata_doc_parser_v2();
private final Object thread_lock = new Object();
private final Bry_bfr tmp_bfr = Bry_bfr_.New_w_size(32);
private final Xoae_app app;
private final Wdata_prop_val_visitor prop_val_visitor;
private final Wdata_doc_parser wdoc_parser_v1 = new Wdata_doc_parser_v1(), wdoc_parser_v2 = new Wdata_doc_parser_v2();
private final Object thread_lock = new Object();
private final Bry_bfr tmp_bfr = Bry_bfr_.New_w_size(32);
public Wdata_wiki_mgr(Xoae_app app) {
this.app = app;
this.evt_mgr = new Gfo_evt_mgr(this);
@ -78,11 +78,11 @@ public class Wdata_wiki_mgr implements Gfo_evt_itm, Gfo_invk {
this.prop_val_visitor = new Wdata_prop_val_visitor(app, this);
this.Enabled_(true);
}
public Gfo_evt_mgr Evt_mgr() {return evt_mgr;} private final Gfo_evt_mgr evt_mgr;
public final Wbase_qid_mgr Qid_mgr;
public final Wbase_pid_mgr Pid_mgr;
public final Wbase_doc_mgr Doc_mgr;
public Wbase_prop_mgr Prop_mgr() {return prop_mgr;} private final Wbase_prop_mgr prop_mgr;
public Gfo_evt_mgr Evt_mgr() {return evt_mgr;} private final Gfo_evt_mgr evt_mgr;
public final Wbase_qid_mgr Qid_mgr;
public final Wbase_pid_mgr Pid_mgr;
public final Wbase_doc_mgr Doc_mgr;
public Wbase_prop_mgr Prop_mgr() {return prop_mgr;} private final Wbase_prop_mgr prop_mgr;
public boolean Enabled() {return enabled;} private boolean enabled;
public void Enabled_(boolean v) {
this.enabled = v;
@ -109,7 +109,7 @@ public class Wdata_wiki_mgr implements Gfo_evt_itm, Gfo_invk {
public Json_parser Jdoc_parser() {return jdoc_parser;} private Json_parser jdoc_parser = new Json_parser();
public void Init_by_app() {}
public Wdata_doc_parser Wdoc_parser(Json_doc jdoc) {
Json_kv itm_0 = Json_kv.cast(jdoc.Root_nde().Get_at(0)); // get 1st node
Json_kv itm_0 = Json_kv.Cast(jdoc.Root_nde().Get_at(0)); // get 1st node
return Bry_.Eq(itm_0.Key().Data_bry(), Wdata_doc_parser_v2.Bry_type)
|| Bry_.Eq(itm_0.Key().Data_bry(), Wdata_doc_parser_v2.Bry_id)
? wdoc_parser_v2 : wdoc_parser_v1; // if "type", must be v2
@ -224,7 +224,7 @@ public class Wdata_wiki_mgr implements Gfo_evt_itm, Gfo_invk {
public static final String Ns_lexeme_name = "Lexeme";
public static final byte[] Ns_lexeme_name_bry = Bry_.new_a7(Ns_lexeme_name);
public static final byte[] Html_json_id = Bry_.new_a7("xowa-wikidata-json");
public static final byte[] Html_json_id = Bry_.new_a7("xowa-wikidata-json");
public static boolean Wiki_page_is_json(int wiki_tid, int ns_id) {
switch (wiki_tid) {
case Xow_domain_tid_.Tid__wikidata:

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,193 +13,234 @@ 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.wbases; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
import gplx.core.primitives.*; import gplx.langs.jsons.*;
import gplx.xowa.wikis.nss.*; import gplx.xowa.wikis.domains.*;
import gplx.xowa.xtns.wbases.core.*; import gplx.xowa.xtns.wbases.pfuncs.*; import gplx.xowa.xtns.wbases.claims.*; import gplx.xowa.xtns.wbases.claims.enums.*; import gplx.xowa.xtns.wbases.claims.itms.*; import gplx.xowa.xtns.wbases.stores.*;
public class Wdata_wiki_mgr_fxt {
private Xoae_app app; private Xowe_wiki wiki; private Wdata_doc_bldr wdoc_bldr;
private final Wdata_xwiki_link_wtr wdata_lang_wtr = new Wdata_xwiki_link_wtr();
private final Bry_bfr tmp_time_bfr = Bry_bfr_.New();
public Xowe_wiki Wiki() {return parser_fxt.Wiki();}
public Wdata_wiki_mgr_fxt Init() {return Init(new Xop_fxt(), true);}
public Wdata_wiki_mgr_fxt Init(Xop_fxt parser_fxt, boolean reset) {
this.parser_fxt = parser_fxt;
this.wiki = parser_fxt.Wiki();
app = wiki.Appe();
app.Xwiki_mgr__sitelink_mgr().Init_by_app();
wdoc_bldr = new Wdata_doc_bldr();
wdata_mgr = app.Wiki_mgr().Wdata_mgr();
wdata_mgr.Prop_mgr().Loader_(Wbase_prop_mgr_loader_.New_mock());
wdata_mgr.Clear();
if (reset) {
Io_mgr.Instance.InitEngine_mem();
parser_fxt.Reset();
}
return this;
}
public Xoae_app App() {return app;}
public Wdata_wiki_mgr Wdata_mgr() {return wdata_mgr;} private Wdata_wiki_mgr wdata_mgr;
public Xop_fxt Parser_fxt() {return parser_fxt;} private Xop_fxt parser_fxt;
public Wdata_doc_bldr Wdoc_bldr(String qid) {return wdoc_bldr.Qid_(qid);}
public Json_doc Make_json(String src) {return app.Utl__json_parser().Parse_by_apos(src);}
public Wbase_claim_base Make_claim_novalue(int pid) {return Wbase_claim_value.New_novalue(pid);}
public Wbase_claim_base Make_claim_somevalue(int pid) {return Wbase_claim_value.New_somevalue(pid);}
public Wbase_claim_base Make_claim_string(int pid, String val) {return Make_claim_string(pid, Bry_.new_u8(val));}
public Wbase_claim_base Make_claim_string(int pid, byte[] val) {return new Wbase_claim_string(pid, Wbase_claim_value_type_.Tid__value, val);}
public Wbase_claim_base Make_claim_time(int pid, String val) {return Make_claim_time(pid, val, Bry_.Empty, Bry_.Empty);}
public Wbase_claim_base Make_claim_time(int pid, String val, int precision) {return Make_claim_time(pid, val, Int_.To_bry(precision), Bry_.Empty);}
public Wbase_claim_base Make_claim_time(int pid, String val, byte[] precision, byte[] calendar) {
return new Wbase_claim_time(pid, Wbase_claim_value_type_.Tid__value, Wbase_claim_time_.To_bry(tmp_time_bfr, val), Bry_.Empty, Bry_.Empty, Bry_.Empty, precision, calendar);
}
public Wbase_claim_base Make_claim_monolingual(int pid, String lang, String text) {return new Wbase_claim_monolingualtext(pid, Wbase_claim_value_type_.Tid__value, Bry_.new_u8(lang), Bry_.new_u8(text));}
public Wbase_claim_base Make_claim_quantity(int pid, String amount, String unit, String ubound, String lbound) {return new Wbase_claim_quantity(pid, Wbase_claim_value_type_.Tid__value, Bry_.new_a7(amount), Bry_.new_a7(unit), Bry_.new_a7(ubound), Bry_.new_a7(lbound));}
public Wbase_claim_base Make_claim_entity_qid(int pid, int val) {return new Wbase_claim_entity(pid, Wbase_claim_value_type_.Tid__value, Wbase_claim_entity_type_.Tid__item, Int_.To_bry(val));}
public Wbase_claim_base Make_claim_entity_pid(int pid, int val) {return new Wbase_claim_entity(pid, Wbase_claim_value_type_.Tid__value, Wbase_claim_entity_type_.Tid__property, Int_.To_bry(val));}
public Wbase_claim_base Make_claim_geo(int pid, String lon, String lat) {return Make_claim_geo(pid, lon, lat, ".00001", null, "http://www.wikidata.org/entity/Q2");}
public Wbase_claim_base Make_claim_geo(int pid, String lon, String lat, String prc, String alt, String glb) {
return new Wbase_claim_globecoordinate(pid, Wbase_claim_value_type_.Tid__value, Bry_.new_a7(lat), Bry_.new_a7(lon), Bry_.new_a7(alt), Bry_.new_a7(prc), Bry_.new_a7(glb));
}
public Wbase_claim_grp Make_qualifiers_grp(int pid, Wbase_claim_base... ary) {return new Wbase_claim_grp(Int_obj_ref.New(pid), ary);}
public Wbase_claim_grp_list Make_qualifiers(Wbase_claim_grp... ary) {
Wbase_claim_grp_list rv = new Wbase_claim_grp_list();
int len = ary.length;
for (int i = 0; i < len; ++i)
rv.Add(ary[i]);
return rv;
}
public Wbase_references_grp[] Make_references(Wbase_references_grp... ary) {
return ary;
}
public Wbase_references_grp Make_reference_grp(String hash, int[] snaks_order, Wbase_claim_grp... snaks) {
Wbase_claim_grp_list list = new Wbase_claim_grp_list();
for (Wbase_claim_grp itm : snaks)
list.Add(itm);
return new Wbase_references_grp(Bry_.new_u8(hash), list, snaks_order);
}
public Wbase_claim_grp Make_reference_itm(int id, Wbase_claim_base... itms) {
return new Wbase_claim_grp(Int_obj_ref.New(id), itms);
}
public Wdata_doc_bldr Wdoc(String qid) {return wdoc_bldr.Qid_(qid);}
public Wdata_doc doc_(String qid, Wbase_claim_base... props) {return wdoc_bldr.Qid_(qid).Add_claims(props).Xto_wdoc();}
public void Init_pids_add(String lang_key, String pid_name, int pid) {wdata_mgr.Pid_mgr.Add(Bry_.new_u8(lang_key + "|" + pid_name), pid);}
public void Init_qids_add(String lang_key, int wiki_tid, String ttl, String qid) {
Bry_bfr tmp_bfr = wiki.Utl__bfr_mkr().Get_b512();
wdata_mgr.Qid_mgr.Add(tmp_bfr, Bry_.new_a7(lang_key), wiki_tid, Bry_.new_a7("000"), Bry_.new_a7(ttl), Bry_.new_a7(qid));
tmp_bfr.Mkr_rls();
}
public void Init_lang_fallbacks(String... fallbacks) {wiki.Lang().Fallback_bry_(Bry_.new_a7(String_.Concat_with_str(",", fallbacks)));}
public void Init_xwikis_add(String... prefixes) {
int len = prefixes.length;
for (int i = 0; i < len; i++) {
String prefix = prefixes[i];
wiki.Xwiki_mgr().Add_by_atrs(prefix, prefix + ".wikipedia.org");
}
}
public void Init_external_links_mgr_clear() {wiki.Parser_mgr().Ctx().Page().Wdata_external_lang_links().Reset();}
public void Init_external_links_mgr_add(String... langs) {
Wdata_external_lang_links_data external_lang_links = wiki.Parser_mgr().Ctx().Page().Wdata_external_lang_links();
external_lang_links.Enabled_(true);
int len = langs.length;
for (int i = 0; i < len; i++) {
String lang = langs[i];
if (String_.Eq(lang, "*"))
external_lang_links.Sort_(true);
else
external_lang_links.Langs_add(Bry_.new_a7(lang));
}
}
public void Init__docs__add(Wdata_doc_bldr bldr) {Init__docs__add(bldr.Xto_wdoc());}
public void Init__docs__add(Wdata_doc wdoc) {
wdata_mgr.Doc_mgr.Add(wdoc.Qid(), wdoc);
Bry_bfr tmp_bfr = Bry_bfr_.New();
Wbase_qid_mgr qid_mgr = wdata_mgr.Qid_mgr;
Ordered_hash slinks = wdoc.Slink_list();
int slinks_len = slinks.Len();
for (int i = 0; i < slinks_len; i++) {
Wdata_sitelink_itm slink = (Wdata_sitelink_itm)slinks.Get_at(i);
Xow_domain_itm domain = Xow_abrv_wm_.Parse_to_domain_itm(slink.Site());
Xoa_ttl page_ttl = wiki.Ttl_parse(slink.Name());
qid_mgr.Add(tmp_bfr, domain.Lang_actl_key(), domain.Domain_type_id(), page_ttl.Ns().Num_bry(), page_ttl.Page_db(), wdoc.Qid());
}
}
public void Test_link(String ttl_str, String expd) {Test_link(Xoa_ttl.Parse(wiki, Xow_ns_.Tid__main, Bry_.new_u8(ttl_str)), expd);}
public void Test_link(Xoa_ttl ttl, String expd) {
byte[] qid_ttl = wdata_mgr.Qid_mgr.Get_qid_or_null(wiki, ttl);
Tfds.Eq(expd, String_.new_u8(qid_ttl));
}
public void Test_parse_pid_null(String val) {Test_parse_pid(val, Wbase_pid.Id_null);}
public void Test_parse_pid(String val, int expd) {Tfds.Eq(expd, Wbase_statement_mgr_.Parse_pid(num_parser, Bry_.new_a7(val)));} private Gfo_number_parser num_parser = new Gfo_number_parser();
public void Test_parse(String raw, String expd) {
parser_fxt.Test_parse_page_tmpl_str(raw, expd);
}
public void Test_parse_langs(String raw, String expd) {
// setup langs
Xoae_page page = wiki.Parser_mgr().Ctx().Page();
app.Xwiki_mgr__sitelink_mgr().Parse(Bry_.new_u8(String_.Concat_lines_nl
( "0|grp1"
, "1|en|English"
, "1|fr|French"
, "1|de|German"
, "1|pl|Polish"
)));
wiki.Xwiki_mgr().Add_by_sitelink_mgr();
wiki.Appe().Usere().Wiki().Xwiki_mgr().Add_by_csv(Bry_.new_a7(String_.Concat_lines_nl
( "1|en.wikipedia.org|en.wikipedia.org"
, "1|fr.wikipedia.org|fr.wikipedia.org"
, "1|de.wikipedia.org|de.wikipedia.org"
, "1|pl.wikipedia.org|pl.wikipedia.org"
)));
parser_fxt.Page_ttl_("Q1_en");
parser_fxt.Exec_parse_page_all_as_str(raw);
Bry_bfr tmp_bfr = wiki.Utl__bfr_mkr().Get_b512();
wdata_lang_wtr.Page_(page).Bfr_arg__add(tmp_bfr);
Tfds.Eq_str_lines(expd, tmp_bfr.To_str_and_rls());
}
public void Test_xwiki_links(String ttl, String... expd) {
tmp_langs.Clear();
Wdata_xwiki_link_wtr.Write_wdata_links(tmp_langs, wiki, Xoa_ttl.Parse(wiki, Bry_.new_u8(ttl)), wiki.Parser_mgr().Ctx().Page().Wdata_external_lang_links());
Tfds.Eq_ary_str(expd, Test_xwiki_links_xto_str_ary(tmp_langs));
} private List_adp tmp_langs = List_adp_.New();
String[] Test_xwiki_links_xto_str_ary(List_adp list) {
int len = list.Count();
String[] rv = new String[len];
for (int i = 0; i < len; i++) {
Wdata_sitelink_itm itm = (Wdata_sitelink_itm)list.Get_at(i);
rv[i] = String_.new_a7(itm.Page_ttl().Page_db());
}
tmp_langs.Clear();
return rv;
}
public void Test_write_json_as_html(String raw_str, String expd) {
byte[] raw_bry = Bry_.new_a7(raw_str);
raw_bry = gplx.langs.jsons.Json_parser_tst.Replace_apos(raw_bry);
Bry_bfr bfr = wiki.Utl__bfr_mkr().Get_b512();
Wdata_wiki_mgr.Write_json_as_html(wdata_mgr.Jdoc_parser(), bfr, raw_bry);
Tfds.Eq(expd, bfr.To_str_and_rls());
}
public static String New_json(String entity_id, String grp_key, String[] grp_vals) {
Bry_bfr bfr = Bry_bfr_.New();
bfr.Add_str_a7("{ 'entity':'").Add_str_u8(entity_id).Add_byte(Byte_ascii.Apos).Add_byte_nl();
bfr.Add_str_a7(", 'datatype':'commonsMedia'\n");
bfr.Add_str_a7(", '").Add_str_u8(grp_key).Add_str_a7("':").Add_byte_nl();
int len = grp_vals.length;
for (int i = 0; i < len; i += 2) {
bfr.Add_byte_repeat(Byte_ascii.Space, 2);
bfr.Add_byte(i == 0 ? Byte_ascii.Curly_bgn : Byte_ascii.Comma).Add_byte(Byte_ascii.Space);
bfr.Add_byte(Byte_ascii.Apos).Add_str_u8(grp_vals[i ]).Add_byte(Byte_ascii.Apos).Add_byte(Byte_ascii.Colon);
bfr.Add_byte(Byte_ascii.Apos).Add_str_u8(grp_vals[i + 1]).Add_byte(Byte_ascii.Apos).Add_byte_nl();
}
bfr.Add_str_a7(" }").Add_byte_nl();
bfr.Add_str_a7("}").Add_byte_nl();
return String_.Replace(bfr.To_str_and_clear(), "'", "\"");
}
}
package gplx.xowa.xtns.wbases;
import gplx.Bry_;
import gplx.Bry_bfr;
import gplx.Bry_bfr_;
import gplx.Byte_ascii;
import gplx.Int_;
import gplx.Io_mgr;
import gplx.List_adp;
import gplx.List_adp_;
import gplx.Ordered_hash;
import gplx.String_;
import gplx.Tfds;
import gplx.core.primitives.Gfo_number_parser;
import gplx.core.primitives.Int_obj_ref;
import gplx.langs.jsons.Json_doc;
import gplx.xowa.Xoa_ttl;
import gplx.xowa.Xoae_app;
import gplx.xowa.Xoae_page;
import gplx.xowa.Xop_fxt;
import gplx.xowa.Xowe_wiki;
import gplx.xowa.wikis.domains.Xow_abrv_wm_;
import gplx.xowa.wikis.domains.Xow_domain_itm;
import gplx.xowa.wikis.nss.Xow_ns_;
import gplx.xowa.xtns.wbases.claims.Wbase_claim_grp;
import gplx.xowa.xtns.wbases.claims.Wbase_claim_grp_list;
import gplx.xowa.xtns.wbases.claims.Wbase_references_grp;
import gplx.xowa.xtns.wbases.claims.enums.Wbase_claim_entity_type_;
import gplx.xowa.xtns.wbases.claims.enums.Wbase_claim_value_type_;
import gplx.xowa.xtns.wbases.claims.itms.Wbase_claim_base;
import gplx.xowa.xtns.wbases.claims.itms.Wbase_claim_entity;
import gplx.xowa.xtns.wbases.claims.itms.Wbase_claim_globecoordinate;
import gplx.xowa.xtns.wbases.claims.itms.Wbase_claim_monolingualtext;
import gplx.xowa.xtns.wbases.claims.itms.Wbase_claim_quantity;
import gplx.xowa.xtns.wbases.claims.itms.Wbase_claim_string;
import gplx.xowa.xtns.wbases.claims.itms.Wbase_claim_time;
import gplx.xowa.xtns.wbases.claims.itms.Wbase_claim_time_;
import gplx.xowa.xtns.wbases.claims.itms.Wbase_claim_value;
import gplx.xowa.xtns.wbases.core.Wbase_pid;
import gplx.xowa.xtns.wbases.core.Wdata_sitelink_itm;
import gplx.xowa.xtns.wbases.pfuncs.Wbase_statement_mgr_;
import gplx.xowa.xtns.wbases.pfuncs.Wdata_external_lang_links_data;
import gplx.xowa.xtns.wbases.stores.Wbase_prop_mgr_loader_;
import gplx.xowa.xtns.wbases.stores.Wbase_qid_mgr;
public class Wdata_wiki_mgr_fxt {
private Xoae_app app; private Xowe_wiki wiki; private Wdata_doc_bldr wdoc_bldr;
private final Wdata_xwiki_link_wtr wdata_lang_wtr = new Wdata_xwiki_link_wtr();
private final Bry_bfr tmp_time_bfr = Bry_bfr_.New();
public Xowe_wiki Wiki() {return parser_fxt.Wiki();}
public Wdata_wiki_mgr_fxt Init() {return Init(new Xop_fxt(), true);}
public Wdata_wiki_mgr_fxt Init(Xop_fxt parser_fxt, boolean reset) {
this.parser_fxt = parser_fxt;
this.wiki = parser_fxt.Wiki();
app = wiki.Appe();
app.Xwiki_mgr__sitelink_mgr().Init_by_app();
wdoc_bldr = new Wdata_doc_bldr();
wdata_mgr = app.Wiki_mgr().Wdata_mgr();
wdata_mgr.Prop_mgr().Loader_(Wbase_prop_mgr_loader_.New_mock());
wdata_mgr.Clear();
if (reset) {
Io_mgr.Instance.InitEngine_mem();
parser_fxt.Reset();
}
return this;
}
public Xoae_app App() {return app;}
public Wdata_wiki_mgr Wdata_mgr() {return wdata_mgr;} private Wdata_wiki_mgr wdata_mgr;
public Xop_fxt Parser_fxt() {return parser_fxt;} private Xop_fxt parser_fxt;
public Wdata_doc_bldr Wdoc_bldr(String qid) {return wdoc_bldr.Qid_(qid);}
public Json_doc Make_json(String src) {return app.Utl__json_parser().Parse_by_apos(src);}
public Wbase_claim_base Make_claim_novalue(int pid) {return Wbase_claim_value.New_novalue(pid);}
public Wbase_claim_base Make_claim_somevalue(int pid) {return Wbase_claim_value.New_somevalue(pid);}
public Wbase_claim_base Make_claim_string(int pid, String val) {return Make_claim_string(pid, Bry_.new_u8(val));}
public Wbase_claim_base Make_claim_string(int pid, byte[] val) {return new Wbase_claim_string(pid, Wbase_claim_value_type_.Tid__value, val);}
public Wbase_claim_base Make_claim_time(int pid, String val) {return Make_claim_time(pid, val, Bry_.Empty, Bry_.Empty);}
public Wbase_claim_base Make_claim_time(int pid, String val, int precision) {return Make_claim_time(pid, val, Int_.To_bry(precision), Bry_.Empty);}
public Wbase_claim_base Make_claim_time(int pid, String val, byte[] precision, byte[] calendar) {
return new Wbase_claim_time(pid, Wbase_claim_value_type_.Tid__value, Wbase_claim_time_.To_bry(tmp_time_bfr, val), Bry_.Empty, Bry_.Empty, Bry_.Empty, precision, calendar);
}
public Wbase_claim_base Make_claim_monolingual(int pid, String lang, String text) {return new Wbase_claim_monolingualtext(pid, Wbase_claim_value_type_.Tid__value, Bry_.new_u8(lang), Bry_.new_u8(text));}
public Wbase_claim_base Make_claim_quantity(int pid, String amount, String unit, String ubound, String lbound) {return new Wbase_claim_quantity(pid, Wbase_claim_value_type_.Tid__value, Bry_.new_a7(amount), Bry_.new_a7(unit), Bry_.new_a7(ubound), Bry_.new_a7(lbound));}
public Wbase_claim_base Make_claim_entity_qid(int pid, int val) {return new Wbase_claim_entity(pid, Wbase_claim_value_type_.Tid__value, Wbase_claim_entity_type_.Tid__item, Int_.To_bry(val));}
public Wbase_claim_base Make_claim_entity_pid(int pid, int val) {return new Wbase_claim_entity(pid, Wbase_claim_value_type_.Tid__value, Wbase_claim_entity_type_.Tid__property, Int_.To_bry(val));}
public Wbase_claim_base Make_claim_geo(int pid, String lon, String lat) {return Make_claim_geo(pid, lon, lat, ".00001", null, "http://www.wikidata.org/entity/Q2");}
public Wbase_claim_base Make_claim_geo(int pid, String lon, String lat, String prc, String alt, String glb) {
return new Wbase_claim_globecoordinate(pid, Wbase_claim_value_type_.Tid__value, Bry_.new_a7(lat), Bry_.new_a7(lon), Bry_.new_a7(alt), Bry_.new_a7(prc), Bry_.new_a7(glb));
}
public Wbase_claim_grp Make_qualifiers_grp(int pid, Wbase_claim_base... ary) {return new Wbase_claim_grp(Int_obj_ref.New(pid), ary);}
public Wbase_claim_grp_list Make_qualifiers(Wbase_claim_grp... ary) {
Wbase_claim_grp_list rv = new Wbase_claim_grp_list();
int len = ary.length;
for (int i = 0; i < len; ++i)
rv.Add(ary[i]);
return rv;
}
public Wbase_references_grp[] Make_references(Wbase_references_grp... ary) {
return ary;
}
public Wbase_references_grp Make_reference_grp(String hash, int[] snaks_order, Wbase_claim_grp... snaks) {
Wbase_claim_grp_list list = new Wbase_claim_grp_list();
for (Wbase_claim_grp itm : snaks)
list.Add(itm);
return new Wbase_references_grp(Bry_.new_u8(hash), list, snaks_order);
}
public Wbase_claim_grp Make_reference_itm(int id, Wbase_claim_base... itms) {
return new Wbase_claim_grp(Int_obj_ref.New(id), itms);
}
public Wdata_doc_bldr Wdoc(String qid) {return wdoc_bldr.Qid_(qid);}
public Wdata_doc doc_(String qid, Wbase_claim_base... props) {return wdoc_bldr.Qid_(qid).Add_claims(props).Xto_wdoc();}
public void Init_pids_add(String lang_key, String pid_name, int pid) {wdata_mgr.Pid_mgr.Add(Bry_.new_u8(lang_key + "|" + pid_name), pid);}
public void Init_qids_add(String lang_key, int wiki_tid, String ttl, String qid) {
Bry_bfr tmp_bfr = wiki.Utl__bfr_mkr().Get_b512();
wdata_mgr.Qid_mgr.Add(tmp_bfr, Bry_.new_a7(lang_key), wiki_tid, Bry_.new_a7("000"), Bry_.new_a7(ttl), Bry_.new_a7(qid));
tmp_bfr.Mkr_rls();
}
public void Init_lang_fallbacks(String... fallbacks) {wiki.Lang().Fallback_bry_(Bry_.new_a7(String_.Concat_with_str(",", fallbacks)));}
public void Init_xwikis_add(String... prefixes) {
int len = prefixes.length;
for (int i = 0; i < len; i++) {
String prefix = prefixes[i];
wiki.Xwiki_mgr().Add_by_atrs(prefix, prefix + ".wikipedia.org");
}
}
public void Init_external_links_mgr_clear() {wiki.Parser_mgr().Ctx().Page().Wdata_external_lang_links().Reset();}
public void Init_external_links_mgr_add(String... langs) {
Wdata_external_lang_links_data external_lang_links = wiki.Parser_mgr().Ctx().Page().Wdata_external_lang_links();
external_lang_links.Enabled_(true);
int len = langs.length;
for (int i = 0; i < len; i++) {
String lang = langs[i];
if (String_.Eq(lang, "*"))
external_lang_links.Sort_(true);
else
external_lang_links.Langs_add(Bry_.new_a7(lang));
}
}
public void Init__docs__add(Wdata_doc_bldr bldr) {Init__docs__add(bldr.Xto_wdoc());}
public void Init__docs__add(Wdata_doc wdoc) {
wdata_mgr.Doc_mgr.Add(wdoc.Qid(), wdoc);
Bry_bfr tmp_bfr = Bry_bfr_.New();
Wbase_qid_mgr qid_mgr = wdata_mgr.Qid_mgr;
Ordered_hash slinks = wdoc.Slink_list();
int slinks_len = slinks.Len();
for (int i = 0; i < slinks_len; i++) {
Wdata_sitelink_itm slink = (Wdata_sitelink_itm)slinks.Get_at(i);
Xow_domain_itm domain = Xow_abrv_wm_.Parse_to_domain_itm(slink.Site());
Xoa_ttl page_ttl = wiki.Ttl_parse(slink.Name());
qid_mgr.Add(tmp_bfr, domain.Lang_actl_key(), domain.Domain_type_id(), page_ttl.Ns().Num_bry(), page_ttl.Page_db(), wdoc.Qid());
}
}
public void Test_link(String ttl_str, String expd) {Test_link(Xoa_ttl.Parse(wiki, Xow_ns_.Tid__main, Bry_.new_u8(ttl_str)), expd);}
public void Test_link(Xoa_ttl ttl, String expd) {
byte[] qid_ttl = wdata_mgr.Qid_mgr.Get_qid_or_null(wiki, ttl);
Tfds.Eq(expd, String_.new_u8(qid_ttl));
}
public void Test_parse_pid_null(String val) {Test_parse_pid(val, Wbase_pid.Id_null);}
public void Test_parse_pid(String val, int expd) {Tfds.Eq(expd, Wbase_statement_mgr_.Parse_pid(num_parser, Bry_.new_a7(val)));} private Gfo_number_parser num_parser = new Gfo_number_parser();
public void Test_parse(String raw, String expd) {
parser_fxt.Test_parse_page_tmpl_str(raw, expd);
}
public void Test_parse_langs(String raw, String expd) {
// setup langs
Xoae_page page = wiki.Parser_mgr().Ctx().Page();
app.Xwiki_mgr__sitelink_mgr().Parse(Bry_.new_u8(String_.Concat_lines_nl
( "0|grp1"
, "1|en|English"
, "1|fr|French"
, "1|de|German"
, "1|pl|Polish"
)));
wiki.Xwiki_mgr().Add_by_sitelink_mgr();
wiki.Appe().Usere().Wiki().Xwiki_mgr().Add_by_csv(Bry_.new_a7(String_.Concat_lines_nl
( "1|en.wikipedia.org|en.wikipedia.org"
, "1|fr.wikipedia.org|fr.wikipedia.org"
, "1|de.wikipedia.org|de.wikipedia.org"
, "1|pl.wikipedia.org|pl.wikipedia.org"
)));
parser_fxt.Page_ttl_("Q1_en");
parser_fxt.Exec_parse_page_all_as_str(raw);
Bry_bfr tmp_bfr = wiki.Utl__bfr_mkr().Get_b512();
wdata_lang_wtr.Page_(page).Bfr_arg__add(tmp_bfr);
Tfds.Eq_str_lines(expd, tmp_bfr.To_str_and_rls());
}
public void Test_xwiki_links(String ttl, String... expd) {
tmp_langs.Clear();
Wdata_xwiki_link_wtr.Write_wdata_links(tmp_langs, wiki, Xoa_ttl.Parse(wiki, Bry_.new_u8(ttl)), wiki.Parser_mgr().Ctx().Page().Wdata_external_lang_links());
Tfds.Eq_ary_str(expd, Test_xwiki_links_xto_str_ary(tmp_langs));
} private List_adp tmp_langs = List_adp_.New();
String[] Test_xwiki_links_xto_str_ary(List_adp list) {
int len = list.Count();
String[] rv = new String[len];
for (int i = 0; i < len; i++) {
Wdata_sitelink_itm itm = (Wdata_sitelink_itm)list.Get_at(i);
rv[i] = String_.new_a7(itm.Page_ttl().Page_db());
}
tmp_langs.Clear();
return rv;
}
public void Test_write_json_as_html(String raw_str, String expd) {
byte[] raw_bry = Bry_.new_a7(raw_str);
raw_bry = Bry_.new_u8(Json_doc.Make_str_by_apos(raw_str));
Bry_bfr bfr = wiki.Utl__bfr_mkr().Get_b512();
Wdata_wiki_mgr.Write_json_as_html(wdata_mgr.Jdoc_parser(), bfr, raw_bry);
Tfds.Eq(expd, bfr.To_str_and_rls());
}
public static String New_json(String entity_id, String grp_key, String[] grp_vals) {
Bry_bfr bfr = Bry_bfr_.New();
bfr.Add_str_a7("{ 'entity':'").Add_str_u8(entity_id).Add_byte(Byte_ascii.Apos).Add_byte_nl();
bfr.Add_str_a7(", 'datatype':'commonsMedia'\n");
bfr.Add_str_a7(", '").Add_str_u8(grp_key).Add_str_a7("':").Add_byte_nl();
int len = grp_vals.length;
for (int i = 0; i < len; i += 2) {
bfr.Add_byte_repeat(Byte_ascii.Space, 2);
bfr.Add_byte(i == 0 ? Byte_ascii.Curly_bgn : Byte_ascii.Comma).Add_byte(Byte_ascii.Space);
bfr.Add_byte(Byte_ascii.Apos).Add_str_u8(grp_vals[i ]).Add_byte(Byte_ascii.Apos).Add_byte(Byte_ascii.Colon);
bfr.Add_byte(Byte_ascii.Apos).Add_str_u8(grp_vals[i + 1]).Add_byte(Byte_ascii.Apos).Add_byte_nl();
}
bfr.Add_str_a7(" }").Add_byte_nl();
bfr.Add_str_a7("}").Add_byte_nl();
return String_.Replace(bfr.To_str_and_clear(), "'", "\"");
}
}

@ -39,11 +39,11 @@ public class Wbase_claim_factory {
public Wbase_claim_base Parse(byte[] qid, int pid, byte snak_tid, Json_nde nde, byte value_tid, Json_itm value_itm) {
switch (value_tid) {
case Wbase_claim_type_.Tid__string: return new Wbase_claim_string(pid, snak_tid, value_itm.Data_bry());
case Wbase_claim_type_.Tid__entity: return Parse_datavalue_entity (qid, pid, snak_tid, Json_nde.cast(value_itm));
case Wbase_claim_type_.Tid__time: return Parse_datavalue_time (qid, pid, snak_tid, Json_nde.cast(value_itm));
case Wbase_claim_type_.Tid__quantity: return Parse_datavalue_quantity (qid, pid, snak_tid, Json_nde.cast(value_itm));
case Wbase_claim_type_.Tid__globecoordinate: return Parse_datavalue_globecoordinate (qid, pid, snak_tid, Json_nde.cast(value_itm));
case Wbase_claim_type_.Tid__monolingualtext: return Parse_datavalue_monolingualtext (qid, pid, snak_tid, Json_nde.cast(value_itm));
case Wbase_claim_type_.Tid__entity: return Parse_datavalue_entity (qid, pid, snak_tid, Json_nde.Cast(value_itm));
case Wbase_claim_type_.Tid__time: return Parse_datavalue_time (qid, pid, snak_tid, Json_nde.Cast(value_itm));
case Wbase_claim_type_.Tid__quantity: return Parse_datavalue_quantity (qid, pid, snak_tid, Json_nde.Cast(value_itm));
case Wbase_claim_type_.Tid__globecoordinate: return Parse_datavalue_globecoordinate (qid, pid, snak_tid, Json_nde.Cast(value_itm));
case Wbase_claim_type_.Tid__monolingualtext: return Parse_datavalue_monolingualtext (qid, pid, snak_tid, Json_nde.Cast(value_itm));
default: throw Err_.new_unhandled_default(value_tid);
}
}
@ -53,7 +53,7 @@ public class Wbase_claim_factory {
byte[] numericId = null;
byte[] id = null;
for (int i = 0; i < len; ++i) {
Json_kv sub = Json_kv.cast(nde.Get_at(i));
Json_kv sub = Json_kv.Cast(nde.Get_at(i));
byte tid = Wbase_claim_entity_.Reg.Get_tid_or_max_and_log(qid, sub.Key().Data_bry()); if (tid == Byte_.Max_value_127) continue;
byte[] subValBry = sub.Val().Data_bry();
switch (tid) {
@ -70,7 +70,7 @@ public class Wbase_claim_factory {
int len = nde.Len();
byte[] lang = null, text = null;
for (int i = 0; i < len; ++i) {
Json_kv sub = Json_kv.cast(nde.Get_at(i));
Json_kv sub = Json_kv.Cast(nde.Get_at(i));
byte tid = Wbase_claim_monolingualtext_.Reg.Get_tid_or_max_and_log(qid, sub.Key().Data_bry()); if (tid == Byte_.Max_value_127) continue;
byte[] sub_val_bry = sub.Val().Data_bry();
switch (tid) {
@ -85,7 +85,7 @@ public class Wbase_claim_factory {
int len = nde.Len();
byte[] lat = null, lng = null, alt = null, prc = null, glb = null;
for (int i = 0; i < len; ++i) {
Json_kv sub = Json_kv.cast(nde.Get_at(i));
Json_kv sub = Json_kv.Cast(nde.Get_at(i));
byte tid = Wbase_claim_globecoordinate_.Reg.Get_tid_or_max_and_log(qid, sub.Key().Data_bry()); if (tid == Byte_.Max_value_127) continue;
byte[] sub_val_bry = sub.Val().Data_bry();
switch (tid) {
@ -103,7 +103,7 @@ public class Wbase_claim_factory {
int len = nde.Len();
byte[] amount = null, unit = null, ubound = null, lbound = null;
for (int i = 0; i < len; ++i) {
Json_kv sub = Json_kv.cast(nde.Get_at(i));
Json_kv sub = Json_kv.Cast(nde.Get_at(i));
byte tid = Wbase_claim_quantity_.Reg.Get_tid_or_max_and_log(qid, sub.Key().Data_bry()); if (tid == Byte_.Max_value_127) continue;
byte[] sub_val_bry = sub.Val().Data_bry();
switch (tid) {
@ -120,7 +120,7 @@ public class Wbase_claim_factory {
int len = nde.Len();
byte[] time = null, timezone = null, before = null, after = null, precision = null, calendarmodel = null;
for (int i = 0; i < len; ++i) {
Json_kv sub = Json_kv.cast(nde.Get_at(i));
Json_kv sub = Json_kv.Cast(nde.Get_at(i));
byte tid = Wbase_claim_time_.Reg.Get_tid_or_max_and_log(qid, sub.Key().Data_bry()); if (tid == Byte_.Max_value_127) continue;
byte[] sub_val_bry = sub.Val().Data_bry();
switch (tid) {

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,135 +13,158 @@ 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.wbases.parsers; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.wbases.*;
import gplx.core.primitives.*;
import gplx.langs.jsons.*; import gplx.xowa.xtns.wbases.core.*; import gplx.xowa.xtns.wbases.claims.*; import gplx.xowa.xtns.wbases.claims.enums.*; import gplx.xowa.xtns.wbases.claims.itms.*;
class Wdata_claims_parser_v2 {
private final Wbase_claim_factory factory = new Wbase_claim_factory();
public void Make_claim_itms(byte[] qid, List_adp claim_itms_list, byte[] src, Json_kv claim_grp) {
Json_ary claim_itms_ary = Json_ary.cast_or_null(claim_grp.Val());
int claim_itms_len = claim_itms_ary.Len();
int pid = Parse_pid(claim_grp.Key().Data_bry());
for (int i = 0; i < claim_itms_len; ++i) {
Json_nde claim_itm_nde = Json_nde.cast(claim_itms_ary.Get_at(i));
Wbase_claim_base itm = Parse_claim_itm(qid, claim_itm_nde, pid);
if (itm != null) // HACK: itm can be null if value is "somevalue"; DATE:2014-09-20
claim_itms_list.Add(itm);
}
}
private Wbase_claim_base Parse_claim_itm(byte[] qid, Json_nde nde, int pid) {
int len = nde.Len();
byte rank_tid = Wbase_claim_rank_.Tid__unknown;
Wbase_claim_base claim_itm = null; Wbase_claim_grp_list qualifiers = null; int[] qualifiers_order = null; Wbase_references_grp[] snaks_grp = null;
for (int i = 0; i < len; ++i) {
Json_kv sub = Json_kv.cast(nde.Get_at(i));
byte tid = Wdata_dict_claim.Reg.Get_tid_or_max_and_log(qid, sub.Key().Data_bry()); if (tid == Byte_.Max_value_127) continue;
switch (tid) {
case Wdata_dict_claim.Tid__mainsnak: claim_itm = Parse_mainsnak(qid, Json_nde.cast(sub.Val()), pid); break;
case Wdata_dict_claim.Tid__rank: rank_tid = Wbase_claim_rank_.Reg.Get_tid_or(sub.Val().Data_bry(), Wbase_claim_rank_.Tid__unknown); break;
case Wdata_dict_claim.Tid__references: snaks_grp = Parse_references(qid, Json_ary.cast_or_null(sub.Val())); break;
case Wdata_dict_claim.Tid__qualifiers: qualifiers = Parse_qualifiers(qid, Json_nde.cast(sub.Val())); break;
case Wdata_dict_claim.Tid__qualifiers_order: qualifiers_order = Parse_pid_order(Json_ary.cast_or_null(sub.Val())); break;
case Wdata_dict_claim.Tid__type: break; // ignore: "statement"
case Wdata_dict_claim.Tid__id: break; // ignore: "Q2$F909BD1C-D34D-423F-9ED2-3493663321AF"
}
}
if (claim_itm != null) {
claim_itm.Rank_tid_(rank_tid);
if (qualifiers != null) claim_itm.Qualifiers_(qualifiers);
if (qualifiers_order != null) claim_itm.Qualifiers_order_(qualifiers_order);
if (snaks_grp != null) claim_itm.References_(snaks_grp);
}
return claim_itm;
}
public Wbase_references_grp[] Parse_references(byte[] qid, Json_ary owner) {
int len = owner.Len();
Wbase_references_grp[] rv = new Wbase_references_grp[len];
for (int i = 0; i < len; ++i) {
Json_nde grp_nde = Json_nde.cast(owner.Get_at(i));
rv[i] = Parse_references_grp(qid, grp_nde);
}
return rv;
}
private Wbase_references_grp Parse_references_grp(byte[] qid, Json_nde owner) {
byte[] hash = null;
Wbase_claim_grp_list snaks = null;
int[] snaks_order = null;
int len = owner.Len();
for (int i = 0; i < len; ++i) {
Json_kv sub = Json_kv.cast(owner.Get_at(i));
byte tid = Wdata_dict_reference.Reg.Get_tid_or_max_and_log(qid, sub.Key().Data_bry()); if (tid == Byte_.Max_value_127) continue;
switch (tid) {
case Wdata_dict_reference.Tid__hash: hash = sub.Val_as_bry(); break;
case Wdata_dict_reference.Tid__snaks: snaks = Parse_qualifiers(qid, Json_nde.cast(sub.Val())); break;
case Wdata_dict_reference.Tid__snaks_order: snaks_order = Parse_pid_order(Json_ary.cast_or_null(sub.Val())); break;
}
}
return new Wbase_references_grp(hash, snaks, snaks_order);
}
public Wbase_claim_grp_list Parse_qualifiers(byte[] qid, Json_nde qualifiers_nde) {
Wbase_claim_grp_list rv = new Wbase_claim_grp_list();
if (qualifiers_nde == null) return rv; // NOTE:sometimes references can have 0 snaks; return back an empty Wbase_claim_grp_list, not null; PAGE:Птичкин,_Евгений_Николаевич; DATE:2015-02-16
int len = qualifiers_nde.Len();
for (int i = 0; i < len; ++i) {
Json_kv qualifier_kv = Json_kv.cast(qualifiers_nde.Get_at(i));
int pid = Parse_pid(qualifier_kv.Key().Data_bry());
Wbase_claim_grp claims_grp = Parse_props_grp(qid, pid, Json_ary.cast_or_null(qualifier_kv.Val()));
rv.Add(claims_grp);
}
return rv;
}
public int[] Parse_pid_order(Json_ary ary) {
int len = ary.Len();
int[] rv = new int[len];
for (int i = 0; i < len; ++i) {
Json_itm pid_itm = ary.Get_at(i);
rv[i] = Parse_pid(pid_itm.Data_bry());
}
return rv;
}
private Wbase_claim_grp Parse_props_grp(byte[] qid, int pid, Json_ary props_ary) {
List_adp list = List_adp_.New();
int len = props_ary.Len();
for (int i = 0; i < len; ++i) {
Json_nde qualifier_nde = Json_nde.cast(props_ary.Get_at(i));
Wbase_claim_base qualifier_itm = Parse_mainsnak(qid, qualifier_nde, pid);
list.Add(qualifier_itm);
}
return new Wbase_claim_grp(Int_obj_ref.New(pid), (Wbase_claim_base[])list.To_ary_and_clear(Wbase_claim_base.class));
}
public Wbase_claim_base Parse_mainsnak(byte[] qid, Json_nde nde, int pid) {
int len = nde.Len();
byte snak_tid = Byte_.Max_value_127;
for (int i = 0; i < len; ++i) {
Json_kv sub = Json_kv.cast(nde.Get_at(i));
byte tid = Wdata_dict_mainsnak.Reg.Get_tid_or_max_and_log(qid, sub.Key().Data_bry()); if (tid == Byte_.Max_value_127) continue;
switch (tid) {
case Wdata_dict_mainsnak.Tid__snaktype: snak_tid = Wbase_claim_value_type_.Reg.Get_tid_or_fail(sub.Val().Data_bry()); break;
case Wdata_dict_mainsnak.Tid__datavalue: return Parse_datavalue(qid, pid, snak_tid, Json_nde.cast(sub.Val()));
case Wdata_dict_mainsnak.Tid__datatype: break; // ignore: has values like "wikibase-property"; EX: www.wikidata.org/wiki/Property:P397; DATE:2015-06-12
case Wdata_dict_mainsnak.Tid__property: break; // ignore: pid already available above
case Wdata_dict_mainsnak.Tid__hash: break; // ignore: "84487fc3f93b4f74ab1cc5a47d78f596f0b49390"
}
}
return new Wbase_claim_value(pid, Wbase_claim_type_.Tid__unknown, snak_tid); // NOTE: mainsnak can be null, especially for qualifiers; PAGE:Q2!P576; DATE:2014-09-20
}
public Wbase_claim_base Parse_datavalue(byte[] qid, int pid, byte snak_tid, Json_nde nde) {
int len = nde.Len();
Json_itm value_itm = null; byte value_tid = Wbase_claim_type_.Tid__unknown;
for (int i = 0; i < len; ++i) {
Json_kv sub = Json_kv.cast(nde.Get_at(i));
byte tid = Wdata_dict_datavalue.Reg.Get_tid_or_max_and_log(qid, sub.Key().Data_bry()); if (tid == Byte_.Max_value_127) continue;
switch (tid) {
case Wdata_dict_datavalue.Tid__type: value_tid = Wbase_claim_type_.Get_tid_or_unknown(sub.Val().Data_bry()); break;
case Wdata_dict_datavalue.Tid__value: value_itm = sub.Val(); break;
case Wdata_dict_datavalue.Tid__error: break; // ignore: "Can only construct GlobeCoordinateValue with a String globe parameter"
}
}
return factory.Parse(qid, pid, snak_tid, nde, value_tid, value_itm);
}
private static int Parse_pid(byte[] pid_bry) {
int rv = Bry_.To_int_or(pid_bry, 1, pid_bry.length, -1); if (rv == -1) throw Err_.new_wo_type("invalid pid", "pid", String_.new_u8(pid_bry));
return rv;
}
}
package gplx.xowa.xtns.wbases.parsers;
import gplx.Bry_;
import gplx.Byte_;
import gplx.Err_;
import gplx.List_adp;
import gplx.List_adp_;
import gplx.String_;
import gplx.core.primitives.Int_obj_ref;
import gplx.langs.jsons.Json_ary;
import gplx.langs.jsons.Json_itm;
import gplx.langs.jsons.Json_kv;
import gplx.langs.jsons.Json_nde;
import gplx.xowa.xtns.wbases.claims.Wbase_claim_grp;
import gplx.xowa.xtns.wbases.claims.Wbase_claim_grp_list;
import gplx.xowa.xtns.wbases.claims.Wbase_references_grp;
import gplx.xowa.xtns.wbases.claims.enums.Wbase_claim_rank_;
import gplx.xowa.xtns.wbases.claims.enums.Wbase_claim_type_;
import gplx.xowa.xtns.wbases.claims.enums.Wbase_claim_value_type_;
import gplx.xowa.xtns.wbases.claims.itms.Wbase_claim_base;
import gplx.xowa.xtns.wbases.claims.itms.Wbase_claim_value;
import gplx.xowa.xtns.wbases.core.Wdata_dict_claim;
import gplx.xowa.xtns.wbases.core.Wdata_dict_datavalue;
import gplx.xowa.xtns.wbases.core.Wdata_dict_mainsnak;
import gplx.xowa.xtns.wbases.core.Wdata_dict_reference;
class Wdata_claims_parser_v2 {
private final Wbase_claim_factory factory = new Wbase_claim_factory();
public void Make_claim_itms(byte[] qid, List_adp claim_itms_list, byte[] src, Json_kv claim_grp) {
Json_ary claim_itms_ary = Json_ary.cast_or_null(claim_grp.Val());
int claim_itms_len = claim_itms_ary.Len();
int pid = Parse_pid(claim_grp.Key().Data_bry());
for (int i = 0; i < claim_itms_len; ++i) {
Json_nde claim_itm_nde = Json_nde.Cast(claim_itms_ary.Get_at(i));
Wbase_claim_base itm = Parse_claim_itm(qid, claim_itm_nde, pid);
if (itm != null) // HACK: itm can be null if value is "somevalue"; DATE:2014-09-20
claim_itms_list.Add(itm);
}
}
private Wbase_claim_base Parse_claim_itm(byte[] qid, Json_nde nde, int pid) {
int len = nde.Len();
byte rank_tid = Wbase_claim_rank_.Tid__unknown;
Wbase_claim_base claim_itm = null; Wbase_claim_grp_list qualifiers = null; int[] qualifiers_order = null; Wbase_references_grp[] snaks_grp = null;
for (int i = 0; i < len; ++i) {
Json_kv sub = Json_kv.Cast(nde.Get_at(i));
byte tid = Wdata_dict_claim.Reg.Get_tid_or_max_and_log(qid, sub.Key().Data_bry()); if (tid == Byte_.Max_value_127) continue;
switch (tid) {
case Wdata_dict_claim.Tid__mainsnak: claim_itm = Parse_mainsnak(qid, Json_nde.Cast(sub.Val()), pid); break;
case Wdata_dict_claim.Tid__rank: rank_tid = Wbase_claim_rank_.Reg.Get_tid_or(sub.Val().Data_bry(), Wbase_claim_rank_.Tid__unknown); break;
case Wdata_dict_claim.Tid__references: snaks_grp = Parse_references(qid, Json_ary.cast_or_null(sub.Val())); break;
case Wdata_dict_claim.Tid__qualifiers: qualifiers = Parse_qualifiers(qid, Json_nde.Cast(sub.Val())); break;
case Wdata_dict_claim.Tid__qualifiers_order: qualifiers_order = Parse_pid_order(Json_ary.cast_or_null(sub.Val())); break;
case Wdata_dict_claim.Tid__type: break; // ignore: "statement"
case Wdata_dict_claim.Tid__id: break; // ignore: "Q2$F909BD1C-D34D-423F-9ED2-3493663321AF"
}
}
if (claim_itm != null) {
claim_itm.Rank_tid_(rank_tid);
if (qualifiers != null) claim_itm.Qualifiers_(qualifiers);
if (qualifiers_order != null) claim_itm.Qualifiers_order_(qualifiers_order);
if (snaks_grp != null) claim_itm.References_(snaks_grp);
}
return claim_itm;
}
public Wbase_references_grp[] Parse_references(byte[] qid, Json_ary owner) {
int len = owner.Len();
Wbase_references_grp[] rv = new Wbase_references_grp[len];
for (int i = 0; i < len; ++i) {
Json_nde grp_nde = Json_nde.Cast(owner.Get_at(i));
rv[i] = Parse_references_grp(qid, grp_nde);
}
return rv;
}
private Wbase_references_grp Parse_references_grp(byte[] qid, Json_nde owner) {
byte[] hash = null;
Wbase_claim_grp_list snaks = null;
int[] snaks_order = null;
int len = owner.Len();
for (int i = 0; i < len; ++i) {
Json_kv sub = Json_kv.Cast(owner.Get_at(i));
byte tid = Wdata_dict_reference.Reg.Get_tid_or_max_and_log(qid, sub.Key().Data_bry()); if (tid == Byte_.Max_value_127) continue;
switch (tid) {
case Wdata_dict_reference.Tid__hash: hash = sub.Val_as_bry(); break;
case Wdata_dict_reference.Tid__snaks: snaks = Parse_qualifiers(qid, Json_nde.Cast(sub.Val())); break;
case Wdata_dict_reference.Tid__snaks_order: snaks_order = Parse_pid_order(Json_ary.cast_or_null(sub.Val())); break;
}
}
return new Wbase_references_grp(hash, snaks, snaks_order);
}
public Wbase_claim_grp_list Parse_qualifiers(byte[] qid, Json_nde qualifiers_nde) {
Wbase_claim_grp_list rv = new Wbase_claim_grp_list();
if (qualifiers_nde == null) return rv; // NOTE:sometimes references can have 0 snaks; return back an empty Wbase_claim_grp_list, not null; PAGE:Птичкин,_Евгений_Николаевич; DATE:2015-02-16
int len = qualifiers_nde.Len();
for (int i = 0; i < len; ++i) {
Json_kv qualifier_kv = Json_kv.Cast(qualifiers_nde.Get_at(i));
int pid = Parse_pid(qualifier_kv.Key().Data_bry());
Wbase_claim_grp claims_grp = Parse_props_grp(qid, pid, Json_ary.cast_or_null(qualifier_kv.Val()));
rv.Add(claims_grp);
}
return rv;
}
public int[] Parse_pid_order(Json_ary ary) {
int len = ary.Len();
int[] rv = new int[len];
for (int i = 0; i < len; ++i) {
Json_itm pid_itm = ary.Get_at(i);
rv[i] = Parse_pid(pid_itm.Data_bry());
}
return rv;
}
private Wbase_claim_grp Parse_props_grp(byte[] qid, int pid, Json_ary props_ary) {
List_adp list = List_adp_.New();
int len = props_ary.Len();
for (int i = 0; i < len; ++i) {
Json_nde qualifier_nde = Json_nde.Cast(props_ary.Get_at(i));
Wbase_claim_base qualifier_itm = Parse_mainsnak(qid, qualifier_nde, pid);
list.Add(qualifier_itm);
}
return new Wbase_claim_grp(Int_obj_ref.New(pid), (Wbase_claim_base[])list.To_ary_and_clear(Wbase_claim_base.class));
}
public Wbase_claim_base Parse_mainsnak(byte[] qid, Json_nde nde, int pid) {
int len = nde.Len();
byte snak_tid = Byte_.Max_value_127;
for (int i = 0; i < len; ++i) {
Json_kv sub = Json_kv.Cast(nde.Get_at(i));
byte tid = Wdata_dict_mainsnak.Reg.Get_tid_or_max_and_log(qid, sub.Key().Data_bry()); if (tid == Byte_.Max_value_127) continue;
switch (tid) {
case Wdata_dict_mainsnak.Tid__snaktype: snak_tid = Wbase_claim_value_type_.Reg.Get_tid_or_fail(sub.Val().Data_bry()); break;
case Wdata_dict_mainsnak.Tid__datavalue: return Parse_datavalue(qid, pid, snak_tid, Json_nde.Cast(sub.Val()));
case Wdata_dict_mainsnak.Tid__datatype: break; // ignore: has values like "wikibase-property"; EX: www.wikidata.org/wiki/Property:P397; DATE:2015-06-12
case Wdata_dict_mainsnak.Tid__property: break; // ignore: pid already available above
case Wdata_dict_mainsnak.Tid__hash: break; // ignore: "84487fc3f93b4f74ab1cc5a47d78f596f0b49390"
}
}
return new Wbase_claim_value(pid, Wbase_claim_type_.Tid__unknown, snak_tid); // NOTE: mainsnak can be null, especially for qualifiers; PAGE:Q2!P576; DATE:2014-09-20
}
public Wbase_claim_base Parse_datavalue(byte[] qid, int pid, byte snak_tid, Json_nde nde) {
int len = nde.Len();
Json_itm value_itm = null; byte value_tid = Wbase_claim_type_.Tid__unknown;
for (int i = 0; i < len; ++i) {
Json_kv sub = Json_kv.Cast(nde.Get_at(i));
byte tid = Wdata_dict_datavalue.Reg.Get_tid_or_max_and_log(qid, sub.Key().Data_bry()); if (tid == Byte_.Max_value_127) continue;
switch (tid) {
case Wdata_dict_datavalue.Tid__type: value_tid = Wbase_claim_type_.Get_tid_or_unknown(sub.Val().Data_bry()); break;
case Wdata_dict_datavalue.Tid__value: value_itm = sub.Val(); break;
case Wdata_dict_datavalue.Tid__error: break; // ignore: "Can only construct GlobeCoordinateValue with a String globe parameter"
}
}
return factory.Parse(qid, pid, snak_tid, nde, value_tid, value_itm);
}
private static int Parse_pid(byte[] pid_bry) {
int rv = Bry_.To_int_or(pid_bry, 1, pid_bry.length, -1); if (rv == -1) throw Err_.new_wo_type("invalid pid", "pid", String_.new_u8(pid_bry));
return rv;
}
}

@ -52,8 +52,8 @@ import gplx.xowa.xtns.wbases.core.Wdata_sitelink_itm;
abstract class Wdata_doc_parser_fxt_base {
protected Wdata_doc_parser wdoc_parser;
private final Json_parser json_parser = new Json_parser();
private final Bry_bfr tmp_time_bfr = Bry_bfr_.New();
private final Json_parser json_parser = new Json_parser();
private final Bry_bfr tmp_time_bfr = Bry_bfr_.New();
public void Init() {
if (wdoc_parser == null) wdoc_parser = Make_parser();
}
@ -100,13 +100,13 @@ abstract class Wdata_doc_parser_fxt_base {
}
public void Test_qualifiers(String raw, Wbase_claim_base... expd_itms) {
Json_doc jdoc = json_parser.Parse_by_apos(raw);
Json_nde qualifiers_nde = Json_nde.cast(Json_kv.cast(jdoc.Root_nde().Get_at(0)).Val());
Json_nde qualifiers_nde = Json_nde.Cast(Json_kv.Cast(jdoc.Root_nde().Get_at(0)).Val());
Wbase_claim_grp_list actl = wdoc_parser.Parse_qualifiers(Q1_bry, qualifiers_nde);
Tfds.Eq_ary_str(expd_itms, To_ary(actl));
}
public void Test_references(String raw, int[] expd_order, Wbase_claim_base... expd_itms) {
Json_doc jdoc = json_parser.Parse_by_apos(raw);
Json_ary owner = Json_ary.cast_or_null(Json_kv.cast(jdoc.Root_nde().Get_at(0)).Val());
Json_ary owner = Json_ary.cast_or_null(Json_kv.Cast(jdoc.Root_nde().Get_at(0)).Val());
Wbase_references_grp[] actl = wdoc_parser.Parse_references(Q1_bry, owner);
Wbase_references_grp actl_grp = actl[0];
Tfds.Eq_ary(expd_order, actl_grp.Snaks_order());
@ -114,7 +114,7 @@ abstract class Wdata_doc_parser_fxt_base {
}
public void Test_pid_order(String raw, int... expd) {
Json_doc jdoc = json_parser.Parse_by_apos(raw);
Json_ary nde = Json_ary.cast_or_null(Json_kv.cast(jdoc.Root_nde().Get_at(0)).Val());
Json_ary nde = Json_ary.cast_or_null(Json_kv.Cast(jdoc.Root_nde().Get_at(0)).Val());
int[] actl = wdoc_parser.Parse_pid_order(Q1_bry, nde);
Tfds.Eq_ary(expd, actl);
}
@ -131,7 +131,7 @@ abstract class Wdata_doc_parser_fxt_base {
}
return (Wbase_claim_base[])rv.To_ary_and_clear(Wbase_claim_base.class);
}
private static final byte[] Q1_bry = Bry_.new_a7("Q1");
private static final byte[] Q1_bry = Bry_.new_a7("Q1");
}
class Wdata_doc_parser_v2_fxt extends Wdata_doc_parser_fxt_base {
@Override public Wdata_doc_parser Make_parser() {return new Wdata_doc_parser_v2();}

@ -1,19 +1,19 @@
/*
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.wbases.parsers; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.wbases.*;
/*
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.wbases.parsers; import gplx.*;
import gplx.core.primitives.*; import gplx.langs.jsons.*;
import gplx.xowa.xtns.wbases.core.*; import gplx.xowa.xtns.wbases.claims.*; import gplx.xowa.xtns.wbases.claims.enums.*; import gplx.xowa.xtns.wbases.claims.itms.*;
public class Wdata_doc_parser_v1 implements Wdata_doc_parser {
@ -36,18 +36,18 @@ public class Wdata_doc_parser_v1 implements Wdata_doc_parser {
}
public Ordered_hash Parse_sitelinks(byte[] qid, Json_doc doc) {
try {
Json_nde list_nde = Json_nde.cast(doc.Get_grp(Bry_links)); if (list_nde == null) return Wdata_doc_parser_v1.Empty_ordered_hash_bry;
Json_nde list_nde = Json_nde.Cast(doc.Get_grp(Bry_links)); if (list_nde == null) return Wdata_doc_parser_v1.Empty_ordered_hash_bry;
Ordered_hash rv = Ordered_hash_.New_bry();
int list_len = list_nde.Len();
for (int i = 0; i < list_len; ++i) {
Json_kv wiki_kv = Json_kv.cast(list_nde.Get_at(i));
Json_kv wiki_kv = Json_kv.Cast(list_nde.Get_at(i));
byte[] site_bry = wiki_kv.Key().Data_bry();
byte[] title_bry = null; byte[][] badges_bry_ary = null;
if (wiki_kv.Val().Tid() == Json_itm_.Tid__nde) { // v1.2: "enwiki":{name:"Earth", badges:[]}
Json_nde val_nde = Json_nde.cast(wiki_kv.Val());
Json_kv name_kv = Json_kv.cast(val_nde.Get_at(0));
Json_nde val_nde = Json_nde.Cast(wiki_kv.Val());
Json_kv name_kv = Json_kv.Cast(val_nde.Get_at(0));
title_bry = name_kv.Val().Data_bry();
Json_kv badges_kv = Json_kv.cast(val_nde.Get_at(1));
Json_kv badges_kv = Json_kv.Cast(val_nde.Get_at(1));
if (badges_kv != null) {// TEST:some tests do not define a badges nde; ignore if null; DATE:2014-09-19
Json_ary badges_ary = Json_ary.cast_or_null(badges_kv.Val());
badges_bry_ary = badges_ary.Xto_bry_ary();
@ -65,11 +65,11 @@ public class Wdata_doc_parser_v1 implements Wdata_doc_parser {
public Ordered_hash Parse_langvals(byte[] qid, Json_doc doc, boolean label_or_description) {
try {
byte[] langval_key = label_or_description ? Bry_label : Bry_description;
Json_nde list_nde = Json_nde.cast(doc.Get_grp(langval_key)); if (list_nde == null) return Wdata_doc_parser_v1.Empty_ordered_hash_bry;
Json_nde list_nde = Json_nde.Cast(doc.Get_grp(langval_key)); if (list_nde == null) return Wdata_doc_parser_v1.Empty_ordered_hash_bry;
Ordered_hash rv = Ordered_hash_.New_bry();
int list_len = list_nde.Len();
for (int i = 0; i < list_len; ++i) {
Json_kv data_kv = Json_kv.cast(list_nde.Get_at(i));
Json_kv data_kv = Json_kv.Cast(list_nde.Get_at(i));
byte[] lang_bry = data_kv.Key().Data_bry();
Wdata_langtext_itm itm = new Wdata_langtext_itm(lang_bry, data_kv.Val().Data_bry());
rv.Add(lang_bry, itm);
@ -79,11 +79,11 @@ public class Wdata_doc_parser_v1 implements Wdata_doc_parser {
}
public Ordered_hash Parse_aliases(byte[] qid, Json_doc doc) {
try {
Json_nde list_nde = Json_nde.cast(doc.Get_grp(Bry_aliases)); if (list_nde == null) return Wdata_doc_parser_v1.Empty_ordered_hash_bry;
Json_nde list_nde = Json_nde.Cast(doc.Get_grp(Bry_aliases)); if (list_nde == null) return Wdata_doc_parser_v1.Empty_ordered_hash_bry;
Ordered_hash rv = Ordered_hash_.New_bry();
int list_len = list_nde.Len();
for (int i = 0; i < list_len; ++i) {
Json_kv data_kv = Json_kv.cast(list_nde.Get_at(i));
Json_kv data_kv = Json_kv.Cast(list_nde.Get_at(i));
byte[] lang_bry = data_kv.Key().Data_bry();
byte[][] vals_bry_ary = null;
Json_itm data_val = data_kv.Val();
@ -93,11 +93,11 @@ public class Wdata_doc_parser_v1 implements Wdata_doc_parser {
vals_bry_ary = vals_ary.Xto_bry_ary();
break;
case Json_itm_.Tid__nde: // EX: 'en':{'0:en_val_1','1:en_val_2'}; PAGE:wd.q:621080 DATE:2014-09-21
Json_nde vals_nde = Json_nde.cast(data_val);
Json_nde vals_nde = Json_nde.Cast(data_val);
int vals_len = vals_nde.Len();
vals_bry_ary = new byte[vals_len][];
for (int j = 0; j < vals_len; ++j) {
Json_kv vals_sub_kv = Json_kv.cast(vals_nde.Get_at(j));
Json_kv vals_sub_kv = Json_kv.Cast(vals_nde.Get_at(j));
vals_bry_ary[j] = vals_sub_kv.Val().Data_bry();
}
break;
@ -116,7 +116,7 @@ public class Wdata_doc_parser_v1 implements Wdata_doc_parser {
byte[] src = doc.Src();
int len = list_nde.Len();
for (int i = 0; i < len; i++) {
Json_nde claim_nde = Json_nde.cast(list_nde.Get_at(i));
Json_nde claim_nde = Json_nde.Cast(list_nde.Get_at(i));
Wbase_claim_base claim_itm = Make_claim_itm(src, claim_nde);
temp_list.Add(claim_itm);
}
@ -150,10 +150,10 @@ public class Wdata_doc_parser_v1 implements Wdata_doc_parser {
int len = prop_nde.Len(); // should have 5 (m, q, g, rank, refs), but don't enforce (can rely on keys)
Wbase_claim_base rv = null;
for (int i = 0; i < len; i++) {
Json_kv kv = Json_kv.cast(prop_nde.Get_at(i));
Json_kv kv = Json_kv.Cast(prop_nde.Get_at(i));
Json_itm kv_key = kv.Key();
Byte_obj_val bv = (Byte_obj_val)Prop_key_hash.Get_by_mid(src, kv_key.Src_bgn(), kv_key.Src_end());
if (bv == null) {Warn("invalid prop node: ~{0}", String_.new_u8(src, kv_key.Src_bgn(), kv_key.Src_end())); return null;}
Byte_obj_val bv = (Byte_obj_val)Prop_key_hash.Get_by_bry(kv_key.Data_bry());
if (bv == null) {Warn("invalid prop node: ~{0}", String_.new_u8(kv_key.Data_bry())); return null;}
switch (bv.Val()) {
case Prop_tid_m:
rv = New_prop_by_m(src, Json_ary.cast_or_null(kv.Val()));
@ -176,13 +176,13 @@ public class Wdata_doc_parser_v1 implements Wdata_doc_parser {
}
private Wbase_claim_base New_prop_by_m(byte[] src, Json_ary ary) {
byte snak_tid = Wbase_claim_value_type_.Reg.Get_tid_or_fail(ary.Get_at(0).Data_bry());
int pid = Json_itm_int.cast(ary.Get_at(1)).Data_as_int();
int pid = Json_itm_int.Cast(ary.Get_at(1)).Data_as_int();
switch (snak_tid) {
case Wbase_claim_value_type_.Tid__novalue : return Wbase_claim_value.New_novalue(pid);
case Wbase_claim_value_type_.Tid__somevalue : return Wbase_claim_value.New_somevalue(pid);
}
Json_itm val_tid_itm = ary.Get_at(2);
byte val_tid = Wbase_claim_type_.Get_tid_or_unknown(src, val_tid_itm.Src_bgn(), val_tid_itm.Src_end());
byte val_tid = Wbase_claim_type_.Get_tid_or_unknown(val_tid_itm.Data_bry());
return Make_itm(pid, snak_tid, val_tid, ary);
}
private Wbase_claim_base Make_itm(int pid, byte snak_tid, byte val_tid, Json_ary ary) {
@ -190,31 +190,31 @@ public class Wdata_doc_parser_v1 implements Wdata_doc_parser {
case Wbase_claim_type_.Tid__string:
return new Wbase_claim_string(pid, snak_tid, ary.Get_at(3).Data_bry());
case Wbase_claim_type_.Tid__entity: {
Json_nde sub_nde = Json_nde.cast(ary.Get_at(3));
Json_kv entity_kv = Json_kv.cast(sub_nde.Get_at(1));
Json_nde sub_nde = Json_nde.Cast(ary.Get_at(3));
Json_kv entity_kv = Json_kv.Cast(sub_nde.Get_at(1));
return new Wbase_claim_entity(pid, snak_tid, Wbase_claim_entity_type_.Tid__item, entity_kv.Val().Data_bry());
}
case Wbase_claim_type_.Tid__time: {
Json_nde sub_nde = Json_nde.cast(ary.Get_at(3));
Json_nde sub_nde = Json_nde.Cast(ary.Get_at(3));
return new Wbase_claim_time(pid, snak_tid, Get_val(sub_nde, 0), Get_val(sub_nde, 1), Get_val(sub_nde, 2), Get_val(sub_nde, 3), Get_val(sub_nde, 4), Get_val(sub_nde, 5));
}
case Wbase_claim_type_.Tid__globecoordinate: case Wbase_claim_type_.Tid__bad: {
Json_nde sub_nde = Json_nde.cast(ary.Get_at(3));
Json_nde sub_nde = Json_nde.Cast(ary.Get_at(3));
return new Wbase_claim_globecoordinate(pid, snak_tid, Get_val(sub_nde, 0), Get_val(sub_nde, 1), Get_val(sub_nde, 2), Get_val(sub_nde, 3), Get_val(sub_nde, 4));
}
case Wbase_claim_type_.Tid__quantity: {
Json_nde sub_nde = Json_nde.cast(ary.Get_at(3));
Json_nde sub_nde = Json_nde.Cast(ary.Get_at(3));
return new Wbase_claim_quantity(pid, snak_tid, Get_val(sub_nde, 0), Get_val(sub_nde, 1), Get_val(sub_nde, 2), Get_val(sub_nde, 3));
}
case Wbase_claim_type_.Tid__monolingualtext: {
Json_nde sub_nde = Json_nde.cast(ary.Get_at(3));
Json_nde sub_nde = Json_nde.Cast(ary.Get_at(3));
return new Wbase_claim_monolingualtext(pid, snak_tid, Get_val(sub_nde, 1), Get_val(sub_nde, 0));
}
default: {throw Err_.new_unhandled(val_tid);}
}
}
private static byte[] Get_val(Json_nde sub_nde, int i) {
Json_kv kv = Json_kv.cast(sub_nde.Get_at(i));
Json_kv kv = Json_kv.Cast(sub_nde.Get_at(i));
return kv.Val().Data_bry();
}
private void Warn(String fmt, Object... args) {usr_dlg.Warn_many("", "", fmt, args);}
@ -227,11 +227,11 @@ public class Wdata_doc_parser_v1 implements Wdata_doc_parser {
.Add_bry_byte(Wdata_dict_claim_v1.Bry_rank , Prop_tid_rank)
.Add_bry_byte(Wdata_dict_claim_v1.Bry_refs , Prop_tid_refs);
Ordered_hash Bld_hash(Json_doc doc, byte[] key) {
Json_nde nde = Json_nde.cast(doc.Get_grp(key)); if (nde == null) return Empty_ordered_hash_bry;
Json_nde nde = Json_nde.Cast(doc.Get_grp(key)); if (nde == null) return Empty_ordered_hash_bry;
Ordered_hash rv = Ordered_hash_.New_bry();
int len = nde.Len();
for (int i = 0; i < len; i++) {
Json_kv kv = Json_kv.cast(nde.Get_at(i));
Json_kv kv = Json_kv.Cast(nde.Get_at(i));
byte[] kv_key = kv.Key().Data_bry();
rv.Add(kv_key, kv);
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 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.
@ -13,133 +13,154 @@ 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.wbases.parsers; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.wbases.*;
import gplx.langs.jsons.*; import gplx.core.btries.*;
import gplx.xowa.xtns.wbases.core.*; import gplx.xowa.xtns.wbases.claims.*; import gplx.xowa.xtns.wbases.claims.enums.*; import gplx.xowa.xtns.wbases.claims.itms.*;
public class Wdata_doc_parser_v2 implements Wdata_doc_parser {
private Wdata_claims_parser_v2 claims_parser = new Wdata_claims_parser_v2();
public byte[] Parse_qid(Json_doc doc) {
try {
Json_itm itm = doc.Find_nde(Bry_id);
return Bry_.Lcase__1st(itm.Data_bry()); // standardize on "q" instead of "Q" for compatibility with v1
} catch (Exception e) {throw Err_.new_exc(e, "xo", "failed to parse qid", "src", String_.new_u8(doc.Src()));}
}
public Ordered_hash Parse_sitelinks(byte[] qid, Json_doc doc) {
try {
Json_nde list_nde = Json_nde.cast(doc.Get_grp(Bry_sitelinks)); if (list_nde == null) return Wdata_doc_parser_v1.Empty_ordered_hash_bry;
Ordered_hash rv = Ordered_hash_.New_bry();
int list_len = list_nde.Len();
for (int i = 0; i < list_len; ++i) {
Json_kv data_kv = Json_kv.cast(list_nde.Get_at(i));
Json_nde data_nde = Json_nde.cast(data_kv.Val());
int data_nde_len = data_nde.Len();
Json_kv site_kv = null, name_kv = null; Json_ary badges_ary = null;
for (int j = 0; j < data_nde_len; ++j) {
Json_kv sub = Json_kv.cast(data_nde.Get_at(j));
byte tid = Wdata_dict_sitelink.Reg.Get_tid_or_max_and_log(qid, sub.Key().Data_bry()); if (tid == Byte_.Max_value_127) continue;
switch (tid) {
case Wdata_dict_sitelink.Tid__site: site_kv = Json_kv.cast(sub); break;
case Wdata_dict_sitelink.Tid__title: name_kv = Json_kv.cast(sub); break;
case Wdata_dict_sitelink.Tid__badges: badges_ary = Json_ary.cast_or_null(Json_kv.cast(sub).Val()); break;
}
}
byte[] site_bry = site_kv.Val().Data_bry();
Wdata_sitelink_itm itm = new Wdata_sitelink_itm(site_bry, name_kv.Val().Data_bry(), badges_ary.Xto_bry_ary());
rv.Add(site_bry, itm);
}
return rv;
} catch (Exception e) {throw Err_.new_exc(e, "xo", "failed to parse sitelinks", "qid", String_.new_u8(qid));}
}
public Ordered_hash Parse_langvals(byte[] qid, Json_doc doc, boolean label_or_description) {
try {
byte[] langval_key = label_or_description ? Bry_labels : Bry_descriptions;
Json_nde list_nde = Json_nde.cast(doc.Get_grp(langval_key)); if (list_nde == null) return Wdata_doc_parser_v1.Empty_ordered_hash_bry;
Ordered_hash rv = Ordered_hash_.New_bry();
int list_len = list_nde.Len();
for (int i = 0; i < list_len; ++i) {
Json_kv data_kv = Json_kv.cast(list_nde.Get_at(i));
Json_nde data_nde = Json_nde.cast(data_kv.Val());
Json_kv text_kv = null;
int data_nde_len = data_nde.Len();
for (int j = 0; j < data_nde_len; ++j) {
Json_kv sub = Json_kv.cast(data_nde.Get_at(j));
byte tid = Wdata_dict_langtext.Reg.Get_tid_or_max_and_log(qid, sub.Key().Data_bry()); if (tid == Byte_.Max_value_127) continue;
switch (tid) {
case Wdata_dict_langtext.Tid__language: break;
case Wdata_dict_langtext.Tid__value: text_kv = Json_kv.cast(sub); break;
}
}
byte[] lang_bry = data_kv.Key().Data_bry();
Wdata_langtext_itm itm = new Wdata_langtext_itm(lang_bry, text_kv.Val().Data_bry());
rv.Add(lang_bry, itm);
}
return rv;
} catch (Exception e) {throw Err_.new_exc(e, "xo", "failed to parse langvals", "qid", String_.new_u8(qid), "langval_tid", label_or_description);}
}
public Ordered_hash Parse_aliases(byte[] qid, Json_doc doc) {
try {
Json_nde list_nde = Json_nde.cast(doc.Get_grp(Bry_aliases)); if (list_nde == null) return Wdata_doc_parser_v1.Empty_ordered_hash_bry;
Ordered_hash rv = Ordered_hash_.New_bry();
int list_len = list_nde.Len();
for (int i = 0; i < list_len; ++i) {
Json_kv data_kv = Json_kv.cast(list_nde.Get_at(i));
Json_ary vals_ary = Json_ary.cast_or_null(data_kv.Val());
int vals_len = vals_ary.Len();
byte[][] vals = new byte[vals_len][];
for (int j = 0; j < vals_len; ++j) {
Json_nde lang_nde = Json_nde.cast(vals_ary.Get_at(j));
int k_len = lang_nde.Len();
for (int k = 0; k < k_len; ++k) {
Json_kv sub = Json_kv.cast(lang_nde.Get_at(k));
byte tid = Wdata_dict_langtext.Reg.Get_tid_or_max_and_log(qid, sub.Key().Data_bry()); if (tid == Byte_.Max_value_127) continue;
switch (tid) {
case Wdata_dict_langtext.Tid__language: break;
case Wdata_dict_langtext.Tid__value: vals[j] = sub.Val().Data_bry(); break;
}
}
}
byte[] lang_bry = data_kv.Key().Data_bry();
Wdata_alias_itm itm = new Wdata_alias_itm(lang_bry, vals);
rv.Add(lang_bry, itm);
}
return rv;
} catch (Exception e) {throw Err_.new_exc(e, "xo", "failed to parse sitelinks", "qid", String_.new_u8(qid));}
}
public Ordered_hash Parse_claims(byte[] qid, Json_doc doc) {
synchronized (this) {// TS; DATE:2016-07-06
try {
Json_nde list_nde = Json_nde.cast(doc.Get_grp(Bry_claims)); if (list_nde == null) return Wdata_doc_parser_v1.Empty_ordered_hash_generic;
List_adp temp_list = List_adp_.New();
byte[] src = doc.Src();
int len = list_nde.Len();
for (int i = 0; i < len; i++) {
Json_kv claim_nde = Json_kv.cast(list_nde.Get_at(i));
claims_parser.Make_claim_itms(qid, temp_list, src, claim_nde);
}
return Wdata_doc_parser_v1.Claims_list_to_hash(temp_list);
} catch (Exception e) {throw Err_.new_exc(e, "xo", "failed to parse claims", "qid", String_.new_u8(doc.Src()));}
}
}
public Wbase_claim_base Parse_claims_data(byte[] qid, int pid, byte snak_tid, Json_nde nde) {return claims_parser.Parse_datavalue(qid, pid, snak_tid, nde);}
public Wbase_claim_grp_list Parse_qualifiers(byte[] qid, Json_nde nde) {return claims_parser.Parse_qualifiers(qid, nde);}
public Wbase_references_grp[] Parse_references(byte[] qid, Json_ary owner) {return claims_parser.Parse_references(qid, owner);}
public int[] Parse_pid_order(byte[] qid, Json_ary ary) {return claims_parser.Parse_pid_order(ary);}
public static final String
Str_id = "id"
, Str_sitelinks = "sitelinks"
, Str_labels = "labels"
, Str_descriptions = "descriptions"
, Str_aliases = "aliases"
, Str_claims = "claims"
, Str_type = "type"
;
public static final byte[]
Bry_id = Bry_.new_a7(Str_id)
, Bry_sitelinks = Bry_.new_a7(Str_sitelinks)
, Bry_labels = Bry_.new_a7(Str_labels)
, Bry_descriptions = Bry_.new_a7(Str_descriptions)
, Bry_aliases = Bry_.new_a7(Str_aliases)
, Bry_claims = Bry_.new_a7(Str_claims)
, Bry_type = Bry_.new_a7(Str_type)
;
}
package gplx.xowa.xtns.wbases.parsers;
import gplx.Bry_;
import gplx.Byte_;
import gplx.Err_;
import gplx.List_adp;
import gplx.List_adp_;
import gplx.Ordered_hash;
import gplx.Ordered_hash_;
import gplx.String_;
import gplx.langs.jsons.Json_ary;
import gplx.langs.jsons.Json_doc;
import gplx.langs.jsons.Json_itm;
import gplx.langs.jsons.Json_kv;
import gplx.langs.jsons.Json_nde;
import gplx.xowa.xtns.wbases.claims.Wbase_claim_grp_list;
import gplx.xowa.xtns.wbases.claims.Wbase_references_grp;
import gplx.xowa.xtns.wbases.claims.itms.Wbase_claim_base;
import gplx.xowa.xtns.wbases.core.Wdata_alias_itm;
import gplx.xowa.xtns.wbases.core.Wdata_dict_langtext;
import gplx.xowa.xtns.wbases.core.Wdata_dict_sitelink;
import gplx.xowa.xtns.wbases.core.Wdata_langtext_itm;
import gplx.xowa.xtns.wbases.core.Wdata_sitelink_itm;
public class Wdata_doc_parser_v2 implements Wdata_doc_parser {
private Wdata_claims_parser_v2 claims_parser = new Wdata_claims_parser_v2();
public byte[] Parse_qid(Json_doc doc) {
try {
Json_itm itm = doc.Find_nde(Bry_id);
return Bry_.Lcase__1st(itm.Data_bry()); // standardize on "q" instead of "Q" for compatibility with v1
} catch (Exception e) {throw Err_.new_exc(e, "xo", "failed to parse qid", "src", String_.new_u8(doc.Src()));}
}
public Ordered_hash Parse_sitelinks(byte[] qid, Json_doc doc) {
try {
Json_nde list_nde = Json_nde.Cast(doc.Get_grp(Bry_sitelinks)); if (list_nde == null) return Wdata_doc_parser_v1.Empty_ordered_hash_bry;
Ordered_hash rv = Ordered_hash_.New_bry();
int list_len = list_nde.Len();
for (int i = 0; i < list_len; ++i) {
Json_kv data_kv = Json_kv.Cast(list_nde.Get_at(i));
Json_nde data_nde = Json_nde.Cast(data_kv.Val());
int data_nde_len = data_nde.Len();
Json_kv site_kv = null, name_kv = null; Json_ary badges_ary = null;
for (int j = 0; j < data_nde_len; ++j) {
Json_kv sub = Json_kv.Cast(data_nde.Get_at(j));
byte tid = Wdata_dict_sitelink.Reg.Get_tid_or_max_and_log(qid, sub.Key().Data_bry()); if (tid == Byte_.Max_value_127) continue;
switch (tid) {
case Wdata_dict_sitelink.Tid__site: site_kv = Json_kv.Cast(sub); break;
case Wdata_dict_sitelink.Tid__title: name_kv = Json_kv.Cast(sub); break;
case Wdata_dict_sitelink.Tid__badges: badges_ary = Json_ary.cast_or_null(Json_kv.Cast(sub).Val()); break;
}
}
byte[] site_bry = site_kv.Val().Data_bry();
Wdata_sitelink_itm itm = new Wdata_sitelink_itm(site_bry, name_kv.Val().Data_bry(), badges_ary.Xto_bry_ary());
rv.Add(site_bry, itm);
}
return rv;
} catch (Exception e) {throw Err_.new_exc(e, "xo", "failed to parse sitelinks", "qid", String_.new_u8(qid));}
}
public Ordered_hash Parse_langvals(byte[] qid, Json_doc doc, boolean label_or_description) {
try {
byte[] langval_key = label_or_description ? Bry_labels : Bry_descriptions;
Json_nde list_nde = Json_nde.Cast(doc.Get_grp(langval_key)); if (list_nde == null) return Wdata_doc_parser_v1.Empty_ordered_hash_bry;
Ordered_hash rv = Ordered_hash_.New_bry();
int list_len = list_nde.Len();
for (int i = 0; i < list_len; ++i) {
Json_kv data_kv = Json_kv.Cast(list_nde.Get_at(i));
Json_nde data_nde = Json_nde.Cast(data_kv.Val());
Json_kv text_kv = null;
int data_nde_len = data_nde.Len();
for (int j = 0; j < data_nde_len; ++j) {
Json_kv sub = Json_kv.Cast(data_nde.Get_at(j));
byte tid = Wdata_dict_langtext.Reg.Get_tid_or_max_and_log(qid, sub.Key().Data_bry()); if (tid == Byte_.Max_value_127) continue;
switch (tid) {
case Wdata_dict_langtext.Tid__language: break;
case Wdata_dict_langtext.Tid__value: text_kv = Json_kv.Cast(sub); break;
}
}
byte[] lang_bry = data_kv.Key().Data_bry();
Wdata_langtext_itm itm = new Wdata_langtext_itm(lang_bry, text_kv.Val().Data_bry());
rv.Add(lang_bry, itm);
}
return rv;
} catch (Exception e) {throw Err_.new_exc(e, "xo", "failed to parse langvals", "qid", String_.new_u8(qid), "langval_tid", label_or_description);}
}
public Ordered_hash Parse_aliases(byte[] qid, Json_doc doc) {
try {
Json_nde list_nde = Json_nde.Cast(doc.Get_grp(Bry_aliases)); if (list_nde == null) return Wdata_doc_parser_v1.Empty_ordered_hash_bry;
Ordered_hash rv = Ordered_hash_.New_bry();
int list_len = list_nde.Len();
for (int i = 0; i < list_len; ++i) {
Json_kv data_kv = Json_kv.Cast(list_nde.Get_at(i));
Json_ary vals_ary = Json_ary.cast_or_null(data_kv.Val());
int vals_len = vals_ary.Len();
byte[][] vals = new byte[vals_len][];
for (int j = 0; j < vals_len; ++j) {
Json_nde lang_nde = Json_nde.Cast(vals_ary.Get_at(j));
int k_len = lang_nde.Len();
for (int k = 0; k < k_len; ++k) {
Json_kv sub = Json_kv.Cast(lang_nde.Get_at(k));
byte tid = Wdata_dict_langtext.Reg.Get_tid_or_max_and_log(qid, sub.Key().Data_bry()); if (tid == Byte_.Max_value_127) continue;
switch (tid) {
case Wdata_dict_langtext.Tid__language: break;
case Wdata_dict_langtext.Tid__value: vals[j] = sub.Val().Data_bry(); break;
}
}
}
byte[] lang_bry = data_kv.Key().Data_bry();
Wdata_alias_itm itm = new Wdata_alias_itm(lang_bry, vals);
rv.Add(lang_bry, itm);
}
return rv;
} catch (Exception e) {throw Err_.new_exc(e, "xo", "failed to parse sitelinks", "qid", String_.new_u8(qid));}
}
public Ordered_hash Parse_claims(byte[] qid, Json_doc doc) {
synchronized (this) {// TS; DATE:2016-07-06
try {
Json_nde list_nde = Json_nde.Cast(doc.Get_grp(Bry_claims)); if (list_nde == null) return Wdata_doc_parser_v1.Empty_ordered_hash_generic;
List_adp temp_list = List_adp_.New();
byte[] src = doc.Src();
int len = list_nde.Len();
for (int i = 0; i < len; i++) {
Json_kv claim_nde = Json_kv.Cast(list_nde.Get_at(i));
claims_parser.Make_claim_itms(qid, temp_list, src, claim_nde);
}
return Wdata_doc_parser_v1.Claims_list_to_hash(temp_list);
} catch (Exception e) {throw Err_.new_exc(e, "xo", "failed to parse claims", "qid", String_.new_u8(doc.Src()));}
}
}
public Wbase_claim_base Parse_claims_data(byte[] qid, int pid, byte snak_tid, Json_nde nde) {return claims_parser.Parse_datavalue(qid, pid, snak_tid, nde);}
public Wbase_claim_grp_list Parse_qualifiers(byte[] qid, Json_nde nde) {return claims_parser.Parse_qualifiers(qid, nde);}
public Wbase_references_grp[] Parse_references(byte[] qid, Json_ary owner) {return claims_parser.Parse_references(qid, owner);}
public int[] Parse_pid_order(byte[] qid, Json_ary ary) {return claims_parser.Parse_pid_order(ary);}
public static final String
Str_id = "id"
, Str_sitelinks = "sitelinks"
, Str_labels = "labels"
, Str_descriptions = "descriptions"
, Str_aliases = "aliases"
, Str_claims = "claims"
, Str_type = "type"
;
public static final byte[]
Bry_id = Bry_.new_a7(Str_id)
, Bry_sitelinks = Bry_.new_a7(Str_sitelinks)
, Bry_labels = Bry_.new_a7(Str_labels)
, Bry_descriptions = Bry_.new_a7(Str_descriptions)
, Bry_aliases = Bry_.new_a7(Str_aliases)
, Bry_claims = Bry_.new_a7(Str_claims)
, Bry_type = Bry_.new_a7(Str_type)
;
}

@ -0,0 +1,47 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2020 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.langs.jsons;
import gplx.Bry_bfr;
import gplx.Bry_bfr_;
import gplx.core.tests.Gftest;
import org.junit.Test;
public class JsonDocBldrTest {
private JsonDocBldrTestUtil util = new JsonDocBldrTestUtil();
@Test public void Basic() {
JsonDocBldr bldr = JsonDocBldr.NewRootNde();
bldr.NdeBgn("nde")
.KvBool("bool", true)
.KvInt("int", 123)
.KvStr("str", "abc")
.NdeEnd();
util.Test(bldr
, "{ 'nde':"
, " { 'bool':true"
, " , 'int':123"
, " , 'str':'abc'"
, " }"
, "}");
}
}
class JsonDocBldrTestUtil {
public void Test(JsonDocBldr bldr, String... ary) {
Bry_bfr bfr = Bry_bfr_.New();
bldr.ToDoc().Root_grp().Print_as_json(bfr, 0);
Gftest.Eq__ary__lines(Json_doc.Make_str_by_apos(ary), bfr.To_str_and_clear());
}
}

@ -0,0 +1,71 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2020 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.langs.mustaches;
import gplx.Bry_;
import gplx.Bry_bfr_;
import gplx.core.tests.Gftest;
import gplx.langs.jsons.Json_doc;
import gplx.langs.jsons.Json_parser;
import org.junit.Test;
public class JsonMustacheNdeTest {
private JsonMustacheNdeTestUtil util = new JsonMustacheNdeTestUtil();
@Test public void Str() {
util.TestWrite("[{{key}}]", "{'key':'abc'}", "[abc]");
}
@Test public void Bool() {
String mustache = "[{{#key}}y{{/key}}]";
util.TestWrite(mustache, "{'key':true}", "[y]");
util.TestWrite(mustache, "{'key':false}", "[]");
}
@Test public void Ary() {
String mustache = "[{{#group}}{{key}} {{/group}}]";
util.TestWrite(mustache, "{'group':[{'key':'a'}, {'key':'b'}, {'key':'c'}]}", "[a b c ]");
}
@Test public void SectionPropWithDot() {
String mustache = "[{{#key}}{{.}}{{/key}}]";
util.TestWrite(mustache, "{'key':'test'}", "[test]");
util.TestWrite(mustache, "{'key1':'test'}", "[]");
}
@Test public void SectionPropWithoutDot() {
String mustache = "[{{#prop}}{{propx}}{{/prop}}]";
util.TestWrite(mustache, "{'prop':'test'}", "[]");
util.TestWrite(mustache, "{'propx':'test'}", "[]");
}
@Test public void Dot() {// NOTE: online demo gives `([object Object])`; https://mustache.github.io/#demo
String mustache = "({{.}})";
util.TestWrite(mustache, "{'key':'test'}", "()");
}
}
class JsonMustacheNdeTestUtil {
public void TestWrite(String mustache, String json, String expd) {
// parse JSON to mustache itm
Json_doc jdoc = Json_parser.ParseToJdoc(Json_doc.Make_str_by_apos(json));
JsonMustacheNde nde = new JsonMustacheNde(jdoc.Root_nde());
// parse template
Mustache_tkn_itm actl_itm = new Mustache_tkn_parser().Parse(Bry_.new_u8(mustache));
// render
Mustache_bfr bfr = new Mustache_bfr(Bry_bfr_.New());
actl_itm.Render(bfr, new Mustache_render_ctx().Init(nde));
// test
Gftest.Eq__ary__lines(expd, bfr.To_str_and_clear());
}
}

@ -140,10 +140,14 @@ app.wikis.get('~{wiki_key}') {
app.wikis.get('~{wiki_key}').html.portal {
div_personal =
<:["
<div id="p-personal" class="">
<h3>~{<>msgs.get('personaltools');<>}</h3>
<nav id="p-personal" class="vector-menu" aria-labelledby="p-personal-label" role="navigation">
<h3 id="p-personal-label">
<span>~{<>app.user.msgs.get('personaltools');<>}</span>
</h3>
<div class="body vector-menu-content">
~{portal_indicators_pagesource}
</div>
</div>
</nav>
"]:>
;
div_ns =
@ -178,7 +182,7 @@ app.wikis.get('~{wiki_key}').html.portal {
<input type="search" name="search" placeholder="~{<>msgs.get('searchbutton');<>} ~{sitename}" id="searchInput"~{<>msgs.get_html_accesskey_and_title('search');<>} value="~{search_text}" autocomplete="off">
<input type="hidden" name="fulltext" value="y">
<input type="submit"~{<>msgs.get_html_accesskey_and_title('search');<>} id="mw-searchButton" class="searchButton mw-fallbackSearchButton" />
<input type="submit" name="go" value="~{<>msgs.get('go');<>}" title="~{<>msgs.get('tooltip-search-go');<>}" id="searchButton" class="searchButton" />
<input type="submit" name="go" value="~{<>msgs.get('go');<>}" title="~{<>msgs.get('tooltip-search-go');<>}" id="searchButton" class="searchButton" />
</div>
</form>
</li>
@ -195,8 +199,10 @@ app.wikis.get('~{wiki_key}').html.portal {
;
div_home =
<:["
<div class="portal" id='xowa-portal-home'>
<h3>XOWA</h3>
<nav id="xowa-portal-home" class="vector-menu vector-menu-portal portal" aria-labelledby="xowa-portal-home" role="navigation">
<h3>
<span>XOWA</span>
</h3>
<div class="body">
<ul>
<li><a href="/site/home/wiki/Main_Page" class='xowa-hover-off'>~{<>app.user.msgs.get('mainpage-description');<>}</a></li>
@ -209,32 +215,36 @@ app.wikis.get('~{wiki_key}').html.portal {
<li><a href="/site/home/wiki/Special:XowaCfg" class='xowa-hover-off'~{<>app.user.msgs.get_html_accesskey_and_title('xowa-portal-options');<>}>~{<>app.user.msgs.get('xowa-portal-options');<>}</a></li>
</ul>
</div>
</div>
</nav>
"]:>
;
div_sync =
<:["
<div id="xowa-portal-sync" class="portal">
<h3>~{<>app.user.msgs.get('xowa-portal-sync');<>}</h3>
<nav id="xowa-portal-sync" class="vector-menu vector-menu-portal portal" aria-labelledby="xowa-portal-sync" role="navigation">
<h3>
<span>~{<>app.user.msgs.get('xowa-portal-sync');<>}</span>
</h3>
<div class="body">
<ul>
<li><a href="/wiki/Special:XowaSyncHtml?page=~{page_url}" class='xowa-hover-off'~{<>app.user.msgs.get_html_accesskey_and_title('xowa-portal-sync_html');<>}>~{<>app.user.msgs.get('xowa-portal-sync_html');<>}</a></li>
</ul>
</div>
</div>
</nav>
<!--
-->
"]:>
;
div_wikis =
<:["
<div id="xowa-portal-wikis" class="portal">
<h3>~{toggle_btn}</h3>
<div class="body">
<nav id="xowa-portal-wikis" class="vector-menu vector-menu-portal portal" aria-labelledby="xowa-portal-wikis" role="navigation">
<h3 id="p-wiki">
<span>~{toggle_btn}</span>
</h3>
<div class="body vector-menu-content">
<ul~{toggle_hdr}>~{<>app.gui.html.portal.wikis.itms_as_html;<>}
</ul>
</div>
</div>
</nav>
"]:>
;
}
@ -254,12 +264,12 @@ app.wikis.get('~{wiki_key}').html.article {
<link rel="stylesheet" href="~{app_root_dir}bin/any/xowa/html/res/src/xowa/find/xowa_find_html.css" type="text/css">
<script src="~{app_root_dir}bin/any/xowa/html/res/src/xowa/find/xowa_find_html.js" type='text/javascript'></script>
<style type="text/css">
div#simpleSearch #searchButton,
div#simpleSearch #searchButton,
div#simpleSearch #mw-searchButton {
~{<>lang.x_axis_end;<>}: 0;
direction: ~{<>lang.dir_str;<>};
z-index:initial; /* reset z-index, else will show in front of popup; DATE:2015-07-31 */
}
}
.new {!important; color:green;}
</style>
</head>
@ -267,7 +277,7 @@ app.wikis.get('~{wiki_key}').html.article {
<div id="mw-page-base" class="noprint"></div>
<div id="mw-head-base" class="noprint"></div>
<div id="content" class="mw-body">~{page_indicators}~{page_pgbnr}
<div id='xowa_err_div' class='xowa_err' style='display:none; color:red; white-space:pre; display:block; unicode-bidi:embed;'></div>~{page_heading}
<div id='xowa_err_div' class='xowa_err' style='display:none; color:red; white-space:pre; display:block; unicode-bidi:embed;'></div>~{page_heading}
<div id="bodyContent" class="mw-body-content">
<div id="siteSub">From XOWA: the free, open-source, offline wiki application</div>
<div id="contentSub" class="visible">
@ -321,7 +331,7 @@ app.wikis.get('~{wiki_key}').html.article {
~{html_css_night_tag}<!--XOWA.SCRIPT.HEAD.TOP-->~{xowa_head}<!--XOWA.SCRIPT.HEAD.BOT-->
<script src="~{app_root_dir}bin/any/xowa/html/res/src/xowa/edit-toolbar/edit-toolbar.js" type='text/javascript'></script>
<style type="text/css">
div#simpleSearch #searchButton,
div#simpleSearch #searchButton,
div#simpleSearch #mw-searchButton {
~{<>lang.x_axis_end;<>}: 0;
direction: ~{<>lang.dir_str;<>};
@ -347,7 +357,7 @@ app.wikis.get('~{wiki_key}').html.article {
<div id="mw-page-base" class="noprint"></div>
<div id="mw-head-base" class="noprint"></div>
<div id="content" class="mw-body">~{page_indicators}~{page_pgbnr}
<div id='xowa_err_div' class='xowa_err'></div>~{page_heading}
<div id='xowa_err_div' class='xowa_err'></div>~{page_heading}
<div id="bodyContent" class="mw-body-content">
<div id="siteSub">From XOWA: the free, open-source, offline wiki application</div>
<div id="contentSub" class="visible">~{page_content_sub}</div>
@ -362,7 +372,7 @@ app.wikis.get('~{wiki_key}').html.article {
<a href="/wiki/Special:XowaPageDelete?delete=~{page_ttl_full}" onclick="return confirm('Please confirm you wish to delete this page.')" class="xowa_anchor_button" style="width:100px;max-width:1024px;">Delete page</a>
<a href="/wiki/~{page_ttl_full}" class="xowa_anchor_button" style="width:100px;max-width:1024px;">~{<>msgs.get('cancel');<>}</a>
</a>
</div>
</div>
</form>
</div>
</div>
@ -407,7 +417,7 @@ app.wikis.get('~{wiki_key}').html.article {
<link rel="stylesheet" href="~{html_css_wiki_path}" type="text/css">
~{html_css_night_tag}<!--XOWA.SCRIPT.HEAD.TOP-->~{xowa_head}<!--XOWA.SCRIPT.HEAD.BOT-->
<style type="text/css">
div#simpleSearch #searchButton,
div#simpleSearch #searchButton,
div#simpleSearch #mw-searchButton {
~{<>lang.x_axis_end;<>}: 0;
direction: ~{<>lang.dir_str;<>};
@ -472,9 +482,13 @@ app.wikis.scripts.set
app.wikis.get('~{wiki_key}').html.portal
.div_personal_(
<:["
<div id="p-personal" class="">
<h3>~{<>app.user.msgs.get('personaltools');<>}</h3>
</div>
<nav id="p-personal" class="vector-menu" aria-labelledby="p-personal-label" role="navigation">
<h3 id="p-personal-label">
<span>~{<>app.user.msgs.get('personaltools');<>}</span>
</h3>
<div class="body vector-menu-content">
</div>
</nav>
"]:>
)
;

File diff suppressed because it is too large Load Diff

@ -104,6 +104,18 @@ if (!window.xowa) {
},
remove: function () {},
fire: function () {}
} : name === 'wikipage.collapsibleContent' ? {
add: function (f) {
//fc = f;
f(mw.collapsibleContent);
// f(window.jQuery ? $collapsible.find( '> .mw-collapsible-content' ) : null);
},
remove: function () {},
fire: function (t) {
// different order!!!! wrong order HACK
mw.collapsibleContent = t;
//fc(t);
}
} : {
add: function () {},
remove: function () {},

@ -0,0 +1,22 @@
{{!
See @typedef MenuDefinition
}}
{{! `role` is unnecessary but kept to support selectors in any gadgets or user styles. }}
<!-- Please do not use role attribute as CSS selector, it is deprecated. -->
<nav id="{{id}}" {{#class}}class="{{.}}"{{/class}} aria-labelledby="{{label-id}}" role="navigation" {{{html-tooltip}}}
{{{html-user-language-attributes}}}>
{{#is-dropdown}}
<input type="checkbox" class="vector-menu-checkbox vectorMenuCheckbox" aria-labelledby="{{label-id}}" />
{{/is-dropdown}}
<h3 id="{{label-id}}">
<span>{{label}}</span>
</h3>
{{! `body` class for backwards compatibility but let editors know not to use
it via HTML comment below: }}
<!-- Please do not use the .body class, it is deprecated. -->
<div class="body vector-menu-content">
<!-- Please do not use the .menu class, it is deprecated. -->
<ul class="{{list-classes}}">{{{html-items}}}</ul>
{{{html-after-portal}}}
</div>
</nav>

@ -0,0 +1,16 @@
<div id="mw-navigation">
<h2>{{msg-navigation-heading}}</h2>
<div id="mw-head">
{{#data-personal-menu}}{{>Menu}}{{/data-personal-menu}}
<div id="left-navigation">
{{#data-namespace-tabs}}{{>Menu}}{{/data-namespace-tabs}}
{{#data-variants}}{{>Menu}}{{/data-variants}}
</div>
<div id="right-navigation">
{{#data-page-actions}}{{>Menu}}{{/data-page-actions}}
{{#data-page-actions-more}}{{>Menu}}{{/data-page-actions-more}}
{{#data-search-box}}{{>SearchBox}}{{/data-search-box}}
</div>
</div>
{{#data-sidebar}}{{>legacy/Sidebar}}{{/data-sidebar}}
</div>

@ -0,0 +1,13 @@
{{!
See @typedef SidebarData
string html-logo-attributes for site logo. Must be used inside tag e.g. `class="logo" lang="en-gb"`
}}
<div id="mw-panel">
<div id="p-logo" role="banner">
<a {{{html-logo-attributes}}}></a>
</div>
{{#data-portals-first}}{{>Menu}}{{/data-portals-first}}
{{#array-portals-rest}}{{>Menu}}{{/array-portals-rest}}
{{#data-portals-languages}}{{>Menu}}{{/data-portals-languages}}
</div>

@ -0,0 +1,69 @@
{{!
string|null html-site-notice the contents of a banner defined in MediaWiki:Sitenotice.
Also used by CentralNotice to inject banners into Vector.
Indicator[] array-indicators wiki-defined badges such as "good article",
"featured article". An empty array if none are defined.
string page-langcode the content language of the article. Assumed to be escaped HTML.
string html-title
bool page-isarticle
string msg-tagline
string html-subtitle
string html-undelete-link
string html-newtalk
string msg-vector-jumptonavigation
string msg-vector-jumptosearch
string html-body-content
string html-categories
string html-after-content
string msg-navigation-heading heading for entire navigation that is
usually hidden to screen readers
MenuDefinition data-personal-menu
MenuDefinition data-namespace-tabs
MenuDefinition data-variants
MenuDefinition data-page-actions
MenuDefinition data-page-actions-more
object data-search-box. See SearchBox.mustache for documentation.
object data-sidebar. See Sidebar.mustache for documentation.
object data-footer for footer template partial. see Footer.mustache for documentation.
}}
<div id="mw-page-base" class="noprint"></div>
<div id="mw-head-base" class="noprint"></div>
<div id="content" class="mw-body" role="main">
<a id="top"></a>
<div id="siteNotice" class="mw-body-content">{{{html-site-notice}}}</div>
{{>Indicators}}
<h1 id="firstHeading" class="firstHeading" lang="{{page-langcode}}">{{{html-title}}}</h1>
<div id="bodyContent" class="mw-body-content">
{{#page-isarticle}}<div id="siteSub" class="noprint">{{msg-tagline}}</div>{{/page-isarticle}}
<div id="contentSub"{{{html-user-language-attributes}}}>{{{html-subtitle}}}</div>
<div id="contentSub2">{{{html-undelete-link}}}</div>
{{{html-newtalk}}}
{{!
Keep this empty `div` for compatibility with gadgets and user scripts
using this place to insert extra elements before.
}}
<div id="jump-to-nav"></div>
<a class="mw-jump-link" href="#mw-head">{{msg-vector-jumptonavigation}}</a>
<a class="mw-jump-link" href="#searchInput">{{msg-vector-jumptosearch}}</a>
{{{html-body-content}}}
{{{html-categories}}}
</div>
</div>
{{{html-after-content}}}
<div id="mw-navigation">
<h2>{{msg-navigation-heading}}</h2>
<div id="mw-head">
{{#data-personal-menu}}{{>Menu}}{{/data-personal-menu}}
<div id="left-navigation">
{{#data-namespace-tabs}}{{>Menu}}{{/data-namespace-tabs}}
{{#data-variants}}{{>Menu}}{{/data-variants}}
</div>
<div id="right-navigation">
{{#data-page-actions}}{{>Menu}}{{/data-page-actions}}
{{#data-page-actions-more}}{{>Menu}}{{/data-page-actions-more}}
{{#data-search-box}}{{>SearchBox}}{{/data-search-box}}
</div>
</div>
{{#data-sidebar}}{{>legacy/Sidebar}}{{/data-sidebar}}
</div>
{{#data-footer}}{{>Footer}}{{/data-footer}}

@ -1,7 +1,7 @@
<div class="ext-wpb-pagebanner pre-content">
<div class="ext-wpb-pagebanner">
<div class="{{#isPanorama}}wpb-banner-image-panorama {{/isPanorama}}wpb-topbanner{{extraClass}}">
{{#isHeadingOverrideEnabled}}<h1 class="wpb-name">{{title}}</h1>{{/isHeadingOverrideEnabled}}
<a class="image" dir="ltr" title="{{tooltip}}" href="{{bannerfile}}" xowa_title="{{file_ttl}}"><img{{{img_id_atr}}}{{{img_xottl}}}{{{img_xoimg}}} src="{{banner}}" srcset="{{srcset}}" class="wpb-banner-image"{{#hasPosition}} data-pos-x="{{data-pos-x}}" data-pos-y="{{data-pos-y}}" {{/hasPosition}} style="max-width:{{maxWidth}}px"></a>
<a class="image" dir="ltr" title="{{tooltip}}" href="{{bannerfile}}" xowa_title="{{file_ttl}}"><img{{{img_id_atr}}}{{{img_xottl}}}{{{img_xoimg}}} src="{{banner}}" srcset="{{srcset}}" class="wpb-banner-image"{{#hasPosition}} data-pos-x="{{data-pos-x}}" data-pos-y="{{data-pos-y}}"{{/hasPosition}}></a>
{{#hasIcons}}
<div class="wpb-iconbox">
{{#icons}}

Loading…
Cancel
Save