mirror of https://github.com/gnosygnu/xowa
Skin: Change to mustache-backed Skin.Vector (temporary commit) [#797]
parent
5c3d6a173b
commit
2f4693ac47
@ -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();
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
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.Bry_bfr;
|
||||
import gplx.Bry_bfr_;
|
||||
|
||||
public class Json_mustache {
|
||||
|
||||
public static Json_kv Add_text(String keystr, byte[] bytes) {
|
||||
if (bytes == null) return null;
|
||||
Json_itm_str key = new Json_itm_str(Bry_.new_a7(keystr), true);
|
||||
Json_itm_str val = new Json_itm_str(bytes, false);
|
||||
return new Json_kv(key, val);
|
||||
}
|
||||
|
||||
public static Json_kv Add_int(String keystr, int intval) {
|
||||
Json_itm_str key = new Json_itm_str(Bry_.new_a7(keystr), true);
|
||||
Json_itm_int val = new Json_itm_int(intval);
|
||||
return new Json_kv(key, val);
|
||||
}
|
||||
|
||||
public static Json_kv Add_double(String keystr, double doubleval) {
|
||||
// eek
|
||||
Json_itm_str key = new Json_itm_str(Bry_.new_a7(keystr), true);
|
||||
Bry_bfr bfr = Bry_bfr_.New();
|
||||
byte[] bytes = bfr.Add_double(doubleval).To_bry();
|
||||
Json_itm_str val = new Json_itm_str(bytes, true);
|
||||
return new Json_kv(key, val);
|
||||
}
|
||||
|
||||
public static Json_kv Add_bool(String keystr, boolean bool) {
|
||||
Json_itm_str key = new Json_itm_str(Bry_.new_a7(keystr), true);
|
||||
Json_itm_bool val = new Json_itm_bool(bool);
|
||||
return new Json_kv(key, val);
|
||||
}
|
||||
|
||||
public static Json_kv Add_nde(String keystr, Json_nde nde) {
|
||||
Json_itm_str key = new Json_itm_str(Bry_.new_a7(keystr), true);
|
||||
return new Json_kv(key, nde);
|
||||
}
|
||||
|
||||
public static Json_kv Add_ary(String keystr, Json_ary ary) {
|
||||
if (ary == null) return null;
|
||||
Json_itm_str key = new Json_itm_str(Bry_.new_a7(keystr), true);
|
||||
return new Json_kv(key, ary);
|
||||
}
|
||||
}
|
@ -0,0 +1,292 @@
|
||||
package gplx.xowa;
|
||||
import gplx.*;
|
||||
import gplx.langs.mustaches.*;
|
||||
//import gplx.langs.mustaches.Mustache_tkn_itm;
|
||||
//import gplx.langs.mustaches.Mustache_tkn_parser;
|
||||
import gplx.xowa.Xowe_wiki;
|
||||
import gplx.langs.jsons.Json_nde;
|
||||
import gplx.langs.jsons.Json_mustache;
|
||||
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(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 = new Json_nde(null, -1);
|
||||
for (int i = 0; i < msg_len; i++) {
|
||||
String msg = msgs[i];
|
||||
msgdata.Add( Json_mustache.Add_text("msg-" + msg, msg_mgr.Val_by_str_or_empty(msg)));
|
||||
}
|
||||
}
|
||||
private void Test() {
|
||||
Json_nde namespaces = new Json_nde(null, -1);
|
||||
Json_nde jnde = new Json_nde(null, -1);
|
||||
jnde.Add_many(
|
||||
Json_mustache.Add_text("class", Bry_.new_a7("CLASS"))
|
||||
,Json_mustache.Add_text("text", Bry_.new_a7("TEXT"))
|
||||
,Json_mustache.Add_text("href", Bry_.new_a7("URL_str"))
|
||||
,Json_mustache.Add_bool("exists", true)
|
||||
,Json_mustache.Add_bool("primary", true)
|
||||
,Json_mustache.Add_text("link-class", Bry_.Empty)
|
||||
);
|
||||
jnde.Add(Json_mustache.Add_text("context", Bry_.new_a7("subject")));
|
||||
|
||||
namespaces.Add(Json_mustache.Add_nde("subject", jnde));
|
||||
|
||||
//Json_nde data_namespaces = new Json_nde(null, -1);
|
||||
msgdata.Add(Json_mustache.Add_nde("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(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, 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",
|
||||
*/
|
||||
|
||||
byte[] listClasses;
|
||||
byte[] msg = label; // for now
|
||||
byte[] linkertooltip = Bry_.Empty;
|
||||
if (type == MENU_TYPE_DROPDOWN)
|
||||
listClasses = Bry_.new_a7("menu vector-menu-content-list");
|
||||
else
|
||||
listClasses = Bry_.new_a7("vector-menu-content-list");
|
||||
|
||||
byte[] plabel = Bry_.Add(Bry_.new_a7("p-"), label);
|
||||
Json_nde props = new Json_nde(null, -1);
|
||||
props.Add_many(
|
||||
Json_mustache.Add_text("id", plabel)
|
||||
/*
|
||||
'label-id' => "p-{$label}-label",
|
||||
*/
|
||||
,Json_mustache.Add_text("label-id", Bry_.Add(plabel, Bry_.new_a7("-label")))
|
||||
/*
|
||||
// If no message exists fallback to plain text (T252727)
|
||||
'label' => $msgObj->exists() ? $msgObj->text() : $label,
|
||||
*/
|
||||
,Json_mustache.Add_text("label", msg)
|
||||
/*
|
||||
'list-classes' => $listClasses[$type] ?? 'vector-menu-content-list',
|
||||
*/
|
||||
,Json_mustache.Add_text("list-classes", listClasses)
|
||||
/*
|
||||
'html-items' => '',
|
||||
'is-dropdown' => $type === self::MENU_TYPE_DROPDOWN,
|
||||
*/
|
||||
,Json_mustache.Add_bool("is-dropdown", type == MENU_TYPE_DROPDOWN)
|
||||
,Json_mustache.Add_text("html-tooltip", wiki.Msg_mgr().Val_html_accesskey_and_title(plabel))
|
||||
/*
|
||||
'html-tooltip' => Linker::tooltip( 'p-' . $label ),
|
||||
];
|
||||
*/
|
||||
,Json_mustache.Add_text("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.Add(Json_mustache.Add_text("html-items", Bry_.new_u8("<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.Add(Json_mustache.Add_text("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, byte[] urls, int type, boolean setLabelToSelected) {
|
||||
boolean isPortal = type == MENU_TYPE_PORTAL;
|
||||
|
||||
byte[] listClasses;
|
||||
byte[] msg = label; // for now
|
||||
byte[] linkertooltip = Bry_.Empty;
|
||||
if (type == MENU_TYPE_DROPDOWN)
|
||||
listClasses = Bry_.new_a7("menu vector-menu-content-list");
|
||||
else
|
||||
listClasses = Bry_.new_a7("vector-menu-content-list");
|
||||
|
||||
byte[] plabel = Bry_.Add(Bry_.new_a7("p-"), label);
|
||||
Json_nde props = new Json_nde(null, -1);
|
||||
props.Add_many(
|
||||
Json_mustache.Add_text("id", plabel)
|
||||
,Json_mustache.Add_text("label-id", Bry_.Add(plabel, Bry_.new_a7("-label")))
|
||||
,Json_mustache.Add_text("label", msg)
|
||||
,Json_mustache.Add_text("list-classes", listClasses)
|
||||
,Json_mustache.Add_bool("is-dropdown", type == MENU_TYPE_DROPDOWN)
|
||||
,Json_mustache.Add_text("html-tooltip", wiki.Msg_mgr().Val_html_accesskey_and_title(plabel))
|
||||
,Json_mustache.Add_text("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.Add(Json_mustache.Add_text("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.Add(Json_mustache.Add_text("class", extraClasses[type]));
|
||||
return props;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,400 @@
|
||||
/* 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;
|
||||
import gplx.Bry_;
|
||||
import gplx.List_adp;
|
||||
import gplx.List_adp_;
|
||||
|
||||
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;
|
||||
import gplx.xowa.xtns.lst.Lst_pfunc_itm;
|
||||
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;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -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}}
|
Loading…
Reference in new issue