From 3d958564ecc8f80a0946adb631e4e4fc1bd281b2 Mon Sep 17 00:00:00 2001 From: Michael Dale Date: Thu, 17 Sep 2009 01:19:02 +0000 Subject: [PATCH] * Enhanced OutputPage to support js2 style javascript without scriptloader enabled ** loadGM output ** unique request id based on wikiTitle revision / file time * Moved jsAutoLoadClasses to setup.php ( made conditional ) --- includes/AutoLoader.php | 5 -- includes/OutputPage.php | 143 +++++++++++++++++---------------- includes/Setup.php | 14 ++-- includes/json/FormatJson.php | 8 +- js2/mwEmbed/jsScriptLoader.php | 58 ++++++++----- 5 files changed, 126 insertions(+), 102 deletions(-) diff --git a/includes/AutoLoader.php b/includes/AutoLoader.php index 5051ad389c..6b06a80b99 100644 --- a/includes/AutoLoader.php +++ b/includes/AutoLoader.php @@ -623,11 +623,6 @@ $wgJSAutoloadLocalClasses = array( 'ajaxCategories' => 'js2/ajaxcategories.js', ); -//Include the js2 autoLoadClasses -//@@todo move jsAutoloadLocalClasses.php to post Setup so we have default values and can check the $wgEnableJS2system var -$wgMwEmbedDirectory = "js2/mwEmbed/"; -require_once("$IP/js2/mwEmbed/php/jsAutoloadLocalClasses.php"); - class AutoLoader { /** * autoload - take a class name and attempt to load it diff --git a/includes/OutputPage.php b/includes/OutputPage.php index a5da831e5a..abf33fee1b 100644 --- a/includes/OutputPage.php +++ b/includes/OutputPage.php @@ -16,10 +16,9 @@ class OutputPage { var $mScriptLoaderClassList = array(); - // The most recent revision ID of any wikiPage script that is grouped in the script request - var $mLatestScriptRevID = 0; - var $mScripts = '', $mLinkColours, $mPageLinkTitle = '', $mHeadItems = array(); + var $mInlineMsg = array(); + var $mTemplateIds = array(); var $mAllowUserJs; @@ -119,7 +118,7 @@ class OutputPage { */ function addScriptFile( $file ) { global $wgStylePath, $wgScript, $wgUser; - global $wgJSAutoloadClasses, $wgJSAutoloadLocalClasses, $wgEnableScriptLoader, $wgScriptPath; + global $wgEnableScriptLoader, $wgScriptPath; if( substr( $file, 0, 1 ) == '/' ) { $path = $file; @@ -127,42 +126,41 @@ class OutputPage { $path = "{$wgStylePath}/common/{$file}"; } - if( $wgEnableScriptLoader ) { - if( strpos( $path, $wgScript ) !== false ) { - $reqPath = str_replace( $wgScript . '?', '', $path ); - $reqArgs = explode( '&', $reqPath ); - $reqSet = array(); + // If the class can be determined, use the addScriptClass method + $js_class = $this->getJsClassFromPath( $path ); + if( $js_class ) { + $this->addScriptClass( $js_class ); + return true; + } - foreach( $reqArgs as $arg ) { - list( $key, $var ) = explode( '=', $arg ); - $reqSet[$key] = $var; - } + //do checks for wiki-titles + if( strpos( $path, $wgScript ) !== false ) { + $reqPath = str_replace( $wgScript . '?', '', $path ); + $reqArgs = explode( '&', $reqPath ); + $reqSet = array(); + + foreach( $reqArgs as $arg ) { + list( $key, $var ) = explode( '=', $arg ); + $reqSet[$key] = $var; + } - if( isset( $reqSet['title'] ) && $reqSet != '' ) { + if( isset( $reqSet['title'] ) && $reqSet != '' ) { + $jsTitleClass = 'WT:' . $reqSet['title']; + if( $wgEnableScriptLoader ) { // Extract any extra parameters (for now just skin) $ext_param = ( isset( $reqSet['useskin'] ) && $reqSet['useskin'] != '' ) ? '|useskin=' . ucfirst( $reqSet['useskin'] ) : ''; - $this->mScriptLoaderClassList[] = 'WT:' . $reqSet['title'] . $ext_param ; - // Add the title revision to the key. - // If there is no title, we will just use $wgStyleVersion, - // which should be updated on the relevant commits. - $t = Title::newFromText( $reqSet['title'] ); - if( $t && $t->exists() ) { - if( $t->getLatestRevID() > $this->mLatestScriptRevID ) - $this->mLatestScriptRevID = $t->getLatestRevID(); - } + $this->mScriptLoaderClassList[] = $jsTitleClass . $ext_param ; + return true; + }else{ + $this->addScript( Html::linkedScript( + wfAppendQuery( $path, $this->getURIDparam( $jsTitleClass ) ) + ) + ); return true; } } - - // If the class can be determined, add it to the class list to be loaded later - $js_class = $this->getJsClassFromPath( $path ); - if( $js_class ) { - $this->mScriptLoaderClassList[] = $js_class; - return true; - } } - // If the script loader could not be used, just add the script to the header $this->addScript( Html::linkedScript( wfAppendQuery( $path, $this->getURIDparam() ) ) ); } @@ -171,7 +169,7 @@ class OutputPage { * Add the core scripts that are included on every page, for later output into the header */ function addCoreScripts2Top(){ - global $wgEnableScriptLoader, $wgJSAutoloadLocalClasses, $wgScriptPath, $wgStylePath, $wgEnableJS2system; + global $wgEnableScriptLoader, $wgJSAutoloadLocalClasses, $wgScriptPath, $wgEnableJS2system; // @todo We should deprecate wikibits in favor of mv_embed and jQuery if( $wgEnableJS2system ){ @@ -181,38 +179,30 @@ class OutputPage { } if( $wgEnableScriptLoader ){ + //add core to top of mScripts $this->mScripts = $this->getScriptLoaderJs( $core_classes ) . $this->mScripts; } else { $so = ''; - foreach( $core_classes as $s ){ - if( isset( $wgJSAutoloadLocalClasses[$s] ) ){ - $path = $wgJSAutoloadLocalClasses[$s]; - // @fixme this is an awful hack - if( substr( $path, 0, 4 ) == "http" || substr( $path, 0, 1 ) == '/' ) { - // Assume a full or local path - } elseif( substr( $path, 0, 6 ) == "skins/" ) { - $path = $wgStylePath . substr( $path, 5 ); - } else { - $path = $wgScriptPath . "/" . $path; - } - $so .= Html::linkedScript( $path . "?" . $this->getURIDparam() ); - } + //make sure scripts are on top: + $postMscripts = $this->mScripts; + $this->mScripts = ''; + foreach( $core_classes as $js_class ){ + $this->addScriptClass( $js_class ); } - $this->mScripts = $so . $this->mScripts; + $this->mScripts .= $postMscripts; } } /** - * @param $js_class string Name of the JavaScript class + * @param string $js_class Name of the JavaScript class * @return boolean False if the class wasn't found, true on success */ function addScriptClass( $js_class ){ global $wgDebugJavaScript, $wgJSAutoloadLocalClasses, $wgJSAutoloadClasses, $wgEnableScriptLoader, $wgStyleVersion, $wgScriptPath; - if( isset( $wgJSAutoloadClasses[$js_class] ) - || isset( $wgJSAutoloadLocalClasses[$js_class] ) ) - { + $path = jsScriptLoader::getJsPathFromClass( $js_class ); + if( $path !== false ){ if( $wgEnableScriptLoader ) { // Register it with the script loader if( !in_array( $js_class, $this->mScriptLoaderClassList ) ) { @@ -220,17 +210,18 @@ class OutputPage { } } else { // Source the script directly - $path = $wgScriptPath . '/'; - if( isset( $wgJSAutoloadClasses[$js_class] ) ) { - $path .= $wgJSAutoloadClasses[$js_class]; - } elseif( isset( $wgJSAutoloadLocalClasses[$js_class] ) ) { - $path .= $wgJSAutoloadLocalClasses[$js_class]; - } - $urlAppend = ( $wgDebugJavaScript ) ? time() : $wgStyleVersion; + $path = $wgScriptPath . '/' . $path; + $urlAppend = ( $wgDebugJavaScript ) ? time() : $this->getURIDparam( $js_class ); $this->addScript( Html::linkedScript( "$path?$urlAppend" ) ); + + //merge in language text: + $inlineMsg = jsScriptLoader::getLocalizedMsgsFromClass( $js_class ); + if( $inlineMsg != '' ) + $this->addScript( Html::inlineScript( $inlineMsg )); } return true; } + print "could not find: $js_class\n"; wfDebug( __METHOD__ . ' could not find js_class: ' . $js_class ); return false; // could not find the class } @@ -252,7 +243,7 @@ class OutputPage { $wgRequest->getVal( 'debug' ) == '1' ) ? '&debug=true' : ''; - return Html::linkedScript( wfScript( 'mwScriptLoader' ) . + return Html::linkedScript( wfScript( 'mwScriptLoader' ) . "?class={$class_list}{$debug_param}&" . $this->getURIDparam( $classAry) ); } @@ -264,9 +255,13 @@ class OutputPage { if( $wgDebugJavaScript ) { return 'urid=' . time(); } else { - $ftime=0; - if($wgScriptModifiedCheck) { - foreach( $classAry as $class ) { + //support single class_name attr + if( gettype( $classAry) == 'string' ){ + $classAry = array( $classAry ); + } + $ftime = $frev = 0; + foreach( $classAry as $class ) { + if( $wgScriptModifiedCheck ) { $js_path = jsScriptLoader::getJsPathFromClass( $class ); if( $js_path ) { $cur_ftime = filemtime ( $IP ."/". $js_path ); @@ -274,16 +269,26 @@ class OutputPage { $ftime = $cur_ftime; } } + // Add the latest revision ID if the class set includes a WT (wiki title) + if( substr($class, 0, 3) == 'WT:'){ + $title_str = substr($class, 3); + $t = Title::newFromText( $title_str ); + if( $t && $t->exists() ) { + if( $t->getLatestRevID() > $frev ) + $frev = $t->getLatestRevID(); + } + } } + //build the actual unique request id: $urid = "urid={$wgStyleVersion}"; - // Add the latest revision ID if we have it - if($this->mLatestScriptRevID != 0 ) - $urid .= "_{$this->mLatestScriptRevID}"; - - // Add the file modification time + // Add the file modification time if set if( $ftime != 0 ) - $urid .= "_".$ftime; + $urid .= "_" . $ftime; + + //add the wiki rev id if set + if( $frev != 0 ) + $urid.= "_" . $frev; return $urid; } @@ -1691,8 +1696,10 @@ class OutputPage { /** * @return string The doctype, opening , and head element. + * + * @param $sk Skin The given Skin */ - public function headElement( Skin $sk ) { + public function headElement( Skin $sk , $includeStyle = true ) { global $wgDocType, $wgDTD, $wgContLanguageCode, $wgOutputEncoding, $wgMimeType; global $wgXhtmlDefaultNamespace, $wgXhtmlNamespaces; global $wgContLang, $wgUseTrackbacks, $wgStyleVersion, $wgEnableScriptLoader, $wgHtml5; diff --git a/includes/Setup.php b/includes/Setup.php index 23ac018c9d..c73620767a 100644 --- a/includes/Setup.php +++ b/includes/Setup.php @@ -319,13 +319,17 @@ $wgArticle = null; wfProfileOut( $fname.'-misc2' ); wfProfileIn( $fname.'-extensions' ); -/* - * load the $wgExtensionMessagesFiles for the script loader - * this can't be done in a normal extension type way - * since the script-loader is an entry point - */ +# load the $wgExtensionMessagesFiles for the script loader +# this can't be done in a normal extension type way +# since the script-loader is an entry point +# $wgExtensionMessagesFiles['mwEmbed'] = "{$IP}/js2/mwEmbed/php/languages/mwEmbed.i18n.php"; +# Include the js2/mwEmbed autoLoadClasses if js2 is enabled +if( $wgEnableJS2system ){ + require_once("$IP/js2/mwEmbed/php/jsAutoloadLocalClasses.php"); +} + # Extension setup functions for extensions other than skins # Entries should be added to this variable during the inclusion # of the extension file. This allows the extension to perform diff --git a/includes/json/FormatJson.php b/includes/json/FormatJson.php index 3fbb21bf54..6db4a23f01 100644 --- a/includes/json/FormatJson.php +++ b/includes/json/FormatJson.php @@ -18,15 +18,15 @@ class FormatJson{ return json_encode($value); } } - public static function decode($value, $assoc=false){ + public static function decode( $value, $assoc=false ){ if (!function_exists('json_decode') ) { $json = new Services_JSON(); - $jsonDec = $json->decode($value); - if($assoc) + $jsonDec = $json->decode( $value ); + if( $assoc ) $jsonDec = wfObjectToArray( $jsonDec ); return $jsonDec; } else { - return json_decode($value, $assoc); + return json_decode( $value, $assoc ); } } } diff --git a/js2/mwEmbed/jsScriptLoader.php b/js2/mwEmbed/jsScriptLoader.php index c60afb55ab..56f400a616 100644 --- a/js2/mwEmbed/jsScriptLoader.php +++ b/js2/mwEmbed/jsScriptLoader.php @@ -22,6 +22,9 @@ class jsScriptLoader { var $jsvarurl = false; // whether we should include generated JS (special class '-') var $doProcReqFlag = true; + //@@todo fix: will break down if someone does }); in their msg text + const loadGMregEx = '/loadGM\s*\(\s*{(.*)}\s*\)\s*/siU'; + function doScriptLoader() { global $wgJSAutoloadClasses, $wgJSAutoloadLocalClasses, $wgEnableScriptLoaderJsFile, $IP, $wgEnableScriptMinify, $wgUseFileCache; @@ -229,7 +232,7 @@ class jsScriptLoader { $this->rKey .= $reqFile; } } else { - $this->error_msg .= 'Not valid requsted JavaScript file' . "\n"; + $this->error_msg .= 'Not valid requested JavaScript file' . "\n"; } } } @@ -256,18 +259,18 @@ class jsScriptLoader { return false; } } - function doProcessJsFile( $file_name ) { + function doProcessJsFile( $file_path ) { global $IP, $wgEnableScriptLocalization, $IP; // Load the file - $str = @file_get_contents( "{$IP}/{$file_name}" ); + $str = @file_get_contents( "{$IP}/{$file_path}" ); if ( $str === false ) { // @@todo check PHP error level. Don't want to expose paths if errors are hidden. - $this->error_msg .= 'Requested File: ' . htmlspecialchars( $file_name ) . ' could not be read' . "\n"; + $this->error_msg .= 'Requested File: ' . htmlspecialchars( $file_path ) . ' could not be read' . "\n"; return ''; } - $this->cur_file = $file_name; + $this->cur_file = $file_path; // Strip out js_log debug lines. Not much luck with this regExp yet: // if( !$this->debug ) @@ -276,19 +279,28 @@ class jsScriptLoader { // Do language swap if ( $wgEnableScriptLocalization ) $str = preg_replace_callback( - // @@todo fix: will break down if someone does }) in their msg text - '/loadGM\s*\(\s*{(.*)}\s*\)\s*/siU', - array( $this, 'languageMsgReplace' ), - $str - ); - + self::loadGMregEx, + array( $this, 'languageMsgReplace' ), + $str + ); return $str; } - - function languageMsgReplace( $jvar ) { + static public function getLocalizedMsgsFromClass( $class ){ + global $IP; + $path = self::getJsPathFromClass( $class ); + // Load the file + $str = @file_get_contents( "{$IP}/{$path}" ); + //extract the msg: + preg_match(self::loadGMregEx, $str, $matches); + if( isset( $matches[1] )){ + return self::languageMsgReplace( $matches, false ); + } + //if could not parse return empty string: + return ''; + } + static public function languageMsgReplace( $jvar ) { if ( !isset( $jvar[1] ) ) - return; - + return ''; $jmsg = FormatJson::decode( '{' . $jvar[1] . '}', true ); // Do the language lookup @@ -296,14 +308,20 @@ class jsScriptLoader { foreach ( $jmsg as $msgKey => $default_en_value ) { $jmsg[$msgKey] = wfMsgNoTrans( $msgKey ); } - // Return the updated loadGM JSON with fixed new lines + // Return the updated loadGM JSON with updated msgs: return 'loadGM( ' . FormatJson::encode( $jmsg ) . ')'; } else { - $this->error_msg .= "Could not parse JSON language msg in File:\n" . - htmlspecialchars ( $this->cur_file ) . "\n"; + print_r($jvar); + + // Could not parse JSON return error: (maybe a alert?) + //we just make a note in the code, visitors will get the fallback language, + //developers will read the js source when its not behaving as expected. + return "/* +* Could not parse JSON language messages in this file, +* Please check that loadGM call contains valid JSON (not javascript) +*/\n\n" . $jvar[0]; //include the original fallback loadGM + } - // Could not parse JSON (throw error?) - return $jvar[0]; } } -- 2.20.1