Index: trunk/extensions/Plotters/PlottersParser.php |
— | — | @@ -0,0 +1,114 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Plotter parser. Parses arguments and data for the Plotters extension. |
| 6 | + * |
| 7 | + * @addtogroup Extensions |
| 8 | + * @author Ryan Lane, rlane32+mwext@gmail.com |
| 9 | + * @copyright © 2009 Ryan Lane |
| 10 | + * @license GNU General Public Licence 2.0 or later |
| 11 | + */ |
| 12 | + |
| 13 | +if ( !defined( 'MEDIAWIKI' ) ) { |
| 14 | + echo( "not a valid entry point.\n" ); |
| 15 | + die( 1 ); |
| 16 | +} |
| 17 | + |
| 18 | +class PlotterParser { |
| 19 | + |
| 20 | + var $argumentArray; |
| 21 | + var $dataArray; |
| 22 | + |
| 23 | + function PlotterParser( $input, $argv, &$parser ) { |
| 24 | + $this->parseArguments( $argv ); |
| 25 | + $this->parseData( $input, $parser ); |
| 26 | + } |
| 27 | + |
| 28 | + function getArguments() { |
| 29 | + return $this->argumentArray; |
| 30 | + } |
| 31 | + |
| 32 | + function getData() { |
| 33 | + return $this->dataArray; |
| 34 | + } |
| 35 | + |
| 36 | + function parseArguments( $argv ) { |
| 37 | + // Parse arguments, set defaults, and do sanity checks |
| 38 | + $this->argumentArray = array ( "renderer" => "plotkit", "preprocessors" => array(), "preprocessorarguments" => array(), |
| 39 | + "script" => "", "scriptarguments" => array(), "datasep" => "," ); |
| 40 | + if ( isset( $argv["renderer"] ) ) { |
| 41 | + $this->argumentArray["renderer"] = $argv["renderer"]; |
| 42 | + } |
| 43 | + if ( isset( $argv["preprocessors"] ) ) { |
| 44 | + // Sanitize scripts - alphanumerics only |
| 45 | + $this->argumentArray["preprocessors"] = explode( ',', $argv["preprocessors"] ); |
| 46 | + foreach ( $this->argumentArray["preprocessors"] as &$preprocessor ) { |
| 47 | + $preprocessor = preg_replace( '/[^A-Z0-9]/i', '', $preprocessor ); |
| 48 | + } |
| 49 | + } |
| 50 | + if ( isset( $argv["preprocessorarguments"] ) ) { |
| 51 | + // Replace escaped separators |
| 52 | + $argv["preprocessorarguments"] = preg_replace( '/\\:/', '§UNIQ§', $argv["preprocessorarguments"] ); |
| 53 | + $argv["preprocessorarguments"] = preg_replace( '/\\,/', '§UNIQ2§', $argv["preprocessorarguments"] ); |
| 54 | + |
| 55 | + // Parse and sanitize arguments - escape single quotes and backslashes |
| 56 | + $arguments = explode( ':', $argv["preprocessorarguments"] ); |
| 57 | + foreach ( $arguments as $argument ) { |
| 58 | + $subargumentarr = explode( ',', $argument ); |
| 59 | + foreach ( $subargumentarr as &$singleargument ) { |
| 60 | + $singleargument = preg_replace( "/\\\\/", '\\\\', $singleargument ); |
| 61 | + $singleargument = preg_replace( "/'/", "\\'", $singleargument ); |
| 62 | + |
| 63 | + // Fix escaped separators |
| 64 | + $singleargument = preg_replace( "/§UNIQ§/", ":", $singleargument ); |
| 65 | + $singleargument = preg_replace( "/§UNIQ2§/", ",", $singleargument ); |
| 66 | + } |
| 67 | + $this->argumentArray["preprocessorarguments"][] = $subargumentarr; |
| 68 | + } |
| 69 | + |
| 70 | + } |
| 71 | + if ( isset( $argv["script"] ) ) { |
| 72 | + // Sanitize scripts - alphanumerics only |
| 73 | + $this->argumentArray["script"] = preg_replace( '/[^A-Z0-9]/i', '', $argv["script"] ); |
| 74 | + } |
| 75 | + if ( isset( $argv["scriptarguments"] ) ) { |
| 76 | + // Replace escaped separators |
| 77 | + $argv["scriptarguments"] = preg_replace( '/\\,/', '§UNIQ§', $argv["scriptarguments"] ); |
| 78 | + |
| 79 | + // Parse and sanitize arguments - escape single quotes and backslashes |
| 80 | + $arguments = explode( ',', $argv["scriptarguments"] ); |
| 81 | + foreach ( $arguments as $argument ) { |
| 82 | + $argument = preg_replace( "/\\\\/", '\\\\', $argument ); |
| 83 | + $argument = preg_replace( "/'/", "\\'", $argument ); |
| 84 | + |
| 85 | + // Fix escaped separators |
| 86 | + $argument = preg_replace( "/§UNIQ§/", ",", $argument ); |
| 87 | + $this->argumentArray["scriptarguments"][] = $argument; |
| 88 | + } |
| 89 | + } |
| 90 | + if ( isset( $argv["datasep"] ) ) { |
| 91 | + $this->argumentArray["datasep"] = $argv["datasep"]; |
| 92 | + } |
| 93 | + } |
| 94 | + |
| 95 | + function parseData( $input, $parser ) { |
| 96 | + // Replace escaped separators |
| 97 | + $sep = $this->argumentArray["datasep"]; |
| 98 | + $input = preg_replace( "/\\\\$sep/", '§UNIQ§', $input ); |
| 99 | + |
| 100 | + // Parse and sanitize data - escape single quotes and backslashes |
| 101 | + $lines = preg_split( "/\n/", $input, -1, PREG_SPLIT_NO_EMPTY ); |
| 102 | + foreach ( $lines as $line ) { |
| 103 | + $values = explode( ',', $line ); |
| 104 | + foreach ( $values as &$value ) { |
| 105 | + $value = preg_replace( "/\\\\/", "\\\\", $value ); |
| 106 | + $value = preg_replace( "/'/", "\\'", $value ); |
| 107 | + |
| 108 | + // Fix escaped separators |
| 109 | + $value = preg_replace( "/§UNIQ§/", "\\$sep", $value ); |
| 110 | + } |
| 111 | + $this->dataArray[] = $values; |
| 112 | + Plotter::debug( 'plot data values: ', $values ); |
| 113 | + } |
| 114 | + } |
| 115 | +} |
Property changes on: trunk/extensions/Plotters/PlottersParser.php |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 116 | + native |
Index: trunk/extensions/Plotters/Plotters.i18n.php |
— | — | @@ -0,0 +1,26 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Internationalisation file for extension Plotters. Based on the Gadgets extension. |
| 5 | + * |
| 6 | + * @addtogroup Extensions |
| 7 | + * @author Ryan Lane, rlane32+mwext@gmail.com |
| 8 | + * @copyright © 2009 Ryan Lane |
| 9 | + * @license GNU General Public Licence 2.0 or later |
| 10 | + */ |
| 11 | + |
| 12 | +$messages = array(); |
| 13 | + |
| 14 | +/** English |
| 15 | + * @author Ryan Lane, rlane32+mwext@gmail.com |
| 16 | + */ |
| 17 | +$messages['en'] = array( |
| 18 | + # for Special:Version |
| 19 | + 'plotters-desc' => 'Lets users use custom javascript in their jsplot tags', |
| 20 | + |
| 21 | + # for Special:Gadgets |
| 22 | + 'plotters' => 'Plotters', |
| 23 | + 'plotters-title' => 'Plotters', |
| 24 | + 'plotters-pagetext' => "Below is a list of special plotters users can use in their jsplot tags, as defined by [[MediaWiki:Plotters-definition]]. |
| 25 | +This overview provides easy access to the system message pages that define each plotter's description and code.", |
| 26 | + 'plotters-uses' => 'Uses', |
| 27 | +); |
Property changes on: trunk/extensions/Plotters/Plotters.i18n.php |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 28 | + native |
Index: trunk/extensions/Plotters/Plotters.php |
— | — | @@ -0,0 +1,250 @@ |
| 2 | +<?php |
| 3 | +# Copyright (C) 2009 Ryan Lane <rlane32+mwext@gmail.com> |
| 4 | +# |
| 5 | +# This program is free software; you can redistribute it and/or modify |
| 6 | +# it under the terms of the GNU General Public License as published by |
| 7 | +# the Free Software Foundation; either version 2 of the License, or |
| 8 | +# (at your option) any later version. |
| 9 | +# |
| 10 | +# This program is distributed in the hope that it will be useful, |
| 11 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | +# GNU General Public License for more details. |
| 14 | +# |
| 15 | +# You should have received a copy of the GNU General Public License along |
| 16 | +# with this program; if not, write to the Free Software Foundation, Inc., |
| 17 | +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| 18 | +# http://www.gnu.org/copyleft/gpl.html |
| 19 | + |
| 20 | +# Based off of the Gadgets and SmoothGallery extensions |
| 21 | + |
| 22 | +if ( !defined( 'MEDIAWIKI' ) ) |
| 23 | + die( -1 ); |
| 24 | + |
| 25 | +/** |
| 26 | + * Add extension information to Special:Version |
| 27 | + */ |
| 28 | +$wgExtensionCredits['other'][] = array( |
| 29 | + 'path' => __FILE__, |
| 30 | + 'name' => 'Plotter parser extension', |
| 31 | + 'version' => '0.1b', |
| 32 | + 'author' => 'Ryan Lane', |
| 33 | + 'description' => 'Allows users to create client side graphs and plots', |
| 34 | + 'descriptionmsg' => 'plotters-desc', |
| 35 | + 'url' => 'http://www.mediawiki.org/wiki/Extension:Plotters', |
| 36 | +); |
| 37 | + |
| 38 | +$wgExtensionFunctions[] = "efPlotter"; |
| 39 | + |
| 40 | +$wgHooks['OutputPageParserOutput'][] = 'PlotterParserOutput'; |
| 41 | +$wgHooks['LanguageGetMagic'][] = 'PlotterLanguageGetMagic'; |
| 42 | +$wgHooks['ArticleSaveComplete'][] = 'wfPlottersArticleSaveComplete'; |
| 43 | + |
| 44 | +$dir = dirname( __FILE__ ) . '/'; |
| 45 | +$wgExtensionMessagesFiles['Plotters'] = $dir . 'Plotters.i18n.php'; |
| 46 | +$wgExtensionAliasesFiles['Plotters'] = $dir . 'Plotters.alias.php'; |
| 47 | +$wgAutoloadClasses['Plotter'] = $dir . 'PlottersClass.php'; |
| 48 | +$wgAutoloadClasses['PlotterParser'] = $dir . 'PlottersParser.php'; |
| 49 | +$wgAutoloadClasses['SpecialPlotters'] = $dir . 'SpecialPlotters.php'; |
| 50 | +$wgSpecialPages['Plotters'] = 'SpecialPlotters'; |
| 51 | +$wgSpecialPageGroups['Plotters'] = 'wiki'; |
| 52 | + |
| 53 | +// sane defaults. always initialize to avoid register_globals vulnerabilities |
| 54 | +$wgPlotterExtensionPath = $wgScriptPath . '/extensions/Plotter'; |
| 55 | + |
| 56 | +function wfPlottersArticleSaveComplete( &$article, &$wgUser, &$text ) { |
| 57 | + // update cache if MediaWiki:Plotters-definition was edited |
| 58 | + $title = $article->mTitle; |
| 59 | + if ( $title->getNamespace() == NS_MEDIAWIKI && $title->getText() == 'Plotters-definition' ) { |
| 60 | + wfLoadPlottersStructured( $text ); |
| 61 | + } |
| 62 | + return true; |
| 63 | +} |
| 64 | + |
| 65 | +function wfLoadPlotters() { |
| 66 | + static $plotters = NULL; |
| 67 | + |
| 68 | + if ( $plotters !== NULL ) return $plotters; |
| 69 | + |
| 70 | + $struct = wfLoadPlottersStructured(); |
| 71 | + if ( !$struct ) { |
| 72 | + $plotters = $struct; |
| 73 | + return $plotters; |
| 74 | + } |
| 75 | + |
| 76 | + $plotters = array(); |
| 77 | + foreach ( $struct as $section => $entries ) { |
| 78 | + $plotters = array_merge( $plotters, $entries ); |
| 79 | + } |
| 80 | + |
| 81 | + return $plotters; |
| 82 | +} |
| 83 | + |
| 84 | +function wfLoadPlottersStructured( $forceNewText = NULL ) { |
| 85 | + global $wgMemc; |
| 86 | + |
| 87 | + static $plotters = NULL; |
| 88 | + if ( $plotters !== NULL && $forceNewText !== NULL ) return $plotters; |
| 89 | + |
| 90 | + $key = wfMemcKey( 'plotters-definition' ); |
| 91 | + |
| 92 | + if ( $forceNewText === NULL ) { |
| 93 | + // cached? |
| 94 | + $plotters = $wgMemc->get( $key ); |
| 95 | + if ( is_array( $plotters ) ) return $plotters; |
| 96 | + |
| 97 | + $p = wfMsgForContentNoTrans( "plotters-definition" ); |
| 98 | + if ( wfEmptyMsg( "plotters-definition", $p ) ) { |
| 99 | + $plotters = false; |
| 100 | + return $plotters; |
| 101 | + } |
| 102 | + } else { |
| 103 | + $p = $forceNewText; |
| 104 | + } |
| 105 | + |
| 106 | + $p = preg_replace( '/<!--.*-->/s', '', $p ); |
| 107 | + $p = preg_split( '/(\r\n|\r|\n)+/', $p ); |
| 108 | + |
| 109 | + $plotters = array(); |
| 110 | + $section = ''; |
| 111 | + |
| 112 | + foreach ( $p as $line ) { |
| 113 | + if ( preg_match( '/^==+ *([^*:\s|]+?)\s*==+\s*$/', $line, $m ) ) { |
| 114 | + $section = $m[1]; |
| 115 | + } |
| 116 | + else if ( preg_match( '/^\*+ *([a-zA-Z](?:[-_:.\w\d ]*[a-zA-Z0-9])?)\s*((\|[^|]*)+)\s*$/', $line, $m ) ) { |
| 117 | + // NOTE: the plotter name is used as part of the name of a form field, |
| 118 | + // and must follow the rules defined in http://www.w3.org/TR/html4/types.html#type-cdata |
| 119 | + // Also, title-normalization applies. |
| 120 | + $name = str_replace( ' ', '_', $m[1] ); |
| 121 | + |
| 122 | + $code = preg_split( '/\s*\|\s*/', $m[2], - 1, PREG_SPLIT_NO_EMPTY ); |
| 123 | + |
| 124 | + if ( $code ) { |
| 125 | + $plotters[$section][$name] = $code; |
| 126 | + } |
| 127 | + } |
| 128 | + } |
| 129 | + |
| 130 | + // cache for a while. gets purged automatically when MediaWiki:Plotters-definition is edited |
| 131 | + $wgMemc->set( $key, $plotters, 60 * 60 * 24 ); |
| 132 | + $source = $forceNewText !== NULL ? 'input text' : 'MediaWiki:Plotters-definition'; |
| 133 | + wfDebug( __METHOD__ . ": $source parsed, cache entry $key updated\n" ); |
| 134 | + |
| 135 | + return $plotters; |
| 136 | +} |
| 137 | + |
| 138 | +function wfApplyPlotterCode( $code, &$out, &$done ) { |
| 139 | + global $wgSkin, $wgJsMimeType; |
| 140 | + |
| 141 | + // FIXME: stuff added via $out->addScript appears below usercss and userjs in the head tag. |
| 142 | + // but we'd want it to appear above explicit user stuff, so it can be overwritten. |
| 143 | + foreach ( $code as $codePage ) { |
| 144 | + // include only once |
| 145 | + if ( isset( $done[$codePage] ) ) continue; |
| 146 | + $done[$codePage] = true; |
| 147 | + |
| 148 | + $t = Title::makeTitleSafe( NS_MEDIAWIKI, "Plotters-$codePage" ); |
| 149 | + if ( !$t ) continue; |
| 150 | + |
| 151 | + if ( preg_match( '/\.js/', $codePage ) ) { |
| 152 | + $u = $t->getLocalURL( 'action=raw&ctype=' . $wgJsMimeType ); |
| 153 | + $out->addScript( '<script type="' . $wgJsMimeType . '" src="' . htmlspecialchars( $u ) . '"></script>' . "\n" ); |
| 154 | + } |
| 155 | + else if ( preg_match( '/\.css/', $codePage ) ) { |
| 156 | + $u = $t->getLocalURL( 'action=raw&ctype=text/css' ); |
| 157 | + $out->addScript( '<style type="text/css">/*<![CDATA[*/ @import "' . $u . '"; /*]]>*/</style>' . "\n" ); |
| 158 | + } |
| 159 | + } |
| 160 | +} |
| 161 | + |
| 162 | +function efPlotter() { |
| 163 | + global $wgParser; |
| 164 | + |
| 165 | + $wgParser->setHook( 'plot', 'initPlotter' ); |
| 166 | + $wgParser->setFunctionHook( 'plot', 'initPlotterPF' ); |
| 167 | +} |
| 168 | + |
| 169 | +function initPlotterPF( &$parser ) { |
| 170 | + global $wgPlotterDelimiter; |
| 171 | + |
| 172 | + $numargs = func_num_args(); |
| 173 | + if ( $numargs < 2 ) { |
| 174 | + $input = "#Plotter: no arguments specified"; |
| 175 | + return str_replace( '§', '<', '§pre>§nowiki>' . $input . '§/nowiki>§/pre>' ); |
| 176 | + } |
| 177 | + |
| 178 | + // fetch all user-provided arguments (skipping $parser) |
| 179 | + $input = ""; |
| 180 | + $argv = array(); |
| 181 | + $arg_list = func_get_args(); |
| 182 | + for ( $i = 1; $i < $numargs; $i++ ) { |
| 183 | + $p1 = $arg_list[$i]; |
| 184 | + |
| 185 | + $aParam = explode( '=', $p1, 2 ); |
| 186 | + if ( count( $aParam ) < 2 ) { |
| 187 | + continue; |
| 188 | + } |
| 189 | + Plotter::debug( 'plot tag parameter: ', $aParam ); |
| 190 | + if ( $aParam[0] == "data" ) { |
| 191 | + $input = $aParam[1]; |
| 192 | + continue; |
| 193 | + } |
| 194 | + $sKey = trim( $aParam[0] ); |
| 195 | + $sVal = trim( $aParam[1] ); |
| 196 | + |
| 197 | + if ( $sKey != '' ) { |
| 198 | + $argv[$sKey] = $sVal; |
| 199 | + } |
| 200 | + } |
| 201 | + |
| 202 | + $output = initPlotter( $input, $argv, $parser ); |
| 203 | + return array( $output, 'noparse' => true, 'isHTML' => true ); |
| 204 | +} |
| 205 | + |
| 206 | +function initPlotter( $input, $argv, &$parser ) { |
| 207 | + $pParser = new PlotterParser( $input, $argv, $parser ); |
| 208 | + $pPlotter = new Plotter( $pParser, $parser ); |
| 209 | + |
| 210 | + $pPlotter->checkForErrors(); |
| 211 | + if ( $pPlotter->hasErrors() ) { |
| 212 | + return $pPlotter->getErrors(); |
| 213 | + } else { |
| 214 | + return $pPlotter->toHTML(); |
| 215 | + } |
| 216 | +} |
| 217 | + |
| 218 | +/** |
| 219 | + * Hook callback that injects messages and things into the <head> tag |
| 220 | + * Does nothing if $parserOutput->mPlotterTag is not set |
| 221 | + */ |
| 222 | +function PlotterParserOutput( &$outputPage, &$parserOutput ) { |
| 223 | + if ( !empty( $parserOutput->mPlotterTag ) ) { |
| 224 | + // Output required javascript |
| 225 | + Plotter::setPlotterHeaders( $outputPage ); |
| 226 | + |
| 227 | + // Output user defined javascript |
| 228 | + $plotters = wfLoadPlotters(); |
| 229 | + if ( !$plotters ) return true; |
| 230 | + |
| 231 | + $done = array(); |
| 232 | + |
| 233 | + foreach ( $plotters as $pname => $code ) { |
| 234 | + $tname = strtolower( "mplotter-$pname" ); |
| 235 | + if ( !empty( $parserOutput->$tname ) ) { |
| 236 | + wfApplyPlotterCode( $code, $outputPage, $done ); |
| 237 | + } |
| 238 | + } |
| 239 | + } |
| 240 | + return true; |
| 241 | +} |
| 242 | + |
| 243 | +// FIXME: doesn't this make using this method and the hook above useless? |
| 244 | +/** |
| 245 | + * We ignore langCode - parser function names can be translated but |
| 246 | + * we are not using this feature |
| 247 | + */ |
| 248 | +function PlotterLanguageGetMagic( &$magicWords, $langCode ) { |
| 249 | + $magicWords['plot'] = array( 0, 'plot' ); |
| 250 | + return true; |
| 251 | +} |
Property changes on: trunk/extensions/Plotters/Plotters.php |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 252 | + native |
Index: trunk/extensions/Plotters/SpecialPlotters.php |
— | — | @@ -0,0 +1,98 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Special:Plotters, provides a preview of MediaWiki:Plotters. Based on the Gadgets extension. |
| 5 | + * |
| 6 | + * @addtogroup Extensions |
| 7 | + * @author Ryan Lane, rlane32+mwext@gmail.com |
| 8 | + * @copyright © 2009 Ryan Lane |
| 9 | + * @license GNU General Public Licence 2.0 or later |
| 10 | + */ |
| 11 | + |
| 12 | +if ( !defined( 'MEDIAWIKI' ) ) { |
| 13 | + echo( "not a valid entry point.\n" ); |
| 14 | + die( 1 ); |
| 15 | +} |
| 16 | + |
| 17 | +/** |
| 18 | + * |
| 19 | + */ |
| 20 | +class SpecialPlotters extends SpecialPage { |
| 21 | + |
| 22 | + /** |
| 23 | + * Constructor |
| 24 | + */ |
| 25 | + function __construct() { |
| 26 | + SpecialPage::SpecialPage( 'Plotters', '', true ); |
| 27 | + } |
| 28 | + |
| 29 | + /** |
| 30 | + * Main execution function |
| 31 | + * @param $par Parameters passed to the page |
| 32 | + */ |
| 33 | + function execute( $par ) { |
| 34 | + global $wgOut, $wgUser; |
| 35 | + |
| 36 | + wfLoadExtensionMessages( 'Plotters' ); |
| 37 | + $skin = $wgUser->getSkin(); |
| 38 | + |
| 39 | + $this->setHeaders(); |
| 40 | + $wgOut->setPagetitle( wfMsg( "plotters-title" ) ); |
| 41 | + $wgOut->addWikiText( wfMsg( "plotters-pagetext" ) ); |
| 42 | + |
| 43 | + $plotters = wfLoadPlottersStructured(); |
| 44 | + if ( !$plotters ) return; |
| 45 | + |
| 46 | + $listOpen = false; |
| 47 | + |
| 48 | + $msgOpt = array( 'parseinline', 'parsemag' ); |
| 49 | + |
| 50 | + foreach ( $plotters as $section => $entries ) { |
| 51 | + if ( $section !== false && $section !== '' ) { |
| 52 | + $t = Title::makeTitleSafe( NS_MEDIAWIKI, "Plotter-section-$section" ); |
| 53 | + $lnk = $t ? $skin->makeLinkObj( $t, wfMsgHTML( "edit" ), 'action=edit' ) : htmlspecialchars( $section ); |
| 54 | + $ttext = wfMsgExt( "plotter-section-$section", $msgOpt ); |
| 55 | + |
| 56 | + if ( $listOpen ) { |
| 57 | + $wgOut->addHTML( '</ul>' ); |
| 58 | + $listOpen = false; |
| 59 | + } |
| 60 | + $wgOut->addHTML( "\n<h2>$ttext [$lnk]</h2>\n" ); |
| 61 | + } |
| 62 | + |
| 63 | + foreach ( $entries as $pname => $code ) { |
| 64 | + $t = Title::makeTitleSafe( NS_MEDIAWIKI, "Plotter-$pname" ); |
| 65 | + if ( !$t ) continue; |
| 66 | + |
| 67 | + $lnk = $skin->makeLinkObj( $t, wfMsgHTML( "edit" ), 'action=edit' ); |
| 68 | + $ttext = wfMsgExt( "plotter-$pname", $msgOpt ); |
| 69 | + |
| 70 | + if ( !$listOpen ) { |
| 71 | + $listOpen = true; |
| 72 | + $wgOut->addHTML( '<ul>' ); |
| 73 | + } |
| 74 | + $wgOut->addHTML( "<li>" ); |
| 75 | + $wgOut->addHTML( "$ttext [$lnk]<br />" ); |
| 76 | + |
| 77 | + $wgOut->addHTML( wfMsgHTML( "plotters-uses" ) . ": " ); |
| 78 | + |
| 79 | + $first = true; |
| 80 | + foreach ( $code as $codePage ) { |
| 81 | + $t = Title::makeTitleSafe( NS_MEDIAWIKI, "Plotters-$codePage" ); |
| 82 | + if ( !$t ) continue; |
| 83 | + |
| 84 | + if ( $first ) $first = false; |
| 85 | + else $wgOut->addHTML( ", " ); |
| 86 | + |
| 87 | + $lnk = $skin->makeLinkObj( $t, htmlspecialchars( $t->getText() ) ); |
| 88 | + $wgOut->addHTML( $lnk ); |
| 89 | + } |
| 90 | + |
| 91 | + $wgOut->addHtml( "</li>" ); |
| 92 | + } |
| 93 | + } |
| 94 | + |
| 95 | + if ( $listOpen ) { |
| 96 | + $wgOut->addHTML( '</ul>' ); |
| 97 | + } |
| 98 | + } |
| 99 | +} |
Property changes on: trunk/extensions/Plotters/SpecialPlotters.php |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 100 | + native |
Index: trunk/extensions/Plotters/PlottersClass.php |
— | — | @@ -0,0 +1,152 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Plotter class. Renders html and javascript for the Plotters extension. |
| 6 | + * |
| 7 | + * @addtogroup Extensions |
| 8 | + * @author Ryan Lane, rlane32+mwext@gmail.com |
| 9 | + * @copyright © 2009 Ryan Lane |
| 10 | + * @license GNU General Public Licence 2.0 or later |
| 11 | + */ |
| 12 | + |
| 13 | +class Plotter { |
| 14 | + |
| 15 | + var $parser; |
| 16 | + var $set; |
| 17 | + var $argumentArray, $dataArray; |
| 18 | + var $errors; |
| 19 | + |
| 20 | + function Plotter( $pParser, &$parser ) { |
| 21 | + $this->parser = $parser; |
| 22 | + $this->argumentArray = $pParser->getArguments(); |
| 23 | + $this->dataArray = $pParser->getData(); |
| 24 | + } |
| 25 | + |
| 26 | + function hasErrors() { |
| 27 | + if ( $this->errors == '' ) { |
| 28 | + return false; |
| 29 | + } else { |
| 30 | + return true; |
| 31 | + } |
| 32 | + } |
| 33 | + |
| 34 | + function getErrors() { |
| 35 | + return $this->errors; |
| 36 | + } |
| 37 | + |
| 38 | + function checkForErrors() { |
| 39 | + // Check for a script |
| 40 | + // Check for data |
| 41 | + return ''; |
| 42 | + } |
| 43 | + |
| 44 | + function toHTML() { |
| 45 | + // Add html |
| 46 | + $output = $this->renderPlot(); |
| 47 | + |
| 48 | + // Add fallback |
| 49 | + $output .= $this->renderFallback(); |
| 50 | + |
| 51 | + // Add javascript |
| 52 | + $output .= $this->renderJavascript(); |
| 53 | + |
| 54 | + // Add tags to parser |
| 55 | + $this->parser->mOutput->mPlotterTag = true; |
| 56 | + |
| 57 | + foreach ( $this->argumentArray["preprocessors"] as $preprocessor ) { |
| 58 | + $preprocessor = "mplotter-" . $preprocessor; |
| 59 | + $this->parser->mOutput->$preprocessor = true; |
| 60 | + } |
| 61 | + |
| 62 | + $script = "mplotter-" . $this->argumentArray["script"]; |
| 63 | + $this->parser->mOutput->$script = true; |
| 64 | + |
| 65 | + // output |
| 66 | + return $output; |
| 67 | + } |
| 68 | + |
| 69 | + function renderPlot() { |
| 70 | + // TODO: allow user defined height and width |
| 71 | + // TODO: allow user defined graph id |
| 72 | + return '<div><canvas id="graph" height="300" width="300"></canvas></div>'; |
| 73 | + } |
| 74 | + |
| 75 | + function renderFallback() { |
| 76 | + // Return an html table of the data |
| 77 | + return ''; |
| 78 | + } |
| 79 | + |
| 80 | + function renderJavascript() { |
| 81 | + // Prepare data |
| 82 | + $data = "["; |
| 83 | + foreach ( $this->dataArray as $line ) { |
| 84 | + $data .= "[" . implode( $this->argumentArray["datasep"], $line ) . "]" . ", "; |
| 85 | + } |
| 86 | + $data = substr( $data, 0, -2 ); |
| 87 | + $data .= "]"; |
| 88 | + |
| 89 | + // Run preprocessors |
| 90 | + $output = '<script type="text/javascript">'; |
| 91 | + // TODO: allow user defined graph id |
| 92 | + $output .= 'function drawGraph() {'; |
| 93 | + $output .= 'var data = ' . $data . ';'; |
| 94 | + foreach ( $this->argumentArray["preprocessors"] as $preprocessor ) { |
| 95 | + $output .= 'data = plotter_' . $preprocessor . '_process( data, '; |
| 96 | + foreach ( $this->argumentArray["preprocessorarguments"] as $argument ) { |
| 97 | + $output .= $argument . ', '; |
| 98 | + } |
| 99 | + // Strip the last ', ' |
| 100 | + $output = substr( $output, 0, -2 ); |
| 101 | + $output .= " );"; |
| 102 | + } |
| 103 | + |
| 104 | + // Run script |
| 105 | + $output .= 'plotter_' . $this->argumentArray["script"] . '_draw( data, '; |
| 106 | + foreach ( $this->argumentArray["scriptarguments"] as $argument ) { |
| 107 | + $output .= $argument . ', '; |
| 108 | + } |
| 109 | + $output = substr( $output, 0, -2 ); |
| 110 | + $output .= " );"; |
| 111 | + |
| 112 | + $output .= "}"; |
| 113 | + |
| 114 | + // Add hook event |
| 115 | + // TODO: allow user defined graph id |
| 116 | + $output .= 'hookEvent("load", drawGraph);'; |
| 117 | + $output .= "</script>"; |
| 118 | + |
| 119 | + return $output; |
| 120 | + } |
| 121 | + |
| 122 | + static function setPlotterHeaders( &$outputPage ) { |
| 123 | + global $wgPlotterExtensionPath; |
| 124 | + |
| 125 | + $extensionpath = $wgPlotterExtensionPath; |
| 126 | + |
| 127 | + // Add mochikit (required by PlotKit) |
| 128 | + $outputPage->addScript( '<script src="' . $extensionpath . '/mochikit/MochiKit.js" type="text/javascript"></script>' ); |
| 129 | + |
| 130 | + // Add PlotKit javascript |
| 131 | + $outputPage->addScript( '<script src="' . $extensionpath . '/plotkit/Base.js" type="text/javascript"></script>' ); |
| 132 | + $outputPage->addScript( '<script src="' . $extensionpath . '/plotkit/Layout.js" type="text/javascript"></script>' ); |
| 133 | + $outputPage->addScript( '<script src="' . $extensionpath . '/plotkit/Canvas.js" type="text/javascript"></script>' ); |
| 134 | + $outputPage->addScript( '<script src="' . $extensionpath . '/plotkit/SweetCanvas.js" type="text/javascript"></script>' ); |
| 135 | + |
| 136 | + return true; |
| 137 | + } |
| 138 | + |
| 139 | + static function debug( $debugText, $debugArr = null ) { |
| 140 | + global $wgPlotterDebug; |
| 141 | + |
| 142 | + if ( isset( $debugArr ) ) { |
| 143 | + if ( $wgPlotterDebug > 0 ) { |
| 144 | + $text = $debugText . " " . implode( "::", $debugArr ); |
| 145 | + wfDebugLog( 'plot', $text, false ); |
| 146 | + } |
| 147 | + } else { |
| 148 | + if ( $wgPlotterDebug > 0 ) { |
| 149 | + wfDebugLog( 'plot', $debugText, false ); |
| 150 | + } |
| 151 | + } |
| 152 | + } |
| 153 | +} |
Property changes on: trunk/extensions/Plotters/PlottersClass.php |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 154 | + native |
Index: trunk/extensions/Plotters/Plotters.alias.php |
— | — | @@ -0,0 +1,15 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Aliases for Special:Plotters. Based on the Gadgets extension. |
| 5 | + * |
| 6 | + * @addtogroup Extensions |
| 7 | + */ |
| 8 | + |
| 9 | +$aliases = array(); |
| 10 | + |
| 11 | +/** English |
| 12 | + * @author Ryan Lane, rlane32+mwext@gmail.com |
| 13 | + */ |
| 14 | +$aliases['en'] = array( |
| 15 | + 'Plotters' => array( 'Plotters' ), |
| 16 | +); |
Property changes on: trunk/extensions/Plotters/Plotters.alias.php |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 17 | + native |
Index: trunk/extensions/Plotters/README |
— | — | @@ -0,0 +1,30 @@ |
| 2 | +This extension allows users to create client side graphs (like pie, bar, etc) |
| 3 | +from data using javascript. The javascript is created by sysops in the |
| 4 | +MediaWiki namespace. Adding new scripts works like the Gadgets extension (as |
| 5 | +this extension borrows heavily from Gadgets). |
| 6 | + |
| 7 | +Preprocessing scripts, and plotting scripts are available, and the javascript |
| 8 | +function for each should be defined as follows: |
| 9 | + |
| 10 | +/* For preprocessing scripts */ |
| 11 | +function plotter_<functionname>_process( $data, $arg1, $arg2, ... ) { |
| 12 | + ... |
| 13 | +} |
| 14 | + |
| 15 | +/* For plotting scripts */ |
| 16 | +function plotter_<functionname>_draw( $data, $arg1, $arg2, ... ) { |
| 17 | + ... |
| 18 | +} |
| 19 | + |
| 20 | +You can use these in a parser function like so: |
| 21 | + |
| 22 | +{{#plot: |
| 23 | +|script=<functionname> |
| 24 | +|scriptarguments=arg1,arg2,... |
| 25 | +|data=1,2 |
| 26 | +3,4}} |
| 27 | + |
| 28 | +Currently, only PlotKit is supported; but other javascript plotting libraries |
| 29 | +will be supported in the future. |
| 30 | + |
| 31 | +This code is very alpha quality right now; many features may not work. |
Property changes on: trunk/extensions/Plotters/README |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 32 | + native |