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

View File

@@ -0,0 +1,85 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.xtns.poems; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
import gplx.html.*; import gplx.xowa.html.*;
public class Poem_nde implements Xox_xnde {
private Xop_root_tkn xtn_root;
public void Xtn_parse(Xowe_wiki wiki, Xop_ctx ctx, Xop_root_tkn root, byte[] src, Xop_xnde_tkn xnde) {// REF.MW: Poem.php|wfRenderPoemTag
int itm_bgn = xnde.Tag_open_end(), itm_end = xnde.Tag_close_bgn();
if (itm_bgn == src.length) return; // NOTE: handle inline where there is no content to parse; EX: <poem/>
if (itm_bgn >= itm_end) return; // NOTE: handle inline where there is no content to parse; EX: a<poem/>b
if (src[itm_bgn] == Byte_ascii.Nl) ++itm_bgn; // ignore 1st \n;
if (src[itm_end - 1] == Byte_ascii.Nl // ignore last \n;
&& itm_end != itm_bgn) --itm_end; // ...if not same as 1st \n; EX: <poem>\n</poem>
Poem_xtn_mgr xtn_mgr = (Poem_xtn_mgr)wiki.Xtn_mgr().Get_or_fail(Poem_xtn_mgr.XTN_KEY);
byte[] poem_bry = Parse_lines(wiki.Utl__bfr_mkr(), src, itm_bgn, itm_end);
xtn_root = xtn_mgr.Parser().Parse_text_to_wdom_old_ctx(ctx, poem_bry, true); // NOTE: ignoring paragraph mode; technically MW enables para mode, but by replacing "\n" with "<br/>\n" all the logic with para/pre mode is skipped
}
public void Xtn_write(Bry_bfr bfr, Xoae_app app, Xop_ctx ctx, Xoh_html_wtr html_wtr, Xoh_wtr_ctx hctx, Xop_xnde_tkn xnde, byte[] src) {
if (xtn_root == null) return; // inline poem; write nothing; EX: <poem/>
bfr.Add(Div_poem_bgn);
html_wtr.Write_tkn(bfr, ctx, hctx, xtn_root.Root_src(), xnde, Xoh_html_wtr.Sub_idx_null, xtn_root);
bfr.Add(Div_poem_end);
}
private static byte[] Parse_lines(Bry_bfr_mkr bfr_mkr, byte[] src, int src_bgn, int src_end) {
Bry_bfr bfr = bfr_mkr.Get_k004().Mkr_rls();
int line_bgn = src_bgn; boolean line_is_1st = true;
while (line_bgn < src_end) { // iterate over each \n
boolean indent_enabled = false;
if (line_is_1st) line_is_1st = false;
else {
int line_end_w_br = line_bgn + Xowa_br_mark.length;
if ( line_end_w_br < src_end // check for out of bounds; PAGE:en.s:The Hebrew Nation did not write it; DATE:2015-01-31
&& Bry_.Match(src, line_bgn, line_end_w_br, Xowa_br_mark)) // "<br/>\n" already inserted by XOWA; do not insert again; DATE:2014-10-20
bfr.Add_byte_nl();
else
bfr.Add(Html_tag_.Br_inl).Add_byte_nl().Add(Xowa_br_mark); // add "<br/>\n" unless 1st line; EX: "<poem>\n\s" should not add leading "<br/>\n"
}
switch (src[line_bgn]) {
case Byte_ascii.Space: // "\n\s" -> "\n&#160;"
int space_end = Bry_finder.Find_fwd_while(src, line_bgn, src_end, Byte_ascii.Space);
int space_count = space_end - line_bgn;
line_bgn = space_end;
for (int i = 0; i < space_count; ++i)
bfr.Add(Html_entity_.Nbsp_num_bry);
break;
case Byte_ascii.Colon: { // "\n:" -> <span class='mw-poem-indented' style='display: inline-block; margin-left: #em;'>
int colon_end = Bry_finder.Find_fwd_while(src, line_bgn, src_end, Byte_ascii.Colon);
int colon_count = colon_end - line_bgn;
line_bgn = colon_end;
bfr.Add(Indent_bgn).Add_int_variable(colon_count).Add(Indent_end); // add <span class='mw-poem-indented' style='display: inline-block; margin-left: #em;'>
indent_enabled = true;
break;
}
}
int line_end = Bry_finder.Find_fwd(src, Byte_ascii.Nl, line_bgn, src_end); // find end "\n"
if (line_end == Bry_finder.Not_found) line_end = src_end; // no "\n"; use eos;
bfr.Add_mid(src, line_bgn, line_end); // add everything from line_bgn to line_end
if (indent_enabled) bfr.Add(Html_tag_.Span_rhs); // if "\n:", add </span>
line_bgn = line_end + 1; // +1 to skip over end "\n"
}
return bfr.Xto_bry_and_clear();
}
private static byte[]
Div_poem_bgn = Bry_.new_a7("<div class=\"poem\">\n<p>\n") // NOTE: always enclose in <p>; MW does this implicitly in its modified parse; DATE:2014-04-27
, Div_poem_end = Bry_.new_a7("\n</p>\n</div>")
, Indent_bgn = Bry_.new_a7("\n<span class='mw-poem-indented' style='display: inline-block; margin-left: ")
, Indent_end = Bry_.new_a7("em;'>")
, Xowa_br_mark = Bry_.new_a7("<!--xowa.br-->")
;
}

View File

@@ -0,0 +1,285 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.xtns.poems; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
import org.junit.*;
public class Poem_nde_tst {
@Before public void init() {fxt.Wiki().Xtn_mgr().Init_by_wiki(fxt.Wiki());} private Xop_fxt fxt = new Xop_fxt();
@Test public void Lines() { // NOTE: first \n (poem\n) and last \n (\n</poem>)ignored
fxt.Test_parse_page_wiki_str(String_.Concat_lines_nl_skip_last
( "<poem>"
, "a"
, "b"
, "c"
, "d"
, "</poem>"
), String_.Concat_lines_nl_skip_last
( "<div class=\"poem\">"
, "<p>"
, "a<br/>"
, "b<br/>"
, "c<br/>"
, "d"
, "</p>"
, "</div>"
));
}
@Test public void Nbsp_basic() {
fxt.Test_parse_page_wiki_str(String_.Concat_lines_nl_skip_last
( "<poem>"
, "a 1"
, " b 1"
, "c 1"
, " d 1"
, "</poem>"
), String_.Concat_lines_nl_skip_last
( "<div class=\"poem\">"
, "<p>"
, "a 1<br/>"
, "&#160;&#160;b 1<br/>"
, "c 1<br/>"
, "&#160;&#160;d 1"
, "</p>"
, "</div>"
));
}
@Test public void Nbsp_line_0() {// PURPOSE: indent on 1st line caused page_break
fxt.Test_parse_page_wiki_str(String_.Concat_lines_nl_skip_last
( "<poem>"
, " a"
, " b"
, " c"
, " d"
, "</poem>"
), String_.Concat_lines_nl_skip_last
( "<div class=\"poem\">"
, "<p>"
, "&#160;&#160;a<br/>"
, "&#160;&#160;b<br/>"
, "&#160;&#160;c<br/>"
, "&#160;&#160;d"
, "</p>"
, "</div>"
));
}
@Test public void Nbsp_blank_lines() {// PURPOSE: check blank lines; PAGE:none
fxt.Test_parse_page_wiki_str(String_.Concat_lines_nl_skip_last
( "<poem>"
, " a"
, " "
, " "
, " b"
, "</poem>"
), String_.Concat_lines_nl_skip_last
( "<div class=\"poem\">"
, "<p>"
, "&#160;&#160;a<br/>"
, "&#160;&#160;<br/>"
, "&#160;&#160;<br/>"
, "&#160;&#160;b"
, "</p>"
, "</div>"
));
}
@Test public void Comment() {
fxt.Test_parse_page_wiki_str("<poem>a<!-- b --> c</poem>", String_.Concat_lines_nl_skip_last
( "<div class=\"poem\">"
, "<p>"
, "a c"
, "</p>"
, "</div>"
));
}
@Test public void Xtn() { // NOTE: behavior as per MW: DATE:2014-03-03
fxt.Init_defn_clear();
fxt.Init_defn_add("test_print", "{{{1}}}");
fxt.Init_defn_add("test_outer", String_.Concat_lines_nl_skip_last
( "{{test_print|a <poem>b}}c</poem>}}"
));
fxt.Test_parse_page_all_str(String_.Concat_lines_nl_skip_last
( "{{test_outer}}"
), String_.Concat_lines_nl_skip_last
( "a <div class=\"poem\">"
, "<p>"
, "b}}c"
, "</p>"
, "</div>"
));
fxt.Init_defn_clear();
}
@Test public void Err_empty_line() {// PURPOSE: one \n caused poem to fail
fxt.Test_parse_page_wiki_str("<poem>\n</poem>", String_.Concat_lines_nl_skip_last
( "<div class=\"poem\">"
, "<p>"
, ""
, "</p>"
, "</div>"
));
}
@Test public void Err_dangling_comment() {// PURPOSE: ArrayIndexOutOfBoundsError if poem has <references/> and ends with <!--; PAGE:en.s:The Hebrew Nation did not write it; DATE:2015-01-31
fxt.Test_parse_page_wiki_str(String_.Concat_lines_nl_skip_last
( "<poem>"
, "<references/>"
, "<!--"
), String_.Concat_lines_nl_skip_last
( "<div class=\"poem\">"
, "<p>"
, "<br/>"
, ""
, "</p>"
, "</div>"
));
}
@Test public void Ref() { // PURPOSE: <ref> inside poem was not showing up; DATE:2014-01-17
fxt.Test_parse_page_all_str(String_.Concat_lines_nl_skip_last
( "<poem>a<ref>b</ref></poem>"
, "<references/>"), String_.Concat_lines_nl_skip_last
( "<div class=\"poem\">"
, "<p>"
, "a<sup id=\"cite_ref-0\" class=\"reference\"><a href=\"#cite_note-0\">[1]</a></sup>"
, "</p>"
, "</div>"
, "<ol class=\"references\">"
, "<li id=\"cite_note-0\"><span class=\"mw-cite-backlink\"><a href=\"#cite_ref-0\">^</a></span> <span class=\"reference-text\">b</span></li>"
, "</ol>"
, ""
));
}
@Test public void Template_tkn() { // PURPOSE: make sure {{{1}}} is interpreted as invk_prm, not as text; DATE:2014-03-03
fxt.Test_parse_tmpl("<poem>{{{1}}}</poem>"
, fxt.tkn_xnde_(0, 20).Subs_
( fxt.tkn_tmpl_prm_find_(fxt.tkn_txt_(9, 10))
)
);
}
@Test public void Template_parse() { // PURPOSE: <poem> inside template was not evaluating args; EX:en.s:The_Canterville_Ghost; DATE:2014-03-03
fxt.Init_page_create("Template:A", "<poem>{{{1}}}</poem>");
fxt.Test_parse_page_all_str("{{A|b}}", String_.Concat_lines_nl_skip_last
( "<div class=\"poem\">"
, "<p>"
, "b" // was {{{1}}}
, "</p>"
, "</div>"
));
}
@Test public void Nested() { // PURPOSE: handled nested poems; EX:en.s:The_Canterville_Ghost; DATE:2014-03-03
fxt.Test_parse_page_all_str("a<poem>b<poem>c</poem>d</poem>e", String_.Concat_lines_nl_skip_last
( "a<div class=\"poem\">"
, "<p>"
, "b<div class=\"poem\">"
, "<p>"
, "c"
, "</p>"
, "</div>"
, "</p>"
, "</div>de"
));
}
@Test public void Indent_line_0() { // PURPOSE: handle colon on 1st line; PAGE:en.w:Mary_Wollstonecraft DATE:2014-10-19
fxt.Test_parse_page_all_str(String_.Concat_lines_nl_skip_last
( "<poem>"
, ":a"
, ":b"
, "</poem>"
), String_.Concat_lines_nl_skip_last
( "<div class=\"poem\">"
, "<p>"
, "<span class='mw-poem-indented' style='display: inline-block; margin-left: 1em;'>a</span><br/>"
, "<span class='mw-poem-indented' style='display: inline-block; margin-left: 1em;'>b</span>"
, "</p>"
, "</div>"
));
}
@Test public void Indent_many() { // PURPOSE: handle colon on 2nd line; PAGE:vi.s:Văn_Côi_thánh_nguyệt_tán_tụng_thi_ca DATE:2014-10-15
fxt.Test_parse_page_all_str(String_.Concat_lines_nl_skip_last
( "<poem>"
, "a"
, ":b"
, "::c"
, "</poem>"
), String_.Concat_lines_nl_skip_last
( "<div class=\"poem\">"
, "<p>"
, "a<br/>"
, "<span class='mw-poem-indented' style='display: inline-block; margin-left: 1em;'>b</span><br/>"
, "<span class='mw-poem-indented' style='display: inline-block; margin-left: 2em;'>c</span>"
, "</p>"
, "</div>"
));
}
@Test public void Indent_blank() { // PURPOSE: check blank lines; PAGE:none DATE:2014-10-19
fxt.Test_parse_page_all_str(String_.Concat_lines_nl_skip_last
( "<poem>"
, ":a"
, ":"
, ":b"
, "</poem>"
), String_.Concat_lines_nl_skip_last
( "<div class=\"poem\">"
, "<p>"
, "<span class='mw-poem-indented' style='display: inline-block; margin-left: 1em;'>a</span><br/>"
, "<span class='mw-poem-indented' style='display: inline-block; margin-left: 1em;'></span><br/>"
, "<span class='mw-poem-indented' style='display: inline-block; margin-left: 1em;'>b</span>"
, "</p>"
, "</div>"
));
}
@Test public void List_does_not_end() {// PURPOSE: list does not end with "\ntext"; PAGE:vi.s:Dương_Từ_Hà_Mậu_(dị_bản_mới); li.s:Sint_Servaes_legende/Nuuj_fergmènter DATE:2014-10-19
fxt.Test_parse_page_all_str(String_.Concat_lines_nl_skip_last
( "<poem>"
, "a"
, "*b"
, "**c"
, "d"
, "</poem>"
), String_.Concat_lines_nl_skip_last
( "<div class=\"poem\">"
, "<p>"
, "a<br/>"
, "<ul>"
, " <li>b<br/>"
, " <ul>"
, " <li>c<br/>"
, " </li>"
, " </ul>"
, " </li>"
, "</ul>"
, "d" // was being embedded directly after <li>c
, "</p>"
, "</div>"
));
}
@Test public void Page() { // PURPOSE: handled dangling poems across pages; PAGE:ca.s:Llibre_de_Disputació_de_l'Ase DATE:2014-10-19
fxt.Init_xtn_pages();
fxt.Init_page_create("Page:A/1", "<poem>a\nb\n");
fxt.Init_page_create("Page:A/2", "<poem>c\nd\n");
fxt.Test_parse_page_wiki_str("<pages index=\"A\" from=1 to=2 />", String_.Concat_lines_nl_skip_last
( "<p><div class=\"poem\">"
, "<p>"
, "a<br/>"
, "b"
, "</p>"
, "</div>&#32;<div class=\"poem\">"
, "<p>"
, "c<br/>" // NOTE: "<br/>" not "<br/><br/>"
, "d"
, "</p>"
, "</div>&#32;"
, "</p>"
));
}
}

View File

@@ -0,0 +1,28 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.xtns.poems; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
public class Poem_xtn_mgr extends Xox_mgr_base {
@Override public byte[] Xtn_key() {return XTN_KEY;} public static final byte[] XTN_KEY = Bry_.new_a7("poem");
@Override public Xox_mgr Clone_new() {return new Poem_xtn_mgr();}
public Xop_parser Parser() {return parser;} private Xop_parser parser;
@Override public void Xtn_init_by_wiki(Xowe_wiki wiki) {
parser = new Xop_parser(wiki, wiki.Parser().Tmpl_lxr_mgr(), wiki.Parser().Wtxt_lxr_mgr());
parser.Init_by_wiki(wiki);
parser.Init_by_lang(wiki.Lang());
}
}