MediaWiki
REL1_19
|
00001 <?php 00026 abstract class ResourceLoaderModule { 00027 00028 # Type of resource 00029 const TYPE_SCRIPTS = 'scripts'; 00030 const TYPE_STYLES = 'styles'; 00031 const TYPE_MESSAGES = 'messages'; 00032 const TYPE_COMBINED = 'combined'; 00033 00034 # sitewide core module like a skin file or jQuery component 00035 const ORIGIN_CORE_SITEWIDE = 1; 00036 00037 # per-user module generated by the software 00038 const ORIGIN_CORE_INDIVIDUAL = 2; 00039 00040 # sitewide module generated from user-editable files, like MediaWiki:Common.js, or 00041 # modules accessible to multiple users, such as those generated by the Gadgets extension. 00042 const ORIGIN_USER_SITEWIDE = 3; 00043 00044 # per-user module generated from user-editable files, like User:Me/vector.js 00045 const ORIGIN_USER_INDIVIDUAL = 4; 00046 00047 # an access constant; make sure this is kept as the largest number in this group 00048 const ORIGIN_ALL = 10; 00049 00050 # script and style modules form a hierarchy of trustworthiness, with core modules like 00051 # skins and jQuery as most trustworthy, and user scripts as least trustworthy. We can 00052 # limit the types of scripts and styles we allow to load on, say, sensitive special 00053 # pages like Special:UserLogin and Special:Preferences 00054 protected $origin = self::ORIGIN_CORE_SITEWIDE; 00055 00056 /* Protected Members */ 00057 00058 protected $name = null; 00059 00060 // In-object cache for file dependencies 00061 protected $fileDeps = array(); 00062 // In-object cache for message blob mtime 00063 protected $msgBlobMtime = array(); 00064 00065 /* Methods */ 00066 00073 public function getName() { 00074 return $this->name; 00075 } 00076 00083 public function setName( $name ) { 00084 $this->name = $name; 00085 } 00086 00094 public function getOrigin() { 00095 return $this->origin; 00096 } 00097 00104 public function setOrigin( $origin ) { 00105 $this->origin = $origin; 00106 } 00107 00112 public function getFlip( $context ) { 00113 global $wgContLang; 00114 00115 return $wgContLang->getDir() !== $context->getDirection(); 00116 } 00117 00125 public function getScript( ResourceLoaderContext $context ) { 00126 // Stub, override expected 00127 return ''; 00128 } 00129 00144 public function getScriptURLsForDebug( ResourceLoaderContext $context ) { 00145 $url = ResourceLoader::makeLoaderURL( 00146 array( $this->getName() ), 00147 $context->getLanguage(), 00148 $context->getSkin(), 00149 $context->getUser(), 00150 $context->getVersion(), 00151 true, // debug 00152 'scripts', // only 00153 $context->getRequest()->getBool( 'printable' ), 00154 $context->getRequest()->getBool( 'handheld' ) 00155 ); 00156 return array( $url ); 00157 } 00158 00165 public function supportsURLLoading() { 00166 return true; 00167 } 00168 00175 public function getStyles( ResourceLoaderContext $context ) { 00176 // Stub, override expected 00177 return array(); 00178 } 00179 00189 public function getStyleURLsForDebug( ResourceLoaderContext $context ) { 00190 $url = ResourceLoader::makeLoaderURL( 00191 array( $this->getName() ), 00192 $context->getLanguage(), 00193 $context->getSkin(), 00194 $context->getUser(), 00195 $context->getVersion(), 00196 true, // debug 00197 'styles', // only 00198 $context->getRequest()->getBool( 'printable' ), 00199 $context->getRequest()->getBool( 'handheld' ) 00200 ); 00201 return array( 'all' => array( $url ) ); 00202 } 00203 00211 public function getMessages() { 00212 // Stub, override expected 00213 return array(); 00214 } 00215 00221 public function getGroup() { 00222 // Stub, override expected 00223 return null; 00224 } 00225 00231 public function getSource() { 00232 // Stub, override expected 00233 return 'local'; 00234 } 00235 00243 public function getPosition() { 00244 return 'bottom'; 00245 } 00246 00252 public function getLoaderScript() { 00253 // Stub, override expected 00254 return false; 00255 } 00256 00272 public function getDependencies() { 00273 // Stub, override expected 00274 return array(); 00275 } 00276 00284 public function getFileDependencies( $skin ) { 00285 // Try in-object cache first 00286 if ( isset( $this->fileDeps[$skin] ) ) { 00287 return $this->fileDeps[$skin]; 00288 } 00289 00290 $dbr = wfGetDB( DB_SLAVE ); 00291 $deps = $dbr->selectField( 'module_deps', 'md_deps', array( 00292 'md_module' => $this->getName(), 00293 'md_skin' => $skin, 00294 ), __METHOD__ 00295 ); 00296 if ( !is_null( $deps ) ) { 00297 $this->fileDeps[$skin] = (array) FormatJson::decode( $deps, true ); 00298 } else { 00299 $this->fileDeps[$skin] = array(); 00300 } 00301 return $this->fileDeps[$skin]; 00302 } 00303 00310 public function setFileDependencies( $skin, $deps ) { 00311 $this->fileDeps[$skin] = $deps; 00312 } 00313 00320 public function getMsgBlobMtime( $lang ) { 00321 if ( !isset( $this->msgBlobMtime[$lang] ) ) { 00322 if ( !count( $this->getMessages() ) ) 00323 return 0; 00324 00325 $dbr = wfGetDB( DB_SLAVE ); 00326 $msgBlobMtime = $dbr->selectField( 'msg_resource', 'mr_timestamp', array( 00327 'mr_resource' => $this->getName(), 00328 'mr_lang' => $lang 00329 ), __METHOD__ 00330 ); 00331 // If no blob was found, but the module does have messages, that means we need 00332 // to regenerate it. Return NOW 00333 if ( $msgBlobMtime === false ) { 00334 $msgBlobMtime = wfTimestampNow(); 00335 } 00336 $this->msgBlobMtime[$lang] = wfTimestamp( TS_UNIX, $msgBlobMtime ); 00337 } 00338 return $this->msgBlobMtime[$lang]; 00339 } 00340 00347 public function setMsgBlobMtime( $lang, $mtime ) { 00348 $this->msgBlobMtime[$lang] = $mtime; 00349 } 00350 00351 /* Abstract Methods */ 00352 00367 public function getModifiedTime( ResourceLoaderContext $context ) { 00368 // 0 would mean now 00369 return 1; 00370 } 00371 00381 public function isKnownEmpty( ResourceLoaderContext $context ) { 00382 return false; 00383 } 00384 00385 00387 private static $jsParser; 00388 private static $parseCacheVersion = 1; 00389 00398 protected function validateScriptFile( $fileName, $contents ) { 00399 global $wgResourceLoaderValidateJS; 00400 if ( $wgResourceLoaderValidateJS ) { 00401 // Try for cache hit 00402 // Use CACHE_ANYTHING since filtering is very slow compared to DB queries 00403 $key = wfMemcKey( 'resourceloader', 'jsparse', self::$parseCacheVersion, md5( $contents ) ); 00404 $cache = wfGetCache( CACHE_ANYTHING ); 00405 $cacheEntry = $cache->get( $key ); 00406 if ( is_string( $cacheEntry ) ) { 00407 return $cacheEntry; 00408 } 00409 00410 $parser = self::javaScriptParser(); 00411 try { 00412 $parser->parse( $contents, $fileName, 1 ); 00413 $result = $contents; 00414 } catch (Exception $e) { 00415 // We'll save this to cache to avoid having to validate broken JS over and over... 00416 $err = $e->getMessage(); 00417 $result = "throw new Error(" . Xml::encodeJsVar("JavaScript parse error: $err") . ");"; 00418 } 00419 00420 $cache->set( $key, $result ); 00421 return $result; 00422 } else { 00423 return $contents; 00424 } 00425 } 00426 00430 protected static function javaScriptParser() { 00431 if ( !self::$jsParser ) { 00432 self::$jsParser = new JSParser(); 00433 } 00434 return self::$jsParser; 00435 } 00436 00437 }