MediaWiki
REL1_22
|
00001 <?php 00028 abstract class ResourceLoaderModule { 00029 00030 # Type of resource 00031 const TYPE_SCRIPTS = 'scripts'; 00032 const TYPE_STYLES = 'styles'; 00033 const TYPE_MESSAGES = 'messages'; 00034 const TYPE_COMBINED = 'combined'; 00035 00036 # sitewide core module like a skin file or jQuery component 00037 const ORIGIN_CORE_SITEWIDE = 1; 00038 00039 # per-user module generated by the software 00040 const ORIGIN_CORE_INDIVIDUAL = 2; 00041 00042 # sitewide module generated from user-editable files, like MediaWiki:Common.js, or 00043 # modules accessible to multiple users, such as those generated by the Gadgets extension. 00044 const ORIGIN_USER_SITEWIDE = 3; 00045 00046 # per-user module generated from user-editable files, like User:Me/vector.js 00047 const ORIGIN_USER_INDIVIDUAL = 4; 00048 00049 # an access constant; make sure this is kept as the largest number in this group 00050 const ORIGIN_ALL = 10; 00051 00052 # script and style modules form a hierarchy of trustworthiness, with core modules like 00053 # skins and jQuery as most trustworthy, and user scripts as least trustworthy. We can 00054 # limit the types of scripts and styles we allow to load on, say, sensitive special 00055 # pages like Special:UserLogin and Special:Preferences 00056 protected $origin = self::ORIGIN_CORE_SITEWIDE; 00057 00058 /* Protected Members */ 00059 00060 protected $name = null; 00061 protected $targets = array( 'desktop' ); 00062 00063 // In-object cache for file dependencies 00064 protected $fileDeps = array(); 00065 // In-object cache for message blob mtime 00066 protected $msgBlobMtime = array(); 00067 00068 /* Methods */ 00069 00076 public function getName() { 00077 return $this->name; 00078 } 00079 00086 public function setName( $name ) { 00087 $this->name = $name; 00088 } 00089 00097 public function getOrigin() { 00098 return $this->origin; 00099 } 00100 00107 public function setOrigin( $origin ) { 00108 $this->origin = $origin; 00109 } 00110 00115 public function getFlip( $context ) { 00116 global $wgContLang; 00117 00118 return $wgContLang->getDir() !== $context->getDirection(); 00119 } 00120 00128 public function getScript( ResourceLoaderContext $context ) { 00129 // Stub, override expected 00130 return ''; 00131 } 00132 00147 public function getScriptURLsForDebug( ResourceLoaderContext $context ) { 00148 $url = ResourceLoader::makeLoaderURL( 00149 array( $this->getName() ), 00150 $context->getLanguage(), 00151 $context->getSkin(), 00152 $context->getUser(), 00153 $context->getVersion(), 00154 true, // debug 00155 'scripts', // only 00156 $context->getRequest()->getBool( 'printable' ), 00157 $context->getRequest()->getBool( 'handheld' ) 00158 ); 00159 return array( $url ); 00160 } 00161 00168 public function supportsURLLoading() { 00169 return true; 00170 } 00171 00180 public function getStyles( ResourceLoaderContext $context ) { 00181 // Stub, override expected 00182 return array(); 00183 } 00184 00194 public function getStyleURLsForDebug( ResourceLoaderContext $context ) { 00195 $url = ResourceLoader::makeLoaderURL( 00196 array( $this->getName() ), 00197 $context->getLanguage(), 00198 $context->getSkin(), 00199 $context->getUser(), 00200 $context->getVersion(), 00201 true, // debug 00202 'styles', // only 00203 $context->getRequest()->getBool( 'printable' ), 00204 $context->getRequest()->getBool( 'handheld' ) 00205 ); 00206 return array( 'all' => array( $url ) ); 00207 } 00208 00216 public function getMessages() { 00217 // Stub, override expected 00218 return array(); 00219 } 00220 00226 public function getGroup() { 00227 // Stub, override expected 00228 return null; 00229 } 00230 00236 public function getSource() { 00237 // Stub, override expected 00238 return 'local'; 00239 } 00240 00248 public function getPosition() { 00249 return 'bottom'; 00250 } 00251 00259 public function isRaw() { 00260 return false; 00261 } 00262 00268 public function getLoaderScript() { 00269 // Stub, override expected 00270 return false; 00271 } 00272 00283 public function getDependencies() { 00284 // Stub, override expected 00285 return array(); 00286 } 00287 00293 public function getTargets() { 00294 return $this->targets; 00295 } 00296 00304 public function getFileDependencies( $skin ) { 00305 // Try in-object cache first 00306 if ( isset( $this->fileDeps[$skin] ) ) { 00307 return $this->fileDeps[$skin]; 00308 } 00309 00310 $dbr = wfGetDB( DB_SLAVE ); 00311 $deps = $dbr->selectField( 'module_deps', 'md_deps', array( 00312 'md_module' => $this->getName(), 00313 'md_skin' => $skin, 00314 ), __METHOD__ 00315 ); 00316 if ( !is_null( $deps ) ) { 00317 $this->fileDeps[$skin] = (array)FormatJson::decode( $deps, true ); 00318 } else { 00319 $this->fileDeps[$skin] = array(); 00320 } 00321 return $this->fileDeps[$skin]; 00322 } 00323 00330 public function setFileDependencies( $skin, $deps ) { 00331 $this->fileDeps[$skin] = $deps; 00332 } 00333 00340 public function getMsgBlobMtime( $lang ) { 00341 if ( !isset( $this->msgBlobMtime[$lang] ) ) { 00342 if ( !count( $this->getMessages() ) ) { 00343 return 0; 00344 } 00345 00346 $dbr = wfGetDB( DB_SLAVE ); 00347 $msgBlobMtime = $dbr->selectField( 'msg_resource', 'mr_timestamp', array( 00348 'mr_resource' => $this->getName(), 00349 'mr_lang' => $lang 00350 ), __METHOD__ 00351 ); 00352 // If no blob was found, but the module does have messages, that means we need 00353 // to regenerate it. Return NOW 00354 if ( $msgBlobMtime === false ) { 00355 $msgBlobMtime = wfTimestampNow(); 00356 } 00357 $this->msgBlobMtime[$lang] = wfTimestamp( TS_UNIX, $msgBlobMtime ); 00358 } 00359 return $this->msgBlobMtime[$lang]; 00360 } 00361 00368 public function setMsgBlobMtime( $lang, $mtime ) { 00369 $this->msgBlobMtime[$lang] = $mtime; 00370 } 00371 00372 /* Abstract Methods */ 00373 00392 public function getModifiedTime( ResourceLoaderContext $context ) { 00393 // 0 would mean now 00394 return 1; 00395 } 00396 00403 public function getHashMtime( ResourceLoaderContext $context ) { 00404 $hash = $this->getModifiedHash( $context ); 00405 if ( !is_string( $hash ) ) { 00406 return 0; 00407 } 00408 00409 $cache = wfGetCache( CACHE_ANYTHING ); 00410 $key = wfMemcKey( 'resourceloader', 'modulemodifiedhash', $this->getName() ); 00411 00412 $data = $cache->get( $key ); 00413 if ( is_array( $data ) && $data['hash'] === $hash ) { 00414 // Hash is still the same, re-use the timestamp of when we first saw this hash. 00415 return $data['timestamp']; 00416 } 00417 00418 $timestamp = wfTimestamp(); 00419 $cache->set( $key, array( 00420 'hash' => $hash, 00421 'timestamp' => $timestamp, 00422 ) ); 00423 00424 return $timestamp; 00425 } 00426 00434 public function getModifiedHash( ResourceLoaderContext $context ) { 00435 return null; 00436 } 00437 00447 public function isKnownEmpty( ResourceLoaderContext $context ) { 00448 return false; 00449 } 00450 00452 private static $jsParser; 00453 private static $parseCacheVersion = 1; 00454 00463 protected function validateScriptFile( $fileName, $contents ) { 00464 global $wgResourceLoaderValidateJS; 00465 if ( $wgResourceLoaderValidateJS ) { 00466 // Try for cache hit 00467 // Use CACHE_ANYTHING since filtering is very slow compared to DB queries 00468 $key = wfMemcKey( 'resourceloader', 'jsparse', self::$parseCacheVersion, md5( $contents ) ); 00469 $cache = wfGetCache( CACHE_ANYTHING ); 00470 $cacheEntry = $cache->get( $key ); 00471 if ( is_string( $cacheEntry ) ) { 00472 return $cacheEntry; 00473 } 00474 00475 $parser = self::javaScriptParser(); 00476 try { 00477 $parser->parse( $contents, $fileName, 1 ); 00478 $result = $contents; 00479 } catch ( Exception $e ) { 00480 // We'll save this to cache to avoid having to validate broken JS over and over... 00481 $err = $e->getMessage(); 00482 $result = "throw new Error(" . Xml::encodeJsVar( "JavaScript parse error: $err" ) . ");"; 00483 } 00484 00485 $cache->set( $key, $result ); 00486 return $result; 00487 } else { 00488 return $contents; 00489 } 00490 } 00491 00495 protected static function javaScriptParser() { 00496 if ( !self::$jsParser ) { 00497 self::$jsParser = new JSParser(); 00498 } 00499 return self::$jsParser; 00500 } 00501 00508 protected static function safeFilemtime( $filename ) { 00509 if ( file_exists( $filename ) ) { 00510 return filemtime( $filename ); 00511 } else { 00512 // We only ever map this function on an array if we're gonna call max() after, 00513 // so return our standard minimum timestamps here. This is 1, not 0, because 00514 // wfTimestamp(0) == NOW 00515 return 1; 00516 } 00517 } 00518 }