summaryrefslogtreecommitdiff
path: root/includes/resourceloader/ResourceLoaderModule.php
diff options
context:
space:
mode:
authorPierre Schmitz <pierre@archlinux.de>2011-12-03 13:29:22 +0100
committerPierre Schmitz <pierre@archlinux.de>2011-12-03 13:29:22 +0100
commitca32f08966f1b51fcb19460f0996bb0c4048e6fe (patch)
treeec04cc15b867bc21eedca904cea9af0254531a11 /includes/resourceloader/ResourceLoaderModule.php
parenta22fbfc60f36f5f7ee10d5ae6fe347340c2ee67c (diff)
Update to MediaWiki 1.18.0
* also update ArchLinux skin to chagnes in MonoBook * Use only css to hide our menu bar when printing
Diffstat (limited to 'includes/resourceloader/ResourceLoaderModule.php')
-rw-r--r--includes/resourceloader/ResourceLoaderModule.php189
1 files changed, 184 insertions, 5 deletions
diff --git a/includes/resourceloader/ResourceLoaderModule.php b/includes/resourceloader/ResourceLoaderModule.php
index 77d230c9..ae1be5af 100644
--- a/includes/resourceloader/ResourceLoaderModule.php
+++ b/includes/resourceloader/ResourceLoaderModule.php
@@ -24,6 +24,34 @@
* Abstraction for resource loader modules, with name registration and maxage functionality.
*/
abstract class ResourceLoaderModule {
+
+ # Type of resource
+ const TYPE_SCRIPTS = 'scripts';
+ const TYPE_STYLES = 'styles';
+ const TYPE_MESSAGES = 'messages';
+ const TYPE_COMBINED = 'combined';
+
+ # sitewide core module like a skin file or jQuery component
+ const ORIGIN_CORE_SITEWIDE = 1;
+
+ # per-user module generated by the software
+ const ORIGIN_CORE_INDIVIDUAL = 2;
+
+ # sitewide module generated from user-editable files, like MediaWiki:Common.js, or
+ # modules accessible to multiple users, such as those generated by the Gadgets extension.
+ const ORIGIN_USER_SITEWIDE = 3;
+
+ # per-user module generated from user-editable files, like User:Me/vector.js
+ const ORIGIN_USER_INDIVIDUAL = 4;
+
+ # an access constant; make sure this is kept as the largest number in this group
+ const ORIGIN_ALL = 10;
+
+ # script and style modules form a hierarchy of trustworthiness, with core modules like
+ # skins and jQuery as most trustworthy, and user scripts as least trustworthy. We can
+ # limit the types of scripts and styles we allow to load on, say, sensitive special
+ # pages like Special:UserLogin and Special:Preferences
+ protected $origin = self::ORIGIN_CORE_SITEWIDE;
/* Protected Members */
@@ -57,10 +85,34 @@ abstract class ResourceLoaderModule {
}
/**
- * Get whether CSS for this module should be flipped
+ * Get this module's origin. This is set when the module is registered
+ * with ResourceLoader::register()
+ *
+ * @return Int ResourceLoaderModule class constant, the subclass default
+ * if not set manuall
+ */
+ public function getOrigin() {
+ return $this->origin;
+ }
+
+ /**
+ * Set this module's origin. This is called by ResourceLodaer::register()
+ * when registering the module. Other code should not call this.
+ *
+ * @param $origin Int origin
+ */
+ public function setOrigin( $origin ) {
+ $this->origin = $origin;
+ }
+
+ /**
+ * @param $context ResourceLoaderContext
+ * @return bool
*/
public function getFlip( $context ) {
- return $context->getDirection() === 'rtl';
+ global $wgContLang;
+
+ return $wgContLang->getDir() !== $context->getDirection();
}
/**
@@ -74,6 +126,44 @@ abstract class ResourceLoaderModule {
// Stub, override expected
return '';
}
+
+ /**
+ * Get the URL or URLs to load for this module's JS in debug mode.
+ * The default behavior is to return a load.php?only=scripts URL for
+ * the module, but file-based modules will want to override this to
+ * load the files directly.
+ *
+ * This function is called only when 1) we're in debug mode, 2) there
+ * is no only= parameter and 3) supportsURLLoading() returns true.
+ * #2 is important to prevent an infinite loop, therefore this function
+ * MUST return either an only= URL or a non-load.php URL.
+ *
+ * @param $context ResourceLoaderContext: Context object
+ * @return Array of URLs
+ */
+ public function getScriptURLsForDebug( ResourceLoaderContext $context ) {
+ global $wgLoadScript; // TODO factor out to ResourceLoader static method and deduplicate from makeResourceLoaderLink()
+ $query = array(
+ 'modules' => $this->getName(),
+ 'only' => 'scripts',
+ 'skin' => $context->getSkin(),
+ 'user' => $context->getUser(),
+ 'debug' => 'true',
+ 'version' => $context->getVersion()
+ );
+ ksort( $query );
+ return array( wfAppendQuery( $wgLoadScript, $query ) . '&*' );
+ }
+
+ /**
+ * Whether this module supports URL loading. If this function returns false,
+ * getScript() will be used even in cases (debug mode, no only param) where
+ * getScriptURLsForDebug() would normally be used instead.
+ * @return bool
+ */
+ public function supportsURLLoading() {
+ return true;
+ }
/**
* Get all CSS for this module for a given skin.
@@ -83,7 +173,30 @@ abstract class ResourceLoaderModule {
*/
public function getStyles( ResourceLoaderContext $context ) {
// Stub, override expected
- return '';
+ return array();
+ }
+
+ /**
+ * Get the URL or URLs to load for this module's CSS in debug mode.
+ * The default behavior is to return a load.php?only=styles URL for
+ * the module, but file-based modules will want to override this to
+ * load the files directly. See also getScriptURLsForDebug()
+ *
+ * @param $context ResourceLoaderContext: Context object
+ * @return Array: array( mediaType => array( URL1, URL2, ... ), ... )
+ */
+ public function getStyleURLsForDebug( ResourceLoaderContext $context ) {
+ global $wgLoadScript; // TODO factor out to ResourceLoader static method and deduplicate from makeResourceLoaderLink()
+ $query = array(
+ 'modules' => $this->getName(),
+ 'only' => 'styles',
+ 'skin' => $context->getSkin(),
+ 'user' => $context->getUser(),
+ 'debug' => 'true',
+ 'version' => $context->getVersion()
+ );
+ ksort( $query );
+ return array( 'all' => array( wfAppendQuery( $wgLoadScript, $query ) . '&*' ) );
}
/**
@@ -107,6 +220,17 @@ abstract class ResourceLoaderModule {
// Stub, override expected
return null;
}
+
+ /**
+ * Where on the HTML page should this module's JS be loaded?
+ * 'top': in the <head>
+ * 'bottom': at the bottom of the <body>
+ *
+ * @return string
+ */
+ public function getPosition() {
+ return 'bottom';
+ }
/**
* Get the loader JS for this module, if set.
@@ -179,7 +303,7 @@ abstract class ResourceLoaderModule {
* Get the last modification timestamp of the message blob for this
* module in a given language.
* @param $lang String: Language code
- * @return Integer: UNIX timestamp, or 0 if no blob found
+ * @return Integer: UNIX timestamp, or 0 if the module doesn't have messages
*/
public function getMsgBlobMtime( $lang ) {
if ( !isset( $this->msgBlobMtime[$lang] ) ) {
@@ -192,7 +316,12 @@ abstract class ResourceLoaderModule {
'mr_lang' => $lang
), __METHOD__
);
- $this->msgBlobMtime[$lang] = $msgBlobMtime ? wfTimestamp( TS_UNIX, $msgBlobMtime ) : 0;
+ // If no blob was found, but the module does have messages, that means we need
+ // to regenerate it. Return NOW
+ if ( $msgBlobMtime === false ) {
+ $msgBlobMtime = wfTimestampNow();
+ }
+ $this->msgBlobMtime[$lang] = wfTimestamp( TS_UNIX, $msgBlobMtime );
}
return $this->msgBlobMtime[$lang];
}
@@ -236,4 +365,54 @@ abstract class ResourceLoaderModule {
public function isKnownEmpty( ResourceLoaderContext $context ) {
return false;
}
+
+
+ /** @var JSParser lazy-initialized; use self::javaScriptParser() */
+ private static $jsParser;
+ private static $parseCacheVersion = 1;
+
+ /**
+ * Validate a given script file; if valid returns the original source.
+ * If invalid, returns replacement JS source that throws an exception.
+ *
+ * @param string $fileName
+ * @param string $contents
+ * @return string JS with the original, or a replacement error
+ */
+ protected function validateScriptFile( $fileName, $contents ) {
+ global $wgResourceLoaderValidateJS;
+ if ( $wgResourceLoaderValidateJS ) {
+ // Try for cache hit
+ // Use CACHE_ANYTHING since filtering is very slow compared to DB queries
+ $key = wfMemcKey( 'resourceloader', 'jsparse', self::$parseCacheVersion, md5( $contents ) );
+ $cache = wfGetCache( CACHE_ANYTHING );
+ $cacheEntry = $cache->get( $key );
+ if ( is_string( $cacheEntry ) ) {
+ return $cacheEntry;
+ }
+
+ $parser = self::javaScriptParser();
+ try {
+ $parser->parse( $contents, $fileName, 1 );
+ $result = $contents;
+ } catch (Exception $e) {
+ // We'll save this to cache to avoid having to validate broken JS over and over...
+ $err = $e->getMessage();
+ $result = "throw new Error(" . Xml::encodeJsVar("JavaScript parse error: $err") . ");";
+ }
+
+ $cache->set( $key, $result );
+ return $result;
+ } else {
+ return $contents;
+ }
+ }
+
+ protected static function javaScriptParser() {
+ if ( !self::$jsParser ) {
+ self::$jsParser = new JSParser();
+ }
+ return self::$jsParser;
+ }
+
}