Exemplo n.º 1
0
function wfCSSRender(&$parser, $css)
{
    global $wgOut, $wgRequest;
    $parser->mOutput->mCacheTime = -1;
    $url = false;
    if (preg_match('|\\{|', $css)) {
        # Inline CSS
        $css = htmlspecialchars(trim(Sanitizer::checkCss($css)));
        $parser->mOutput->addHeadItem(<<<EOT
<style type="text/css">
/*<![CDATA[*/
{$css}
/*]]>*/
</style>
EOT
);
    } elseif ($css[0] == '/') {
        # File
        $url = $css;
    } else {
        # Article?
        $title = Title::newFromText($css);
        if (is_object($title)) {
            $url = $title->getLocalURL('action=raw&ctype=text/css');
            $url = str_replace("&", "&amp;", $url);
        }
    }
    if ($url) {
        $wgOut->addScript("<link rel=\"stylesheet\" type=\"text/css\" href=\"{$url}\" />");
    }
    return '';
}
Exemplo n.º 2
0
	public static function parse( $content, array $args, Parser $parser ) {
		$css = htmlspecialchars( trim( Sanitizer::checkCss( $content ) ) );
		$parser->mOutput->addHeadItem( <<<EOT
<style type="text/css">
/*<![CDATA[*/
{$css}
/*]]>*/
</style>
EOT
		);
	}
Exemplo n.º 3
0
 /**
  * Override the title of the page when viewed, provided we've been given a
  * title which will normalise to the canonical title
  *
  * @param Parser $parser Parent parser
  * @param string $text Desired title text
  * @param string $uarg
  * @return string
  */
 public static function displaytitle($parser, $text = '', $uarg = '')
 {
     global $wgRestrictDisplayTitle;
     static $magicWords = null;
     if (is_null($magicWords)) {
         $magicWords = new MagicWordArray(['displaytitle_noerror', 'displaytitle_noreplace']);
     }
     $arg = $magicWords->matchStartToEnd($uarg);
     // parse a limited subset of wiki markup (just the single quote items)
     $text = $parser->doQuotes($text);
     // remove stripped text (e.g. the UNIQ-QINU stuff) that was generated by tag extensions/whatever
     $text = $parser->killMarkers($text);
     // list of disallowed tags for DISPLAYTITLE
     // these will be escaped even though they are allowed in normal wiki text
     $bad = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'div', 'blockquote', 'ol', 'ul', 'li', 'hr', 'table', 'tr', 'th', 'td', 'dl', 'dd', 'caption', 'p', 'ruby', 'rb', 'rt', 'rtc', 'rp', 'br'];
     // disallow some styles that could be used to bypass $wgRestrictDisplayTitle
     if ($wgRestrictDisplayTitle) {
         $htmlTagsCallback = function (&$params) {
             $decoded = Sanitizer::decodeTagAttributes($params);
             if (isset($decoded['style'])) {
                 // this is called later anyway, but we need it right now for the regexes below to be safe
                 // calling it twice doesn't hurt
                 $decoded['style'] = Sanitizer::checkCss($decoded['style']);
                 if (preg_match('/(display|user-select|visibility)\\s*:/i', $decoded['style'])) {
                     $decoded['style'] = '/* attempt to bypass $wgRestrictDisplayTitle */';
                 }
             }
             $params = Sanitizer::safeEncodeTagAttributes($decoded);
         };
     } else {
         $htmlTagsCallback = null;
     }
     // only requested titles that normalize to the actual title are allowed through
     // if $wgRestrictDisplayTitle is true (it is by default)
     // mimic the escaping process that occurs in OutputPage::setPageTitle
     $text = Sanitizer::normalizeCharReferences(Sanitizer::removeHTMLtags($text, $htmlTagsCallback, [], [], $bad));
     $title = Title::newFromText(Sanitizer::stripAllTags($text));
     if (!$wgRestrictDisplayTitle || $title instanceof Title && !$title->hasFragment() && $title->equals($parser->mTitle)) {
         $old = $parser->mOutput->getProperty('displaytitle');
         if ($old === false || $arg !== 'displaytitle_noreplace') {
             $parser->mOutput->setDisplayTitle($text);
         }
         if ($old !== false && $old !== $text && !$arg) {
             $converter = $parser->getConverterLanguage()->getConverter();
             return '<span class="error">' . wfMessage('duplicate-displaytitle', $converter->markNoConversion(wfEscapeWikiText($old)), $converter->markNoConversion(wfEscapeWikiText($text)))->inContentLanguage()->text() . '</span>';
         } else {
             return '';
         }
     } else {
         $parser->addTrackingCategory('restricted-displaytitle-ignored');
         $converter = $parser->getConverterLanguage()->getConverter();
         return '<span class="error">' . wfMessage('restricted-displaytitle', $converter->markNoConversion(wfEscapeWikiText($text)))->inContentLanguage()->text() . '</span>';
     }
 }
Exemplo n.º 4
0
 /**
  * Take an array of attribute names and values and normalize or discard
  * illegal values for the given whitelist.
  *
  * - Discards attributes not the given whitelist
  * - Unsafe style attributes are discarded
  * - Invalid id attributes are re-encoded
  *
  * @param array $attribs
  * @param array $whitelist List of allowed attribute names
  * @return array
  *
  * @todo Check for legal values where the DTD limits things.
  * @todo Check for unique id attribute :P
  */
 static function validateAttributes($attribs, $whitelist)
 {
     global $wgAllowRdfaAttributes, $wgAllowMicrodataAttributes;
     $whitelist = array_flip($whitelist);
     $hrefExp = '/^(' . wfUrlProtocols() . ')[^\\s]+$/';
     $out = array();
     foreach ($attribs as $attribute => $value) {
         #allow XML namespace declaration if RDFa is enabled
         if ($wgAllowRdfaAttributes && preg_match(self::XMLNS_ATTRIBUTE_PATTERN, $attribute)) {
             if (!preg_match(self::EVIL_URI_PATTERN, $value)) {
                 $out[$attribute] = $value;
             }
             continue;
         }
         # Allow any attribute beginning with "data-"
         if (!preg_match('/^data-(?!ooui)/i', $attribute) && !isset($whitelist[$attribute])) {
             continue;
         }
         # Strip javascript "expression" from stylesheets.
         # http://msdn.microsoft.com/workshop/author/dhtml/overview/recalc.asp
         if ($attribute == 'style') {
             $value = Sanitizer::checkCss($value);
         }
         if ($attribute === 'id') {
             $value = Sanitizer::escapeId($value, 'noninitial');
         }
         # WAI-ARIA
         # http://www.w3.org/TR/wai-aria/
         # http://www.whatwg.org/html/elements.html#wai-aria
         # For now we only support role="presentation" until we work out what roles should be
         # usable by content and we ensure that our code explicitly rejects patterns that
         # violate HTML5's ARIA restrictions.
         if ($attribute === 'role' && $value !== 'presentation') {
             continue;
         }
         // RDFa and microdata properties allow URLs, URIs and/or CURIs.
         // Check them for sanity.
         if ($attribute === 'rel' || $attribute === 'rev' || $attribute === 'about' || $attribute === 'property' || $attribute === 'resource' || $attribute === 'datatype' || $attribute === 'typeof' || $attribute === 'itemid' || $attribute === 'itemprop' || $attribute === 'itemref' || $attribute === 'itemscope' || $attribute === 'itemtype') {
             //Paranoia. Allow "simple" values but suppress javascript
             if (preg_match(self::EVIL_URI_PATTERN, $value)) {
                 continue;
             }
         }
         # NOTE: even though elements using href/src are not allowed directly, supply
         #       validation code that can be used by tag hook handlers, etc
         if ($attribute === 'href' || $attribute === 'src') {
             if (!preg_match($hrefExp, $value)) {
                 continue;
                 //drop any href or src attributes not using an allowed protocol.
                 // NOTE: this also drops all relative URLs
             }
         }
         // If this attribute was previously set, override it.
         // Output should only have one attribute of each name.
         $out[$attribute] = $value;
     }
     if ($wgAllowMicrodataAttributes) {
         # itemtype, itemid, itemref don't make sense without itemscope
         if (!array_key_exists('itemscope', $out)) {
             unset($out['itemtype']);
             unset($out['itemid']);
             unset($out['itemref']);
         }
         # TODO: Strip itemprop if we aren't descendants of an itemscope or pointed to by an itemref.
     }
     return $out;
 }
Exemplo n.º 5
0
 /**
  * Take an array of attribute names and values and normalize or discard
  * illegal values for the given whitelist.
  *
  * - Discards attributes not the given whitelist
  * - Unsafe style attributes are discarded
  * - Invalid id attributes are reencoded
  *
  * @param array $attribs
  * @param array $whitelist list of allowed attribute names
  * @return array
  *
  * @todo Check for legal values where the DTD limits things.
  * @todo Check for unique id attribute :P
  */
 static function validateAttributes($attribs, $whitelist)
 {
     $whitelist = array_flip($whitelist);
     $out = array();
     foreach ($attribs as $attribute => $value) {
         if (!isset($whitelist[$attribute])) {
             continue;
         }
         # Strip javascript "expression" from stylesheets.
         # http://msdn.microsoft.com/workshop/author/dhtml/overview/recalc.asp
         if ($attribute == 'style') {
             $value = Sanitizer::checkCss($value);
             if ($value === false) {
                 # haxx0r
                 continue;
             }
         }
         if ($attribute === 'id') {
             $value = Sanitizer::escapeId($value);
         }
         // If this attribute was previously set, override it.
         // Output should only have one attribute of each name.
         $out[$attribute] = $value;
     }
     return $out;
 }
Exemplo n.º 6
0
 /**
  * Take an array of attribute names and values and normalize or discard
  * illegal values for the given whitelist.
  *
  * - Discards attributes not the given whitelist
  * - Unsafe style attributes are discarded
  * - Invalid id attributes are reencoded
  *
  * @param $attribs Array
  * @param $whitelist Array: list of allowed attribute names
  * @return Array
  *
  * @todo Check for legal values where the DTD limits things.
  * @todo Check for unique id attribute :P
  */
 static function validateAttributes($attribs, $whitelist)
 {
     global $wgAllowRdfaAttributes, $wgAllowMicrodataAttributes;
     $whitelist = array_flip($whitelist);
     $hrefExp = '/^(' . wfUrlProtocols() . ')[^\\s]+$/';
     $out = array();
     foreach ($attribs as $attribute => $value) {
         #allow XML namespace declaration if RDFa is enabled
         if ($wgAllowRdfaAttributes && preg_match(MW_XMLNS_ATTRIBUTE_PATTRN, $attribute)) {
             if (!preg_match(MW_EVIL_URI_PATTERN, $value)) {
                 $out[$attribute] = $value;
             }
             continue;
         }
         if (!isset($whitelist[$attribute])) {
             continue;
         }
         # Strip javascript "expression" from stylesheets.
         # http://msdn.microsoft.com/workshop/author/dhtml/overview/recalc.asp
         if ($attribute == 'style') {
             $value = Sanitizer::checkCss($value);
         }
         if ($attribute === 'id') {
             $value = Sanitizer::escapeId($value, 'noninitial');
         }
         //RDFa and microdata properties allow URLs, URIs and/or CURIs. check them for sanity
         if ($attribute === 'rel' || $attribute === 'rev' || $attribute === 'about' || $attribute === 'property' || $attribute === 'resource' || $attribute === 'datatype' || $attribute === 'typeof' || $attribute === 'itemid' || $attribute === 'itemprop' || $attribute === 'itemref' || $attribute === 'itemscope' || $attribute === 'itemtype') {
             #HTML5 microdata
             //Paranoia. Allow "simple" values but suppress javascript
             if (preg_match(MW_EVIL_URI_PATTERN, $value)) {
                 continue;
             }
         }
         # NOTE: even though elements using href/src are not allowed directly, supply
         #       validation code that can be used by tag hook handlers, etc
         if ($attribute === 'href' || $attribute === 'src') {
             if (!preg_match($hrefExp, $value)) {
                 continue;
                 //drop any href or src attributes not using an allowed protocol.
                 //NOTE: this also drops all relative URLs
             }
         }
         // If this attribute was previously set, override it.
         // Output should only have one attribute of each name.
         $out[$attribute] = $value;
     }
     if ($wgAllowMicrodataAttributes) {
         # There are some complicated validity constraints we need to
         # enforce here.  First of all, we don't want to allow non-standard
         # itemtypes.
         $allowedTypes = array('http://microformats.org/profile/hcard', 'http://microformats.org/profile/hcalendar#vevent', 'http://n.whatwg.org/work');
         if (isset($out['itemtype']) && !in_array($out['itemtype'], $allowedTypes)) {
             # Kill everything
             unset($out['itemscope']);
         }
         # itemtype, itemid, itemref don't make sense without itemscope
         if (!array_key_exists('itemscope', $out)) {
             unset($out['itemtype']);
             unset($out['itemid']);
             unset($out['itemref']);
         }
         # TODO: Strip itemprop if we aren't descendants of an itemscope.
     }
     return $out;
 }
Exemplo n.º 7
0
 /**
  * @author Maciej Błaszkowski <marooned at wikia-inc.com>
  * TODO: because of late change in specs, this function has to handle parameters in different formats and thus it's little confused - would be good to clean up the code someday
  */
 static function parseParameters($parametersIn)
 {
     global $wgContLang;
     wfProfileIn(__METHOD__);
     $excludeNamespaces = array();
     $parameters = array();
     //default values
     $parameters['maxElements'] = 10;
     $parameters['flags'] = array();
     $parameters['includeNamespaces'] = null;
     if (is_array($parametersIn) && !empty($parametersIn)) {
         foreach ($parametersIn as $parameter => $value) {
             if (is_int($parameter)) {
                 //ajax
                 @(list($var, $val) = explode('=', $value));
             } else {
                 //parser tag
                 $var = $parameter;
                 $val = $value;
             }
             switch (trim($var)) {
                 case 'size':
                     if (!empty($val)) {
                         $parameters['maxElements'] = intval($val);
                     }
                     break;
                 case 'hideimages':
                     if (!isset($val) || $val != 'false') {
                         $parameters['flags'][] = 'hideimages';
                     }
                     break;
                 case 'hidevideos':
                     if (!isset($val) || $val != 'false') {
                         $parameters['flags'][] = 'hidevideos';
                     }
                     break;
                 case 'hidedetails':
                     if (!isset($val) || $val != 'false') {
                         $parameters['flags'][] = 'hidedetails';
                     }
                     break;
                 case 'hidecategories':
                     if (!isset($val) || $val != 'false') {
                         $parameters['flags'][] = 'hidecategories';
                     }
                     break;
                 case 'shortlist':
                     if (!isset($val) || $val != 'false') {
                         $parameters['flags'][] = 'shortlist';
                     }
                     break;
                 case 'hidenewpages':
                     if (!isset($val) || $val != 'false') {
                         $parameters['flags'][] = 'hidenewpages';
                     }
                     break;
                 case 'exclude':
                     //only from tag
                     if (!empty($val)) {
                         $namespaces = explode(',', $val);
                         $blankNamespace = wfMsgForContent('blanknamespace');
                         $blankNamespace = wfEmptyMsg('blanknamespace', $blankNamespace) ? null : $wgContLang->lc($blankNamespace);
                         foreach ($namespaces as $namespace) {
                             $namespace = trim($namespace);
                             if (($namespaceIndex = $wgContLang->getNsIndex($namespace)) !== false && $namespaceIndex >= 0) {
                                 $excludeNamespaces[] = $namespaceIndex;
                             } else {
                                 //check for main namespace which doesn't have formal name - try hardcoded 'main' and 'blanknamespace' message used in many places
                                 $namespaceLC = $wgContLang->lc($namespace);
                                 if ($namespaceLC == 'main' || $namespaceLC == $blankNamespace) {
                                     $excludeNamespaces[] = 0;
                                 }
                             }
                         }
                         if (count($excludeNamespaces)) {
                             global $wgCanonicalNamespaceNames;
                             $allNS[0] = 'Main';
                             //hack to add main namespace
                             $allNS += $wgCanonicalNamespaceNames;
                             unset($allNS[-1]);
                             unset($allNS[-2]);
                             $parameters['includeNamespaces'] = implode('|', array_diff(array_keys($allNS), $excludeNamespaces));
                         }
                     }
                     break;
                 case 'style':
                     //only from tag
                     if (!empty($val)) {
                         $style = Sanitizer::checkCss($val);
                         if ($style) {
                             $parameters['style'] = $style;
                         }
                     }
                     break;
                 case 'uselang':
                     //only from ajax
                     if (!empty($val)) {
                         $parameters['uselang'] = $val;
                     }
                     break;
                 case 'ns':
                     //only from ajax
                     if (!empty($val)) {
                         $parameters['includeNamespaces'] = $val;
                     }
                     break;
                 case 'flags':
                     //only from ajax
                     if (!empty($val)) {
                         $flags = explode('|', $val);
                         if (in_array('hideimages', $flags)) {
                             $parameters['flags'][] = 'hideimages';
                         }
                         if (in_array('hidedetails', $flags)) {
                             $parameters['flags'][] = 'hidedetails';
                         }
                         if (in_array('hidevideos', $flags)) {
                             $parameters['flags'][] = 'hidevideos';
                         }
                         if (in_array('hidecategories', $flags)) {
                             $parameters['flags'][] = 'hidecategories';
                         }
                         if (in_array('shortlist', $flags)) {
                             $parameters['flags'][] = 'shortlist';
                         }
                         if (in_array('hidenewpages', $flags)) {
                             $parameters['flags'][] = 'hidenewpages';
                         }
                     }
                     break;
                 case 'tagid':
                     //only from ajax
                     if (!empty($val)) {
                         $parameters['tagid'] = $val;
                     }
                     break;
                 case 'type':
                     //pick proper template for tag or widget
                     if (!empty($val)) {
                         $parameters['type'] = $val;
                     }
                     break;
             }
         }
         if (in_array('shortlist', $parameters['flags'])) {
             global $wgContentNamespaces;
             $parameters['includeNamespaces'] = implode('|', array_diff($wgContentNamespaces, $excludeNamespaces));
         }
     }
     wfProfileOut(__METHOD__);
     return $parameters;
 }
Exemplo n.º 8
0
 /**
  * Take an array of attribute names and values and normalize or discard
  * illegal values for the given whitelist.
  *
  * - Discards attributes not on the given whitelist
  * - Unsafe style attributes are discarded
  * - Invalid id attributes are re-encoded
  *
  * @param array $attribs
  * @param array $whitelist List of allowed attribute names
  * @return array
  *
  * @todo Check for legal values where the DTD limits things.
  * @todo Check for unique id attribute :P
  */
 static function validateAttributes($attribs, $whitelist)
 {
     $whitelist = array_flip($whitelist);
     $hrefExp = '/^(' . wfUrlProtocols() . ')[^\\s]+$/';
     $out = [];
     foreach ($attribs as $attribute => $value) {
         # Allow XML namespace declaration to allow RDFa
         if (preg_match(self::XMLNS_ATTRIBUTE_PATTERN, $attribute)) {
             if (!preg_match(self::EVIL_URI_PATTERN, $value)) {
                 $out[$attribute] = $value;
             }
             continue;
         }
         # Allow any attribute beginning with "data-"
         # However:
         # * data-ooui is reserved for ooui
         # * data-mw and data-parsoid are reserved for parsoid
         # * data-mw-<name here> is reserved for extensions (or core) if
         #   they need to communicate some data to the client and want to be
         #   sure that it isn't coming from an untrusted user.
         # * Ensure that the attribute is not namespaced by banning
         #   colons.
         if (!preg_match('/^data-(?!ooui|mw|parsoid)[^:]*$/i', $attribute) && !isset($whitelist[$attribute])) {
             continue;
         }
         # Strip javascript "expression" from stylesheets.
         # http://msdn.microsoft.com/workshop/author/dhtml/overview/recalc.asp
         if ($attribute == 'style') {
             $value = Sanitizer::checkCss($value);
         }
         # Escape HTML id attributes
         if ($attribute === 'id') {
             $value = Sanitizer::escapeId($value, 'noninitial');
         }
         # Escape HTML id reference lists
         if ($attribute === 'aria-describedby' || $attribute === 'aria-flowto' || $attribute === 'aria-labelledby' || $attribute === 'aria-owns') {
             $value = Sanitizer::escapeIdReferenceList($value, 'noninitial');
         }
         // RDFa and microdata properties allow URLs, URIs and/or CURIs.
         // Check them for sanity.
         if ($attribute === 'rel' || $attribute === 'rev' || $attribute === 'about' || $attribute === 'property' || $attribute === 'resource' || $attribute === 'datatype' || $attribute === 'typeof' || $attribute === 'itemid' || $attribute === 'itemprop' || $attribute === 'itemref' || $attribute === 'itemscope' || $attribute === 'itemtype') {
             // Paranoia. Allow "simple" values but suppress javascript
             if (preg_match(self::EVIL_URI_PATTERN, $value)) {
                 continue;
             }
         }
         # NOTE: even though elements using href/src are not allowed directly, supply
         #       validation code that can be used by tag hook handlers, etc
         if ($attribute === 'href' || $attribute === 'src') {
             if (!preg_match($hrefExp, $value)) {
                 continue;
                 // drop any href or src attributes not using an allowed protocol.
                 // NOTE: this also drops all relative URLs
             }
         }
         // If this attribute was previously set, override it.
         // Output should only have one attribute of each name.
         $out[$attribute] = $value;
     }
     # itemtype, itemid, itemref don't make sense without itemscope
     if (!array_key_exists('itemscope', $out)) {
         unset($out['itemtype']);
         unset($out['itemid']);
         unset($out['itemref']);
     }
     # TODO: Strip itemprop if we aren't descendants of an itemscope or pointed to by an itemref.
     return $out;
 }
	/**
	 * Get the JS and HTML that needs to be added to the output to create the chart.
	 * 
	 * @since 1.7
	 * 
	 * @param array $data label => value
	 */
	protected function getFormatOutput( array $data ) {
		$json = array();
		
		foreach ( $data as $name => $value ) {
			$json[] = array( $name, $value );
		}
		
		$pie_data_str = '[' . FormatJson::encode( $json ) . ']';
		$pieID = 'pie' . self::$m_piechartnum;
		
		self::$m_piechartnum++;

    $chartlegend    = FormatJson::encode( $this->params['chartlegend'] );
    $legendlocation = FormatJson::encode( $this->params['legendlocation'] );
		$datalabels     = FormatJson::encode( $this->params['datalabels'] );
		$datalabeltype  = FormatJson::encode( $this->params['datalabeltype'] );

		$js_pie =<<<END
<script type="text/javascript">
jQuery(document).ready(function(){
	jQuery.jqplot.config.enablePlugins = true;
	plot1 = jQuery.jqplot('$pieID', $pie_data_str, {
		title: '$this->m_charttitle',
		seriesDefaults: {
			renderer: jQuery.jqplot.PieRenderer,
			rendererOptions: {
			  showDataLabels: $datalabels,
			  dataLabels: $datalabeltype,
				sliceMargin:2
			}
		},
			legend: { show:$chartlegend, location: $legendlocation }
	});
});
</script>
END;
		global $wgOut;
		$wgOut->addScript( $js_pie );

		$this->isHTML = true;
		
		return Html::element(
			'div',
			array(
				'id' => $pieID,
				'style' => Sanitizer::checkCss( "margin-top: 20px; margin-left: 20px; width: {$this->m_width}px; height: {$this->m_height}px;" )
			)
		);
	}
Exemplo n.º 10
0
	/**
	 * Get the JS and HTML that needs to be added to the output to create the chart.
	 * 
	 * @since 1.7
	 * 
	 * @param array $data label => value
	 */
	protected function getFormatOutput( array $data ) {
		global $wgOut;

		$this->isHTML = true;

		$maxValue = count( $data ) == 0 ? 0 : max( $data );
		
		if ( $this->params['min'] === false ) {
			$minValue = count( $data ) == 0 ? 0 : min( $data );
		}
		else {
			$minValue = $this->params['min'];
		}
		
		foreach ( $data as $i => &$nr ) {
			if ( $this->m_bardirection == 'horizontal' ) {
				$nr = array( $nr, $i );
			}
		}
		
		$barID = 'bar' . self::$m_barchartnum;
		self::$m_barchartnum++;
		
		$labels_str = FormatJson::encode( array_keys( $data ) );
		$numbers_str = FormatJson::encode( array_values( $data ) );
		
		$labels_axis = 'xaxis';
		$numbers_axis = 'yaxis';
		
		$angle_val = -40;
		$barmargin = 6;
		
		if ( $this->m_bardirection == 'horizontal' ) {
			$labels_axis = 'yaxis';
			$numbers_axis = 'xaxis';
			$angle_val = 0;
			$barmargin = 8 ;
		}
		
		$barwidth = 20; // width of each bar
		$bardistance = 4; // distance between two bars

		// Calculate the tick values for the numbers, based on the
		// lowest and highest number. jqPlot has its own option for
		// calculating ticks automatically - "autoscale" - but it
		// currently (September 2010) fails for numbers less than 1,
		// and negative numbers.
		// If both max and min are 0, just escape now.
		if ( $maxValue == 0 && $minValue == 0 ) {
			return null;
		}
		// Make the max and min slightly larger and bigger than the
		// actual max and min, so that the bars don't directly touch
		// the top and bottom of the graph
		if ( $maxValue > 0 ) { $maxValue += .001; }
		if ( $minValue < 0 ) { $minValue -= .001; }
		if ( $maxValue == 0 ) {
			$multipleOf10 = 0;
			$maxAxis = 0;
		} else {
			$multipleOf10 = pow( 10, floor( log( $maxValue, 10 ) ) );
			$maxAxis = ceil( $maxValue / $multipleOf10 ) * $multipleOf10;
		}
		
		if ( $minValue == 0 ) {
			$negativeMultipleOf10 = 0;
			$minAxis = 0;
		} else {
			$negativeMultipleOf10 = -1 * pow( 10, floor( log( $minValue, 10 ) ) );
			$minAxis = ceil( $minValue / $negativeMultipleOf10 ) * $negativeMultipleOf10;
		}
		
		$numbers_ticks = '';
		$biggerMultipleOf10 = max( $multipleOf10, -1 * $negativeMultipleOf10 );
		$lowestTick = floor( $minAxis / $biggerMultipleOf10 + .001 );
		$highestTick = ceil( $maxAxis / $biggerMultipleOf10 - .001 );
		
		for ( $i = $lowestTick; $i <= $highestTick; $i++ ) {
			$numbers_ticks .= ($i * $biggerMultipleOf10) . ', ';
		}

		$pointlabels = FormatJson::encode( $this->params['pointlabels'] );
		
		$js_bar =<<<END
<script type="text/javascript">
jQuery(document).ready(function(){
	jQuery.jqplot.config.enablePlugins = true;
	plot1 = jQuery.jqplot('$barID', [{$numbers_str}], {
		title: '{$this->m_charttitle}',
		seriesColors: ['$this->m_barcolor'],
		seriesDefaults: {
			fillToZero: true
		},
		series: [  {
			renderer: jQuery.jqplot.BarRenderer, rendererOptions: {
				barDirection: '{$this->m_bardirection}',
				barPadding: 6,
				barMargin: $barmargin
			},
			pointLabels: {show: $pointlabels}
		}],
		axes: {
			$labels_axis: {
				renderer: jQuery.jqplot.CategoryAxisRenderer,
				ticks: {$labels_str},
				tickRenderer: jQuery.jqplot.CanvasAxisTickRenderer,
				tickOptions: {
					angle: $angle_val
				}
			},
			$numbers_axis: {
				ticks: [$numbers_ticks],
				label: '{$this->m_numbersaxislabel}'
			}
		}
	});
});
</script>
END;
		$wgOut->addScript( $js_bar );
		
		$width = $this->params['width'];
		$height = $this->params['height'];
		
		return Html::element(
			'div',
			array(
				'id' => $barID,
				'style' => Sanitizer::checkCss( "margin-top: 20px; margin-left: 20px; width: {$width}px; height: {$height}px;" )
			)
		);
	}
Exemplo n.º 11
0
 /**
  * @dataProvider provideCssCommentsFixtures
  * @covers Sanitizer::checkCss
  */
 function testCssCommentsChecking($expected, $css, $message = '')
 {
     $this->assertEquals($expected, Sanitizer::checkCss($css), $message);
 }
Exemplo n.º 12
0
	/**
	 * Get the JS and HTML that needs to be added to the output to create the chart.
	 * 
	 * @since 1.7
	 * 
	 * @param array $data label => value
	 */
	protected function getFormatOutput( array $data ) {
		global $wgOut;

		$this->isHTML = true;

		$maxValue = count( $data ) == 0 ? 0 : max( $data );
		
		if ( $this->params['min'] === false ) {
			$minValue = count( $data ) == 0 ? 0 : min( $data );
		}
		else {
			$minValue = $this->params['min'];
		}
		
		foreach ( $data as $i => &$nr ) {
			if ( $this->params['bardirection'] == 'horizontal' ) {
				$nr = array( $nr, $i );
			}
		}
		
		$treemapID = 'treemap' . self::$m_barchartnum;
		self::$m_barchartnum++;
		
		$labels_str = FormatJson::encode( array_keys( $data ) );
		$numbers_str = FormatJson::encode( array_values( $data ) );
		
		$labels_axis = 'xaxis';
		$numbers_axis = 'yaxis';
		
		$angle_val = -40;
		$barmargin = 6;
		
		if ( $this->params['bardirection'] == 'horizontal' ) {
			$labels_axis = 'yaxis';
			$numbers_axis = 'xaxis';
			$angle_val = 0;
			$barmargin = 8 ;
		}
		
		$barwidth = 20; // width of each bar
		$bardistance = 4; // distance between two bars

		// Calculate the tick values for the numbers, based on the
		// lowest and highest number. jqPlot has its own option for
		// calculating ticks automatically - "autoscale" - but it
		// currently (September 2010) fails for numbers less than 1,
		// and negative numbers.
		// If both max and min are 0, just escape now.
		if ( $maxValue == 0 && $minValue == 0 ) {
			return null;
		}
		// Make the max and min slightly larger and bigger than the
		// actual max and min, so that the bars don't directly touch
		// the top and bottom of the graph
		if ( $maxValue > 0 ) { $maxValue += .001; }
		if ( $minValue < 0 ) { $minValue -= .001; }
		if ( $maxValue == 0 ) {
			$multipleOf10 = 0;
			$maxAxis = 0;
		} else {
			$multipleOf10 = pow( 10, floor( log( $maxValue, 10 ) ) );
			$maxAxis = ceil( $maxValue / $multipleOf10 ) * $multipleOf10;
		}
		
		if ( $minValue == 0 ) {
			$negativeMultipleOf10 = 0;
			$minAxis = 0;
		} else {
			$negativeMultipleOf10 = -1 * pow( 10, floor( log( $minValue, 10 ) ) );
			$minAxis = ceil( $minValue / $negativeMultipleOf10 ) * $negativeMultipleOf10;
		}
		
		$numbers_ticks = '';
		$biggerMultipleOf10 = max( $multipleOf10, -1 * $negativeMultipleOf10 );
		$lowestTick = floor( $minAxis / $biggerMultipleOf10 + .001 );
		$highestTick = ceil( $maxAxis / $biggerMultipleOf10 - .001 );
		
		for ( $i = $lowestTick; $i <= $highestTick; $i++ ) {
			$numbers_ticks .= ($i * $biggerMultipleOf10) . ', ';
		}

#		$pointlabels = FormatJson::encode( $this->params['pointlabels'] );

		$width = $this->params['width'];
		$height = $this->params['height'];

		
		$js_treemap =<<<END
<script type="text/javascript">
$(document).ready(function() {
//http://dealloc.me/2011/06/24/d3-is-not-a-graphing-library.html
var data, h, max, pb, pl, pr, pt, ticks, version, vis, w, x, y, _ref;
    version = Number(document.location.hash.replace('#', ''));
    data = {$numbers_str};
    _ref = [20, 20, 20, 20], pt = _ref[0], pl = _ref[1], pr = _ref[2], pb = _ref[3];
    w = $width - (pl + pr);
    h = $height - (pt + pb);
    max = d3.max(data);
    x = d3.scale.linear().domain([0, data.length - 1]).range([0, w]);
    y = d3.scale.linear().domain([0, max]).range([h, 0]);
    vis = d3.select('#$treemapID').style('margin', '20px auto').style('width', "" + w + "px").append('svg:svg').attr('width', w + (pl + pr)).attr('height', h + pt + pb).attr('class', 'viz').append('svg:g').attr('transform', "translate(" + pl + "," + pt + ")");
    vis.selectAll('path.line').data([data]).enter().append("svg:path").attr("d", d3.svg.line().x(function(d, i) {
      return x(i);
    }).y(y));
    if (version < 2 && version !== 0) {
      return;
    }
    ticks = vis.selectAll('.ticky').data(y.ticks(7)).enter().append('svg:g').attr('transform', function(d) {
      return "translate(0, " + (y(d)) + ")";
    }).attr('class', 'ticky');
    ticks.append('svg:line').attr('y1', 0).attr('y2', 0).attr('x1', 0).attr('x2', w);
    ticks.append('svg:text').text(function(d) {
      return d;
    }).attr('text-anchor', 'end').attr('dy', 2).attr('dx', -4);
    ticks = vis.selectAll('.tickx').data(x.ticks(data.length)).enter().append('svg:g').attr('transform', function(d, i) {
      return "translate(" + (x(i)) + ", 0)";
    }).attr('class', 'tickx');
    ticks.append('svg:line').attr('y1', h).attr('y2', 0).attr('x1', 0).attr('x2', 0);
    ticks.append('svg:text').text(function(d, i) {
      return i;
    }).attr('y', h).attr('dy', 15).attr('dx', -2);
    if (version < 3 && version !== 0) {
      return;
    }
    return vis.selectAll('.point').data(data).enter().append("svg:circle").attr("class", function(d, i) {
      if (d === max) {
        return 'point max';
      } else {
        return 'point';
      }
    }).attr("r", function(d, i) {
      if (d === max) {
        return 6;
      } else {
        return 4;
      }
    }).attr("cx", function(d, i) {
      return x(i);
    }).attr("cy", function(d) {
      return y(d);
    }).on('mouseover', function() {
      return d3.select(this).attr('r', 8);
    }).on('mouseout', function() {
      return d3.select(this).attr('r', 4);
    }).on('click', function(d, i) {
      return console.log(d, i);
    });
  });
</script>
END;
		$wgOut->addScript( $js_treemap );
				
		return Html::element(
			'div',
			array(
				'id' => $treemapID,
				'style' => Sanitizer::checkCss( "margin-top: 20px; margin-left: 20px; margin-right: 20px; width: {$width}px; height: {$height}px;" )
			)
		);
	}
Exemplo n.º 13
0
 /**
  * Override the title of the page when viewed, provided we've been given a
  * title which will normalise to the canonical title
  *
  * @param $parser Parser: parent parser
  * @param string $text desired title text
  * @return String
  */
 static function displaytitle($parser, $text = '')
 {
     global $wgRestrictDisplayTitle;
     // parse a limited subset of wiki markup (just the single quote items)
     $text = $parser->doQuotes($text);
     // remove stripped text (e.g. the UNIQ-QINU stuff) that was generated by tag extensions/whatever
     $text = preg_replace('/' . preg_quote($parser->uniqPrefix(), '/') . '.*?' . preg_quote(Parser::MARKER_SUFFIX, '/') . '/', '', $text);
     // list of disallowed tags for DISPLAYTITLE
     // these will be escaped even though they are allowed in normal wiki text
     $bad = array('h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'div', 'blockquote', 'ol', 'ul', 'li', 'hr', 'table', 'tr', 'th', 'td', 'dl', 'dd', 'caption', 'p', 'ruby', 'rb', 'rt', 'rp', 'br');
     // disallow some styles that could be used to bypass $wgRestrictDisplayTitle
     if ($wgRestrictDisplayTitle) {
         $htmlTagsCallback = function (&$params) {
             $decoded = Sanitizer::decodeTagAttributes($params);
             if (isset($decoded['style'])) {
                 // this is called later anyway, but we need it right now for the regexes below to be safe
                 // calling it twice doesn't hurt
                 $decoded['style'] = Sanitizer::checkCss($decoded['style']);
                 if (preg_match('/(display|user-select|visibility)\\s*:/i', $decoded['style'])) {
                     $decoded['style'] = '/* attempt to bypass $wgRestrictDisplayTitle */';
                 }
             }
             $params = Sanitizer::safeEncodeTagAttributes($decoded);
         };
     } else {
         $htmlTagsCallback = null;
     }
     // only requested titles that normalize to the actual title are allowed through
     // if $wgRestrictDisplayTitle is true (it is by default)
     // mimic the escaping process that occurs in OutputPage::setPageTitle
     $text = Sanitizer::normalizeCharReferences(Sanitizer::removeHTMLtags($text, $htmlTagsCallback, array(), array(), $bad));
     $title = Title::newFromText(Sanitizer::stripAllTags($text));
     if (!$wgRestrictDisplayTitle) {
         $parser->mOutput->setDisplayTitle($text);
     } elseif ($title instanceof Title && !$title->hasFragment() && $title->equals($parser->mTitle)) {
         $parser->mOutput->setDisplayTitle($text);
     }
     return '';
 }
Exemplo n.º 14
0
function wfCSSRawPageViewBeforeOutput(&$rawPage, &$text)
{
    global $wgCSSIdentifier;
    if ($rawPage->getRequest()->getBool($wgCSSIdentifier)) {
        $text = Sanitizer::checkCss($text);
    }
    return true;
}
Exemplo n.º 15
0
	/**
	 * Get the JS and HTML that needs to be added to the output to create the chart.
	 * 
	 * @since 1.7
	 * 
	 * @param array $data label => value
	 */
	protected function getFormatOutput( array $data ) {
		global $wgOut;

		$this->isHTML = true;

		$maxValue = count( $data ) == 0 ? 0 : max( $data );
		
		if ( $this->params['min'] === false ) {
			$minValue = count( $data ) == 0 ? 0 : min( $data );
		}
		else {
			$minValue = $this->params['min'];
		}
		
		$barID = 'bar' . self::$m_barchartnum;
		self::$m_barchartnum++;
		
		$labels_str = FormatJson::encode( array_keys( $data ) );
		$numbers_str = FormatJson::encode( array_values( $data ) );
		
		$labels_axis = 'xaxis';
		$numbers_axis = 'yaxis';
		
		$angle_val = -40;
		$barmargin = 6;
		
		$barwidth = 20; // width of each bar
		$bardistance = 4; // distance between two bars

		// Calculate the tick values for the numbers, based on the
		// lowest and highest number. jqPlot has its own option for
		// calculating ticks automatically - "autoscale" - but it
		// currently (September 2010) fails for numbers less than 1,
		// and negative numbers.
		// If both max and min are 0, just escape now.
		if ( $maxValue == 0 && $minValue == 0 ) {
			return null;
		}
		// Make the max and min slightly larger and bigger than the
		// actual max and min, so that the bars don't directly touch
		// the top and bottom of the graph
		if ( $maxValue > 0 ) { $maxValue += .001; }
		if ( $minValue < 0 ) { $minValue -= .001; }
		if ( $maxValue == 0 ) {
			$multipleOf10 = 0;
			$maxAxis = 0;
		} else {
			$multipleOf10 = pow( 10, floor( log( $maxValue, 10 ) ) );
			$maxAxis = ceil( $maxValue / $multipleOf10 ) * $multipleOf10;
		}
		
		if ( $minValue == 0 ) {
			$negativeMultipleOf10 = 0;
			$minAxis = 0;
		} else {
			$negativeMultipleOf10 = -1 * pow( 10, floor( log( $minValue, 10 ) ) );
			$minAxis = ceil( $minValue / $negativeMultipleOf10 ) * $negativeMultipleOf10;
		}
		
		$numbers_ticks = '';
		$biggerMultipleOf10 = max( $multipleOf10, -1 * $negativeMultipleOf10 );
		$lowestTick = floor( $minAxis / $biggerMultipleOf10 + .001 );
		$highestTick = ceil( $maxAxis / $biggerMultipleOf10 - .001 );
		
		for ( $i = $lowestTick; $i <= $highestTick; $i++ ) {
			$numbers_ticks .= ($i * $biggerMultipleOf10) . ', ';
		}

#		$pointlabels = FormatJson::encode( $this->params['pointlabels'] );

		$width = $this->params['width'];
		$height = $this->params['height'];
		$charttitle = $this->patams['charttitle'];
		
		$js_bar =<<<END
<script type="text/javascript">
$(document).ready(function() {
//Examples based on http://www.verisi.com/resources/d3-tutorial-basic-charts.htm
//Alternating to form a single series. Bar Color will switch back & forth 
//var data = d3.range(10).map(Math.random);
var data = {$numbers_str};
var colorlist = ["steelblue", "lightblue"];
var labellist = ($labels_str);
 
var w = $width,
    h = $height - 20 ,
    labelpad = $width / 3,
    barwidth = 20,
    x = d3.scale.linear().domain([0, 100]).range([0, w]),
    y = d3.scale.ordinal().domain(d3.range(data.length)).rangeBands([0, h], .2);
 
var vis = d3.select("#$barID")
    .append("svg:svg")
    .attr("width", $width - $barwidth  )
    .attr("height", h + 20)
    .append("svg:g")
    .attr("transform", "translate(20,0)")
    .attr("class", "chart");    
 
var bars = vis.selectAll("g.bar")
    .data(data)
    .enter().append("svg:g")
    .attr("class", "bar")
    .attr("transform", function(d, i) { return "translate(" + labelpad + "," + y(i) + ")"; });

bars.append("svg:rect")
    .attr("fill", function(d, i) { return colorlist[i % 2]; } )   //Alternate colors
    .attr("width", x )
    .attr("height", y.rangeBand())
    .text(function(d) { return d; });
 
bars.append("svg:text")
    .attr("x", 0)
    .attr("y", -2 + y.rangeBand() / 2)
    .attr("dx", -16)
    .attr("dy", ".55em")
    .attr("class", "barlabel")
    .attr("text-anchor", "end")
    .text(function(d, i) { return labellist[i]; });

//Generate labels for each bar
var labels = vis.selectAll("g.bar")
    .append("svg:text")
    .attr("class", "barvalue")
    .attr("x", 3)
//    .attr("x", function(d) { return x(d) + 2; })    
    .attr("y", -5 + y.rangeBand() / 2 + 10 )
    .attr("text-anchor", "right")
    .attr("transform", function(d) { return "translate(" + x(d) + ", 0)"; })
    .style("width", function(d) { return d * 10 + "px"; })   
    .text(function(d) {  return d; });
     
//END Generate labels for each bar 
 
var rules = vis.selectAll("g.rule")
    .data(x.ticks(10))
    .enter().append("svg:g")
    .attr("class", "rule")
    .attr("transform", function(d) { return "translate(" + x(d) + ", 0)"; });
 
// ---------------------------------------
// Add Title, then Legend
// ---------------------------------------
vis.append("svg:text")
   .attr("x", 0)
   .attr("y", 25    )
   .attr("class", "chartitle")
   .text('{$charttitle}'); 
 
rules.append("svg:line")
    .attr("y1", h)
    .attr("y2", h + 6)
    .attr("x1", labelpad)
    .attr("x2", labelpad)
    .attr("stroke", "black");
 
rules.append("svg:line")
    .attr("y1", 0)
    .attr("y2", h)
    .attr("x1", labelpad)
    .attr("x2", labelpad)
    .attr("stroke", "white")
    .attr("stroke-opacity", .3);
 
rules.append("svg:text")
    .attr("y", h + 2 )
    .attr("x", labelpad)
    .attr("dy", ".71em")
    .attr("text-anchor", "middle")
    .text(x.tickFormat(10));

});
</script>
END;
		$wgOut->addScript( $js_bar );
				
		return Html::element(
			'div',
			array(
				'id' => $barID,
				'style' => Sanitizer::checkCss( "margin-top: 20px; margin-left: 20px; margin-right: 20px; width: {$width}px; height: {$height}px;" )
			)
		);
	}