mirror of
https://github.com/gnosygnu/xowa.git
synced 2024-10-27 20:34:16 +00:00
2226 lines
81 KiB
Java
2226 lines
81 KiB
Java
/*
|
||
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.xowa.mediawiki.includes; import gplx.*;
|
||
import gplx.xowa.mediawiki.*;
|
||
import gplx.core.btries.*;
|
||
import gplx.langs.htmls.*;
|
||
import gplx.xowa.mediawiki.includes.xohtml.*; import gplx.xowa.mediawiki.includes.linkers.*; import gplx.xowa.mediawiki.includes.parsers.*;
|
||
import gplx.xowa.mediawiki.includes.filerepo.file.*; import gplx.xowa.mediawiki.includes.media.*;
|
||
import gplx.xowa.mediawiki.includes.parsers.lnkis.*;
|
||
/* TODO.XO
|
||
* thumb = $file->getUnscaledThumb(handlerParams);
|
||
* P8: wfMessage
|
||
* P7: titleFormatter->getPrefixedText
|
||
* P7: $html = HtmlArmor::getHtml($text);
|
||
*/
|
||
public class XomwLinker {
|
||
// private XomwEnv env;
|
||
private final Bry_bfr tmp = Bry_bfr_.New(), tmp_2 = Bry_bfr_.New();
|
||
private final Linker_rel_splitter splitter = new Linker_rel_splitter();
|
||
private byte[] wg_title = null;
|
||
private final Btrie_rv trv = new Btrie_rv();
|
||
private final byte[][] split_trail_rv = new byte[2][];
|
||
private Btrie_slim_mgr split_trail_trie;
|
||
private final Xomw_atr_mgr tmp_attribs = new Xomw_atr_mgr();
|
||
private final XomwHtmlTemp htmlTemp = new XomwHtmlTemp();
|
||
|
||
private static final byte[] Atr__class = Bry_.new_a7("class"), Atr__rel = Bry_.new_a7("rel"), Atr__href = Bry_.new_a7("href"), Rel__nofollow = Bry_.new_a7("nofollow");
|
||
public static final byte[]
|
||
Align__frame__center = Bry_.new_a7("center")
|
||
, Align__frame__none = Bry_.new_a7("none")
|
||
, Align__frame__right = Bry_.new_a7("right")
|
||
, Prefix__center = Bry_.new_a7("<div class=\"center\">")
|
||
, Class__internal = Bry_.new_a7("internal")
|
||
, Class__magnify = Bry_.new_a7("magnify")
|
||
, Img_class__thumbborder = Bry_.new_a7("thumbborder")
|
||
, Img_class__thumbimage = Bry_.new_a7("thumbimage")
|
||
;
|
||
private final XomwLinkRenderer link_renderer;
|
||
public XomwLinker(XomwLinkRenderer link_renderer) {
|
||
this.link_renderer = link_renderer;
|
||
}
|
||
public void Init_by_wiki(XomwEnv env, Btrie_slim_mgr trie) {
|
||
// this.env = env;
|
||
this.split_trail_trie = trie;
|
||
}
|
||
// /**
|
||
// * Flags for userToolLinks()
|
||
// */
|
||
// static final TOOL_LINKS_NOBLOCK = 1;
|
||
// static final TOOL_LINKS_EMAIL = 2;
|
||
//
|
||
// /**
|
||
// * Return the CSS colour of a known link
|
||
// *
|
||
// * @deprecated since 1.28, use LinkRenderer::getLinkClasses() instead
|
||
// *
|
||
// * @since 1.16.3
|
||
// * @param LinkTarget $t
|
||
// * @param int $threshold User defined threshold
|
||
// * @return String CSS class
|
||
// */
|
||
// public static function getLinkColour( LinkTarget $t, $threshold ) {
|
||
// wfDeprecated( __METHOD__, '1.28' );
|
||
// $services = MediaWikiServices::getInstance();
|
||
// $linkRenderer = $services->getLinkRenderer();
|
||
// if ( $threshold !== $linkRenderer->getStubThreshold() ) {
|
||
// // Need to create a new instance with the right stub threshold...
|
||
// $linkRenderer = $services->getLinkRendererFactory()->create();
|
||
// $linkRenderer->setStubThreshold( $threshold );
|
||
// }
|
||
//
|
||
// return $linkRenderer->getLinkClasses( $t );
|
||
// }
|
||
// This function returns an HTML link to the given target. It serves a few
|
||
// purposes:
|
||
// 1) If $target is a Title, the correct URL to link to will be figured
|
||
// out automatically.
|
||
// 2) It automatically adds the usual classes for various types of link
|
||
// targets: "new" for red links, "stub" for short articles, etc.
|
||
// 3) It escapes all attribute values safely so there's no risk of XSS.
|
||
// 4) It provides a default tooltip if the target is a Title (the page
|
||
// name of the target).
|
||
// link() replaces the old functions in the makeLink() family.
|
||
//
|
||
// @since 1.18 Method exists since 1.16 as non-static, made static in 1.18.
|
||
// @deprecated since 1.28, use MediaWiki\Linker\LinkRenderer instead
|
||
//
|
||
// @param Title $target Can currently only be a Title, but this may
|
||
// change to support Images, literal URLs, etc.
|
||
// @param String $html The HTML contents of the <a> element, i.e.,
|
||
// the link text. This is raw HTML and will not be escaped. If null,
|
||
// defaults to the prefixed text of the Title; or if the Title is just a
|
||
// fragment, the contents of the fragment.
|
||
// @param array $customAttribs A key => value array of extra HTML attributes,
|
||
// such as title and class. (href is ignored.) Classes will be
|
||
// merged with the default classes, while other attributes will replace
|
||
// default attributes. All passed attribute values will be HTML-escaped.
|
||
// A false attribute value means to suppress that attribute.
|
||
// @param array $query The query String to append to the URL
|
||
// you're linking to, in key => value array form. Query keys and values
|
||
// will be URL-encoded.
|
||
// @param String|array $options String or array of strings:
|
||
// 'known': Page is known to exist, so don't check if it does.
|
||
// 'broken': Page is known not to exist, so don't check if it does.
|
||
// 'noclasses': Don't add any classes automatically (includes "new",
|
||
// "stub", "mw-redirect", "extiw"). Only use the class attribute
|
||
// provided, if any, so you get a simple blue link with no funny i-
|
||
// cons.
|
||
// 'forcearticlepath': Use the article path always, even with a querystring.
|
||
// Has compatibility issues on some setups, so avoid wherever possible.
|
||
// 'http': Force a full URL with http:// as the scheme.
|
||
// 'https': Force a full URL with https:// as the scheme.
|
||
// 'stubThreshold' => (int): Stub threshold to use when determining link classes.
|
||
// @return String HTML <a> attribute
|
||
public void Link(Bry_bfr bfr, XomwTitleOld target, byte[] html, Xomw_atr_mgr custom_attribs, Xomw_qry_mgr query, Xomw_opt_mgr options) {
|
||
// XO.MW.UNSUPPORTED:MW has different renderers -- presumably for forcing "https:" and others; XO only has one
|
||
//if (options != null) {
|
||
// // Custom options, create new LinkRenderer
|
||
// if (!isset($options['stubThreshold'])) {
|
||
// $defaultLinkRenderer = $services->getLinkRenderer();
|
||
// $options['stubThreshold'] = $defaultLinkRenderer->getStubThreshold();
|
||
// }
|
||
// $linkRenderer = $services->getLinkRendererFactory()->createFromLegacyOptions($options);
|
||
//}
|
||
//else {
|
||
// $linkRenderer = $services->getLinkRenderer();
|
||
//}
|
||
|
||
byte[] text = null;
|
||
if (html != null) {
|
||
// $text = new HtmlArmor($html);
|
||
}
|
||
else {
|
||
text = html; // null
|
||
}
|
||
if (options.known) {
|
||
link_renderer.makeKnownLink(bfr, target, text, custom_attribs, query);
|
||
}
|
||
else if (options.broken) {
|
||
link_renderer.makeBrokenLink(bfr, target, text, custom_attribs, query);
|
||
}
|
||
else if (options.no_classes) {
|
||
link_renderer.makePreloadedLink(bfr, target, text, Bry_.Empty, custom_attribs, query);
|
||
}
|
||
else {
|
||
link_renderer.makeLink(bfr, target, text, custom_attribs, query);
|
||
}
|
||
}
|
||
|
||
// /**
|
||
// * Identical to link(), except $options defaults to 'known'.
|
||
// *
|
||
// * @since 1.16.3
|
||
// * @deprecated since 1.28, use MediaWiki\Linker\LinkRenderer instead
|
||
// * @see Linker::link
|
||
// * @return String
|
||
// */
|
||
// public static function linkKnown(
|
||
// $target, $html = null, $customAttribs = [],
|
||
// $query = [], $options = [ 'known' ]
|
||
// ) {
|
||
// return self::link( $target, $html, $customAttribs, $query, $options );
|
||
// }
|
||
|
||
/**
|
||
* Make appropriate markup for a link to the current article. This is
|
||
* currently rendered as the bold link text. The calling sequence is the
|
||
* same as the other make*LinkObj static functions, despite $query not
|
||
* being used.
|
||
*
|
||
* @since 1.16.3
|
||
* @param Title $nt
|
||
* @param String $html [optional]
|
||
* @param String $query [optional]
|
||
* @param String $trail [optional]
|
||
* @param String $prefix [optional]
|
||
*
|
||
* @return String
|
||
*/
|
||
// XO.MW:SYNC:1.29; DATE:2017-02-08
|
||
public void makeSelfLinkObj(Bry_bfr bfr, XomwTitleOld nt, byte[] html, byte[] query, byte[] trail, byte[] prefix) {
|
||
// MW.HOOK:SelfLinkBegin
|
||
if (html == Bry_.Empty) {
|
||
html = tmp.Add_bry_escape_html(nt.getPrefixedText()).To_bry_and_clear();
|
||
}
|
||
byte[] inside = Bry_.Empty;
|
||
byte[][] split_trail = splitTrail(trail);
|
||
inside = split_trail[0];
|
||
trail = split_trail[1];
|
||
bfr.Add_str_a7("<strong class=\"selflink\">");
|
||
bfr.Add_bry_many(prefix, html, inside);
|
||
bfr.Add_str_a7("</strong>");
|
||
bfr.Add(trail);
|
||
}
|
||
|
||
// /**
|
||
// * Get a message saying that an invalid title was encountered.
|
||
// * This should be called after a method like Title::makeTitleSafe() returned
|
||
// * a value indicating that the title Object is invalid.
|
||
// *
|
||
// * @param IContextSource $context Context to use to get the messages
|
||
// * @param int $namespace Namespace number
|
||
// * @param String $title Text of the title, without the namespace part
|
||
// * @return String
|
||
// */
|
||
// public static function getInvalidTitleDescription( IContextSource $context, $namespace, $title ) {
|
||
// global $wgContLang;
|
||
//
|
||
// // First we check whether the namespace exists or not.
|
||
// if ( XomwNamespace::exists( $namespace ) ) {
|
||
// if ( $namespace == NS_MAIN ) {
|
||
// $name = $context->msg( 'blanknamespace' )->text();
|
||
// } else {
|
||
// $name = $wgContLang->getFormattedNsText( $namespace );
|
||
// }
|
||
// return $context->msg( 'invalidtitle-knownnamespace', $namespace, $name, $title )->text();
|
||
// } else {
|
||
// return $context->msg( 'invalidtitle-unknownnamespace', $namespace, $title )->text();
|
||
// }
|
||
// }
|
||
//
|
||
// /**
|
||
// * @since 1.16.3
|
||
// * @param LinkTarget $target
|
||
// * @return LinkTarget
|
||
// */
|
||
public static XomwTitleOld normaliseSpecialPage(XomwTitleOld target) {
|
||
// if (target.Ns().Id_is_special() && !target.Is_external()) {
|
||
// list($name, $subpage) = SpecialPageFactory::resolveAlias($target->getDBkey());
|
||
// if (!$name) {
|
||
// return $target;
|
||
// }
|
||
// $ret = SpecialPage::getTitleValueFor($name, $subpage, $target->getFragment());
|
||
// return $ret;
|
||
// }
|
||
// else {
|
||
return target;
|
||
// }
|
||
}
|
||
|
||
// /**
|
||
// * Returns the filename part of an url.
|
||
// * Used as alternative text for external images.
|
||
// *
|
||
// * @param String $url
|
||
// *
|
||
// * @return String
|
||
// */
|
||
// private static function fnamePart( $url ) {
|
||
// $basename = strrchr( $url, '/' );
|
||
// if ( false === $basename ) {
|
||
// $basename = $url;
|
||
// } else {
|
||
// $basename = substr( $basename, 1 );
|
||
// }
|
||
// return $basename;
|
||
// }
|
||
//
|
||
// /**
|
||
// * Return the code for images which were added via external links,
|
||
// * via Parser::maybeMakeExternalImage().
|
||
// *
|
||
// * @since 1.16.3
|
||
// * @param String $url
|
||
// * @param String $alt
|
||
// *
|
||
// * @return String
|
||
// */
|
||
// public static function makeExternalImage( $url, $alt = '' ) {
|
||
// if ( $alt == '' ) {
|
||
// $alt = self::fnamePart( $url );
|
||
// }
|
||
// $img = '';
|
||
// $success = Hooks::run( 'LinkerMakeExternalImage', [ &$url, &$alt, &$img ] );
|
||
// if ( !$success ) {
|
||
// wfDebug( "Hook LinkerMakeExternalImage changed the output of external image "
|
||
// . "with url {$url} and alt text {$alt} to {$img}\n", true );
|
||
// return $img;
|
||
// }
|
||
// return Html::element( 'img',
|
||
// [
|
||
// 'src' => $url,
|
||
// 'alt' => $alt ] );
|
||
// }
|
||
|
||
|
||
// Given parameters derived from [[Image:Foo|options...]], generate the
|
||
// HTML that that syntax inserts in the page.
|
||
//
|
||
// @param Parser $parser
|
||
// @param Title $title Title Object of the file (not the currently viewed page)
|
||
// @param File $file File Object, or false if it doesn't exist
|
||
// @param array frameParams Associative array of parameters external to the media handler.
|
||
// Boolean parameters are indicated by presence or absence, the value is arbitrary and
|
||
// will often be false.
|
||
// thumbnail If present, downscale and frame
|
||
// manual_thumb Image name to use as a thumbnail, instead of automatic scaling
|
||
// framed Shows image in original size in a frame
|
||
// frameless Downscale but don't frame
|
||
// upright If present, tweak default sizes for portrait orientation
|
||
// upright_factor Fudge factor for "upright" tweak (default 0.75)
|
||
// border If present, show a border around the image
|
||
// align Horizontal alignment (left, right, center, none)
|
||
// valign Vertical alignment (baseline, sub, super, top, text-top, middle,
|
||
// bottom, text-bottom)
|
||
// alt Alternate text for image (i.e. alt attribute). Plain text.
|
||
// class HTML for image classes. Plain text.
|
||
// caption HTML for image caption.
|
||
// link-url URL to link to
|
||
// link-title Title Object to link to
|
||
// link-target Value for the target attribute, only with link-url
|
||
// no-link Boolean, suppress description link
|
||
//
|
||
// @param array handlerParams Associative array of media handler parameters, to be passed
|
||
// to transform(). Typical keys are "width" and "page".
|
||
// @param String|boolean $time Timestamp of the file, set as false for current
|
||
// @param String $query Query params for desc url
|
||
// @param int|null width_option Used by the parser to remember the user preference thumbnailsize
|
||
// @since 1.20
|
||
// @return String HTML for an image, with links, wrappers, etc.
|
||
// XO.MW:SYNC:1.29; DATE:2017-02-08
|
||
public void makeImageLink(Bry_bfr bfr, XomwEnv env, XomwParserCtx pctx, XomwParserIface parser, XomwTitleOld title, XomwFile file, Xomw_params_frame frameParams, Xomw_params_handler handlerParams, Object time, byte[] query, int widthOption) {
|
||
// XO.MW.HOOK:ImageBeforeProduceHTML
|
||
|
||
if (file != null && !file.allowInlineDisplay()) {
|
||
// this.Link(bfr, title, Bry_.Empty, tmp_attribs, tmp_query, tmp_options);
|
||
return;
|
||
}
|
||
|
||
// Clean up parameters
|
||
int page = handlerParams.page;
|
||
if (!XophpObject_.isset(frameParams.align)) {
|
||
frameParams.align = Bry_.Empty;
|
||
}
|
||
if (!XophpObject_.isset(frameParams.alt)) {
|
||
frameParams.alt = Bry_.Empty;
|
||
}
|
||
if (!XophpObject_.isset(frameParams.title)) {
|
||
frameParams.title = Bry_.Empty;
|
||
}
|
||
if (!XophpObject_.isset(frameParams.cls)) {
|
||
frameParams.cls = Bry_.Empty;
|
||
}
|
||
|
||
byte[] prefix = Bry_.Empty; byte[] postfix = Bry_.Empty;
|
||
|
||
if (Bry_.Eq(Align__frame__center, frameParams.align)) {
|
||
prefix = Prefix__center;
|
||
postfix = Gfh_tag_.Div_rhs;
|
||
frameParams.align = Align__frame__none;
|
||
}
|
||
if (file != null && !XophpObject_.isset(handlerParams.width)) {
|
||
if (XophpObject_.isset(handlerParams.height) && file.isVectorized()) {
|
||
// If its a vector image, and user only specifies height
|
||
// we don't want it to be limited by its "normal" width.
|
||
handlerParams.width = env.Global__wgSVGMaxSize;
|
||
}
|
||
else {
|
||
handlerParams.width = file.getWidth(page);
|
||
}
|
||
|
||
if ( XophpObject_.isset(frameParams.thumbnail)
|
||
|| XophpObject_.isset(frameParams.manualthumb)
|
||
|| XophpObject_.isset(frameParams.framed)
|
||
|| XophpObject_.isset(frameParams.frameless)
|
||
|| !XophpObject_.istrue(handlerParams.width)
|
||
) {
|
||
if (widthOption == XophpObject_.NULL_INT) { // XO.MW: MW does extra validation that widthOption is in array; ("!isset( $wgThumbLimits[$widthOption] )")
|
||
widthOption = env.User__default__thumbsize;
|
||
}
|
||
|
||
// Reduce width for upright images when parameter 'upright' is used
|
||
if (frameParams.upright == 0) {
|
||
frameParams.upright = env.Global__wgThumbUpright;
|
||
}
|
||
|
||
// For caching health: If width scaled down due to upright
|
||
// parameter, round to full __0 pixel to avoid the creation of a
|
||
// lot of odd thumbs.
|
||
int prefWidth = XophpObject_.isset(frameParams.upright) ?
|
||
(int)XophpMath_.round(widthOption * frameParams.upright, -1) :
|
||
widthOption;
|
||
|
||
// Use width which is smaller: real image width or user preference width
|
||
// Unless image is scalable vector.
|
||
if (handlerParams.height == XophpObject_.NULL_INT && handlerParams.width <= 0 ||
|
||
prefWidth < handlerParams.width || file.isVectorized()) {
|
||
handlerParams.width = prefWidth;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (frameParams.thumbnail != null || frameParams.manualthumb != null
|
||
|| frameParams.framed != null
|
||
) {
|
||
// Create a thumbnail. Alignment depends on the writing direction of
|
||
// the page content language (right-aligned for LTR languages,
|
||
// left-aligned for RTL languages)
|
||
// If a thumbnail width has not been provided, it is set
|
||
// to the default user option as specified in Language*.php
|
||
if (frameParams.align == Bry_.Empty) {
|
||
frameParams.align = env.Lang__align_end;
|
||
}
|
||
bfr.Add(prefix);
|
||
makeThumbLink2(bfr, env, pctx, title, file, frameParams, handlerParams, time, query);
|
||
bfr.Add(postfix);
|
||
return;
|
||
}
|
||
|
||
if (file != null && frameParams.frameless != null) {
|
||
int srcWidth = file.getWidth(page);
|
||
// For "frameless" option: do not present an image bigger than the
|
||
// source (for bitmap-style images). This is the same behavior as the
|
||
// "thumb" option does it already.
|
||
if (XophpObject_.istrue(srcWidth) && !file.mustRender() && handlerParams.width > srcWidth) {
|
||
handlerParams.width = srcWidth;
|
||
}
|
||
}
|
||
|
||
XomwMediaTransformOutput thumb = null;
|
||
if (file != null && XophpObject_.isset(handlerParams.width)) {
|
||
// Create a resized image, without the additional thumbnail features
|
||
thumb = file.transform(handlerParams);
|
||
}
|
||
else {
|
||
thumb = null;
|
||
}
|
||
|
||
byte[] s = null;
|
||
if (thumb == null) {
|
||
// $s = self::makeBrokenImageLinkObj($title, frameParams['title'], '', '', '', $time == true);
|
||
s = Bry_.Empty;
|
||
}
|
||
else {
|
||
// self::processResponsiveImages($file, $thumb, handlerParams);
|
||
Xomw_params_mto prms = pctx.Linker__makeImageLink__prms.Clear();
|
||
prms.alt = frameParams.alt;
|
||
prms.title = frameParams.title;
|
||
prms.valign = frameParams.valign;
|
||
prms.img_cls = frameParams.cls;
|
||
if (frameParams.border != null) {
|
||
prms.img_cls = Xomw_params_frame.Cls_add(prms.img_cls, Img_class__thumbborder);
|
||
}
|
||
getImageLinkMTOParams(prms, frameParams, query, parser);
|
||
|
||
thumb.toHtml(tmp, tmp_2, prms);
|
||
s = tmp.To_bry_and_clear();
|
||
}
|
||
if (frameParams.align != Bry_.Empty) {
|
||
tmp.Add_str_a7("<div class=\"float").Add(frameParams.align);
|
||
tmp.Add(s);
|
||
tmp.Add_str_a7("\">");
|
||
tmp.Add_str_a7("</div>");
|
||
s = tmp.To_bry_and_clear();
|
||
}
|
||
|
||
// XO.MW: "str_replace("\n", ' ', prefix . $s . postfix);"
|
||
int rv_bgn = bfr.Len();
|
||
bfr.Add(prefix);
|
||
bfr.Add(s);
|
||
bfr.Add(postfix);
|
||
Bry_.Replace_all_direct(bfr.Bfr(), Byte_ascii.Nl, Byte_ascii.Space, rv_bgn, bfr.Len());
|
||
}
|
||
// Get the link parameters for MediaTransformOutput::toHtml() from given
|
||
// frame parameters supplied by the Parser.
|
||
// @param array $frameParams The frame parameters
|
||
// @param String $query An optional query String to add to description page links
|
||
// @param Parser|null $parser
|
||
// @return array
|
||
// XO.MW:SYNC:1.29; DATE:2017-02-08
|
||
private static void getImageLinkMTOParams(Xomw_params_mto rv, Xomw_params_frame frameParams, byte[] query, XomwParserIface parser) {
|
||
if (XophpObject_.isset(frameParams.link_url) && frameParams.link_url != Bry_.Empty) {
|
||
rv.custom_url_link = frameParams.link_url;
|
||
if (XophpObject_.isset(frameParams.link_target)) {
|
||
rv.custom_target_link = frameParams.link_target;
|
||
}
|
||
if (parser != null) {
|
||
// extLinkAttrs = parser->getExternalLinkAttribs(frameParams['link-url']);
|
||
// foreach (extLinkAttrs as name => val) {
|
||
// // Currently could include 'rel' and 'target'
|
||
// rv['parser-extlink-' . name] = val;
|
||
// }
|
||
}
|
||
}
|
||
else if (XophpObject_.isset(frameParams.link_title) && frameParams.link_title != Bry_.Empty) {
|
||
// rv.custom_title_link = Title::newFromLinkTarget(Normalize_speecial_page(frameParams.link_title));
|
||
}
|
||
else if (!XophpObject_.empty(frameParams.no_link)) {
|
||
// No link
|
||
}
|
||
else {
|
||
rv.desc_link = true;
|
||
rv.desc_query = query;
|
||
}
|
||
}
|
||
|
||
// // Make HTML for a thumbnail including image, border and caption
|
||
// public static function makeThumbLinkObj(Title $title, $file, $label = '', $alt,
|
||
// $align = 'right', $params = [], $framed = false, $manual_thumb = ""
|
||
// ) {
|
||
// frameParams = [
|
||
// 'alt' => $alt,
|
||
// 'caption' => $label,
|
||
// 'align' => $align
|
||
// ];
|
||
// if ($framed) {
|
||
// frameParams['framed'] = true;
|
||
// }
|
||
// if ($manual_thumb) {
|
||
// frameParams['manual_thumb'] = $manual_thumb;
|
||
// }
|
||
// return self::makeThumbLink2($title, $file, frameParams, $params);
|
||
// }
|
||
|
||
/**
|
||
* @param Title $title
|
||
* @param File $file
|
||
* @param array $frameParams
|
||
* @param array $handlerParams
|
||
* @param boolean $time
|
||
* @param String $query
|
||
* @return String
|
||
*/
|
||
// XO.MW:SYNC:1.29; DATE:2017-02-08
|
||
private void makeThumbLink2(Bry_bfr bfr, XomwEnv env, XomwParserCtx pctx, XomwTitleOld title, XomwFile file, Xomw_params_frame frameParams, Xomw_params_handler handlerParams, Object time, byte[] query) {
|
||
boolean exists = file != null && file.exists();
|
||
|
||
int page = handlerParams.page;
|
||
if (!XophpObject_.isset(frameParams.align)) {
|
||
frameParams.align = Align__frame__right;
|
||
}
|
||
if (!XophpObject_.isset(frameParams.alt)) {
|
||
frameParams.alt = Bry_.Empty;
|
||
}
|
||
if (!XophpObject_.isset(frameParams.title)) {
|
||
frameParams.title = Bry_.Empty;
|
||
}
|
||
if (!XophpObject_.isset(frameParams.caption)) {
|
||
frameParams.caption = Bry_.Empty;
|
||
}
|
||
|
||
if (XophpObject_.empty(handlerParams.width)) {
|
||
// Reduce width for upright images when parameter 'upright' is used
|
||
handlerParams.width = XophpObject_.isset(frameParams.upright) ? 130 : 180;
|
||
}
|
||
XomwMediaTransformOutput thumb = null;
|
||
boolean noscale = false;
|
||
boolean manualthumb = false;
|
||
|
||
int outerWidth = 0;
|
||
if (!exists) {
|
||
outerWidth = handlerParams.width + 2;
|
||
}
|
||
else {
|
||
if (XophpObject_.isset(frameParams.manualthumb)) {
|
||
// Use manually specified thumbnail
|
||
// $manual_title = Title::makeTitleSafe(NS_FILE, frameParams['manualthumb']);
|
||
// if ($manual_title) {
|
||
// $manual_img = wfFindFile($manual_title);
|
||
// if ($manual_img) {
|
||
// thumb = $manual_img->getUnscaledThumb(handlerParams);
|
||
// manualthumb = true;
|
||
// } else {
|
||
// exists = false;
|
||
// }
|
||
// }
|
||
}
|
||
else if (XophpObject_.isset(frameParams.framed)) {
|
||
// Use image dimensions, don't scale
|
||
// thumb = $file->getUnscaledThumb(handlerParams);
|
||
thumb = new XomwThumbnailImage(file, file.getUrl(), file.getUrl(), file.getWidth(), file.getHeight());
|
||
noscale = true;
|
||
}
|
||
else {
|
||
// Do not present an image bigger than the source, for bitmap-style images
|
||
// This is a hack to maintain compatibility with arbitrary pre-1.10 behavior
|
||
int srcWidth = file.getWidth(page);
|
||
if (XophpObject_.istrue(srcWidth) && !file.mustRender() && handlerParams.width > srcWidth) {
|
||
handlerParams.width = srcWidth;
|
||
}
|
||
thumb = file.transform(handlerParams);
|
||
}
|
||
|
||
if (thumb != null) {
|
||
outerWidth = thumb.getWidth() + 2;
|
||
}
|
||
else {
|
||
outerWidth = handlerParams.width + 2;
|
||
}
|
||
}
|
||
|
||
// ThumbnailImage::toHtml() already adds page= onto the end of DjVu URLs
|
||
// So we don't need to pass it here in $query. However, the URL for the
|
||
// zoom icon still needs it, so we make a unique query for it. See bug 14771
|
||
byte[] url = title.getLocalURL(query);
|
||
// byte[] url = Bry_.Empty;
|
||
// if ($page) {
|
||
// $url = wfAppendQuery($url, [ 'page' => $page ]);
|
||
// }
|
||
if (manualthumb
|
||
&& !XophpObject_.isset(frameParams.link_title)
|
||
&& !XophpObject_.isset(frameParams.link_url)
|
||
&& !XophpObject_.isset(frameParams.no_link)
|
||
) {
|
||
frameParams.link_url = url;
|
||
}
|
||
|
||
int rv_bgn = bfr.Len();
|
||
bfr.Add_str_a7("<div class=\"thumb t").Add(frameParams.align)
|
||
.Add_str_a7("\"><div class=\"thumbinner\" style=\"width:").Add_int_variable(outerWidth).Add_str_a7("px;\">");
|
||
|
||
byte[] zoom_icon = Bry_.Empty;
|
||
if (!exists) {
|
||
// $s .= self::makeBrokenImageLinkObj($title, frameParams.title, '', '', '', $time == true);
|
||
zoom_icon = Bry_.Empty;
|
||
}
|
||
else if (thumb == null) {
|
||
// env.Msg_mgr().Get_by_id().Escaped();
|
||
// $s .= wfMessage('thumbnail_error', '')->escaped();
|
||
zoom_icon = Bry_.Empty;
|
||
}
|
||
else {
|
||
if (!noscale && !manualthumb) {
|
||
// self::processResponsiveImages($file, thumb, handlerParams);
|
||
}
|
||
Xomw_params_mto prms = pctx.Linker__makeImageLink__prms.Clear();
|
||
prms.alt = frameParams.alt;
|
||
prms.title = frameParams.title;
|
||
prms.img_cls = Xomw_params_frame.Cls_add(frameParams.cls, Img_class__thumbimage);
|
||
|
||
getImageLinkMTOParams(prms, frameParams, query, null);
|
||
thumb.toHtml(bfr, tmp, prms);
|
||
if (XophpObject_.isset(frameParams.framed)) {
|
||
zoom_icon = Bry_.Empty;
|
||
}
|
||
else {
|
||
XomwHtml.rawElement(tmp, htmlTemp, 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.wfMessageOld(env, "thumbnail-more").text())
|
||
, Bry_.Empty);
|
||
byte[] zoom_anch = tmp.To_bry_and_clear();
|
||
XomwHtml.rawElement(tmp, htmlTemp, Gfh_tag_.Bry__div, tmp_attribs.Clear().Add(Gfh_atr_.Bry__class, Class__magnify), zoom_anch);
|
||
zoom_icon = tmp.To_bry_and_clear();
|
||
}
|
||
}
|
||
bfr.Add_str_a7(" <div class=\"thumbcaption\">").Add(zoom_icon).Add(frameParams.caption).Add_str_a7("</div></div></div>");
|
||
Bry_.Replace_all_direct(bfr.Bfr(), Byte_ascii.Nl, Byte_ascii.Space, rv_bgn, bfr.Len()); // XO.MW:str_replace("\n", ' ', $s);
|
||
}
|
||
// /**
|
||
// * Process responsive images: add 1.5x and 2x subimages to the thumbnail, where
|
||
// * applicable.
|
||
// *
|
||
// * @param File $file
|
||
// * @param MediaTransformOutput $thumb
|
||
// * @param array $hp Image parameters
|
||
// */
|
||
// public static function processResponsiveImages( $file, $thumb, $hp ) {
|
||
// global $wgResponsiveImages;
|
||
// if ( $wgResponsiveImages && $thumb && !$thumb->isError() ) {
|
||
// $hp15 = $hp;
|
||
// $hp15['width'] = round( $hp['width'] * 1.5 );
|
||
// $hp20 = $hp;
|
||
// $hp20['width'] = $hp['width'] * 2;
|
||
// if ( isset( $hp['height'] ) ) {
|
||
// $hp15['height'] = round( $hp['height'] * 1.5 );
|
||
// $hp20['height'] = $hp['height'] * 2;
|
||
// }
|
||
//
|
||
// $thumb15 = $file->transform( $hp15 );
|
||
// $thumb20 = $file->transform( $hp20 );
|
||
// if ( $thumb15 && !$thumb15->isError() && $thumb15->getUrl() !== $thumb->getUrl() ) {
|
||
// $thumb->responsiveUrls['1.5'] = $thumb15->getUrl();
|
||
// }
|
||
// if ( $thumb20 && !$thumb20->isError() && $thumb20->getUrl() !== $thumb->getUrl() ) {
|
||
// $thumb->responsiveUrls['2'] = $thumb20->getUrl();
|
||
// }
|
||
// }
|
||
// }
|
||
//
|
||
// /**
|
||
// * Make a "broken" link to an image
|
||
// *
|
||
// * @since 1.16.3
|
||
// * @param Title $title
|
||
// * @param String $label Link label (plain text)
|
||
// * @param String $query Query String
|
||
// * @param String $unused1 Unused parameter kept for b/c
|
||
// * @param String $unused2 Unused parameter kept for b/c
|
||
// * @param boolean $time A file of a certain timestamp was requested
|
||
// * @return String
|
||
// */
|
||
// public static function makeBrokenImageLinkObj( $title, $label = '',
|
||
// $query = '', $unused1 = '', $unused2 = '', $time = false
|
||
// ) {
|
||
// if ( !$title instanceof Title ) {
|
||
// wfWarn( __METHOD__ . ': Requires $title to be a Title Object.' );
|
||
// return "<!-- ERROR -->" . htmlspecialchars( $label );
|
||
// }
|
||
//
|
||
// global $wgEnableUploads, $wgUploadMissingFileUrl, $wgUploadNavigationUrl;
|
||
// if ( $label == '' ) {
|
||
// $label = $title->getPrefixedText();
|
||
// }
|
||
// $encLabel = htmlspecialchars( $label );
|
||
// $currentExists = $time ? ( wfFindFile( $title ) != false ) : false;
|
||
//
|
||
// if ( ( $wgUploadMissingFileUrl || $wgUploadNavigationUrl || $wgEnableUploads )
|
||
// && !$currentExists
|
||
// ) {
|
||
// $redir = RepoGroup::singleton()->getLocalRepo()->checkRedirect( $title );
|
||
//
|
||
// if ( $redir ) {
|
||
// // We already know it's a redirect, so mark it
|
||
// // accordingly
|
||
// return self::link(
|
||
// $title,
|
||
// $encLabel,
|
||
// [ 'class' => 'mw-redirect' ],
|
||
// wfCgiToArray( $query ),
|
||
// [ 'known', 'noclasses' ]
|
||
// );
|
||
// }
|
||
//
|
||
// $href = self::getUploadUrl( $title, $query );
|
||
//
|
||
// return '<a href="' . htmlspecialchars( $href ) . '" class="new" title="' .
|
||
// htmlspecialchars( $title->getPrefixedText(), ENT_QUOTES ) . '">' .
|
||
// $encLabel . '</a>';
|
||
// }
|
||
//
|
||
// return self::link( $title, $encLabel, [], wfCgiToArray( $query ), [ 'known', 'noclasses' ] );
|
||
// }
|
||
//
|
||
// /**
|
||
// * Get the URL to upload a certain file
|
||
// *
|
||
// * @since 1.16.3
|
||
// * @param Title $destFile Title Object of the file to upload
|
||
// * @param String $query Urlencoded query String to prepend
|
||
// * @return String Urlencoded URL
|
||
// */
|
||
// protected static function getUploadUrl( $destFile, $query = '' ) {
|
||
// global $wgUploadMissingFileUrl, $wgUploadNavigationUrl;
|
||
// $q = 'wpDestFile=' . $destFile->getPartialURL();
|
||
// if ( $query != '' ) {
|
||
// $q .= '&' . $query;
|
||
// }
|
||
//
|
||
// if ( $wgUploadMissingFileUrl ) {
|
||
// return wfAppendQuery( $wgUploadMissingFileUrl, $q );
|
||
// } elseif ( $wgUploadNavigationUrl ) {
|
||
// return wfAppendQuery( $wgUploadNavigationUrl, $q );
|
||
// } else {
|
||
// $upload = SpecialPage::getTitleFor( 'Upload' );
|
||
// return $upload->getLocalURL( $q );
|
||
// }
|
||
// }
|
||
//
|
||
// /**
|
||
// * Create a direct link to a given uploaded file.
|
||
// *
|
||
// * @since 1.16.3
|
||
// * @param Title $title
|
||
// * @param String $html Pre-sanitized HTML
|
||
// * @param String $time MW timestamp of file creation time
|
||
// * @return String HTML
|
||
// */
|
||
// public static function makeMediaLinkObj( $title, $html = '', $time = false ) {
|
||
// $img = wfFindFile( $title, [ 'time' => $time ] );
|
||
// return self::makeMediaLinkFile( $title, $img, $html );
|
||
// }
|
||
//
|
||
// /**
|
||
// * Create a direct link to a given uploaded file.
|
||
// * This will make a broken link if $file is false.
|
||
// *
|
||
// * @since 1.16.3
|
||
// * @param Title $title
|
||
// * @param File|boolean $file File Object or false
|
||
// * @param String $html Pre-sanitized HTML
|
||
// * @return String HTML
|
||
// *
|
||
// * @todo Handle invalid or missing images better.
|
||
// */
|
||
// public static function makeMediaLinkFile( Title $title, $file, $html = '' ) {
|
||
// if ( $file && $file->exists() ) {
|
||
// $url = $file->getUrl();
|
||
// $class = '@gplx.Internal protected';
|
||
// } else {
|
||
// $url = self::getUploadUrl( $title );
|
||
// $class = 'new';
|
||
// }
|
||
//
|
||
// $alt = $title->getText();
|
||
// if ( $html == '' ) {
|
||
// $html = $alt;
|
||
// }
|
||
//
|
||
// $ret = '';
|
||
// $attribs = [
|
||
// 'href' => $url,
|
||
// 'class' => $class,
|
||
// 'title' => $alt
|
||
// ];
|
||
//
|
||
// if ( !Hooks::run( 'LinkerMakeMediaLinkFile',
|
||
// [ $title, $file, &$html, &$attribs, &$ret ] ) ) {
|
||
// wfDebug( "Hook LinkerMakeMediaLinkFile changed the output of link "
|
||
// . "with url {$url} and text {$html} to {$ret}\n", true );
|
||
// return $ret;
|
||
// }
|
||
//
|
||
// return Html::rawElement( 'a', $attribs, $html );
|
||
// }
|
||
//
|
||
// /**
|
||
// * Make a link to a special page given its name and, optionally,
|
||
// * a message key from the link text.
|
||
// * Usage example: Linker::specialLink( 'Recentchanges' )
|
||
// *
|
||
// * @since 1.16.3
|
||
// * @param String $name
|
||
// * @param String $key
|
||
// * @return String
|
||
// */
|
||
// public static function specialLink( $name, $key = '' ) {
|
||
// if ( $key == '' ) {
|
||
// $key = strtolower( $name );
|
||
// }
|
||
//
|
||
// return self::linkKnown( SpecialPage::getTitleFor( $name ), wfMessage( $key )->text() );
|
||
// }
|
||
|
||
/**
|
||
* Make an external link
|
||
* @since 1.16.3. $title added in 1.21
|
||
* @param String $url URL to link to
|
||
* @param String $text Text of link
|
||
* @param boolean $escape Do we escape the link text?
|
||
* @param String $linktype Type of external link. Gets added to the classes
|
||
* @param array $attribs Array of extra attributes to <a>
|
||
* @param Title|null $title Title Object used for title specific link attributes
|
||
* @return String
|
||
*/
|
||
// XO.MW:SYNC:1.29; DATE:2017-02-08
|
||
public void makeExternalLink(Bry_bfr bfr, byte[] url, byte[] text, boolean escape, byte[] link_type, Xomw_atr_mgr attribs, byte[] title) {
|
||
tmp.Add_str_a7("external");
|
||
if (link_type != null) {
|
||
tmp.Add_byte_space().Add(link_type);
|
||
}
|
||
Xomw_atr_itm cls_itm = attribs.Get_by_or_make(Atr__class);
|
||
if (cls_itm.Val() != null) {
|
||
tmp.Add(cls_itm.Val());
|
||
}
|
||
cls_itm.Val_(tmp.To_bry_and_clear());
|
||
|
||
if (escape) {
|
||
text = tmp.Add_bry_escape_html(text).To_bry_and_clear();
|
||
}
|
||
|
||
if (title == null)
|
||
title = wg_title;
|
||
|
||
byte[] new_rel = getExternalLinkRel(url, title);
|
||
Xomw_atr_itm cur_rel_atr = attribs.Get_by_or_make(Atr__rel);
|
||
if (cur_rel_atr.Val() == null) {
|
||
cur_rel_atr.Val_(new_rel);
|
||
}
|
||
else {
|
||
// Merge the rel attributes.
|
||
byte[] cur_rel = cur_rel_atr.Val();
|
||
Bry_split_.Split(new_rel, 0, new_rel.length, Byte_ascii.Space, Bool_.N, splitter); // $newRels = explode(' ', $newRel);
|
||
Bry_split_.Split(cur_rel, 0, cur_rel.length, Byte_ascii.Space, Bool_.N, splitter); // $oldRels = explode(' ', $attribs['rel']);
|
||
cur_rel_atr.Val_(splitter.To_bry()); // $attribs['rel'] = implode(' ', $combined);
|
||
}
|
||
// XO.MW.HOOK:LinkerMakeExternalLink
|
||
attribs.Set(Atr__href, url);
|
||
|
||
XomwHtml.rawElement(bfr, htmlTemp, Bry_.new_a7("a"), attribs, text);
|
||
}
|
||
// XO.MW: MW puts this function in Parser.php
|
||
private byte[] getExternalLinkRel(byte[] url, byte[] title) {
|
||
// global $wgNoFollowLinks, $wgNoFollowNsExceptions, $wgNoFollowDomainExceptions;
|
||
// $ns = $title ? $title->getNamespace() : false;
|
||
// if ($wgNoFollowLinks && !in_array($ns, $wgNoFollowNsExceptions)
|
||
// && !wfMatchesDomainList($url, $wgNoFollowDomainExceptions)
|
||
//) {
|
||
return Rel__nofollow;
|
||
// }
|
||
// return null;
|
||
}
|
||
// /**
|
||
// * Make user link (or user contributions for unregistered users)
|
||
// * @param int $userId User id in database.
|
||
// * @param String $userName User name in database.
|
||
// * @param String $altUserName Text to display instead of the user name (optional)
|
||
// * @return String HTML fragment
|
||
// * @since 1.16.3. $altUserName was added in 1.19.
|
||
// */
|
||
// public static function userLink( $userId, $userName, $altUserName = false ) {
|
||
// $classes = 'mw-userlink';
|
||
// if ( $userId == 0 ) {
|
||
// $page = SpecialPage::getTitleFor( 'Contributions', $userName );
|
||
// if ( $altUserName === false ) {
|
||
// $altUserName = IP::prettifyIP( $userName );
|
||
// }
|
||
// $classes .= ' mw-anonuserlink'; // Separate link class for anons (bug 43179)
|
||
// } else {
|
||
// $page = Title::makeTitle( NS_USER, $userName );
|
||
// }
|
||
//
|
||
// // Wrap the output with <bdi> tags for directionality isolation
|
||
// return self::link(
|
||
// $page,
|
||
// '<bdi>' . htmlspecialchars( $altUserName !== false ? $altUserName : $userName ) . '</bdi>',
|
||
// [ 'class' => $classes ]
|
||
// );
|
||
// }
|
||
//
|
||
// /**
|
||
// * Generate standard user tool links (talk, contributions, block link, etc.)
|
||
// *
|
||
// * @since 1.16.3
|
||
// * @param int $userId User identifier
|
||
// * @param String $userText User name or IP address
|
||
// * @param boolean $redContribsWhenNoEdits Should the contributions link be
|
||
// * red if the user has no edits?
|
||
// * @param int $flags Customisation flags (e.g. Linker::TOOL_LINKS_NOBLOCK
|
||
// * and Linker::TOOL_LINKS_EMAIL).
|
||
// * @param int $edits User edit count (optional, for performance)
|
||
// * @return String HTML fragment
|
||
// */
|
||
// public static function userToolLinks(
|
||
// $userId, $userText, $redContribsWhenNoEdits = false, $flags = 0, $edits = null
|
||
// ) {
|
||
// global $wgUser, $wgDisableAnonTalk, $wgLang;
|
||
// $talkable = !( $wgDisableAnonTalk && 0 == $userId );
|
||
// $blockable = !( $flags & self::TOOL_LINKS_NOBLOCK );
|
||
// $addEmailLink = $flags & self::TOOL_LINKS_EMAIL && $userId;
|
||
//
|
||
// $items = [];
|
||
// if ( $talkable ) {
|
||
// $items[] = self::userTalkLink( $userId, $userText );
|
||
// }
|
||
// if ( $userId ) {
|
||
// // check if the user has an edit
|
||
// $attribs = [];
|
||
// if ( $redContribsWhenNoEdits ) {
|
||
// if ( intval( $edits ) === 0 && $edits !== 0 ) {
|
||
// $user = User::newFromId( $userId );
|
||
// $edits = $user->getEditCount();
|
||
// }
|
||
// if ( $edits === 0 ) {
|
||
// $attribs['class'] = 'new';
|
||
// }
|
||
// }
|
||
// $contribsPage = SpecialPage::getTitleFor( 'Contributions', $userText );
|
||
//
|
||
// $items[] = self::link( $contribsPage, wfMessage( 'contribslink' )->escaped(), $attribs );
|
||
// }
|
||
// if ( $blockable && $wgUser->isAllowed( 'block' ) ) {
|
||
// $items[] = self::blockLink( $userId, $userText );
|
||
// }
|
||
//
|
||
// if ( $addEmailLink && $wgUser->canSendEmail() ) {
|
||
// $items[] = self::emailLink( $userId, $userText );
|
||
// }
|
||
//
|
||
// Hooks::run( 'UserToolLinksEdit', [ $userId, $userText, &$items ] );
|
||
//
|
||
// if ( $items ) {
|
||
// return wfMessage( 'word-separator' )->escaped()
|
||
// . '<span class="mw-usertoollinks">'
|
||
// . wfMessage( 'parentheses' )->rawParams( $wgLang->pipeList( $items ) )->escaped()
|
||
// . '</span>';
|
||
// } else {
|
||
// return '';
|
||
// }
|
||
// }
|
||
//
|
||
// /**
|
||
// * Alias for userToolLinks( $userId, $userText, true );
|
||
// * @since 1.16.3
|
||
// * @param int $userId User identifier
|
||
// * @param String $userText User name or IP address
|
||
// * @param int $edits User edit count (optional, for performance)
|
||
// * @return String
|
||
// */
|
||
// public static function userToolLinksRedContribs( $userId, $userText, $edits = null ) {
|
||
// return self::userToolLinks( $userId, $userText, true, 0, $edits );
|
||
// }
|
||
//
|
||
// /**
|
||
// * @since 1.16.3
|
||
// * @param int $userId User id in database.
|
||
// * @param String $userText User name in database.
|
||
// * @return String HTML fragment with user talk link
|
||
// */
|
||
// public static function userTalkLink( $userId, $userText ) {
|
||
// $userTalkPage = Title::makeTitle( NS_USER_TALK, $userText );
|
||
// $userTalkLink = self::link( $userTalkPage, wfMessage( 'talkpagelinktext' )->escaped() );
|
||
// return $userTalkLink;
|
||
// }
|
||
//
|
||
// /**
|
||
// * @since 1.16.3
|
||
// * @param int $userId Userid
|
||
// * @param String $userText User name in database.
|
||
// * @return String HTML fragment with block link
|
||
// */
|
||
// public static function blockLink( $userId, $userText ) {
|
||
// $blockPage = SpecialPage::getTitleFor( 'Block', $userText );
|
||
// $blockLink = self::link( $blockPage, wfMessage( 'blocklink' )->escaped() );
|
||
// return $blockLink;
|
||
// }
|
||
//
|
||
// /**
|
||
// * @param int $userId Userid
|
||
// * @param String $userText User name in database.
|
||
// * @return String HTML fragment with e-mail user link
|
||
// */
|
||
// public static function emailLink( $userId, $userText ) {
|
||
// $emailPage = SpecialPage::getTitleFor( 'Emailuser', $userText );
|
||
// $emailLink = self::link( $emailPage, wfMessage( 'emaillink' )->escaped() );
|
||
// return $emailLink;
|
||
// }
|
||
//
|
||
// /**
|
||
// * Generate a user link if the current user is allowed to view it
|
||
// * @since 1.16.3
|
||
// * @param Revision $rev
|
||
// * @param boolean $isPublic Show only if all users can see it
|
||
// * @return String HTML fragment
|
||
// */
|
||
// public static function revUserLink( $rev, $isPublic = false ) {
|
||
// if ( $rev->isDeleted( Revision::DELETED_USER ) && $isPublic ) {
|
||
// $link = wfMessage( 'rev-deleted-user' )->escaped();
|
||
// } elseif ( $rev->userCan( Revision::DELETED_USER ) ) {
|
||
// $link = self::userLink( $rev->getUser( Revision::FOR_THIS_USER ),
|
||
// $rev->getUserText( Revision::FOR_THIS_USER ) );
|
||
// } else {
|
||
// $link = wfMessage( 'rev-deleted-user' )->escaped();
|
||
// }
|
||
// if ( $rev->isDeleted( Revision::DELETED_USER ) ) {
|
||
// return '<span class="history-deleted">' . $link . '</span>';
|
||
// }
|
||
// return $link;
|
||
// }
|
||
//
|
||
// /**
|
||
// * Generate a user tool link cluster if the current user is allowed to view it
|
||
// * @since 1.16.3
|
||
// * @param Revision $rev
|
||
// * @param boolean $isPublic Show only if all users can see it
|
||
// * @return String HTML
|
||
// */
|
||
// public static function revUserTools( $rev, $isPublic = false ) {
|
||
// if ( $rev->isDeleted( Revision::DELETED_USER ) && $isPublic ) {
|
||
// $link = wfMessage( 'rev-deleted-user' )->escaped();
|
||
// } elseif ( $rev->userCan( Revision::DELETED_USER ) ) {
|
||
// $userId = $rev->getUser( Revision::FOR_THIS_USER );
|
||
// $userText = $rev->getUserText( Revision::FOR_THIS_USER );
|
||
// $link = self::userLink( $userId, $userText )
|
||
// . self::userToolLinks( $userId, $userText );
|
||
// } else {
|
||
// $link = wfMessage( 'rev-deleted-user' )->escaped();
|
||
// }
|
||
// if ( $rev->isDeleted( Revision::DELETED_USER ) ) {
|
||
// return ' <span class="history-deleted">' . $link . '</span>';
|
||
// }
|
||
// return $link;
|
||
// }
|
||
//
|
||
// /**
|
||
// * This function is called by all recent changes variants, by the page history,
|
||
// * and by the user contributions list. It is responsible for formatting edit
|
||
// * summaries. It escapes any HTML in the summary, but adds some CSS to format
|
||
// * auto-generated comments (from section editing) and formats [[wikilinks]].
|
||
// *
|
||
// * @author Erik Moeller <moeller@scireview.de>
|
||
// * @since 1.16.3. $wikiId added in 1.26
|
||
// *
|
||
// * Note: there's not always a title to pass to this function.
|
||
// * Since you can't set a default parameter for a reference, I've turned it
|
||
// * temporarily to a value pass. Should be adjusted further. --brion
|
||
// *
|
||
// * @param String $comment
|
||
// * @param Title|null $title Title Object (to generate link to the section in autocomment)
|
||
// * or null
|
||
// * @param boolean $local Whether section links should refer to local page
|
||
// * @param String|null $wikiId Id (as used by WikiMap) of the wiki to generate links to.
|
||
// * For use with external changes.
|
||
// *
|
||
// * @return mixed|String
|
||
// */
|
||
// public static function formatComment(
|
||
// $comment, $title = null, $local = false, $wikiId = null
|
||
// ) {
|
||
// # Sanitize text a bit:
|
||
// $comment = str_replace( "\n", " ", $comment );
|
||
// # Allow HTML entities (for bug 13815)
|
||
// $comment = Sanitizer::escapeHtmlAllowEntities( $comment );
|
||
//
|
||
// # Render autocomments and make links:
|
||
// $comment = self::formatAutocomments( $comment, $title, $local, $wikiId );
|
||
// $comment = self::formatLinksInComment( $comment, $title, $local, $wikiId );
|
||
//
|
||
// return $comment;
|
||
// }
|
||
//
|
||
// /**
|
||
// * Converts autogenerated comments in edit summaries into section links.
|
||
// *
|
||
// * The pattern for autogen comments is / * foo * /, which makes for
|
||
// * some nasty regex.
|
||
// * We look for all comments, match any text before and after the comment,
|
||
// * add a separator where needed and format the comment itself with CSS
|
||
// * Called by Linker::formatComment.
|
||
// *
|
||
// * @param String $comment Comment text
|
||
// * @param Title|null $title An optional title Object used to links to sections
|
||
// * @param boolean $local Whether section links should refer to local page
|
||
// * @param String|null $wikiId Id of the wiki to link to (if not the local wiki),
|
||
// * as used by WikiMap.
|
||
// *
|
||
// * @return String Formatted comment (wikitext)
|
||
// */
|
||
// private static function formatAutocomments(
|
||
// $comment, $title = null, $local = false, $wikiId = null
|
||
// ) {
|
||
// // @todo $append here is something of a hack to preserve the status
|
||
// // quo. Someone who knows more about bidi and such should decide
|
||
// // (1) what sane rendering even *is* for an LTR edit summary on an RTL
|
||
// // wiki, both when autocomments exist and when they don't, and
|
||
// // (2) what markup will make that actually happen.
|
||
// $append = '';
|
||
// $comment = preg_replace_callback(
|
||
// // To detect the presence of content before or after the
|
||
// // auto-comment, we use capturing groups inside optional zero-width
|
||
// // assertions. But older versions of PCRE can't directly make
|
||
// // zero-width assertions optional, so wrap them in a non-capturing
|
||
// // group.
|
||
// '!(?:(?<=(.)))?/\*\s*(.*?)\s*\*/(?:(?=(.)))?!',
|
||
// function ( $match ) use ( $title, $local, $wikiId, &$append ) {
|
||
// global $wgLang;
|
||
//
|
||
// // Ensure all match positions are defined
|
||
// $match += [ '', '', '', '' ];
|
||
//
|
||
// $pre = $match[1] !== '';
|
||
// $auto = $match[2];
|
||
// $post = $match[3] !== '';
|
||
// $comment = null;
|
||
//
|
||
// Hooks::run(
|
||
// 'FormatAutocomments',
|
||
// [ &$comment, $pre, $auto, $post, $title, $local, $wikiId ]
|
||
// );
|
||
//
|
||
// if ( $comment === null ) {
|
||
// $link = '';
|
||
// if ( $title ) {
|
||
// $section = $auto;
|
||
// # Remove links that a user may have manually put in the autosummary
|
||
// # This could be improved by copying as much of Parser::stripSectionName as desired.
|
||
// $section = str_replace( '[[:', '', $section );
|
||
// $section = str_replace( '[[', '', $section );
|
||
// $section = str_replace( ']]', '', $section );
|
||
//
|
||
// $section = Sanitizer::normalizeSectionNameWhitespace( $section ); # bug 22784
|
||
// if ( $local ) {
|
||
// $sectionTitle = Title::newFromText( '#' . $section );
|
||
// } else {
|
||
// $sectionTitle = Title::makeTitleSafe( $title->getNamespace(),
|
||
// $title->getDBkey(), $section );
|
||
// }
|
||
// if ( $sectionTitle ) {
|
||
// $link = Linker::makeCommentLink( $sectionTitle, $wgLang->getArrow(), $wikiId, 'noclasses' );
|
||
// } else {
|
||
// $link = '';
|
||
// }
|
||
// }
|
||
// if ( $pre ) {
|
||
// # written summary $presep autocomment (summary /* section */)
|
||
// $pre = wfMessage( 'autocomment-prefix' )->inContentLanguage()->escaped();
|
||
// }
|
||
// if ( $post ) {
|
||
// # autocomment $postsep written summary (/* section */ summary)
|
||
// $auto .= wfMessage( 'colon-separator' )->inContentLanguage()->escaped();
|
||
// }
|
||
// $auto = '<span class="autocomment">' . $auto . '</span>';
|
||
// $comment = $pre . $link . $wgLang->getDirMark()
|
||
// . '<span dir="auto">' . $auto;
|
||
// $append .= '</span>';
|
||
// }
|
||
// return $comment;
|
||
// },
|
||
// $comment
|
||
// );
|
||
// return $comment . $append;
|
||
// }
|
||
//
|
||
// /**
|
||
// * Formats wiki links and media links in text; all other wiki formatting
|
||
// * is ignored
|
||
// *
|
||
// * @since 1.16.3. $wikiId added in 1.26
|
||
// * @todo FIXME: Doesn't handle sub-links as in image thumb texts like the main parser
|
||
// *
|
||
// * @param String $comment Text to format links in. WARNING! Since the output of this
|
||
// * function is html, $comment must be sanitized for use as html. You probably want
|
||
// * to pass $comment through Sanitizer::escapeHtmlAllowEntities() before calling
|
||
// * this function.
|
||
// * @param Title|null $title An optional title Object used to links to sections
|
||
// * @param boolean $local Whether section links should refer to local page
|
||
// * @param String|null $wikiId Id of the wiki to link to (if not the local wiki),
|
||
// * as used by WikiMap.
|
||
// *
|
||
// * @return String
|
||
// */
|
||
// public static function formatLinksInComment(
|
||
// $comment, $title = null, $local = false, $wikiId = null
|
||
// ) {
|
||
// return preg_replace_callback(
|
||
// '/
|
||
// \[\[
|
||
// :? # ignore optional leading colon
|
||
// ([^\]|]+) # 1. link target; page names cannot include ] or |
|
||
// (?:\|
|
||
// # 2. link text
|
||
// # Stop matching at ]] without relying on backtracking.
|
||
// ((?:]?[^\]])*+)
|
||
// )?
|
||
// \]\]
|
||
// ([^[]*) # 3. link trail (the text up until the next link)
|
||
// /x',
|
||
// function ( $match ) use ( $title, $local, $wikiId ) {
|
||
// global $wgContLang;
|
||
//
|
||
// $medians = '(?:' . preg_quote( XomwNamespace::getCanonicalName( NS_MEDIA ), '/' ) . '|';
|
||
// $medians .= preg_quote( $wgContLang->getNsText( NS_MEDIA ), '/' ) . '):';
|
||
//
|
||
// $comment = $match[0];
|
||
//
|
||
// # fix up urlencoded title texts (copied from Parser::replaceInternalLinks)
|
||
// if ( strpos( $match[1], '%' ) !== false ) {
|
||
// $match[1] = strtr(
|
||
// rawurldecode( $match[1] ),
|
||
// [ '<' => '<', '>' => '>' ]
|
||
// );
|
||
// }
|
||
//
|
||
// # Handle link renaming [[foo|text]] will show link as "text"
|
||
// if ( $match[2] != "" ) {
|
||
// $text = $match[2];
|
||
// } else {
|
||
// $text = $match[1];
|
||
// }
|
||
// $submatch = [];
|
||
// $thelink = null;
|
||
// if ( preg_match( '/^' . $medians . '(.*)$/i', $match[1], $submatch ) ) {
|
||
// # Media link; trail not supported.
|
||
// $linkRegexp = '/\[\[(.*?)\]\]/';
|
||
// $title = Title::makeTitleSafe( NS_FILE, $submatch[1] );
|
||
// if ( $title ) {
|
||
// $thelink = Linker::makeMediaLinkObj( $title, $text );
|
||
// }
|
||
// } else {
|
||
// # Other kind of link
|
||
// # Make sure its target is non-empty
|
||
// if ( isset( $match[1][0] ) && $match[1][0] == ':' ) {
|
||
// $match[1] = substr( $match[1], 1 );
|
||
// }
|
||
// if ( $match[1] !== false && $match[1] !== '' ) {
|
||
// if ( preg_match( $wgContLang->linkTrail(), $match[3], $submatch ) ) {
|
||
// $trail = $submatch[1];
|
||
// } else {
|
||
// $trail = "";
|
||
// }
|
||
// $linkRegexp = '/\[\[(.*?)\]\]' . preg_quote( $trail, '/' ) . '/';
|
||
// list( $inside, $trail ) = Linker::splitTrail( $trail );
|
||
//
|
||
// $linkText = $text;
|
||
// $linkTarget = Linker::normalizeSubpageLink( $title, $match[1], $linkText );
|
||
//
|
||
// $target = Title::newFromText( $linkTarget );
|
||
// if ( $target ) {
|
||
// if ( $target->getText() == '' && !$target->isExternal()
|
||
// && !$local && $title
|
||
// ) {
|
||
// $newTarget = clone $title;
|
||
// $newTarget->setFragment( '#' . $target->getFragment() );
|
||
// $target = $newTarget;
|
||
// }
|
||
//
|
||
// $thelink = Linker::makeCommentLink( $target, $linkText . $inside, $wikiId ) . $trail;
|
||
// }
|
||
// }
|
||
// }
|
||
// if ( $thelink ) {
|
||
// // If the link is still valid, go ahead and replace it in!
|
||
// $comment = preg_replace(
|
||
// $linkRegexp,
|
||
// StringUtils::escapeRegexReplacement( $thelink ),
|
||
// $comment,
|
||
// 1
|
||
// );
|
||
// }
|
||
//
|
||
// return $comment;
|
||
// },
|
||
// $comment
|
||
// );
|
||
// }
|
||
//
|
||
// /**
|
||
// * Generates a link to the given Title
|
||
// *
|
||
// * @note This is only public for technical reasons. It's not intended for use outside Linker.
|
||
// *
|
||
// * @param Title $title
|
||
// * @param String $text
|
||
// * @param String|null $wikiId Id of the wiki to link to (if not the local wiki),
|
||
// * as used by WikiMap.
|
||
// * @param String|String[] $options See the $options parameter in Linker::link.
|
||
// *
|
||
// * @return String HTML link
|
||
// */
|
||
// public static function makeCommentLink(
|
||
// Title $title, $text, $wikiId = null, $options = []
|
||
// ) {
|
||
// if ( $wikiId !== null && !$title->isExternal() ) {
|
||
// $link = Linker::makeExternalLink(
|
||
// WikiMap::getForeignURL(
|
||
// $wikiId,
|
||
// $title->getPrefixedText(),
|
||
// $title->getFragment()
|
||
// ),
|
||
// $text,
|
||
// /* escape = */ false // Already escaped
|
||
// );
|
||
// } else {
|
||
// $link = Linker::link( $title, $text, [], [], $options );
|
||
// }
|
||
//
|
||
// return $link;
|
||
// }
|
||
|
||
/**
|
||
* @param Title $contextTitle
|
||
* @param String $target
|
||
* @param String $text
|
||
* @return String
|
||
*/
|
||
// XO.MW:SYNC:1.29; DATE:2017-02-08
|
||
public void normalizeSubpageLink(XomwLinker_NormalizeSubpageLink rv, XomwTitleOld context_title, byte[] target, byte[] text) {
|
||
// Valid link forms:
|
||
// Foobar -- normal
|
||
// :Foobar -- override special treatment of prefix (images, language links)
|
||
// /Foobar -- convert to CurrentPage/Foobar
|
||
// /Foobar/ -- convert to CurrentPage/Foobar, strip the initial and final / from text
|
||
// ../ -- convert to CurrentPage, from CurrentPage/CurrentSubPage
|
||
// ../Foobar -- convert to CurrentPage/Foobar,
|
||
// (from CurrentPage/CurrentSubPage)
|
||
// ../Foobar/ -- convert to CurrentPage/Foobar, use 'Foobar' as text
|
||
// (from CurrentPage/CurrentSubPage)
|
||
|
||
byte[] ret = target; // default return value is no change
|
||
|
||
// Some namespaces don't allow subpages,
|
||
// so only perform processing if subpages are allowed
|
||
if (context_title != null) {// && context_title.Ns().Subpages_enabled()) {
|
||
int hash = Bry_find_.Find_fwd(target, Byte_ascii.Hash);
|
||
byte[] suffix = null;
|
||
if (hash != Bry_find_.Not_found) {
|
||
suffix = Bry_.Mid(target, hash);
|
||
target = Bry_.Mid(target, 0, hash);
|
||
}
|
||
else {
|
||
suffix = Bry_.Empty;
|
||
}
|
||
// bug 7425
|
||
target = Bry_.Trim(target);
|
||
// Look at the first character
|
||
if (target != Bry_.Empty && target[0] == Byte_ascii.Slash) {
|
||
// / at end means we don't want the slash to be shown
|
||
int target_len = target.length;
|
||
int trailing_slashes_bgn = Bry_find_.Find_bwd_while(target, target_len, 0, Byte_ascii.Slash) + 1;
|
||
byte[] no_slash = null;
|
||
if (trailing_slashes_bgn != target_len) {
|
||
no_slash = target = Bry_.Mid(target, 1, trailing_slashes_bgn);
|
||
}
|
||
else {
|
||
no_slash = Bry_.Mid(target, 1);
|
||
}
|
||
|
||
ret = Bry_.Add(context_title.getPrefixedText(), Byte_ascii.Slash_bry, Bry_.Trim(no_slash), suffix);
|
||
if (text == Bry_.Empty) {
|
||
text = Bry_.Add(target, suffix);
|
||
} // this might be changed for ugliness reasons
|
||
}
|
||
else {
|
||
// check for .. subpage backlinks
|
||
int dot2_count = 0;
|
||
byte[] dot2_stripped = target;
|
||
while (Bry_.Match(dot2_stripped, 0, 3, Bry__dot2)) {
|
||
++dot2_count;
|
||
dot2_stripped = Bry_.Mid(dot2_stripped, 3);
|
||
}
|
||
if (dot2_count > 0) {
|
||
byte[][] exploded = Bry_split_.Split(context_title.getPrefixedText(), Byte_ascii.Slash);
|
||
int exploded_len = exploded.length;
|
||
if (exploded_len > dot2_count) { // not allowed to go below top level page
|
||
// PORTED: ret = implode('/', array_slice($exploded, 0, -dot2_count));
|
||
int implode_len = exploded_len - dot2_count;
|
||
for (int i = 0; i < implode_len; i++) {
|
||
if (i != 0) tmp.Add_byte(Byte_ascii.Slash);
|
||
tmp.Add(exploded[i]);
|
||
}
|
||
// / at the end means don't show full path
|
||
if (Bry_.Has_at_end(dot2_stripped, Byte_ascii.Slash)) {
|
||
dot2_stripped = Bry_.Mid(dot2_stripped, 0, dot2_stripped.length - 1);
|
||
if (text == Bry_.Empty) {
|
||
text = Bry_.Add(dot2_stripped, suffix);
|
||
}
|
||
}
|
||
dot2_stripped = Bry_.Trim(dot2_stripped);
|
||
if (dot2_stripped != Bry_.Empty) {
|
||
tmp.Add_bry_many(Byte_ascii.Slash_bry, dot2_stripped);
|
||
}
|
||
tmp.Add(suffix);
|
||
ret = tmp.To_bry_and_clear();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
rv.Init(ret, text);
|
||
}
|
||
// /**
|
||
// * Wrap a comment in standard punctuation and formatting if
|
||
// * it's non-empty, otherwise return empty String.
|
||
// *
|
||
// * @since 1.16.3. $wikiId added in 1.26
|
||
// * @param String $comment
|
||
// * @param Title|null $title Title Object (to generate link to section in autocomment) or null
|
||
// * @param boolean $local Whether section links should refer to local page
|
||
// * @param String|null $wikiId Id (as used by WikiMap) of the wiki to generate links to.
|
||
// * For use with external changes.
|
||
// *
|
||
// * @return String
|
||
// */
|
||
// public static function commentBlock(
|
||
// $comment, $title = null, $local = false, $wikiId = null
|
||
// ) {
|
||
// // '*' used to be the comment inserted by the software way back
|
||
// // in antiquity in case none was provided, here for backwards
|
||
// // compatibility, acc. to brion -<2D>var
|
||
// if ( $comment == '' || $comment == '*' ) {
|
||
// return '';
|
||
// } else {
|
||
// $formatted = self::formatComment( $comment, $title, $local, $wikiId );
|
||
// $formatted = wfMessage( 'parentheses' )->rawParams( $formatted )->escaped();
|
||
// return " <span class=\"comment\">$formatted</span>";
|
||
// }
|
||
// }
|
||
//
|
||
// /**
|
||
// * Wrap and format the given revision's comment block, if the current
|
||
// * user is allowed to view it.
|
||
// *
|
||
// * @since 1.16.3
|
||
// * @param Revision $rev
|
||
// * @param boolean $local Whether section links should refer to local page
|
||
// * @param boolean $isPublic Show only if all users can see it
|
||
// * @return String HTML fragment
|
||
// */
|
||
// public static function revComment( Revision $rev, $local = false, $isPublic = false ) {
|
||
// if ( $rev->getComment( Revision::RAW ) == "" ) {
|
||
// return "";
|
||
// }
|
||
// if ( $rev->isDeleted( Revision::DELETED_COMMENT ) && $isPublic ) {
|
||
// $block = " <span class=\"comment\">" . wfMessage( 'rev-deleted-comment' )->escaped() . "</span>";
|
||
// } elseif ( $rev->userCan( Revision::DELETED_COMMENT ) ) {
|
||
// $block = self::commentBlock( $rev->getComment( Revision::FOR_THIS_USER ),
|
||
// $rev->getTitle(), $local );
|
||
// } else {
|
||
// $block = " <span class=\"comment\">" . wfMessage( 'rev-deleted-comment' )->escaped() . "</span>";
|
||
// }
|
||
// if ( $rev->isDeleted( Revision::DELETED_COMMENT ) ) {
|
||
// return " <span class=\"history-deleted\">$block</span>";
|
||
// }
|
||
// return $block;
|
||
// }
|
||
//
|
||
// /**
|
||
// * @since 1.16.3
|
||
// * @param int $size
|
||
// * @return String
|
||
// */
|
||
// public static function formatRevisionSize( $size ) {
|
||
// if ( $size == 0 ) {
|
||
// $stxt = wfMessage( 'historyempty' )->escaped();
|
||
// } else {
|
||
// $stxt = wfMessage( 'nbytes' )->numParams( $size )->escaped();
|
||
// $stxt = wfMessage( 'parentheses' )->rawParams( $stxt )->escaped();
|
||
// }
|
||
// return "<span class=\"history-size\">$stxt</span>";
|
||
// }
|
||
//
|
||
// /**
|
||
// * Add another level to the Table of Contents
|
||
// *
|
||
// * @since 1.16.3
|
||
// * @return String
|
||
// */
|
||
// public static function tocIndent() {
|
||
// return "\n<ul>";
|
||
// }
|
||
//
|
||
// /**
|
||
// * Finish one or more sublevels on the Table of Contents
|
||
// *
|
||
// * @since 1.16.3
|
||
// * @param int $level
|
||
// * @return String
|
||
// */
|
||
// public static function tocUnindent( $level ) {
|
||
// return "</li>\n" . str_repeat( "</ul>\n</li>\n", $level > 0 ? $level : 0 );
|
||
// }
|
||
//
|
||
// /**
|
||
// * parameter level defines if we are on an indentation level
|
||
// *
|
||
// * @since 1.16.3
|
||
// * @param String $anchor
|
||
// * @param String $tocline
|
||
// * @param String $tocnumber
|
||
// * @param String $level
|
||
// * @param String|boolean $sectionIndex
|
||
// * @return String
|
||
// */
|
||
// public static function tocLine( $anchor, $tocline, $tocnumber, $level, $sectionIndex = false ) {
|
||
// $classes = "toclevel-$level";
|
||
// if ( $sectionIndex !== false ) {
|
||
// $classes .= " tocsection-$sectionIndex";
|
||
// }
|
||
// return "\n<li class=\"$classes\"><a href=\"#" .
|
||
// $anchor . '"><span class="tocnumber">' .
|
||
// $tocnumber . '</span> <span class="toctext">' .
|
||
// $tocline . '</span></a>';
|
||
// }
|
||
//
|
||
// /**
|
||
// * End a Table Of Contents line.
|
||
// * tocUnindent() will be used instead if we're ending a line below
|
||
// * the new level.
|
||
// * @since 1.16.3
|
||
// * @return String
|
||
// */
|
||
// public static function tocLineEnd() {
|
||
// return "</li>\n";
|
||
// }
|
||
//
|
||
// /**
|
||
// * Wraps the TOC in a table and provides the hide/collapse javascript.
|
||
// *
|
||
// * @since 1.16.3
|
||
// * @param String $toc Html of the Table Of Contents
|
||
// * @param String|Language|boolean $lang Language for the toc title, defaults to user language
|
||
// * @return String Full html of the TOC
|
||
// */
|
||
// public static function tocList( $toc, $lang = false ) {
|
||
// $lang = wfGetLangObj( $lang );
|
||
// $title = wfMessage( 'toc' )->inLanguage( $lang )->escaped();
|
||
//
|
||
// return '<div id="toc" class="toc">'
|
||
// . '<div id="toctitle"><h2>' . $title . "</h2></div>\n"
|
||
// . $toc
|
||
// . "</ul>\n</div>\n";
|
||
// }
|
||
//
|
||
// /**
|
||
// * Generate a table of contents from a section tree.
|
||
// *
|
||
// * @since 1.16.3. $lang added in 1.17
|
||
// * @param array $tree Return value of ParserOutput::getSections()
|
||
// * @param String|Language|boolean $lang Language for the toc title, defaults to user language
|
||
// * @return String HTML fragment
|
||
// */
|
||
// public static function generateTOC( $tree, $lang = false ) {
|
||
// $toc = '';
|
||
// $lastLevel = 0;
|
||
// foreach ( $tree as $section ) {
|
||
// if ( $section['toclevel'] > $lastLevel ) {
|
||
// $toc .= self::tocIndent();
|
||
// } elseif ( $section['toclevel'] < $lastLevel ) {
|
||
// $toc .= self::tocUnindent(
|
||
// $lastLevel - $section['toclevel'] );
|
||
// } else {
|
||
// $toc .= self::tocLineEnd();
|
||
// }
|
||
//
|
||
// $toc .= self::tocLine( $section['anchor'],
|
||
// $section['line'], $section['number'],
|
||
// $section['toclevel'], $section['index'] );
|
||
// $lastLevel = $section['toclevel'];
|
||
// }
|
||
// $toc .= self::tocLineEnd();
|
||
// return self::tocList( $toc, $lang );
|
||
// }
|
||
//
|
||
// /**
|
||
// * Create a headline for content
|
||
// *
|
||
// * @since 1.16.3
|
||
// * @param int $level The level of the headline (1-6)
|
||
// * @param String $attribs Any attributes for the headline, starting with
|
||
// * a space and ending with '>'
|
||
// * This *must* be at least '>' for no attribs
|
||
// * @param String $anchor The anchor to give the headline (the bit after the #)
|
||
// * @param String $html Html for the text of the header
|
||
// * @param String $link HTML to add for the section edit link
|
||
// * @param boolean|String $legacyAnchor A second, optional anchor to give for
|
||
// * backward compatibility (false to omit)
|
||
// *
|
||
// * @return String HTML headline
|
||
// */
|
||
// public static function makeHeadline( $level, $attribs, $anchor, $html,
|
||
// $link, $legacyAnchor = false
|
||
// ) {
|
||
// $ret = "<h$level$attribs"
|
||
// . "<span class=\"mw-headline\" id=\"$anchor\">$html</span>"
|
||
// . $link
|
||
// . "</h$level>";
|
||
// if ( $legacyAnchor !== false ) {
|
||
// $ret = "<div id=\"$legacyAnchor\"></div>$ret";
|
||
// }
|
||
// return $ret;
|
||
// }
|
||
|
||
/**
|
||
* Split a link trail, return the "inside" portion and the remainder of the trail
|
||
* as a two-element array
|
||
* @param String $trail
|
||
* @return array
|
||
*/
|
||
// XO.MW:SYNC:1.29; DATE:2017-02-08
|
||
public byte[][] splitTrail(byte[] trail) {
|
||
int cur = 0;
|
||
int src_end = trail.length;
|
||
while (true) {
|
||
Object o = split_trail_trie.Match_at(trv, trail, cur, src_end);
|
||
if (o == null) break;
|
||
byte[] bry = (byte[])o;
|
||
cur += bry.length;
|
||
}
|
||
|
||
if (cur == 0) { // no trail
|
||
split_trail_rv[0] = null;
|
||
split_trail_rv[1] = trail;
|
||
}
|
||
else {
|
||
split_trail_rv[0] = Bry_.Mid(trail, 0, cur);
|
||
split_trail_rv[1] = Bry_.Mid(trail, cur, src_end);
|
||
}
|
||
return split_trail_rv;
|
||
}
|
||
// // Create a direct link to a given uploaded file.
|
||
// public static function makeMediaLinkObj($title, $html = '', $time = false) {
|
||
// $img = wfFindFile($title, [ 'time' => $time ]);
|
||
// return self::makeMediaLinkFile($title, $img, $html);
|
||
// }
|
||
//
|
||
// // Create a direct link to a given uploaded file.
|
||
// // This will make a broken link if $file is false.
|
||
// public static function makeMediaLinkFile(Title $title, $file, $html = '') {
|
||
// if ($file && $file->exists()) {
|
||
// $url = $file->getUrl();
|
||
// $class = '@gplx.Internal protected';
|
||
// } else {
|
||
// $url = self::getUploadUrl($title);
|
||
// $class = 'new';
|
||
// }
|
||
//
|
||
// $alt = $title->getText();
|
||
// if ($html == '') {
|
||
// $html = $alt;
|
||
// }
|
||
//
|
||
// $ret = '';
|
||
// $attribs = [
|
||
// 'href' => $url,
|
||
// 'class' => $class,
|
||
// 'title' => $alt
|
||
// ];
|
||
//
|
||
// if (!Hooks::run('LinkerMakeMediaLinkFile',
|
||
// [ $title, $file, &$html, &$attribs, &$ret ])) {
|
||
// wfDebug("Hook LinkerMakeMediaLinkFile changed the output of link "
|
||
// . "with url {$url} and text {$html} to {$ret}\n", true);
|
||
// return $ret;
|
||
// }
|
||
//
|
||
// return Html::rawElement('a', $attribs, $html);
|
||
// }
|
||
// /**
|
||
// * Generate a rollback link for a given revision. Currently it's the
|
||
// * caller's responsibility to ensure that the revision is the top one. If
|
||
// * it's not, of course, the user will get an error message.
|
||
// *
|
||
// * If the calling page is called with the parameter &bot=1, all rollback
|
||
// * links also get that parameter. It causes the edit itself and the rollback
|
||
// * to be marked as "bot" edits. Bot edits are hidden by default from recent
|
||
// * changes, so this allows sysops to combat a busy vandal without bothering
|
||
// * other users.
|
||
// *
|
||
// * If the option verify is set this function will return the link only in case the
|
||
// * revision can be reverted. Please note that due to performance limitations
|
||
// * it might be assumed that a user isn't the only contributor of a page while
|
||
// * (s)he is, which will lead to useless rollback links. Furthermore this wont
|
||
// * work if $wgShowRollbackEditCount is disabled, so this can only function
|
||
// * as an additional check.
|
||
// *
|
||
// * If the option noBrackets is set the rollback link wont be enclosed in "[]".
|
||
// *
|
||
// * @since 1.16.3. $context added in 1.20. $options added in 1.21
|
||
// *
|
||
// * @param Revision $rev
|
||
// * @param IContextSource $context Context to use or null for the main context.
|
||
// * @param array $options
|
||
// * @return String
|
||
// */
|
||
// public static function generateRollback( $rev, IContextSource $context = null,
|
||
// $options = [ 'verify' ]
|
||
// ) {
|
||
// if ( $context === null ) {
|
||
// $context = RequestContext::getMain();
|
||
// }
|
||
//
|
||
// $editCount = false;
|
||
// if ( in_array( 'verify', $options, true ) ) {
|
||
// $editCount = self::getRollbackEditCount( $rev, true );
|
||
// if ( $editCount === false ) {
|
||
// return '';
|
||
// }
|
||
// }
|
||
//
|
||
// $inner = self::buildRollbackLink( $rev, $context, $editCount );
|
||
//
|
||
// if ( !in_array( 'noBrackets', $options, true ) ) {
|
||
// $inner = $context->msg( 'brackets' )->rawParams( $inner )->escaped();
|
||
// }
|
||
//
|
||
// return '<span class="mw-rollback-link">' . $inner . '</span>';
|
||
// }
|
||
//
|
||
// /**
|
||
// * This function will return the number of revisions which a rollback
|
||
// * would revert and, if $verify is set it will verify that a revision
|
||
// * can be reverted (that the user isn't the only contributor and the
|
||
// * revision we might rollback to isn't deleted). These checks can only
|
||
// * function as an additional check as this function only checks against
|
||
// * the last $wgShowRollbackEditCount edits.
|
||
// *
|
||
// * Returns null if $wgShowRollbackEditCount is disabled or false if $verify
|
||
// * is set and the user is the only contributor of the page.
|
||
// *
|
||
// * @param Revision $rev
|
||
// * @param boolean $verify Try to verify that this revision can really be rolled back
|
||
// * @return int|boolean|null
|
||
// */
|
||
// public static function getRollbackEditCount( $rev, $verify ) {
|
||
// global $wgShowRollbackEditCount;
|
||
// if ( !is_int( $wgShowRollbackEditCount ) || !$wgShowRollbackEditCount > 0 ) {
|
||
// // Nothing has happened, indicate this by returning 'null'
|
||
// return null;
|
||
// }
|
||
//
|
||
// $dbr = wfGetDB( DB_REPLICA );
|
||
//
|
||
// // Up to the value of $wgShowRollbackEditCount revisions are counted
|
||
// $res = $dbr->select(
|
||
// 'revision',
|
||
// [ 'rev_user_text', 'rev_deleted' ],
|
||
// // $rev->getPage() returns null sometimes
|
||
// [ 'rev_page' => $rev->getTitle()->getArticleID() ],
|
||
// __METHOD__,
|
||
// [
|
||
// 'USE INDEX' => [ 'revision' => 'page_timestamp' ],
|
||
// 'ORDER BY' => 'rev_timestamp DESC',
|
||
// 'LIMIT' => $wgShowRollbackEditCount + 1
|
||
// ]
|
||
// );
|
||
//
|
||
// $editCount = 0;
|
||
// $moreRevs = false;
|
||
// foreach ( $res as $row ) {
|
||
// if ( $rev->getUserText( Revision::RAW ) != $row->rev_user_text ) {
|
||
// if ( $verify &&
|
||
// ( $row->rev_deleted & Revision::DELETED_TEXT
|
||
// || $row->rev_deleted & Revision::DELETED_USER
|
||
// ) ) {
|
||
// // If the user or the text of the revision we might rollback
|
||
// // to is deleted in some way we can't rollback. Similar to
|
||
// // the sanity checks in WikiPage::commitRollback.
|
||
// return false;
|
||
// }
|
||
// $moreRevs = true;
|
||
// break;
|
||
// }
|
||
// $editCount++;
|
||
// }
|
||
//
|
||
// if ( $verify && $editCount <= $wgShowRollbackEditCount && !$moreRevs ) {
|
||
// // We didn't find at least $wgShowRollbackEditCount revisions made by the current user
|
||
// // and there weren't any other revisions. That means that the current user is the only
|
||
// // editor, so we can't rollback
|
||
// return false;
|
||
// }
|
||
// return $editCount;
|
||
// }
|
||
//
|
||
// /**
|
||
// * Build a raw rollback link, useful for collections of "tool" links
|
||
// *
|
||
// * @since 1.16.3. $context added in 1.20. $editCount added in 1.21
|
||
// * @param Revision $rev
|
||
// * @param IContextSource|null $context Context to use or null for the main context.
|
||
// * @param int $editCount Number of edits that would be reverted
|
||
// * @return String HTML fragment
|
||
// */
|
||
// public static function buildRollbackLink( $rev, IContextSource $context = null,
|
||
// $editCount = false
|
||
// ) {
|
||
// global $wgShowRollbackEditCount, $wgMiserMode;
|
||
//
|
||
// // To config which pages are affected by miser mode
|
||
// $disableRollbackEditCountSpecialPage = [ 'Recentchanges', 'Watchlist' ];
|
||
//
|
||
// if ( $context === null ) {
|
||
// $context = RequestContext::getMain();
|
||
// }
|
||
//
|
||
// $title = $rev->getTitle();
|
||
// $query = [
|
||
// 'action' => 'rollback',
|
||
// 'from' => $rev->getUserText(),
|
||
// 'token' => $context->getUser()->getEditToken( 'rollback' ),
|
||
// ];
|
||
// $attrs = [
|
||
// 'data-mw' => 'interface',
|
||
// 'title' => $context->msg( 'tooltip-rollback' )->text(),
|
||
// ];
|
||
// $options = [ 'known', 'noclasses' ];
|
||
//
|
||
// if ( $context->getRequest()->getBool( 'bot' ) ) {
|
||
// $query['bot'] = '1';
|
||
// $query['hidediff'] = '1'; // bug 15999
|
||
// }
|
||
//
|
||
// $disableRollbackEditCount = false;
|
||
// if ( $wgMiserMode ) {
|
||
// foreach ( $disableRollbackEditCountSpecialPage as $specialPage ) {
|
||
// if ( $context->getTitle()->isSpecial( $specialPage ) ) {
|
||
// $disableRollbackEditCount = true;
|
||
// break;
|
||
// }
|
||
// }
|
||
// }
|
||
//
|
||
// if ( !$disableRollbackEditCount
|
||
// && is_int( $wgShowRollbackEditCount )
|
||
// && $wgShowRollbackEditCount > 0
|
||
// ) {
|
||
// if ( !is_numeric( $editCount ) ) {
|
||
// $editCount = self::getRollbackEditCount( $rev, false );
|
||
// }
|
||
//
|
||
// if ( $editCount > $wgShowRollbackEditCount ) {
|
||
// $html = $context->msg( 'rollbacklinkcount-morethan' )
|
||
// ->numParams( $wgShowRollbackEditCount )->parse();
|
||
// } else {
|
||
// $html = $context->msg( 'rollbacklinkcount' )->numParams( $editCount )->parse();
|
||
// }
|
||
//
|
||
// return self::link( $title, $html, $attrs, $query, $options );
|
||
// } else {
|
||
// $html = $context->msg( 'rollbacklink' )->escaped();
|
||
// return self::link( $title, $html, $attrs, $query, $options );
|
||
// }
|
||
// }
|
||
//
|
||
// /**
|
||
// * @deprecated since 1.28, use TemplatesOnThisPageFormatter directly
|
||
// *
|
||
// * Returns HTML for the "templates used on this page" list.
|
||
// *
|
||
// * Make an HTML list of templates, and then add a "More..." link at
|
||
// * the bottom. If $more is null, do not add a "More..." link. If $more
|
||
// * is a Title, make a link to that title and use it. If $more is a String,
|
||
// * directly paste it in as the link (escaping needs to be done manually).
|
||
// * Finally, if $more is a Message, call toString().
|
||
// *
|
||
// * @since 1.16.3. $more added in 1.21
|
||
// * @param Title[] $templates Array of templates
|
||
// * @param boolean $preview Whether this is for a preview
|
||
// * @param boolean $section Whether this is for a section edit
|
||
// * @param Title|Message|String|null $more An escaped link for "More..." of the templates
|
||
// * @return String HTML output
|
||
// */
|
||
// public static function formatTemplates( $templates, $preview = false,
|
||
// $section = false, $more = null
|
||
// ) {
|
||
// wfDeprecated( __METHOD__, '1.28' );
|
||
//
|
||
// $type = false;
|
||
// if ( $preview ) {
|
||
// $type = 'preview';
|
||
// } elseif ( $section ) {
|
||
// $type = 'section';
|
||
// }
|
||
//
|
||
// if ( $more instanceof Message ) {
|
||
// $more = $more->toString();
|
||
// }
|
||
//
|
||
// $formatter = new TemplatesOnThisPageFormatter(
|
||
// RequestContext::getMain(),
|
||
// MediaWikiServices::getInstance()->getLinkRenderer()
|
||
// );
|
||
// return $formatter->format( $templates, $type, $more );
|
||
// }
|
||
//
|
||
// /**
|
||
// * Returns HTML for the "hidden categories on this page" list.
|
||
// *
|
||
// * @since 1.16.3
|
||
// * @param array $hiddencats Array of hidden categories from Article::getHiddenCategories
|
||
// * or similar
|
||
// * @return String HTML output
|
||
// */
|
||
// public static function formatHiddenCategories( $hiddencats ) {
|
||
//
|
||
// $outText = '';
|
||
// if ( count( $hiddencats ) > 0 ) {
|
||
// # Construct the HTML
|
||
// $outText = '<div class="mw-hiddenCategoriesExplanation">';
|
||
// $outText .= wfMessage( 'hiddencategories' )->numParams( count( $hiddencats ) )->parseAsBlock();
|
||
// $outText .= "</div><ul>\n";
|
||
//
|
||
// foreach ( $hiddencats as $titleObj ) {
|
||
// # If it's hidden, it must exist - no need to check with a LinkBatch
|
||
// $outText .= '<li>'
|
||
// . self::link( $titleObj, null, [], [], 'known' )
|
||
// . "</li>\n";
|
||
// }
|
||
// $outText .= '</ul>';
|
||
// }
|
||
// return $outText;
|
||
// }
|
||
//
|
||
// /**
|
||
// * @deprecated since 1.28, use Language::formatSize() directly
|
||
// *
|
||
// * Format a size in bytes for output, using an appropriate
|
||
// * unit (B, KB, MB or GB) according to the magnitude in question
|
||
// *
|
||
// * @since 1.16.3
|
||
// * @param int $size Size to format
|
||
// * @return String
|
||
// */
|
||
// public static function formatSize( $size ) {
|
||
// wfDeprecated( __METHOD__, '1.28' );
|
||
//
|
||
// global $wgLang;
|
||
// return htmlspecialchars( $wgLang->formatSize( $size ) );
|
||
// }
|
||
//
|
||
// /**
|
||
// * Given the id of an interface element, constructs the appropriate title
|
||
// * attribute from the system messages. (Note, this is usually the id but
|
||
// * isn't always, because sometimes the accesskey needs to go on a different
|
||
// * element than the id, for reverse-compatibility, etc.)
|
||
// *
|
||
// * @since 1.16.3 $msgParams added in 1.27
|
||
// * @param String $name Id of the element, minus prefixes.
|
||
// * @param String|null $options Null or the String 'withaccess' to add an access-
|
||
// * key hint
|
||
// * @param array $msgParams Parameters to pass to the message
|
||
// *
|
||
// * @return String Contents of the title attribute (which you must HTML-
|
||
// * escape), or false for no title attribute
|
||
// */
|
||
// public static function titleAttrib( $name, $options = null, array $msgParams = [] ) {
|
||
// $message = wfMessage( "tooltip-$name", $msgParams );
|
||
// if ( !$message->exists() ) {
|
||
// $tooltip = false;
|
||
// } else {
|
||
// $tooltip = $message->text();
|
||
// # Compatibility: formerly some tooltips had [alt-.] hardcoded
|
||
// $tooltip = preg_replace( "/ ?\[alt-.\]$/", '', $tooltip );
|
||
// # Message equal to '-' means suppress it.
|
||
// if ( $tooltip == '-' ) {
|
||
// $tooltip = false;
|
||
// }
|
||
// }
|
||
//
|
||
// if ( $options == 'withaccess' ) {
|
||
// $accesskey = self::accesskey( $name );
|
||
// if ( $accesskey !== false ) {
|
||
// // Should be build the same as in jquery.accessKeyLabel.js
|
||
// if ( $tooltip === false || $tooltip === '' ) {
|
||
// $tooltip = wfMessage( 'brackets', $accesskey )->text();
|
||
// } else {
|
||
// $tooltip .= wfMessage( 'word-separator' )->text();
|
||
// $tooltip .= wfMessage( 'brackets', $accesskey )->text();
|
||
// }
|
||
// }
|
||
// }
|
||
//
|
||
// return $tooltip;
|
||
// }
|
||
//
|
||
// public static $accesskeycache;
|
||
//
|
||
// /**
|
||
// * Given the id of an interface element, constructs the appropriate
|
||
// * accesskey attribute from the system messages. (Note, this is usually
|
||
// * the id but isn't always, because sometimes the accesskey needs to go on
|
||
// * a different element than the id, for reverse-compatibility, etc.)
|
||
// *
|
||
// * @since 1.16.3
|
||
// * @param String $name Id of the element, minus prefixes.
|
||
// * @return String Contents of the accesskey attribute (which you must HTML-
|
||
// * escape), or false for no accesskey attribute
|
||
// */
|
||
// public static function accesskey( $name ) {
|
||
// if ( isset( self::$accesskeycache[$name] ) ) {
|
||
// return self::$accesskeycache[$name];
|
||
// }
|
||
//
|
||
// $message = wfMessage( "accesskey-$name" );
|
||
//
|
||
// if ( !$message->exists() ) {
|
||
// $accesskey = false;
|
||
// } else {
|
||
// $accesskey = $message->plain();
|
||
// if ( $accesskey === '' || $accesskey === '-' ) {
|
||
// # @todo FIXME: Per standard MW behavior, a value of '-' means to suppress the
|
||
// # attribute, but this is broken for accesskey: that might be a useful
|
||
// # value.
|
||
// $accesskey = false;
|
||
// }
|
||
// }
|
||
//
|
||
// self::$accesskeycache[$name] = $accesskey;
|
||
// return self::$accesskeycache[$name];
|
||
// }
|
||
//
|
||
// /**
|
||
// * Get a revision-deletion link, or disabled link, or nothing, depending
|
||
// * on user permissions & the settings on the revision.
|
||
// *
|
||
// * Will use forward-compatible revision ID in the Special:RevDelete link
|
||
// * if possible, otherwise the timestamp-based ID which may break after
|
||
// * undeletion.
|
||
// *
|
||
// * @param User $user
|
||
// * @param Revision $rev
|
||
// * @param Title $title
|
||
// * @return String HTML fragment
|
||
// */
|
||
// public static function getRevDeleteLink( User $user, Revision $rev, Title $title ) {
|
||
// $canHide = $user->isAllowed( 'deleterevision' );
|
||
// if ( !$canHide && !( $rev->getVisibility() && $user->isAllowed( 'deletedhistory' ) ) ) {
|
||
// return '';
|
||
// }
|
||
//
|
||
// if ( !$rev->userCan( Revision::DELETED_RESTRICTED, $user ) ) {
|
||
// return Linker::revDeleteLinkDisabled( $canHide ); // revision was hidden from sysops
|
||
// } else {
|
||
// if ( $rev->getId() ) {
|
||
// // RevDelete links using revision ID are stable across
|
||
// // page deletion and undeletion; use when possible.
|
||
// $query = [
|
||
// 'type' => 'revision',
|
||
// 'target' => $title->getPrefixedDBkey(),
|
||
// 'ids' => $rev->getId()
|
||
// ];
|
||
// } else {
|
||
// // Older deleted entries didn't save a revision ID.
|
||
// // We have to refer to these by timestamp, ick!
|
||
// $query = [
|
||
// 'type' => 'archive',
|
||
// 'target' => $title->getPrefixedDBkey(),
|
||
// 'ids' => $rev->getTimestamp()
|
||
// ];
|
||
// }
|
||
// return Linker::revDeleteLink( $query,
|
||
// $rev->isDeleted( Revision::DELETED_RESTRICTED ), $canHide );
|
||
// }
|
||
// }
|
||
//
|
||
// /**
|
||
// * Creates a (show/hide) link for deleting revisions/log entries
|
||
// *
|
||
// * @param array $query Query parameters to be passed to link()
|
||
// * @param boolean $restricted Set to true to use a "<strong>" instead of a "<span>"
|
||
// * @param boolean $delete Set to true to use (show/hide) rather than (show)
|
||
// *
|
||
// * @return String HTML "<a>" link to Special:Revisiondelete, wrapped in a
|
||
// * span to allow for customization of appearance with CSS
|
||
// */
|
||
// public static function revDeleteLink( $query = [], $restricted = false, $delete = true ) {
|
||
// $sp = SpecialPage::getTitleFor( 'Revisiondelete' );
|
||
// $msgKey = $delete ? 'rev-delundel' : 'rev-showdeleted';
|
||
// $html = wfMessage( $msgKey )->escaped();
|
||
// $tag = $restricted ? 'strong' : 'span';
|
||
// $link = self::link( $sp, $html, [], $query, [ 'known', 'noclasses' ] );
|
||
// return Xml::tags(
|
||
// $tag,
|
||
// [ 'class' => 'mw-revdelundel-link' ],
|
||
// wfMessage( 'parentheses' )->rawParams( $link )->escaped()
|
||
// );
|
||
// }
|
||
//
|
||
// /**
|
||
// * Creates a dead (show/hide) link for deleting revisions/log entries
|
||
// *
|
||
// * @since 1.16.3
|
||
// * @param boolean $delete Set to true to use (show/hide) rather than (show)
|
||
// *
|
||
// * @return String HTML text wrapped in a span to allow for customization
|
||
// * of appearance with CSS
|
||
// */
|
||
// public static function revDeleteLinkDisabled( $delete = true ) {
|
||
// $msgKey = $delete ? 'rev-delundel' : 'rev-showdeleted';
|
||
// $html = wfMessage( $msgKey )->escaped();
|
||
// $htmlParentheses = wfMessage( 'parentheses' )->rawParams( $html )->escaped();
|
||
// return Xml::tags( 'span', [ 'class' => 'mw-revdelundel-link' ], $htmlParentheses );
|
||
// }
|
||
//
|
||
// /* Deprecated methods */
|
||
//
|
||
// /**
|
||
// * Returns the attributes for the tooltip and access key.
|
||
// *
|
||
// * @since 1.16.3. $msgParams introduced in 1.27
|
||
// * @param String $name
|
||
// * @param array $msgParams Params for constructing the message
|
||
// *
|
||
// * @return array
|
||
// */
|
||
// public static function tooltipAndAccesskeyAttribs( $name, array $msgParams = [] ) {
|
||
// # @todo FIXME: If Sanitizer::expandAttributes() treated "false" as "output
|
||
// # no attribute" instead of "output '' as value for attribute", this
|
||
// # would be three lines.
|
||
// $attribs = [
|
||
// 'title' => self::titleAttrib( $name, 'withaccess', $msgParams ),
|
||
// 'accesskey' => self::accesskey( $name )
|
||
// ];
|
||
// if ( $attribs['title'] === false ) {
|
||
// unset( $attribs['title'] );
|
||
// }
|
||
// if ( $attribs['accesskey'] === false ) {
|
||
// unset( $attribs['accesskey'] );
|
||
// }
|
||
// return $attribs;
|
||
// }
|
||
//
|
||
// /**
|
||
// * Returns raw bits of HTML, use titleAttrib()
|
||
// * @since 1.16.3
|
||
// * @param String $name
|
||
// * @param array|null $options
|
||
// * @return null|String
|
||
// */
|
||
// public static function tooltip( $name, $options = null ) {
|
||
// # @todo FIXME: If Sanitizer::expandAttributes() treated "false" as "output
|
||
// # no attribute" instead of "output '' as value for attribute", this
|
||
// # would be two lines.
|
||
// $tooltip = self::titleAttrib( $name, $options );
|
||
// if ( $tooltip === false ) {
|
||
// return '';
|
||
// }
|
||
// return Xml::expandAttributes( [
|
||
// 'title' => $tooltip
|
||
// ] );
|
||
// }
|
||
private static final byte[] Bry__dot2 = Bry_.new_a7("../");
|
||
}
|
||
class Linker_rel_splitter implements gplx.core.brys.Bry_split_wkr {
|
||
private final Hash_adp_bry hash = Hash_adp_bry.cs();
|
||
private final Bry_bfr bfr = Bry_bfr_.New();
|
||
public int Split(byte[] src, int itm_bgn, int itm_end) { // $combined = array_unique(array_merge($newRels, $oldRels));
|
||
byte[] val = (byte[])hash.Get_by_mid(src, itm_bgn, itm_end);
|
||
if (val == null) {
|
||
val = Bry_.Mid(src, itm_bgn, itm_end);
|
||
hash.Add_as_key_and_val(val);
|
||
if (bfr.Len_gt_0()) bfr.Add_byte_space();
|
||
bfr.Add(val);
|
||
}
|
||
return Bry_split_.Rv__ok;
|
||
}
|
||
public byte[] To_bry() {
|
||
hash.Clear();
|
||
return bfr.To_bry_and_clear();
|
||
}
|
||
}
|