TemplateStyles: Apply wrapper to each class, not to top only [#712]

staging
gnosygnu 4 years ago
parent ecbcf1e707
commit a4b5f5de5d

@ -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<String> preservedTokens) {

@ -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("<strong class=\"error\">~{msg}</strong>")
;
}

@ -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
( "<templatestyles src='Test.css'/>"
, ""
, 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
( "<templatestyles src=':Test.css'/>"
, ""
, 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
( "<templatestyles src='Module:Test.css'/>"
, ""
, 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
( "<templatestyles src='Module:Test1.css'/>"
, "<templatestyles src='Module:Test2.css'/>"
)
, ""
, 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
( "<templatestyles src='Module:Test.css'/>"
, "<templatestyles src='Module:Test.css'/>"
( "<templatestyles src='Module:Test.css'/>"
, "<templatestyles src='Module:Test.css'/>"
)
, ""
, 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("<templatestyles src='Test.css'/>", "a")
, String_.Concat_lines_nl_skip_last("", "<p>a", "</p>")
, 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
( "<templatestyles src='A|b.css'/>"
, "<strong class=\"error\">Invalid title for TemplateStyles src attribute.</strong>"
, ""
);
}
@Test public void Error__missing_page() {
fxt.Test__parse
@Test public void Error__missing_page() {
fxt.Test_parse
( "<templatestyles src='Missing.css'/>"
, "<strong class=\"error\">Page Missing.css has no content.</strong>"
, ""
);
}
@Test public void Error__missing_src() {
fxt.Test__parse
@Test public void Error__missing_src() {
fxt.Test_parse
( "<templatestyles src{{=}}'Missing.css'/>"// PAGE:en.w:Switzerland; ISSUE#:416; DATE:2019-03-31
, "<strong class=\"error\">Invalid title for TemplateStyles src attribute.</strong>"
, ""
);
}
@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
( "<templatestyles src='Test.css' wrapper='.wrapper_class' />"
, ""
, 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
( "<templatestyles src='Test.css' />"
, ""
, 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
( "<templatestyles src='Test.css' />"
, ""
, 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) {
public String Make_css_url(String url) {
return ".style1{url(" + url + "}";
}
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
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) {
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());
}

@ -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<String, Pattern> 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;}
}

@ -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);
}
}
Loading…
Cancel
Save