r72372 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r72371‎ | r72372 | r72373 >
Date:12:53, 4 September 2010
Author:siebrand
Status:ok
Tags:
Comment:
Stylize files added in r72349
Modified paths:
  • /trunk/phase3/includes/CSSJanus.php (modified) (history)
  • /trunk/phase3/includes/CSSMin.php (modified) (history)
  • /trunk/phase3/includes/MessageBlobStore.php (modified) (history)
  • /trunk/phase3/includes/ResourceLoader.php (modified) (history)
  • /trunk/phase3/includes/ResourceLoaderContext.php (modified) (history)
  • /trunk/phase3/includes/ResourceLoaderModule.php (modified) (history)
  • /trunk/phase3/load.php (modified) (history)
  • /trunk/phase3/maintenance/tests/ResourceLoaderFileModuleTest.php (modified) (history)
  • /trunk/phase3/maintenance/tests/ResourceLoaderTest.php (modified) (history)

Diff [purge]

Index: trunk/phase3/maintenance/tests/ResourceLoaderTest.php
@@ -1,16 +1,15 @@
22 <?php
33
44 class ResourceLoaderTest extends PHPUnit_Framework_TestCase {
5 -
65 /* Provider Methods */
7 -
 6+
87 public function provide() {
9 -
 8+
109 }
11 -
 10+
1211 /* Test Methods */
13 -
 12+
1413 public function test() {
15 -
 14+
1615 }
17 -}
\ No newline at end of file
 16+}
Index: trunk/phase3/maintenance/tests/ResourceLoaderFileModuleTest.php
@@ -1,16 +1,15 @@
22 <?php
33
44 class ResourceLoaderFileModuleTest extends PHPUnit_Framework_TestCase {
5 -
65 /* Provider Methods */
7 -
 6+
87 public function provide() {
9 -
 8+
109 }
11 -
 10+
1211 /* Test Methods */
13 -
 12+
1413 public function test() {
15 -
 14+
1615 }
17 -}
\ No newline at end of file
 16+}
Index: trunk/phase3/includes/CSSMin.php
@@ -1,22 +1,21 @@
22 <?php
33
44 class CSSMin {
5 -
65 /* Constants */
7 -
 6+
87 /**
98 * Maximum file size to still qualify for in-line embedding as a data-URI
10 - *
 9+ *
1110 * 24,576 is used because Internet Explorer has a 32,768 byte limit for data URIs, which when base64 encoded will
1211 * result in a 1/3 increase in size.
1312 */
1413 const EMBED_SIZE_LIMIT = 24576;
15 -
 14+
1615 /* Static Methods */
17 -
 16+
1817 /**
1918 * Gets a list of local file paths which are referenced in a CSS style sheet
20 - *
 19+ *
2120 * @param $source string CSS data to remap
2221 * @param $path string File path where the source was read from (optional)
2322 * @return array List of local file references
@@ -24,39 +23,46 @@
2524 public static function getLocalFileReferences( $source, $path = null ) {
2625 $pattern = '/url\([\'"]?(?<file>[^\?\)\:]*)\??[^\)]*[\'"]?\)/';
2726 $files = array();
 27+
2828 if ( preg_match_all( $pattern, $source, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER ) ) {
2929 foreach ( $matches as $match ) {
3030 $file = ( isset( $path ) ? rtrim( $path, '/' ) . '/' : '' ) . "{$match['file'][0]}";
 31+
3132 // Only proceed if we can access the file
3233 if ( file_exists( $file ) ) {
3334 $files[] = $file;
3435 }
3536 }
3637 }
 38+
3739 return $files;
3840 }
39 -
 41+
4042 /**
4143 * Remaps CSS URL paths and automatically embeds data URIs for URL rules preceded by an /* @embed * / comment
42 - *
 44+ *
4345 * @param $source string CSS data to remap
4446 * @param $path string File path where the source was read from
4547 * @return string Remapped CSS data
4648 */
4749 public static function remap( $source, $path ) {
4850 global $wgUseDataURLs;
 51+
4952 $pattern = '/((?<embed>\s*\/\*\s*\@embed\s*\*\/)(?<rule>[^\;\}]*))?url\([\'"]?(?<file>[^\?\)\:]*)\??[^\)]*[\'"]?\)(?<extra>[^;]*)[\;]?/';
5053 $offset = 0;
 54+
5155 while ( preg_match( $pattern, $source, $match, PREG_OFFSET_CAPTURE, $offset ) ) {
5256 // Shortcuts
5357 $embed = $match['embed'][0];
5458 $rule = $match['rule'][0];
5559 $extra = $match['extra'][0];
5660 $file = "{$path}/{$match['file'][0]}";
 61+
5762 // Only proceed if we can access the file
5863 if ( file_exists( $file ) ) {
5964 // Add version parameter as a time-stamp in ISO 8601 format, using Z for the timezone, meaning GMT
6065 $url = "{$file}?" . gmdate( 'Y-m-d\TH:i:s\Z', round( filemtime( $file ), -2 ) );
 66+
6167 // Detect when URLs were preceeded with embed tags, and also verify file size is below the limit
6268 if ( $wgUseDataURLs && $match['embed'][1] > 0 && filesize( $file ) < self::EMBED_SIZE_LIMIT ) {
6369 // If we ever get to PHP 5.3, we should use the Fileinfo extension instead of mime_content_type
@@ -71,6 +77,7 @@
7278 // Build a CSS property with a remapped and versioned URL
7379 $replacement = "{$embed}{$rule}url({$url}){$extra};";
7480 }
 81+
7582 // Perform replacement on the source
7683 $source = substr_replace( $source, $replacement, $match[0][1], strlen( $match[0][0] ) );
7784 // Move the offset to the end of the replacement in the source
@@ -80,14 +87,15 @@
8188 // Move the offset to the end of the match, leaving it alone
8289 $offset = $match[0][1] + strlen( $match[0][0] );
8390 }
 91+
8492 return $source;
8593 }
86 -
 94+
8795 /**
8896 * Removes whitespace from CSS data
89 - *
 97+ *
9098 * @param $source string CSS data to minify
91 - * @return string Minified CSS data
 99+ * @return string Minified CSS data
92100 */
93101 public static function minify( $css ) {
94102 return trim(
@@ -98,4 +106,4 @@
99107 )
100108 );
101109 }
102 -}
\ No newline at end of file
 110+}
Index: trunk/phase3/includes/ResourceLoaderContext.php
@@ -23,9 +23,8 @@
2424 * Object passed around to modules which contains information about the state of a specific loader request
2525 */
2626 class ResourceLoaderContext {
27 -
2827 /* Protected Members */
29 -
 28+
3029 protected $request;
3130 protected $server;
3231 protected $modules;
@@ -35,12 +34,12 @@
3635 protected $debug;
3736 protected $only;
3837 protected $hash;
39 -
 38+
4039 /* Methods */
41 -
 40+
4241 public function __construct( WebRequest $request, $server ) {
4342 global $wgUser, $wgLang, $wgDefaultSkin;
44 -
 43+
4544 $this->request = $request;
4645 $this->server = $server;
4746 // Interperet request
@@ -50,30 +49,33 @@
5150 $this->skin = $request->getVal( 'skin' );
5251 $this->debug = $request->getVal( 'debug' ) === 'true' || $request->getBool( 'debug' );
5352 $this->only = $request->getVal( 'only' );
 53+
5454 // Fallback on system defaults
5555 if ( !$this->language ) {
5656 $this->language = $wgLang->getCode();
5757 }
 58+
5859 if ( !$this->direction ) {
5960 $this->direction = Language::factory( $this->language )->getDir();
6061 }
 62+
6163 if ( !$this->skin ) {
6264 $this->skin = $wgDefaultSkin;
6365 }
6466 }
65 -
 67+
6668 public function getRequest() {
6769 return $this->request;
6870 }
69 -
 71+
7072 public function getServer() {
7173 return $this->server;
7274 }
73 -
 75+
7476 public function getModules() {
7577 return $this->modules;
7678 }
77 -
 79+
7880 public function getLanguage() {
7981 return $this->language;
8082 }
@@ -81,33 +83,33 @@
8284 public function getDirection() {
8385 return $this->direction;
8486 }
85 -
 87+
8688 public function getSkin() {
8789 return $this->skin;
8890 }
89 -
 91+
9092 public function getDebug() {
9193 return $this->debug;
9294 }
93 -
 95+
9496 public function getOnly() {
9597 return $this->only;
9698 }
97 -
 99+
98100 public function shouldIncludeScripts() {
99101 return is_null( $this->only ) || $this->only === 'scripts';
100102 }
101 -
 103+
102104 public function shouldIncludeStyles() {
103105 return is_null( $this->only ) || $this->only === 'styles';
104106 }
105 -
 107+
106108 public function shouldIncludeMessages() {
107109 return is_null( $this->only ) || $this->only === 'messages';
108110 }
109 -
 111+
110112 public function getHash() {
111113 return isset( $this->hash ) ?
112114 $this->hash : $this->hash = implode( '|', array( $this->language, $this->skin, $this->debug ) );
113115 }
114 -}
\ No newline at end of file
 116+}
Index: trunk/phase3/includes/ResourceLoader.php
@@ -61,14 +61,13 @@
6262 * ResourceLoader::respond( $wgRequest, $wgServer . $wgScriptPath . '/load.php' );
6363 */
6464 class ResourceLoader {
65 -
6665 /* Protected Static Members */
67 -
 66+
6867 // @var array list of module name/ResourceLoaderModule object pairs
6968 protected static $modules = array();
70 -
 69+
7170 /* Protected Static Methods */
72 -
 71+
7372 /**
7473 * Runs text through a filter, caching the filtered result for future calls
7574 *
@@ -79,18 +78,20 @@
8079 */
8180 protected static function filter( $filter, $data ) {
8281 global $wgMemc;
 82+
8383 // For empty or whitespace-only things, don't do any processing
8484 if ( trim( $data ) === '' ) {
8585 return $data;
8686 }
87 -
 87+
8888 // Try memcached
8989 $key = wfMemcKey( 'resourceloader', 'filter', $filter, md5( $data ) );
9090 $cached = $wgMemc->get( $key );
 91+
9192 if ( $cached !== false && $cached !== null ) {
9293 return $cached;
9394 }
94 -
 95+
9596 // Run the filter
9697 try {
9798 switch ( $filter ) {
@@ -110,24 +111,25 @@
111112 } catch ( Exception $exception ) {
112113 throw new MWException( 'Filter threw an exception: ' . $exception->getMessage() );
113114 }
114 -
 115+
115116 // Save to memcached
116117 $wgMemc->set( $key, $result );
 118+
117119 return $result;
118120 }
119 -
 121+
120122 /* Static Methods */
121 -
 123+
122124 /**
123125 * Registers a module with the ResourceLoader system.
124126 *
125127 * Note that registering the same object under multiple names is not supported and may silently fail in all
126128 * kinds of interesting ways.
127 - *
 129+ *
128130 * @param {mixed} $name string of name of module or array of name/object pairs
129131 * @param {ResourceLoaderModule} $object module object (optional when using multiple-registration calling style)
130132 * @return {boolean} false if there were any errors, in which case one or more modules were not registered
131 - *
 133+ *
132134 * @todo We need much more clever error reporting, not just in detailing what happened, but in bringing errors to
133135 * the client in a way that they can easily see them if they want to, such as by using FireBug
134136 */
@@ -137,8 +139,10 @@
138140 foreach ( $name as $key => $value ) {
139141 self::register( $key, $value );
140142 }
 143+
141144 return;
142145 }
 146+
143147 // Disallow duplicate registrations
144148 if ( isset( self::$modules[$name] ) ) {
145149 // A module has already been registered by this name
@@ -148,7 +152,7 @@
149153 self::$modules[$name] = $object;
150154 $object->setName( $name );
151155 }
152 -
 156+
153157 /**
154158 * Gets a map of all modules and their options
155159 *
@@ -157,7 +161,7 @@
158162 public static function getModules() {
159163 return self::$modules;
160164 }
161 -
 165+
162166 /**
163167 * Get the ResourceLoaderModule object for a given module name
164168 * @param $name string Module name
@@ -166,7 +170,7 @@
167171 public static function getModule( $name ) {
168172 return isset( self::$modules[$name] ) ? self::$modules[$name] : null;
169173 }
170 -
 174+
171175 /**
172176 * Gets registration code for all modules, except pre-registered ones listed in self::$preRegisteredModules
173177 *
@@ -180,6 +184,7 @@
181185 public static function getModuleRegistrations( ResourceLoaderContext $context ) {
182186 $scripts = '';
183187 $registrations = array();
 188+
184189 foreach ( self::$modules as $name => $module ) {
185190 // Support module loader scripts
186191 if ( ( $loader = $module->getLoaderScript() ) !== false ) {
@@ -199,7 +204,7 @@
200205 }
201206 return $scripts . "mediaWiki.loader.register( " . FormatJson::encode( $registrations ) . " );";
202207 }
203 -
 208+
204209 /**
205210 * Get the highest modification time of all modules, based on a given combination of language code,
206211 * skin name and debug mode flag.
@@ -210,14 +215,16 @@
211216 */
212217 public static function getHighestModifiedTime( ResourceLoaderContext $context ) {
213218 $time = 1; // wfTimestamp() treats 0 as 'now', so that's not a suitable choice
 219+
214220 foreach ( self::$modules as $module ) {
215221 $time = max( $time, $module->getModifiedTime( $context ) );
216222 }
 223+
217224 return $time;
218225 }
219 -
 226+
220227 /* Methods */
221 -
 228+
222229 /*
223230 * Outputs a response to a resource load-request, including a content-type header
224231 *
@@ -237,6 +244,7 @@
238245 // Split requested modules into two groups, modules and missing
239246 $modules = array();
240247 $missing = array();
 248+
241249 foreach ( $context->getModules() as $name ) {
242250 if ( isset( self::$modules[$name] ) ) {
243251 $modules[] = $name;
@@ -244,52 +252,58 @@
245253 $missing[] = $name;
246254 }
247255 }
248 -
 256+
249257 // Calculate the mtime and caching maxages for this request. We need this, 304 or no 304
250258 $mtime = 1;
251259 $maxage = PHP_INT_MAX;
252260 $smaxage = PHP_INT_MAX;
 261+
253262 foreach ( $modules as $name ) {
254263 $mtime = max( $mtime, self::$modules[$name]->getModifiedTime( $context ) );
255264 $maxage = min( $maxage, self::$modules[$name]->getClientMaxage() );
256265 $smaxage = min( $smaxage, self::$modules[$name]->getServerMaxage() );
257266 }
258 -
 267+
259268 // Output headers
260269 if ( $context->getOnly() === 'styles' ) {
261270 header( 'Content-Type: text/css' );
262271 } else {
263272 header( 'Content-Type: text/javascript' );
264273 }
 274+
265275 header( 'Last-Modified: ' . wfTimestamp( TS_RFC2822, $mtime ) );
266276 $expires = wfTimestamp( TS_RFC2822, min( $maxage, $smaxage ) + time() );
267277 header( "Cache-Control: public, maxage=$maxage, s-maxage=$smaxage" );
268278 header( "Expires: $expires" );
269 -
 279+
270280 // Check if there's an If-Modified-Since header and respond with a 304 Not Modified if possible
271281 $ims = $context->getRequest()->getHeader( 'If-Modified-Since' );
 282+
272283 if ( $ims !== false && wfTimestamp( TS_UNIX, $ims ) == $mtime ) {
273284 header( 'HTTP/1.0 304 Not Modified' );
274285 header( 'Status: 304 Not Modified' );
275286 return;
276287 }
277 -
 288+
278289 // Use output buffering
279290 ob_start();
280 -
 291+
281292 // Pre-fetch blobs
282293 $blobs = $context->shouldIncludeMessages() ?
283294 MessageBlobStore::get( $modules, $context->getLanguage() ) : array();
284 -
 295+
285296 // Generate output
286297 foreach ( $modules as $name ) {
287298 // Scripts
288299 $scripts = '';
 300+
289301 if ( $context->shouldIncludeScripts() ) {
290302 $scripts .= self::$modules[$name]->getScript( $context );
291303 }
 304+
292305 // Styles
293306 $styles = '';
 307+
294308 if (
295309 $context->shouldIncludeStyles() &&
296310 ( $styles .= self::$modules[$name]->getStyle( $context ) ) !== ''
@@ -299,8 +313,10 @@
300314 }
301315 $styles = $context->getDebug() ? $styles : self::filter( 'minify-css', $styles );
302316 }
 317+
303318 // Messages
304319 $messages = isset( $blobs[$name] ) ? $blobs[$name] : '{}';
 320+
305321 // Output
306322 if ( $context->getOnly() === 'styles' ) {
307323 echo $styles;
@@ -313,21 +329,26 @@
314330 echo "mediaWiki.loader.implement( '$name', function() {{$scripts}},\n'$styles',\n$messages );\n";
315331 }
316332 }
 333+
317334 // Update the status of script-only modules
318335 if ( $context->getOnly() === 'scripts' && !in_array( 'startup', $modules ) ) {
319336 $statuses = array();
 337+
320338 foreach ( $modules as $name ) {
321339 $statuses[$name] = 'ready';
322340 }
 341+
323342 $statuses = FormatJson::encode( $statuses );
324343 echo "mediaWiki.loader.state( $statuses );";
325344 }
 345+
326346 // Register missing modules
327347 if ( $context->shouldIncludeScripts() ) {
328348 foreach ( $missing as $name ) {
329349 echo "mediaWiki.loader.register( '$name', null, 'missing' );\n";
330350 }
331351 }
 352+
332353 // Output the appropriate header
333354 if ( $context->getOnly() !== 'styles' ) {
334355 if ( $context->getDebug() ) {
@@ -340,4 +361,4 @@
341362 }
342363
343364 // FIXME: Temp hack
344 -require_once "$IP/resources/Resources.php";
\ No newline at end of file
 365+require_once "$IP/resources/Resources.php";
Index: trunk/phase3/includes/MessageBlobStore.php
@@ -42,7 +42,7 @@
4343 }
4444 // Try getting from the DB first
4545 $blobs = self::getFromDB( $modules, $lang );
46 -
 46+
4747 // Generate blobs for any missing modules and store them in the DB
4848 $missing = array_diff( $modules, array_keys( $blobs ) );
4949 foreach ( $missing as $module ) {
@@ -51,9 +51,10 @@
5252 $blobs[$module] = $blob;
5353 }
5454 }
 55+
5556 return $blobs;
5657 }
57 -
 58+
5859 /**
5960 * Generate and insert a new message blob. If the blob was already
6061 * present, it is not regenerated; instead, the preexisting blob
@@ -64,10 +65,11 @@
6566 */
6667 public static function insertMessageBlob( $module, $lang ) {
6768 $blob = self::generateMessageBlob( $module, $lang );
 69+
6870 if ( !$blob ) {
6971 return false;
7072 }
71 -
 73+
7274 $dbw = wfGetDb( DB_MASTER );
7375 $success = $dbw->insert( 'msg_resource', array(
7476 'mr_lang' => $lang,
@@ -78,6 +80,7 @@
7981 __METHOD__,
8082 array( 'IGNORE' )
8183 );
 84+
8285 if ( $success ) {
8386 if ( $dbw->affectedRows() == 0 ) {
8487 // Blob was already present, fetch it
@@ -91,6 +94,7 @@
9295 // Update msg_resource_links
9396 $rows = array();
9497 $mod = ResourceLoader::getModule( $module );
 98+
9599 foreach ( $mod->getMessages() as $key ) {
96100 $rows[] = array(
97101 'mrl_resource' => $module,
@@ -102,9 +106,10 @@
103107 );
104108 }
105109 }
 110+
106111 return $blob;
107112 }
108 -
 113+
109114 /**
110115 * Update all message blobs for a given module.
111116 * @param $module string Module name
@@ -113,22 +118,24 @@
114119 */
115120 public static function updateModule( $module, $lang = null ) {
116121 $retval = null;
117 -
 122+
118123 // Find all existing blobs for this module
119124 $dbw = wfGetDb( DB_MASTER );
120125 $res = $dbw->select( 'msg_resource', array( 'mr_lang', 'mr_blob' ),
121126 array( 'mr_resource' => $module ),
122127 __METHOD__
123128 );
124 -
 129+
125130 // Build the new msg_resource rows
126131 $newRows = array();
127132 $now = $dbw->timestamp();
128133 // Save the last-processed old and new blobs for later
129134 $oldBlob = $newBlob = null;
 135+
130136 foreach ( $res as $row ) {
131137 $oldBlob = $row->mr_blob;
132138 $newBlob = self::generateMessageBlob( $module, $row->mr_lang );
 139+
133140 if ( $row->mr_lang === $lang ) {
134141 $retval = $newBlob;
135142 }
@@ -144,13 +151,13 @@
145152 array( array( 'mr_resource', 'mr_lang' ) ),
146153 $newRows, __METHOD__
147154 );
148 -
 155+
149156 // Figure out which messages were added and removed
150157 $oldMessages = array_keys( FormatJson::decode( $oldBlob, true ) );
151158 $newMessages = array_keys( FormatJson::decode( $newBlob, true ) );
152159 $added = array_diff( $newMessages, $oldMessages );
153160 $removed = array_diff( $oldMessages, $newMessages );
154 -
 161+
155162 // Delete removed messages, insert added ones
156163 if ( $removed ) {
157164 $dbw->delete( 'msg_resource_links', array(
@@ -159,35 +166,39 @@
160167 ), __METHOD__
161168 );
162169 }
 170+
163171 $newLinksRows = array();
 172+
164173 foreach ( $added as $message ) {
165174 $newLinksRows[] = array(
166175 'mrl_resource' => $module,
167176 'mrl_message' => $message
168177 );
169178 }
 179+
170180 if ( $newLinksRows ) {
171181 $dbw->insert( 'msg_resource_links', $newLinksRows, __METHOD__,
172182 array( 'IGNORE' ) // just in case
173183 );
174184 }
175 -
 185+
176186 return $retval;
177187 }
178 -
 188+
179189 /**
180190 * Update a single message in all message blobs it occurs in.
181191 * @param $key string Message key
182192 */
183193 public static function updateMessage( $key ) {
184194 $dbw = wfGetDb( DB_MASTER );
185 -
 195+
186196 // Keep running until the updates queue is empty.
187197 // Due to update conflicts, the queue might not be emptied
188198 // in one iteration.
189199 $updates = null;
190200 do {
191201 $updates = self::getUpdatesForMessage( $key, $updates );
 202+
192203 foreach ( $updates as $key => $update ) {
193204 // Update the row on the condition that it
194205 // didn't change since we fetched it by putting
@@ -200,7 +211,7 @@
201212 'mr_timestamp' => $update['timestamp'] ),
202213 __METHOD__
203214 );
204 -
 215+
205216 // Only requeue conflicted updates.
206217 // If update() returned false, don't retry, for
207218 // fear of getting into an infinite loop
@@ -210,11 +221,11 @@
211222 }
212223 }
213224 } while ( count( $updates ) );
214 -
 225+
215226 // No need to update msg_resource_links because we didn't add
216227 // or remove any messages, we just changed their contents.
217228 }
218 -
 229+
219230 public static function clear() {
220231 // TODO: Give this some more thought
221232 // TODO: Is TRUNCATE better?
@@ -222,7 +233,7 @@
223234 $dbw->delete( 'msg_resource', '*', __METHOD__ );
224235 $dbw->delete( 'msg_resource_links', '*', __METHOD__ );
225236 }
226 -
 237+
227238 /**
228239 * Create an update queue for updateMessage()
229240 * @param $key string Message key
@@ -231,6 +242,7 @@
232243 */
233244 private static function getUpdatesForMessage( $key, $prevUpdates = null ) {
234245 $dbw = wfGetDb( DB_MASTER );
 246+
235247 if ( is_null( $prevUpdates ) ) {
236248 // Fetch all blobs referencing $key
237249 $res = $dbw->select(
@@ -241,23 +253,25 @@
242254 );
243255 } else {
244256 // Refetch the blobs referenced by $prevUpdates
245 -
 257+
246258 // Reorganize the (resource, lang) pairs in the format
247259 // expected by makeWhereFrom2d()
248260 $twoD = array();
 261+
249262 foreach ( $prevUpdates as $update ) {
250263 $twoD[$update['resource']][$update['lang']] = true;
251264 }
252 -
 265+
253266 $res = $dbw->select( 'msg_resource',
254267 array( 'mr_resource', 'mr_lang', 'mr_blob', 'mr_timestamp' ),
255268 $dbw->makeWhereFrom2d( $twoD, 'mr_resource', 'mr_lang' ),
256269 __METHOD__
257270 );
258271 }
259 -
 272+
260273 // Build the new updates queue
261274 $updates = array();
 275+
262276 foreach ( $res as $row ) {
263277 $updates[] = array(
264278 'resource' => $row->mr_resource,
@@ -267,9 +281,10 @@
268282 $key, $row->mr_lang )
269283 );
270284 }
 285+
271286 return $updates;
272287 }
273 -
 288+
274289 /**
275290 * Reencode a message blob with the updated value for a message
276291 * @param $blob string Message blob (JSON object)
@@ -280,9 +295,10 @@
281296 private static function reencodeBlob( $blob, $key, $lang ) {
282297 $decoded = FormatJson::decode( $blob, true );
283298 $decoded[$key] = wfMsgExt( $key, array( 'language' => $lang ) );
 299+
284300 return FormatJson::encode( $decoded );
285301 }
286 -
 302+
287303 /**
288304 * Get the message blobs for a set of modules from the database.
289305 * Modules whose blobs are not in the database are silently dropped.
@@ -297,6 +313,7 @@
298314 array( 'mr_resource' => $modules, 'mr_lang' => $lang ),
299315 __METHOD__
300316 );
 317+
301318 foreach ( $res as $row ) {
302319 $module = ResourceLoader::getModule( $row->mr_resource );
303320 if ( !$module ) {
@@ -309,9 +326,10 @@
310327 $retval[$row->mr_resource] = $row->mr_blob;
311328 }
312329 }
 330+
313331 return $retval;
314332 }
315 -
 333+
316334 /**
317335 * Generate the message blob for a given module in a given language.
318336 * @param $module string Module name
@@ -321,9 +339,11 @@
322340 private static function generateMessageBlob( $module, $lang ) {
323341 $mod = ResourceLoader::getModule( $module );
324342 $messages = array();
 343+
325344 foreach ( $mod->getMessages() as $key ) {
326345 $messages[$key] = wfMsgExt( $key, array( 'language' => $lang ) );
327346 }
 347+
328348 return FormatJson::encode( $messages );
329349 }
330350 }
Index: trunk/phase3/includes/CSSJanus.php
@@ -20,10 +20,10 @@
2121 /**
2222 * This is a PHP port of CSSJanus, a utility that transforms CSS style sheets
2323 * written for LTR to RTL.
24 - *
 24+ *
2525 * The original Python version of CSSJanus is Copyright 2008 by Google Inc. and
26 - * is distributed under the Apache license.
27 - *
 26+ * is distributed under the Apache license.
 27+ *
2828 * Original code: http://code.google.com/p/cssjanus/source/browse/trunk/cssjanus.py
2929 * License of original code: http://code.google.com/p/cssjanus/source/browse/trunk/LICENSE
3030 * @author Roan Kattouw
@@ -55,7 +55,6 @@
5656 'lookbehind_not_letter' => '(?<![a-zA-Z])',
5757 'chars_within_selector' => '[^\}]*?',
5858 'noflip_annotation' => '\/\*\s*@noflip\s*\*\/',
59 -
6059 'noflip_single' => null,
6160 'noflip_class' => null,
6261 'comment' => '/\/\*[^*]*\*+([^\/*][^*]*\*+)*\//',
@@ -74,7 +73,7 @@
7574 'bg_horizontal_percentage' => null,
7675 'bg_horizontal_percentage_x' => null,
7776 );
78 -
 77+
7978 /**
8079 * Build patterns we can't define above because they depend on other patterns.
8180 */
@@ -83,6 +82,7 @@
8483 // Patterns have already been built
8584 return;
8685 }
 86+
8787 $patterns =& self::$patterns;
8888 $patterns['escape'] = "(?:{$patterns['unicode']}|\\[^\r\n\f0-9a-f])";
8989 $patterns['nmstart'] = "(?:[_a-z]|{$patterns['nonAscii']}|{$patterns['escape']})";
@@ -95,7 +95,6 @@
9696 $patterns['lookahead_not_open_brace'] = "(?!({$patterns['nmchar']}|\r?\n|\s|#|\:|\.|\,|\+|>)*?{)";
9797 $patterns['lookahead_not_closing_paren'] = "(?!{$patterns['url_chars']}?{$patterns['valid_after_uri_chars']}\))";
9898 $patterns['lookahead_for_closing_paren'] = "(?={$patterns['url_chars']}?{$patterns['valid_after_uri_chars']}\))";
99 -
10099 $patterns['noflip_single'] = "/({$patterns['noflip_annotation']}{$patterns['lookahead_not_open_brace']}[^;}]+;?)/i";
101100 $patterns['noflip_class'] = "/({$patterns['noflip_annotation']}{$patterns['chars_within_selector']}})/i";
102101 $patterns['body_direction_ltr'] = "/({$patterns['body_selector']}{$patterns['chars_within_selector']}{$patterns['direction']})ltr/i";
@@ -115,7 +114,7 @@
116115 $patterns['bg_horizontal_percentage'] = "/(background(?:-position)?\s*:\s*[^%]*?)({$patterns['num']})(%\s*(?:{$patterns['quantity']}|{$patterns['ident']}))/";
117116 $patterns['bg_horizontal_percentage_x'] = "/(background-position-x\s*:\s*)({$patterns['num']})(%)/";
118117 }
119 -
 118+
120119 /**
121120 * Transform an LTR stylesheet to RTL
122121 * @param string $css Stylesheet to transform
@@ -126,28 +125,29 @@
127126 public static function transform( $css, $swapLtrRtlInURL = false, $swapLeftRightInURL = false ) {
128127 // We wrap tokens in ` , not ~ like the original implementation does.
129128 // This was done because ` is not a legal character in CSS and can only
130 - // occur in URLs, where we escape it to %60 before inserting our tokens.
 129+ // occur in URLs, where we escape it to %60 before inserting our tokens.
131130 $css = str_replace( '`', '%60', $css );
132 -
 131+
133132 self::buildPatterns();
134 -
 133+
135134 // Tokenize single line rules with /* @noflip */
136135 $noFlipSingle = new CSSJanus_Tokenizer( self::$patterns['noflip_single'], '`NOFLIP_SINGLE`' );
137136 $css = $noFlipSingle->tokenize( $css );
138 -
 137+
139138 // Tokenize class rules with /* @noflip */
140139 $noFlipClass = new CSSJanus_Tokenizer( self::$patterns['noflip_class'], '`NOFLIP_CLASS`' );
141140 $css = $noFlipClass->tokenize( $css );
142 -
 141+
143142 // Tokenize comments
144143 $comments = new CSSJanus_Tokenizer( self::$patterns['comment'], '`C`' );
145144 $css = $comments->tokenize( $css );
146 -
 145+
147146 // LTR->RTL fixes start here
148147 $css = self::fixBodyDirection( $css );
149148 if ( $swapLtrRtlInURL ) {
150149 $css = self::fixLtrRtlInURL( $css );
151150 }
 151+
152152 if ( $swapLeftRightInURL ) {
153153 $css = self::fixLeftRightInURL( $css );
154154 }
@@ -155,18 +155,19 @@
156156 $css = self::fixCursorProperties( $css );
157157 $css = self::fixFourPartNotation( $css );
158158 $css = self::fixBackgroundPosition( $css );
159 -
 159+
160160 // Detokenize stuff we tokenized before
161161 $css = $comments->detokenize( $css );
162162 $css = $noFlipClass->detokenize( $css );
163163 $css = $noFlipSingle->detokenize( $css );
 164+
164165 return $css;
165166 }
166 -
 167+
167168 /**
168169 * Replace direction: ltr; with direction: rtl; and vice versa, but *only*
169170 * those inside a body { .. } selector.
170 - *
 171+ *
171172 * Unlike the original implementation, this function doesn't suffer from
172173 * the bug causing "body\n{\ndirection: ltr;\n}" to be missed.
173174 * See http://code.google.com/p/cssjanus/issues/detail?id=15
@@ -176,9 +177,10 @@
177178 '$1' . self::$patterns['tmpToken'], $css );
178179 $css = preg_replace( self::$patterns['body_direction_rtl'], '$1ltr', $css );
179180 $css = str_replace( self::$patterns['tmpToken'], 'rtl', $css );
 181+
180182 return $css;
181183 }
182 -
 184+
183185 /**
184186 * Replace 'ltr' with 'rtl' and vice versa in background URLs
185187 */
@@ -186,9 +188,10 @@
187189 $css = preg_replace( self::$patterns['ltr_in_url'], self::$patterns['tmpToken'], $css );
188190 $css = preg_replace( self::$patterns['rtl_in_url'], 'ltr', $css );
189191 $css = str_replace( self::$patterns['tmpToken'], 'rtl', $css );
 192+
190193 return $css;
191194 }
192 -
 195+
193196 /**
194197 * Replace 'left' with 'right' and vice versa in background URLs
195198 */
@@ -196,9 +199,10 @@
197200 $css = preg_replace( self::$patterns['left_in_url'], self::$patterns['tmpToken'], $css );
198201 $css = preg_replace( self::$patterns['right_in_url'], 'left', $css );
199202 $css = str_replace( self::$patterns['tmpToken'], 'right', $css );
 203+
200204 return $css;
201205 }
202 -
 206+
203207 /**
204208 * Flip rules like left: , padding-right: , etc.
205209 */
@@ -206,9 +210,10 @@
207211 $css = preg_replace( self::$patterns['left'], self::$patterns['tmpToken'], $css );
208212 $css = preg_replace( self::$patterns['right'], 'left', $css );
209213 $css = str_replace( self::$patterns['tmpToken'], 'right', $css );
 214+
210215 return $css;
211216 }
212 -
 217+
213218 /**
214219 * Flip East and West in rules like cursor: nw-resize;
215220 */
@@ -217,13 +222,14 @@
218223 '$1' . self::$patterns['tmpToken'], $css );
219224 $css = preg_replace( self::$patterns['cursor_west'], '$1e-resize', $css );
220225 $css = str_replace( self::$patterns['tmpToken'], 'w-resize', $css );
 226+
221227 return $css;
222228 }
223 -
 229+
224230 /**
225231 * Swap the second and fourth parts in four-part notation rules like
226232 * padding: 1px 2px 3px 4px;
227 - *
 233+ *
228234 * Unlike the original implementation, this function doesn't suffer from
229235 * the bug where whitespace is not preserved when flipping four-part rules
230236 * and four-part color rules with multiple whitespace characters between
@@ -233,27 +239,29 @@
234240 private static function fixFourPartNotation( $css ) {
235241 $css = preg_replace( self::$patterns['four_notation_quantity'], '$1$2$7$4$5$6$3', $css );
236242 $css = preg_replace( self::$patterns['four_notation_color'], '$1$2$3$8$5$6$7$4', $css );
 243+
237244 return $css;
238245 }
239 -
 246+
240247 /**
241 - * Flip horizontal background percentages.
 248+ * Flip horizontal background percentages.
242249 */
243250 private static function fixBackgroundPosition( $css ) {
244251 $css = preg_replace_callback( self::$patterns['bg_horizontal_percentage'],
245252 array( 'self', 'calculateNewBackgroundPosition' ), $css );
246253 $css = preg_replace_callback( self::$patterns['bg_horizontal_percentage_x'],
247254 array( 'self', 'calculateNewBackgroundPosition' ), $css );
 255+
248256 return $css;
249257 }
250 -
 258+
251259 /**
252 - * Callback for calculateNewBackgroundPosition()
 260+ * Callback for calculateNewBackgroundPosition()
253261 */
254262 private static function calculateNewBackgroundPosition( $matches ) {
255263 return $matches[1] . ( 100 - $matches[2] ) . $matches[3];
256264 }
257 -}
 265+}
258266
259267 /**
260268 * Utility class used by CSSJanus that tokenizes and untokenizes things we want
@@ -263,7 +271,7 @@
264272 class CSSJanus_Tokenizer {
265273 private $regex, $token;
266274 private $originals;
267 -
 275+
268276 /**
269277 * Constructor
270278 * @param $regex string Regular expression whose matches to replace by a token.
@@ -274,22 +282,22 @@
275283 $this->token = $token;
276284 $this->originals = array();
277285 }
278 -
 286+
279287 /**
280288 * Replace all occurrences of $regex in $str with a token and remember
281 - * the original strings.
 289+ * the original strings.
282290 * @param $str string String to tokenize
283291 * @return string Tokenized string
284292 */
285293 public function tokenize( $str ) {
286294 return preg_replace_callback( $this->regex, array( $this, 'tokenizeCallback' ), $str );
287295 }
288 -
 296+
289297 private function tokenizeCallback( $matches ) {
290298 $this->originals[] = $matches[0];
291299 return $this->token;
292300 }
293 -
 301+
294302 /**
295303 * Replace tokens with their originals. If multiple strings were tokenized, it's important they be
296304 * detokenized in exactly the SAME ORDER.
@@ -303,11 +311,11 @@
304312 return preg_replace_callback( '/' . preg_quote( $this->token, '/' ) . '/',
305313 array( $this, 'detokenizeCallback' ), $str );
306314 }
307 -
 315+
308316 private function detokenizeCallback( $matches ) {
309317 $retval = current( $this->originals );
310318 next( $this->originals );
 319+
311320 return $retval;
312321 }
313 -
314 -}
\ No newline at end of file
 322+}
Index: trunk/phase3/includes/ResourceLoaderModule.php
@@ -14,7 +14,7 @@
1515 * with this program; if not, write to the Free Software Foundation, Inc.,
1616 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
1717 * http://www.gnu.org/copyleft/gpl.html
18 - *
 18+ *
1919 * @author Trevor Parscal
2020 * @author Roan Kattouw
2121 */
@@ -23,13 +23,12 @@
2424 * Interface for resource loader modules, with name registration and maxage functionality.
2525 */
2626 abstract class ResourceLoaderModule {
27 -
2827 /* Protected Members */
29 -
 28+
3029 protected $name = null;
31 -
 30+
3231 /* Methods */
33 -
 32+
3433 /**
3534 * Get this module's name. This is set when the module is registered
3635 * with ResourceLoader::register()
@@ -38,7 +37,7 @@
3938 public function getName() {
4039 return $this->name;
4140 }
42 -
 41+
4342 /**
4443 * Set this module's name. This is called by ResourceLodaer::register()
4544 * when registering the module. Other code should not call this.
@@ -47,7 +46,7 @@
4847 public function setName( $name ) {
4948 $this->name = $name;
5049 }
51 -
 50+
5251 /**
5352 * The maximum number of seconds to cache this module for in the
5453 * client-side (browser) cache. Override this only if you have a good
@@ -58,7 +57,7 @@
5958 global $wgResourceLoaderClientMaxage;
6059 return $wgResourceLoaderClientMaxage;
6160 }
62 -
 61+
6362 /**
6463 * The maximum number of seconds to cache this module for in the
6564 * server-side (Squid / proxy) cache. Override this only if you have a
@@ -76,9 +75,9 @@
7776 public function getFlip( $context ) {
7877 return $context->getDirection() === 'rtl';
7978 }
80 -
 79+
8180 /* Abstract Methods */
82 -
 81+
8382 /**
8483 * Get all JS for this module for a given language and skin.
8584 * Includes all relevant JS except loader scripts.
@@ -88,14 +87,14 @@
8988 * @return string JS
9089 */
9190 public abstract function getScript( ResourceLoaderContext $context );
92 -
 91+
9392 /**
9493 * Get all CSS for this module for a given skin.
9594 * @param $skin string Skin name
9695 * @return string CSS
9796 */
9897 public abstract function getStyle( ResourceLoaderContext $context );
99 -
 98+
10099 /**
101100 * Get the messages needed for this module.
102101 *
@@ -103,13 +102,13 @@
104103 * @return array of message keys. Keys may occur more than once
105104 */
106105 public abstract function getMessages();
107 -
 106+
108107 /**
109108 * Get the loader JS for this module, if set.
110109 * @return mixed Loader JS (string) or false if no custom loader set
111110 */
112111 public abstract function getLoaderScript();
113 -
 112+
114113 /**
115114 * Get a list of modules this module depends on.
116115 *
@@ -126,7 +125,7 @@
127126 * @return array Array of module names (strings)
128127 */
129128 public abstract function getDependencies();
130 -
 129+
131130 /**
132131 * Get this module's last modification timestamp for a given
133132 * combination of language, skin and debug mode flag. This is typically
@@ -145,9 +144,8 @@
146145 * Module based on local JS/CSS files. This is the most common type of module.
147146 */
148147 class ResourceLoaderFileModule extends ResourceLoaderModule {
149 -
150148 /* Protected Members */
151 -
 149+
152150 protected $scripts = array();
153151 protected $styles = array();
154152 protected $messages = array();
@@ -158,24 +156,24 @@
159157 protected $skinStyles = array();
160158 protected $loaders = array();
161159 protected $parameters = array();
162 -
 160+
163161 // In-object cache for file dependencies
164162 protected $fileDeps = array();
165163 // In-object cache for mtime
166164 protected $modifiedTime = array();
167 -
 165+
168166 /* Methods */
169 -
 167+
170168 /**
171169 * Construct a new module from an options array.
172170 *
173171 * @param $options array Options array. If empty, an empty module will be constructed
174 - *
 172+ *
175173 * $options format:
176174 * array(
177175 * // Required module options (mutually exclusive)
178176 * 'scripts' => 'dir/script.js' | array( 'dir/script1.js', 'dir/script2.js' ... ),
179 - *
 177+ *
180178 * // Optional module options
181179 * 'languageScripts' => array(
182180 * '[lang name]' => 'dir/lang.js' | '[lang name]' => array( 'dir/lang1.js', 'dir/lang2.js' ... )
@@ -183,7 +181,7 @@
184182 * ),
185183 * 'skinScripts' => 'dir/skin.js' | array( 'dir/skin1.js', 'dir/skin2.js' ... ),
186184 * 'debugScripts' => 'dir/debug.js' | array( 'dir/debug1.js', 'dir/debug2.js' ... ),
187 - *
 185+ *
188186 * // Non-raw module options
189187 * 'dependencies' => 'module' | array( 'module1', 'module2' ... )
190188 * 'loaderScripts' => 'dir/loader.js' | array( 'dir/loader1.js', 'dir/loader2.js' ... ),
@@ -228,7 +226,7 @@
229227 }
230228 }
231229 }
232 -
 230+
233231 /**
234232 * Add script files to this module. In order to be valid, a module
235233 * must contain at least one script file.
@@ -237,7 +235,7 @@
238236 public function addScripts( $scripts ) {
239237 $this->scripts = array_merge( $this->scripts, (array)$scripts );
240238 }
241 -
 239+
242240 /**
243241 * Add style (CSS) files to this module.
244242 * @param $styles mixed Path to CSS file (string) or array of paths
@@ -245,7 +243,7 @@
246244 public function addStyles( $styles ) {
247245 $this->styles = array_merge( $this->styles, (array)$styles );
248246 }
249 -
 247+
250248 /**
251249 * Add messages to this module.
252250 * @param $messages mixed Message key (string) or array of message keys
@@ -253,7 +251,7 @@
254252 public function addMessages( $messages ) {
255253 $this->messages = array_merge( $this->messages, (array)$messages );
256254 }
257 -
 255+
258256 /**
259257 * Add dependencies. Dependency information is taken into account when
260258 * loading a module on the client side. When adding a module on the
@@ -271,7 +269,7 @@
272270 public function addDependencies( $dependencies ) {
273271 $this->dependencies = array_merge( $this->dependencies, (array)$dependencies );
274272 }
275 -
 273+
276274 /**
277275 * Add debug scripts to the module. These scripts are only included
278276 * in debug mode.
@@ -280,7 +278,7 @@
281279 public function addDebugScripts( $scripts ) {
282280 $this->debugScripts = array_merge( $this->debugScripts, (array)$scripts );
283281 }
284 -
 282+
285283 /**
286284 * Add language-specific scripts. These scripts are only included for
287285 * a given language.
@@ -306,7 +304,7 @@
307305 array( $skin => $scripts )
308306 );
309307 }
310 -
 308+
311309 /**
312310 * Add skin-specific CSS. These CSS files are only included for a
313311 * given skin. If there are no skin-specific CSS files for a skin,
@@ -320,7 +318,7 @@
321319 array( $skin => $scripts )
322320 );
323321 }
324 -
 322+
325323 /**
326324 * Add loader scripts. These scripts are loaded on every page and are
327325 * responsible for registering this module using
@@ -337,23 +335,25 @@
338336 public function addLoaders( $scripts ) {
339337 $this->loaders = array_merge( $this->loaders, (array)$scripts );
340338 }
341 -
 339+
342340 public function getScript( ResourceLoaderContext $context ) {
343341 $retval = $this->getPrimaryScript() . "\n" .
344342 $this->getLanguageScript( $context->getLanguage() ) . "\n" .
345343 $this->getSkinScript( $context->getSkin() );
 344+
346345 if ( $context->getDebug() ) {
347346 $retval .= $this->getDebugScript();
348347 }
 348+
349349 return $retval;
350350 }
351 -
 351+
352352 public function getStyle( ResourceLoaderContext $context ) {
353353 $style = $this->getPrimaryStyle() . "\n" . $this->getSkinStyle( $context->getSkin() );
354 -
 354+
355355 // Extract and store the list of referenced files
356356 $files = CSSMin::getLocalFileReferences( $style );
357 -
 357+
358358 // Only store if modified
359359 if ( $files !== $this->getFileDependencies( $context->getSkin() ) ) {
360360 $encFiles = FormatJson::encode( $files );
@@ -365,30 +365,33 @@
366366 'md_deps' => $encFiles,
367367 )
368368 );
369 -
 369+
370370 // Save into memcached
371371 global $wgMemc;
 372+
372373 $key = wfMemcKey( 'resourceloader', 'module_deps', $this->getName(), $context->getSkin() );
373374 $wgMemc->set( $key, $encFiles );
374375 }
 376+
375377 return $style;
376378 }
377 -
 379+
378380 public function getMessages() {
379381 return $this->messages;
380382 }
381 -
 383+
382384 public function getDependencies() {
383385 return $this->dependencies;
384386 }
385 -
 387+
386388 public function getLoaderScript() {
387389 if ( count( $this->loaders ) == 0 ) {
388390 return false;
389391 }
 392+
390393 return self::concatScripts( $this->loaders );
391394 }
392 -
 395+
393396 /**
394397 * Get the last modified timestamp of this module, which is calculated
395398 * as the highest last modified timestamp of its constituent files and
@@ -405,7 +408,7 @@
406409 if ( isset( $this->modifiedTime[$context->getHash()] ) ) {
407410 return $this->modifiedTime[$context->getHash()];
408411 }
409 -
 412+
410413 $files = array_merge(
411414 $this->scripts,
412415 $this->styles,
@@ -417,8 +420,9 @@
418421 $this->loaders,
419422 $this->getFileDependencies( $context->getSkin() )
420423 );
 424+
421425 $filesMtime = max( array_map( 'filemtime', array_map( array( __CLASS__, 'remapFilename' ), $files ) ) );
422 -
 426+
423427 // Get the mtime of the message blob
424428 // TODO: This timestamp is queried a lot and queried separately for each module. Maybe it should be put in memcached?
425429 $dbr = wfGetDb( DB_SLAVE );
@@ -428,13 +432,13 @@
429433 ), __METHOD__
430434 );
431435 $msgBlobMtime = $msgBlobMtime ? wfTimestamp( TS_UNIX, $msgBlobMtime ) : 0;
432 -
 436+
433437 $this->modifiedTime[$context->getHash()] = max( $filesMtime, $msgBlobMtime );
434438 return $this->modifiedTime[$context->getHash()];
435439 }
436 -
 440+
437441 /* Protected Members */
438 -
 442+
439443 /**
440444 * Get the primary JS for this module. This is pulled from the
441445 * script files added through addScripts()
@@ -443,7 +447,7 @@
444448 protected function getPrimaryScript() {
445449 return self::concatScripts( $this->scripts );
446450 }
447 -
 451+
448452 /**
449453 * Get the primary CSS for this module. This is pulled from the CSS
450454 * files added through addStyles()
@@ -452,7 +456,7 @@
453457 protected function getPrimaryStyle() {
454458 return self::concatStyles( $this->styles );
455459 }
456 -
 460+
457461 /**
458462 * Get the debug JS for this module. This is pulled from the script
459463 * files added through addDebugScripts()
@@ -461,7 +465,7 @@
462466 protected function getDebugScript() {
463467 return self::concatScripts( $this->debugScripts );
464468 }
465 -
 469+
466470 /**
467471 * Get the language-specific JS for a given language. This is pulled
468472 * from the language-specific script files added through addLanguageScripts()
@@ -473,7 +477,7 @@
474478 }
475479 return self::concatScripts( $this->languageScripts[$lang] );
476480 }
477 -
 481+
478482 /**
479483 * Get the skin-specific JS for a given skin. This is pulled from the
480484 * skin-specific JS files added through addSkinScripts()
@@ -482,7 +486,7 @@
483487 protected function getSkinScript( $skin ) {
484488 return self::concatScripts( self::getSkinFiles( $skin, $this->skinScripts ) );
485489 }
486 -
 490+
487491 /**
488492 * Get the skin-specific CSS for a given skin. This is pulled from the
489493 * skin-specific CSS files added through addSkinStyles()
@@ -491,7 +495,7 @@
492496 protected function getSkinStyle( $skin ) {
493497 return self::concatStyles( self::getSkinFiles( $skin, $this->skinStyles ) );
494498 }
495 -
 499+
496500 /**
497501 * Helper function to get skin-specific data from an array.
498502 * @param $skin string Skin name
@@ -500,14 +504,16 @@
501505 */
502506 protected static function getSkinFiles( $skin, $map ) {
503507 $retval = array();
 508+
504509 if ( isset( $map[$skin] ) && $map[$skin] ) {
505510 $retval = $map[$skin];
506511 } else if ( isset( $map['default'] ) ) {
507512 $retval = $map['default'];
508513 }
 514+
509515 return $retval;
510516 }
511 -
 517+
512518 /**
513519 * Get the files this module depends on indirectly for a given skin.
514520 * Currently these are only image files referenced by the module's CSS.
@@ -519,12 +525,13 @@
520526 if ( isset( $this->fileDeps[$skin] ) ) {
521527 return $this->fileDeps[$skin];
522528 }
523 -
 529+
524530 // Now try memcached
525531 global $wgMemc;
 532+
526533 $key = wfMemcKey( 'resourceloader', 'module_deps', $this->getName(), $skin );
527534 $deps = $wgMemc->get( $key );
528 -
 535+
529536 if ( !$deps ) {
530537 $dbr = wfGetDb( DB_SLAVE );
531538 $deps = $dbr->selectField( 'module_deps', 'md_deps', array(
@@ -537,10 +544,12 @@
538545 }
539546 $wgMemc->set( $key, $deps );
540547 }
 548+
541549 $this->fileDeps = FormatJson::decode( $deps, true );
 550+
542551 return $this->fileDeps;
543552 }
544 -
 553+
545554 /**
546555 * Get the contents of a set of files and concatenate them, with
547556 * newlines in between. Each file is used only once.
@@ -550,7 +559,7 @@
551560 protected static function concatScripts( $files ) {
552561 return implode( "\n", array_map( 'file_get_contents', array_map( array( __CLASS__, 'remapFilename' ), array_unique( (array) $files ) ) ) );
553562 }
554 -
 563+
555564 /**
556565 * Get the contents of a set of CSS files, remap then and concatenate
557566 * them, with newlines in between. Each file is used only once.
@@ -560,7 +569,7 @@
561570 protected static function concatStyles( $files ) {
562571 return implode( "\n", array_map( array( __CLASS__, 'remapStyle' ), array_unique( (array) $files ) ) );
563572 }
564 -
 573+
565574 /**
566575 * Remap a relative to $IP. Used as a callback for array_map()
567576 * @param $file string File name
@@ -568,9 +577,10 @@
569578 */
570579 protected static function remapFilename( $file ) {
571580 global $IP;
 581+
572582 return "$IP/$file";
573583 }
574 -
 584+
575585 /**
576586 * Get the contents of a CSS file and run it through CSSMin::remap().
577587 * This wrapper is needed so we can use array_map() in concatStyles()
@@ -587,44 +597,45 @@
588598 * TODO: Add Site CSS functionality too
589599 */
590600 class ResourceLoaderSiteModule extends ResourceLoaderModule {
591 -
592601 /* Protected Members */
593 -
 602+
594603 // In-object cache for modified time
595604 protected $modifiedTime = null;
596 -
 605+
597606 /* Methods */
598 -
 607+
599608 public function getScript( ResourceLoaderContext $context ) {
600609 return Skin::newFromKey( $context->getSkin() )->generateUserJs();
601610 }
602 -
 611+
603612 public function getModifiedTime( ResourceLoaderContext $context ) {
604613 if ( isset( $this->modifiedTime[$context->getHash()] ) ) {
605614 return $this->modifiedTime[$context->getHash()];
606615 }
607 -
 616+
608617 // HACK: We duplicate the message names from generateUserJs()
609618 // here and weird things (i.e. mtime moving backwards) can happen
610619 // when a MediaWiki:Something.js page is deleted
611620 $jsPages = array( Title::makeTitle( NS_MEDIAWIKI, 'Common.js' ),
612621 Title::makeTitle( NS_MEDIAWIKI, ucfirst( $context->getSkin() ) . '.js' )
613622 );
614 -
 623+
615624 // Do batch existence check
616625 // TODO: This would work better if page_touched were loaded by this as well
617626 $lb = new LinkBatch( $jsPages );
618627 $lb->execute();
619 -
 628+
620629 $this->modifiedTime = 1; // wfTimestamp() interprets 0 as "now"
 630+
621631 foreach ( $jsPages as $jsPage ) {
622632 if ( $jsPage->exists() ) {
623633 $this->modifiedTime = max( $this->modifiedTime, wfTimestamp( TS_UNIX, $jsPage->getTouched() ) );
624634 }
625635 }
 636+
626637 return $this->modifiedTime;
627638 }
628 -
 639+
629640 public function getStyle( ResourceLoaderContext $context ) { return ''; }
630641 public function getMessages() { return array(); }
631642 public function getLoaderScript() { return ''; }
@@ -633,17 +644,17 @@
634645
635646
636647 class ResourceLoaderStartUpModule extends ResourceLoaderModule {
637 -
638648 /* Protected Members */
639 -
 649+
640650 protected $modifiedTime = null;
641 -
 651+
642652 /* Methods */
643 -
 653+
644654 public function getScript( ResourceLoaderContext $context ) {
645655 global $IP;
646 -
 656+
647657 $scripts = file_get_contents( "$IP/resources/startup.js" );
 658+
648659 if ( $context->getOnly() === 'scripts' ) {
649660 // Get all module registrations
650661 $registration = ResourceLoader::getModuleRegistrations( $context );
@@ -668,6 +679,7 @@
669680 ), -2 ) )
670681 )
671682 );
 683+
672684 // Build HTML code for loading jquery and mediawiki modules
673685 $loadScript = Html::linkedScript( $context->getServer() . "?$query" );
674686 // Add code to add jquery and mediawiki loading code; only if the current client is compatible
@@ -675,34 +687,39 @@
676688 // Delete the compatible function - it's not needed anymore
677689 $scripts .= "delete window['isCompatible'];";
678690 }
 691+
679692 return $scripts;
680693 }
681 -
 694+
682695 public function getModifiedTime( ResourceLoaderContext $context ) {
683696 global $IP;
 697+
684698 if ( !is_null( $this->modifiedTime ) ) {
685699 return $this->modifiedTime;
686700 }
 701+
687702 // HACK getHighestModifiedTime() calls this function, so protect against infinite recursion
688703 $this->modifiedTime = filemtime( "$IP/resources/startup.js" );
689704 $this->modifiedTime = ResourceLoader::getHighestModifiedTime( $context );
690705 return $this->modifiedTime;
691706 }
692 -
 707+
693708 public function getClientMaxage() {
694709 return 300; // 5 minutes
695710 }
696 -
 711+
697712 public function getServerMaxage() {
698713 return 300; // 5 minutes
699714 }
700 -
 715+
701716 public function getStyle( ResourceLoaderContext $context ) { return ''; }
 717+
702718 public function getFlip( $context ) {
703719 global $wgContLang;
 720+
704721 return $wgContLang->getDir() !== $context->getDirection();
705722 }
706723 public function getMessages() { return array(); }
707724 public function getLoaderScript() { return ''; }
708725 public function getDependencies() { return array(); }
709 -}
\ No newline at end of file
 726+}
Index: trunk/phase3/load.php
@@ -22,7 +22,7 @@
2323 * @author Trevor Parscal
2424 *
2525 */
26 -
 26+
2727 require ( dirname( __FILE__ ) . '/includes/WebStart.php' );
2828 wfProfileIn( 'load.php' );
2929
@@ -51,4 +51,4 @@
5252 wfLogProfilingData();
5353
5454 // Shut down the database
55 -wfGetLBFactory()->shutdown();
\ No newline at end of file
 55+wfGetLBFactory()->shutdown();

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r72349Merging resourceloader branch into trunk. Full documentation is at http://www...catrope04:00, 4 September 2010

Status & tagging log