MediaWiki
REL1_20
|
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 00062 // In-object cache for file dependencies 00063 protected $fileDeps = array(); 00064 // In-object cache for message blob mtime 00065 protected $msgBlobMtime = array(); 00066 00067 /* Methods */ 00068 00075 public function getName() { 00076 return $this->name; 00077 } 00078 00085 public function setName( $name ) { 00086 $this->name = $name; 00087 } 00088 00096 public function getOrigin() { 00097 return $this->origin; 00098 } 00099 00106 public function setOrigin( $origin ) { 00107 $this->origin = $origin; 00108 } 00109 00114 public function getFlip( $context ) { 00115 global $wgContLang; 00116 00117 return $wgContLang->getDir() !== $context->getDirection(); 00118 } 00119 00127 public function getScript( ResourceLoaderContext $context ) { 00128 // Stub, override expected 00129 return ''; 00130 } 00131 00146 public function getScriptURLsForDebug( ResourceLoaderContext $context ) { 00147 $url = ResourceLoader::makeLoaderURL( 00148 array( $this->getName() ), 00149 $context->getLanguage(), 00150 $context->getSkin(), 00151 $context->getUser(), 00152 $context->getVersion(), 00153 true, // debug 00154 'scripts', // only 00155 $context->getRequest()->getBool( 'printable' ), 00156 $context->getRequest()->getBool( 'handheld' ) 00157 ); 00158 return array( $url ); 00159 } 00160 00167 public function supportsURLLoading() { 00168 return true; 00169 } 00170 00179 public function getStyles( ResourceLoaderContext $context ) { 00180 // Stub, override expected 00181 return array(); 00182 } 00183 00193 public function getStyleURLsForDebug( ResourceLoaderContext $context ) { 00194 $url = ResourceLoader::makeLoaderURL( 00195 array( $this->getName() ), 00196 $context->getLanguage(), 00197 $context->getSkin(), 00198 $context->getUser(), 00199 $context->getVersion(), 00200 true, // debug 00201 'styles', // only 00202 $context->getRequest()->getBool( 'printable' ), 00203 $context->getRequest()->getBool( 'handheld' ) 00204 ); 00205 return array( 'all' => array( $url ) ); 00206 } 00207 00215 public function getMessages() { 00216 // Stub, override expected 00217 return array(); 00218 } 00219 00225 public function getGroup() { 00226 // Stub, override expected 00227 return null; 00228 } 00229 00235 public function getSource() { 00236 // Stub, override expected 00237 return 'local'; 00238 } 00239 00247 public function getPosition() { 00248 return 'bottom'; 00249 } 00250 00258 public function isRaw() { 00259 return false; 00260 } 00261 00267 public function getLoaderScript() { 00268 // Stub, override expected 00269 return false; 00270 } 00271 00287 public function getDependencies() { 00288 // Stub, override expected 00289 return array(); 00290 } 00291 00299 public function getFileDependencies( $skin ) { 00300 // Try in-object cache first 00301 if ( isset( $this->fileDeps[$skin] ) ) { 00302 return $this->fileDeps[$skin]; 00303 } 00304 00305 $dbr = wfGetDB( DB_SLAVE ); 00306 $deps = $dbr->selectField( 'module_deps', 'md_deps', array( 00307 'md_module' => $this->getName(), 00308 'md_skin' => $skin, 00309 ), __METHOD__ 00310 ); 00311 if ( !is_null( $deps ) ) { 00312 $this->fileDeps[$skin] = (array) FormatJson::decode( $deps, true ); 00313 } else { 00314 $this->fileDeps[$skin] = array(); 00315 } 00316 return $this->fileDeps[$skin]; 00317 } 00318 00325 public function setFileDependencies( $skin, $deps ) { 00326 $this->fileDeps[$skin] = $deps; 00327 } 00328 00335 public function getMsgBlobMtime( $lang ) { 00336 if ( !isset( $this->msgBlobMtime[$lang] ) ) { 00337 if ( !count( $this->getMessages() ) ) 00338 return 0; 00339 00340 $dbr = wfGetDB( DB_SLAVE ); 00341 $msgBlobMtime = $dbr->selectField( 'msg_resource', 'mr_timestamp', array( 00342 'mr_resource' => $this->getName(), 00343 'mr_lang' => $lang 00344 ), __METHOD__ 00345 ); 00346 // If no blob was found, but the module does have messages, that means we need 00347 // to regenerate it. Return NOW 00348 if ( $msgBlobMtime === false ) { 00349 $msgBlobMtime = wfTimestampNow(); 00350 } 00351 $this->msgBlobMtime[$lang] = wfTimestamp( TS_UNIX, $msgBlobMtime ); 00352 } 00353 return $this->msgBlobMtime[$lang]; 00354 } 00355 00362 public function setMsgBlobMtime( $lang, $mtime ) { 00363 $this->msgBlobMtime[$lang] = $mtime; 00364 } 00365 00366 /* Abstract Methods */ 00367 00382 public function getModifiedTime( ResourceLoaderContext $context ) { 00383 // 0 would mean now 00384 return 1; 00385 } 00386 00396 public function isKnownEmpty( ResourceLoaderContext $context ) { 00397 return false; 00398 } 00399 00400 00402 private static $jsParser; 00403 private static $parseCacheVersion = 1; 00404 00413 protected function validateScriptFile( $fileName, $contents ) { 00414 global $wgResourceLoaderValidateJS; 00415 if ( $wgResourceLoaderValidateJS ) { 00416 // Try for cache hit 00417 // Use CACHE_ANYTHING since filtering is very slow compared to DB queries 00418 $key = wfMemcKey( 'resourceloader', 'jsparse', self::$parseCacheVersion, md5( $contents ) ); 00419 $cache = wfGetCache( CACHE_ANYTHING ); 00420 $cacheEntry = $cache->get( $key ); 00421 if ( is_string( $cacheEntry ) ) { 00422 return $cacheEntry; 00423 } 00424 00425 $parser = self::javaScriptParser(); 00426 try { 00427 $parser->parse( $contents, $fileName, 1 ); 00428 $result = $contents; 00429 } catch (Exception $e) { 00430 // We'll save this to cache to avoid having to validate broken JS over and over... 00431 $err = $e->getMessage(); 00432 $result = "throw new Error(" . Xml::encodeJsVar("JavaScript parse error: $err") . ");"; 00433 } 00434 00435 $cache->set( $key, $result ); 00436 return $result; 00437 } else { 00438 return $contents; 00439 } 00440 } 00441 00445 protected static function javaScriptParser() { 00446 if ( !self::$jsParser ) { 00447 self::$jsParser = new JSParser(); 00448 } 00449 return self::$jsParser; 00450 } 00451 00452 }