/** * Core parser tag hook function for 'pre'. * Text is treated roughly as 'nowiki' wrapped in an HTML 'pre' tag; * valid HTML attributes are passed on. * * @param string $text * @param array $attribs * @param Parser $parser * @return string HTML */ public static function pre($text, $attribs, $parser) { // Backwards-compatibility hack $content = StringUtils::delimiterReplace('<nowiki>', '</nowiki>', '$1', $text, 'i'); $attribs = Sanitizer::validateTagAttributes($attribs, 'pre'); return Xml::openElement('pre', $attribs) . Xml::escapeTagsOnly($content) . '</pre>'; }
function PoemExtension($in, $param = array(), $parser = null) { /* using newlines in the text will cause the parser to add <p> tags, * which may not be desired in some cases */ $nl = isset($param['compact']) ? '' : "\n"; if (method_exists($parser, 'recursiveTagParse')) { //new methods in 1.8 allow nesting <nowiki> in <poem>. $tag = $parser->insertStripItem("<br />", $parser->mStripState); $text = preg_replace(array("/^\n/", "/\n\$/D", "/\n/", "/^( +)/me"), array("", "", "{$tag}\n", "str_replace(' ',' ','\\1')"), $in); $text = $parser->recursiveTagParse($text); } else { $text = preg_replace(array("/^\n/", "/\n\$/D", "/\n/", "/^( +)/me"), array("", "", "<br />\n", "str_replace(' ',' ','\\1')"), $in); $ret = $parser->parse($text, $parser->getTitle(), $parser->getOptions(), true, false); $text = $ret->getText(); } global $wgVersion; if (version_compare($wgVersion, "1.7alpha") >= 0) { // Pass HTML attributes through to the output. $attribs = Sanitizer::validateTagAttributes($param, 'div'); } else { // Can't guarantee safety on 1.6 or older. $attribs = array(); } // Wrap output in a <div> with "poem" class. if (isset($attribs['class'])) { $attribs['class'] = 'poem ' . $attribs['class']; } else { $attribs['class'] = 'poem'; } return Xml::openElement('div', $attribs) . $nl . trim($text) . "{$nl}</div>"; }
/** * Core parser tag hook function for 'pre'. * Text is treated roughly as 'nowiki' wrapped in an HTML 'pre' tag; * valid HTML attributes are passed on. * * @param string $text * @param array $attribs * @param Parser $parser * @return string HTML */ public static function pre($text, $attribs, $parser) { // Backwards-compatibility hack $content = StringUtils::delimiterReplace('<nowiki>', '</nowiki>', '$1', $text, 'i'); $attribs = Sanitizer::validateTagAttributes($attribs, 'pre'); // We need to let both '"' and '&' through, // for strip markers and entities respectively. $content = str_replace(['>', '<'], ['>', '<'], $content); return Html::rawElement('pre', $attribs, $content); }
/** * @param $in * @param array $param * @param $parser Parser * @param bool $frame * @return string */ function wfRenderPoemTag($in, $param = array(), $parser = null, $frame = false) { /* using newlines in the text will cause the parser to add <p> tags, * which may not be desired in some cases */ $nl = isset($param['compact']) ? '' : "\n"; $tag = $parser->insertStripItem("<br />", $parser->mStripState); $text = preg_replace(array("/^\n/", "/\n\$/D", "/\n/"), array("", "", "{$tag}\n"), $in); $text = preg_replace_callback('/^( +)/m', 'wfPoemReplaceSpaces', $text); $text = $parser->recursiveTagParse($text, $frame); $attribs = Sanitizer::validateTagAttributes($param, 'div'); // Wrap output in a <div> with "poem" class. if (isset($attribs['class'])) { $attribs['class'] = 'poem ' . $attribs['class']; } else { $attribs['class'] = 'poem'; } return Html::rawElement('div', $attribs, $nl . trim($text) . $nl); }
/** * Parse the text into proper poem format * @param string $in The text inside the poem tag * @param array $param * @param Parser $parser * @param boolean $frame * @return string */ public static function renderPoem($in, $param = array(), $parser = null, $frame = false) { // using newlines in the text will cause the parser to add <p> tags, // which may not be desired in some cases $newline = isset($param['compact']) ? '' : "\n"; $tag = $parser->insertStripItem("<br />", $parser->mStripState); // replace colons with indented spans $text = preg_replace_callback('/^(:+)(.+)$/m', array('Poem', 'indentVerse'), $in); // replace newlines with <br /> tags unless they are at the beginning or end // of the poem $text = preg_replace(array("/^\n/", "/\n\$/D", "/\n/"), array("", "", "{$tag}\n"), $text); // replace spaces at the beginning of a line with non-breaking spaces $text = preg_replace_callback('/^( +)/m', array('Poem', 'replaceSpaces'), $text); $text = $parser->recursiveTagParse($text, $frame); $attribs = Sanitizer::validateTagAttributes($param, 'div'); // Wrap output in a <div> with "poem" class. if (isset($attribs['class'])) { $attribs['class'] = 'poem ' . $attribs['class']; } else { $attribs['class'] = 'poem'; } return Html::rawElement('div', $attribs, $newline . trim($text) . $newline); }
/** * Renders an image gallery from a text with one line per image. * text labels may be given by using |-style alternative text. E.g. * Image:one.jpg|The number "1" * Image:tree.jpg|A tree * given as text will return the HTML of a gallery with two images, * labeled 'The number "1"' and * 'A tree'. * * @param string $text * @param array $params * @return string HTML */ function renderImageGallery($text, $params) { $ig = new ImageGallery(); $ig->setContextTitle($this->mTitle); $ig->setShowBytes(false); $ig->setShowFilename(false); $ig->setParser($this); $ig->setHideBadImages(); $ig->setAttributes(Sanitizer::validateTagAttributes($params, 'table')); if (isset($params['showfilename'])) { $ig->setShowFilename(true); } else { $ig->setShowFilename(false); } if (isset($params['caption'])) { $caption = $params['caption']; $caption = htmlspecialchars($caption); $caption = $this->replaceInternalLinks($caption); $ig->setCaptionHtml($caption); } if (isset($params['perrow'])) { $ig->setPerRow($params['perrow']); } if (isset($params['widths'])) { $ig->setWidths($params['widths']); } if (isset($params['heights'])) { $ig->setHeights($params['heights']); } wfRunHooks('BeforeParserrenderImageGallery', array(&$this, &$ig)); $lines = StringUtils::explode("\n", $text); foreach ($lines as $line) { # match lines like these: # Image:someimage.jpg|This is some image $matches = array(); preg_match("/^([^|]+)(\\|(.*))?\$/", $line, $matches); # Skip empty lines if (count($matches) == 0) { continue; } if (strpos($matches[0], '%') !== false) { $matches[1] = rawurldecode($matches[1]); } $title = Title::newFromText($matches[1], NS_FILE); if (is_null($title)) { # Bogus title. Ignore these so we don't bomb out later. continue; } $label = ''; $alt = ''; $link = ''; if (isset($matches[3])) { // look for an |alt= definition while trying not to break existing // captions with multiple pipes (|) in it, until a more sensible grammar // is defined for images in galleries $matches[3] = $this->recursiveTagParse(trim($matches[3])); $parameterMatches = StringUtils::explode('|', $matches[3]); $magicWordAlt = MagicWord::get('img_alt'); $magicWordLink = MagicWord::get('img_link'); foreach ($parameterMatches as $parameterMatch) { if ($match = $magicWordAlt->matchVariableStartToEnd($parameterMatch)) { $alt = $this->stripAltText($match, false); } elseif ($match = $magicWordLink->matchVariableStartToEnd($parameterMatch)) { $link = strip_tags($this->replaceLinkHoldersText($match)); $chars = self::EXT_LINK_URL_CLASS; $prots = $this->mUrlProtocols; //check to see if link matches an absolute url, if not then it must be a wiki link. if (!preg_match("/^({$prots}){$chars}+\$/u", $link)) { $localLinkTitle = Title::newFromText($link); $link = $localLinkTitle->getLocalURL(); } } else { // concatenate all other pipes $label .= '|' . $parameterMatch; } } // remove the first pipe $label = substr($label, 1); } $ig->add($title, $label, $alt, $link); } return $ig->toHTML(); }
/** * Take a tag soup fragment listing an HTML element's attributes * and normalize it to well-formed XML, discarding unwanted attributes. * Output is safe for further wikitext processing, with escaping of * values that could trigger problems. * * - Normalizes attribute names to lowercase * - Discards attributes not on a whitelist for the given element * - Turns broken or invalid entities into plaintext * - Double-quotes all attribute values * - Attributes without values are given the name as attribute * - Double attributes are discarded * - Unsafe style attributes are discarded * - Prepends space if there are attributes. * * @param string $text * @param string $element * @return string */ static function fixTagAttributes($text, $element) { if (trim($text) == '') { return ''; } $decoded = Sanitizer::decodeTagAttributes($text); $stripped = Sanitizer::validateTagAttributes($decoded, $element); return Sanitizer::safeEncodeTagAttributes($stripped); }
/** * Take a tag soup fragment listing an HTML element's attributes * and normalize it to well-formed XML, discarding unwanted attributes. * Output is safe for further wikitext processing, with escaping of * values that could trigger problems. * * - Normalizes attribute names to lowercase * - Discards attributes not on a whitelist for the given element * - Turns broken or invalid entities into plaintext * - Double-quotes all attribute values * - Attributes without values are given the name as attribute * - Double attributes are discarded * - Unsafe style attributes are discarded * - Prepends space if there are attributes. * * @param $text String * @param $element String * @return String */ static function fixTagAttributes($text, $element) { if (trim($text) == '') { return ''; } $stripped = Sanitizer::validateTagAttributes(Sanitizer::decodeTagAttributes($text), $element); $attribs = array(); foreach ($stripped as $attribute => $value) { $encAttribute = htmlspecialchars($attribute); $encValue = Sanitizer::safeEncodeAttribute($value); $attribs[] = "{$encAttribute}=\"{$encValue}\""; } return count($attribs) ? ' ' . implode(' ', $attribs) : ''; }
function _attribs($tag, $defaults = array(), $overrides = array()) { $attribs = Sanitizer::validateTagAttributes($this->params, $tag); $attribs = Sanitizer::mergeAttributes($defaults, $attribs); $attribs = Sanitizer::mergeAttributes($attribs, $overrides); return $attribs; }
/** * Take a tag soup fragment listing an HTML element's attributes * and normalize it to well-formed XML, discarding unwanted attributes. * Output is safe for further wikitext processing, with escaping of * values that could trigger problems. * * - Normalizes attribute names to lowercase * - Discards attributes not on a whitelist for the given element * - Turns broken or invalid entities into plaintext * - Double-quotes all attribute values * - Attributes without values are given the name as attribute * - Double attributes are discarded * - Unsafe style attributes are discarded * - Prepends space if there are attributes. * * @param $text String * @param $element String * @return String */ static function fixTagAttributes($text, $element) { if (trim($text) == '') { return ''; } $decoded = Sanitizer::decodeTagAttributes($text); $decoded = Sanitizer::fixDeprecatedAttributes($decoded, $element); $stripped = Sanitizer::validateTagAttributes($decoded, $element); $attribs = array(); foreach ($stripped as $attribute => $value) { $encAttribute = htmlspecialchars($attribute); $encValue = Sanitizer::safeEncodeAttribute($value); # RTE (Rich Text Editor) - begin # @author: Inez Korczyński, macbre global $wgRTEParserEnabled; if (!empty($wgRTEParserEnabled) && $encAttribute == 'style') { // BugId:2462 - remove apostrophes from style attribute $encValue = str_replace(''', '', $encValue); $attribs[] = "data-rte-style=\"{$encValue}\""; } # RTE - end $attribs[] = "{$encAttribute}=\"{$encValue}\""; } # RTE (Rich Text Editor) - begin # @author: Inez Korczyński global $wgRTEParserEnabled; if (!empty($wgRTEParserEnabled)) { if (strpos($text, "") !== false) { RTE::$edgeCases[] = 'COMPLEX.08'; } $attribs[] = RTEParser::encodeAttributesStr($text); } # RTE - end return count($attribs) ? ' ' . implode(' ', $attribs) : ''; }
/** * Parser hook * * @param string $text * @param array $args * @param Parser $parser * @return string */ public static function parserHook($text, $args = array(), $parser) { global $wgSyntaxHighlightDefaultLang, $wgUseTidy; self::initialise(); $text = rtrim($text); // Don't trim leading spaces away, just the linefeeds $text = preg_replace('/^\\n+/', '', $text); // Validate language if (isset($args['lang']) && $args['lang']) { $lang = $args['lang']; } else { // language is not specified. Check if default exists, if yes, use it. if (!is_null($wgSyntaxHighlightDefaultLang)) { $lang = $wgSyntaxHighlightDefaultLang; } else { $error = self::formatLanguageError($text); return $error; } } $lang = strtolower($lang); if (!preg_match('/^[a-z_0-9-]*$/', $lang)) { $error = self::formatLanguageError($text); return $error; } $geshi = self::prepare($text, $lang); if (!$geshi instanceof GeSHi) { $error = self::formatLanguageError($text); return $error; } $enclose = self::getEncloseType($args); // Line numbers if (isset($args['line'])) { $geshi->enable_line_numbers(GESHI_FANCY_LINE_NUMBERS); } // Highlighting specific lines if (isset($args['highlight'])) { $lines = self::parseHighlightLines($args['highlight']); if (count($lines)) { $geshi->highlight_lines_extra($lines); } } // Starting line number if (isset($args['start'])) { $geshi->start_line_numbers_at($args['start']); } $geshi->set_header_type($enclose); // Strict mode if (isset($args['strict'])) { $geshi->enable_strict_mode(); } // Remove font override $geshi->set_overall_style(''); $geshi->set_code_style('margin:0; padding:0; background:none; vertical-align:top;'); // Format $out = $geshi->parse_code(); if ($geshi->error == GESHI_ERROR_NO_SUCH_LANG) { // Common error :D $error = self::formatLanguageError($text); return $error; } $err = $geshi->error(); if ($err) { // Other unknown error! $error = self::formatError($err); return $error; } // Armour for Parser::doBlockLevels() if ($enclose === GESHI_HEADER_DIV) { $out = str_replace("\n", '', $out); } // HTML Tidy will convert tabs to spaces incorrectly (bug 30930). // But the conversion from tab to space occurs while reading the input, // before the conversion from 	 to tab, so we can armor it that way. if ($wgUseTidy) { $out = str_replace("\t", '	', $out); } // Register CSS $parser->getOutput()->addModuleStyles(array("ext.geshi.language.{$lang}", 'ext.geshi.local')); $encloseTag = $enclose === GESHI_HEADER_NONE ? 'span' : 'div'; $attribs = Sanitizer::validateTagAttributes($args, $encloseTag); //lang is valid in HTML context, but also used on GeSHi unset($attribs['lang']); if ($enclose === GESHI_HEADER_NONE) { $attribs = self::addAttribute($attribs, 'class', 'mw-geshi ' . $lang . ' source-' . $lang); } else { // Default dir="ltr" (but allow dir="rtl", although unsure if needed) $attribs['dir'] = isset($attribs['dir']) && $attribs['dir'] === 'rtl' ? 'rtl' : 'ltr'; $attribs = self::addAttribute($attribs, 'class', 'mw-geshi mw-code mw-content-' . $attribs['dir']); } $out = Html::rawElement($encloseTag, $attribs, $out); return $out; }
/** * Entry point for the <categorytree> tag parser hook. * This loads CategoryTreeFunctions.php and calls CategoryTree::getTag() */ function efCategoryTreeParserHook($cat, $argv, $parser = null, $allowMissing = false) { global $wgOut; if ($parser) { $parser->mOutput->mCategoryTreeTag = true; # flag for use by efCategoryTreeParserOutput } else { CategoryTree::setHeaders($wgOut); } $ct = new CategoryTree($argv); $attr = Sanitizer::validateTagAttributes($argv, 'div'); $hideroot = isset($argv['hideroot']) ? CategoryTree::decodeBoolean($argv['hideroot']) : null; $onlyroot = isset($argv['onlyroot']) ? CategoryTree::decodeBoolean($argv['onlyroot']) : null; $depthArg = isset($argv['depth']) ? (int) $argv['depth'] : null; $depth = efCategoryTreeCapDepth($ct->getOption('mode'), $depthArg); if ($onlyroot) { $depth = 0; } return $ct->getTag($parser, $cat, $hideroot, $attr, $depth, $allowMissing); }
/** * Parser hook * * @param string $text * @param array $args * @param Parser $parser * @return string */ public static function parserHook( $text, $args = array(), $parser ) { global $wgSyntaxHighlightDefaultLang, $wgUseSiteCss, $wgUseTidy; wfProfileIn( __METHOD__ ); self::initialise(); $text = rtrim( $text ); // Don't trim leading spaces away, just the linefeeds $text = preg_replace( '/^\n+/', '', $text ); if( $wgUseTidy ) { // HTML Tidy will convert tabs to spaces incorrectly (bug 30930). // Preemptively replace the spaces in a more controlled fashion. $text = self::tabsToSpaces( $text ); } // Validate language if( isset( $args['lang'] ) && $args['lang'] ) { $lang = $args['lang']; } else { // language is not specified. Check if default exists, if yes, use it. if ( !is_null( $wgSyntaxHighlightDefaultLang ) ) { $lang = $wgSyntaxHighlightDefaultLang; } else { $error = self::formatLanguageError( $text ); wfProfileOut( __METHOD__ ); return $error; } } $lang = strtolower( $lang ); if( !preg_match( '/^[a-z_0-9-]*$/', $lang ) ) { $error = self::formatLanguageError( $text ); wfProfileOut( __METHOD__ ); return $error; } $geshi = self::prepare( $text, $lang ); if( !$geshi instanceof GeSHi ) { $error = self::formatLanguageError( $text ); wfProfileOut( __METHOD__ ); return $error; } $enclose = self::getEncloseType( $args ); // Line numbers if( isset( $args['line'] ) ) { $geshi->enable_line_numbers( GESHI_FANCY_LINE_NUMBERS ); } // Highlighting specific lines if( isset( $args['highlight'] ) ) { $lines = self::parseHighlightLines( $args['highlight'] ); if ( count( $lines ) ) { $geshi->highlight_lines_extra( $lines ); } } // Starting line number if( isset( $args['start'] ) ) { $geshi->start_line_numbers_at( $args['start'] ); } $geshi->set_header_type( $enclose ); // Strict mode if( isset( $args['strict'] ) ) { $geshi->enable_strict_mode(); } // Format $out = $geshi->parse_code(); if ( $geshi->error == GESHI_ERROR_NO_SUCH_LANG ) { // Common error :D $error = self::formatLanguageError( $text ); wfProfileOut( __METHOD__ ); return $error; } $err = $geshi->error(); if( $err ) { // Other unknown error! $error = self::formatError( $err ); wfProfileOut( __METHOD__ ); return $error; } // Armour for Parser::doBlockLevels() if( $enclose === GESHI_HEADER_DIV ) { $out = str_replace( "\n", '', $out ); } // Register CSS $parser->getOutput()->addHeadItem( self::buildHeadItem( $geshi ), "source-{$lang}" ); if( $wgUseSiteCss ) { $parser->getOutput()->addModuleStyles( 'ext.geshi.local' ); } $encloseTag = $enclose === GESHI_HEADER_NONE ? 'span' : 'div'; $attribs = Sanitizer::validateTagAttributes( $args, $encloseTag ); //lang is valid in HTML context, but also used on GeSHi unset( $attribs['lang'] ); if ( $enclose === GESHI_HEADER_NONE ) { $attribs = self::addAttribute( $attribs, 'class', 'mw-geshi ' . $lang . ' source-' . $lang ); } else { // Default dir="ltr" (but allow dir="rtl", although unsure if needed) $attribs['dir'] = isset( $attribs['dir'] ) && $attribs['dir'] === 'rtl' ? 'rtl' : 'ltr'; $attribs = self::addAttribute( $attribs, 'class', 'mw-geshi mw-content-' . $attribs['dir'] ); } $out = Xml::tags( $encloseTag, $attribs, $out ); wfProfileOut( __METHOD__ ); return $out; }
/** * Tag hook handler for 'pre'. */ function renderPreTag($text, $attribs, $parser) { // Backwards-compatibility hack $content = preg_replace('!<nowiki>(.*?)</nowiki>!is', '\\1', $text); $attribs = Sanitizer::validateTagAttributes($attribs, 'pre'); return wfOpenElement('pre', $attribs) . wfEscapeHTMLTagsOnly($content) . '</pre>'; }
/** * Entry point for the <categorytree> tag parser hook. * This loads CategoryTreeFunctions.php and calls CategoryTree::getTag() */ function efCategoryTreeParserHook($cat, $argv, &$parser) { global $wgCategoryTreeDefaultMode; $parser->mOutput->mCategoryTreeTag = true; # flag for use by efCategoryTreeParserOutput static $initialized = false; $divAttribs = Sanitizer::validateTagAttributes($argv, 'div'); $style = isset($divAttribs['style']) ? $divAttribs['style'] : null; $mode = isset($argv['mode']) ? $argv['mode'] : null; if ($mode !== NULL) { $mode = trim(strtolower($mode)); if ($mode == 'all') { $mode = CT_MODE_ALL; } else { if ($mode == 'pages') { $mode = CT_MODE_PAGES; } else { if ($mode == 'categories') { $mode = CT_MODE_CATEGORIES; } } } } else { $mode = $wgCategoryTreeDefaultMode; } $hideroot = isset($argv['hideroot']) ? efCategoryTreeAsBool($argv['hideroot']) : null; $onlyroot = isset($argv['onlyroot']) ? efCategoryTreeAsBool($argv['onlyroot']) : null; $depthArg = isset($argv['depth']) ? $argv['depth'] : null; $depth = efCategoryTreeCapDepth($mode, $depthArg); if ($onlyroot) { $depth = 0; } $ct = new CategoryTree(); return $ct->getTag($parser, $cat, $mode, $hideroot, $style, $depth); }
/** * Renders an image gallery from a text with one line per image. * text labels may be given by using |-style alternative text. E.g. * Image:one.jpg|The number "1" * Image:tree.jpg|A tree * given as text will return the HTML of a gallery with two images, * labeled 'The number "1"' and * 'A tree'. */ function renderImageGallery($text, $params) { $ig = new ImageGallery(); $ig->setContextTitle($this->mTitle); $ig->setShowBytes(false); $ig->setShowFilename(false); $ig->setParser($this); $ig->setHideBadImages(); $ig->setAttributes(Sanitizer::validateTagAttributes($params, 'table')); $ig->useSkin($this->mOptions->getSkin()); $ig->mRevisionId = $this->mRevisionId; if (isset($params['caption'])) { $caption = $params['caption']; $caption = htmlspecialchars($caption); $caption = $this->replaceInternalLinks($caption); $ig->setCaptionHtml($caption); } if (isset($params['perrow'])) { $ig->setPerRow($params['perrow']); } if (isset($params['widths'])) { $ig->setWidths($params['widths']); } if (isset($params['heights'])) { $ig->setHeights($params['heights']); } wfRunHooks('BeforeParserrenderImageGallery', array(&$this, &$ig)); $lines = StringUtils::explode("\n", $text); foreach ($lines as $line) { # match lines like these: # Image:someimage.jpg|This is some image $matches = array(); preg_match("/^([^|]+)(\\|(.*))?\$/", $line, $matches); # Skip empty lines if (count($matches) == 0) { continue; } if (strpos($matches[0], '%') !== false) { $matches[1] = urldecode($matches[1]); } $tp = Title::newFromText($matches[1]); $nt =& $tp; if (is_null($nt)) { # Bogus title. Ignore these so we don't bomb out later. continue; } if (isset($matches[3])) { $label = $matches[3]; } else { $label = ''; } $html = $this->recursiveTagParse(trim($label)); $ig->add($nt, $html); # Only add real images (bug #5586) if ($nt->getNamespace() == NS_FILE) { $this->mOutput->addImage($nt->getDBkey()); } } return $ig->toHTML(); }
/** * Renders an image gallery from a text with one line per image. * text labels may be given by using |-style alternative text. E.g. * Image:one.jpg|The number "1" * Image:tree.jpg|A tree * given as text will return the HTML of a gallery with two images, * labeled 'The number "1"' and * 'A tree'. * * @param string $text * @param array $params * @return string HTML */ function renderImageGallery($text, $params) { wfProfileIn(__METHOD__); $mode = false; if (isset($params['mode'])) { $mode = $params['mode']; } try { $ig = ImageGalleryBase::factory($mode); } catch (MWException $e) { // If invalid type set, fallback to default. $ig = ImageGalleryBase::factory(false); } $ig->setContextTitle($this->mTitle); $ig->setShowBytes(false); $ig->setShowFilename(false); $ig->setParser($this); $ig->setHideBadImages(); $ig->setAttributes(Sanitizer::validateTagAttributes($params, 'table')); if (isset($params['showfilename'])) { $ig->setShowFilename(true); } else { $ig->setShowFilename(false); } if (isset($params['caption'])) { $caption = $params['caption']; $caption = htmlspecialchars($caption); $caption = $this->replaceInternalLinks($caption); $ig->setCaptionHtml($caption); } if (isset($params['perrow'])) { $ig->setPerRow($params['perrow']); } if (isset($params['widths'])) { $ig->setWidths($params['widths']); } if (isset($params['heights'])) { $ig->setHeights($params['heights']); } $ig->setAdditionalOptions($params); wfRunHooks('BeforeParserrenderImageGallery', array(&$this, &$ig)); $lines = StringUtils::explode("\n", $text); foreach ($lines as $line) { # match lines like these: # Image:someimage.jpg|This is some image $matches = array(); preg_match("/^([^|]+)(\\|(.*))?\$/", $line, $matches); # Skip empty lines if (count($matches) == 0) { continue; } if (strpos($matches[0], '%') !== false) { $matches[1] = rawurldecode($matches[1]); } $title = Title::newFromText($matches[1], NS_FILE); if (is_null($title)) { # Bogus title. Ignore these so we don't bomb out later. continue; } # We need to get what handler the file uses, to figure out parameters. # Note, a hook can overide the file name, and chose an entirely different # file (which potentially could be of a different type and have different handler). $options = array(); $descQuery = false; wfRunHooks('BeforeParserFetchFileAndTitle', array($this, $title, &$options, &$descQuery)); # Don't register it now, as ImageGallery does that later. $file = $this->fetchFileNoRegister($title, $options); $handler = $file ? $file->getHandler() : false; wfProfileIn(__METHOD__ . '-getMagicWord'); $paramMap = array('img_alt' => 'gallery-internal-alt', 'img_link' => 'gallery-internal-link'); if ($handler) { $paramMap = $paramMap + $handler->getParamMap(); // We don't want people to specify per-image widths. // Additionally the width parameter would need special casing anyhow. unset($paramMap['img_width']); } $mwArray = new MagicWordArray(array_keys($paramMap)); wfProfileOut(__METHOD__ . '-getMagicWord'); $label = ''; $alt = ''; $link = ''; $handlerOptions = array(); if (isset($matches[3])) { // look for an |alt= definition while trying not to break existing // captions with multiple pipes (|) in it, until a more sensible grammar // is defined for images in galleries // FIXME: Doing recursiveTagParse at this stage, and the trim before // splitting on '|' is a bit odd, and different from makeImage. $matches[3] = $this->recursiveTagParse(trim($matches[3])); $parameterMatches = StringUtils::explode('|', $matches[3]); foreach ($parameterMatches as $parameterMatch) { list($magicName, $match) = $mwArray->matchVariableStartToEnd($parameterMatch); if ($magicName) { $paramName = $paramMap[$magicName]; switch ($paramName) { case 'gallery-internal-alt': $alt = $this->stripAltText($match, false); break; case 'gallery-internal-link': $linkValue = strip_tags($this->replaceLinkHoldersText($match)); $chars = self::EXT_LINK_URL_CLASS; $prots = $this->mUrlProtocols; //check to see if link matches an absolute url, if not then it must be a wiki link. if (preg_match("/^({$prots}){$chars}+\$/u", $linkValue)) { $link = $linkValue; } else { $localLinkTitle = Title::newFromText($linkValue); if ($localLinkTitle !== null) { $link = $localLinkTitle->getLocalURL(); } } break; default: // Must be a handler specific parameter. if ($handler->validateParam($paramName, $match)) { $handlerOptions[$paramName] = $match; } else { // Guess not. Append it to the caption. wfDebug("{$parameterMatch} failed parameter validation\n"); $label .= '|' . $parameterMatch; } } } else { // concatenate all other pipes $label .= '|' . $parameterMatch; } } // remove the first pipe $label = substr($label, 1); } $ig->add($title, $label, $alt, $link, $handlerOptions); } $html = $ig->toHTML(); wfProfileOut(__METHOD__); return $html; }
/** * Renders an image gallery from a text with one line per image. * text labels may be given by using |-style alternative text. E.g. * Image:one.jpg|The number "1" * Image:tree.jpg|A tree * given as text will return the HTML of a gallery with two images, * labeled 'The number "1"' and * 'A tree'. * * @param string $text * @param array $params * @return string HTML */ function renderImageGallery($text, $params) { $ig = new ImageGallery(); /* Wikia change begin - @author: Macbre */ /* Allow extensions to use different class to render image gallery */ wfRunHooks('renderImageGallerySetup', array(&$ig, &$text, &$params)); /* Wikia change end */ $ig->setContextTitle($this->mTitle); $ig->setShowBytes(false); $ig->setShowFilename(false); $ig->setParser($this); $ig->setHideBadImages(); $ig->setAttributes(Sanitizer::validateTagAttributes($params, 'table')); if (isset($params['showfilename'])) { $ig->setShowFilename(true); } else { $ig->setShowFilename(false); } if (isset($params['caption'])) { $caption = $params['caption']; $caption = htmlspecialchars($caption); $caption = $this->replaceInternalLinks($caption); $ig->setCaptionHtml($caption); } if (isset($params['perrow'])) { $ig->setPerRow($params['perrow']); } if (isset($params['widths'])) { $ig->setWidths($params['widths']); } if (isset($params['heights'])) { $ig->setHeights($params['heights']); } /* Wikia change begin */ /* Allow extensions to use their own "parser" for <gallery> tag content */ if (!wfRunHooks('BeforeParserrenderImageGallery', array(&$this, &$ig))) { return $ig->toHTML(); } /* Wikia change end */ $lines = StringUtils::explode("\n", $text); foreach ($lines as $line) { # match lines like these: # Image:someimage.jpg|This is some image $matches = array(); preg_match("/^([^|]+)(\\|(.*))?\$/", $line, $matches); # Skip empty lines if (count($matches) == 0) { continue; } if (strpos($matches[0], '%') !== false) { $matches[1] = rawurldecode($matches[1]); } $title = Title::newFromText($matches[1], NS_FILE); if (is_null($title)) { # Bogus title. Ignore these so we don't bomb out later. continue; } $label = ''; $alt = ''; if (isset($matches[3])) { // look for an |alt= definition while trying not to break existing // captions with multiple pipes (|) in it, until a more sensible grammar // is defined for images in galleries $matches[3] = $this->recursiveTagParse(trim($matches[3])); $altmatches = StringUtils::explode('|', $matches[3]); $magicWordAlt = MagicWord::get('img_alt'); foreach ($altmatches as $altmatch) { $match = $magicWordAlt->matchVariableStartToEnd($altmatch); if ($match) { $alt = $this->stripAltText($match, false); } else { // concatenate all other pipes $label .= '|' . $altmatch; } } // remove the first pipe $label = substr($label, 1); } $ig->add($title, $label, $alt); } return $ig->toHTML(); }