Index: trunk/extensions/ParserFunctions/ParserFunctions.php |
— | — | @@ -103,7 +103,64 @@ |
104 | 104 | return '';
|
105 | 105 | }
|
106 | 106 | }
|
107 | | -
|
| 107 | +
|
| 108 | + /**
|
| 109 | + * Returns the absolute path to a subpage, relative to the current article
|
| 110 | + * title. Treats titles as slash-separated paths.
|
| 111 | + *
|
| 112 | + * Following subpage link syntax instead of standard path syntax, an
|
| 113 | + * initial slash is treated as a relative path, and vice versa.
|
| 114 | + */
|
| 115 | + public function rel2abs( &$parser , $to = '' ) {
|
| 116 | +
|
| 117 | + $from = $parser->mTitle->getPrefixedText();
|
| 118 | + $to = rtrim( $to , ' /' );
|
| 119 | +
|
| 120 | + // if we have an empty path, or just one containing a dot
|
| 121 | + if( $to == '' || $to == '.' ) {
|
| 122 | + return $from;
|
| 123 | + }
|
| 124 | +
|
| 125 | + // if the path isn't relative
|
| 126 | + if ( substr( $to , 0 , 1) != '/' &&
|
| 127 | + substr( $to , 0 , 2) != './' &&
|
| 128 | + substr( $to , 0 , 3) != '../' &&
|
| 129 | + $to != '..' )
|
| 130 | + {
|
| 131 | + return $to;
|
| 132 | + }
|
| 133 | + // Make a long path, containing both, enclose it in /.../
|
| 134 | + $fullPath = '/' . $from . '/' . $to . '/';
|
| 135 | +
|
| 136 | + // remove redundant current path dots
|
| 137 | + $fullPath = preg_replace( '!/(\./)+!', '/', $fullPath );
|
| 138 | +
|
| 139 | + // remove double slashes
|
| 140 | + $fullPath = preg_replace( '!/{2,}!', '/', $fullPath );
|
| 141 | +
|
| 142 | + // remove the enclosing slashes now
|
| 143 | + $fullPath = trim( $fullPath , '/' );
|
| 144 | + $exploded = explode ( '/' , $fullPath );
|
| 145 | + $newExploded = array();
|
| 146 | +
|
| 147 | + foreach ( $exploded as $current ) {
|
| 148 | + if( $current == '..' ) { // removing one level
|
| 149 | + if( !count( $newExploded ) ){
|
| 150 | + // attempted to access a node above root node
|
| 151 | + return wfMsgForContent( 'pfunc_rel2abs_invalid_depth', $fullPath );
|
| 152 | + }
|
| 153 | + // remove last level from the stack
|
| 154 | + array_pop( $newExploded );
|
| 155 | + } else {
|
| 156 | + // add the current level to the stack
|
| 157 | + $newExploded[] = $current;
|
| 158 | + }
|
| 159 | + }
|
| 160 | +
|
| 161 | + // we can now join it again
|
| 162 | + return implode( '/' , $newExploded );
|
| 163 | + }
|
| 164 | +
|
108 | 165 | function ifexist( &$parser, $title = '', $then = '', $else = '' ) {
|
109 | 166 | $title = Title::newFromText( $title );
|
110 | 167 | return is_object( $title ) && $title->exists() ? $then : $else;
|
— | — | @@ -157,9 +214,11 @@ |
158 | 215 | $wgParser->setFunctionHook( 'switch', array( &$wgExtParserFunctions, 'switchHook' ) );
|
159 | 216 | $wgParser->setFunctionHook( 'ifexist', array( &$wgExtParserFunctions, 'ifexist' ) );
|
160 | 217 | $wgParser->setFunctionHook( 'time', array( &$wgExtParserFunctions, 'time' ) );
|
| 218 | + $wgParser->setFunctionHook( 'rel2abs', array( &$wgExtParserFunctions, 'rel2abs' ) );
|
161 | 219 |
|
162 | 220 | $wgMessageCache->addMessage( 'pfunc_time_error', "Error: invalid time" );
|
163 | 221 | $wgMessageCache->addMessage( 'pfunc_time_too_long', "Error: too many #time calls" );
|
| 222 | + $wgMessageCache->addMessage( 'pfunc_rel2abs_invalid_depth', "Error: Invalid depth in path: \"$1\" (tried to access a node above the root node)" );
|
164 | 223 |
|
165 | 224 | $wgHooks['ParserClearState'][] = array( &$wgExtParserFunctions, 'clearState' );
|
166 | 225 | }
|
— | — | @@ -185,6 +244,7 @@ |
186 | 245 | $magicWords['default'] = array( 0, '#default' );
|
187 | 246 | $magicWords['ifexist'] = array( 0, 'ifexist' );
|
188 | 247 | $magicWords['time'] = array( 0, 'time' );
|
| 248 | + $magicWords['rel2abs'] = array( 0, 'rel2abs' );
|
189 | 249 | }
|
190 | 250 | return true;
|
191 | 251 | }
|