Index: trunk/extensions/ParserFun/PFun_Caller.php |
— | — | @@ -0,0 +1,267 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Class for the 'CALLER' variable-style parser function. |
| 6 | + * |
| 7 | + * @since 0.2 |
| 8 | + * |
| 9 | + * @file PFun_Caller.php |
| 10 | + * @ingroup ParserFun |
| 11 | + * |
| 12 | + * @author Daniel Werner |
| 13 | + */ |
| 14 | +class ParserFunCaller extends ParserHook { |
| 15 | + |
| 16 | + public function __construct() { |
| 17 | + // make this a parser function extension (no tag extension) only: |
| 18 | + parent::__construct( false, true, ParserHook::FH_NO_HASH ); |
| 19 | + } |
| 20 | + |
| 21 | + /** |
| 22 | + * No LSB in pre-5.3 PHP, to be refactored later |
| 23 | + */ |
| 24 | + public static function staticMagic( array &$magicWords, $langCode ) { |
| 25 | + $instance = new self; |
| 26 | + return $instance->magic( $magicWords, $langCode ); |
| 27 | + } |
| 28 | + |
| 29 | + /** |
| 30 | + * No LSB in pre-5.3 PHP, to be refactored later |
| 31 | + */ |
| 32 | + public static function staticInit( Parser &$parser ) { |
| 33 | + global $egParserFunEnabledFunctions; |
| 34 | + if( in_array( ExtParserFun::MAG_CALLER, $egParserFunEnabledFunctions ) ) { |
| 35 | + // only register function if not disabled by configuration |
| 36 | + $instance = new self; |
| 37 | + $instance->init( $parser ); |
| 38 | + } |
| 39 | + return true; |
| 40 | + } |
| 41 | + |
| 42 | + /** |
| 43 | + * Gets the name of the parser hook. |
| 44 | + * @see ParserHook::getName |
| 45 | + * |
| 46 | + * @return string |
| 47 | + */ |
| 48 | + protected function getName() { |
| 49 | + return 'CALLER'; |
| 50 | + } |
| 51 | + |
| 52 | + /** |
| 53 | + * Returns an array containing the parameter info. |
| 54 | + * @see ParserHook::getParameterInfo |
| 55 | + * |
| 56 | + * @return array |
| 57 | + */ |
| 58 | + protected function getParameterInfo( $type ) { |
| 59 | + $params = array(); |
| 60 | + |
| 61 | + # what to get, index (any number) or certain mode (count, list) |
| 62 | + # since 0.2 |
| 63 | + $params['mode'] = new Parameter( 'mode', Parameter::TYPE_STRING ); |
| 64 | + $params['mode']->addAliases( 'index' ); |
| 65 | + |
| 66 | + # where in the stack to start returning. |
| 67 | + # negative value will return that many elements from the top-level caller |
| 68 | + # since 0.2 |
| 69 | + $params['offset'] = new Parameter( 'offset', Parameter::TYPE_INTEGER ); |
| 70 | + $params['offset']->setDefault( false, false ); |
| 71 | + |
| 72 | + # max return, if negative stop that many elements from end |
| 73 | + # since 0.2 |
| 74 | + $params['limit'] = new Parameter( 'limit', Parameter::TYPE_INTEGER ); |
| 75 | + $params['limit']->setDefault( false, false ); |
| 76 | + $params['limit']->addAliases( 'len', 'length' ); |
| 77 | + |
| 78 | + # whether to link the page names |
| 79 | + # since 0.2 |
| 80 | + $params['linked'] = new Parameter( 'linked', Parameter::TYPE_BOOLEAN ); |
| 81 | + $params['linked']->setDefault( false ); |
| 82 | + |
| 83 | + # separator between list items |
| 84 | + # since 0.2 |
| 85 | + $params['sep'] = new Parameter( 'sep', Parameter::TYPE_STRING ); |
| 86 | + $params['sep']->setDefault( ', ', false ); |
| 87 | + |
| 88 | + return $params; |
| 89 | + } |
| 90 | + |
| 91 | + /** |
| 92 | + * Returns the list of default parameters. |
| 93 | + * @see ParserHook::getDefaultParameters |
| 94 | + * |
| 95 | + * @return array |
| 96 | + */ |
| 97 | + protected function getDefaultParameters( $type ) { |
| 98 | + return array( |
| 99 | + array( 'mode' ), |
| 100 | + ); |
| 101 | + } |
| 102 | + |
| 103 | + /** |
| 104 | + * Renders and returns the output. |
| 105 | + * @see ParserHook::renderTag |
| 106 | + * |
| 107 | + * @param array $parameters |
| 108 | + * |
| 109 | + * @return string |
| 110 | + */ |
| 111 | + public function render( array $parameters ) { |
| 112 | + |
| 113 | + $mode = $parameters['mode']; |
| 114 | + $linked = $parameters['linked']; |
| 115 | + $limit = $parameters['limit']; |
| 116 | + $offset = $parameters['offset']; |
| 117 | + |
| 118 | + if( is_numeric( $mode ) ) { |
| 119 | + // get specific caller |
| 120 | + /* |
| 121 | + * do not just set $offset to $mode, $mode to 'list' and $limit to 1 here since handling |
| 122 | + * for negative offset is different in 'list' mode. Here non-existant negative index will |
| 123 | + * return '', in 'list' mode it will jump to the 0 element. |
| 124 | + */ |
| 125 | + $index = (int)$mode; |
| 126 | + $frame = self::getFrameStackItem( $this->frame, $index ); |
| 127 | + |
| 128 | + if( $frame === null ) { |
| 129 | + return ''; |
| 130 | + } |
| 131 | + return self::createSiteList( |
| 132 | + array( $frame ), |
| 133 | + $linked |
| 134 | + ); |
| 135 | + } |
| 136 | + |
| 137 | + $mode = strtolower( $mode ); |
| 138 | + switch( $mode ) { |
| 139 | + case 'level': |
| 140 | + // synnonym for 'count' |
| 141 | + $mode = 'count'; |
| 142 | + case 'count': |
| 143 | + case '': |
| 144 | + /* |
| 145 | + * '{{CALLER:}}', perhaps with additional parameters, but not in list mode except limit |
| 146 | + * is set. Otherwise tread it similar to '{{CALLER}}' variable but with parameters. |
| 147 | + */ |
| 148 | + if( $mode !== 'count' && $limit === false ) { |
| 149 | + $limit = 1; |
| 150 | + } |
| 151 | + if( $offset === false ) { |
| 152 | + // '{{CALLER}}' equals '{{CALLER:1}}', not 0, in count mode ignore current page. |
| 153 | + $offset = 1; |
| 154 | + } |
| 155 | + // no-break, evaluate parameters in 'list' mode but count only |
| 156 | + case 'list': |
| 157 | + $stack = self::getFrameStack( $this->frame ); |
| 158 | + $offset = ( $offset === false ) ? 0 : $offset; |
| 159 | + $limit = ( $limit === false ) ? null : $limit; // Validator can't have null as default... |
| 160 | + |
| 161 | + $stack = array_slice( $stack, $offset, $limit ); |
| 162 | + |
| 163 | + if( $mode === 'count' ) { |
| 164 | + // in 'count' mode, return the level |
| 165 | + return count( $stack ); |
| 166 | + } else { |
| 167 | + // normal list mode |
| 168 | + return self::createSiteList( |
| 169 | + $stack, |
| 170 | + $linked, |
| 171 | + $parameters['sep'] |
| 172 | + ); |
| 173 | + } |
| 174 | + } |
| 175 | + |
| 176 | + /* |
| 177 | + * No valid operation mode or index given to first parameter! |
| 178 | + * Return error message |
| 179 | + */ |
| 180 | + $error = new ValidationError( wfMsgForContent( 'parserfun-invalid-caller-mode' ) ); |
| 181 | + return $this->renderFatalError( $error ); |
| 182 | + } |
| 183 | + |
| 184 | + /** |
| 185 | + * Returns a certain parent caller from a given frame by index. 0 returns the given frame, 1 would return |
| 186 | + * the frame of the site which was calling the given frame and so on. |
| 187 | + * |
| 188 | + * @param PPFrame $frame |
| 189 | + * @param int $index can be negative to return the element from the top-level caller. -1 would return |
| 190 | + * the same as {{FULLPAGENAME}} would be. If the index doesn't exist, null will be returned. |
| 191 | + * |
| 192 | + * @return PPFrame|null |
| 193 | + */ |
| 194 | + static function getFrameStackItem( PPFrame $frame, $index ) { |
| 195 | + // get the whole stack or just till some certain index |
| 196 | + $stack = self::getFrameStack( $frame, $index ); |
| 197 | + |
| 198 | + if( $index >= 0 ) { |
| 199 | + if( array_key_exists( $index, $stack ) ) { |
| 200 | + return $stack[ $index ]; |
| 201 | + } |
| 202 | + } else { |
| 203 | + // negative index, return from top-level |
| 204 | + $index = count( $stack ) + $index; |
| 205 | + if( $index >= 0 ) { |
| 206 | + return $stack[ $index ]; |
| 207 | + } |
| 208 | + } |
| 209 | + |
| 210 | + // index doesn't exist! |
| 211 | + return null; |
| 212 | + } |
| 213 | + |
| 214 | + /** |
| 215 | + * Gets all parent frames from a frame and returns them as array with the given frame as first element. |
| 216 | + * |
| 217 | + * @param PPFrame $frame |
| 218 | + * @param int $limit how many parent frames should be returned as maximum (in addition to given frame). |
| 219 | + * Limit below 0 means no limit. 0 will just return an array with the given frame. |
| 220 | + * |
| 221 | + * @return PPFrame[] |
| 222 | + */ |
| 223 | + static function getFrameStack( PPFrame $frame, $limit = -1 ) { |
| 224 | + $frames = array(); |
| 225 | + if( $limit >= 0 ) { |
| 226 | + $limit++; // given $frame doesn't count so this will be returned if 0 is given |
| 227 | + } |
| 228 | + |
| 229 | + while( $frame !== null && $limit !== 0 ) { |
| 230 | + $frames[] = $frame; |
| 231 | + $limit--; |
| 232 | + |
| 233 | + if( $frame instanceof PPTemplateFrame_DOM ) { |
| 234 | + $frame = $frame->parent; |
| 235 | + } else { |
| 236 | + // frame is no template, so this is the top-level frame (page being rendered) |
| 237 | + $frame = null; |
| 238 | + } |
| 239 | + }; |
| 240 | + |
| 241 | + return $frames; |
| 242 | + } |
| 243 | + |
| 244 | + /** |
| 245 | + * Create a list with page titles from a given array of frames, optionally linked output. |
| 246 | + * The output ist un-parsed wiki markup, no HTML. |
| 247 | + * |
| 248 | + * @param array $frames the titles represented as frames |
| 249 | + * @param bool $link whether or not to link the pages in the list |
| 250 | + * @param string $sep glue between the pages |
| 251 | + * |
| 252 | + * @return string |
| 253 | + */ |
| 254 | + protected static function createSiteList( $frames, $link = false, $sep = ', ' ) { |
| 255 | + $out = array(); |
| 256 | + foreach( $frames as $frame ) { |
| 257 | + $text = $frame->title->getPrefixedText(); |
| 258 | + if( $link ) { |
| 259 | + $out[] = "[[:{$text}]]"; |
| 260 | + } else { |
| 261 | + $text = wfEscapeWikiText( $text ); |
| 262 | + $out[] = $text; |
| 263 | + } |
| 264 | + } |
| 265 | + return implode( $sep, $out ); |
| 266 | + } |
| 267 | + |
| 268 | +} |
Property changes on: trunk/extensions/ParserFun/PFun_Caller.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 269 | + native |
Index: trunk/extensions/ParserFun/RELEASE-NOTES |
— | — | @@ -1,6 +1,19 @@ |
2 | 2 | 'Parser Fun' Changelog: |
3 | 3 | ======================= |
4 | 4 | |
| 5 | + * (trunk) -- Version 0.2 alpha |
| 6 | + - New parser function/variable 'CALLER' to return a templates caller. Comes with the following parameters: |
| 7 | + + <1>/mode - can be the level of the call stack to return (if negative the value will be returned from the |
| 8 | + bottom. Instead of a numer a mode can be given: 'count' will return the current callstack level, |
| 9 | + 'list' will return a list of all sites in the stack. |
| 10 | + + linked - boolean whether page(s) should be returned linked. |
| 11 | + + sep - separator between pages in 'list' mode. ', ' by default. |
| 12 | + + offset - first stack item to return in 'list' mode. If negative, the list starts that far from the stacks top. |
| 13 | + + limit - how many items to return in 'list' mode. If negative the list will end that far from the stacks top. |
| 14 | + All parameters with specific meaning in 'list' mode have the same effect for the 'count' mode. In 'count' mode the |
| 15 | + offset is set to 1 by default, in 'list' mode to 0. |
| 16 | + |
| 17 | + |
5 | 18 | * December 2, 2011 -- Version 0.1 (initial release) |
6 | 19 | - Magic word prefix 'THIS:', which is working with basically all functions returning page related information: |
7 | 20 | 'FULLPAGENAME', 'PAGENAME', 'BASEPAGENAME', 'SUBPAGENAME', 'SUBJECTPAGENAME', 'TALKPAGENAME', 'NAMESPACE', |
Index: trunk/extensions/ParserFun/PFun_Parse.php |
— | — | @@ -105,7 +105,7 @@ |
106 | 106 | } |
107 | 107 | |
108 | 108 | /** |
109 | | - * Returns the parser function otpions. |
| 109 | + * Returns the parser function options. |
110 | 110 | * @see ParserHook::getFunctionOptions |
111 | 111 | * |
112 | 112 | * @return array |
— | — | @@ -126,9 +126,6 @@ |
127 | 127 | * @return string |
128 | 128 | */ |
129 | 129 | public function render( array $parameters ) { |
130 | | - |
131 | | - |
132 | | - |
133 | 130 | $text = $parameters['text']; |
134 | 131 | |
135 | 132 | // current parsers StripState object |
Index: trunk/extensions/ParserFun/ParserFun.i18n.magic.php |
— | — | @@ -19,6 +19,7 @@ |
20 | 20 | $magicWords['en'] = array( |
21 | 21 | 'parse' => array( 0, 'parse' ), |
22 | 22 | ExtParserFun::MAG_THIS => array( 1, 'THIS' ), |
| 23 | + ExtParserFun::MAG_CALLER => array( 1, 'CALLER' ), |
23 | 24 | ); |
24 | 25 | |
25 | 26 | /** Message documentation (Message documentation) |
— | — | @@ -27,6 +28,7 @@ |
28 | 29 | $messages['qqq'] = array( |
29 | 30 | 'parse' => array( 0, 'Do not translate this! This is the magic word for the "#parse" function' ), |
30 | 31 | ExtParserFun::MAG_THIS => array( 1, 'Keyword to put in front of a variable like "{{THIS:PAGENAME}}". This will output the pagename of the page where it is defined on instead of the page actually being parsed. "THIS" refers to that page.' ), |
| 32 | + ExtParserFun::MAG_CALLER => array( 1, 'Variable/Parser function returning an templates direct initiator or with options even all or just specific initiators.' ), |
31 | 33 | ); |
32 | 34 | |
33 | 35 | /** German (Deutsch) |
Index: trunk/extensions/ParserFun/ParserFun.i18n.php |
— | — | @@ -17,6 +17,7 @@ |
18 | 18 | */ |
19 | 19 | $messages['en'] = array( |
20 | 20 | 'parserfun-desc' => "Adds a parser function <code>#parse</code> for parsing wikitext and introduces <code>THIS:</code> prefix for page information related magic variables", |
| 21 | + 'parserfun-invalid-caller-mode' => 'No valid operation mode or numeric index given.', |
21 | 22 | ); |
22 | 23 | |
23 | 24 | /** Message documentation (Message documentation) |
Index: trunk/extensions/ParserFun/ParserFun.php |
— | — | @@ -8,7 +8,7 @@ |
9 | 9 | * Support: http://www.mediawiki.org/wiki/Extension_talk:Parser_Fun |
10 | 10 | * Source code: http://svn.wikimedia.org/viewvc/mediawiki/trunk/extensions/ParserFun |
11 | 11 | * |
12 | | - * @version: 0.1 |
| 12 | + * @version: 0.2 alpha |
13 | 13 | * @license: ISC license |
14 | 14 | * @author: Daniel Werner < danweetz@web.de > |
15 | 15 | * |
— | — | @@ -59,19 +59,22 @@ |
60 | 60 | $wgHooks['ParserGetVariableValueSwitch'][] = 'ExtParserFun::onParserGetVariableValueSwitch'; |
61 | 61 | |
62 | 62 | |
63 | | -// 'parse' parser function initialization: |
64 | | -$wgAutoloadClasses['ParserFunParse'] = ExtParserFun::getDir() . '/PFun_Parse.php'; |
| 63 | +// 'parse' and 'CALLER' parser function initializations: |
| 64 | +$wgAutoloadClasses['ParserFunParse' ] = ExtParserFun::getDir() . '/PFun_Parse.php'; |
| 65 | +$wgAutoloadClasses['ParserFunCaller'] = ExtParserFun::getDir() . '/PFun_Caller.php'; |
65 | 66 | |
66 | 67 | $wgHooks['ParserFirstCallInit'][] = 'ParserFunParse::staticInit'; |
67 | 68 | $wgHooks['LanguageGetMagic' ][] = 'ParserFunParse::staticMagic'; |
68 | 69 | |
| 70 | +$wgHooks['ParserFirstCallInit'][] = 'ParserFunCaller::staticInit'; |
| 71 | +$wgHooks['LanguageGetMagic' ][] = 'ParserFunCaller::staticMagic'; |
69 | 72 | |
| 73 | + |
70 | 74 | /** |
71 | 75 | * Extension class of the 'Parser Fun' extension. |
72 | 76 | * Handling the functionality around the 'THIS' magic word feature. |
73 | 77 | */ |
74 | 78 | class ExtParserFun { |
75 | | - |
76 | 79 | /** |
77 | 80 | * Version of the 'Parser Fun' extension. |
78 | 81 | * |
— | — | @@ -79,9 +82,10 @@ |
80 | 83 | * |
81 | 84 | * @var string |
82 | 85 | */ |
83 | | - const VERSION = '0.1'; |
| 86 | + const VERSION = '0.2 alpha'; |
84 | 87 | |
85 | 88 | const MAG_THIS = 'this'; |
| 89 | + const MAG_CALLER = 'caller'; |
86 | 90 | |
87 | 91 | public static function init( Parser &$parser ) { |
88 | 92 | global $egParserFunEnabledFunctions; |
— | — | @@ -158,6 +162,7 @@ |
159 | 163 | * |
160 | 164 | * @param Parser $parser |
161 | 165 | * @param type $word |
| 166 | + * |
162 | 167 | * @return string|null |
163 | 168 | */ |
164 | 169 | static function getVariablesMagicWordId( Parser $parser, $word ) { |
— | — | @@ -184,7 +189,7 @@ |
185 | 190 | /** |
186 | 191 | * Returns the value of a variable like '{{FULLPAGENAME}}' in the context of the given PPFrame objects |
187 | 192 | * $frame->$title instead of the Parser objects subject. Returns null in case the requested variable |
188 | | - * doesn't support {{THIS:}}. |
| 193 | + * does not support '{{THIS:}}'. |
189 | 194 | * |
190 | 195 | * @param string $mwId magic word ID of the variable |
191 | 196 | * @param Parser $parser |
— | — | @@ -203,6 +208,14 @@ |
204 | 209 | |
205 | 210 | // check whether info is available, e.g. 'THIS:FULLPAGENAME' requires 'FULLPAGENAME' |
206 | 211 | switch( $mwId ) { |
| 212 | + case 'namespace': |
| 213 | + // 'namespace' function name was renamed as PHP 5.3 came along |
| 214 | + if( is_callable( 'CoreParserFunctions::mwnamespace' ) ) { |
| 215 | + $ret = CoreParserFunctions::mwnamespace( $parser, $title->getPrefixedText() ); |
| 216 | + break; |
| 217 | + } |
| 218 | + // else: no different from the other variables |
| 219 | + // no-break, default function call |
207 | 220 | case 'fullpagename': |
208 | 221 | case 'fullpagenamee': |
209 | 222 | case 'pagename': |
— | — | @@ -215,24 +228,15 @@ |
216 | 229 | case 'subjectpagenamee': |
217 | 230 | case 'talkpagename': |
218 | 231 | case 'talkpagenamee': |
219 | | - case 'namespacee': // for 'namespace', see bottom |
| 232 | + case 'namespacee': // special treat for 'namespace', on top |
220 | 233 | case 'subjectspace': |
221 | 234 | case 'subjectspacee': |
222 | 235 | case 'talkspace': |
223 | 236 | case 'talkspacee': |
224 | | - // core parser function information requested |
| 237 | + // core parser function information requested |
225 | 238 | $ret = CoreParserFunctions::$mwId( $parser, $title->getPrefixedText() ); |
226 | 239 | break; |
227 | 240 | |
228 | | - case 'namespace': |
229 | | - // 'namespace' function name was renamed as PHP 5.3 came along |
230 | | - if( is_callable( 'CoreParserFunctions::mwnamespace' ) ) { |
231 | | - $ret = CoreParserFunctions::mwnamespace( $parser, $title->getPrefixedText() ); |
232 | | - } else { |
233 | | - $ret = CoreParserFunctions::$mwId( $parser, $title->getPrefixedText() ); |
234 | | - } |
235 | | - break; |
236 | | - |
237 | 241 | default: |
238 | 242 | // give other extensions a chance to hook up with this and return their own values: |
239 | 243 | wfRunHooks( 'GetThisVariableValueSwitch', array( &$parser, $title, &$mwId, &$ret, $frame, $args ) ); |
— | — | @@ -240,22 +244,41 @@ |
241 | 245 | return $ret; |
242 | 246 | } |
243 | 247 | |
| 248 | + |
| 249 | + ################## |
| 250 | + # Hooks Handling # |
| 251 | + ################## |
| 252 | + |
244 | 253 | static function onParserGetVariableValueSwitch( Parser &$parser, &$cache, &$magicWordId, &$ret, $frame = null ) { |
| 254 | + if( $frame === null ) { |
| 255 | + // unsupported MW version |
| 256 | + return true; |
| 257 | + } |
245 | 258 | switch( $magicWordId ) { |
246 | 259 | /** THIS **/ |
247 | 260 | case self::MAG_THIS: |
248 | 261 | $ret = self::pfObj_this( $parser, $frame, null ); |
249 | 262 | break; |
| 263 | + |
| 264 | + /** CALLER **/ |
| 265 | + case self::MAG_CALLER: |
| 266 | + $siteFrame = ParserFunCaller::getFrameStackItem( $frame, 1 ); |
| 267 | + $ret = ( $siteFrame !== null ) ? $siteFrame->title->getPrefixedText() : ''; |
| 268 | + break; |
250 | 269 | } |
251 | 270 | return true; |
252 | 271 | } |
253 | 272 | |
254 | 273 | static function onMagicWordwgVariableIDs( &$variableIds ) { |
255 | 274 | global $egParserFunEnabledFunctions; |
| 275 | + // only register variables if not disabled by configuration |
| 276 | + |
256 | 277 | if( in_array( self::MAG_THIS, $egParserFunEnabledFunctions ) ) { |
257 | | - // only register variable if not disabled by configuration |
258 | 278 | $variableIds[] = self::MAG_THIS; |
259 | 279 | } |
| 280 | + if( in_array( self::MAG_CALLER, $egParserFunEnabledFunctions ) ) { |
| 281 | + $variableIds[] = self::MAG_CALLER; |
| 282 | + } |
260 | 283 | return true; |
261 | 284 | } |
262 | 285 | |
Index: trunk/extensions/ParserFun/ParserFun_Settings.php |
— | — | @@ -29,4 +29,4 @@ |
30 | 30 | * @since 0.1 |
31 | 31 | * @var array |
32 | 32 | */ |
33 | | -$egParserFunEnabledFunctions = array( 'this', 'parse' ); |
| 33 | +$egParserFunEnabledFunctions = array( 'this', 'parse', 'caller' ); |