diff --git a/400_xowa/src/gplx/xowa/mws/Xomw_linker.java b/400_xowa/src/gplx/xowa/mws/Xomw_linker.java index 2598030ad..3e671dc2a 100644 --- a/400_xowa/src/gplx/xowa/mws/Xomw_linker.java +++ b/400_xowa/src/gplx/xowa/mws/Xomw_linker.java @@ -17,8 +17,8 @@ along with this program. If not, see . */ package gplx.xowa.mws; import gplx.*; import gplx.xowa.*; import gplx.core.btries.*; -import gplx.xowa.mws.htmls.*; -import gplx.xowa.mws.linkers.*; +import gplx.langs.htmls.*; +import gplx.xowa.mws.htmls.*; import gplx.xowa.mws.linkers.*; import gplx.xowa.mws.parsers.*; /* TODO.XO * P7: titleFormatter->getPrefixedText * P7: $html = HtmlArmor::getHtml($text); @@ -32,6 +32,12 @@ public class Xomw_linker { private final byte[][] split_trail_rv = new byte[2][]; private Btrie_slim_mgr split_trail_trie; 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("
") + ; private final Xomw_link_renderer link_renderer; public Xomw_linker(Xomw_link_renderer link_renderer) { this.link_renderer = link_renderer; @@ -39,6 +45,292 @@ public class Xomw_linker { public void Init_by_wiki(Btrie_slim_mgr trie) { this.split_trail_trie = trie; } + // 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 frame_params 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 $widthOption Used by the parser to remember the user preference thumbnailsize + // @since 1.20 + // @return String HTML for an image, with links, wrappers, etc. + public void Make_image_link(Xomw_parser parser, Xoa_ttl title, Object file, Xomw_img_frame frame_params, Object handlerParams, Object time, Object query, Object widthOption) { + // XO.MW.HOOK:ImageBeforeProduceHTML + +// if ($file && !$file->allowInlineDisplay()) { +// wfDebug(__METHOD__ . ': ' . $title->getPrefixedDBkey() . " does not allow inline display\n"); +// return self::link($title); +// } + + // Clean up parameters +// $page = isset($handlerParams['page']) ? $handlerParams['page'] : false; + if (frame_params.align == null) { + frame_params.align = Bry_.Empty; + } + if (frame_params.alt == null) { + frame_params.alt = Bry_.Empty; + } + if (frame_params.title == null) { + frame_params.title = Bry_.Empty; + } + if (frame_params.cls == null) { + frame_params.cls = Bry_.Empty; + } + + byte[] prefix = Bry_.Empty; byte[] postfix = Bry_.Empty; + + if (Bry_.Eq(Align__frame__center, frame_params.align)) { + prefix = Prefix__center; + postfix = Gfh_tag_.Div_rhs; + frame_params.align = Align__frame__none; + } +// if ($file && !isset($handlerParams['width'])) { +// if (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. +// global $wgSVGMaxSize; +// $handlerParams['width'] = $wgSVGMaxSize; +// } else { +// $handlerParams['width'] = $file->getWidth($page); +// } +// + if ( frame_params.thumbnail != null + || frame_params.manual_thumb != null + || frame_params.framed != null + || frame_params.frameless != null +// || !$handlerParams['width'] + ) { +// global $wgThumbLimits, $wgThumbUpright; +// +// if ($widthOption === null || !isset($wgThumbLimits[$widthOption])) { +// $widthOption = User::getDefaultOption('thumbsize'); +// } +// +// // Reduce width for upright images when parameter 'upright' is used +// if (isset(frame_params['upright']) && frame_params['upright'] == 0) { +// frame_params['upright'] = $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. +// $prefWidth = isset(frame_params['upright']) ? +// round($wgThumbLimits[$widthOption] * frame_params['upright'], -1) : +// $wgThumbLimits[$widthOption]; +// +// // Use width which is smaller: real image width or user preference width +// // Unless image is scalable vector. +// if (!isset($handlerParams['height']) && ($handlerParams['width'] <= 0 || +// $prefWidth < $handlerParams['width'] || $file->isVectorized())) { +// $handlerParams['width'] = $prefWidth; +// } + } +// } + + if (frame_params.thumbnail != null || frame_params.manual_thumb != null + || frame_params.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 (frame_params.align == Bry_.Empty) { +// frame_params.align = $parser->getTargetLanguage()->alignEnd(); + } +// return prefix . +// self::makeThumbLink2($title, $file, frame_params, $handlerParams, $time, $query) . +// postfix; + } +// +// if ($file && isset(frame_params['frameless'])) { +// $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 ($srcWidth && !$file->mustRender() && $handlerParams['width'] > $srcWidth) { +// $handlerParams['width'] = $srcWidth; +// } +// } +// +// if ($file && isset($handlerParams['width'])) { +// // Create a resized image, without the additional thumbnail features +// $thumb = $file->transform($handlerParams); +// } else { +// $thumb = false; +// } +// +// if (!$thumb) { +// $s = self::makeBrokenImageLinkObj($title, frame_params['title'], '', '', '', $time == true); +// } else { +// self::processResponsiveImages($file, $thumb, $handlerParams); +// $params = [ +// 'alt' => frame_params['alt'], +// 'title' => frame_params['title'], +// 'valign' => isset(frame_params['valign']) ? frame_params['valign'] : false, +// 'img-class' => frame_params['class'] ]; +// if (isset(frame_params['border'])) { +// $params['img-class'] .= ($params['img-class'] !== '' ? ' ' : '') . 'thumbborder'; +// } +// $params = self::getImageLinkMTOParams(frame_params, $query, $parser) + $params; +// +// $s = $thumb->toHtml($params); +// } +// if (frame_params['align'] != '') { +// $s = "
{$s}
"; +// } +// return str_replace("\n", ' ', prefix . $s . postfix); + if (prefix == null || postfix == null) { + } + } + public void Make_thumb_link2(Bry_bfr bfr, Xoa_ttl title, Object file, Xomw_img_frame frame_params, Object handlerParams, Object time, Object query) { + boolean exists = false; // = $file && $file->exists(); + +// $page = isset($handlerParams['page']) ? $handlerParams['page'] : false; + if (frame_params.align == null) { + frame_params.align = Align__frame__right; + } + if (frame_params.alt == null) { + frame_params.alt = Bry_.Empty; + } + if (frame_params.title == null) { + frame_params.title = Bry_.Empty; + } + if (frame_params.caption == null) { + frame_params.caption = Bry_.Empty; + } + +// if (empty($handlerParams['width'])) { +// // Reduce width for upright images when parameter 'upright' is used +// $handlerParams['width'] = isset(frame_params['upright']) ? 130 : 180; +// } + boolean thumb = false; + boolean no_scale = false; + boolean manual_thumb = false; + int outer_width = 0; + + if (!exists) { +// outer_width = $handlerParams['width'] + 2; + } + else { + if (frame_params.manual_thumb != null) { + // Use manually specified thumbnail +// $manual_title = Title::makeTitleSafe(NS_FILE, frame_params['manual_thumb']); +// if ($manual_title) { +// $manual_img = wfFindFile($manual_title); +// if ($manual_img) { +// thumb = $manual_img->getUnscaledThumb($handlerParams); +// manual_thumb = true; +// } else { +// exists = false; +// } +// } + } + else if (frame_params.framed != null) { + // Use image dimensions, don't scale +// thumb = $file->getUnscaledThumb($handlerParams); + no_scale = 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 +// $srcWidth = $file->getWidth($page); +// if ($srcWidth && !$file->mustRender() && $handlerParams['width'] > $srcWidth) { +// $handlerParams['width'] = $srcWidth; +// } +// thumb = $file->transform($handlerParams); + } + + if (thumb) { +// outer_width = thumb->getWidth() + 2; + } + else { +// outer_width = $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 +// $url = $title->getLocalURL($query); +// if ($page) { +// $url = wfAppendQuery($url, [ 'page' => $page ]); +// } + if (manual_thumb + && frame_params.link_title != null + && frame_params.link_url != null + && frame_params.no_link != null) { +// frame_params.link_url = url; + } + + int rv_bgn = bfr.Len(); + bfr.Add_str_a7("
"); + + byte[] zoom_icon = Bry_.Empty; + if (!exists) { +// $s .= self::makeBrokenImageLinkObj($title, frame_params['title'], '', '', '', $time == true); +// zoom_icon = ''; + } + else if (!thumb) { +// $s .= wfMessage('thumbnail_error', '')->escaped(); +// zoom_icon = ''; + } + else { + if (!no_scale && !manual_thumb) { +// self::processResponsiveImages($file, thumb, $handlerParams); + } +// $params = [ +// 'alt' => frame_params['alt'], +// 'title' => frame_params['title'], +// 'img-class' => (isset(frame_params['class']) && frame_params['class'] !== '' +// ? frame_params['class'] . ' ' +// : '') . 'thumbimage' +// ]; +// $params = self::getImageLinkMTOParams(frame_params, $query) + $params; +// $s .= thumb->toHtml($params); + if (frame_params.framed != null) { + zoom_icon = Bry_.Empty; + } + else { +// html_utl.Raw_element(bfr, Gfh_tag_.Bry__div, +// zoom_icon = Html::rawElement('div', [ 'class' => 'magnify' ], +// Html::rawElement('a', [ +// 'href' => $url, +// 'class' => '@gplx.Internal protected', +// 'title' => wfMessage('thumbnail-more')->text() ], +// "")); + } + } + bfr.Add_str_a7("
").Add(zoom_icon).Add(frame_params.caption).Add_str_a7("
"); + Bry_.Replace_all_direct(bfr.Bfr(), Byte_ascii.Nl, Byte_ascii.Space, rv_bgn, bfr.Len()); // str_replace("\n", ' ', $s); + } + // 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 @@ -283,218 +575,6 @@ public class Xomw_linker { } return split_trail_rv; } - public void Make_image(Bry_bfr bfr, Xoa_ttl title, byte[] options, boolean holders) { - // Check if the options text is of the form "options|alt text" - // Options are: - // * thumbnail make a thumbnail with enlarge-icon and caption, alignment depends on lang - // * left no resizing, just left align. label is used for alt= only - // * right same, but right aligned - // * none same, but not aligned - // * ___px scale to ___ pixels width, no aligning. e.g. use in taxobox - // * center center the image - // * frame Keep original image size, no magnify-button. - // * framed Same as "frame" - // * frameless like 'thumb' but without a frame. Keeps user preferences for width - // * upright reduce width for upright images, rounded to full __0 px - // * border draw a 1px border around the image - // * alt Text for HTML alt attribute (defaults to empty) - // * class Set a class for img node - // * link Set the target of the image link. Can be external, interwiki, or local - // vertical-align values (no % or length right now): - // * baseline - // * sub - // * super - // * top - // * text-top - // * middle - // * bottom - // * text-bottom - - // Protect LanguageConverter markup when splitting into parts -// $parts = StringUtils::delimiterExplode( -// '-{', '}-', '|', $options, true /* allow nesting */ -// ); - - // Give extensions a chance to select the file revision for us -// $options = []; -// $descQuery = false; - // MW.HOOK:BeforeParserFetchFileAndTitle - - // Fetch and register the file (file title may be different via hooks) -// list($file, $title) = $this->fetchFileAndTitle($title, $options); - - // Get parameter map -// $handler = $file ? $file->getHandler() : false; - -// list($paramMap, $mwArray) = $this->getImageParams($handler); - -// if (!$file) { -// $this->addTrackingCategory('broken-file-category'); -// } - - // Process the input parameters -// $caption = ''; -// $params = [ 'frame' => [], 'handler' => [], -// 'horizAlign' => [], 'vertAlign' => [] ]; -// $seenformat = false; -// foreach ($parts as $part) { -// $part = trim($part); -// list($magicName, $value) = $mwArray->matchVariableStartToEnd($part); -// $validated = false; -// if (isset($paramMap[$magicName])) { -// list($type, $paramName) = $paramMap[$magicName]; - - // Special case; width and height come in one variable together -// if ($type === 'handler' && $paramName === 'width') { -// $parsedWidthParam = $this->parseWidthParam($value); -// if (isset($parsedWidthParam['width'])) { -// $width = $parsedWidthParam['width']; -// if ($handler->validateParam('width', $width)) { -// $params[$type]['width'] = $width; -// $validated = true; -// } -// } -// if (isset($parsedWidthParam['height'])) { -// $height = $parsedWidthParam['height']; -// if ($handler->validateParam('height', $height)) { -// $params[$type]['height'] = $height; -// $validated = true; -// } -// } - // else no validation -- T15436 -// } else { -// if ($type === 'handler') { -// // Validate handler parameter -// $validated = $handler->validateParam($paramName, $value); -// } else { -// // Validate @gplx.Internal protected parameters -// switch ($paramName) { -// case 'manualthumb': -// case 'alt': -// case 'class': - // @todo FIXME: Possibly check validity here for - // manualthumb? downstream behavior seems odd with - // missing manual thumbs. -// $validated = true; -// $value = $this->stripAltText($value, $holders); -// break; -// case 'link': -// $chars = self::EXT_LINK_URL_CLASS; -// $addr = self::EXT_LINK_ADDR; -// $prots = $this->mUrlProtocols; -// if ($value === '') { -// $paramName = 'no-link'; -// $value = true; -// $validated = true; -// } else if (preg_match("/^((?i)$prots)/", $value)) { -// if (preg_match("/^((?i)$prots)$addr$chars*$/u", $value, $m)) { -// $paramName = 'link-url'; -// $this->mOutput->addExternalLink($value); -// if ($this->mOptions->getExternalLinkTarget()) { -// $params[$type]['link-target'] = $this->mOptions->getExternalLinkTarget(); -// } -// $validated = true; -// } -// } else { -// $linkTitle = Title::newFromText($value); -// if ($linkTitle) { -// $paramName = 'link-title'; -// $value = $linkTitle; -// $this->mOutput->addLink($linkTitle); -// $validated = true; -// } -// } -// break; -// case 'frameless': -// case 'framed': -// case 'thumbnail': -// // use first appearing option, discard others. -// $validated = !$seenformat; -// $seenformat = true; -// break; -// default: -// // Most other things appear to be empty or numeric... -// $validated = ($value === false || is_numeric(trim($value))); -// } -// } - -// if ($validated) { -// $params[$type][$paramName] = $value; -// } -// } -// } -// if (!$validated) { -// $caption = $part; -// } -// } - - // Process alignment parameters -// if ($params['horizAlign']) { -// $params['frame']['align'] = key($params['horizAlign']); -// } -// if ($params['vertAlign']) { -// $params['frame']['valign'] = key($params['vertAlign']); -// } - -// $params['frame']['caption'] = $caption; - - // Will the image be presented in a frame, with the caption below? -// $imageIsFramed = isset($params['frame']['frame']) -// || isset($params['frame']['framed']) -// || isset($params['frame']['thumbnail']) -// || isset($params['frame']['manualthumb']); - - // In the old days, [[Image:Foo|text...]] would set alt text. Later it - // came to also set the caption, ordinary text after the image -- which - // makes no sense, because that just repeats the text multiple times in - // screen readers. It *also* came to set the title attribute. - // Now that we have an alt attribute, we should not set the alt text to - // equal the caption: that's worse than useless, it just repeats the - // text. This is the framed/thumbnail case. If there's no caption, we - // use the unnamed parameter for alt text as well, just for the time be- - // ing, if the unnamed param is set and the alt param is not. - // For the future, we need to figure out if we want to tweak this more, - // e.g., introducing a title= parameter for the title; ignoring the un- - // named parameter entirely for images without a caption; adding an ex- - // plicit caption= parameter and preserving the old magic unnamed para- - // meter for BC; ... -// if ($imageIsFramed) { // Framed image -// if ($caption === '' && !isset($params['frame']['alt'])) { -// // No caption or alt text, add the filename as the alt text so -// // that screen readers at least get some description of the image -// $params['frame']['alt'] = $title->getText(); -// } - // Do not set $params['frame']['title'] because tooltips don't make sense - // for framed images -// } else { // Inline image -// if (!isset($params['frame']['alt'])) { -// // No alt text, use the "caption" for the alt text -// if ($caption !== '') { -// $params['frame']['alt'] = $this->stripAltText($caption, $holders); -// } else { -// // No caption, fall back to using the filename for the -// // alt text -// $params['frame']['alt'] = $title->getText(); -// } -// } - // Use the "caption" for the tooltip text -// $params['frame']['title'] = $this->stripAltText($caption, $holders); -// } - - // MW.HOOK:ParserMakeImageParams - - // Linker does the rest -// $time = isset($options['time']) ? $options['time'] : false; -// $ret = Linker::makeImageLink($this, $title, $file, $params['frame'], $params['handler'], -// $time, $descQuery, $this->mOptions->getThumbSize()); - - // Give the handler a chance to modify the parser Object -// if ($handler) { -// $handler->parserTransformHook($this, $file); -// } - -// return $ret; - } // public function getImageParams($handler) { // if ($handler) { // $handlerClass = get_class($handler); @@ -508,7 +588,7 @@ public class Xomw_linker { // 'horizAlign' => [ 'left', 'right', 'center', 'none' ], // 'vertAlign' => [ 'baseline', 'sub', 'super', 'top', 'text-top', 'middle', // 'bottom', 'text-bottom' ], -// 'frame' => [ 'thumbnail', 'manualthumb', 'framed', 'frameless', +// 'frame' => [ 'thumbnail', 'manual_thumb', 'framed', 'frameless', // 'upright', 'border', 'link', 'alt', 'class' ], // ]; // static $internalParamMap; @@ -537,135 +617,22 @@ public class Xomw_linker { // } // // Make HTML for a thumbnail including image, border and caption // public static function makeThumbLinkObj(Title $title, $file, $label = '', $alt, -// $align = 'right', $params = [], $framed = false, $manualthumb = "" +// $align = 'right', $params = [], $framed = false, $manual_thumb = "" // ) { -// $frameParams = [ +// frame_params = [ // 'alt' => $alt, // 'caption' => $label, // 'align' => $align // ]; // if ($framed) { -// $frameParams['framed'] = true; +// frame_params['framed'] = true; // } -// if ($manualthumb) { -// $frameParams['manualthumb'] = $manualthumb; +// if ($manual_thumb) { +// frame_params['manual_thumb'] = $manual_thumb; // } -// return self::makeThumbLink2($title, $file, $frameParams, $params); +// return self::makeThumbLink2($title, $file, frame_params, $params); // } -// public static function makeThumbLink2(Title $title, $file, $frameParams = [], -// $handlerParams = [], $time = false, $query = "" -// ) { -// $exists = $file && $file->exists(); -// -// $page = isset($handlerParams['page']) ? $handlerParams['page'] : false; -// if (!isset($frameParams['align'])) { -// $frameParams['align'] = 'right'; -// } -// if (!isset($frameParams['alt'])) { -// $frameParams['alt'] = ''; -// } -// if (!isset($frameParams['title'])) { -// $frameParams['title'] = ''; -// } -// if (!isset($frameParams['caption'])) { -// $frameParams['caption'] = ''; -// } -// -// if (empty($handlerParams['width'])) { -// // Reduce width for upright images when parameter 'upright' is used -// $handlerParams['width'] = isset($frameParams['upright']) ? 130 : 180; -// } -// $thumb = false; -// $noscale = false; -// $manualthumb = false; -// -// if (!$exists) { -// $outerWidth = $handlerParams['width'] + 2; -// } else { -// if (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 (isset($frameParams['framed'])) { -// // Use image dimensions, don't scale -// $thumb = $file->getUnscaledThumb($handlerParams); -// $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 -// $srcWidth = $file->getWidth($page); -// if ($srcWidth && !$file->mustRender() && $handlerParams['width'] > $srcWidth) { -// $handlerParams['width'] = $srcWidth; -// } -// $thumb = $file->transform($handlerParams); -// } -// -// if ($thumb) { -// $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 -// $url = $title->getLocalURL($query); -// if ($page) { -// $url = wfAppendQuery($url, [ 'page' => $page ]); -// } -// if ($manualthumb -// && !isset($frameParams['link-title']) -// && !isset($frameParams['link-url']) -// && !isset($frameParams['no-link'])) { -// $frameParams['link-url'] = $url; -// } -// -// $s = "
" -// . "
"; -// -// if (!$exists) { -// $s .= self::makeBrokenImageLinkObj($title, $frameParams['title'], '', '', '', $time == true); -// $zoomIcon = ''; -// } else if (!$thumb) { -// $s .= wfMessage('thumbnail_error', '')->escaped(); -// $zoomIcon = ''; -// } else { -// if (!$noscale && !$manualthumb) { -// self::processResponsiveImages($file, $thumb, $handlerParams); -// } -// $params = [ -// 'alt' => $frameParams['alt'], -// 'title' => $frameParams['title'], -// 'img-class' => (isset($frameParams['class']) && $frameParams['class'] !== '' -// ? $frameParams['class'] . ' ' -// : '') . 'thumbimage' -// ]; -// $params = self::getImageLinkMTOParams($frameParams, $query) + $params; -// $s .= $thumb->toHtml($params); -// if (isset($frameParams['framed'])) { -// $zoomIcon = ""; -// } else { -// $zoomIcon = Html::rawElement('div', [ 'class' => 'magnify' ], -// Html::rawElement('a', [ -// 'href' => $url, -// 'class' => '@gplx.Internal protected', -// 'title' => wfMessage('thumbnail-more')->text() ], -// "")); -// } -// } -// $s .= '
' . $zoomIcon . $frameParams['caption'] . "
"; -// return str_replace("\n", ' ', $s); -// } // // Make a "broken" link to an image // public static function makeBrokenImageLinkObj($title, $label = '', // $query = '', $unused1 = '', $unused2 = '', $time = false diff --git a/400_xowa/src/gplx/xowa/mws/htmls/Xomw_img_frame.java b/400_xowa/src/gplx/xowa/mws/htmls/Xomw_img_frame.java new file mode 100644 index 000000000..27de3a6b2 --- /dev/null +++ b/400_xowa/src/gplx/xowa/mws/htmls/Xomw_img_frame.java @@ -0,0 +1,34 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.xowa.mws.htmls; import gplx.*; import gplx.xowa.*; import gplx.xowa.mws.*; +public class Xomw_img_frame { + public byte[] align = null; + public byte[] valign = null; + public byte[] caption = null; + public byte[] frame = null; + public byte[] framed = null; + public byte[] frameless = null; + public byte[] thumbnail = null; + public byte[] manual_thumb = null; + public byte[] alt = null; + public byte[] title = null; + public byte[] cls = null; + public byte[] link_title = null; + public byte[] link_url = null; + public byte[] no_link = null; +} diff --git a/400_xowa/src/gplx/xowa/mws/htmls/Xomw_opt_mgr.java b/400_xowa/src/gplx/xowa/mws/htmls/Xomw_opt_mgr.java index 49ca5b582..b96d6df15 100644 --- a/400_xowa/src/gplx/xowa/mws/htmls/Xomw_opt_mgr.java +++ b/400_xowa/src/gplx/xowa/mws/htmls/Xomw_opt_mgr.java @@ -20,4 +20,5 @@ public class Xomw_opt_mgr { public boolean known; public boolean broken; public boolean no_classes; + public byte[] time = null; } diff --git a/400_xowa/src/gplx/xowa/mws/htmls/Xomw_prm_itm.java b/400_xowa/src/gplx/xowa/mws/htmls/Xomw_prm_itm.java new file mode 100644 index 000000000..01265ffb8 --- /dev/null +++ b/400_xowa/src/gplx/xowa/mws/htmls/Xomw_prm_itm.java @@ -0,0 +1,38 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.xowa.mws.htmls; import gplx.*; import gplx.xowa.*; import gplx.xowa.mws.*; +public class Xomw_prm_itm { + public int type = 0; + public int name_type = 1; + public byte[] name = null; + public byte[] val = null; + + public static final int + Type__handler = 0 + ; + public static final int + Name__width = 0 + , Name__manual_thumb = 0 + , Name__alt = 1 + , Name__class = 2 + , Name__link = 3 + , Name__frameless = 4 + , Name__framed = 5 + , Name__thumbnail = 6 + ; +} diff --git a/400_xowa/src/gplx/xowa/mws/htmls/Xomw_prm_mgr.java b/400_xowa/src/gplx/xowa/mws/htmls/Xomw_prm_mgr.java new file mode 100644 index 000000000..9630ae74a --- /dev/null +++ b/400_xowa/src/gplx/xowa/mws/htmls/Xomw_prm_mgr.java @@ -0,0 +1,30 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.xowa.mws.htmls; import gplx.*; import gplx.xowa.*; import gplx.xowa.mws.*; +public class Xomw_prm_mgr { + public Xomw_prm_itm Get_or_null(int name_type) { + return null; + } + public Xomw_prm_itm Get_or_null(byte[] key) { + return null; + } + public static final int + Name__horiz_align = 0 + , Name__vert_align = 1 + ; +} diff --git a/400_xowa/src/gplx/xowa/mws/parsers/lnkis/Xomw_lnki_wkr.java b/400_xowa/src/gplx/xowa/mws/parsers/lnkis/Xomw_lnki_wkr.java index 1d25638db..ce8eb776e 100644 --- a/400_xowa/src/gplx/xowa/mws/parsers/lnkis/Xomw_lnki_wkr.java +++ b/400_xowa/src/gplx/xowa/mws/parsers/lnkis/Xomw_lnki_wkr.java @@ -23,6 +23,18 @@ import gplx.xowa.mws.parsers.*; import gplx.xowa.mws.parsers.quotes.*; import gplx.xowa.mws.htmls.*; import gplx.xowa.mws.linkers.*; import gplx.xowa.mws.utls.*; import gplx.xowa.parsers.uniqs.*; +/* TODO.XO + * P7: multi-line links; // look at the next 'line' to see if we can close it there + * P7: interwiki + * P7: [[File:]] + * P7: [[Category:]] + * P6: [[Media:]] + * P4: handle "]]]"; "If we get a ] at the beginning of $m[3]" + * P4: handle "[[http://a.org]]" + * P3: $langObj->formatNum( ++$this->mAutonumber ); + * P2: $this->getConverterLanguage()->markNoConversion( $text ); + * P1: link_prefix; EX: b[[A]]; [not enabled on enwiki] +*/ public class Xomw_lnki_wkr {// THREAD.UNSAFE: caching for repeated calls private final Xomw_link_holders holders; private final Xomw_linker linker; @@ -73,9 +85,12 @@ public class Xomw_lnki_wkr {// THREAD.UNSAFE: caching for repeated calls Replace_internal_links(bfr, src, src_bgn, src_end); } + // XO.MW:SYNC:1.29; DATE:2017-02-02 public void Replace_internal_links(Bry_bfr bfr, byte[] src, int src_bgn, int src_end) { - // PORTED: regex for tc move to header; e1 and e1_img moved to code - // split the entire text String on occurrences of [[ + // XO.MW: regex for tc move to header; e1 and e1_img moved to code + // the % is needed to support urlencoded titles as well + + // XO.MW.BGN: split the entire text String on occurrences of [[ int cur = src_bgn; int prv = cur; while (true) { @@ -86,9 +101,9 @@ public class Xomw_lnki_wkr {// THREAD.UNSAFE: caching for repeated calls } cur = lnki_bgn + 2; // 2="[[".length - // IGNORE: handles strange split logic of adding space to String; "$s = substr($s, 1);" + // XO.MW.IGNORE: handles strange split logic of adding space to String; "$s = substr($s, 1);" - // TODO.XO:lnke_bgn; EX: b[[A]] + // TODO.XO:link_prefix; EX: b[[A]] // $useLinkPrefixExtension = $this->getTargetLanguage()->linkPrefixExtension(); // $e2 = null; // if ($useLinkPrefixExtension) { @@ -103,7 +118,7 @@ public class Xomw_lnki_wkr {// THREAD.UNSAFE: caching for repeated calls // $nottalk = !$this->mTitle->isTalkPage(); - // TODO.XO:lnke_bgn + // TODO.XO:link_prefix byte[] prefix = Bry_.Empty; //if ($useLinkPrefixExtension) { // $m = []; @@ -116,9 +131,7 @@ public class Xomw_lnki_wkr {// THREAD.UNSAFE: caching for repeated calls // $prefix = ''; //} - // IGNORE: "Check for excessive memory usage" - - // TODO.XO:lnke_bgn; EX: b[[A]] + // TODO.XO:link_prefix; EX: b[[A]] //if ($useLinkPrefixExtension) { // if (preg_match($e2, $s, $m)) { // $prefix = $m[2]; @@ -183,6 +196,7 @@ public class Xomw_lnki_wkr {// THREAD.UNSAFE: caching for repeated calls byte[] text = Bry_.Mid(src, capt_bgn, capt_end); byte[] trail = Bry_.Empty; if (!might_be_img) { + // TODO.XO: // If we get a ] at the beginning of $m[3] that means we have a link that's something like: // [[Image:Foo.jpg|[http://example.com desc]]] <- having three ] in a row fucks up, // the real problem is with the $e1 regex @@ -416,6 +430,248 @@ public class Xomw_lnki_wkr {// THREAD.UNSAFE: caching for repeated calls } } } + public void Make_image(Bry_bfr bfr, Xoa_ttl title, byte[] options, boolean holders) { + // Check if the options text is of the form "options|alt text" + // Options are: + // * thumbnail make a thumbnail with enlarge-icon and caption, alignment depends on lang + // * left no resizing, just left align. label is used for alt= only + // * right same, but right aligned + // * none same, but not aligned + // * ___px scale to ___ pixels width, no aligning. e.g. use in taxobox + // * center center the image + // * frame Keep original image size, no magnify-button. + // * framed Same as "frame" + // * frameless like 'thumb' but without a frame. Keeps user preferences for width + // * upright reduce width for upright images, rounded to full __0 px + // * border draw a 1px border around the image + // * alt Text for HTML alt attribute (defaults to empty) + // * class Set a class for img node + // * link Set the target of the image link. Can be external, interwiki, or local + // vertical-align values (no % or length right now): + // * baseline + // * sub + // * super + // * top + // * text-top + // * middle + // * bottom + // * text-bottom + + // Protect LanguageConverter markup when splitting into parts +// $parts = StringUtils::delimiterExplode( +// '-{', '}-', '|', $options, true /* allow nesting */ +// ); + + // Give extensions a chance to select the file revision for us +// $options = []; +// $descQuery = false; + // MW.HOOK:BeforeParserFetchFileAndTitle + + // Fetch and register the file (file title may be different via hooks) +// list($file, $title) = $this->fetchFileAndTitle($title, $options); + + // Get parameter map +// $handler = $file ? $file->getHandler() : false; + +// list($paramMap, $mwArray) = $this->getImageParams($handler); + +// if (!$file) { +// $this->addTrackingCategory('broken-file-category'); +// } + + // Process the input parameters +// caption = ''; +// $params = [ 'frame' => [], 'handler' => [], +// 'horizAlign' => [], 'vertAlign' => [] ]; +// $seenformat = false; +// foreach ($parts as $part) { + Xomw_prm_mgr param_map = new Xomw_prm_mgr(); + Xomw_prm_mgr param_mgr = new Xomw_prm_mgr(); + byte[] caption = Bry_.Empty; + + byte[] part = null; + part = Bry_.Trim(part); + byte[] magic_name = null; // $mwArray->matchVariableStartToEnd($part); + boolean validated = false; + + Xomw_prm_itm prm_itm = param_map.Get_or_null(magic_name); + if (prm_itm != null) { + int prm_type = prm_itm.type; + int prm_name = prm_itm.name_type; + // Special case; width and height come in one variable together + if (prm_type == Xomw_prm_itm.Type__handler && prm_name == Xomw_prm_itm.Name__width) { +// $parsedWidthParam = $this->parseWidthParam($value); +// if (isset($parsedWidthParam['width'])) { +// $width = $parsedWidthParam['width']; +// if ($handler->validateParam('width', $width)) { +// $params[$type]['width'] = $width; +// validated = true; +// } +// } +// if (isset($parsedWidthParam['height'])) { +// $height = $parsedWidthParam['height']; +// if ($handler->validateParam('height', $height)) { +// $params[$type]['height'] = $height; +// validated = true; +// } +// } + // else no validation -- T15436 + } + else { + if (prm_type == Xomw_prm_itm.Type__handler) { + // Validate handler parameter + // validated = $handler->validateParam($paramName, $value); + } + else { + // Validate @gplx.Internal protected parameters + switch (prm_name) { + case Xomw_prm_itm.Name__manual_thumb: + case Xomw_prm_itm.Name__alt: + case Xomw_prm_itm.Name__class: + // @todo FIXME: Possibly check validity here for + // manualthumb? downstream behavior seems odd with + // missing manual thumbs. + validated = true; + // $value = $this->stripAltText($value, $holders); + break; + case Xomw_prm_itm.Name__link: +// $chars = self::EXT_LINK_URL_CLASS; +// $addr = self::EXT_LINK_ADDR; +// $prots = $this->mUrlProtocols; +// if ($value === '') { +// $paramName = 'no-link'; +// $value = true; +// validated = true; +// } else if (preg_match("/^((?i)$prots)/", $value)) { +// if (preg_match("/^((?i)$prots)$addr$chars*$/u", $value, $m)) { +// $paramName = 'link-url'; +// $this->mOutput->addExternalLink($value); +// if ($this->mOptions->getExternalLinkTarget()) { +// $params[$type]['link-target'] = $this->mOptions->getExternalLinkTarget(); +// } +// validated = true; +// } +// } else { +// $linkTitle = Title::newFromText($value); +// if ($linkTitle) { +// $paramName = 'link-title'; +// $value = $linkTitle; +// $this->mOutput->addLink($linkTitle); +// validated = true; +// } +// } + break; + case Xomw_prm_itm.Name__frameless: + case Xomw_prm_itm.Name__framed: + case Xomw_prm_itm.Name__thumbnail: + // use first appearing option, discard others. + // validated = !$seenformat; + // $seenformat = true; + break; + default: + // Most other things appear to be empty or numeric... + // validated = ($value === false || is_numeric(trim($value))); + break; + } + } + } + } + if (!validated) { + caption = part; + } +// } + + // Process alignment parameters + Xomw_prm_itm tmp = param_mgr.Get_or_null(Xomw_prm_mgr.Name__horiz_align); + Xomw_img_frame frame = new Xomw_img_frame(); // param_mgr.frame; + if (tmp != null) { + frame.align = tmp.val; + } + tmp = param_mgr.Get_or_null(Xomw_prm_mgr.Name__vert_align); + if (tmp != null) { + frame.valign = tmp.val; + } + + frame.caption = caption; + + boolean image_is_framed + = frame.frame != null + || frame.framed != null + || frame.thumbnail != null + || frame.manual_thumb != null + ; + + // Will the image be presented in a frame, with the caption below? + // In the old days, [[Image:Foo|text...]] would set alt text. Later it + // came to also set the caption, ordinary text after the image -- which + // makes no sense, because that just repeats the text multiple times in + // screen readers. It *also* came to set the title attribute. + // Now that we have an alt attribute, we should not set the alt text to + // equal the caption: that's worse than useless, it just repeats the + // text. This is the framed/thumbnail case. If there's no caption, we + // use the unnamed parameter for alt text as well, just for the time be- + // ing, if the unnamed param is set and the alt param is not. + // For the future, we need to figure out if we want to tweak this more, + // e.g., introducing a title= parameter for the title; ignoring the un- + // named parameter entirely for images without a caption; adding an ex- + // plicit caption= parameter and preserving the old magic unnamed para- + // meter for BC; ... + if (image_is_framed) { // Framed image + if (caption == Bry_.Empty && frame.alt == null) { + // No caption or alt text, add the filename as the alt text so + // that screen readers at least get some description of the image +// frame.alt = title.Get_text(); + } + // Do not set $params['frame']['title'] because tooltips don't make sense + // for framed images + } + else { // Inline image + if (frame.alt == null) { + // No alt text, use the "caption" for the alt text + if (caption != Bry_.Empty) { +// frame.alt = $this->stripAltText(caption, $holders); + } + else { + // No caption, fall back to using the filename for the + // alt text +// frame.alt = title.Get_text(); + } + } + // Use the "caption" for the tooltip text +// frame.title = $this->stripAltText(caption, $holders); + } + + // MW.HOOK:ParserMakeImageParams + + // Linker does the rest +// byte[] time = options.time; +// $ret = Linker::makeImageLink($this, $title, $file, $params['frame'], $params['handler'], +// $time, $descQuery, $this->mOptions->getThumbSize()); +// +// // Give the handler a chance to modify the parser Object +// if (handler != null) { +// $handler->parserTransformHook($this, $file); +// } + } +// protected function stripAltText( $caption, $holders ) { +// // Strip bad stuff out of the title (tooltip). We can't just use +// // replaceLinkHoldersText() here, because if this function is called +// // from replaceInternalLinks2(), mLinkHolders won't be up-to-date. +// if ( $holders ) { +// $tooltip = $holders->replaceText( $caption ); +// } else { +// $tooltip = $this->replaceLinkHoldersText( $caption ); +// } +// +// // make sure there are no placeholders in thumbnail attributes +// // that are later expanded to html- so expand them now and +// // remove the tags +// $tooltip = $this->mStripState->unstripBoth( $tooltip ); +// $tooltip = Sanitizer::stripAllTags( $tooltip ); +// +// return $tooltip; +// } + public void Maybe_do_subpage_link(Xomw_linker__normalize_subpage_link rv, byte[] target, byte[] text) { linker.Normalize_subpage_link(rv, page_title, target, text); } diff --git a/400_xowa/src/gplx/xowa/mws/parsers/lnkis/Xomw_lnki_wkr__tst.java b/400_xowa/src/gplx/xowa/mws/parsers/lnkis/Xomw_lnki_wkr__tst.java index 8ac4bde78..4b64446fa 100644 --- a/400_xowa/src/gplx/xowa/mws/parsers/lnkis/Xomw_lnki_wkr__tst.java +++ b/400_xowa/src/gplx/xowa/mws/parsers/lnkis/Xomw_lnki_wkr__tst.java @@ -27,7 +27,9 @@ public class Xomw_lnki_wkr__tst { // @Test public void Capt() {fxt.Test__parse("a [[A|a]] z" , "a a z");} // @Test public void Text() {fxt.Test__parse("a [[A]] z" , "a z");} // @Test public void Invalid__char() {fxt.Test__parse("[[]]" , "[[]]");} - @Test public void Self() {fxt.Test__to_html("[[Page_1]]" , "Page_1");} + @Test public void Html__self() {fxt.Test__to_html("[[Page_1]]" , "Page_1");} + @Test public void Html__text() {fxt.Test__to_html("[[A]]" , "A");} + @Test public void Html__capt() {fxt.Test__to_html("[[A|a]]" , "a");} } class Xomw_lnki_wkr__fxt { private final Xomw_lnki_wkr wkr;