Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/LocalSettings.php |
— | — | @@ -11,4 +11,4 @@ |
12 | 12 | * $wgMwEmbedModuleConfig[ {configuration name} ] = value; |
13 | 13 | */ |
14 | 14 | |
15 | | -//$wgResourceLoaderDebug = true; |
\ No newline at end of file |
| 15 | +$wgResourceLoaderDebug = false; |
\ No newline at end of file |
Property changes on: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/cache |
___________________________________________________________________ |
Added: svn:ignore |
16 | 16 | + a |
9 |
4 |
2 |
5 |
f |
d |
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/includes/MwEmbedAutoLoader.php |
— | — | @@ -23,7 +23,7 @@ |
24 | 24 | |
25 | 25 | 'CSSJanus' => 'includes/libs/CSSJanus.php', |
26 | 26 | 'CSSMin' => 'includes/libs/CSSMin.php', |
27 | | - 'JSMin' => 'includes/libs/JSMin.php', |
| 27 | + 'JavaScriptDistiller' => 'includes/libs/JavaScriptDistiller.php', |
28 | 28 | |
29 | 29 | # MwEmbed files ( that get autoloaded ): |
30 | 30 | 'MwEmbedResourceLoaderContext' => 'includes/MwEmbedResourceLoaderContext.php', |
— | — | @@ -31,8 +31,7 @@ |
32 | 32 | 'MwEmbedResourceLoader' => 'includes/MwEmbedResourceLoader.php', |
33 | 33 | 'MwEmbedResourceLoaderFileModule' => 'includes/MwEmbedResourceLoaderFileModule.php', |
34 | 34 | 'MwEmbedResourceLoaderStartUpModule' => 'includes/MwEmbedResourceLoaderStartUpModule.php', |
35 | | - 'MwEmbedResourceManager' => 'includes/MwEmbedResourceManager.php', |
36 | | - |
| 35 | + 'MwEmbedResourceManager' => 'includes/MwEmbedResourceManager.php', |
37 | 36 | ); |
38 | 37 | |
39 | 38 | class AutoLoader { |
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/includes/MwEmbedResourceManager.php |
— | — | @@ -102,7 +102,7 @@ |
103 | 103 | // Add the mwEmbed module to the page: |
104 | 104 | public static function addMwEmbedModule( &$out, &$sk ){ |
105 | 105 | // Add the mwEmbed module to the output |
106 | | - $out->addModules( 'mwEmbed' ); |
| 106 | + $out->addModules( 'MwEmbedSupport' ); |
107 | 107 | return true; |
108 | 108 | } |
109 | 109 | } |
\ No newline at end of file |
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/includes/libs/JSMin.php |
— | — | @@ -1,283 +0,0 @@ |
2 | | -<?php |
3 | | -/** |
4 | | - * jsmin.php - PHP implementation of Douglas Crockford's JSMin. |
5 | | - * |
6 | | - * This is pretty much a direct port of jsmin.c to PHP with just a few |
7 | | - * PHP-specific performance tweaks. Also, whereas jsmin.c reads from stdin and |
8 | | - * outputs to stdout, this library accepts a string as input and returns another |
9 | | - * string as output. |
10 | | - * |
11 | | - * PHP 5 or higher is required. |
12 | | - * |
13 | | - * Permission is hereby granted to use this version of the library under the |
14 | | - * same terms as jsmin.c, which has the following license: |
15 | | - * |
16 | | - * -- |
17 | | - * Copyright (c) 2002 Douglas Crockford (www.crockford.com) |
18 | | - * |
19 | | - * Permission is hereby granted, free of charge, to any person obtaining a copy of |
20 | | - * this software and associated documentation files (the "Software"), to deal in |
21 | | - * the Software without restriction, including without limitation the rights to |
22 | | - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies |
23 | | - * of the Software, and to permit persons to whom the Software is furnished to do |
24 | | - * so, subject to the following conditions: |
25 | | - * |
26 | | - * The above copyright notice and this permission notice shall be included in all |
27 | | - * copies or substantial portions of the Software. |
28 | | - * |
29 | | - * The Software shall be used for Good, not Evil. |
30 | | - * |
31 | | - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
32 | | - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
33 | | - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
34 | | - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
35 | | - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
36 | | - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
37 | | - * SOFTWARE. |
38 | | - * -- |
39 | | - * |
40 | | - * @file |
41 | | - * @author Ryan Grove <ryan@wonko.com> |
42 | | - * @copyright 2002 Douglas Crockford <douglas@crockford.com> (jsmin.c) |
43 | | - * @copyright 2008 Ryan Grove <ryan@wonko.com> (PHP port) |
44 | | - * @license http://opensource.org/licenses/mit-license.php MIT License |
45 | | - * @version 1.1.1 (2008-03-02) |
46 | | - * @link http://github.com/rgrove/jsmin-php/ |
47 | | - */ |
48 | | - |
49 | | -class JSMin { |
50 | | - const ORD_LF = 10; |
51 | | - const ORD_SPACE = 32; |
52 | | - |
53 | | - // Action constants |
54 | | - const OUTPUT = 1; |
55 | | - const DELETE_A = 2; |
56 | | - const DELETE_B = 3; |
57 | | - |
58 | | - /** Current character */ |
59 | | - protected $a = ''; |
60 | | - |
61 | | - /** Next character */ |
62 | | - protected $b = ''; |
63 | | - |
64 | | - protected $input = ''; |
65 | | - protected $inputIndex = 0; |
66 | | - protected $inputLength = 0; |
67 | | - protected $lookAhead = null; |
68 | | - protected $output = ''; |
69 | | - |
70 | | - // -- Public Static Methods -------------------------------------------------- |
71 | | - |
72 | | - public static function minify( $js ) { |
73 | | - $jsmin = new self( $js ); |
74 | | - $ret = $jsmin->min(); |
75 | | - return $ret; |
76 | | - } |
77 | | - |
78 | | - // -- Public Instance Methods ------------------------------------------------ |
79 | | - |
80 | | - public function __construct( $input ) { |
81 | | - // Fix line endings |
82 | | - $this->input = str_replace( "\r\n", "\n", $input ); |
83 | | - // Replace tabs and other control characters (except LF) with spaces |
84 | | - $this->input = preg_replace( '/[\x00-\x09\x0b-\x1f]/', ' ', $this->input ); |
85 | | - $this->inputLength = strlen( $this->input ); |
86 | | - } |
87 | | - |
88 | | - // -- Protected Instance Methods --------------------------------------------- |
89 | | - |
90 | | - /** |
91 | | - * Do something! What you do is determined by the argument: |
92 | | - * - self::OUTPUT Output A. Copy B to A. Get the next B. |
93 | | - * - self::DELETE_A Copy B to A. Get the next B. (Delete A). |
94 | | - * - self::DELETE_B Get the next B. (Delete B). |
95 | | - * action treats a string as a single character. Wow! |
96 | | - * action recognizes a regular expression if it is preceded by ( or , or =. |
97 | | - */ |
98 | | - protected function action( $d ) { |
99 | | - switch( $d ) { |
100 | | - case self::OUTPUT: |
101 | | - $this->output .= $this->a; |
102 | | - |
103 | | - case self::DELETE_A: |
104 | | - $this->a = $this->b; |
105 | | - |
106 | | - if ( $this->a === "'" || $this->a === '"' ) { |
107 | | - $interestingChars = $this->a . "\\\n"; |
108 | | - $this->output .= $this->a; |
109 | | - for ( ; ; ) { |
110 | | - $runLength = strcspn( $this->input, $interestingChars, $this->inputIndex ); |
111 | | - $this->output .= substr( $this->input, $this->inputIndex, $runLength ); |
112 | | - $this->inputIndex += $runLength; |
113 | | - $c = $this->get(); |
114 | | - |
115 | | - if ( $c === $this->b ) { |
116 | | - break; |
117 | | - } |
118 | | - |
119 | | - if ( $c === "\n" || $c === null ) { |
120 | | - throw new JSMinException( 'Unterminated string literal.' ); |
121 | | - } |
122 | | - |
123 | | - if ( $c === '\\' ) { |
124 | | - $this->output .= $c . $this->get(); |
125 | | - } |
126 | | - } |
127 | | - } |
128 | | - |
129 | | - case self::DELETE_B: |
130 | | - $this->b = $this->next(); |
131 | | - |
132 | | - if ( $this->b === '/' && ( |
133 | | - $this->a === '(' || $this->a === ',' || $this->a === '=' || |
134 | | - $this->a === ':' || $this->a === '[' || $this->a === '!' || |
135 | | - $this->a === '&' || $this->a === '|' || $this->a === '?' ) ) { |
136 | | - |
137 | | - $this->output .= $this->a . $this->b; |
138 | | - |
139 | | - for ( ; ; ) { |
140 | | - $runLength = strcspn( $this->input, "/\\\n", $this->inputIndex ); |
141 | | - $this->output .= substr( $this->input, $this->inputIndex, $runLength ); |
142 | | - $this->inputIndex += $runLength; |
143 | | - $this->a = $this->get(); |
144 | | - |
145 | | - if ( $this->a === '/' ) { |
146 | | - break; |
147 | | - } elseif ( $this->a === '\\' ) { |
148 | | - $this->output .= $this->a; |
149 | | - $this->a = $this->get(); |
150 | | - } elseif ( $this->a === "\n" || $this->a === null ) { |
151 | | - throw new JSMinException( 'Unterminated regular expression ' . |
152 | | - 'literal.' ); |
153 | | - } |
154 | | - |
155 | | - $this->output .= $this->a; |
156 | | - } |
157 | | - |
158 | | - $this->b = $this->next(); |
159 | | - } |
160 | | - } |
161 | | - } |
162 | | - |
163 | | - /** |
164 | | - * Return the next character from the input. Watch out for lookahead. If |
165 | | - * the character is a control character, translate it to a space or |
166 | | - * linefeed. |
167 | | - */ |
168 | | - protected function get() { |
169 | | - if ( $this->inputIndex < $this->inputLength ) { |
170 | | - return $this->input[$this->inputIndex++]; |
171 | | - } else { |
172 | | - return null; |
173 | | - } |
174 | | - } |
175 | | - |
176 | | - /** |
177 | | - * Return true if the character is a letter, digit, underscore, |
178 | | - * dollar sign, or non-ASCII character. |
179 | | - */ |
180 | | - protected function isAlphaNum( $c ) { |
181 | | - return ord( $c ) > 126 || $c === '\\' || preg_match( '/^[\w\$]$/', $c ) === 1; |
182 | | - } |
183 | | - |
184 | | - /** |
185 | | - * Copy the input to the output, deleting the characters which are |
186 | | - * insignificant to JavaScript. Comments will be removed. Tabs will be |
187 | | - * replaced with spaces. Carriage returns will be replaced with linefeeds. |
188 | | - * Most spaces and linefeeds will be removed. |
189 | | - */ |
190 | | - protected function min() { |
191 | | - $this->a = "\n"; |
192 | | - $this->action( self::DELETE_B ); |
193 | | - |
194 | | - while ( $this->a !== null ) { |
195 | | - switch ( $this->a ) { |
196 | | - case ' ': |
197 | | - if ( $this->isAlphaNum( $this->b ) ) { |
198 | | - $this->action( self::OUTPUT ); |
199 | | - } else { |
200 | | - $this->action( self::DELETE_A ); |
201 | | - } |
202 | | - break; |
203 | | - |
204 | | - case "\n": |
205 | | - switch ( $this->b ) { |
206 | | - case ' ': |
207 | | - $this->action( self::DELETE_B ); |
208 | | - break; |
209 | | - |
210 | | - default: |
211 | | - $this->action( self::OUTPUT ); |
212 | | - } |
213 | | - break; |
214 | | - |
215 | | - default: |
216 | | - switch ( $this->b ) { |
217 | | - case ' ': |
218 | | - if ( $this->isAlphaNum( $this->a ) ) { |
219 | | - $this->action( self::OUTPUT ); |
220 | | - break; |
221 | | - } |
222 | | - |
223 | | - $this->action( self::DELETE_B ); |
224 | | - break; |
225 | | - default: |
226 | | - $this->action( self::OUTPUT ); |
227 | | - break; |
228 | | - } |
229 | | - } |
230 | | - } |
231 | | - |
232 | | - // Remove initial line break |
233 | | - if ( $this->output[0] !== "\n" ) { |
234 | | - throw new JSMinException( 'Unexpected lack of line break.' ); |
235 | | - } |
236 | | - if ( $this->output === "\n" ) { |
237 | | - return ''; |
238 | | - } else { |
239 | | - return substr( $this->output, 1 ); |
240 | | - } |
241 | | - } |
242 | | - |
243 | | - /** |
244 | | - * Get the next character, excluding comments. |
245 | | - */ |
246 | | - protected function next() { |
247 | | - if ( $this->inputIndex >= $this->inputLength ) { |
248 | | - return null; |
249 | | - } |
250 | | - $c = $this->input[$this->inputIndex++]; |
251 | | - |
252 | | - if ( $this->inputIndex >= $this->inputLength ) { |
253 | | - return $c; |
254 | | - } |
255 | | - |
256 | | - if ( $c === '/' ) { |
257 | | - switch( $this->input[$this->inputIndex] ) { |
258 | | - case '/': |
259 | | - $this->inputIndex += strcspn( $this->input, "\n", $this->inputIndex ) + 1; |
260 | | - return "\n"; |
261 | | - case '*': |
262 | | - $endPos = strpos( $this->input, '*/', $this->inputIndex + 1 ); |
263 | | - if ( $endPos === false ) { |
264 | | - throw new JSMinException( 'Unterminated comment.' ); |
265 | | - } |
266 | | - $numLines = substr_count( $this->input, "\n", $this->inputIndex, |
267 | | - $endPos - $this->inputIndex ); |
268 | | - $this->inputIndex = $endPos + 2; |
269 | | - if ( $numLines ) { |
270 | | - return str_repeat( "\n", $numLines ); |
271 | | - } else { |
272 | | - return ' '; |
273 | | - } |
274 | | - default: |
275 | | - return $c; |
276 | | - } |
277 | | - } |
278 | | - |
279 | | - return $c; |
280 | | - } |
281 | | -} |
282 | | - |
283 | | -// -- Exceptions --------------------------------------------------------------- |
284 | | -class JSMinException extends Exception {} |
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/includes/libs/JavaScriptDistiller.php |
— | — | @@ -0,0 +1,305 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * JavaScript Distiller |
| 5 | + * |
| 6 | + * Author: Dean Edwards, Nicholas Martin, Trevor Parscal |
| 7 | + * License: LGPL |
| 8 | + */ |
| 9 | +class JavaScriptDistiller { |
| 10 | + |
| 11 | + /* Static Methods */ |
| 12 | + |
| 13 | + /** |
| 14 | + * Removes most of the white-space from JavaScript code. |
| 15 | + * |
| 16 | + * This code came from the first pass of Dean Edwards' JavaScript Packer. Compared to using |
| 17 | + * JSMin::minify, this produces < 1% larger output (after gzip) in approx. 25% of the time. |
| 18 | + * |
| 19 | + * @param $script String: JavaScript code to minify |
| 20 | + * @param $stripVerticalSpace Boolean: Try to remove as much vertical whitespace as possible |
| 21 | + */ |
| 22 | + public static function stripWhiteSpace( $script, $stripVerticalSpace = false ) { |
| 23 | + $script = self::stripHorizontalSpace( $script ); |
| 24 | + // If requested, make some vertical whitespace collapsing as well |
| 25 | + if ( $stripVerticalSpace ) { |
| 26 | + $script = self::stripVerticalSpace( $script ); |
| 27 | + } |
| 28 | + // Done |
| 29 | + return $script; |
| 30 | + } |
| 31 | + |
| 32 | + private static function stripHorizontalSpace( $script ) { |
| 33 | + $parser = self::createParser(); |
| 34 | + // Collapse horizontal whitespaces between variable names into a single space |
| 35 | + $parser->add( '/(\\b|\\$)[ \\t]+(\\b|\\$)/', '$2 $3' ); |
| 36 | + // Collapse horizontal whitespaces between unary operators into a single space |
| 37 | + $parser->add( '/([+\\-])[ \\t]+([+\\-])/', '$2 $3' ); |
| 38 | + // Remove all remaining un-protected horizontal whitespace |
| 39 | + $parser->add( '/[ \\t]+/'); |
| 40 | + // Collapse multiple vertical whitespaces with some horizontal spaces between them |
| 41 | + $parser->add( '/[\\r\\n]+[ \\t]*[\\r\\n]+/', "\n" ); |
| 42 | + // Execute and return |
| 43 | + return $parser->exec($script); |
| 44 | + } |
| 45 | + |
| 46 | + private static function stripVerticalSpace( $script ) { |
| 47 | + $parser = self::createParser(); |
| 48 | + // Collapse whitespaces between and after a ){ pair (function definitions) |
| 49 | + $parser->add( '/\\)\\s+\\{\\s+/', '){' ); |
| 50 | + // Collapse whitespaces between and after a ({ pair (JSON argument) |
| 51 | + $parser->add( '/\\(\\s+\\{\\s+/', '({' ); |
| 52 | + // Collapse whitespaces between a parenthesis and a period (call chaining) |
| 53 | + $parser->add( '/\\)\\s+\\./', ').'); |
| 54 | + // Collapse vertical whitespaces which come directly after a semicolon or a comma |
| 55 | + $parser->add( '/([;,])\\s+/', '$2' ); |
| 56 | + // Collapse whitespaces between multiple parenthesis/brackets of similar direction |
| 57 | + $parser->add( '/([\\)\\}])\\s+([\\)\\}])/', '$2$3' ); |
| 58 | + $parser->add( '/([\\(\\{])\\s+([\\(\\{])/', '$2$3' ); |
| 59 | + return $parser->exec( $script ); |
| 60 | + } |
| 61 | + |
| 62 | + /* |
| 63 | + * Creates an instance of ParseMaster and protects sensitive JavaScript regions. |
| 64 | + * |
| 65 | + * This parser is based on regular expressions, which all get or'd together, so rules take |
| 66 | + * precedence in the order they are added. We can use it to minify by armoring certain regions |
| 67 | + * by matching them and replacing them with the full match, leaving the remaining regions around |
| 68 | + * for further matching and replacing. When creating rules please note that because ParseMaster |
| 69 | + * "or"s all of the rules together in a single pattern, encapsulating them in parenthesis, $1 |
| 70 | + * represents the whole match for a given rule, and $2 is the first submatch. |
| 71 | + */ |
| 72 | + private static function createParser() { |
| 73 | + $parser = new ParseMaster(); |
| 74 | + // There is a bug in ParseMaster that causes a backslash at the end of a line to be changed |
| 75 | + // to \s if we use a backslash as the escape character. We work around this by using an |
| 76 | + // obscure escape character that we hope will never appear at the end of a line. |
| 77 | + $parser->escapeChar = chr( 1 ); |
| 78 | + // Protect strings. The original code had [^\'\\v] here, but that didn't armor multiline |
| 79 | + // strings correctly. This also armors multiline strings that don't have backslashes at the |
| 80 | + // end of the line (these are invalid), but that's fine because we're just armoring here. |
| 81 | + $parser->add( '/\'([^\'\\\\]*(\\\\.[^\'\\\\]*)*)\'/', '$1' ); |
| 82 | + $parser->add( '/"([^"\\\\]*(\\\\.[^"\\\\]*)*)"/', '$1' ); |
| 83 | + // Protect regular expressions |
| 84 | + $parser->add( '/[ \\t]+(\\/[^\\/\\r\\n\\*][^\\/\\r\\n]*\\/g?i?)/', '$2' ); |
| 85 | + $parser->add( '/[^\\w\\$\\/\'"*)\\?:]\\/[^\\/\\r\\n\\*][^\\/\\r\\n]*\\/g?i?/', '$1' ); |
| 86 | + // Remove comments |
| 87 | + $parser->add( '/\\/\\*(.|[\\r\\n])*?\\*\\//' ); |
| 88 | + // Preserve the newline after a C++-style comment -- bug 27046 |
| 89 | + $parser->add( '/\\/\\/[^\\r\\n]*([\\r\\n])/', '$2' ); |
| 90 | + return $parser; |
| 91 | + } |
| 92 | +} |
| 93 | + |
| 94 | +/** |
| 95 | + * ParseMaster, version 1.0.2 (2005-08-19) Copyright 2005, Dean Edwards |
| 96 | + * A multi-pattern parser. |
| 97 | + * License: http://creativecommons.org/licenses/LGPL/2.1/ |
| 98 | + * |
| 99 | + * This is the PHP version of the ParseMaster component of Dean Edwards' (http://dean.edwards.name/) |
| 100 | + * Packer, which was originally written in JavaScript. It was ported to PHP by Nicolas Martin. |
| 101 | + * |
| 102 | + * Original Source: http://joliclic.free.fr/php/javascript-packer/en/ |
| 103 | + * |
| 104 | + * Changes should be pushed back upstream. |
| 105 | + */ |
| 106 | +class ParseMaster { |
| 107 | + public $ignoreCase = false; |
| 108 | + public $escapeChar = ''; |
| 109 | + |
| 110 | + // constants |
| 111 | + const EXPRESSION = 0; |
| 112 | + const REPLACEMENT = 1; |
| 113 | + const LENGTH = 2; |
| 114 | + |
| 115 | + // used to determine nesting levels |
| 116 | + private $GROUPS = '/\\(/';//g |
| 117 | + private $SUB_REPLACE = '/\\$\\d/'; |
| 118 | + private $INDEXED = '/^\\$\\d+$/'; |
| 119 | + private $TRIM = '/([\'"])\\1\\.(.*)\\.\\1\\1$/'; |
| 120 | + private $ESCAPE = '/\\\./';//g |
| 121 | + private $QUOTE = '/\'/'; |
| 122 | + private $DELETED = '/\\x01[^\\x01]*\\x01/';//g |
| 123 | + |
| 124 | + public function add($expression, $replacement = '') { |
| 125 | + // count the number of sub-expressions |
| 126 | + // - add one because each pattern is itself a sub-expression |
| 127 | + $length = 1 + preg_match_all($this->GROUPS, $this->_internalEscape((string)$expression), $out); |
| 128 | + |
| 129 | + // treat only strings $replacement |
| 130 | + if (is_string($replacement)) { |
| 131 | + // does the pattern deal with sub-expressions? |
| 132 | + if (preg_match($this->SUB_REPLACE, $replacement)) { |
| 133 | + // a simple lookup? (e.g. "$2") |
| 134 | + if (preg_match($this->INDEXED, $replacement)) { |
| 135 | + // store the index (used for fast retrieval of matched strings) |
| 136 | + $replacement = (int)(substr($replacement, 1)) - 1; |
| 137 | + } else { // a complicated lookup (e.g. "Hello $2 $1") |
| 138 | + // build a function to do the lookup |
| 139 | + $quote = preg_match($this->QUOTE, $this->_internalEscape($replacement)) |
| 140 | + ? '"' : "'"; |
| 141 | + $replacement = array( |
| 142 | + 'fn' => '_backReferences', |
| 143 | + 'data' => array( |
| 144 | + 'replacement' => $replacement, |
| 145 | + 'length' => $length, |
| 146 | + 'quote' => $quote |
| 147 | + ) |
| 148 | + ); |
| 149 | + } |
| 150 | + } |
| 151 | + } |
| 152 | + // pass the modified arguments |
| 153 | + if (!empty($expression)) $this->_add($expression, $replacement, $length); |
| 154 | + else $this->_add('/^$/', $replacement, $length); |
| 155 | + } |
| 156 | + |
| 157 | + public function exec($string) { |
| 158 | + // execute the global replacement |
| 159 | + $this->_escaped = array(); |
| 160 | + |
| 161 | + // simulate the _patterns.toSTring of Dean |
| 162 | + $regexp = '/'; |
| 163 | + foreach ($this->_patterns as $reg) { |
| 164 | + $regexp .= '(' . substr($reg[self::EXPRESSION], 1, -1) . ')|'; |
| 165 | + } |
| 166 | + $regexp = substr($regexp, 0, -1) . '/S'; |
| 167 | + $regexp .= ($this->ignoreCase) ? 'i' : ''; |
| 168 | + |
| 169 | + $string = $this->_escape($string, $this->escapeChar); |
| 170 | + $string = preg_replace_callback( |
| 171 | + $regexp, |
| 172 | + array( |
| 173 | + &$this, |
| 174 | + '_replacement' |
| 175 | + ), |
| 176 | + $string |
| 177 | + ); |
| 178 | + $string = $this->_unescape($string, $this->escapeChar); |
| 179 | + |
| 180 | + return preg_replace($this->DELETED, '', $string); |
| 181 | + } |
| 182 | + |
| 183 | + public function reset() { |
| 184 | + // clear the patterns collection so that this object may be re-used |
| 185 | + $this->_patterns = array(); |
| 186 | + } |
| 187 | + |
| 188 | + // private |
| 189 | + private $_escaped = array(); // escaped characters |
| 190 | + private $_patterns = array(); // patterns stored by index |
| 191 | + |
| 192 | + // create and add a new pattern to the patterns collection |
| 193 | + private function _add() { |
| 194 | + $arguments = func_get_args(); |
| 195 | + $this->_patterns[] = $arguments; |
| 196 | + } |
| 197 | + |
| 198 | + // this is the global replace function (it's quite complicated) |
| 199 | + private function _replacement($arguments) { |
| 200 | + if (empty($arguments)) return ''; |
| 201 | + |
| 202 | + $i = 1; $j = 0; |
| 203 | + // loop through the patterns |
| 204 | + while (isset($this->_patterns[$j])) { |
| 205 | + $pattern = $this->_patterns[$j++]; |
| 206 | + // do we have a result? |
| 207 | + if (isset($arguments[$i]) && ($arguments[$i] != '')) { |
| 208 | + $replacement = $pattern[self::REPLACEMENT]; |
| 209 | + |
| 210 | + if (is_array($replacement) && isset($replacement['fn'])) { |
| 211 | + |
| 212 | + if (isset($replacement['data'])) $this->buffer = $replacement['data']; |
| 213 | + return call_user_func(array(&$this, $replacement['fn']), $arguments, $i); |
| 214 | + |
| 215 | + } elseif (is_int($replacement)) { |
| 216 | + return $arguments[$replacement + $i]; |
| 217 | + |
| 218 | + } |
| 219 | + $delete = ($this->escapeChar == '' || |
| 220 | + strpos($arguments[$i], $this->escapeChar) === false) |
| 221 | + ? '' : "\x01" . $arguments[$i] . "\x01"; |
| 222 | + return $delete . $replacement; |
| 223 | + |
| 224 | + // skip over references to sub-expressions |
| 225 | + } else { |
| 226 | + $i += $pattern[self::LENGTH]; |
| 227 | + } |
| 228 | + } |
| 229 | + } |
| 230 | + |
| 231 | + private function _backReferences($match, $offset) { |
| 232 | + $replacement = $this->buffer['replacement']; |
| 233 | + $quote = $this->buffer['quote']; |
| 234 | + $i = $this->buffer['length']; |
| 235 | + while ($i) { |
| 236 | + $replacement = str_replace('$'.$i--, $match[$offset + $i], $replacement); |
| 237 | + } |
| 238 | + return $replacement; |
| 239 | + } |
| 240 | + |
| 241 | + private function _replace_name($match, $offset){ |
| 242 | + $length = strlen($match[$offset + 2]); |
| 243 | + $start = $length - max($length - strlen($match[$offset + 3]), 0); |
| 244 | + return substr($match[$offset + 1], $start, $length) . $match[$offset + 4]; |
| 245 | + } |
| 246 | + |
| 247 | + private function _replace_encoded($match, $offset) { |
| 248 | + return $this->buffer[$match[$offset]]; |
| 249 | + } |
| 250 | + |
| 251 | + |
| 252 | + // php : we cannot pass additional data to preg_replace_callback, |
| 253 | + // and we cannot use &$this in create_function, so let's go to lower level |
| 254 | + private $buffer; |
| 255 | + |
| 256 | + // encode escaped characters |
| 257 | + private function _escape($string, $escapeChar) { |
| 258 | + if ($escapeChar) { |
| 259 | + $this->buffer = $escapeChar; |
| 260 | + return preg_replace_callback( |
| 261 | + '/\\' . $escapeChar . '(.)' .'/', |
| 262 | + array(&$this, '_escapeBis'), |
| 263 | + $string |
| 264 | + ); |
| 265 | + |
| 266 | + } else { |
| 267 | + return $string; |
| 268 | + } |
| 269 | + } |
| 270 | + private function _escapeBis($match) { |
| 271 | + $this->_escaped[] = $match[1]; |
| 272 | + return $this->buffer; |
| 273 | + } |
| 274 | + |
| 275 | + // decode escaped characters |
| 276 | + private function _unescape($string, $escapeChar) { |
| 277 | + if ($escapeChar) { |
| 278 | + $regexp = '/'.'\\'.$escapeChar.'/'; |
| 279 | + $this->buffer = array('escapeChar'=> $escapeChar, 'i' => 0); |
| 280 | + return preg_replace_callback |
| 281 | + ( |
| 282 | + $regexp, |
| 283 | + array(&$this, '_unescapeBis'), |
| 284 | + $string |
| 285 | + ); |
| 286 | + |
| 287 | + } else { |
| 288 | + return $string; |
| 289 | + } |
| 290 | + } |
| 291 | + private function _unescapeBis() { |
| 292 | + if (isset($this->_escaped[$this->buffer['i']]) |
| 293 | + && $this->_escaped[$this->buffer['i']] != '') |
| 294 | + { |
| 295 | + $temp = $this->_escaped[$this->buffer['i']]; |
| 296 | + } else { |
| 297 | + $temp = ''; |
| 298 | + } |
| 299 | + $this->buffer['i']++; |
| 300 | + return $this->buffer['escapeChar'] . $temp; |
| 301 | + } |
| 302 | + |
| 303 | + private function _internalEscape($string) { |
| 304 | + return preg_replace($this->ESCAPE, '', $string); |
| 305 | + } |
| 306 | +} |
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/includes/DefaultSettings.php |
— | — | @@ -64,6 +64,8 @@ |
65 | 65 | // If the resource loader is in 'debug mode' |
66 | 66 | $wgResourceLoaderDebug = false; |
67 | 67 | |
| 68 | +// If the resource loader should minify vertical space |
| 69 | +$wgResourceLoaderMinifyJSVerticalSpace = false; |
68 | 70 | |
69 | 71 | /** |
70 | 72 | * Maximum time in seconds to cache resources served by the resource loader |
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/includes/MwEmbedResourceLoaderFileModule.php |
— | — | @@ -20,14 +20,6 @@ |
21 | 21 | $deps = mweGetFromFileCache( implode( |
22 | 22 | array( 'module_deps', 'md_deps', 'md_module_' . $this->getName(), 'md_skin_' . $skin ) |
23 | 23 | ) ); |
24 | | - /* |
25 | | - $dbr = wfGetDB( DB_SLAVE ); |
26 | | - $deps = $dbr->selectField( 'module_deps', 'md_deps', array( |
27 | | - 'md_module' => $this->getName(), |
28 | | - 'md_skin' => $skin, |
29 | | - ), __METHOD__ |
30 | | - ); |
31 | | - */ |
32 | 24 | if ( !is_null( $deps ) ) { |
33 | 25 | $this->fileDeps[$skin] = (array) FormatJson::decode( $deps, true ); |
34 | 26 | } else { |
— | — | @@ -35,7 +27,36 @@ |
36 | 28 | } |
37 | 29 | return $this->fileDeps[$skin]; |
38 | 30 | } |
| 31 | + public function getRemotePath($file){ |
| 32 | + global $wgServer; |
| 33 | + $path = parent:: getRemotePath( $file ); |
| 34 | + return $wgServer . $path; |
| 35 | + } |
39 | 36 | |
| 37 | +/** |
| 38 | + * Gets all styles for a given context concatenated together. |
| 39 | + * |
| 40 | + * @param $context ResourceLoaderContext: Context in which to generate styles |
| 41 | + * @return String: CSS code for $context |
| 42 | + */ |
| 43 | + public function getStyles( ResourceLoaderContext $context ) { |
| 44 | + // Merge general styles and skin specific styles, retaining media type collation |
| 45 | + $styles = $this->readStyleFiles( $this->styles, $this->getFlip( $context ) ); |
| 46 | + $skinStyles = $this->readStyleFiles( |
| 47 | + self::tryForKey( $this->skinStyles, $context->getSkin(), 'default' ), |
| 48 | + $this->getFlip( $context ) |
| 49 | + ); |
| 50 | + |
| 51 | + foreach ( $skinStyles as $media => $style ) { |
| 52 | + if ( isset( $styles[$media] ) ) { |
| 53 | + $styles[$media] .= $style; |
| 54 | + } else { |
| 55 | + $styles[$media] = $style; |
| 56 | + } |
| 57 | + } |
| 58 | + return $styles; |
| 59 | + } |
| 60 | + |
40 | 61 | /** |
41 | 62 | * Get the last modification timestamp of the message blob for this |
42 | 63 | * module in a given language. |
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/includes/MwEmbedResourceLoaderStartUpModule.php |
— | — | @@ -38,7 +38,7 @@ |
39 | 39 | return array( 'jquery', 'mediawiki', 'jquery.triggerQueueCallback', 'jquery.mwEmbedUtil', 'mwEmbedStartup' ); |
40 | 40 | } |
41 | 41 | |
42 | | - public function getScript( ResourceLoaderContext $context ) { |
| 42 | + public function getScript( ResourceLoaderContext $context ) { |
43 | 43 | $out = parent::getScript( $context ); |
44 | 44 | // Append mediaWiki.loader.go() for stand alone context: |
45 | 45 | $out.= Xml::encodeJsCall( 'document.write', array( Html::inlineScript( "mediaWiki.loader.go();" ) ) ); |
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/includes/resourceloader/ResourceLoader.php |
— | — | @@ -62,7 +62,7 @@ |
63 | 63 | // Get file dependency information |
64 | 64 | $res = $dbr->select( 'module_deps', array( 'md_module', 'md_deps' ), array( |
65 | 65 | 'md_module' => $modules, |
66 | | - 'md_skin' => $skin, |
| 66 | + 'md_skin' => $skin |
67 | 67 | ), __METHOD__ |
68 | 68 | ); |
69 | 69 | |
— | — | @@ -95,7 +95,8 @@ |
96 | 96 | ), __METHOD__ |
97 | 97 | ); |
98 | 98 | foreach ( $res as $row ) { |
99 | | - $this->getModule( $row->mr_resource )->setMsgBlobMtime( $lang, $row->mr_timestamp ); |
| 99 | + $this->getModule( $row->mr_resource )->setMsgBlobMtime( $lang, |
| 100 | + wfTimestamp( TS_UNIX, $row->mr_timestamp ) ); |
100 | 101 | unset( $modulesWithoutMessages[$row->mr_resource] ); |
101 | 102 | } |
102 | 103 | } |
— | — | @@ -108,7 +109,7 @@ |
109 | 110 | * Runs JavaScript or CSS data through a filter, caching the filtered result for future calls. |
110 | 111 | * |
111 | 112 | * Available filters are: |
112 | | - * - minify-js \see JSMin::minify |
| 113 | + * - minify-js \see JavaScriptDistiller::stripWhiteSpace |
113 | 114 | * - minify-css \see CSSMin::minify |
114 | 115 | * |
115 | 116 | * If $data is empty, only contains whitespace or the filter was unknown, |
— | — | @@ -119,6 +120,8 @@ |
120 | 121 | * @return String: Filtered data, or a comment containing an error message |
121 | 122 | */ |
122 | 123 | protected function filter( $filter, $data ) { |
| 124 | + global $wgResourceLoaderMinifyJSVerticalSpace; |
| 125 | + |
123 | 126 | wfProfileIn( __METHOD__ ); |
124 | 127 | |
125 | 128 | // For empty/whitespace-only data or for unknown filters, don't perform |
— | — | @@ -144,7 +147,9 @@ |
145 | 148 | try { |
146 | 149 | switch ( $filter ) { |
147 | 150 | case 'minify-js': |
148 | | - $result = JSMin::minify( $data ); |
| 151 | + $result = JavaScriptDistiller::stripWhiteSpace( |
| 152 | + $data, $wgResourceLoaderMinifyJSVerticalSpace |
| 153 | + ); |
149 | 154 | break; |
150 | 155 | case 'minify-css': |
151 | 156 | $result = CSSMin::minify( $data ); |
— | — | @@ -191,12 +196,12 @@ |
192 | 197 | * multiple-registration calling style. |
193 | 198 | * @throws MWException: If a duplicate module registration is attempted |
194 | 199 | * @throws MWException: If something other than a ResourceLoaderModule is being registered |
195 | | - * @throws MWException: If an empty module name is being registered |
196 | 200 | * @return Boolean: False if there were any errors, in which case one or more modules were not |
197 | 201 | * registered |
198 | 202 | */ |
199 | 203 | public function register( $name, $info = null ) { |
200 | 204 | wfProfileIn( __METHOD__ ); |
| 205 | + |
201 | 206 | // Allow multiple modules to be registered in one call |
202 | 207 | if ( is_array( $name ) ) { |
203 | 208 | foreach ( $name as $key => $value ) { |
— | — | @@ -213,14 +218,6 @@ |
214 | 219 | 'Another module has already been registered as ' . $name |
215 | 220 | ); |
216 | 221 | } |
217 | | - |
218 | | - // Check empty names register calls |
219 | | - if ( trim( $name ) == '' ) { |
220 | | - // Trying to register module with empty name |
221 | | - throw new MWException( |
222 | | - 'ResourceLoader empty module name registration error' |
223 | | - ); |
224 | | - } |
225 | 222 | |
226 | 223 | // Attach module |
227 | 224 | if ( is_object( $info ) ) { |
— | — | @@ -257,7 +254,7 @@ |
258 | 255 | * @param $name String: Module name |
259 | 256 | * @return Mixed: ResourceLoaderModule if module has been registered, null otherwise |
260 | 257 | */ |
261 | | - public function getModule( $name ) { |
| 258 | + public function getModule( $name ) { |
262 | 259 | if ( !isset( $this->modules[$name] ) ) { |
263 | 260 | if ( !isset( $this->moduleInfos[$name] ) ) { |
264 | 261 | // No such module |
— | — | @@ -273,7 +270,7 @@ |
274 | 271 | $class = 'ResourceLoaderFileModule'; |
275 | 272 | } else { |
276 | 273 | $class = $info['class']; |
277 | | - } |
| 274 | + } |
278 | 275 | $object = new $class( $info ); |
279 | 276 | } |
280 | 277 | $object->setName( $name ); |
— | — | @@ -290,7 +287,6 @@ |
291 | 288 | */ |
292 | 289 | public function respond( ResourceLoaderContext $context ) { |
293 | 290 | global $wgResourceLoaderMaxage, $wgCacheEpoch; |
294 | | - |
295 | 291 | // Buffer output to catch warnings. Normally we'd use ob_clean() on the |
296 | 292 | // top-level output buffer to clear warnings, but that breaks when ob_gzhandler |
297 | 293 | // is used: ob_clean() will clear the GZIP header in that case and it won't come |
— | — | @@ -334,16 +330,18 @@ |
335 | 331 | // Add exception to the output as a comment |
336 | 332 | $exceptions .= "/*\n{$e->__toString()}\n*/\n"; |
337 | 333 | } |
| 334 | + |
338 | 335 | wfProfileIn( __METHOD__.'-getModifiedTime' ); |
339 | 336 | |
| 337 | + $private = false; |
340 | 338 | // To send Last-Modified and support If-Modified-Since, we need to detect |
341 | 339 | // the last modified time |
342 | 340 | $mtime = wfTimestamp( TS_UNIX, $wgCacheEpoch ); |
343 | 341 | foreach ( $modules as $module ) { |
344 | 342 | try { |
345 | | - // Bypass squid cache if the request includes any private modules |
| 343 | + // Bypass Squid and other shared caches if the request includes any private modules |
346 | 344 | if ( $module->getGroup() === 'private' ) { |
347 | | - $smaxage = 0; |
| 345 | + $private = true; |
348 | 346 | } |
349 | 347 | // Calculate maximum modified time |
350 | 348 | $mtime = max( $mtime, $module->getModifiedTime( $context ) ); |
— | — | @@ -352,6 +350,7 @@ |
353 | 351 | $exceptions .= "/*\n{$e->__toString()}\n*/\n"; |
354 | 352 | } |
355 | 353 | } |
| 354 | + |
356 | 355 | wfProfileOut( __METHOD__.'-getModifiedTime' ); |
357 | 356 | |
358 | 357 | if ( $context->getOnly() === 'styles' ) { |
— | — | @@ -361,10 +360,18 @@ |
362 | 361 | } |
363 | 362 | header( 'Last-Modified: ' . wfTimestamp( TS_RFC2822, $mtime ) ); |
364 | 363 | if ( $context->getDebug() ) { |
365 | | - header( 'Cache-Control: must-revalidate' ); |
| 364 | + // Do not cache debug responses |
| 365 | + header( 'Cache-Control: private, no-cache, must-revalidate' ); |
| 366 | + header( 'Pragma: no-cache' ); |
366 | 367 | } else { |
367 | | - header( "Cache-Control: public, max-age=$maxage, s-maxage=$smaxage" ); |
368 | | - header( 'Expires: ' . wfTimestamp( TS_RFC2822, min( $maxage, $smaxage ) + time() ) ); |
| 368 | + if ( $private ) { |
| 369 | + header( "Cache-Control: private, max-age=$maxage" ); |
| 370 | + $exp = $maxage; |
| 371 | + } else { |
| 372 | + header( "Cache-Control: public, max-age=$maxage, s-maxage=$smaxage" ); |
| 373 | + $exp = min( $maxage, $smaxage ); |
| 374 | + } |
| 375 | + header( 'Expires: ' . wfTimestamp( TS_RFC2822, $exp + time() ) ); |
369 | 376 | } |
370 | 377 | |
371 | 378 | // If there's an If-Modified-Since header, respond with a 304 appropriately |
— | — | @@ -397,9 +404,10 @@ |
398 | 405 | return; |
399 | 406 | } |
400 | 407 | } |
401 | | - |
| 408 | + |
402 | 409 | // Generate a response |
403 | 410 | $response = $this->makeModuleResponse( $context, $modules, $missing ); |
| 411 | + |
404 | 412 | // Prepend comments indicating exceptions |
405 | 413 | $response = $exceptions . $response; |
406 | 414 | |
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/includes/resourceloader/ResourceLoaderFileModule.php |
— | — | @@ -206,8 +206,7 @@ |
207 | 207 | * @return String: JavaScript code for $context |
208 | 208 | */ |
209 | 209 | public function getScript( ResourceLoaderContext $context ) { |
210 | | - global $wgServer; |
211 | | - |
| 210 | + global $wgServer; |
212 | 211 | $files = array_merge( |
213 | 212 | $this->scripts, |
214 | 213 | self::tryForKey( $this->languageScripts, $context->getLanguage() ), |
— | — | @@ -216,12 +215,10 @@ |
217 | 216 | if ( $context->getDebug() ) { |
218 | 217 | $files = array_merge( $files, $this->debugScripts ); |
219 | 218 | if ( $this->debugRaw ) { |
220 | | - $script = ''; |
| 219 | + $script = ''; |
221 | 220 | foreach ( $files as $file ) { |
222 | | - $path = $wgServer . $this->getRemotePath( $file ); |
223 | | - $script .= "\n\tmediaWiki.loader.load('" .Xml::encodeJsVar( $path ) . "', 'text/javascript', function(){"; |
224 | | - $script .= "\n\t\tmediaWiki.loader.state("; |
225 | | - $script .= "});"; |
| 221 | + $path = $this->getRemotePath( $file ); |
| 222 | + $script .= "\n\t" . Xml::encodeJsCall( 'mediaWiki.loader.load', array( $path ) ); |
226 | 223 | } |
227 | 224 | return $script; |
228 | 225 | } |
— | — | @@ -264,7 +261,17 @@ |
265 | 262 | } |
266 | 263 | // Collect referenced files |
267 | 264 | $this->localFileRefs = array_unique( $this->localFileRefs ); |
268 | | - |
| 265 | + // If the list has been modified since last time we cached it, update the cache |
| 266 | + if ( $this->localFileRefs !== $this->getFileDependencies( $context->getSkin() ) ) { |
| 267 | + $dbw = wfGetDB( DB_MASTER ); |
| 268 | + $dbw->replace( 'module_deps', |
| 269 | + array( array( 'md_module', 'md_skin' ) ), array( |
| 270 | + 'md_module' => $this->getName(), |
| 271 | + 'md_skin' => $context->getSkin(), |
| 272 | + 'md_deps' => FormatJson::encode( $this->localFileRefs ), |
| 273 | + ) |
| 274 | + ); |
| 275 | + } |
269 | 276 | return $styles; |
270 | 277 | } |
271 | 278 | |
— | — | @@ -310,12 +317,10 @@ |
311 | 318 | * @see ResourceLoaderModule::getFileDependencies |
312 | 319 | */ |
313 | 320 | public function getModifiedTime( ResourceLoaderContext $context ) { |
314 | | - |
315 | 321 | if ( isset( $this->modifiedTime[$context->getHash()] ) ) { |
316 | 322 | return $this->modifiedTime[$context->getHash()]; |
317 | 323 | } |
318 | 324 | wfProfileIn( __METHOD__ ); |
319 | | - |
320 | 325 | |
321 | 326 | $files = array(); |
322 | 327 | |
— | — | @@ -332,6 +337,7 @@ |
333 | 338 | foreach ( $skinFiles as $styleFiles ) { |
334 | 339 | $files = array_merge( $files, $styleFiles ); |
335 | 340 | } |
| 341 | + |
336 | 342 | // Final merge, this should result in a master list of dependent files |
337 | 343 | $files = array_merge( |
338 | 344 | $files, |
— | — | @@ -341,10 +347,10 @@ |
342 | 348 | self::tryForKey( $this->skinScripts, $context->getSkin(), 'default' ), |
343 | 349 | $this->loaderScripts |
344 | 350 | ); |
345 | | - |
346 | 351 | $files = array_map( array( $this, 'getLocalPath' ), $files ); |
347 | 352 | // File deps need to be treated separately because they're already prefixed |
348 | 353 | $files = array_merge( $files, $this->getFileDependencies( $context->getSkin() ) ); |
| 354 | + |
349 | 355 | // If a module is nothing but a list of dependencies, we need to avoid |
350 | 356 | // giving max() an empty array |
351 | 357 | if ( count( $files ) === 0 ) { |
— | — | @@ -478,9 +484,8 @@ |
479 | 485 | * @param $path String: File path of script file to read |
480 | 486 | * @return String: CSS data in script file |
481 | 487 | */ |
482 | | - protected function readStyleFile( $path, $flip ) { |
483 | | - global $wgServer; |
484 | | - $localPath = $this->getLocalPath( $path ); |
| 488 | + protected function readStyleFile( $path, $flip ) { |
| 489 | + $localPath = $this->getLocalPath( $path ); |
485 | 490 | $style = file_get_contents( $localPath ); |
486 | 491 | if ( $style === false ) { |
487 | 492 | throw new MWException( __METHOD__.": style file not found: \"$localPath\"" ); |
— | — | @@ -494,7 +499,7 @@ |
495 | 500 | $dirname = ''; |
496 | 501 | } |
497 | 502 | $dir = $this->getLocalPath( $dirname ); |
498 | | - $remoteDir = $wgServer . $this->getRemotePath( $dirname ); |
| 503 | + $remoteDir = $this->getRemotePath( $dirname ); |
499 | 504 | // Get and register local file references |
500 | 505 | $this->localFileRefs = array_merge( |
501 | 506 | $this->localFileRefs, |
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/includes/resourceloader/ResourceLoaderStartUpModule.php |
— | — | @@ -179,8 +179,8 @@ |
180 | 180 | $out .= "if ( mwIsCompatible() ) {\n" . |
181 | 181 | "\t" . Xml::encodeJsCall( 'document.write', array( $scriptTag ) ) . |
182 | 182 | "}\n" . |
183 | | - "delete mwIsCompatible;"; |
184 | | - } |
| 183 | + "delete mwIsCompatible;"; |
| 184 | + } |
185 | 185 | return $out; |
186 | 186 | } |
187 | 187 | public function getStartupModuleList(){ |
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/EmbedPlayer/tests/Player_Themable.html |
— | — | @@ -11,8 +11,11 @@ |
12 | 12 | <script type="text/javascript" src="../../../load.php?modules=startup&only=scripts"></script> |
13 | 13 | </head> |
14 | 14 | <script type="text/javascript"> |
15 | | - // Show the controls ( this is a theme demo ) |
16 | | - mw.setConfig( 'EmbedPlayer.OverlayControls', false ); |
| 15 | + mediaWiki.loader.go(); |
| 16 | + //setTimeout(function(){ |
| 17 | + // Show the controls ( this is a theme demo ) |
| 18 | + // mw.setConfig( 'EmbedPlayer.OverlayControls', false ); |
| 19 | + //}, 1000 ); |
17 | 20 | </script> |
18 | 21 | <body> |
19 | 22 | |
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/EmbedPlayer/EmbedPlayer.config.php |
— | — | @@ -20,7 +20,7 @@ |
21 | 21 | 'EmbedPlayer.LibraryPage'=> 'http://www.kaltura.org/project/HTML5_Video_Media_JavaScript_Library', |
22 | 22 | |
23 | 23 | |
24 | | - // What tags will be re-written to video player by default |
| 24 | + // jQuery selector of tags to be re-written by embedPlayer |
25 | 25 | // Set to empty string or null to avoid automatic video tag rewrites to embedPlayer |
26 | 26 | "EmbedPlayer.RewriteTags" => "video,audio,playlist", |
27 | 27 | |
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/EmbedPlayer/EmbedPlayer.loader.js |
— | — | @@ -2,14 +2,14 @@ |
3 | 3 | * EmbedPlayer loader |
4 | 4 | */ |
5 | 5 | ( function( mw, $ ) { |
| 6 | + |
6 | 7 | /** |
7 | 8 | * Add a DOM ready check for player tags |
8 | 9 | * |
9 | | - * We use SetupInterface so other functions that depend on the interface can |
10 | | - * wait for the IntefacesReady event |
| 10 | + * We use 'SetupInterface' binding so other code that depend on the video interface can |
| 11 | + * work after the 'IntefacesReady' event |
11 | 12 | */ |
12 | 13 | $( mw ).bind( 'SetupInterface', function( event, callback ){ |
13 | | - |
14 | 14 | // Allow modules to extend EmbedPlayerRewritePlayerTags rewrites as well: |
15 | 15 | var doModuleTagRewrites = function(){ |
16 | 16 | $( mw ).triggerQueueCallback( 'EmbedPlayerRewritePlayerTags', callback ); |
— | — | @@ -37,7 +37,7 @@ |
38 | 38 | } else { |
39 | 39 | var playerSelect = this; |
40 | 40 | } |
41 | | - |
| 41 | + mw.log( 'EmbedPlayer::rewrite: ' + playerSelect ); |
42 | 42 | // Hide videonojs class |
43 | 43 | $( '.videonojs' ).hide(); |
44 | 44 | |
— | — | @@ -106,9 +106,11 @@ |
107 | 107 | }); |
108 | 108 | // Do the request and process the playerElements with updated dependency set |
109 | 109 | mediaWiki.loader.using( dependencySet, function(){ |
110 | | - setTimeout( function(){ |
111 | | - mw.processEmbedPlayers( playerSelect, readyCallback ); |
112 | | - }, 500); |
| 110 | + //alert( mw.processEmbedPlayers ); |
| 111 | + mw.processEmbedPlayers( playerSelect, readyCallback ); |
| 112 | + // },500); |
| 113 | + }, function(){ |
| 114 | + throw new Error( 'Error loading EmbedPlayer dependency set' ); |
113 | 115 | }); |
114 | 116 | }; |
115 | 117 | |
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/TimedText/mw.TimedText.js |
— | — | @@ -14,6 +14,12 @@ |
15 | 15 | // Bind to mw ( for uncluttered global namespace ) |
16 | 16 | ( function( mw, $ ) { |
17 | 17 | |
| 18 | + // Merge in timed text related attributes: |
| 19 | + mw.mergeConfig( 'EmbedPlayer.SourceAttributes', [ |
| 20 | + 'srclang', |
| 21 | + 'category' |
| 22 | + ]); |
| 23 | + |
18 | 24 | /** |
19 | 25 | * Timed Text Object |
20 | 26 | * @param embedPlayer Host player for timedText interfaces |
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/TimedText/TimedText.loader.js |
— | — | @@ -4,12 +4,6 @@ |
5 | 5 | // Scope everything in "mw" ( keeps the global namespace clean ) |
6 | 6 | ( function( mw, $ ) { |
7 | 7 | |
8 | | - // Merge in timed text related attributes: |
9 | | - mw.mergeConfig( 'EmbedPlayer.SourceAttributes', [ |
10 | | - 'srclang', |
11 | | - 'category' |
12 | | - ]); |
13 | | - |
14 | 8 | /** |
15 | 9 | * Check if the video tags in the page support timed text |
16 | 10 | * this way we can add our timed text libraries to the player |
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/MwEmbedSupport/jquery.menu/jquery.menu.js |
— | — | @@ -184,10 +184,8 @@ |
185 | 185 | this.showMenu = function() { |
186 | 186 | mw.log('$j.menu:: show menu' ); |
187 | 187 | killAllMenus(); |
188 | | - mw.log('jquery.menu:: killAllMenus' ); |
189 | | - if ( ! menu.menuExists) { |
190 | | - menu.create() |
191 | | - }; |
| 188 | + // always create the menu to ensure it has correct layout |
| 189 | + menu.create() |
192 | 190 | mw.log('jquery.menu:: menu.create' ); |
193 | 191 | caller |
194 | 192 | .addClass('fg-menu-open') |
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/MwEmbedSupport/mwEmbedSupport.js |
— | — | @@ -19,7 +19,6 @@ |
20 | 20 | * |
21 | 21 | * @dependencies |
22 | 22 | */ |
23 | | - |
24 | 23 | ( function( mw, $ ) { |
25 | 24 | |
26 | 25 | /** |
— | — | @@ -53,7 +52,10 @@ |
54 | 53 | * |
55 | 54 | * @param {Function} |
56 | 55 | * callback Function to run once DOM and jQuery are ready |
57 | | - */ |
| 56 | + */ |
| 57 | + // mw.interfacesReadyFlag ( set to true once interfaces are ready ) |
| 58 | + mw.interfacesReadyFlag = false; |
| 59 | + |
58 | 60 | mw.ready = function( callback ) { |
59 | 61 | if( mw.interfacesReadyFlag === false ) { |
60 | 62 | // Add the callbcak to the onLoad function stack |
— | — | @@ -64,14 +66,12 @@ |
65 | 67 | } |
66 | 68 | }; |
67 | 69 | |
68 | | - // mw.interfacesReadyFlag ( set to true once interfaces are ready ) |
69 | | - mw.interfacesReadyFlag = false; |
70 | 70 | |
71 | 71 | // Once interfaces are ready update the mwReadyFlag |
72 | 72 | $j( mw ).bind('InterfacesReady', function(){ mw.interfacesReadyFlag = true } ); |
73 | 73 | |
74 | 74 | // Once the DOM is ready start setting up interfaces |
75 | | - $j( document ).ready(function(){ |
| 75 | + $j( document ).ready(function(){ |
76 | 76 | $j( mw ).triggerQueueCallback('SetupInterface', function(){ |
77 | 77 | // All interfaces have been setup trigger InterfacesReady event |
78 | 78 | $j( mw ).trigger( 'InterfacesReady' ); |
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/resources/mediawiki/mediawiki.js |
— | — | @@ -124,7 +124,7 @@ |
125 | 125 | /* Constants */ |
126 | 126 | |
127 | 127 | // This will not change until we are 100% ready to turn off legacy globals |
128 | | - var LEGACY_GLOBALS = true; |
| 128 | + var LEGACY_GLOBALS = false; |
129 | 129 | |
130 | 130 | /* Private Members */ |
131 | 131 | |
— | — | @@ -195,7 +195,7 @@ |
196 | 196 | * @return boolean Existence of key(s) |
197 | 197 | */ |
198 | 198 | Map.prototype.exists = function( selection ) { |
199 | | - if ( typeof keys === 'object' ) { |
| 199 | + if ( typeof selection === 'object' ) { |
200 | 200 | for ( var s = 0; s < selection.length; s++ ) { |
201 | 201 | if ( !( selection[s] in this.values ) ) { |
202 | 202 | return false; |
— | — | @@ -239,105 +239,17 @@ |
240 | 240 | // Return <key> if key does not exist |
241 | 241 | return '<' + this.key + '>'; |
242 | 242 | } |
243 | | - var text = this.map.get( this.key ); |
244 | | - |
245 | | - /** |
246 | | - * @@FIXME we should not have the .toString function return non-strings ( jQuery object ) |
247 | | - * maybe we have a jQuery.mw.msg ( ie jQuery wrapper for message dom object creation ? ) |
248 | | - * |
249 | | - * @@FIXME Subcomponent conditionals and features should not be managed or called from the core. |
250 | | - * Instead the core should be extended by subcomponents |
251 | | - * |
252 | | - * |
253 | | - * The basic principal of dynamic interface actions being separated from message content |
254 | | - * is something we should preserve ie: |
255 | | - * |
256 | | - * 'myMsg' : 'Thanks for the fish, [$1 close dialog]' |
257 | | - * |
258 | | - * $target.append( mw.Msg('MyMsg', function(){ $dialog.close() } ) ); |
259 | | - */ |
260 | | - var useSwapIndex = false; |
| 243 | + var text = this.map.get( this.key ); |
261 | 244 | var parameters = this.parameters; |
262 | | - |
263 | | - /** |
264 | | - * If parsing is enabled pre-swap the links from [$1 link text] into format: <a id="mw_message_swap_index_{inx}>link text</a> |
265 | | - * @@NOTE: This should be moved into the parser but doing that properly requires that |
266 | | - * the parser handles substitutions not the message.toString() function |
267 | | - */ |
268 | | - |
269 | | - // Swap [$1 link text] replacements |
270 | | - // @@FIXME parsing links should be integrated with the parser |
271 | | - if ( this.format === 'parse' && 'language' in mediaWiki ) { |
272 | | - text = text.replace( /\[([^\s]+[\s]+[^\]]*)\]/g, function( string, match ) { |
273 | | - // Get the mediaWiki link parts: |
274 | | - var mwLinkParts = match.split(/ /); |
275 | | - // Get the link pars: |
276 | | - var link = mwLinkParts[0]; |
277 | | - mwLinkParts.shift(); |
278 | | - var linkText = mwLinkParts.join(' '); |
279 | | - |
280 | | - var indexIdAttribute = ''; |
281 | | - // Check if the link is a swap index or just a string |
282 | | - if( link[0] == '$' ){ |
283 | | - var index = parseInt( link.replace(/\$/,''), 10 ) -1; |
284 | | - // If the parameter is a text string directly replace it |
285 | | - if( typeof parameters[ index ] == 'string' ){ |
286 | | - link = parameters[ index ]; |
287 | | - } else { |
288 | | - indexIdAttribute = ' id="mw_message_swap_index_' + index + '" '; |
289 | | - useSwapIndex = true; |
290 | | - link = '#'; |
291 | | - } |
292 | | - } |
293 | | - return '<a href="' + link + '" ' + indexIdAttribute + '>' + linkText + '</a>'; |
294 | | - }); |
295 | | - } |
296 | | - |
297 | | - // Swap $1 replacements: |
298 | 245 | text = text.replace( /\$(\d+)/g, function( string, match ) { |
299 | 246 | var index = parseInt( match, 10 ) - 1; |
300 | | - // Check the parameters type |
301 | | - if( parameters[index] && ( typeof parameters[index] == 'function' || parameters[index] instanceof jQuery ) ){ |
302 | | - useSwapIndex = true; |
303 | | - return '<span id="mw_message_swap_index_' + index +'"></span>'; |
304 | | - } else { |
305 | | - // directly swap in the index or a missing index indicator ( $1{int} |
306 | | - return ( index in parameters ) ? parameters[index] : '$' + match; |
307 | | - } |
| 247 | + return index in parameters ? parameters[index] : '$' + match; |
308 | 248 | } ); |
309 | | - |
310 | | - |
311 | | - if ( this.format === 'parse' && 'language' in mediaWiki ) { |
312 | | - // Create a parser object with default set of options: |
313 | | - var parserObject = new mediaWiki.language.parser( text, {} ); |
314 | | - |
315 | | - // Get the html representation of wikitext ( all that messages deal with right now ) |
316 | | - text = parserObject.getHTML(); |
317 | | - |
318 | | - } else if ( this.format === 'plain' ){ |
319 | | - // don't transform |
320 | | - } |
321 | | - |
322 | | - // If we use a dom swap id replace it here and return a binded jQuery object: |
323 | | - if( useSwapIndex ) { |
324 | | - // Add bindings to swap index and return binded html jQuery objects |
325 | | - var $text = $('<span />').html( text ); |
326 | | - for( var index=0; index < parameters.length; index++ ) { |
327 | | - if( typeof parameters[index] == 'function' ){ |
328 | | - $text.find( '#mw_message_swap_index_' + index ).click( parameters[index] ); |
329 | | - } |
330 | | - if( parameters[index] instanceof jQuery ){ |
331 | | - // We get the text for the link from the message text, while |
332 | | - // the interface actions of the link are handled by the jQuery object |
333 | | - var $swapIndex = $text.find( '#mw_message_swap_index_' + index ); |
334 | | - parameters[ index ].text( $swapIndex.text() ); |
335 | | - $swapIndex.replaceWith( parameters[ index ] ); |
336 | | - } |
337 | | - } |
338 | | - // return the binded element |
339 | | - return $text; |
| 249 | + /* This should be fixed up when we have a parser |
| 250 | + if ( this.format === 'parse' && 'language' in mediaWiki ) { |
| 251 | + text = mediaWiki.language.parse( text ); |
340 | 252 | } |
341 | | - |
| 253 | + */ |
342 | 254 | return text; |
343 | 255 | }; |
344 | 256 | |
— | — | @@ -395,7 +307,7 @@ |
396 | 308 | */ |
397 | 309 | function generateId() { |
398 | 310 | var id = ''; |
399 | | - var seed = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz'; |
| 311 | + var seed = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; |
400 | 312 | for ( var i = 0, r; i < 32; i++ ) { |
401 | 313 | r = Math.floor( Math.random() * seed.length ); |
402 | 314 | id += seed.substring( r, r + 1 ); |
— | — | @@ -507,14 +419,14 @@ |
508 | 420 | * |
509 | 421 | * @param key string Key of message to get |
510 | 422 | * @param parameters mixed First argument in a list of variadic arguments, each a parameter for $ |
511 | | - * replacement. parameters can be an indexed array of replacements. |
| 423 | + * replacement |
512 | 424 | */ |
513 | 425 | this.message = function( key, parameters ) { |
514 | 426 | // Support variadic arguments |
515 | | - if ( typeof parameters !== 'undefined' && ! $.isArray( parameters ) ) { |
| 427 | + if ( typeof parameters !== 'undefined' ) { |
516 | 428 | parameters = $.makeArray( arguments ); |
517 | 429 | parameters.shift(); |
518 | | - } else if( ! $.isArray( parameters ) ){ |
| 430 | + } else { |
519 | 431 | parameters = []; |
520 | 432 | } |
521 | 433 | return new Message( mediaWiki.messages, key, parameters ); |
— | — | @@ -532,14 +444,6 @@ |
533 | 445 | }; |
534 | 446 | |
535 | 447 | /** |
536 | | - * Gets a message without transforming it similar to wfMsgNoTrans |
537 | | - */ |
538 | | - this.msgNoTrans = function( key ){ |
539 | | - // @@FIXME I know we should use Message.plain() somehow but the above code is not clear at all. |
540 | | - return mediaWiki.messages.get( key ); |
541 | | - }; |
542 | | - |
543 | | - /** |
544 | 448 | * Client-side module loader which integrates with the MediaWiki ResourceLoader |
545 | 449 | */ |
546 | 450 | this.loader = new ( function() { |
— | — | @@ -578,19 +482,19 @@ |
579 | 483 | var suspended = true; |
580 | 484 | // Flag inidicating that document is ready |
581 | 485 | var documentReady = false; |
582 | | - |
583 | 486 | // Marker element for adding dynamic styles |
584 | 487 | var $marker = null ; // lazy init |
585 | 488 | var getMarker = function(){ |
586 | 489 | if( $marker ) |
587 | 490 | return $marker; |
588 | | - $marker = $( 'head meta[name=ResourceLoaderDynamicStyles]' ) |
| 491 | + $marker = $( 'head meta[name=ResourceLoaderDynamicStyles]' ); |
589 | 492 | if( ! $marker.length ){ |
590 | 493 | $marker = $( '<meta />').attr( 'name', 'ResourceLoaderDynamicStyles' ) |
591 | 494 | .appendTo( 'head' ); |
592 | 495 | } |
593 | 496 | return $marker; |
594 | 497 | }; |
| 498 | + |
595 | 499 | /* Private Methods */ |
596 | 500 | |
597 | 501 | function compare( a, b ) { |
— | — | @@ -754,7 +658,7 @@ |
755 | 659 | } else if ( typeof registry[module].style === 'object' |
756 | 660 | && !( registry[module].style instanceof Array ) ) |
757 | 661 | { |
758 | | - for ( var media in registry[module].style ) { |
| 662 | + for ( var media in registry[module].style ) { |
759 | 663 | getMarker().before( mediaWiki.html.element( 'style', |
760 | 664 | { type: 'text/css', media: media }, |
761 | 665 | new mediaWiki.html.Cdata( registry[module].style[media] ) |
— | — | @@ -867,23 +771,11 @@ |
868 | 772 | /** |
869 | 773 | * Appends a set of scripts to the dom |
870 | 774 | * @param url {Mixed} Array or single url string |
| 775 | + * @param callback {function} function called once scripts are loaded |
871 | 776 | */ |
872 | | - function appendScripts( url, callback, error ){ |
| 777 | + function appendScript( url, callback ){ |
873 | 778 | if( ! url ) |
874 | 779 | return ; |
875 | | - if( $.isArray( url ) ){ |
876 | | - var requestCount = 0; |
877 | | - $.each( url, function(inx, singleUrl ){ |
878 | | - requestCount++; |
879 | | - appendScripts( singleUrl, function(){ |
880 | | - requestCount--; |
881 | | - if( requestCount == 0 && typeof callback == 'function') |
882 | | - callback(); |
883 | | - }); |
884 | | - }); |
885 | | - return ; |
886 | | - } |
887 | | - |
888 | 780 | // Load asynchronously after document ready |
889 | 781 | if ( documentReady ) { |
890 | 782 | // Load without jQuery to avoid $.globalEval issue |
— | — | @@ -967,17 +859,12 @@ |
968 | 860 | // again, all before we've cleared it causing each request to |
969 | 861 | // include modules which are already loaded |
970 | 862 | batch = []; |
971 | | - // Asynchronously append a script tag to the end of the body |
972 | | - function getRequestUrs() { |
973 | | - var urls = []; |
974 | | - for ( var r = 0; r < requests.length; r++ ) { |
975 | | - requests[r] = sortQuery( requests[r] ); |
976 | | - // Build out the HTML |
977 | | - urls.push( mediaWiki.config.get( 'wgLoadScript' ) + '?' + $.param( requests[r] ) ); |
978 | | - } |
979 | | - return urls; |
| 863 | + // Append a script tag to the end of the body |
| 864 | + for ( var r = 0; r < requests.length; r++ ) { |
| 865 | + requests[r] = sortQuery( requests[r] ); |
| 866 | + // Build out the HTML |
| 867 | + appendScript( mediaWiki.config.get( 'wgLoadScript' ) + '?' + $.param( requests[r] ) ); |
980 | 868 | } |
981 | | - appendScripts( getRequestUrs() ); |
982 | 869 | } |
983 | 870 | }; |
984 | 871 | |
— | — | @@ -1104,7 +991,7 @@ |
1105 | 992 | // If any dependencies have errors execute error immediately |
1106 | 993 | else if ( filter( ['error'], dependencies ).length ) { |
1107 | 994 | if ( typeof error === 'function' ) { |
1108 | | - error(); |
| 995 | + error( "Error loading: " + filter( ['error'], dependencies ).join(',') ); |
1109 | 996 | } |
1110 | 997 | } |
1111 | 998 | // Since some dependencies are not yet ready, queue up a request |
— | — | @@ -1141,7 +1028,7 @@ |
1142 | 1029 | .attr( 'href', modules ) ); |
1143 | 1030 | return true; |
1144 | 1031 | } else if ( type === 'text/javascript' || typeof type === 'undefined' ) { |
1145 | | - appendScripts( modules ); |
| 1032 | + appendScript( modules ); |
1146 | 1033 | return true; |
1147 | 1034 | } |
1148 | 1035 | // Unknown type |
— | — | @@ -1271,7 +1158,7 @@ |
1272 | 1159 | */ |
1273 | 1160 | this.element = function( name, attrs, contents ) { |
1274 | 1161 | var s = '<' + name; |
1275 | | - for ( attrName in attrs ) { |
| 1162 | + for ( var attrName in attrs ) { |
1276 | 1163 | s += ' ' + attrName + '="' + this.escape( attrs[attrName] ) + '"'; |
1277 | 1164 | } |
1278 | 1165 | if ( typeof contents == 'undefined' || contents === null ) { |
— | — | @@ -1281,7 +1168,7 @@ |
1282 | 1169 | } |
1283 | 1170 | // Regular open tag |
1284 | 1171 | s += '>'; |
1285 | | - if (typeof contents === 'string') { |
| 1172 | + if ( typeof contents === 'string') { |
1286 | 1173 | // Escaped |
1287 | 1174 | s += this.escape( contents ); |
1288 | 1175 | } else if ( contents instanceof this.Raw ) { |