From a4b5f5de5d7428418817568cc3e5aa259d76ad54 Mon Sep 17 00:00:00 2001 From: gnosygnu Date: Sun, 26 Apr 2020 15:51:56 -0400 Subject: [PATCH] TemplateStyles: Apply wrapper to each class, not to top only [#712] --- .../src/gplx/xowa/htmls/minifys/XoCssMin.java | 15 +- .../template_styles/Template_styles_nde.java | 16 ++- .../Template_styles_nde_tst.java | 135 ++++++++++-------- .../template_styles/XoCssTransformer.java | 37 +++++ .../template_styles/XoCssTransformerTest.java | 43 ++++++ 5 files changed, 168 insertions(+), 78 deletions(-) create mode 100644 400_xowa/src/gplx/xowa/xtns/template_styles/XoCssTransformer.java create mode 100644 400_xowa/tst/gplx/xowa/xtns/template_styles/XoCssTransformerTest.java diff --git a/400_xowa/src/gplx/xowa/htmls/minifys/XoCssMin.java b/400_xowa/src/gplx/xowa/htmls/minifys/XoCssMin.java index 5c78c6b17..d76478041 100644 --- a/400_xowa/src/gplx/xowa/htmls/minifys/XoCssMin.java +++ b/400_xowa/src/gplx/xowa/htmls/minifys/XoCssMin.java @@ -35,14 +35,12 @@ public class XoCssMin { public static final int MODE_NODEJS = 1 , MODE_YCSS_MIN = 2 - , MODE_XOWA = 4 - , MODE_ALL = MODE_NODEJS | MODE_YCSS_MIN | MODE_XOWA + , MODE_ALL = MODE_NODEJS | MODE_YCSS_MIN ; public void DataCollectorMgr_(GfoDataCollectorMgr v) {this.dataCollectorMgr = v;} private GfoDataCollectorMgr dataCollectorMgr; public String cssmin(String css, int linebreakpos) {return cssmin(css, linebreakpos, MODE_ALL);} public String cssmin(String css, int linebreakpos, int mode) { boolean isModeYcssMin = Bitmask_.Has_int(mode, MODE_YCSS_MIN); - boolean isModeXowa = Bitmask_.Has_int(mode, MODE_XOWA); int startIndex = 0, endIndex = 0, @@ -288,17 +286,6 @@ public class XoCssMin { // Trim the final string (for any leading or trailing white spaces) css = JsString_.replace(css, patterns, "^\\s+|\\s+$", ""); - if (isModeXowa) { - // add the '.mw-parser-output ' selector - css = JsString_.replace(css, patterns, "\\}([^@}].{2})", "}.mw-parser-output $1"); - css = JsString_.replace(css, patterns, "(@media[^\\{]*\\{)", "$1.mw-parser-output "); - if (css.charAt(0) != '@') - css = ".mw-parser-output " + css; - - // change some url(...) entries - css = css.replace("//upload.wikimedia.org", "//www.xowa.org/xowa/fsys/bin/any/xowa/upload.wikimedia.org"); - } - return css; } private String _extractDataUrls(String css, List preservedTokens) { diff --git a/400_xowa/src/gplx/xowa/xtns/template_styles/Template_styles_nde.java b/400_xowa/src/gplx/xowa/xtns/template_styles/Template_styles_nde.java index d5cd1e0b1..7bb902036 100644 --- a/400_xowa/src/gplx/xowa/xtns/template_styles/Template_styles_nde.java +++ b/400_xowa/src/gplx/xowa/xtns/template_styles/Template_styles_nde.java @@ -27,7 +27,6 @@ import gplx.xowa.htmls.heads.Xoh_head_itm__css_dynamic; import gplx.xowa.htmls.hxtns.blobs.Hxtn_blob_tbl; import gplx.xowa.htmls.hxtns.pages.Hxtn_page_mgr; import gplx.xowa.htmls.hxtns.wikis.Hxtn_wiki_itm; -import gplx.xowa.htmls.minifys.XoCssMin; import gplx.xowa.parsers.Xop_ctx; import gplx.xowa.parsers.Xop_root_tkn; import gplx.xowa.parsers.htmls.Mwh_atr_itm; @@ -40,17 +39,17 @@ import gplx.xowa.xtns.Xox_xnde; import gplx.xowa.xtns.Xox_xnde_; public class Template_styles_nde implements Xox_xnde, Mwh_atr_itm_owner2 { private byte[] css_ttl_bry; - private byte[] wrapper; private byte[] css_src; private boolean css_ignore; private int css_page_id; private Xoa_ttl css_ttl; - private static XoCssMin cssMin = new XoCssMin(); + private String prepend = ".mw-parser-output"; + public void Xatr__set(Xowe_wiki wiki, byte[] src, Mwh_atr_itm xatr, byte xatr_id) { switch (xatr_id) { case Xatr__src: css_ttl_bry = xatr.Val_as_bry(); break; case Xatr__wrapper: - wrapper = Bry_.Add(xatr.Val_as_bry(), Byte_ascii.Space); // add trailing space for html_head.format + prepend = prepend + " " + xatr.Val_as_str(); break; } } @@ -104,7 +103,12 @@ public class Template_styles_nde implements Xox_xnde, Mwh_atr_itm_owner2 { if (!css_ignore) { Bry_bfr tmp_bfr = ctx.Wiki().Utl__bfr_mkr().Get_b512(); try { - html_head.Bld_many(tmp_bfr, css_page_id, wrapper, Bry_.new_u8(cssMin.cssmin(String_.new_u8(css_src), -1)) ); + css_src = new XoCssTransformer(String_.new_u8(css_src)) + .Minify() + .Prepend(prepend) + .Url("upload.wikimedia.org", "www.xowa.org/xowa/fsys/bin/any/xowa/upload.wikimedia.org") + .ToBry(); + html_head.Bld_many(tmp_bfr, css_page_id, css_src); Xoh_head_itm__css_dynamic css_dynamic = ctx.Page().Html_data().Head_mgr().Itm__css_dynamic(); css_dynamic.Enabled_y_(); css_dynamic.Add(tmp_bfr.To_bry_and_clear()); @@ -130,7 +134,7 @@ public class Template_styles_nde implements Xox_xnde, Mwh_atr_itm_owner2 { .Add_str_byte("wrapper", Xatr__wrapper) ; private static final Bry_fmt - html_head = Bry_fmt.Auto("\n/*TemplateStyles:r~{id}*/\n~{wrapper}~{css}") + html_head = Bry_fmt.Auto("\n/*TemplateStyles:r~{id}*/\n~{css}") , html_error = Bry_fmt.Auto("~{msg}") ; } diff --git a/400_xowa/src/gplx/xowa/xtns/template_styles/Template_styles_nde_tst.java b/400_xowa/src/gplx/xowa/xtns/template_styles/Template_styles_nde_tst.java index ee37ffa34..a7dd42927 100644 --- a/400_xowa/src/gplx/xowa/xtns/template_styles/Template_styles_nde_tst.java +++ b/400_xowa/src/gplx/xowa/xtns/template_styles/Template_styles_nde_tst.java @@ -25,111 +25,127 @@ public class Template_styles_nde_tst { @Before public void init() { fxt.Reset(); } - @Test public void Implicit_template() { // PURPOSE: default to template - String css = fxt.Make__css_color("red"); - fxt.Init__page("Template:Test.css", css); - fxt.Test__parse + @Test public void Implicit_template() { // PURPOSE: default to template + String css = fxt.Make_css_color("red"); + fxt.Init_page("Template:Test.css", css); + fxt.Test_parse ( "" , "" - , fxt.Make__style(0, css) + , fxt.Make_style(0, css) ); } - @Test public void Force_main() { // PURPOSE: ":" forces main - String css = fxt.Make__css_color("red"); - fxt.Init__page("Test.css", css); - fxt.Test__parse + @Test public void Force_main() { // PURPOSE: ":" forces main + String css = fxt.Make_css_color("red"); + fxt.Init_page("Test.css", css); + fxt.Test_parse ( "" , "" - , fxt.Make__style(0, css) + , fxt.Make_style(0, css) ); } - @Test public void Explicit() { // PURPOSE: explicit ns - String css = fxt.Make__css_color("red"); - fxt.Init__page("Module:Test.css", css); - fxt.Test__parse + @Test public void Explicit() { // PURPOSE: explicit ns + String css = fxt.Make_css_color("red"); + fxt.Init_page("Module:Test.css", css); + fxt.Test_parse ( "" , "" - , fxt.Make__style(0, css) + , fxt.Make_style(0, css) ); } - @Test public void Multiple() { // PURPOSE: multiple calls to diff page should output diff styles; DATE:2018-12-30 - String css_red = fxt.Make__css_color("red"); - String css_blue = fxt.Make__css_color("blue"); - fxt.Init__page("Module:Test1.css", css_red); - fxt.Init__page("Module:Test2.css", css_blue); - fxt.Test__parse + @Test public void Multiple() { // PURPOSE: multiple calls to diff page should output diff styles; DATE:2018-12-30 + String css_red = fxt.Make_css_color("red"); + String css_blue = fxt.Make_css_color("blue"); + fxt.Init_page("Module:Test1.css", css_red); + fxt.Init_page("Module:Test2.css", css_blue); + fxt.Test_parse ( String_.Concat_lines_nl ( "" , "" ) , "" - , fxt.Make__style(0, css_red) - + fxt.Make__style(1, css_blue) + , fxt.Make_style(0, css_red) + + fxt.Make_style(1, css_blue) ); } - @Test public void Dedupe() { // PURPOSE: multiple calls to same page should output link; DATE:2018-12-30 - String css = fxt.Make__css_color("red"); - fxt.Init__page("Module:Test.css", css); - fxt.Test__parse + @Test public void Dedupe() { // PURPOSE: multiple calls to same page should output link; DATE:2018-12-30 + String css = fxt.Make_css_color("red"); + fxt.Init_page("Module:Test.css", css); + fxt.Test_parse ( String_.Concat_lines_nl - ( "" - , "" + ( "" + , "" ) , "" , String_.Concat_lines_nl - ( fxt.Make__style(0, css)) + ( fxt.Make_style(0, css)) ); } - @Test public void Tag() { // PURPOSE: {{#tag}} - String css = fxt.Make__css_color("red"); - fxt.Init__page("Module:A/Test.css", css); - fxt.Test__parse + @Test public void Tag() { // PURPOSE: {{#tag}} + String css = fxt.Make_css_color("red"); + fxt.Init_page("Module:A/Test.css", css); + fxt.Test_parse ( "{{#tag:templatestyles||src='Module:A/Test.css'}}" , "" - , fxt.Make__style(0, css) + , fxt.Make_style(0, css) ); } - @Test public void Fix_single_word_paragraph() { // PURPOSE:make sure block is closed, else single-word paragraphs; ISSUE#:616; DATE:2019-11-18 - String css = fxt.Make__css_color("red"); - fxt.Init__page("Template:Test.css", css); + @Test public void Fix_single_word_paragraph() { // PURPOSE:make sure block is closed, else single-word paragraphs; ISSUE#:616; DATE:2019-11-18 + String css = fxt.Make_css_color("red"); + fxt.Init_page("Template:Test.css", css); fxt.Parser_fxt().Init_para_y_(); - fxt.Test__parse + fxt.Test_parse ( String_.Concat_lines_nl_skip_last("", "a") , String_.Concat_lines_nl_skip_last("", "

a", "

") - , fxt.Make__style(0, css) + , fxt.Make_style(0, css) ); fxt.Parser_fxt().Init_para_n_(); } - @Test public void Error__invalid_title() { - fxt.Test__parse + @Test public void Error__invalid_title() { + fxt.Test_parse ( "" , "Invalid title for TemplateStyles src attribute." , "" ); } - @Test public void Error__missing_page() { - fxt.Test__parse + @Test public void Error__missing_page() { + fxt.Test_parse ( "" , "Page Missing.css has no content." , "" ); } - @Test public void Error__missing_src() { - fxt.Test__parse + @Test public void Error__missing_src() { + fxt.Test_parse ( ""// PAGE:en.w:Switzerland; ISSUE#:416; DATE:2019-03-31 , "Invalid title for TemplateStyles src attribute." , "" ); } - @Test public void Wrapper() { - String css = fxt.Make__css_color("red"); - fxt.Init__page("Template:Test.css", css); - fxt.Test__parse + @Test public void Wrapper() { + String css = fxt.Make_css_color("red"); + fxt.Init_page("Template:Test.css", css); + fxt.Test_parse ( "" , "" - , fxt.Make__style(0, ".wrapper_class", css) + , fxt.Make_style(0, ".wrapper_class", css) ); } + @Test public void Url() { + fxt.Init_page("Template:Test.css", fxt.Make_css_url("//upload.wikimedia.org/A.png")); + fxt.Test_parse + ( "" + , "" + , fxt.Make_style(0, fxt.Make_css_url("//www.xowa.org/xowa/fsys/bin/any/xowa/upload.wikimedia.org/A.png")) + ); + } + @Test public void Minify() { + fxt.Init_page("Template:Test.css", fxt.Make_css_color("rgb (128,128,128)")); + fxt.Test_parse + ( "" + , "" + , fxt.Make_style(0, fxt.Make_css_color("#808080")) + ); + } } class Template_styles_nde_fxt { private final Xop_fxt parser_fxt = new Xop_fxt(); @@ -138,18 +154,21 @@ class Template_styles_nde_fxt { parser_fxt.Reset(); parser_fxt.Wiki().Xtn_mgr().Init_by_wiki(parser_fxt.Wiki()); } - public void Init__page(String page, String text) { + public void Init_page(String page, String text) { parser_fxt.Init_page_create(page, text); } - public String Make__css_color(String color) { + public String Make_css_color(String color) { return ".style0{color:" + color + "}"; } - public String Make__style(int id, String css) {return Make__style(id, null, css);} - public String Make__style(int id, String wrapper, String css) { - wrapper = wrapper == null ? "" : wrapper + " "; - return "\n/*TemplateStyles:r" + id + "*/\n" + wrapper + ".mw-parser-output " + css; // .mw-parser-output needs to be added to all TemplateStyles CSS, else TS ids called "portal" will affect sidebar; ISSUE#:426; PAGE:en.w:Poland DATE:2020-04-10 + public String Make_css_url(String url) { + return ".style1{url(" + url + "}"; } - public void Test__parse(String src, String expd_html, String expd_head) { + public String Make_style(int id, String css) {return Make_style(id, null, css);} + public String Make_style(int id, String wrapper, String css) { + wrapper = wrapper == null ? "" : wrapper + " "; + return "\n/*TemplateStyles:r" + id + "*/\n" + ".mw-parser-output " + wrapper + css; // .mw-parser-output needs to be added to all TemplateStyles CSS, else TS ids called "portal" will affect sidebar; ISSUE#:426; PAGE:en.w:Poland DATE:2020-04-10 + } + public void Test_parse(String src, String expd_html, String expd_head) { parser_fxt.Test__parse__tmpl_to_html(src, expd_html); Gftest.Eq__ary__lines(expd_head, parser_fxt.Page().Html_data().Head_mgr().Itm__css_dynamic().Get_and_clear()); } diff --git a/400_xowa/src/gplx/xowa/xtns/template_styles/XoCssTransformer.java b/400_xowa/src/gplx/xowa/xtns/template_styles/XoCssTransformer.java new file mode 100644 index 000000000..952a07c99 --- /dev/null +++ b/400_xowa/src/gplx/xowa/xtns/template_styles/XoCssTransformer.java @@ -0,0 +1,37 @@ +package gplx.xowa.xtns.template_styles; + +import gplx.Bry_; +import gplx.langs.javascripts.JsString_; +import gplx.xowa.htmls.minifys.XoCssMin; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Pattern; + +public class XoCssTransformer { + private final static ConcurrentHashMap patterns = new ConcurrentHashMap<>(); + private String css; + public XoCssTransformer(String css) { + this.css = css; + } + + public XoCssTransformer Minify() { + XoCssMin minifier = new XoCssMin(); + this.css = minifier.cssmin(css, -1); + return this; + } + public XoCssTransformer Prepend(String prepend) { + // prepend any classes to all declarations; primarily for '.mw-parser-output ' selector + css = JsString_.replace(css, patterns, "\\}([^@}].{2})", "} " + prepend + " $1"); + css = JsString_.replace(css, patterns, "(@media[^\\{]*\\{)", "$1" + prepend + " "); + if (css.charAt(0) != '@') + css = prepend + " " + css; + return this; + } + public XoCssTransformer Url(String src, String trg) { + // change some url(...) entries + css = css.replace("//" + src, "//" + trg); + return this; + } + public byte[] ToBry() {return Bry_.new_u8(css);} + public String ToStr() {return css;} +} diff --git a/400_xowa/tst/gplx/xowa/xtns/template_styles/XoCssTransformerTest.java b/400_xowa/tst/gplx/xowa/xtns/template_styles/XoCssTransformerTest.java new file mode 100644 index 000000000..63670fe8b --- /dev/null +++ b/400_xowa/tst/gplx/xowa/xtns/template_styles/XoCssTransformerTest.java @@ -0,0 +1,43 @@ +package gplx.xowa.xtns.template_styles; + +import gplx.core.tests.Gftest; +import org.junit.Test; + +public class XoCssTransformerTest { + private final XoCssTranformerTstr tstr = new XoCssTranformerTstr(); + + @Test + public void Minify() { + tstr.Test_Minify("basic" ,"rgb (128,128,128)", "#808080"); + } + + @Test + public void Prepend() { + tstr.Test_Prepend("cls.1.1" ,"x {}" , ".a" , ".a x {}"); + tstr.Test_Prepend("cls.n.1" ,"x {}y {}", ".a" , ".a x {} .a y {}"); + } + + @Test + public void Url() { + tstr.Test_Url("match.y" , "url(//site/a.png)", "site", "prepend/site", "url(//prepend/site/a.png)"); + tstr.Test_Url("match.y.any", "//site/abc" , "site", "prepend/site", "//prepend/site/abc"); // NOTE: matches any "//" + tstr.Test_Url("match.n" , "url(/-site/a.png)", "site", "prepend/site", "url(/-site/a.png)"); + } +} +class XoCssTranformerTstr { + public void Test_Url(String note, String css, String src, String trg, String expd) { + XoCssTransformer transformer = new XoCssTransformer(css); + String actl = transformer.Url(src, trg).ToStr(); + Gftest.Eq__str(expd, actl, note); + } + public void Test_Prepend(String note, String css, String prepend, String expd) { + XoCssTransformer transformer = new XoCssTransformer(css); + String actl = transformer.Prepend(prepend).ToStr(); + Gftest.Eq__str(expd, actl, note); + } + public void Test_Minify(String note, String css, String expd) { + XoCssTransformer transformer = new XoCssTransformer(css); + String actl = transformer.Minify().ToStr(); + Gftest.Eq__str(expd, actl, note); + } +}