MediaWiki
REL1_21
|
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 00288 public function getDependencies() { 00289 // Stub, override expected 00290 return array(); 00291 } 00292 00298 public function getTargets() { 00299 return $this->targets; 00300 } 00301 00309 public function getFileDependencies( $skin ) { 00310 // Try in-object cache first 00311 if ( isset( $this->fileDeps[$skin] ) ) { 00312 return $this->fileDeps[$skin]; 00313 } 00314 00315 $dbr = wfGetDB( DB_SLAVE ); 00316 $deps = $dbr->selectField( 'module_deps', 'md_deps', array( 00317 'md_module' => $this->getName(), 00318 'md_skin' => $skin, 00319 ), __METHOD__ 00320 ); 00321 if ( !is_null( $deps ) ) { 00322 $this->fileDeps[$skin] = (array) FormatJson::decode( $deps, true ); 00323 } else { 00324 $this->fileDeps[$skin] = array(); 00325 } 00326 return $this->fileDeps[$skin]; 00327 } 00328 00335 public function setFileDependencies( $skin, $deps ) { 00336 $this->fileDeps[$skin] = $deps; 00337 } 00338 00345 public function getMsgBlobMtime( $lang ) { 00346 if ( !isset( $this->msgBlobMtime[$lang] ) ) { 00347 if ( !count( $this->getMessages() ) ) { 00348 return 0; 00349 } 00350 00351 $dbr = wfGetDB( DB_SLAVE ); 00352 $msgBlobMtime = $dbr->selectField( 'msg_resource', 'mr_timestamp', array( 00353 'mr_resource' => $this->getName(), 00354 'mr_lang' => $lang 00355 ), __METHOD__ 00356 ); 00357 // If no blob was found, but the module does have messages, that means we need 00358 // to regenerate it. Return NOW 00359 if ( $msgBlobMtime === false ) { 00360 $msgBlobMtime = wfTimestampNow(); 00361 } 00362 $this->msgBlobMtime[$lang] = wfTimestamp( TS_UNIX, $msgBlobMtime ); 00363 } 00364 return $this->msgBlobMtime[$lang]; 00365 } 00366 00373 public function setMsgBlobMtime( $lang, $mtime ) { 00374 $this->msgBlobMtime[$lang] = $mtime; 00375 } 00376 00377 /* Abstract Methods */ 00378 00393 public function getModifiedTime( ResourceLoaderContext $context ) { 00394 // 0 would mean now 00395 return 1; 00396 } 00397 00407 public function isKnownEmpty( ResourceLoaderContext $context ) { 00408 return false; 00409 } 00410 00412 private static $jsParser; 00413 private static $parseCacheVersion = 1; 00414 00423 protected function validateScriptFile( $fileName, $contents ) { 00424 global $wgResourceLoaderValidateJS; 00425 if ( $wgResourceLoaderValidateJS ) { 00426 // Try for cache hit 00427 // Use CACHE_ANYTHING since filtering is very slow compared to DB queries 00428 $key = wfMemcKey( 'resourceloader', 'jsparse', self::$parseCacheVersion, md5( $contents ) ); 00429 $cache = wfGetCache( CACHE_ANYTHING ); 00430 $cacheEntry = $cache->get( $key ); 00431 if ( is_string( $cacheEntry ) ) { 00432 return $cacheEntry; 00433 } 00434 00435 $parser = self::javaScriptParser(); 00436 try { 00437 $parser->parse( $contents, $fileName, 1 ); 00438 $result = $contents; 00439 } catch ( Exception $e ) { 00440 // We'll save this to cache to avoid having to validate broken JS over and over... 00441 $err = $e->getMessage(); 00442 $result = "throw new Error(" . Xml::encodeJsVar( "JavaScript parse error: $err" ) . ");"; 00443 } 00444 00445 $cache->set( $key, $result ); 00446 return $result; 00447 } else { 00448 return $contents; 00449 } 00450 } 00451 00455 protected static function javaScriptParser() { 00456 if ( !self::$jsParser ) { 00457 self::$jsParser = new JSParser(); 00458 } 00459 return self::$jsParser; 00460 } 00461 00468 protected static function safeFilemtime( $filename ) { 00469 if ( file_exists( $filename ) ) { 00470 return filemtime( $filename ); 00471 } else { 00472 // We only ever map this function on an array if we're gonna call max() after, 00473 // so return our standard minimum timestamps here. This is 1, not 0, because 00474 // wfTimestamp(0) == NOW 00475 return 1; 00476 } 00477 } 00478 }