1
0
mirror of https://github.com/gnosygnu/xowa.git synced 2025-05-30 14:04:56 +00:00

Xomw: Convert XomwLinkRenderer

This commit is contained in:
gnosygnu 2017-02-24 08:38:12 -05:00
parent d8c2eaba1d
commit dc87cdcb5e
5 changed files with 344 additions and 78 deletions

View File

@ -146,16 +146,16 @@ public class XomwLinker {
text = html; // null
}
if (options.known) {
link_renderer.Make_known_link(bfr, target, text, custom_attribs, query);
link_renderer.makeKnownLink(bfr, target, text, custom_attribs, query);
}
else if (options.broken) {
link_renderer.Make_broken_link(bfr, target, text, custom_attribs, query);
link_renderer.makeBrokenLink(bfr, target, text, custom_attribs, query);
}
else if (options.no_classes) {
link_renderer.Make_preloaded_link(bfr, target, text, Bry_.Empty, custom_attribs, query);
link_renderer.makePreloadedLink(bfr, target, text, Bry_.Empty, custom_attribs, query);
}
else {
link_renderer.Make_link(bfr, target, text, Bry_.Empty, custom_attribs, query);
link_renderer.makeLink(bfr, target, text, custom_attribs, query);
}
}
@ -646,14 +646,14 @@ public class XomwLinker {
zoom_icon = Bry_.Empty;
}
else {
html_utl.Raw_element(tmp, Gfh_tag_.Bry__a
html_utl.rawElement(tmp, Gfh_tag_.Bry__a
, tmp_attribs.Clear()
.Add(Gfh_atr_.Bry__href , url)
.Add(Gfh_atr_.Bry__class, Class__internal)
.Add(Gfh_atr_.Bry__title, XomwGlobalFunctions.wfMessage(env, "thumbnail-more").text())
, Bry_.Empty);
byte[] zoom_anch = tmp.To_bry_and_clear();
html_utl.Raw_element(tmp, Gfh_tag_.Bry__div, tmp_attribs.Clear().Add(Gfh_atr_.Bry__class, Class__magnify), zoom_anch);
html_utl.rawElement(tmp, Gfh_tag_.Bry__div, tmp_attribs.Clear().Add(Gfh_atr_.Bry__class, Class__magnify), zoom_anch);
zoom_icon = tmp.To_bry_and_clear();
}
}
@ -890,7 +890,7 @@ public class XomwLinker {
// XO.MW.HOOK:LinkerMakeExternalLink
attribs.Set(Atr__href, url);
html_utl.Raw_element(bfr, Bry_.new_a7("a"), attribs, text);
html_utl.rawElement(bfr, Bry_.new_a7("a"), attribs, text);
}
// XO.MW: MW puts this function in Parser.php
private byte[] getExternalLinkRel(byte[] url, byte[] title) {

View File

@ -18,7 +18,7 @@ import gplx.core.btries.*;
public class XomwHtml {
private final Bry_bfr tmp = Bry_bfr_.New();
private final Btrie_rv trv = new Btrie_rv();
public void Raw_element(Bry_bfr bfr, byte[] element, Xomw_atr_mgr attribs, byte[] contents) {
public void rawElement(Bry_bfr bfr, byte[] element, Xomw_atr_mgr attribs, byte[] contents) {
Bry_.Lcase__all(element); // XO:lcase element
Open_element__lcased(bfr, element, attribs);

View File

@ -18,90 +18,304 @@ import gplx.langs.htmls.*;
import gplx.xowa.mediawiki.includes.htmls.*;
/* TODO.XO
* P7: $html = HtmlArmor::getHtml($text);
* P3: Get_link_url [alternate urls? EX: mw/wiki/index.php/title?]
* P3: getLinkUrl [alternate urls? EX: mw/wiki/index.php/title?]
* P2: titleFormatter->getPrefixedText [depends on redlinks]
* P1: Get_link_classes [depends on redlinks]
* P1: getLinkClasses [depends on redlinks]
*/
/**
* Class that generates HTML <a> links for pages.
*
* @see https://www.mediawiki.org/wiki/Manual:LinkRenderer
* @since 1.28
*/
public class Xomw_link_renderer {
private boolean expand_urls = false;
private final XomwHtml html_utl = new XomwHtml();
/**
* Whether to force the pretty article path
*
* @var boolean
*/
private boolean forceArticlePath = false;
/**
* A PROTO_* constant or false
*
* @var String|boolean|int
*/
private boolean expandUrls = false;
/**
* @var int
*/
private int stubThreshold = 0;
/**
* @var TitleFormatter
*/
// private $titleFormatter;
/**
* @var LinkCache
*/
// private $linkCache;
/**
* Whether to run the legacy Linker hooks
*
* @var boolean
*/
// private boolean runLegacyBeginHook = true;
private final XomwHtml html = new XomwHtml();
private final Xomw_atr_mgr attribs = new Xomw_atr_mgr();
private final List_adp tmp_merge_deleted = List_adp_.New();
private final XomwSanitizer sanitizer;
public Xomw_link_renderer(XomwSanitizer sanitizer) {
// /**
// * @param TitleFormatter $titleFormatter
// * @param LinkCache $linkCache
// */
public Xomw_link_renderer(XomwSanitizer sanitizer) { // TitleFormatter $titleFormatter, LinkCache $linkCache
// this.titleFormatter = $titleFormatter;
// this.linkCache = $linkCache;
this.sanitizer = sanitizer;
}
// XO.MW:SYNC:1.29; DATE:2017-01-31
public void Make_link(Bry_bfr bfr, XomwTitle target, byte[] text, byte[] classes, Xomw_atr_mgr extra_atrs, Xomw_qry_mgr query) {
/**
* @param boolean $force
*/
public void setForceArticlePath(boolean force) {
this.forceArticlePath = force;
}
/**
* @return boolean
*/
public boolean getForceArticlePath() {
return this.forceArticlePath;
}
/**
* @param String|boolean|int $expand A PROTO_* constant or false
*/
public void setExpandURLs(boolean expand) {
this.expandUrls = expand;
}
/**
* @return String|boolean|int a PROTO_* constant or false
*/
public boolean getExpandURLs() {
return this.expandUrls;
}
/**
* @param int $threshold
*/
public void setStubThreshold(int threshold) {
this.stubThreshold = threshold;
}
/**
* @return int
*/
public int getStubThreshold() {
return this.stubThreshold;
}
/**
* @param boolean $run
*/
// public void setRunLegacyBeginHook(boolean run) {
// this.runLegacyBeginHook = run;
// }
/**
* @param LinkTarget $target
* @param String|HtmlArmor|null $text
* @param array $extraAttribs
* @param array $query
* @return String
*/
public void makeLink(Bry_bfr bfr,
XomwTitle target, byte[] text, Xomw_atr_mgr extraAttribs, Xomw_qry_mgr query) {
// $title = Title::newFromLinkTarget($target); // does db lookup?
if (target.isKnown()) {
this.Make_known_link(bfr, target, text, extra_atrs, query);
this.makeKnownLink(bfr, target, text, extraAttribs, query);
} else {
this.Make_broken_link(bfr, target, text, extra_atrs, query);
this.makeBrokenLink(bfr, target, text, extraAttribs, query);
}
}
// If you have already looked up the proper CSS classes using LinkRenderer::getLinkClasses()
// or some other method, use this to avoid looking it up again.
// XO.MW:SYNC:1.29; DATE:2017-01-31
public void Make_preloaded_link(Bry_bfr bfr, XomwTitle target, byte[] text, byte[] classes, Xomw_atr_mgr extra_atrs, Xomw_qry_mgr query) {
// XO.MW.HOOK: $this->runBeginHook --> 'HtmlPageLinkRendererBegin', 'LinkBegin'
/**
* Get the options in the legacy format
*
* @param boolean $isKnown Whether the link is known or broken
* @return array
*/
// private function getLegacyOptions($isKnown) {
// $options = [ 'stubThreshold' => this.stubThreshold ];
// if (this.forceArticlePath) {
// $options[] = 'forcearticlepath';
// }
// if (this.expandUrls === PROTO_HTTP) {
// $options[] = 'http';
// } elseif (this.expandUrls === PROTO_HTTPS) {
// $options[] = 'https';
// }
//
// $options[] = $isKnown ? 'known' : 'broken';
//
// return $options;
// }
//
// private function runBeginHook(LinkTarget $target, &$text, &$extraAttribs, &$query, $isKnown) {
// $ret = null;
// if (!Hooks::run('HtmlPageLinkRendererBegin',
// [ $this, $target, &$text, &$extraAttribs, &$query, &$ret ])
// ) {
// return $ret;
// }
//
// // Now run the legacy hook
// return this.runLegacyBeginHook($target, $text, $extraAttribs, $query, $isKnown);
// }
//
// private function runLegacyBeginHook(LinkTarget $target, &$text, &$extraAttribs, &$query,
// $isKnown
// ) {
// if (!this.runLegacyBeginHook || !Hooks::isRegistered('LinkBegin')) {
// // Disabled, or nothing registered
// return null;
// }
//
// $realOptions = $options = this.getLegacyOptions($isKnown);
// $ret = null;
// $dummy = new DummyLinker();
// $title = Title::newFromLinkTarget($target);
// if ($text !== null) {
// $realHtml = $html = HtmlArmor::getHtml($text);
// } else {
// $realHtml = $html = null;
// }
// if (!Hooks::run('LinkBegin',
// [ $dummy, $title, &$html, &$extraAttribs, &$query, &$options, &$ret ])
// ) {
// return $ret;
// }
//
// if ($html !== null && $html !== $realHtml) {
// // &$html was modified, so re-armor it as $text
// $text = new HtmlArmor($html);
// }
//
// // Check if they changed any of the options, hopefully not!
// if ($options !== $realOptions) {
// $factory = MediaWikiServices::getInstance()->getLinkRendererFactory();
// // They did, so create a separate instance and have that take over the rest
// $newRenderer = $factory->createFromLegacyOptions($options);
// // Don't recurse the hook...
// $newRenderer->setRunLegacyBeginHook(false);
// if (in_array('known', $options, true)) {
// return $newRenderer->makeKnownLink($title, $text, $extraAttribs, $query);
// } elseif (in_array('broken', $options, true)) {
// return $newRenderer->makeBrokenLink($title, $text, $extraAttribs, $query);
// } else {
// return $newRenderer->makeLink($title, $text, $extraAttribs, $query);
// }
// }
//
// return null;
// }
target = Normalize_target(target);
byte[] url = Get_link_url(target, query);
/**
* If you have already looked up the proper CSS classes using LinkRenderer::getLinkClasses()
* or some other method, use this to avoid looking it up again.
*
* @param LinkTarget $target
* @param String|HtmlArmor|null $text
* @param String $classes CSS classes to add
* @param array $extraAttribs
* @param array $query
* @return String
*/
public void makePreloadedLink(Bry_bfr bfr,
XomwTitle target, byte[] text, byte[] classes, Xomw_atr_mgr extraAttribs, Xomw_qry_mgr query) {
// XO.MW.HOOK: this.runBeginHook --> 'HtmlPageLinkRendererBegin', 'LinkBegin'
target = this.normalizeTarget(target);
byte[] url = this.getLinkUrl(target, query);
attribs.Clear();
attribs.Add(Gfh_atr_.Bry__href, url); // XO.MW: add url 1st; MW does attribs["url", url] + attribs + extra_attribs
if (classes.length > 0) // XO.MW:do not bother adding if empty
if (classes.length > 0) // XO.MW: do not bother adding if empty
attribs.Add(Gfh_atr_.Bry__class, classes);
byte[] prefixed_text = target.getPrefixedText();
if (prefixed_text != Bry_.Empty) {
attribs.Add(Gfh_atr_.Bry__title, prefixed_text);
}
Merge_attribs(attribs, extra_atrs);
this.mergeAttribs(attribs, extraAttribs); // XO.MW: changed to not always create another array
if (text == null) {
text = this.Get_link_text(target);
text = this.getLinkText(target);
}
Build_a_element(bfr, target,text, attribs, true);
}
// XO.MW:SYNC:1.29; DATE:2017-01-31
public void Make_known_link(Bry_bfr bfr, XomwTitle target, byte[] text, Xomw_atr_mgr extra_atrs, Xomw_qry_mgr query) {
this.buildAElement(bfr, target, text, attribs, true);
}
/**
* @param LinkTarget $target
* @param String|HtmlArmor|null $text
* @param array $extraAttribs
* @param array $query
* @return String
*/
public void makeKnownLink(Bry_bfr bfr,
XomwTitle target, byte[] text, Xomw_atr_mgr extraAttribs, Xomw_qry_mgr query) {
byte[] classes = Bry_.Empty;
if (target.isExternal()) {
classes = Bry__classes__extiw;
}
byte[] colour = Get_link_classes(target);
byte[] colour = this.getLinkClasses(target);
if (colour != Bry_.Empty) {
classes = Bry_.Add(classes, Byte_ascii.Space_bry, colour);
classes = Bry_.Add(classes, Byte_ascii.Space_bry, colour); // XO.MW: also does "$classes ? implode(' ', $classes) : '',"
}
Make_preloaded_link(bfr, target, text, classes, extra_atrs, query);
this.makePreloadedLink(bfr,
target,
text,
classes,
extraAttribs,
query);
}
// XO.MW:SYNC:1.29; DATE:2017-01-31
public void Make_broken_link(Bry_bfr bfr, XomwTitle target, byte[] text, Xomw_atr_mgr extra_atrs, Xomw_qry_mgr query) {
/**
* @param LinkTarget $target
* @param String|HtmlArmor|null $text
* @param array $extraAttribs
* @param array $query
* @return String
*/
public void makeBrokenLink(Bry_bfr bfr,
XomwTitle target, byte[] text, Xomw_atr_mgr extraAttribs, Xomw_qry_mgr query) {
// XO.MW.HOOK: Run legacy hook
// We don't want to include fragments for broken links, because they
// generally make no sense.
if (target.hasFragment()) {
target = target.createFragmentTarget(target.getFragment());
target = target.createFragmentTarget(Bry_.Empty);
}
target = Normalize_target(target);
target = this.normalizeTarget(target);
if (query.action == null && target.getNamespace() != XomwDefines.NS_SPECIAL) {
query.action = Bry_.new_a7("edit");
if (!XophpUtility.isset(query.action) && target.getNamespace() != XomwDefines.NS_SPECIAL) {
query.action = Bry__action__edit;
query.redlink = 1;
}
byte[] url = Get_link_url(target, query);
byte[] url = this.getLinkUrl(target, query);
attribs.Clear();
attribs.Add(Gfh_atr_.Bry__href, url); // $attribs = ['href' => $url,] + $this->mergeAttribs($attribs, $extraAttribs);
attribs.Add(Gfh_atr_.Bry__class, Bry_.new_a7("new"));
Merge_attribs(attribs, extra_atrs);
attribs.Add(Gfh_atr_.Bry__href, url); // $attribs = ['href' => $url,] + this.mergeAttribs($attribs, $extraAttribs);
attribs.Add(Gfh_atr_.Bry__class, Bry__class__new);
// $prefixedText = $this->titleFormatter->getPrefixedText($target);
// $prefixedText = this.titleFormatter->getPrefixedText($target);
// if ($prefixedText !== '') {
// // This ends up in parser cache!
// $attribs['title'] = wfMessage('red-link-title', $prefixedText)
@ -109,25 +323,41 @@ public class Xomw_link_renderer {
// ->text();
// }
this.mergeAttribs(attribs, extraAttribs);
if (text == null) {
text = Get_link_text(target);
text = this.getLinkText(target);
}
Build_a_element(bfr, target, text, attribs, false);
this.buildAElement(bfr, target, text, attribs, false);
}
// XO.MW:SYNC:1.29; DATE:2017-01-31
private void Build_a_element(Bry_bfr bfr, XomwTitle target, byte[] text, Xomw_atr_mgr attribs, boolean is_known) {
/**
* Builds the final <a> element
*
* @param LinkTarget $target
* @param String|HtmlArmor $text
* @param array $attribs
* @param boolean $isKnown
* @return null|String
*/
private void buildAElement(Bry_bfr bfr, XomwTitle target, byte[] text, Xomw_atr_mgr attribs, boolean isKnown) {
// XO.MW.HOOK:HtmlPageLinkRendererEnd
byte[] html = text;
byte[] htmlBry = text;
// $html = HtmlArmor::getHtml($text);
// XO.MW.HOOK:LinkEnd
html_utl.Raw_element(bfr, Gfh_tag_.Bry__a, attribs, html);
html.rawElement(bfr, Gfh_tag_.Bry__a, attribs, htmlBry);
}
/**
* @param LinkTarget $target
* @return String non-escaped text
*/
// XO.MW:SYNC:1.29; DATE:2017-01-31
private byte[] Get_link_text(XomwTitle target) {
private byte[] getLinkText(XomwTitle target) {
byte[] prefixed_text = target.getPrefixedText();
// If the target is just a fragment, with no title, we return the fragment
// text. Otherwise, we return the title text itself.
@ -136,41 +366,65 @@ public class Xomw_link_renderer {
}
return prefixed_text;
}
private byte[] Get_link_url(XomwTitle target, Xomw_qry_mgr query) {
// TODO: Use a LinkTargetResolver service instead of Title
// if ($this->forceArticlePath) {
private byte[] getLinkUrl(XomwTitle target, Xomw_qry_mgr query) {
// TODO: Use a LinkTargetResolver service instead of Title
// $title = Title::newFromLinkTarget($target);
// if (this.forceArticlePath) {
// $realQuery = $query;
// $query = [];
// }
// else {
// $realQuery = [];
// }
byte[] url = target.getLinkURL(query, false, expand_urls);
byte[] url = target.getLinkURL(query, false, this.expandUrls);
// if ($this->forceArticlePath && $realQuery) {
// if (this.forceArticlePath && $realQuery) {
// $url = wfAppendQuery($url, $realQuery);
// }
return url;
}
// XO.MW:SYNC:1.29; DATE:2017-01-31
private XomwTitle Normalize_target(XomwTitle target) {
/**
* Normalizes the provided target
*
* @todo move the code from Linker actually here
* @param LinkTarget $target
* @return LinkTarget
*/
private XomwTitle normalizeTarget(XomwTitle target) {
return XomwLinker.normaliseSpecialPage(target);
}
// XO.MW:SYNC:1.29; DATE:2017-02-01
private void Merge_attribs(Xomw_atr_mgr src, Xomw_atr_mgr trg) {
// XO.MW: ignore; src is always non-null and empty; if trg exists, it will be merged below
// if (!$attribs) {return $defaults;}
/**
* Merges two sets of attributes
*
* @param array $defaults
* @param array $attribs
*
* @return array
*/
private void mergeAttribs(Xomw_atr_mgr defaults, Xomw_atr_mgr attribs) {
// XO.MW: ignore; defaults is always non-null and empty; if attribs exists, it will be merged below
// if (!$attribs) {
// return $defaults;
// }
// Merge the custom attribs with the default ones, and iterate
// over that, deleting all "false" attributes.
sanitizer.mergeAttributes(src, trg);
sanitizer.mergeAttributes(defaults, attribs);
// XO.MW:MW removes "false" values; XO removes "null" values
// XO.MW.PORTED.BGN:MW removes "false" values; XO removes "null" values
// foreach ($merged as $key => $val) {
// # A false value suppresses the attribute
// if ($val !== false) {
// $ret[$key] = $val;
// }
// }
boolean deleted = false;
int len = trg.Len();
int len = attribs.Len();
for (int i = 0; i < len; i++) {
Xomw_atr_itm trg_atr = trg.Get_at(i);
Xomw_atr_itm trg_atr = attribs.Get_at(i);
// A false value suppresses the attribute
if (trg_atr.Val() == null) {
tmp_merge_deleted.Add(trg_atr);
@ -180,26 +434,34 @@ public class Xomw_link_renderer {
if (deleted) {
len = tmp_merge_deleted.Len();
for (int i = 0; i < len; i++) {
Xomw_atr_itm atr = (Xomw_atr_itm)trg.Get_at(i);
trg.Del(atr.Key_bry());
Xomw_atr_itm atr = (Xomw_atr_itm)attribs.Get_at(i);
attribs.Del(atr.Key_bry());
}
tmp_merge_deleted.Clear();
}
// XO.MW.PORTED.END
}
public byte[] Get_link_classes(XomwTitle target) {
/**
* Return the CSS classes of a known link
*
* @param LinkTarget $target
* @return String CSS class
*/
public byte[] getLinkClasses(XomwTitle target) {
// Make sure the target is in the cache
// $id = $this->linkCache->addLinkObj($target);
// $id = this.linkCache->addLinkObj($target);
// if ($id == 0) {
// // Doesn't exist
// return '';
// }
// if ($this->linkCache->getGoodLinkFieldObj($target, 'redirect')) {
// if (this.linkCache->getGoodLinkFieldObj($target, 'redirect')) {
// Page is a redirect
// return 'mw-redirect';
// }
// elseif ($this->stubThreshold > 0 && XomwNamespace::isContent($target->getNamespace())
// && $this->linkCache->getGoodLinkFieldObj($target, 'length') < $this->stubThreshold
// elseif (this.stubThreshold > 0 && XomwNamespace::isContent($target->getNamespace())
// && this.linkCache->getGoodLinkFieldObj($target, 'length') < this.stubThreshold
// ) {
// Page is a stub
// return 'stub';
@ -207,5 +469,9 @@ public class Xomw_link_renderer {
return Bry_.Empty;
}
private static final byte[] Bry__classes__extiw = Bry_.new_a7("extiw");
private static final byte[]
Bry__classes__extiw = Bry_.new_a7("extiw")
, Bry__class__new = Bry_.new_a7("new")
, Bry__action__edit = Bry_.new_a7("edit")
;
}

View File

@ -422,7 +422,7 @@ public class XomwLinkHolderArray {
// }
// }
bfr.Add_mid(src, prv, link_bgn);
linkRenderer.Make_preloaded_link(bfr, item.Title(), item.Text(), Bry_.Empty, extraAtrs, query.Clear());
linkRenderer.makePreloadedLink(bfr, item.Title(), item.Text(), Bry_.Empty, extraAtrs, query.Clear());
cur = key_end + Gfh_tag_.Comm_end_len;
prv = cur;
}

View File

@ -814,7 +814,7 @@ public class Xomw_lnki_wkr {// THREAD.UNSAFE: caching for repeated calls
tmp.Add_bry_escape_html(inside);
text = tmp.To_bry_and_clear();
link_renderer.Make_known_link(bfr, nt, text, extra_atrs, query);
link_renderer.makeKnownLink(bfr, nt, text, extra_atrs, query);
byte[] link = bfr.To_bry_and_clear();
parser.armorLinks(bfr, link, 0, link.length);
bfr.Add(trail);