/**
  * @param Parser $parser
  * @return array
  */
 public static function render($parser)
 {
     $html = '';
     $html .= $parser->insertStripItem('<a href="#" class="custom-watchlist-wrapper" id="add-to-watchlist"></a>');
     $parser->getOutput()->addModules('ext.customwatchlist.foo');
     return array($html, 'markerType' => 'nowiki');
 }
 /**
  * Outputs the internal image wrapped in a link
  * @param Parser $parser Instance of running Parser.
  * @param String $image Name of image to display.
  * @param String $url External URL to which to link
  * @param String $alt Alternate text for image and link (optional)
  * @return String A parser strip flag which will be later replaced with raw html.
  */
 function imageLink($parser, $image = null, $url = null, $alt = '')
 {
     # Short-circuit if requried params are missing
     if ($image === null || $url === null) {
         return $this->error('missing-params');
     }
     # Prepare incomming params
     $image = trim($image);
     $url = trim($url);
     $alt = trim($alt);
     # Check for bad URLs
     if (!preg_match('/^(' . wfUrlProtocols() . ')/', $url) || preg_match('/\'"/', $url)) {
         $t = Title::newFromText($url);
         if (!$t) {
             return $this->error('bad-url', $url);
         }
         $url = $t->getFullURL();
     }
     # Check to see that the selected image exists
     $imageObj = Image::newFromName($image);
     if (!$imageObj->exists()) {
         return $this->error('no-such-image', $image);
     }
     # Finally, since all checks passed, display it!
     return $parser->insertStripItem($this->msg('embed-clause', htmlentities($url, ENT_COMPAT), $imageObj->getURL(), htmlentities($alt, ENT_COMPAT)), $parser->mStripState);
 }
 /**
  * @param Parser $parser
  * @return string
  */
 public static function sprintbtn($parser)
 {
     $html = '';
     $title = $parser->getTitle();
     $link = $title->getFullURL('printable=yes');
     $link = '#';
     $parser->getOutput()->addModules('ext.stools.foo');
     $html .= $parser->insertStripItem('<a id="print-button" href="' . $link . '" type="button" class="btn btn-primary"><i class="fa fa-print"></i> ' . wfMessage('stools-button-print')->plain() . '</a>');
     return $html;
 }
Exemple #4
0
 /**
  * Handler for rendering the function hook.
  * 
  * @since 0.4
  * 
  * @param Parser $parser
  * ... further arguments ...
  * 
  * @return array
  */
 public function renderFunction()
 {
     $args = func_get_args();
     $this->parser = array_shift($args);
     $output = $this->validateAndRender($args, self::TYPE_FUNCTION);
     $options = $this->getFunctionOptions();
     if (array_key_exists('isHTML', $options) && $options['isHTML']) {
         return $this->parser->insertStripItem($output, $this->parser->mStripState);
     }
     return array_merge(array($output), $options);
 }
Exemple #5
0
/**
 * Creates a HTML link that will open in a new browser window or tab.
 *
 * @param Parser $parser Parser being used
 * @param string $target literal URI or a MediaWiki link for linked resource
 * @param string $label link text
 * @return string HTML
 */
function efParserCreateLink($parser, $target, $label = null)
{
    // sanitise the input and set defaults
    if (is_null($label)) {
        $label = $target;
        $label = htmlspecialchars($label, ENT_NOQUOTES, 'UTF-8');
    } else {
        $label = preg_replace("/\\b({$parser->mUrlProtocols})/", "\$1 ", $label);
        // Hack to not parse external links by breaking them
        $label = $parser->recursiveTagParse($label);
        $label = preg_replace("/\\b({$parser->mUrlProtocols}) /", "\$1", $label);
        // Put them back together
    }
    $attributes = array('target' => '_blank');
    // WARNING: the order of the statements below does matter!
    //
    // Also, the Parser::insertStripItem is used to render the HTML inline.
    // See: http://www.mediawiki.org/wiki/Manual:Parser_functions#Parser_interface
    // Process (or rule out) external targets (literal URIs)
    if (preg_match($parser->mExtLinkBracketedRegex, "[{$target}]")) {
        return $parser->insertStripItem(Linker::makeExternalLink($target, $label, false, '', $attributes), $parser->mStripState);
    }
    // The target is not a literal URI.  Create a Title object.
    $oTitle = Title::newFromText($target);
    // Title::newFromText may occasionally return null, which means something is really wrong with the $target.
    if (is_null($oTitle)) {
        return $parser->insertStripItem(wfMsg('newwindowlinks-invalid-target'), $parser->mStripState);
    }
    // Process (or rule out) existing local articles.
    if ($oTitle->exists()) {
        return $parser->insertStripItem(Linker::link($oTitle, $label, $attributes), $parser->mStripState);
    }
    // Process (or rule out) interwiki links.
    if (true !== $oTitle->isLocal()) {
        return $parser->insertStripItem(Linker::makeExternalLink($oTitle->getFullURL(), $label, false, '', $attributes), $parser->mStripState);
    }
    // Only non existing local articles remain.
    return $parser->insertStripItem(Linker::link($oTitle, $label, $attributes), $parser->mStripState);
}
 /**
  * Handler for rendering the function hook registered by Parser::setFunctionHook()
  *
  * @since 0.4
  *
  * @param Parser &$parser
  * ... further arguments ...
  *
  * @return array
  */
 public function renderFunction(Parser &$parser)
 {
     $args = func_get_args();
     $this->parser = array_shift($args);
     $output = $this->validateAndRender($args, self::TYPE_FUNCTION);
     $options = $this->getFunctionOptions();
     if (array_key_exists('isHTML', $options) && $options['isHTML']) {
         /** @ToDo: FIXME: Is this really necessary? The same thing is propably going to
          *                happen in Parser::braceSubstitution() if 'isHTML' is set!
          *  @ToDo: other options besides 'isHTML' like 'noparse' are ignored here!
          */
         return $this->parser->insertStripItem($output, $this->parser->mStripState);
     }
     return array_merge(array($output), $options);
 }
 /**
  * @param Parser $parser
  * @return string
  */
 public static function render($parser)
 {
     $user = $parser->getUser();
     $title = $parser->getTitle();
     if (!$title || !$title->exists()) {
         return '';
     }
     $author = self::getPageAuthor($title);
     if (!$author) {
         return '';
     }
     $html = '<span class="author-rating-wrapper">';
     // Add user link
     $html .= $parser->insertStripItem(' <a target="_blank" href="' . $author->getUserPage()->getFullURL() . '">' . $author->getName() . '</a>');
     $html .= ' <i style="display: none;" class="fa fa-thumbs-o-up author-thumbs-up" title="' . wfMessage('authorrating-rate-title')->plain() . '"></i>';
     $html .= ' <span class="label label-success">?</span>';
     $html .= '</span>';
     $parser->getOutput()->addModules('ext.authorrating.foo');
     return array($html, 'markerType' => 'nowiki');
 }
Exemple #8
0
 /**
  * Renders the #serieslink parser function.
  * 
  * @param Parser $parser
  * @return string the unique tag which must be inserted into the stripped text 
  */
 public static function renderSeriesLink(&$parser)
 {
     global $wgTitle;
     $params = func_get_args();
     array_shift($params);
     // We don't need the parser.
     // remove the target parameter should it be present
     foreach ($params as $key => $value) {
         $elements = explode('=', $value, 2);
         if ($elements[0] === 'target') {
             unset($params[$key]);
         }
     }
     // set the origin parameter
     // This will block it from use as iterator parameter. Oh well.
     $params[] = "origin=" . $parser->getTitle()->getArticleId();
     // hack to remove newline from beginning of output, thanks to
     // http://jimbojw.com/wiki/index.php?title=Raw_HTML_Output_from_a_MediaWiki_Parser_Function
     return $parser->insertStripItem(SFUtils::createFormLink($parser, 'SeriesEdit', $params), $parser->mStripState);
 }
 /**
  * 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);
 }
Exemple #10
0
 /**
  * @throws MWException
  * @param string|PPNode_DOM|DOMDocument $root
  * @param int $flags
  * @return string
  */
 public function expand($root, $flags = 0)
 {
     static $expansionDepth = 0;
     if (is_string($root)) {
         return $root;
     }
     if (++$this->parser->mPPNodeCount > $this->parser->mOptions->getMaxPPNodeCount()) {
         $this->parser->limitationWarn('node-count-exceeded', $this->parser->mPPNodeCount, $this->parser->mOptions->getMaxPPNodeCount());
         return '<span class="error">Node-count limit exceeded</span>';
     }
     if ($expansionDepth > $this->parser->mOptions->getMaxPPExpandDepth()) {
         $this->parser->limitationWarn('expansion-depth-exceeded', $expansionDepth, $this->parser->mOptions->getMaxPPExpandDepth());
         return '<span class="error">Expansion depth limit exceeded</span>';
     }
     ++$expansionDepth;
     if ($expansionDepth > $this->parser->mHighestExpansionDepth) {
         $this->parser->mHighestExpansionDepth = $expansionDepth;
     }
     if ($root instanceof PPNode_DOM) {
         $root = $root->node;
     }
     if ($root instanceof DOMDocument) {
         $root = $root->documentElement;
     }
     $outStack = array('', '');
     $iteratorStack = array(false, $root);
     $indexStack = array(0, 0);
     while (count($iteratorStack) > 1) {
         $level = count($outStack) - 1;
         $iteratorNode =& $iteratorStack[$level];
         $out =& $outStack[$level];
         $index =& $indexStack[$level];
         if ($iteratorNode instanceof PPNode_DOM) {
             $iteratorNode = $iteratorNode->node;
         }
         if (is_array($iteratorNode)) {
             if ($index >= count($iteratorNode)) {
                 // All done with this iterator
                 $iteratorStack[$level] = false;
                 $contextNode = false;
             } else {
                 $contextNode = $iteratorNode[$index];
                 $index++;
             }
         } elseif ($iteratorNode instanceof DOMNodeList) {
             if ($index >= $iteratorNode->length) {
                 // All done with this iterator
                 $iteratorStack[$level] = false;
                 $contextNode = false;
             } else {
                 $contextNode = $iteratorNode->item($index);
                 $index++;
             }
         } else {
             // Copy to $contextNode and then delete from iterator stack,
             // because this is not an iterator but we do have to execute it once
             $contextNode = $iteratorStack[$level];
             $iteratorStack[$level] = false;
         }
         if ($contextNode instanceof PPNode_DOM) {
             $contextNode = $contextNode->node;
         }
         $newIterator = false;
         if ($contextNode === false) {
             // nothing to do
         } elseif (is_string($contextNode)) {
             $out .= $contextNode;
         } elseif (is_array($contextNode) || $contextNode instanceof DOMNodeList) {
             $newIterator = $contextNode;
         } elseif ($contextNode instanceof DOMNode) {
             if ($contextNode->nodeType == XML_TEXT_NODE) {
                 $out .= $contextNode->nodeValue;
             } elseif ($contextNode->nodeName == 'template') {
                 # Double-brace expansion
                 $xpath = new DOMXPath($contextNode->ownerDocument);
                 $titles = $xpath->query('title', $contextNode);
                 $title = $titles->item(0);
                 $parts = $xpath->query('part', $contextNode);
                 if ($flags & PPFrame::NO_TEMPLATES) {
                     $newIterator = $this->virtualBracketedImplode('{{', '|', '}}', $title, $parts);
                 } else {
                     $lineStart = $contextNode->getAttribute('lineStart');
                     $params = array('title' => new PPNode_DOM($title), 'parts' => new PPNode_DOM($parts), 'lineStart' => $lineStart);
                     $ret = $this->parser->braceSubstitution($params, $this);
                     if (isset($ret['object'])) {
                         $newIterator = $ret['object'];
                     } else {
                         $out .= $ret['text'];
                     }
                 }
             } elseif ($contextNode->nodeName == 'tplarg') {
                 # Triple-brace expansion
                 $xpath = new DOMXPath($contextNode->ownerDocument);
                 $titles = $xpath->query('title', $contextNode);
                 $title = $titles->item(0);
                 $parts = $xpath->query('part', $contextNode);
                 if ($flags & PPFrame::NO_ARGS) {
                     $newIterator = $this->virtualBracketedImplode('{{{', '|', '}}}', $title, $parts);
                 } else {
                     $params = array('title' => new PPNode_DOM($title), 'parts' => new PPNode_DOM($parts));
                     $ret = $this->parser->argSubstitution($params, $this);
                     if (isset($ret['object'])) {
                         $newIterator = $ret['object'];
                     } else {
                         $out .= $ret['text'];
                     }
                 }
             } elseif ($contextNode->nodeName == 'comment') {
                 # HTML-style comment
                 # Remove it in HTML, pre+remove and STRIP_COMMENTS modes
                 # Not in RECOVER_COMMENTS mode (msgnw) though.
                 if (($this->parser->ot['html'] || $this->parser->ot['pre'] && $this->parser->mOptions->getRemoveComments() || $flags & PPFrame::STRIP_COMMENTS) && !($flags & PPFrame::RECOVER_COMMENTS)) {
                     $out .= '';
                 } elseif ($this->parser->ot['wiki'] && !($flags & PPFrame::RECOVER_COMMENTS)) {
                     # Add a strip marker in PST mode so that pstPass2() can
                     # run some old-fashioned regexes on the result.
                     # Not in RECOVER_COMMENTS mode (extractSections) though.
                     $out .= $this->parser->insertStripItem($contextNode->textContent);
                 } else {
                     # Recover the literal comment in RECOVER_COMMENTS and pre+no-remove
                     $out .= $contextNode->textContent;
                 }
             } elseif ($contextNode->nodeName == 'ignore') {
                 # Output suppression used by <includeonly> etc.
                 # OT_WIKI will only respect <ignore> in substed templates.
                 # The other output types respect it unless NO_IGNORE is set.
                 # extractSections() sets NO_IGNORE and so never respects it.
                 if (!isset($this->parent) && $this->parser->ot['wiki'] || $flags & PPFrame::NO_IGNORE) {
                     $out .= $contextNode->textContent;
                 } else {
                     $out .= '';
                 }
             } elseif ($contextNode->nodeName == 'ext') {
                 # Extension tag
                 $xpath = new DOMXPath($contextNode->ownerDocument);
                 $names = $xpath->query('name', $contextNode);
                 $attrs = $xpath->query('attr', $contextNode);
                 $inners = $xpath->query('inner', $contextNode);
                 $closes = $xpath->query('close', $contextNode);
                 if ($flags & PPFrame::NO_TAGS) {
                     $s = '<' . $this->expand($names->item(0), $flags);
                     if ($attrs->length > 0) {
                         $s .= $this->expand($attrs->item(0), $flags);
                     }
                     if ($inners->length > 0) {
                         $s .= '>' . $this->expand($inners->item(0), $flags);
                         if ($closes->length > 0) {
                             $s .= $this->expand($closes->item(0), $flags);
                         }
                     } else {
                         $s .= '/>';
                     }
                     $out .= $s;
                 } else {
                     $params = array('name' => new PPNode_DOM($names->item(0)), 'attr' => $attrs->length > 0 ? new PPNode_DOM($attrs->item(0)) : null, 'inner' => $inners->length > 0 ? new PPNode_DOM($inners->item(0)) : null, 'close' => $closes->length > 0 ? new PPNode_DOM($closes->item(0)) : null);
                     $out .= $this->parser->extensionSubstitution($params, $this);
                 }
             } elseif ($contextNode->nodeName == 'h') {
                 # Heading
                 $s = $this->expand($contextNode->childNodes, $flags);
                 # Insert a heading marker only for <h> children of <root>
                 # This is to stop extractSections from going over multiple tree levels
                 if ($contextNode->parentNode->nodeName == 'root' && $this->parser->ot['html']) {
                     # Insert heading index marker
                     $headingIndex = $contextNode->getAttribute('i');
                     $titleText = $this->title->getPrefixedDBkey();
                     $this->parser->mHeadings[] = array($titleText, $headingIndex);
                     $serial = count($this->parser->mHeadings) - 1;
                     $marker = Parser::MARKER_PREFIX . "-h-{$serial}-" . Parser::MARKER_SUFFIX;
                     $count = $contextNode->getAttribute('level');
                     $s = substr($s, 0, $count) . $marker . substr($s, $count);
                     $this->parser->mStripState->addGeneral($marker, '');
                 }
                 $out .= $s;
             } else {
                 # Generic recursive expansion
                 $newIterator = $contextNode->childNodes;
             }
         } else {
             throw new MWException(__METHOD__ . ': Invalid parameter type');
         }
         if ($newIterator !== false) {
             if ($newIterator instanceof PPNode_DOM) {
                 $newIterator = $newIterator->node;
             }
             $outStack[] = '';
             $iteratorStack[] = $newIterator;
             $indexStack[] = 0;
         } elseif ($iteratorStack[$level] === false) {
             // Return accumulated value to parent
             // With tail recursion
             while ($iteratorStack[$level] === false && $level > 0) {
                 $outStack[$level - 1] .= $out;
                 array_pop($outStack);
                 array_pop($iteratorStack);
                 array_pop($indexStack);
                 $level--;
             }
         }
     }
     --$expansionDepth;
     return $outStack[0];
 }
Exemple #11
0
 /**
  * @throws MWException
  * @param string|PPNode $root
  * @param int $flags
  * @return string
  */
 public function expand($root, $flags = 0)
 {
     static $expansionDepth = 0;
     if (is_string($root)) {
         return $root;
     }
     if (++$this->parser->mPPNodeCount > $this->parser->mOptions->getMaxPPNodeCount()) {
         $this->parser->limitationWarn('node-count-exceeded', $this->parser->mPPNodeCount, $this->parser->mOptions->getMaxPPNodeCount());
         return '<span class="error">Node-count limit exceeded</span>';
     }
     if ($expansionDepth > $this->parser->mOptions->getMaxPPExpandDepth()) {
         $this->parser->limitationWarn('expansion-depth-exceeded', $expansionDepth, $this->parser->mOptions->getMaxPPExpandDepth());
         return '<span class="error">Expansion depth limit exceeded</span>';
     }
     ++$expansionDepth;
     if ($expansionDepth > $this->parser->mHighestExpansionDepth) {
         $this->parser->mHighestExpansionDepth = $expansionDepth;
     }
     $outStack = array('', '');
     $iteratorStack = array(false, $root);
     $indexStack = array(0, 0);
     while (count($iteratorStack) > 1) {
         $level = count($outStack) - 1;
         $iteratorNode =& $iteratorStack[$level];
         $out =& $outStack[$level];
         $index =& $indexStack[$level];
         if (is_array($iteratorNode)) {
             if ($index >= count($iteratorNode)) {
                 // All done with this iterator
                 $iteratorStack[$level] = false;
                 $contextNode = false;
             } else {
                 $contextNode = $iteratorNode[$index];
                 $index++;
             }
         } elseif ($iteratorNode instanceof PPNode_Hash_Array) {
             if ($index >= $iteratorNode->getLength()) {
                 // All done with this iterator
                 $iteratorStack[$level] = false;
                 $contextNode = false;
             } else {
                 $contextNode = $iteratorNode->item($index);
                 $index++;
             }
         } else {
             // Copy to $contextNode and then delete from iterator stack,
             // because this is not an iterator but we do have to execute it once
             $contextNode = $iteratorStack[$level];
             $iteratorStack[$level] = false;
         }
         $newIterator = false;
         if ($contextNode === false) {
             // nothing to do
         } elseif (is_string($contextNode)) {
             $out .= $contextNode;
         } elseif (is_array($contextNode) || $contextNode instanceof PPNode_Hash_Array) {
             $newIterator = $contextNode;
         } elseif ($contextNode instanceof PPNode_Hash_Attr) {
             // No output
         } elseif ($contextNode instanceof PPNode_Hash_Text) {
             $out .= $contextNode->value;
         } elseif ($contextNode instanceof PPNode_Hash_Tree) {
             if ($contextNode->name == 'template') {
                 # Double-brace expansion
                 $bits = $contextNode->splitTemplate();
                 if ($flags & PPFrame::NO_TEMPLATES) {
                     $newIterator = $this->virtualBracketedImplode('{{', '|', '}}', $bits['title'], $bits['parts']);
                 } else {
                     $ret = $this->parser->braceSubstitution($bits, $this);
                     if (isset($ret['object'])) {
                         $newIterator = $ret['object'];
                     } else {
                         $out .= $ret['text'];
                     }
                 }
             } elseif ($contextNode->name == 'tplarg') {
                 # Triple-brace expansion
                 $bits = $contextNode->splitTemplate();
                 if ($flags & PPFrame::NO_ARGS) {
                     $newIterator = $this->virtualBracketedImplode('{{{', '|', '}}}', $bits['title'], $bits['parts']);
                 } else {
                     $ret = $this->parser->argSubstitution($bits, $this);
                     if (isset($ret['object'])) {
                         $newIterator = $ret['object'];
                     } else {
                         $out .= $ret['text'];
                     }
                 }
             } elseif ($contextNode->name == 'comment') {
                 # HTML-style comment
                 # Remove it in HTML, pre+remove and STRIP_COMMENTS modes
                 # Not in RECOVER_COMMENTS mode (msgnw) though.
                 if (($this->parser->ot['html'] || $this->parser->ot['pre'] && $this->parser->mOptions->getRemoveComments() || $flags & PPFrame::STRIP_COMMENTS) && !($flags & PPFrame::RECOVER_COMMENTS)) {
                     $out .= '';
                 } elseif ($this->parser->ot['wiki'] && !($flags & PPFrame::RECOVER_COMMENTS)) {
                     # Add a strip marker in PST mode so that pstPass2() can
                     # run some old-fashioned regexes on the result.
                     # Not in RECOVER_COMMENTS mode (extractSections) though.
                     $out .= $this->parser->insertStripItem($contextNode->firstChild->value);
                 } else {
                     # Recover the literal comment in RECOVER_COMMENTS and pre+no-remove
                     $out .= $contextNode->firstChild->value;
                 }
             } elseif ($contextNode->name == 'ignore') {
                 # Output suppression used by <includeonly> etc.
                 # OT_WIKI will only respect <ignore> in substed templates.
                 # The other output types respect it unless NO_IGNORE is set.
                 # extractSections() sets NO_IGNORE and so never respects it.
                 if (!isset($this->parent) && $this->parser->ot['wiki'] || $flags & PPFrame::NO_IGNORE) {
                     $out .= $contextNode->firstChild->value;
                 } else {
                     // $out .= '';
                 }
             } elseif ($contextNode->name == 'ext') {
                 # Extension tag
                 $bits = $contextNode->splitExt() + array('attr' => null, 'inner' => null, 'close' => null);
                 if ($flags & PPFrame::NO_TAGS) {
                     $s = '<' . $bits['name']->firstChild->value;
                     if ($bits['attr']) {
                         $s .= $bits['attr']->firstChild->value;
                     }
                     if ($bits['inner']) {
                         $s .= '>' . $bits['inner']->firstChild->value;
                         if ($bits['close']) {
                             $s .= $bits['close']->firstChild->value;
                         }
                     } else {
                         $s .= '/>';
                     }
                     $out .= $s;
                 } else {
                     $out .= $this->parser->extensionSubstitution($bits, $this);
                 }
             } elseif ($contextNode->name == 'h') {
                 # Heading
                 if ($this->parser->ot['html']) {
                     # Expand immediately and insert heading index marker
                     $s = '';
                     for ($node = $contextNode->firstChild; $node; $node = $node->nextSibling) {
                         $s .= $this->expand($node, $flags);
                     }
                     $bits = $contextNode->splitHeading();
                     $titleText = $this->title->getPrefixedDBkey();
                     $this->parser->mHeadings[] = array($titleText, $bits['i']);
                     $serial = count($this->parser->mHeadings) - 1;
                     $marker = Parser::MARKER_PREFIX . "-h-{$serial}-" . Parser::MARKER_SUFFIX;
                     $s = substr($s, 0, $bits['level']) . $marker . substr($s, $bits['level']);
                     $this->parser->mStripState->addGeneral($marker, '');
                     $out .= $s;
                 } else {
                     # Expand in virtual stack
                     $newIterator = $contextNode->getChildren();
                 }
             } else {
                 # Generic recursive expansion
                 $newIterator = $contextNode->getChildren();
             }
         } else {
             throw new MWException(__METHOD__ . ': Invalid parameter type');
         }
         if ($newIterator !== false) {
             $outStack[] = '';
             $iteratorStack[] = $newIterator;
             $indexStack[] = 0;
         } elseif ($iteratorStack[$level] === false) {
             // Return accumulated value to parent
             // With tail recursion
             while ($iteratorStack[$level] === false && $level > 0) {
                 $outStack[$level - 1] .= $out;
                 array_pop($outStack);
                 array_pop($iteratorStack);
                 array_pop($indexStack);
                 $level--;
             }
         }
     }
     --$expansionDepth;
     return $outStack[0];
 }
Exemple #12
0
/**
 * This expects to find:
 * 	{{#topic:Text Name}}
 *
 * @param Parser $parser
 * @param string $param1 Full text name of topic, must be converted to wiki topic name.
 * @return array
 * 
 * TODO: Much of this function duplicates code above in efGetTitleFromMarkup(), can we DRY?
 *       There really shouldn't be any real code in this file, just calls to class methods...
 */
function efTopicParserFunction_Render(&$parser, $param1 = '')
{
    global $wgArticlePath, $wgTitle, $action;
    if (PonyDocsExtension::isSpeedProcessingEnabled()) {
        return TRUE;
    }
    /**
     * We ignore this parser function if not in a TOC management page.
     */
    if (!preg_match('/' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':(.*):(.*)TOC(.*)/i', $wgTitle->__toString(), $matches)) {
        return FALSE;
    }
    $manualShortName = $matches[2];
    $productShortName = $matches[1];
    PonyDocsWiki::getInstance($productShortName);
    /**
     * Get the earliest tagged version of this TOC page and append it to the wiki page?
     * Ensure the manual is valid then use PonyDocsManual::getManualByShortName().
     * Next attempt to get the version tags for this page -- which may be NONE -- 
     * and from this determine the "earliest" version to which this page applies.
     * 
     * TODO: This comment is duplicated above in efGetTitleFromMarkup, can we DRY?
     */
    if (!PonyDocsProductManual::IsManual($productShortName, $manualShortName)) {
        return FALSE;
    }
    $pManual = PonyDocsProductManual::GetManualByShortName($productShortName, $manualShortName);
    $pTopic = new PonyDocsTopic(new Article($wgTitle));
    /**
     * @FIXME: If TOC page is NOT tagged with any versions we cannot create the pages/links to the 
     * topics, right?
     */
    $manVersionList = $pTopic->getProductVersions();
    if (!sizeof($manVersionList)) {
        return $parser->insertStripItem($param1, $parser->mStripState);
    }
    $earliestVersion = PonyDocsProductVersion::findEarliest($productShortName, $manVersionList);
    /**
     * Clean up the full text name into a wiki-form. This means remove spaces, #, ?, and a few other
     * characters which are not valid or wanted. It's not important HOW this is done as long as it is
     * consistent.
     */
    $wikiTopic = preg_replace('/([^' . str_replace(' ', '', Title::legalChars()) . '])/', '', $param1);
    $wikiPath = PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':' . $productShortName . ':' . $manualShortName . ':' . $wikiTopic;
    $dbr = wfGetDB(DB_SLAVE);
    /**
     * Now look in the database for any instance of this topic name PLUS :<version>.
     * We need to look in categorylinks for it to find a record with a cl_to (version tag)
     * which is equal to the set of the versions for this TOC page.
     * For instance, if the TOC page was for versions 1.0 and 1.1 and our topic was 'How To Foo'
     * we need to find any cl_sortkey which is 'HowToFoo:%' and has a cl_to equal to 1.0 or 1.1.
     * There should only be 0 or 1, so we ignore anything beyond 1.
     * If found, we use THAT cl_sortkey as the link;
     * if NOT found we create a new topic, the name being the compressed topic name plus the earliest TOC version
     * ($earliestVersion->getName()).
     * We then need to ACTUALLY create it in the database, tag it with all the versions the TOC mgmt page is tagged with,
     * and set the H1 to the text inside the parser function.
     * 
     * @fixme: Can we test if $action=save here so we don't do this on every page view? 
     */
    $versionIn = array();
    foreach ($manVersionList as $pV) {
        $versionIn[] = $productShortName . ':' . $pV->getVersionName();
    }
    $res = $dbr->select(array('categorylinks', 'page'), 'page_title', array('cl_from = page_id', 'page_namespace = "' . NS_PONYDOCS . '"', "cl_to IN ('V:" . implode("','V:", $versionIn) . "')", 'cl_type = "page"', "cl_sortkey LIKE '" . $dbr->strencode(strtoupper($productShortName . ':' . $manualShortName . ':' . $wikiTopic)) . ":%'"), __METHOD__);
    $topicName = '';
    if (!$res->numRows()) {
        /**
         * No match -- so this is a "new" topic. Set name.
         */
        $topicName = PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':' . $productShortName . ':' . $manualShortName . ':' . $wikiTopic . ':' . $earliestVersion->getVersionName();
    } else {
        $row = $dbr->fetchObject($res);
        $topicName = PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ":{$row->page_title}";
    }
    $output = '<a href="' . wfUrlencode(str_replace('$1', $topicName, $wgArticlePath)) . '">' . $param1 . '</a>';
    return $parser->insertStripItem($output, $parser->mStripState);
}
 /**
  * Renders bs:whoisonline:popup output.
  * @param Parser $oParser MediaWiki parser object.
  * @param string $sLinkTitle Label of the link that is the anchor of the flyout
  * @return array Rendered HTML and flags. Used by magic word function hook as well as by onUsersLinkTag.
  */
 public function onUsersLink($oParser, $sLinkTitle = '')
 {
     $oParser->disableCache();
     wfProfileIn('BS::' . __METHOD__);
     $sLinkTitle = BsCore::sanitize($sLinkTitle, '', BsPARAMTYPE::STRING);
     if (empty($sLinkTitle)) {
         $sLinkTitle = wfMessage('bs-whoisonline-widget-title')->plain();
     }
     $oWhoIsOnlineTagView = new ViewWhoIsOnlineTag();
     $oWhoIsOnlineTagView->setOption('title', $sLinkTitle);
     $oWhoIsOnlineTagView->setPortlet($this->getPortlet());
     $sOut = $oWhoIsOnlineTagView->execute();
     wfProfileOut('BS::' . __METHOD__);
     return $oParser->insertStripItem($sOut, $oParser->mStripState);
 }
 /**
  * @throws MWException
  * @param $root
  * @param $flags int
  * @return string
  */
 function expand($root, $flags = 0)
 {
     static $expansionDepth = 0;
     if (is_string($root)) {
         return $root;
     }
     if (++$this->parser->mPPNodeCount > $this->parser->mOptions->getMaxPPNodeCount()) {
         return '<span class="error">Node-count limit exceeded</span>';
     }
     if ($expansionDepth > $this->parser->mOptions->getMaxPPExpandDepth()) {
         return '<span class="error">Expansion depth limit exceeded</span>';
     }
     wfProfileIn(__METHOD__);
     ++$expansionDepth;
     if ($root instanceof PPNode_DOM) {
         $root = $root->node;
     }
     if ($root instanceof DOMDocument) {
         $root = $root->documentElement;
     }
     $outStack = array('', '');
     $iteratorStack = array(false, $root);
     $indexStack = array(0, 0);
     $RTEext_1 = false;
     $RTEext_2 = false;
     while (count($iteratorStack) > 1) {
         if ($RTEext_1) {
             $RTEext_1 = false;
             $RTEext_2 = true;
         }
         $level = count($outStack) - 1;
         $iteratorNode =& $iteratorStack[$level];
         $out =& $outStack[$level];
         $index =& $indexStack[$level];
         if ($iteratorNode instanceof PPNode_DOM) {
             $iteratorNode = $iteratorNode->node;
         }
         if (is_array($iteratorNode)) {
             if ($index >= count($iteratorNode)) {
                 // All done with this iterator
                 $iteratorStack[$level] = false;
                 $contextNode = false;
             } else {
                 $contextNode = $iteratorNode[$index];
                 $index++;
             }
         } elseif ($iteratorNode instanceof DOMNodeList) {
             if ($index >= $iteratorNode->length) {
                 // All done with this iterator
                 $iteratorStack[$level] = false;
                 $contextNode = false;
             } else {
                 $contextNode = $iteratorNode->item($index);
                 $index++;
             }
         } else {
             // Copy to $contextNode and then delete from iterator stack,
             // because this is not an iterator but we do have to execute it once
             $contextNode = $iteratorStack[$level];
             $iteratorStack[$level] = false;
         }
         if ($contextNode instanceof PPNode_DOM) {
             $contextNode = $contextNode->node;
         }
         $newIterator = false;
         if ($contextNode === false) {
             // nothing to do
         } elseif (is_string($contextNode)) {
             $out .= $contextNode;
         } elseif (is_array($contextNode) || $contextNode instanceof DOMNodeList) {
             $newIterator = $contextNode;
         } elseif ($contextNode instanceof DOMNode) {
             if ($contextNode->nodeType == XML_TEXT_NODE) {
                 # RTE (Rich Text Editor) - begin
                 global $wgRTEParserEnabled;
                 if (!empty($wgRTEParserEnabled)) {
                     if ($RTEext_2) {
                         if (strpos($contextNode->nodeValue, 'table') !== false) {
                             RTE::$edgeCases[] = 'COMPLEX.11';
                         }
                     }
                 }
                 # RTE - end
                 $out .= $contextNode->nodeValue;
             } elseif ($contextNode->nodeName == 'template') {
                 # Double-brace expansion
                 $xpath = new DOMXPath($contextNode->ownerDocument);
                 $titles = $xpath->query('title', $contextNode);
                 $title = $titles->item(0);
                 $parts = $xpath->query('part', $contextNode);
                 # RTE (Rich Text Editor) - begin
                 # @author: Inez Korczyński
                 global $wgRTEParserEnabled;
                 if (!empty($wgRTEParserEnabled)) {
                     $dataIdx = RTEData::put('placeholder', array('type' => 'double-brackets', 'wikitextIdx' => $contextNode->getAttribute('_rte_wikitextidx'), 'lineStart' => $contextNode->getAttribute('lineStart'), 'title' => $title->textContent));
                     $out .= RTEMarker::generate(RTEMarker::PLACEHOLDER, $dataIdx);
                 } else {
                     if ($flags & PPFrame::NO_TEMPLATES) {
                         $newIterator = $this->virtualBracketedImplode('{{', '|', '}}', $title, $parts);
                     } else {
                         $lineStart = $contextNode->getAttribute('lineStart');
                         $params = array('title' => new PPNode_DOM($title), 'parts' => new PPNode_DOM($parts), 'lineStart' => $lineStart);
                         $ret = $this->parser->braceSubstitution($params, $this);
                         if (isset($ret['object'])) {
                             $newIterator = $ret['object'];
                         } else {
                             $out .= $ret['text'];
                         }
                     }
                 }
                 # RTE - end
             } elseif ($contextNode->nodeName == 'tplarg') {
                 # Triple-brace expansion
                 $xpath = new DOMXPath($contextNode->ownerDocument);
                 $titles = $xpath->query('title', $contextNode);
                 $title = $titles->item(0);
                 $parts = $xpath->query('part', $contextNode);
                 # RTE (Rich Text Editor) - begin
                 # @author: Wladyslaw Bodzek
                 global $wgRTEParserEnabled;
                 if (!empty($wgRTEParserEnabled)) {
                     //var_dump($contextNode->getAttribute('_rte_wikitextidx'));
                     $dataIdx = RTEData::put('placeholder', array('type' => 'tplarg', 'wikitextIdx' => $contextNode->getAttribute('_rte_wikitextidx'), 'lineStart' => $contextNode->getAttribute('lineStart'), 'title' => $title->textContent));
                     $out .= RTEMarker::generate(RTEMarker::PLACEHOLDER, $dataIdx);
                 } else {
                     if ($flags & PPFrame::NO_ARGS) {
                         $newIterator = $this->virtualBracketedImplode('{{{', '|', '}}}', $title, $parts);
                     } else {
                         $params = array('title' => new PPNode_DOM($title), 'parts' => new PPNode_DOM($parts));
                         $ret = $this->parser->argSubstitution($params, $this);
                         if (isset($ret['object'])) {
                             $newIterator = $ret['object'];
                         } else {
                             $out .= $ret['text'];
                         }
                     }
                 }
                 # RTE - end
             } elseif ($contextNode->nodeName == 'comment') {
                 # HTML-style comment
                 # Remove it in HTML, pre+remove and STRIP_COMMENTS modes
                 if ($this->parser->ot['html'] || $this->parser->ot['pre'] && $this->parser->mOptions->getRemoveComments() || $flags & PPFrame::STRIP_COMMENTS) {
                     # RTE (Rich Text Editor) - begin
                     # @author: Inez Korczyński
                     global $wgRTEParserEnabled;
                     if (!empty($wgRTEParserEnabled)) {
                         if (strlen($out) === 0 || substr($out, -1) == "\n") {
                             if (substr($contextNode->textContent, -1) == "\n") {
                                 $add = "\n";
                                 $text = substr($contextNode->textContent, 0, -1);
                             } else {
                                 $add = "";
                                 $text = $contextNode->textContent;
                             }
                             $dataIdx = RTEData::put('placeholder', array('type' => 'comment', 'wikitext' => $text));
                             $out .= RTEMarker::generate(RTEMarker::PLACEHOLDER, $dataIdx) . $add;
                         } else {
                             RTE::$edgeCases[] = 'COMMENT';
                             $out .= '';
                         }
                     } else {
                         $out .= '';
                     }
                     # RTE - end
                 } elseif ($this->parser->ot['wiki'] && !($flags & PPFrame::RECOVER_COMMENTS)) {
                     $out .= $this->parser->insertStripItem($contextNode->textContent);
                 } else {
                     $out .= $contextNode->textContent;
                 }
             } elseif ($contextNode->nodeName == 'ignore') {
                 # Output suppression used by <includeonly> etc.
                 # OT_WIKI will only respect <ignore> in substed templates.
                 # The other output types respect it unless NO_IGNORE is set.
                 # extractSections() sets NO_IGNORE and so never respects it.
                 if (!isset($this->parent) && $this->parser->ot['wiki'] || $flags & PPFrame::NO_IGNORE) {
                     $out .= $contextNode->textContent;
                 } else {
                     $out .= '';
                 }
             } elseif ($contextNode->nodeName == 'ext') {
                 # Extension tag
                 $xpath = new DOMXPath($contextNode->ownerDocument);
                 $names = $xpath->query('name', $contextNode);
                 $attrs = $xpath->query('attr', $contextNode);
                 $inners = $xpath->query('inner', $contextNode);
                 $closes = $xpath->query('close', $contextNode);
                 $params = array('name' => new PPNode_DOM($names->item(0)), 'attr' => $attrs->length > 0 ? new PPNode_DOM($attrs->item(0)) : null, 'inner' => $inners->length > 0 ? new PPNode_DOM($inners->item(0)) : null, 'close' => $closes->length > 0 ? new PPNode_DOM($closes->item(0)) : null);
                 $out .= $this->parser->extensionSubstitution($params, $this);
                 $RTEext_1 = true;
             } elseif ($contextNode->nodeName == 'h') {
                 # Heading
                 $s = $this->expand($contextNode->childNodes, $flags);
                 # Insert a heading marker only for <h> children of <root>
                 # This is to stop extractSections from going over multiple tree levels
                 if ($contextNode->parentNode->nodeName == 'root' && $this->parser->ot['html']) {
                     # Insert heading index marker
                     $headingIndex = $contextNode->getAttribute('i');
                     $titleText = $this->title->getPrefixedDBkey();
                     $this->parser->mHeadings[] = array($titleText, $headingIndex);
                     $serial = count($this->parser->mHeadings) - 1;
                     $marker = "{$this->parser->mUniqPrefix}-h-{$serial}-" . Parser::MARKER_SUFFIX;
                     $count = $contextNode->getAttribute('level');
                     $s = substr($s, 0, $count) . $marker . substr($s, $count);
                     $this->parser->mStripState->addGeneral($marker, '');
                 }
                 $out .= $s;
             } else {
                 # Generic recursive expansion
                 $newIterator = $contextNode->childNodes;
             }
         } else {
             wfProfileOut(__METHOD__);
             throw new MWException(__METHOD__ . ': Invalid parameter type');
         }
         if ($newIterator !== false) {
             if ($newIterator instanceof PPNode_DOM) {
                 $newIterator = $newIterator->node;
             }
             $outStack[] = '';
             $iteratorStack[] = $newIterator;
             $indexStack[] = 0;
         } elseif ($iteratorStack[$level] === false) {
             // Return accumulated value to parent
             // With tail recursion
             while ($iteratorStack[$level] === false && $level > 0) {
                 $outStack[$level - 1] .= $out;
                 array_pop($outStack);
                 array_pop($iteratorStack);
                 array_pop($indexStack);
                 $level--;
             }
         }
         $RTEext_2 = false;
     }
     --$expansionDepth;
     wfProfileOut(__METHOD__);
     return $outStack[0];
 }
	/**
	 * Parser function hook
	 */
	public static function translationDialogMagicWord( Parser $parser, $title = '', $linktext = '' ) {
		$title = Title::newFromText( $title );
		if ( !$title ) return '';
		$handle = new MessageHandle( $title );
		if ( !$handle->isValid() ) return '';
		$group = $handle->getGroup();
		$callParams = array( $title->getPrefixedText(), $group->getId() );
		$call = Xml::encodeJsCall( 'mw.translate.openDialog', $callParams );
		$js = <<<JAVASCRIPT
mw.loader.using( 'ext.translate.quickedit', function() { $call; } ); return false;
JAVASCRIPT;

		$a = array(
			'href' => $title->getFullUrl( array( 'action' => 'edit' ) ),
			'onclick' => $js,
		);

		if ( $linktext === '' ) {
			$linktext = wfMessage( 'translate-edit-jsopen' )->text();
		}
		$output = Html::element( 'a', $a, $linktext );
		return $parser->insertStripItem( $output, $parser->mStripState );
	}
Exemple #16
0
 /**
  * Renrder the spark div.
  *
  * @since 0.1
  *
  * @param Parser $parser
  *
  * @return string
  */
 public function render(Parser $parser, $frame)
 {
     global $wgVersion;
     global $wgOut;
     global $egSparkScriptPath;
     global $wgResourceModules;
     // What is loaded already?
     static $loadedJsses = array();
     wfDebugLog('myextension', 'Parameters alright? ' . print_r($this->parameters, true));
     if (array_key_exists(egSparkQuery, $this->parameters)) {
         $query = htmlspecialchars($this->parameters[egSparkQuery]);
         // Before that, shall we allow internal parse, at least for the query?
         // We replace variables, templates etc.
         $query = $parser->replaceVariables($query, $frame);
         //$query = $parser->recursiveTagParse( $query );
         // Replace special characters
         $query = str_replace(array('&lt;', '&gt;'), array('<', '>'), $query);
         unset($this->parameters[egSparkQuery]);
         // Depending on the format, we possibly need to add modules
         if (array_key_exists(egSparkFormat, $this->parameters)) {
             $format = htmlspecialchars($this->parameters[egSparkFormat]);
             // Remove everything before "spark.XXX"
             $format = substr($format, strpos($format, "spark."));
             // Remove .js at the end
             $format = str_replace(array('.js'), array(''), $format);
             $module = 'ext.' . $format;
             // for older versions of MW, different
             if (version_compare($wgVersion, '1.17', '<')) {
                 if (isset($wgResourceModules) && array_key_exists($module, $wgResourceModules)) {
                     // only if not already loaded
                     if (!isset($loadedJsses[$module])) {
                         // scripts
                         foreach ($wgResourceModules[$module]['scripts'] as $script) {
                             $wgOut->addScript('<script src="' . $egSparkScriptPath . "/" . $script . '" type="text/javascript"></script>');
                             wfDebugLog('spark', "AddScript:" . ' <script src="' . $egSparkScriptPath . "/" . $script . '" type="text/javascript"></script>');
                         }
                         // css
                         foreach ($wgResourceModules[$module]['styles'] as $style) {
                             $wgOut->addScript('<link rel="stylesheet" href="' . $egSparkScriptPath . "/" . $style . '" type="text/css" />');
                             wfDebugLog('spark', "AddLink:" . ' <link rel="stylesheet" href="' . $egSparkScriptPath . "/" . $style . '" type="text/css" />');
                         }
                         $loadedJsses[$module] = true;
                     }
                 }
             } else {
                 // $wgResourceModules might not exist
                 if (isset($wgResourceModules) && array_key_exists($module, $wgResourceModules)) {
                     // TODO: Do we need to check, whether module has been added already?
                     $parser->getOutput()->addModules($module);
                 }
             }
         }
         $html = '<div class="spark" data-spark-query="' . $query . '" ' . Html::expandAttributes($this->parameters) . ' >' . (is_null($this->contents) ? '' : htmlspecialchars($this->contents)) . '</div>';
         // In MW 1.17 there seems to be the problem that ? after an empty space is replaced by a non-breaking space (&#160;) Therefore we remove all spaces before ? which should still make the SPARQL query work
         $html = preg_replace('/[ \\t]+(\\?)/', '$1', $html);
         // for older versions of MW, different
         if (version_compare($wgVersion, '1.17', '<')) {
             $parser->disableCache();
             return $html;
         } else {
             return array($parser->insertStripItem($html, $parser->mStripState), 'noparse' => true, 'isHTML' => true);
         }
     } else {
         return Html::element('i', array(), wfMsg('spark-missing-query'));
     }
 }