r75178 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r75177‎ | r75178 | r75179 >
Date:00:00, 22 October 2010
Author:dale
Status:deferred (Comments)
Tags:
Comment:
( slightly less broken ) updates for porting mwEmbed to new resource loader
Modified paths:
  • /trunk/extensions/AddMediaWizard/AddMedia/loader.js (modified) (history)
  • /trunk/extensions/AddMediaWizard/AddMedia/mw.RemoteSearchDriver.js (modified) (history)
  • /trunk/extensions/AddMediaWizard/AddMedia/mw.UploadHandler.js (modified) (history)
  • /trunk/extensions/AddMediaWizard/AddMedia/searchLibs/mediaWikiSearch.js (modified) (history)
  • /trunk/extensions/AddMediaWizard/ClipEdit/mw.ClipEdit.js (modified) (history)
  • /trunk/extensions/MwEmbed/MwEmbed/MwEmbed.resourceList.php (deleted) (history)
  • /trunk/extensions/MwEmbed/MwEmbed/MwEmbed.resources.php (added) (history)
  • /trunk/extensions/MwEmbed/MwEmbed/components/mw.Language.js (deleted) (history)
  • /trunk/extensions/MwEmbed/MwEmbed/components/mw.Parser.js (deleted) (history)
  • /trunk/extensions/MwEmbed/MwEmbed/components/mw.jQueryUtil.js (added) (history)
  • /trunk/extensions/MwEmbed/MwEmbed/modules/ApiEmbed (added) (history)
  • /trunk/extensions/MwEmbed/MwEmbed/modules/ApiEmbed/ApiEmbed.resourceList.php (added) (history)
  • /trunk/extensions/MwEmbed/MwEmbed/modules/ApiEmbed/ApiProxy.i18n.php (added) (history)
  • /trunk/extensions/MwEmbed/MwEmbed/modules/ApiEmbed/ApiProxyPage.js (added) (history)
  • /trunk/extensions/MwEmbed/MwEmbed/modules/ApiEmbed/NestedCallbackIframe.html (added) (history)
  • /trunk/extensions/MwEmbed/MwEmbed/modules/ApiEmbed/README (added) (history)
  • /trunk/extensions/MwEmbed/MwEmbed/modules/ApiEmbed/loader.js (added) (history)
  • /trunk/extensions/MwEmbed/MwEmbed/modules/ApiEmbed/mw.Api.js (added) (history)
  • /trunk/extensions/MwEmbed/MwEmbed/modules/ApiEmbed/mw.ApiProxy.js (added) (history)
  • /trunk/extensions/MwEmbed/MwEmbed/modules/ApiEmbed/tests (added) (history)
  • /trunk/extensions/MwEmbed/MwEmbed/modules/ApiEmbed/tests/testApiProxy.html (added) (history)
  • /trunk/extensions/MwEmbed/MwEmbed/modules/README (added) (history)
  • /trunk/extensions/MwEmbed/MwEmbed/mwEmbed.core.js (added) (history)
  • /trunk/extensions/MwEmbed/MwEmbed/mwEmbed.js (modified) (history)
  • /trunk/extensions/MwEmbed/MwEmbed/mwEmbed.old.js (added) (history)
  • /trunk/extensions/MwEmbed/MwEmbedResourceManager.php (modified) (history)
  • /trunk/extensions/TimedMediaHandler/EmbedPlayer/EmbedPlayer.loader.js (modified) (history)
  • /trunk/extensions/TimedMediaHandler/EmbedPlayer/EmbedPlayer.resourceList.php (deleted) (history)
  • /trunk/extensions/TimedMediaHandler/EmbedPlayer/EmbedPlayer.resources.php (added) (history)
  • /trunk/extensions/TimedMediaHandler/EmbedPlayer/mw.EmbedPlayer.js (modified) (history)
  • /trunk/extensions/TimedMediaHandler/EmbedPlayer/skins/mw.PlayerControlBuilder.js (modified) (history)
  • /trunk/extensions/TimedMediaHandler/TimedText/TimedText.resourceList.php (deleted) (history)
  • /trunk/extensions/TimedMediaHandler/TimedText/TimedText.resources.php (added) (history)
  • /trunk/extensions/TimedMediaHandler/TimedText/remotes (added) (history)
  • /trunk/extensions/TimedMediaHandler/TimedText/remotes/RemoteMwTimedText.js (added) (history)
  • /trunk/extensions/TimedMediaHandler/TimedText/tests (added) (history)
  • /trunk/extensions/TimedMediaHandler/TimedText/tests/Player_Timed_Text.html (added) (history)

Diff [purge]

Index: trunk/extensions/MwEmbed/MwEmbedResourceManager.php
@@ -31,10 +31,10 @@
3232 }
3333
3434 // Add the messages to the extension messages set:
35 - $wgExtensionMessagesFiles[ 'MwEmbed.' . $moduleName ] = $fullResourcePath . '/' . $moduleName . '.i18n.php';
 35+ $wgExtensionMessagesFiles[ 'MwEmbed.' . $moduleName ] = $fullResourcePath . '/' . $moduleName . '.i18n.php';
3636
3737 // Get the mwEmbed module resource list
38 - $resourceList = include( $fullResourcePath . '/' . $moduleName . '.resourceList.php' );
 38+ $resourceList = include( $fullResourcePath . '/' . $moduleName . '.resources.php' );
3939
4040 // Look for special 'messages' => 'moduleFile' key and load all modules file messages:
4141 foreach( $resourceList as $name => $resources ){
@@ -46,6 +46,9 @@
4747 }
4848 }
4949 };
 50+
 51+ // Add the moduleLoader to the resource list:
 52+ $resourceList[$moduleName. '.loader'] = array( 'loader' => $moduleName . '.loader.js' );
5053
5154 // Add the resource list into the module set with its provided path
5255 self::$moduleSet[ $mwEmbedResourcePath ] = $resourceList;
Index: trunk/extensions/MwEmbed/MwEmbed/MwEmbed.resourceList.php
@@ -1,69 +0,0 @@
2 -<?php
3 -
4 -/**
5 - * MwEmebed module resource list array
6 - */
7 -
8 -return array(
9 - 'mw.Language' => array ( 'scripts' => 'components/mw.Language.js' ),
10 - 'mw.Parser' => array ( 'scripts' => 'components/mw.Parser.js' ),
11 - 'mw.Api' => array ( 'scripts' => 'components/mw.Api.js' ),
12 - 'mwEmbed' => array(
13 - 'scripts' => 'mwEmbed.js',
14 - 'skinStyles' => array(
15 - 'default' => 'skins/common/mw.style.mwCommon.css'
16 - ),
17 - 'group' => 'ext.mwEmbed',
18 - 'dependencies' => array(
19 - 'jquery'
20 - ),
21 - 'messages' => 'moduleFile',
22 - 'languageScripts' => array(
23 - 'am' => 'languages/classes/LanuageAm.js',
24 - 'ar' => 'languages/classes/LanuageAr.js',
25 - 'bat_smg' => 'languages/classes/LanuageBat_smg.js',
26 - 'be' => 'languages/classes/LanuageBe.js',
27 - 'be_tarask' => 'languages/classes/LanuageBe_tarask.js',
28 - 'bh' => 'languages/classes/LanuageBh.js',
29 - 'bs' => 'languages/classes/LanuageBs.js',
30 - 'cs' => 'languages/classes/LanuageCs.js',
31 - 'cu' => 'languages/classes/LanuageCu.js',
32 - 'cy' => 'languages/classes/LanuageCy.js',
33 - 'dsb' => 'languages/classes/LanuageDsb.js',
34 - 'fr' => 'languages/classes/LanuageFr.js',
35 - 'ga' => 'languages/classes/LanuageGa.js',
36 - 'gd' => 'languages/classes/LanuageGd.js',
37 - 'gv' => 'languages/classes/LanuageGv.js',
38 - 'he' => 'languages/classes/LanuageHe.js',
39 - 'hi' => 'languages/classes/LanuageHi.js',
40 - 'hr' => 'languages/classes/LanuageHr.js',
41 - 'hsb' => 'languages/classes/LanuageHsb.js',
42 - 'hy' => 'languages/classes/LanuageHy.js',
43 - 'ksh' => 'languages/classes/LanuageKsh.js',
44 - 'ln' => 'languages/classes/LanuageLn.js',
45 - 'lt' => 'languages/classes/LanuageLt.js',
46 - 'lv' => 'languages/classes/LanuageLv.js',
47 - 'mg' => 'languages/classes/LanuageMg.js',
48 - 'mk' => 'languages/classes/LanuageMk.js',
49 - 'mo' => 'languages/classes/LanuageMo.js',
50 - 'mt' => 'languages/classes/LanuageMt.js',
51 - 'nso' => 'languages/classes/LanuageNso.js',
52 - 'pl' => 'languages/classes/LanuagePl.js',
53 - 'pt_br' => 'languages/classes/LanuagePt_br.js',
54 - 'ro' => 'languages/classes/LanuageRo.js',
55 - 'ru' => 'languages/classes/LanuageRu.js',
56 - 'se' => 'languages/classes/LanuageSe.js',
57 - 'sh' => 'languages/classes/LanuageSh.js',
58 - 'sk' => 'languages/classes/LanuageSk.js',
59 - 'sl' => 'languages/classes/LanuageSl.js',
60 - 'sma' => 'languages/classes/LanuageSma.js',
61 - 'sr_ec' => 'languages/classes/LanuageSr_ec.js',
62 - 'sr_el' => 'languages/classes/LanuageSr_el.js',
63 - 'sr' => 'languages/classes/LanuageSr.js',
64 - 'ti' => 'languages/classes/LanuageTi.js',
65 - 'tl' => 'languages/classes/LanuageTl.js',
66 - 'uk' => 'languages/classes/LanuageUk.js',
67 - 'wa' => 'languages/classes/LanuageWa.js',
68 - )
69 - )
70 -);
\ No newline at end of file
Index: trunk/extensions/MwEmbed/MwEmbed/MwEmbed.resources.php
@@ -0,0 +1,19 @@
 2+<?php
 3+
 4+/**
 5+ * MwEmebed module resource list array
 6+ */
 7+
 8+return array(
 9+ 'mw.jQueryUtil' => array( 'scripts' => 'components/mw.jQueryUtil.js' ),
 10+ 'mwEmbed' => array(
 11+ 'scripts' => 'mwEmbed.core.js',
 12+ 'dependencies' => array(
 13+ 'mediaWiki.messageParser',
 14+ 'mw.jQueryUtil'
 15+ ),
 16+ 'styles' => 'skins/common/mw.style.mwCommon.css',
 17+ 'group' => 'ext.mwEmbed',
 18+ 'messages' => 'moduleFile',
 19+ )
 20+);
\ No newline at end of file
Index: trunk/extensions/MwEmbed/MwEmbed/mwEmbed.core.js
@@ -0,0 +1,678 @@
 2+// Add support for html5 / mwEmbed elements to IE
 3+// For discussion and comments, see: http://remysharp.com/2009/01/07/html5-enabling-script/
 4+'video audio source track'.replace(/\w+/g,function( n ){ document.createElement( n ) } );
 5+
 6+/**
 7+ * mwEmbed.core includes shared mwEmbed utilities
 8+ *
 9+ * @license
 10+ * mwEmbed
 11+ * Dual licensed under the MIT or GPL Version 2 licenses.
 12+ *
 13+ * @copyright (C) 2010 Kaltura
 14+ * @author Michael Dale ( michael.dale at kaltura.com )
 15+ *
 16+ * @url http://www.kaltura.org/project/HTML5_Video_Media_JavaScript_Library
 17+ *
 18+ * Libraries used include code license in headers
 19+ */
 20+
 21+
 22+/**
 23+ * Setup the "mw" global:
 24+ */
 25+if ( typeof window.mw == 'undefined' ) {
 26+ window.mw = { };
 27+}
 28+
 29+/**
 30+ * Set the mwEmbedVersion
 31+ */
 32+var MW_EMBED_VERSION = '1.1g';
 33+
 34+// Globals to pre-set ready functions in dynamic loading of mwEmbed
 35+if( typeof preMwEmbedReady == 'undefined'){
 36+ var preMwEmbedReady = [];
 37+}
 38+// Globals to pre-set config values in dynamic loading of mwEmbed
 39+if( typeof preMwEmbedConfig == 'undefined') {
 40+ var preMwEmbedConfig = [];
 41+}
 42+
 43+/**
 44+ * Global mw object:
 45+ */
 46+( function( mw ) {
 47+
 48+ /**
 49+ * Add a function to be run during setup ( prior to mw.ready) this is useful
 50+ * for building out interfaces that should be ready before mw.ready is
 51+ * called.
 52+ *
 53+ * @param {callback}
 54+ * Function Callback function must accept a ready function
 55+ * callback to be called once setup is done
 56+ */
 57+ var mwSetupFunctions = []; // Array of setup functions
 58+ mw.addSetupHook = function( callback ) {
 59+ mwSetupFunctions.push ( callback ) ;
 60+ };
 61+
 62+ // flag for mwSetup being run:
 63+ mwSetupFlag = false;
 64+ mw.setupMwEmbed = function(){
 65+ mw.log( 'mw.setupMwEmbed' );
 66+ // Only run the setup once:
 67+ if( mwSetupFlag ) {
 68+ return ;
 69+ }
 70+ mwSetupFlag = true;
 71+ // check if mediaWiki has already been setup.
 72+ if (! window.mediaWiki ) {
 73+ // @@todo load mediaWiki from load.php
 74+
 75+ // Issue a call to load.php to get the set of modules in a way that 'mediaWiki' understands.
 76+ } else {
 77+ mw.setupWithmediaWikiJS();
 78+ }
 79+ };
 80+ mw.setupWithmediaWikiJS = function(){
 81+ // Update mediaWiki object with mwEmbed tools / helpers
 82+
 83+ // Now with window.mediaWiki we can run all the calls and trigger the mw.ready
 84+
 85+ // run setup callbacks
 86+ function runSetupFunctions() {
 87+ if( mwSetupFunctions.length ) {
 88+ mwSetupFunctions.shift()( function() {
 89+ runSetupFunctions();
 90+ } );
 91+ }else{
 92+ mw.runReadyFunctions();
 93+ }
 94+ }
 95+ runSetupFunctions();
 96+ };
 97+
 98+
 99+ /**
 100+ * Enables load hooks to run once mwEmbeed is "ready" Will ensure jQuery is
 101+ * available, is in the $j namespace and mw interfaces and configuration has
 102+ * been loaded and applied
 103+ *
 104+ * This is different from jQuery(document).ready() ( jQuery ready is not
 105+ * friendly with dynamic includes and not friendly with core interface
 106+ * asynchronous build out. )
 107+ *
 108+ * @param {Function}
 109+ * callback Function to run once DOM and jQuery are ready
 110+ */
 111+ var mwOnLoadFunctions = []; // Setup the local mwOnLoadFunctions array:
 112+ var mwReadyFlag = false; // mw Ready flag ( set once mwEmbed is ready )
 113+ mw.ready = function( callback ) {
 114+ if( mwReadyFlag === false ) {
 115+ // Add the callbcak to the onLoad function stack
 116+ mwOnLoadFunctions.push ( callback );
 117+ } else {
 118+ // If mwReadyFlag is already "true" issue the callback directly:
 119+ callback();
 120+ }
 121+ }
 122+
 123+ /**
 124+ * Runs all the queued functions called by mwEmbedSetup
 125+ */
 126+ mw.runReadyFunctions = function ( ) {
 127+ mw.log('mw.runReadyFunctions: ' + mwOnLoadFunctions.length );
 128+ // Run any pre-setup ready functions
 129+ while( preMwEmbedReady.length ){
 130+ preMwEmbedReady.shift()();
 131+ }
 132+ // Run all the queued functions:
 133+ while( mwOnLoadFunctions.length ) {
 134+ mwOnLoadFunctions.shift()();
 135+ }
 136+ // Sets mwReadyFlag to true so that future mw.ready run the
 137+ // callback directly
 138+ mwReadyFlag = true;
 139+
 140+ }
 141+
 142+
 143+ /* User config */
 144+
 145+ var setupUserConfigFlag = false;
 146+ mw.setupUserConfig = function( callback ) {
 147+ if( setupUserConfigFlag ) {
 148+ if( callback ) {
 149+ callback();
 150+ }
 151+ return ;
 152+ }
 153+ // Do Setup user config:
 154+ mw.load( [ '$j.cookie', 'JSON' ], function() {
 155+ if( $j.cookie( 'mwUserConfig' ) ) {
 156+ mwUserConfig = JSON.parse( $j.cookie( 'mwUserConfig' ) );
 157+ }
 158+ setupUserConfigFlag = true;
 159+ if( callback ) {
 160+ callback();
 161+ }
 162+ });
 163+ }
 164+
 165+ /**
 166+ * Save a user configuration var to a cookie & local global variable Loads
 167+ * the cookie plugin if not already loaded
 168+ *
 169+ * @param {String}
 170+ * name Name of user configuration value
 171+ * @param {String}
 172+ * value Value of configuration name
 173+ */
 174+ mw.setUserConfig = function ( name, value, cookieOptions ) {
 175+ if( ! setupUserConfigFlag ) {
 176+ mw.log( "Error: userConfig not setup" );
 177+ return false;
 178+ }
 179+ // Update local value
 180+ mwUserConfig[ name ] = value;
 181+
 182+ // Update the cookie ( '$j.cookie' & 'JSON' should already be loaded )
 183+ $j.cookie( 'mwUserConfig', JSON.stringify( mwUserConfig ) );
 184+ }
 185+
 186+ /**
 187+ * Save a user configuration var to a cookie & local global variable
 188+ *
 189+ * @param {String}
 190+ * name Name of user configuration value
 191+ * @return value of the configuration name false if the configuration name
 192+ * could not be found
 193+ */
 194+ mw.getUserConfig = function ( name ) {
 195+ if( mwUserConfig[ name ] )
 196+ return mwUserConfig[ name ];
 197+ return false;
 198+ }
 199+
 200+
 201+ /**
 202+ * Aliased functions
 203+ *
 204+ * Wrap mediaWiki functionality while we port over the libraries
 205+ */
 206+ mw.setConfig = function( name, value ){
 207+ mediaWiki.config.set( name, value );
 208+ };
 209+ mw.getConfig = function( name, value ){
 210+ mediaWiki.config.get( name, value );
 211+ };
 212+ mw.setDefaultConfig = function( name, value ){
 213+ //@@ FIXME only set if not already present:
 214+ mediaWiki.config.set( name, value );
 215+ };
 216+ mw.load = function( resources, callback ){
 217+ mediaWiki.using( resources, callback, function(){
 218+ // failed to load
 219+ })
 220+ };
 221+ mw.addModuleLoader = function ( name, loaderFunction ) {
 222+ mediaWiki.register( name, 0, loaderFunction );
 223+ }
 224+
 225+
 226+ /**
 227+ * Utility Functions
 228+ */
 229+
 230+ /**
 231+ * Given a float number of seconds, returns npt format response. ( ignore
 232+ * days for now )
 233+ *
 234+ * @param {Float}
 235+ * sec Seconds
 236+ * @param {Boolean}
 237+ * show_ms If milliseconds should be displayed.
 238+ * @return {Float} String npt format
 239+ */
 240+ mw.seconds2npt = function( sec, show_ms ) {
 241+ if ( isNaN( sec ) ) {
 242+ mw.log("Warning: trying to get npt time on NaN:" + sec);
 243+ return '0:00:00';
 244+ }
 245+
 246+ var tm = mw.seconds2Measurements( sec )
 247+
 248+ // Round the number of seconds to the required number of significant
 249+ // digits
 250+ if ( show_ms ) {
 251+ tm.seconds = Math.round( tm.seconds * 1000 ) / 1000;
 252+ } else {
 253+ tm.seconds = Math.round( tm.seconds );
 254+ }
 255+ if ( tm.seconds < 10 ){
 256+ tm.seconds = '0' + tm.seconds;
 257+ }
 258+ if( tm.hours == 0 ){
 259+ hoursStr = ''
 260+ } else {
 261+ if ( tm.minutes < 10 )
 262+ tm.minutes = '0' + tm.minutes;
 263+
 264+ hoursStr = tm.hours + ":";
 265+ }
 266+ return hoursStr + tm.minutes + ":" + tm.seconds;
 267+ }
 268+
 269+ /**
 270+ * Given seconds return array with 'days', 'hours', 'min', 'seconds'
 271+ *
 272+ * @param {float}
 273+ * sec Seconds to be converted into time measurements
 274+ */
 275+ mw.seconds2Measurements = function ( sec ){
 276+ var tm = {};
 277+ tm.days = Math.floor( sec / ( 3600 * 24 ) )
 278+ tm.hours = Math.floor( sec / 3600 );
 279+ tm.minutes = Math.floor( ( sec / 60 ) % 60 );
 280+ tm.seconds = sec % 60;
 281+ return tm;
 282+ }
 283+
 284+ /**
 285+ * Take hh:mm:ss,ms or hh:mm:ss.ms input, return the number of seconds
 286+ *
 287+ * @param {String}
 288+ * npt_str NPT time string
 289+ * @return {Float} Number of seconds
 290+ */
 291+ mw.npt2seconds = function ( npt_str ) {
 292+ if ( !npt_str ) {
 293+ // mw.log('npt2seconds:not valid ntp:'+ntp);
 294+ return false;
 295+ }
 296+ // Strip {npt:}01:02:20 or 32{s} from time if present
 297+ npt_str = npt_str.replace( /npt:|s/g, '' );
 298+
 299+ var hour = 0;
 300+ var min = 0;
 301+ var sec = 0;
 302+
 303+ times = npt_str.split( ':' );
 304+ if ( times.length == 3 ) {
 305+ sec = times[2];
 306+ min = times[1];
 307+ hour = times[0];
 308+ } else if ( times.length == 2 ) {
 309+ sec = times[1];
 310+ min = times[0];
 311+ } else {
 312+ sec = times[0];
 313+ }
 314+ // Sometimes a comma is used instead of period for ms
 315+ sec = sec.replace( /,\s?/, '.' );
 316+ // Return seconds float
 317+ return parseInt( hour * 3600 ) + parseInt( min * 60 ) + parseFloat( sec );
 318+ }
 319+
 320+ /**
 321+ * addLoaderDialog small helper for displaying a loading dialog
 322+ *
 323+ * @param {String}
 324+ * dialogHtml text Html of the loader msg
 325+ */
 326+ mw.addLoaderDialog = function( dialogHtml ) {
 327+ $dialog = mw.addDialog( {
 328+ 'title' : dialogHtml,
 329+ 'content' : dialogHtml + '<br>' +
 330+ $j('<div />')
 331+ .loadingSpinner()
 332+ .html()
 333+ });
 334+ return $dialog;
 335+ }
 336+
 337+ /**
 338+ * Mobile HTML5 has special properties for html5 video::
 339+ *
 340+ * NOTE: should be phased out in favor of browser feature detection where possible
 341+ */
 342+ mw.isMobileHTML5 = function() {
 343+ // check mobile safari foce ( for debug )
 344+ if( mw.getConfig( 'forceMobileHTML5' ) || document.URL.indexOf('forceMobileHTML5') != -1 ){
 345+ return true;
 346+ }
 347+ if (( navigator.userAgent.indexOf('iPhone') != -1) ||
 348+ ( navigator.userAgent.indexOf('iPod') != -1) ||
 349+ ( navigator.userAgent.indexOf('iPad') != -1) ||
 350+ ( mw.isAndroid2() )
 351+ ) {
 352+ return true;
 353+ }
 354+ return false;
 355+ };
 356+ // Android 2 has some restrictions vs other mobile platforms
 357+ mw.isAndroid2 = function(){
 358+ if ( navigator.userAgent.indexOf('Android 2.') != -1) {
 359+ return true;
 360+ }
 361+ return false;
 362+ };
 363+
 364+ /**
 365+ * Add a (temporary) dialog window:
 366+ *
 367+ * @param {Object} with following keys:
 368+ * title: {String} Title string for the dialog
 369+ * content: {String} to be inserted in msg box
 370+ * buttons: {Object} A button object for the dialog Can be a string
 371+ * for the close button
 372+ * any jquery.ui.dialog option
 373+ */
 374+ mw.addDialog = function ( options ) {
 375+ // Remove any other dialog
 376+ $j( '#mwTempLoaderDialog' ).remove();
 377+
 378+ if( !options){
 379+ options = {};
 380+ }
 381+
 382+ // Extend the default options with provided options
 383+ var options = $j.extend({
 384+ 'bgiframe': true,
 385+ 'draggable': true,
 386+ 'resizable': false,
 387+ 'modal': true
 388+ }, options );
 389+
 390+ if( ! options.title || ! options.content ){
 391+ mw.log("Error: mwEmbed addDialog missing required options ( title, content ) ")
 392+ return ;
 393+ }
 394+
 395+ // Append the dialog div on top:
 396+ $j( 'body' ).append(
 397+ $j('<div />')
 398+ .attr( {
 399+ 'id' : "mwTempLoaderDialog",
 400+ 'title' : options.title
 401+ })
 402+ .css({
 403+ 'display': 'none'
 404+ })
 405+ .append( options.content )
 406+ );
 407+
 408+ // Build the uiRequest
 409+ var uiRequest = [ '$j.ui.dialog' ];
 410+ if( options.draggable ){
 411+ uiRequest.push( '$j.ui.draggable' )
 412+ }
 413+ if( options.resizable ){
 414+ uiRequest.push( '$j.ui.resizable' );
 415+ }
 416+
 417+ // Special button string
 418+ if ( typeof options.buttons == 'string' ) {
 419+ var buttonMsg = options.buttons;
 420+ buttons = { };
 421+ options.buttons[ buttonMsg ] = function() {
 422+ $j( this ).dialog( 'close' );
 423+ }
 424+ }
 425+
 426+ // Load the dialog resources
 427+ mw.load([
 428+ [
 429+ '$j.ui'
 430+ ],
 431+ uiRequest
 432+ ], function() {
 433+ $j( '#mwTempLoaderDialog' ).dialog( options );
 434+ } );
 435+ return $j( '#mwTempLoaderDialog' );
 436+ }
 437+
 438+ /**
 439+ * Close the loader dialog created with addLoaderDialog
 440+ */
 441+ mw.closeLoaderDialog = function() {
 442+ // Make sure the dialog resource is present
 443+ if( !mw.isset( '$j.ui.dialog' ) ) {
 444+ return false;
 445+ }
 446+ $j( '#mwTempLoaderDialog' ).dialog( 'destroy' ).remove();
 447+ }
 448+
 449+
 450+ /**
 451+ * Similar to php isset function checks if the variable exists. Does a safe
 452+ * check of a descendant method or variable
 453+ *
 454+ * @param {String}
 455+ * objectPath
 456+ * @return {Boolean} true if objectPath exists false if objectPath is
 457+ * undefined
 458+ */
 459+ mw.isset = function( objectPath ) {
 460+ if ( !objectPath ) {
 461+ return false;
 462+ }
 463+ var pathSet = objectPath.split( '.' );
 464+ var cur_path = '';
 465+
 466+ for ( var p = 0; p < pathSet.length; p++ ) {
 467+ cur_path = ( cur_path == '' ) ? cur_path + pathSet[p] : cur_path + '.' + pathSet[p];
 468+ eval( 'var ptest = typeof ( ' + cur_path + ' ); ' );
 469+ if ( ptest == 'undefined' ) {
 470+ return false;
 471+ }
 472+ }
 473+ return true;
 474+ }
 475+
 476+ /**
 477+ * Wait for a object to be defined and the call the callback
 478+ *
 479+ * @param {Object}
 480+ * objectName Name of object to be defined
 481+ * @param {Function}
 482+ * callback Function to call once object is defined
 483+ * @param {Null}
 484+ * callNumber Used internally to keep track of number of times
 485+ * waitForObject has been called
 486+ */
 487+ var waitTime = 1200; // About 30 seconds
 488+ mw.waitForObject = function( objectName, callback, _callNumber) {
 489+ // mw.log( 'waitForObject: ' + objectName + ' cn: ' + _callNumber);
 490+
 491+ // Increment callNumber:
 492+ if( !_callNumber ) {
 493+ _callNumber = 1;
 494+ } else {
 495+ _callNumber++;
 496+ }
 497+
 498+ if( _callNumber > waitTime ) {
 499+ mw.log( "Error: waiting for object: " + objectName + ' timeout ' );
 500+ callback( false );
 501+ return ;
 502+ }
 503+
 504+ // If the object is defined ( or we are done loading from a callback )
 505+ if ( mw.isset( objectName ) || mwLoadDoneCB[ objectName ] == 'done' ) {
 506+ callback( objectName )
 507+ }else{
 508+ setTimeout( function( ) {
 509+ mw.waitForObject( objectName, callback, _callNumber);
 510+ }, 25);
 511+ }
 512+ }
 513+
 514+ /**
 515+ * Check if an object is empty or if its an empty string.
 516+ *
 517+ * @param {Object}
 518+ * object Object to be checked
 519+ */
 520+ mw.isEmpty = function( object ) {
 521+ if( typeof object == 'string' ) {
 522+ if( object == '' ) return true;
 523+ // Non empty string:
 524+ return false;
 525+ }
 526+
 527+ // If an array check length:
 528+ if( Object.prototype.toString.call( object ) === "[object Array]"
 529+ && object.length == 0 ) {
 530+ return true;
 531+ }
 532+
 533+ // Else check as an object:
 534+ for( var i in object ) { return false; }
 535+
 536+ // Else object is empty:
 537+ return true;
 538+ }
 539+
 540+ /**
 541+ * Log a string msg to the console
 542+ *
 543+ * all mw.log statements will be removed on minification so lots of mw.log
 544+ * calls will not impact performance in non debug mode
 545+ *
 546+ * @param {String}
 547+ * string String to output to console
 548+ */
 549+ mw.log = function( string ) {
 550+ // Add any prepend debug strings if necessary
 551+ if ( mw.getConfig( 'pre-append-log' ) ){
 552+ string = mw.getConfig( 'pre-append-log' ) + string;
 553+ }
 554+
 555+ if ( window.console ) {
 556+ window.console.log( string );
 557+ } else {
 558+ /**
 559+ * Old IE and non-Firebug debug: ( commented out for now )
 560+ */
 561+ /*var log_elm = document.getElementById('mv_js_log');
 562+ if(!log_elm) {
 563+ document.getElementsByTagName("body")[0].innerHTML += '<div ' +
 564+ 'style="position:absolute;z-index:500;bottom:0px;left:0px;right:0px;height:200px;">' +
 565+ '<textarea id="mv_js_log" cols="120" rows="12"></textarea>' +
 566+ '</div>';
 567+ }
 568+ var log_elm = document.getElementById('mv_js_log');
 569+ if(log_elm) {
 570+ log_elm.value+=string+"\n";
 571+ }*/
 572+ }
 573+ }
 574+
 575+
 576+ /**
 577+ * This will get called when the DOM is ready Will check configuration and
 578+ * issue a mw.setupMwEmbed call if needed
 579+ */
 580+ // Flag to register the domReady has been called
 581+ var mwDomReadyFlag = false;
 582+ mw.domReady = function ( ) {
 583+ if( mwDomReadyFlag ) {
 584+ return ;
 585+ }
 586+ // Set the onDomReady Flag
 587+ mwDomReadyFlag = true;
 588+ mw.setupMwEmbed();
 589+ }
 590+
 591+ /**
 592+ * Set DOM-ready call We copy jQuery( document ).ready here since sometimes
 593+ * mwEmbed.js is included without jQuery and we need our own "ready" system so
 594+ * that mwEmbed interfaces can support async built out and the include of
 595+ * jQuery.
 596+ */
 597+ var mwDomIsReady = false;
 598+ function runMwDomReady(){
 599+ mwDomIsReady = true;
 600+ if( mw.domReady ){
 601+ mw.domReady()
 602+ }
 603+ }
 604+ // Check if already ready:
 605+ if ( document.readyState === "complete" ) {
 606+ runMwDomReady();
 607+ }
 608+
 609+ // Cleanup functions for the document ready method
 610+ if ( document.addEventListener ) {
 611+ DOMContentLoaded = function() {
 612+ document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
 613+ runMwDomReady();
 614+ };
 615+
 616+ } else if ( document.attachEvent ) {
 617+ DOMContentLoaded = function() {
 618+ // Make sure body exists, at least, in case IE gets a little overzealous
 619+ // (ticket #5443).
 620+ if ( document.readyState === "complete" ) {
 621+ document.detachEvent( "onreadystatechange", DOMContentLoaded );
 622+ runMwDomReady();
 623+ }
 624+ };
 625+ }
 626+ // Mozilla, Opera and webkit currently support this event
 627+ if ( document.addEventListener ) {
 628+ // Use the handy event callback
 629+ document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
 630+
 631+ // A fallback to window.onload, that will always work
 632+ window.addEventListener( "load", mw.domReady, false );
 633+
 634+ // If IE event model is used
 635+ } else if ( document.attachEvent ) {
 636+ // ensure firing before onload,
 637+ // maybe late but safe also for iframes
 638+ document.attachEvent("onreadystatechange", DOMContentLoaded);
 639+
 640+ // A fallback to window.onload, that will always work
 641+ window.attachEvent( "onload", runMwDomReady );
 642+
 643+ // If IE and not a frame
 644+ // continually check to see if the document is ready
 645+ var toplevel = false;
 646+
 647+ try {
 648+ toplevel = window.frameElement == null;
 649+ } catch(e) {}
 650+
 651+ if ( document.documentElement.doScroll && toplevel ) {
 652+ doScrollCheck();
 653+ }
 654+ }
 655+ // The DOM ready check for Internet Explorer
 656+ function doScrollCheck() {
 657+ if ( mwDomIsReady ) {
 658+ return;
 659+ }
 660+
 661+ try {
 662+ // If IE is used, use the trick by Diego Perini
 663+ // http://javascript.nwbox.com/IEContentLoaded/
 664+ document.documentElement.doScroll("left");
 665+ } catch( error ) {
 666+ setTimeout( doScrollCheck, 1 );
 667+ return;
 668+ }
 669+
 670+ // and execute any waiting functions
 671+ runMwDomReady();
 672+ }
 673+
 674+
 675+} )( window.mw );
 676+
 677+
 678+
 679+
Property changes on: trunk/extensions/MwEmbed/MwEmbed/mwEmbed.core.js
___________________________________________________________________
Added: svn:eol-style
1680 + native
Index: trunk/extensions/MwEmbed/MwEmbed/components/mw.Parser.js
@@ -1,323 +0,0 @@
2 -/**
3 -* Mediawiki language text parser
4 -*/
5 -
6 -// Setup swap string constants
7 -var JQUERY_SWAP_STRING = 'ZjQuerySwapZ';
8 -var LINK_SWAP_STRING = 'ZreplaceZ';
9 -
10 -( function( mw ) {
11 -
12 - // The parser magic global
13 - var pMagicSet = { };
14 -
15 - /**
16 - * addTemplateTransform to the parser
17 - *
18 - * Lets you add a set template key to be transformed by a callback function
19 - *
20 - * @param {Object} magicSet key:callback
21 - */
22 - mw.addTemplateTransform = function( magicSet ) {
23 - for ( var i in magicSet ) {
24 - pMagicSet[ i ] = magicSet[i];
25 - }
26 - };
27 -
28 - /**
29 - * MediaWiki wikitext "Parser" constructor
30 - *
31 - * @param {String} wikiText the wikitext to be parsed
32 - * @return {Object} parserObj returns a parser object that has methods for getting at
33 - * things you would want
34 - */
35 - mw.Parser = function( wikiText, options) {
36 - // return the parserObj
37 - this.init( wikiText, options ) ;
38 - };
39 -
40 - mw.Parser.prototype = {
41 -
42 - // the parser output string container
43 - pOut: false,
44 -
45 - init: function( wikiText, parserOptions ) {
46 - this.wikiText = wikiText;
47 - },
48 -
49 - // Update the text value
50 - updateText : function( wikiText ) {
51 - this.wikiText = wikiText;
52 -
53 - // invalidate the output ( will force a re-parse )
54 - this.pOut = false;
55 - },
56 -
57 - /**
58 - * Quickly recursive / parse out templates:
59 - */
60 - parse: function() {
61 - function recurseTokenizeNodes ( text ) {
62 - var node = { };
63 - // Inspect each char
64 - for ( var a = 0; a < text.length; a++ ) {
65 - if ( text[a] == '{' && text[a + 1] == '{' ) {
66 - a = a + 2;
67 - node['parent'] = node;
68 - if ( !node['child'] ) {
69 - node['child'] = new Array();
70 - }
71 -
72 - node['child'].push( recurseTokenizeNodes( text.substr( a ) ) );
73 - } else if ( text[a] == '}' && text[a + 1] == '}' ) {
74 - a++;
75 - if ( !node['parent'] ) {
76 - return node;
77 - }
78 - node = node['parent'];
79 - }
80 - if ( !node['text'] ) {
81 - node['text'] = '';
82 - }
83 - // Don't put }} closures into output:
84 - if ( text[a] && text[a] != '}' ) {
85 - node['text'] += text[a];
86 - }
87 - }
88 - return node;
89 - }
90 -
91 - /**
92 - * Parse template text as template name and named params
93 - * @param {String} templateString Template String to be parsed
94 - */
95 - function parseTmplTxt( templateString ) {
96 - var templateObject = { };
97 -
98 - // Get template name:
99 - templateName = templateString.split( '\|' ).shift() ;
100 - templateName = templateName.split( '\{' ).shift() ;
101 - templateName = templateName.replace( /^\s+|\s+$/g, "" ); //trim
102 -
103 - // Check for arguments:
104 - if ( templateName.split( ':' ).length == 1 ) {
105 - templateObject["name"] = templateName;
106 - } else {
107 - templateObject["name"] = templateName.split( ':' ).shift();
108 - templateObject["arg"] = templateName.split( ':' ).pop();
109 - }
110 -
111 - var paramSet = templateString.split( '\|' );
112 - paramSet.splice( 0, 1 );
113 - if ( paramSet.length ) {
114 - templateObject.param = new Array();
115 - for ( var pInx in paramSet ) {
116 - var paramString = paramSet[ pInx ];
117 - // check for empty param
118 - if ( paramString == '' ) {
119 - templateObject.param[ pInx ] = '';
120 - continue;
121 - }
122 - for ( var b = 0 ; b < paramString.length ; b++ ) {
123 - if ( paramString[b] == '=' && b > 0 && b < paramString.length && paramString[b - 1] != '\\' ) {
124 - // named param
125 - templateObject.param[ paramString.split( '=' ).shift() ] = paramString.split( '=' ).pop();
126 - } else {
127 - // indexed param
128 - templateObject.param[ pInx ] = paramString;
129 - }
130 - }
131 - }
132 - }
133 - return templateObject;
134 - }
135 -
136 - /**
137 - * Get the Magic text from a template node
138 - */
139 - function getMagicTxtFromTempNode( node ) {
140 - node.templateObject = parseTmplTxt ( node.text );
141 - // Do magic swap if template key found in pMagicSet
142 - if ( node.templateObject.name in pMagicSet ) {
143 - var nodeText = pMagicSet[ node.templateObject.name ]( node.templateObject );
144 - return nodeText;
145 - } else {
146 - // don't swap just return text
147 - return node.text;
148 - }
149 - }
150 -
151 - /**
152 - * swap links of form [ ] for html a links or jquery helper spans
153 - * NOTE: this could be integrated into the tokenizer but for now
154 - * is a staged process.
155 - *
156 - * @param text to swapped
157 - */
158 - function linkSwapText( text ) {
159 - //mw.log( "linkSwapText::" + text );
160 - var re = new RegExp( /\[([^\s]+[\s]+[^\]]*)\]/g );
161 - var matchSet = text.match( re );
162 -
163 - if( !matchSet ){
164 - return text;
165 - }
166 -
167 - text = text.replace( re , LINK_SWAP_STRING );
168 -
169 - for( var i=0; i < matchSet.length; i++ ) {
170 - // Strip the leading [ and trailing ]
171 - var matchParts = matchSet[i].substr(1, matchSet[i].length-2);
172 -
173 - // Check for special jQuery type swap and replace inner JQUERY_SWAP_STRING not value
174 - if( matchParts.indexOf( JQUERY_SWAP_STRING ) !== -1 ) {
175 - // parse the link as html
176 - var $matchParts = $j('<span>' + matchParts + '</span>' );
177 -
178 - $jQuerySpan = $matchParts.find('#' +JQUERY_SWAP_STRING + i );
179 -
180 - var linkText = $matchParts.text();
181 - //mw.log(" going to swap in linktext: " + linkText );
182 - $jQuerySpan.text( linkText );
183 -
184 - text = text.replace( LINK_SWAP_STRING, $j('<span />' ).append( $jQuerySpan ).html() );
185 - } else {
186 - // do text string replace
187 - matchParts = matchParts.split(/ /);
188 - var link = matchParts[0];
189 - matchParts.shift();
190 - var linkText = matchParts.join(' ');
191 -
192 - text = text.replace( LINK_SWAP_STRING, '<a href="' + link + '">' + linkText + '</a>' );
193 - }
194 - }
195 - return text;
196 - }
197 -
198 - /**
199 - * recurse_magic_swap
200 - *
201 - * Go last child first swap upward:
202 - */
203 - var pNode = null;
204 - function recurse_magic_swap( node ) {
205 - if ( !pNode )
206 - pNode = node;
207 -
208 - if ( node['child'] ) {
209 - // swap all the kids:
210 - for ( var i in node['child'] ) {
211 - var nodeText = recurse_magic_swap( node['child'][i] );
212 - // swap it into current
213 - if ( node.text ) {
214 - node.text = node.text.replace( node['child'][i].text, nodeText );
215 - }
216 - // swap into parent
217 - pNode.text = pNode.text.replace( node['child'][i].text, nodeText );
218 - }
219 - // Get the updated node text
220 - var nodeText = getMagicTxtFromTempNode( node );
221 - pNode.text = pNode.text.replace( node.text , nodeText );
222 - // return the node text
223 - return node.text;
224 - } else {
225 - return getMagicTxtFromTempNode( node );
226 - }
227 - }
228 -
229 - // Parse out the template node structure:
230 - this.pNode = recurseTokenizeNodes ( this.wikiText );
231 -
232 - // Strip out the parent from the root
233 - this.pNode['parent'] = null;
234 -
235 - // Do the recursive magic swap text:
236 - this.pOut = recurse_magic_swap( this.pNode );
237 -
238 - // Do link swap
239 - this.pOut = linkSwapText( this.pOut );
240 - },
241 -
242 - /**
243 - * templates
244 - *
245 - * Get a requested template from the wikitext (if available)
246 - * @param templateName
247 - */
248 - templates: function( templateName ) {
249 - this.parse();
250 - var tmplSet = new Array();
251 - function getMatchingTmpl( node ) {
252 - if ( node['child'] ) {
253 - for ( var i in node['child'] ) {
254 - getMatchingTmpl( node['child'] );
255 - }
256 - }
257 - if ( templateName && node.templateObject ) {
258 - if ( node.templateObject['name'] == templateName )
259 - tmplSet.push( node.templateObject );
260 - } else if ( node.templateObject ) {
261 - tmplSet.push( node.templateObject );
262 - }
263 - }
264 - getMatchingTmpl( this.pNode );
265 - return tmplSet;
266 - },
267 -
268 - /**
269 - * getTemplateVars
270 - * returns a set of template values in a given wikitext page
271 - *
272 - * NOTE: should be integrated with the usability wikitext parser
273 - */
274 - getTemplateVars: function() {
275 - //mw.log('matching against: ' + wikiText);
276 - templateVars = new Array();
277 - var tempVars = wikiText.match(/\{\{\{([^\}]*)\}\}\}/gi);
278 -
279 - // Clean up results:
280 - for(var i=0; i < tempVars.length; i++) {
281 - //match
282 - var tvar = tempVars[i].replace('{{{','').replace('}}}','');
283 -
284 - // Strip anything after a |
285 - if(tvar.indexOf('|') != -1) {
286 - tvar = tvar.substr(0, tvar.indexOf('|'));
287 - }
288 -
289 - // Check for duplicates:
290 - var do_add=true;
291 - for(var j=0; j < templateVars.length; j++) {
292 - if( templateVars[j] == tvar)
293 - do_add=false;
294 - }
295 -
296 - // Add the template vars to the output obj
297 - if(do_add)
298 - templateVars.push( tvar );
299 - }
300 - return templateVars;
301 - },
302 -
303 - /**
304 - * Returns the transformed wikitext
305 - *
306 - * Build output from swappable index
307 - * (all transforms must be expanded in parse stage and linearly rebuilt)
308 - * Alternatively we could build output using a place-holder & replace system
309 - * (this lets us be slightly more sloppy with ordering and indexes, but probably slower)
310 - *
311 - * Ideal: we build a 'wiki DOM'
312 - * When editing you update the data structure directly
313 - * Then in output time you just go DOM->html-ish output without re-parsing anything
314 - */
315 - getHTML: function() {
316 - // wikiText updates should invalidate pOut
317 - if ( ! this.pOut ) {
318 - this.parse();
319 - }
320 - return this.pOut;
321 - }
322 - };
323 -
324 -}) ( window.mw );
\ No newline at end of file
Index: trunk/extensions/MwEmbed/MwEmbed/components/mw.Language.js
@@ -1,1131 +0,0 @@
2 -/**
3 -* Core Language mw.Language object
4 -*
5 -* Localized Language support attempts to mirror some of the functionality of Language.php in MediaWiki
6 -* It contains methods for loading and transforming msg text
7 -
8 -*/
9 -
10 -( function( mw ) {
11 -
12 - // Setup the global mw.Language var:
13 - mw.Language = { };
14 -
15 - /**
16 - * Setup the lang object
17 - */
18 - var messageCache = { };
19 - var gRuleSet = { };
20 -
21 - /**
22 - * mw.addMessages function
23 - * Loads a set of json messages into the messegeCache object.
24 - *
25 - * @param {JSON} msgSet The set of msgs to be loaded
26 - */
27 - mw.addMessages = function( msgSet ) {
28 - for ( var i in msgSet ) {
29 - messageCache[ i ] = msgSet[i];
30 - }
31 - }
32 - // By default set the current class missing messages flag to default.
33 - mw.currentClassMissingMessages = false;
34 -
35 - /**
36 - * mw.addMessagesKey function
37 - * Adds a messageKey to be pulled in remotely.
38 - *
39 - * NOTE the script-loader should replace addMessageKeys with localized addMessages calls
40 - *
41 - * If addMessagesKey is called then we are running in raw file debug mode.
42 - * it populates the messegeKeyQueue and loads the values in a separate request callback
43 - *
44 - * @param {Array} msgSet The set of msgs to be loaded
45 - */
46 - mw.addMessageKeys = function( msgSet ) {
47 - // Check if any msg key from this class is missing
48 - for( i=0; i < msgSet.length; i++ ){
49 - msgKey = msgSet[i];
50 - if( ! messageCache[ msgKey ] ) {
51 - // Set the missing messages flag
52 - mw.currentClassMissingMessages = true;
53 - return false;
54 - }
55 - }
56 - return true;
57 - }
58 -
59 - /**
60 - * Special function to register that all of the module messages need to be loaded.
61 - */
62 - mw.includeAllModuleMessages = function (){
63 - mw.currentClassMissingMessages = true;
64 - }
65 -
66 - /**
67 - * Load messages for a given named javascript class.
68 - * This worked in conjunction with the scriptLoader
69 - * @param {string} className Name of class file to be loaded
70 - * @param {function} callback Function to be called once class messages are loaded.
71 - */
72 - mw.loadResourceMessages = function( className, callback ) {
73 - // Check if wgScriptLoaderPath is set ( else guess the path relative to mwEmbed)
74 - if ( typeof wgScriptLoaderLocation == 'undefined' || ! wgScriptLoaderLocation ){
75 - wgScriptLoaderLocation = mw.getMwEmbedPath() + 'ResourceLoader.php';
76 - }
77 - // Run the addMessages script-loader call
78 - mw.getScript( wgScriptLoaderLocation + '?class=' + className + '&format=messages', callback);
79 - }
80 -
81 -
82 - /**
83 - * Returns a transformed msg string
84 - *
85 - * it take a msg key and array of replacement values of form
86 - * $1, $2 and does relevant messageKey transformation returning
87 - * the user msg.
88 - *
89 - * @param {String} messageKey The msg key as set by mw.addMessages
90 - * @param {Mixed} args A string|jQuery Object or array of string|jQuery Objects
91 - *
92 - * extra parameters are appended to the args array as numbered replacements
93 - *
94 - * @return string
95 - */
96 - mw.getMsg = function( messageKey , args ) {
97 -
98 - // Check for missing message key
99 - if ( ! messageCache[ messageKey ] ){
100 - return '[' + messageKey + ']';
101 - }
102 - // Check if we need to do args replacements:
103 - if( typeof args != 'undefined' ) {
104 -
105 - // Make arg into an array if its not already an array
106 - if ( typeof args == 'string'
107 - || typeof args == 'number'
108 - || args instanceof jQuery )
109 - {
110 - args = [ args ];
111 - }
112 -
113 - // Put any extra arguments into the args array
114 - var extraArgs = $j.makeArray( arguments );
115 - for(var i=2; i < extraArgs.length; i ++ ) {
116 - args.push( extraArgs[ i ] );
117 - }
118 - }
119 - // Fast check message text return ( no arguments and no parsing needed )
120 - if( ( !args || args.length == 0 )
121 - && messageCache[ messageKey ].indexOf( '{{' ) === -1
122 - && messageCache[ messageKey ].indexOf( '[' ) === -1
123 - ) {
124 - return messageCache[ messageKey ];
125 - }
126 -
127 - // Else Setup the messageSwap object:
128 - var messageSwap = new mw.Language.messageSwapObject( messageCache[ messageKey ], args );
129 -
130 - // Return the jQuery object or message string
131 - return messageSwap.getMsg();
132 - }
133 -
134 - /**
135 - * A message Swap Object
136 - * Swap object manages message type swapping and returns jQuery or text output
137 - *
138 - * @param {String} message The text of the message
139 - * @param {array} arguments A set of swap arguments
140 - */
141 -
142 - mw.Language.messageSwapObject = function( message, arguments ){
143 - this.init( message, arguments );
144 - }
145 -
146 - mw.Language.messageSwapObject.prototype= {
147 - /* constructor */
148 - init: function( message, arguments ){
149 - this.message = message;
150 - this.arguments = arguments;
151 -
152 - // Set the includesjQueryArgs flag to false
153 - includesjQueryArgs: false;
154 - },
155 -
156 - // Return the transformed message text or jQuery object
157 - getMsg: function(){
158 - // Get message with string swap
159 - this.replaceStringArgs();
160 -
161 - // Check if we need to parse the string
162 - if( this.message.indexOf( '{{' ) === -1
163 - && this.message.indexOf( '[' ) === -1
164 - && ! this.includesjQueryArgs )
165 - {
166 - // replaceStringArgs is all we need, return the msg
167 - return this.message
168 - }
169 -
170 - // Else Send the messageText through the parser
171 - var pObj = new mw.Parser( this.message );
172 -
173 - // Get template and link transformed text:
174 - this.message = pObj.getHTML();
175 -
176 - // if jQuery arguments is false return message string
177 - if(! this.includesjQueryArgs ){
178 - //Do string link substitution
179 - return this.message;
180 - }
181 -
182 - // jQuery arguments exist swap and return jQuery object
183 - return this.getJQueryArgsReplace();
184 -
185 - },
186 -
187 - /**
188 - * Swap in an array of values for $1, $2, $n for a given msg key
189 - *
190 - * @param string messageKey The msg key to lookup
191 - * @param {Array} args An array of string or jQuery objects to be swapped in
192 - * @return string
193 - */
194 - replaceStringArgs : function() {
195 - if( ! this.arguments ) {
196 - return ;
197 - }
198 - // Replace Values
199 - for ( var v = 0; v < this.arguments.length; v++ ) {
200 - if( typeof this.arguments[v] == 'undefined' ) {
201 - continue;
202 - }
203 - var replaceValue = this.arguments[ v ];
204 -
205 - // Convert number if applicable
206 - if( parseInt( replaceValue ) == replaceValue ) {
207 - replaceValue = mw.Language.convertNumber( replaceValue );
208 - }
209 -
210 - // Message test replace arguments start at 1 instead of zero:
211 - var argumentRegExp = new RegExp( '\\$' + ( parseInt( v ) + 1 ), 'g' );
212 -
213 - // Check if we got passed in a jQuery object:
214 - if( replaceValue instanceof jQuery) {
215 - // Set the jQuery msg flag
216 - this.includesjQueryArgs = true;
217 - // Swap in a jQuery span place holder:
218 - this.message = this.message.replace( argumentRegExp,
219 - '<span id="' + JQUERY_SWAP_STRING + v +'"></span>' );
220 - } else {
221 - // Assume replaceValue is a string
222 - this.message = this.message.replace( argumentRegExp, replaceValue );
223 - }
224 - }
225 - },
226 -
227 - /**
228 - * Return a jquery element with resolved swapped arguments.
229 - * return {Element}
230 - */
231 - getJQueryArgsReplace: function() {
232 - var $jQueryMessage = false;
233 - mw.log( 'msgReplaceJQueryArgs' );
234 - for ( var v = 0; v < this.arguments.length; v++ ) {
235 - if( typeof this.arguments[v] == 'undefined' ) {
236 - continue;
237 - }
238 - var $replaceValue = this.arguments[ v ];
239 - // Only look for jQuery replacements
240 - if( $replaceValue instanceof jQuery) {
241 - // Setup the jqueryMessage if not set
242 - if( !$jQueryMessage ){
243 - // Setup the message as html to search for jquery swap points
244 - $jQueryMessage = $j( '<span />' ).html( this.message );
245 - }
246 - mw.log(" current jQueryMessage::: " + $jQueryMessage.html() );
247 - // Find swap target
248 - var $swapTarget = $jQueryMessage.find( '#' + JQUERY_SWAP_STRING + v );
249 - // Now we try and find the jQuerySwap points and replace with jQuery object preserving bindings.
250 - if( ! $swapTarget.length ){
251 - mw.log( "Error could not find jQuery Swap target: " + v + ' by id: '+ JQUERY_SWAP_STRING + v
252 - + ' In string: ' + this.message ) ;
253 - continue;
254 - }
255 -
256 - if( $swapTarget.html() != '' ) {
257 - $replaceValue.html( $swapTarget.html() );
258 - }
259 -
260 - // Swap for $swapTarget for $replaceValue swap target * preserving the jQuery binding )
261 - $swapTarget.replaceWith( $replaceValue );
262 - }
263 - }
264 - // Return the jQuery object ( if no jQuery substitution occurred we return false )
265 - return $jQueryMessage;
266 - }
267 - }
268 -
269 - /**
270 - * Get msg content without transformation
271 - *
272 - * @returns string The msg key without transforming it
273 - */
274 - mw.Language.msgNoTrans = function( key ) {
275 - if ( messageCache[ key ] )
276 - return messageCache[ key ]
277 -
278 - // Missing key placeholder
279 - return '&lt;' + key + '&gt;';
280 - }
281 - /**
282 - * Check if a message key is defined
283 - * @return {Boolean} true if msg is defined, false if msg is not set
284 - */
285 - mw.Language.isMsgKeyDefined = function( msgKey ){
286 - if( messageCache[ msgKey ] ){
287 - return true
288 - }
289 - return false;
290 - }
291 -
292 - /**
293 - * Add Supported Magic Words to parser
294 - */
295 - // Set the setupflag to false:
296 - mw.Language.doneSetup = false;
297 - mw.Language.magicSetup = function() {
298 - if ( !mw.Language.doneSetup ) {
299 - mw.addTemplateTransform ( {
300 - 'PLURAL' : mw.Language.procPLURAL,
301 - 'GENDER' : mw.Language.procGENDER
302 - } )
303 -
304 - mw.Language.doneSetup = true;
305 - }
306 -
307 - }
308 -
309 - /**
310 - * Plural form transformations, needed for some languages.
311 - * For example, there are 3 form of plural in Russian and Polish,
312 - * depending on "count mod 10". See [[w:Plural]]
313 - * For English it is pretty simple.
314 - *
315 - * Invoked by putting {{plural:count|wordform1|wordform2}}
316 - * or {{plural:count|wordform1|wordform2|wordform3}}
317 - *
318 - * Example: {{plural:{{NUMBEROFARTICLES}}|article|articles}}
319 - *
320 - * @param count Integer: non-localized number
321 - * @param forms Array: different plural forms
322 - * @return string Correct form of plural for count in this language
323 - */
324 -
325 - /**
326 - * Base gender transform function
327 - */
328 - mw.Language.gender = function( gender, forms ) {
329 - if ( ! forms.length ) {
330 - return '';
331 - }
332 - forms = mw.Language.preConvertPlural( forms, 2 );
333 - if ( gender === 'male' ) return forms[0];
334 - if ( gender === 'female' ) return forms[1];
335 - return ( forms[2] ) ? forms[2] : forms[0];
336 - };
337 -
338 - /**
339 - * Process the PLURAL template substitution
340 - * @param {Object} template Template object
341 - *
342 - * {{Template:argument|params}}
343 - *
344 - * Template object should include:
345 - * [arg] The argument sent to the template
346 - * [params] The template parameters
347 - */
348 - mw.Language.procPLURAL = function( templateObject ) {
349 - // Setup shortcuts
350 - // ( gRuleSet is loaded from script-loader to contains local ruleset )
351 - var rs = gRuleSet[ 'PLURAL' ];
352 -
353 - if( templateObject.arg && templateObject.param && mw.Language.convertPlural) {
354 - // Check if we have forms to replace
355 - if ( templateObject.param.length == 0 ) {
356 - return '';
357 - }
358 - // Restore the count into a Number ( if it got converted earlier )
359 - var count = mw.Language.convertNumber( templateObject.arg, true );
360 -
361 - // Do convertPlural call
362 - return mw.Language.convertPlural( parseInt( count ), templateObject.param );
363 -
364 - }
365 - // Could not process plural return first form or nothing
366 - if( templateObject.param[0] ) {
367 - return templateObject.param[0];
368 - }
369 - return '';
370 - };
371 -
372 - // NOTE:: add gender support here
373 - mw.Language.procGENDER = function( templateObject ){
374 - return 'gender-not-supported-in-js-yet';
375 - }
376 - /*
377 - * Base convertPlural function:
378 - */
379 - mw.Language.convertPlural = function( count, forms ){
380 - if ( !forms || forms.length == 0 ) {
381 - return '';
382 - }
383 - return ( parseInt( count ) == 1 ) ? forms[0] : forms[1];
384 - };
385 - /**
386 - * Checks that convertPlural was given an array and pads it to requested
387 - * amount of forms by copying the last one.
388 - *
389 - * @param {Array} forms Forms given to convertPlural
390 - * @param {Integer} count How many forms should there be at least
391 - * @return {Array} Padded array of forms or an exception if not an array
392 - */
393 - mw.Language.preConvertPlural = function( forms, count ) {
394 - while ( forms.length < count ) {
395 - forms.push( forms[ forms.length-1 ] );
396 - }
397 - return forms;
398 - };
399 -
400 - /**
401 - * Init the digitTransformTable ( populated by language classes where applicable )
402 - */
403 - mw.Language.digitTransformTable = null;
404 -
405 - /**
406 - * Convert a number using the digitTransformTable
407 - * @param Number number to be converted
408 - * @param Bollean typeInt if we should return a number of type int
409 - */
410 - mw.Language.convertNumber = function( number, typeInt ) {
411 - if( !mw.Language.digitTransformTable )
412 - return number;
413 -
414 - // Set the target Transform table:
415 - var transformTable = mw.Language.digitTransformTable;
416 -
417 - // Check if the "restore" to latin number flag is set:
418 - if( typeInt ) {
419 - if( parseInt( number ) == number )
420 - return number;
421 - var tmp = [];
422 - for( var i in transformTable ) {
423 - tmp[ transformTable[ i ] ] = i;
424 - }
425 - transformTable = tmp;
426 - }
427 -
428 - var numberString = '' + number;
429 - var convertedNumber = '';
430 - for( var i =0; i < numberString.length; i++) {
431 - if( transformTable[ numberString[i] ] ) {
432 - convertedNumber += transformTable[ numberString[i] ];
433 - }else{
434 - convertedNumber += numberString[i];
435 - }
436 - }
437 - return ( typeInt )? parseInt( convertedNumber) : convertedNumber;
438 - }
439 -
440 - /**
441 - * Checks if a language key is valid ( is part of languageCodeList )
442 - * @param {String} langKey Language key to be checked
443 - * @return true if valid language, false if not
444 - */
445 - mw.isValidLang = function( langKey ) {
446 - return ( mw.Language.names[ langKey ] )? true : false;
447 - }
448 -
449 - /**
450 - * Get a language transform key
451 - * returns default "en" fallback if none found
452 - * @param String langKey The language key to be checked
453 - */
454 - mw.getLangTransformKey = function( langKey ) {
455 - if( mw.Language.fallbackTransformMap[ langKey ] ) {
456 - langKey = mw.Language.fallbackTransformMap[ langKey ];
457 - }
458 - // Make sure the langKey has a transformClass:
459 - for( var i = 0; i < mw.Language.transformClass.length ; i++ ) {
460 - if( langKey == mw.Language.transformClass[i] ){
461 - return langKey
462 - }
463 - }
464 - // By default return the base 'en' class
465 - return 'en';
466 - }
467 -
468 - /**
469 - * getRemoteMsg loads remote msg strings
470 - *
471 - * @param {Mixed} msgSet the set of msg to load remotely
472 - * @param function callback the callback to issue once string is ready
473 - */
474 - mw.getRemoteMsg = function( msgSet, callback ) {
475 - var ammessages = '';
476 - if ( typeof msgSet == 'object' ) {
477 - for ( var i in msgSet ) {
478 - if( !messageCache[ i ] ) {
479 - ammessages += msgSet[i] + '|';
480 - }
481 - }
482 - } else if ( typeof msgSet == 'string' ) {
483 - if( !messageCache[ i ] ) {
484 - ammessages += msgSet;
485 - }
486 - }
487 - if ( ammessages == '' ) {
488 - mw.log( 'no remote msgs to get' );
489 - callback();
490 - return false;
491 - }
492 - var request = {
493 - 'meta': 'allmessages',
494 - 'ammessages': ammessages
495 - }
496 - mw.getJSON( request, function( data ) {
497 - if ( data.query.allmessages ) {
498 - var msgs = data.query.allmessages;
499 - for ( var i in msgs ) {
500 - var ld = { };
501 - ld[ msgs[i]['name'] ] = msgs[i]['*'];
502 - mw.addMessages( ld );
503 - }
504 - }
505 - callback();
506 - } );
507 - }
508 -
509 - /**
510 - * Format a size in bytes for output, using an appropriate
511 - * unit (B, KB, MB or GB) according to the magnitude in question
512 - *
513 - * @param size Size to format
514 - * @return string Plain text (not HTML)
515 - */
516 - mw.Language.formatSize = function ( size ) {
517 - // For small sizes no decimal places are necessary
518 - var round = 0;
519 - var msg = '';
520 - if ( size > 1024 ) {
521 - size = size / 1024;
522 - if ( size > 1024 ) {
523 - size = size / 1024;
524 - // For MB and bigger two decimal places are smarter
525 - round = 2;
526 - if ( size > 1024 ) {
527 - size = size / 1024;
528 - msg = 'mwe-size-gigabytes';
529 - } else {
530 - msg = 'mwe-size-megabytes';
531 - }
532 - } else {
533 - msg = 'mwe-size-kilobytes';
534 - }
535 - } else {
536 - msg = 'mwe-size-bytes';
537 - }
538 - // JavaScript does not let you choose the precision when rounding
539 - var p = Math.pow( 10, round );
540 - size = Math.round( size * p ) / p;
541 - return gM( msg , size );
542 - };
543 -
544 - /**
545 - * Format a number
546 - * @param {Number} num Number to be formated
547 - * NOTE: add il8n support to lanuages/class/Language{langCode}.js
548 - */
549 - mw.Language.formatNumber = function( num ) {
550 - /*
551 - * addSeparatorsNF
552 - * @param Str: The number to be formatted, as a string or number.
553 - * @param outD: The decimal character for the output, such as ',' for the number 100,2
554 - * @param sep: The separator character for the output, such as ',' for the number 1,000.2
555 - */
556 - function addSeparatorsNF( nStr, outD, sep ) {
557 - nStr += '';
558 - var dpos = nStr.indexOf( '.' );
559 - var nStrEnd = '';
560 - if ( dpos != -1 ) {
561 - nStrEnd = outD + nStr.substring( dpos + 1, nStr.length );
562 - nStr = nStr.substring( 0, dpos );
563 - }
564 - var rgx = /(\d+)(\d{3})/;
565 - while ( rgx.test( nStr ) ) {
566 - nStr = nStr.replace( rgx, '$1' + sep + '$2' );
567 - }
568 - return nStr + nStrEnd;
569 - }
570 - // @@todo read language code and give periods or comas:
571 - return addSeparatorsNF( num, '.', ',' );
572 - }
573 -
574 -
575 - /**
576 - * List of all languages mediaWiki supports ( Avoid an api call to get this same info )
577 - * http://commons.wikimedia.org/w/api.php?action=query&meta=siteinfo&siprop=languages&format=jsonfm
578 - */
579 - mw.Language.names = {
580 - "aa" : "Qaf\u00e1r af",
581 - "ab" : "\u0410\u04a7\u0441\u0443\u0430",
582 - "ace" : "Ac\u00e8h",
583 - "af" : "Afrikaans",
584 - "ak" : "Akan",
585 - "aln" : "Geg\u00eb",
586 - "als" : "Alemannisch",
587 - "am" : "\u12a0\u121b\u122d\u129b",
588 - "an" : "Aragon\u00e9s",
589 - "ang" : "Anglo-Saxon",
590 - "ar" : "\u0627\u0644\u0639\u0631\u0628\u064a\u0629",
591 - "arc" : "\u0710\u072a\u0721\u071d\u0710",
592 - "arn" : "Mapudungun",
593 - "arz" : "\u0645\u0635\u0631\u0649",
594 - "as" : "\u0985\u09b8\u09ae\u09c0\u09af\u09bc\u09be",
595 - "ast" : "Asturianu",
596 - "av" : "\u0410\u0432\u0430\u0440",
597 - "avk" : "Kotava",
598 - "ay" : "Aymar aru",
599 - "az" : "Az\u0259rbaycan",
600 - "ba" : "\u0411\u0430\u0448\u04a1\u043e\u0440\u0442",
601 - "bar" : "Boarisch",
602 - "bat-smg" : "\u017demait\u0117\u0161ka",
603 - "bcc" : "\u0628\u0644\u0648\u0686\u06cc \u0645\u06a9\u0631\u0627\u0646\u06cc",
604 - "bcl" : "Bikol Central",
605 - "be" : "\u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f",
606 - "be-tarask" : "\u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f (\u0442\u0430\u0440\u0430\u0448\u043a\u0435\u0432\u0456\u0446\u0430)",
607 - "be-x-old" : "\u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f (\u0442\u0430\u0440\u0430\u0448\u043a\u0435\u0432\u0456\u0446\u0430)",
608 - "bg" : "\u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438",
609 - "bh" : "\u092d\u094b\u091c\u092a\u0941\u0930\u0940",
610 - "bi" : "Bislama",
611 - "bm" : "Bamanankan",
612 - "bn" : "\u09ac\u09be\u0982\u09b2\u09be",
613 - "bo" : "\u0f56\u0f7c\u0f51\u0f0b\u0f61\u0f72\u0f42",
614 - "bpy" : "\u0987\u09ae\u09be\u09b0 \u09a0\u09be\u09b0\/\u09ac\u09bf\u09b7\u09cd\u09a3\u09c1\u09aa\u09cd\u09b0\u09bf\u09af\u09bc\u09be \u09ae\u09a3\u09bf\u09aa\u09c1\u09b0\u09c0",
615 - "bqi" : "\u0628\u062e\u062a\u064a\u0627\u0631\u064a",
616 - "br" : "Brezhoneg",
617 - "bs" : "Bosanski",
618 - "bug" : "\u1a05\u1a14 \u1a15\u1a18\u1a01\u1a17",
619 - "bxr" : "\u0411\u0443\u0440\u044f\u0430\u0434",
620 - "ca" : "Catal\u00e0",
621 - "cbk-zam" : "Chavacano de Zamboanga",
622 - "cdo" : "M\u00ecng-d\u0115\u0324ng-ng\u1e73\u0304",
623 - "ce" : "\u041d\u043e\u0445\u0447\u0438\u0439\u043d",
624 - "ceb" : "Cebuano",
625 - "ch" : "Chamoru",
626 - "cho" : "Choctaw",
627 - "chr" : "\u13e3\u13b3\u13a9",
628 - "chy" : "Tsets\u00eahest\u00e2hese",
629 - "ckb" : "Soran\u00ee \/ \u06a9\u0648\u0631\u062f\u06cc",
630 - "ckb-latn" : "\u202aSoran\u00ee (lat\u00een\u00ee)\u202c",
631 - "ckb-arab" : "\u202b\u06a9\u0648\u0631\u062f\u06cc (\u0639\u06d5\u0631\u06d5\u0628\u06cc)\u202c",
632 - "co" : "Corsu",
633 - "cr" : "N\u0113hiyaw\u0113win \/ \u14c0\u1426\u1403\u152d\u140d\u140f\u1423",
634 - "crh" : "Q\u0131r\u0131mtatarca",
635 - "crh-latn" : "\u202aQ\u0131r\u0131mtatarca (Latin)\u202c",
636 - "crh-cyrl" : "\u202a\u041a\u044a\u044b\u0440\u044b\u043c\u0442\u0430\u0442\u0430\u0440\u0434\u0436\u0430 (\u041a\u0438\u0440\u0438\u043b\u043b)\u202c",
637 - "cs" : "\u010cesky",
638 - "csb" : "Kasz\u00ebbsczi",
639 - "cu" : "\u0421\u043b\u043e\u0432\u0463\u0301\u043d\u044c\u0441\u043a\u044a \/ \u2c14\u2c0e\u2c11\u2c02\u2c21\u2c10\u2c20\u2c14\u2c0d\u2c1f",
640 - "cv" : "\u0427\u04d1\u0432\u0430\u0448\u043b\u0430",
641 - "cy" : "Cymraeg",
642 - "da" : "Dansk",
643 - "de" : "Deutsch",
644 - "de-at" : "\u00d6sterreichisches Deutsch",
645 - "de-ch" : "Schweizer Hochdeutsch",
646 - "de-formal" : "Deutsch (Sie-Form)",
647 - "diq" : "Zazaki",
648 - "dk" : "Dansk (deprecated:da)",
649 - "dsb" : "Dolnoserbski",
650 - "dv" : "\u078b\u07a8\u0788\u07ac\u0780\u07a8\u0784\u07a6\u0790\u07b0",
651 - "dz" : "\u0f47\u0f7c\u0f44\u0f0b\u0f41",
652 - "ee" : "E\u028begbe",
653 - "el" : "\u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac",
654 - "eml" : "Emili\u00e0n e rumagn\u00f2l",
655 - "en" : "English",
656 - "en-gb" : "British English",
657 - "eo" : "Esperanto",
658 - "es" : "Espa\u00f1ol",
659 - "et" : "Eesti",
660 - "eu" : "Euskara",
661 - "ext" : "Estreme\u00f1u",
662 - "fa" : "\u0641\u0627\u0631\u0633\u06cc",
663 - "ff" : "Fulfulde",
664 - "fi" : "Suomi",
665 - "fiu-vro" : "V\u00f5ro",
666 - "fj" : "Na Vosa Vakaviti",
667 - "fo" : "F\u00f8royskt",
668 - "fr" : "Fran\u00e7ais",
669 - "frc" : "Fran\u00e7ais cadien",
670 - "frp" : "Arpetan",
671 - "fur" : "Furlan",
672 - "fy" : "Frysk",
673 - "ga" : "Gaeilge",
674 - "gag" : "Gagauz",
675 - "gan" : "\u8d1b\u8a9e",
676 - "gan-hans" : "\u8d63\u8bed(\u7b80\u4f53)",
677 - "gan-hant" : "\u8d1b\u8a9e(\u7e41\u9ad4)",
678 - "gd" : "G\u00e0idhlig",
679 - "gl" : "Galego",
680 - "glk" : "\u06af\u06cc\u0644\u06a9\u06cc",
681 - "gn" : "Ava\u00f1e'\u1ebd",
682 - "got" : "\ud800\udf32\ud800\udf3f\ud800\udf44\ud800\udf39\ud800\udf43\ud800\udf3a",
683 - "grc" : "\u1f08\u03c1\u03c7\u03b1\u03af\u03b1 \u1f11\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u1f74",
684 - "gsw" : "Alemannisch",
685 - "gu" : "\u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0",
686 - "gv" : "Gaelg",
687 - "ha" : "\u0647\u064e\u0648\u064f\u0633\u064e",
688 - "hak" : "Hak-k\u00e2-fa",
689 - "haw" : "Hawai`i",
690 - "he" : "\u05e2\u05d1\u05e8\u05d9\u05ea",
691 - "hi" : "\u0939\u093f\u0928\u094d\u0926\u0940",
692 - "hif" : "Fiji Hindi",
693 - "hif-deva" : "\u092b\u093c\u0940\u091c\u0940 \u0939\u093f\u0928\u094d\u0926\u0940",
694 - "hif-latn" : "Fiji Hindi",
695 - "hil" : "Ilonggo",
696 - "ho" : "Hiri Motu",
697 - "hr" : "Hrvatski",
698 - "hsb" : "Hornjoserbsce",
699 - "ht" : "Krey\u00f2l ayisyen",
700 - "hu" : "Magyar",
701 - "hy" : "\u0540\u0561\u0575\u0565\u0580\u0565\u0576",
702 - "hz" : "Otsiherero",
703 - "ia" : "Interlingua",
704 - "id" : "Bahasa Indonesia",
705 - "ie" : "Interlingue",
706 - "ig" : "Igbo",
707 - "ii" : "\ua187\ua259",
708 - "ik" : "I\u00f1upiak",
709 - "ike-cans" : "\u1403\u14c4\u1483\u144e\u1450\u1466",
710 - "ike-latn" : "inuktitut",
711 - "ilo" : "Ilokano",
712 - "inh" : "\u0413\u0406\u0430\u043b\u0433\u0406\u0430\u0439 \u011eal\u011faj",
713 - "io" : "Ido",
714 - "is" : "\u00cdslenska",
715 - "it" : "Italiano",
716 - "iu" : "\u1403\u14c4\u1483\u144e\u1450\u1466\/inuktitut",
717 - "ja" : "\u65e5\u672c\u8a9e",
718 - "jbo" : "Lojban",
719 - "jut" : "Jysk",
720 - "jv" : "Basa Jawa",
721 - "ka" : "\u10e5\u10d0\u10e0\u10d7\u10e3\u10da\u10d8",
722 - "kaa" : "Qaraqalpaqsha",
723 - "kab" : "Taqbaylit",
724 - "kg" : "Kongo",
725 - "ki" : "G\u0129k\u0169y\u0169",
726 - "kiu" : "Kurmanc\u00ee",
727 - "kj" : "Kwanyama",
728 - "kk" : "\u049a\u0430\u0437\u0430\u049b\u0448\u0430",
729 - "kk-arab" : "\u202b\u0642\u0627\u0632\u0627\u0642\u0634\u0627 (\u062a\u0674\u0648\u062a\u06d5)\u202c",
730 - "kk-cyrl" : "\u202a\u049a\u0430\u0437\u0430\u049b\u0448\u0430 (\u043a\u0438\u0440\u0438\u043b)\u202c",
731 - "kk-latn" : "\u202aQazaq\u015fa (lat\u0131n)\u202c",
732 - "kk-cn" : "\u202b\u0642\u0627\u0632\u0627\u0642\u0634\u0627 (\u062c\u06c7\u0646\u06af\u0648)\u202c",
733 - "kk-kz" : "\u202a\u049a\u0430\u0437\u0430\u049b\u0448\u0430 (\u049a\u0430\u0437\u0430\u049b\u0441\u0442\u0430\u043d)\u202c",
734 - "kk-tr" : "\u202aQazaq\u015fa (T\u00fcrk\u00efya)\u202c",
735 - "kl" : "Kalaallisut",
736 - "km" : "\u1797\u17b6\u179f\u17b6\u1781\u17d2\u1798\u17c2\u179a",
737 - "kn" : "\u0c95\u0ca8\u0ccd\u0ca8\u0ca1",
738 - "ko" : "\ud55c\uad6d\uc5b4",
739 - "ko-kp" : "\ud55c\uad6d\uc5b4 (\uc870\uc120)",
740 - "kr" : "Kanuri",
741 - "kri" : "Krio",
742 - "krj" : "Kinaray-a",
743 - "ks" : "\u0915\u0936\u094d\u092e\u0940\u0930\u0940 - (\u0643\u0634\u0645\u064a\u0631\u064a)",
744 - "ksh" : "Ripoarisch",
745 - "ku" : "Kurd\u00ee \/ \u0643\u0648\u0631\u062f\u06cc",
746 - "ku-latn" : "\u202aKurd\u00ee (lat\u00een\u00ee)\u202c",
747 - "ku-arab" : "\u202b\u0643\u0648\u0631\u062f\u064a (\u0639\u06d5\u0631\u06d5\u0628\u06cc)\u202c",
748 - "kv" : "\u041a\u043e\u043c\u0438",
749 - "kw" : "Kernowek",
750 - "ky" : "\u041a\u044b\u0440\u0433\u044b\u0437\u0447\u0430",
751 - "la" : "Latina",
752 - "lad" : "Ladino",
753 - "lb" : "L\u00ebtzebuergesch",
754 - "lbe" : "\u041b\u0430\u043a\u043a\u0443",
755 - "lez" : "\u041b\u0435\u0437\u0433\u0438",
756 - "lfn" : "Lingua Franca Nova",
757 - "lg" : "Luganda",
758 - "li" : "Limburgs",
759 - "lij" : "L\u00edguru",
760 - "lmo" : "Lumbaart",
761 - "ln" : "Ling\u00e1la",
762 - "lo" : "\u0ea5\u0eb2\u0ea7",
763 - "loz" : "Silozi",
764 - "lt" : "Lietuvi\u0173",
765 - "lv" : "Latvie\u0161u",
766 - "lzh" : "\u6587\u8a00",
767 - "mai" : "\u092e\u0948\u0925\u093f\u0932\u0940",
768 - "map-bms" : "Basa Banyumasan",
769 - "mdf" : "\u041c\u043e\u043a\u0448\u0435\u043d\u044c",
770 - "mg" : "Malagasy",
771 - "mh" : "Ebon",
772 - "mhr" : "\u041e\u043b\u044b\u043a \u041c\u0430\u0440\u0438\u0439",
773 - "mi" : "M\u0101ori",
774 - "mk" : "\u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438",
775 - "ml" : "\u0d2e\u0d32\u0d2f\u0d3e\u0d33\u0d02",
776 - "mn" : "\u041c\u043e\u043d\u0433\u043e\u043b",
777 - "mo" : "\u041c\u043e\u043b\u0434\u043e\u0432\u0435\u043d\u044f\u0441\u043a\u044d",
778 - "mr" : "\u092e\u0930\u093e\u0920\u0940",
779 - "ms" : "Bahasa Melayu",
780 - "mt" : "Malti",
781 - "mus" : "Mvskoke",
782 - "mwl" : "Mirand\u00e9s",
783 - "my" : "\u1019\u103c\u1014\u103a\u1019\u102c\u1018\u102c\u101e\u102c",
784 - "myv" : "\u042d\u0440\u0437\u044f\u043d\u044c",
785 - "mzn" : "\u0645\u064e\u0632\u0650\u0631\u0648\u0646\u064a",
786 - "na" : "Dorerin Naoero",
787 - "nah" : "N\u0101huatl",
788 - "nan" : "B\u00e2n-l\u00e2m-g\u00fa",
789 - "nap" : "Nnapulitano",
790 - "nb" : "\u202aNorsk (bokm\u00e5l)\u202c",
791 - "nds" : "Plattd\u00fc\u00fctsch",
792 - "nds-nl" : "Nedersaksisch",
793 - "ne" : "\u0928\u0947\u092a\u093e\u0932\u0940",
794 - "new" : "\u0928\u0947\u092a\u093e\u0932 \u092d\u093e\u0937\u093e",
795 - "ng" : "Oshiwambo",
796 - "niu" : "Niu\u0113",
797 - "nl" : "Nederlands",
798 - "nn" : "\u202aNorsk (nynorsk)\u202c",
799 - "no" : "\u202aNorsk (bokm\u00e5l)\u202c",
800 - "nov" : "Novial",
801 - "nrm" : "Nouormand",
802 - "nso" : "Sesotho sa Leboa",
803 - "nv" : "Din\u00e9 bizaad",
804 - "ny" : "Chi-Chewa",
805 - "oc" : "Occitan",
806 - "om" : "Oromoo",
807 - "or" : "\u0b13\u0b21\u0b3c\u0b3f\u0b06",
808 - "os" : "\u0418\u0440\u043e\u043d\u0430\u0443",
809 - "pa" : "\u0a2a\u0a70\u0a1c\u0a3e\u0a2c\u0a40",
810 - "pag" : "Pangasinan",
811 - "pam" : "Kapampangan",
812 - "pap" : "Papiamentu",
813 - "pcd" : "Picard",
814 - "pdc" : "Deitsch",
815 - "pdt" : "Plautdietsch",
816 - "pfl" : "Pf\u00e4lzisch",
817 - "pi" : "\u092a\u093e\u093f\u0934",
818 - "pih" : "Norfuk \/ Pitkern",
819 - "pl" : "Polski",
820 - "pms" : "Piemont\u00e8is",
821 - "pnb" : "\u067e\u0646\u062c\u0627\u0628\u06cc",
822 - "pnt" : "\u03a0\u03bf\u03bd\u03c4\u03b9\u03b1\u03ba\u03ac",
823 - "ps" : "\u067e\u069a\u062a\u0648",
824 - "pt" : "Portugu\u00eas",
825 - "pt-br" : "Portugu\u00eas do Brasil",
826 - "qu" : "Runa Simi",
827 - "rif" : "Tarifit",
828 - "rm" : "Rumantsch",
829 - "rmy" : "Romani",
830 - "rn" : "Kirundi",
831 - "ro" : "Rom\u00e2n\u0103",
832 - "roa-rup" : "Arm\u00e3neashce",
833 - "roa-tara" : "Tarand\u00edne",
834 - "ru" : "\u0420\u0443\u0441\u0441\u043a\u0438\u0439",
835 - "ruq" : "Vl\u0103he\u015fte",
836 - "ruq-cyrl" : "\u0412\u043b\u0430\u0445\u0435\u0441\u0442\u0435",
837 - "ruq-latn" : "Vl\u0103he\u015fte",
838 - "rw" : "Kinyarwanda",
839 - "sa" : "\u0938\u0902\u0938\u094d\u0915\u0943\u0924",
840 - "sah" : "\u0421\u0430\u0445\u0430 \u0442\u044b\u043b\u0430",
841 - "sc" : "Sardu",
842 - "scn" : "Sicilianu",
843 - "sco" : "Scots",
844 - "sd" : "\u0633\u0646\u068c\u064a",
845 - "sdc" : "Sassaresu",
846 - "se" : "S\u00e1megiella",
847 - "sei" : "Cmique Itom",
848 - "sg" : "S\u00e4ng\u00f6",
849 - "sh" : "Srpskohrvatski \/ \u0421\u0440\u043f\u0441\u043a\u043e\u0445\u0440\u0432\u0430\u0442\u0441\u043a\u0438",
850 - "shi" : "Ta\u0161l\u1e25iyt",
851 - "si" : "\u0dc3\u0dd2\u0d82\u0dc4\u0dbd",
852 - "simple" : "Simple English",
853 - "sk" : "Sloven\u010dina",
854 - "sl" : "Sloven\u0161\u010dina",
855 - "sli" : "Schl\u00e4sch",
856 - "sm" : "Gagana Samoa",
857 - "sma" : "\u00c5arjelsaemien",
858 - "sn" : "chiShona",
859 - "so" : "Soomaaliga",
860 - "sq" : "Shqip",
861 - "sr" : "\u0421\u0440\u043f\u0441\u043a\u0438 \/ Srpski",
862 - "sr-ec" : "\u0421\u0440\u043f\u0441\u043a\u0438 (\u045b\u0438\u0440\u0438\u043b\u0438\u0446\u0430)",
863 - "sr-el" : "Srpski (latinica)",
864 - "srn" : "Sranantongo",
865 - "ss" : "SiSwati",
866 - "st" : "Sesotho",
867 - "stq" : "Seeltersk",
868 - "su" : "Basa Sunda",
869 - "sv" : "Svenska",
870 - "sw" : "Kiswahili",
871 - "szl" : "\u015al\u016fnski",
872 - "ta" : "\u0ba4\u0bae\u0bbf\u0bb4\u0bcd",
873 - "tcy" : "\u0ca4\u0cc1\u0cb3\u0cc1",
874 - "te" : "\u0c24\u0c46\u0c32\u0c41\u0c17\u0c41",
875 - "tet" : "Tetun",
876 - "tg" : "\u0422\u043e\u04b7\u0438\u043a\u04e3",
877 - "tg-cyrl" : "\u0422\u043e\u04b7\u0438\u043a\u04e3",
878 - "tg-latn" : "tojik\u012b",
879 - "th" : "\u0e44\u0e17\u0e22",
880 - "ti" : "\u1275\u130d\u122d\u129b",
881 - "tk" : "T\u00fcrkmen\u00e7e",
882 - "tl" : "Tagalog",
883 - "tn" : "Setswana",
884 - "to" : "lea faka-Tonga",
885 - "tokipona" : "Toki Pona",
886 - "tp" : "Toki Pona (deprecated:tokipona)",
887 - "tpi" : "Tok Pisin",
888 - "tr" : "T\u00fcrk\u00e7e",
889 - "ts" : "Xitsonga",
890 - "tt" : "\u0422\u0430\u0442\u0430\u0440\u0447\u0430\/Tatar\u00e7a",
891 - "tt-cyrl" : "\u0422\u0430\u0442\u0430\u0440\u0447\u0430",
892 - "tt-latn" : "Tatar\u00e7a",
893 - "tum" : "chiTumbuka",
894 - "tw" : "Twi",
895 - "ty" : "Reo M\u0101`ohi",
896 - "tyv" : "\u0422\u044b\u0432\u0430 \u0434\u044b\u043b",
897 - "udm" : "\u0423\u0434\u043c\u0443\u0440\u0442",
898 - "ug" : "Uyghurche\u200e \/ \u0626\u06c7\u064a\u063a\u06c7\u0631\u0686\u06d5",
899 - "ug-arab" : "\u0626\u06c7\u064a\u063a\u06c7\u0631\u0686\u06d5",
900 - "ug-latn" : "Uyghurche\u200e",
901 - "uk" : "\u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430",
902 - "ur" : "\u0627\u0631\u062f\u0648",
903 - "uz" : "O'zbek",
904 - "ve" : "Tshivenda",
905 - "vec" : "V\u00e8neto",
906 - "vep" : "Vepsan kel'",
907 - "vi" : "Ti\u1ebfng Vi\u1ec7t",
908 - "vls" : "West-Vlams",
909 - "vo" : "Volap\u00fck",
910 - "vro" : "V\u00f5ro",
911 - "wa" : "Walon",
912 - "war" : "Winaray",
913 - "wo" : "Wolof",
914 - "wuu" : "\u5434\u8bed",
915 - "xal" : "\u0425\u0430\u043b\u044c\u043c\u0433",
916 - "xh" : "isiXhosa",
917 - "xmf" : "\u10db\u10d0\u10e0\u10d2\u10d0\u10da\u10e3\u10e0\u10d8",
918 - "yi" : "\u05d9\u05d9\u05b4\u05d3\u05d9\u05e9",
919 - "yo" : "Yor\u00f9b\u00e1",
920 - "yue" : "\u7cb5\u8a9e",
921 - "za" : "Vahcuengh",
922 - "zea" : "Ze\u00eauws",
923 - "zh" : "\u4e2d\u6587",
924 - "zh-classical" : "\u6587\u8a00",
925 - "zh-cn" : "\u202a\u4e2d\u6587(\u4e2d\u56fd\u5927\u9646)\u202c",
926 - "zh-hans" : "\u202a\u4e2d\u6587(\u7b80\u4f53)\u202c",
927 - "zh-hant" : "\u202a\u4e2d\u6587(\u7e41\u9ad4)\u202c",
928 - "zh-hk" : "\u202a\u4e2d\u6587(\u9999\u6e2f)\u202c",
929 - "zh-min-nan" : "B\u00e2n-l\u00e2m-g\u00fa",
930 - "zh-mo" : "\u202a\u4e2d\u6587(\u6fb3\u9580)\u202c",
931 - "zh-my" : "\u202a\u4e2d\u6587(\u9a6c\u6765\u897f\u4e9a)\u202c",
932 - "zh-sg" : "\u202a\u4e2d\u6587(\u65b0\u52a0\u5761)\u202c",
933 - "zh-tw" : "\u202a\u4e2d\u6587(\u53f0\u7063)\u202c",
934 - "zh-yue" : "\u7cb5\u8a9e",
935 - "zu" : "isiZulu"
936 - };
937 -
938 - // Language classes ( has a file in /languages/classes/Language{code}.js )
939 - // ( for languages that override default transforms )
940 - mw.Language.transformClass = ['am', 'ar', 'bat_smg', 'be_tarak', 'be', 'bh',
941 - 'bs', 'cs', 'cu', 'cy', 'dsb', 'fr', 'ga', 'gd', 'gv', 'he', 'hi',
942 - 'hr', 'hsb', 'hy', 'ksh', 'ln', 'lt', 'lv', 'mg', 'mk', 'mo', 'mt',
943 - 'nso', 'pl', 'pt_br', 'ro', 'ru', 'se', 'sh', 'sk', 'sl', 'sma',
944 - 'sr_ec', 'sr_el', 'sr', 'ti', 'tl', 'uk', 'wa'
945 - ];
946 -
947 - // Language fallbacks listed from language -> fallback language
948 - mw.Language.fallbackTransformMap = {
949 - 'mwl' : 'pt',
950 - 'ace' : 'id',
951 - 'hsb' : 'de',
952 - 'frr' : 'de',
953 - 'pms' : 'it',
954 - 'dsb' : 'de',
955 - 'gan' : 'gan-hant',
956 - 'lzz' : 'tr',
957 - 'ksh' : 'de',
958 - 'kl' : 'da',
959 - 'fur' : 'it',
960 - 'zh-hk' : 'zh-hant',
961 - 'kk' : 'kk-cyrl',
962 - 'zh-my' : 'zh-sg',
963 - 'nah' : 'es',
964 - 'sr' : 'sr-ec',
965 - 'ckb-latn' : 'ckb-arab',
966 - 'mo' : 'ro',
967 - 'ay' : 'es',
968 - 'gl' : 'pt',
969 - 'gag' : 'tr',
970 - 'mzn' : 'fa',
971 - 'ruq-cyrl' : 'mk',
972 - 'kk-arab' : 'kk-cyrl',
973 - 'pfl' : 'de',
974 - 'zh-yue' : 'yue',
975 - 'ug' : 'ug-latn',
976 - 'ltg' : 'lv',
977 - 'nds' : 'de',
978 - 'sli' : 'de',
979 - 'mhr' : 'ru',
980 - 'sah' : 'ru',
981 - 'ff' : 'fr',
982 - 'ab' : 'ru',
983 - 'ko-kp' : 'ko',
984 - 'sg' : 'fr',
985 - 'zh-tw' : 'zh-hant',
986 - 'map-bms' : 'jv',
987 - 'av' : 'ru',
988 - 'nds-nl' : 'nl',
989 - 'pt-br' : 'pt',
990 - 'ce' : 'ru',
991 - 'vep' : 'et',
992 - 'wuu' : 'zh-hans',
993 - 'pdt' : 'de',
994 - 'krc' : 'ru',
995 - 'gan-hant' : 'zh-hant',
996 - 'bqi' : 'fa',
997 - 'as' : 'bn',
998 - 'bm' : 'fr',
999 - 'gn' : 'es',
1000 - 'tt' : 'ru',
1001 - 'zh-hant' : 'zh-hans',
1002 - 'hif' : 'hif-latn',
1003 - 'zh' : 'zh-hans',
1004 - 'kaa' : 'kk-latn',
1005 - 'lij' : 'it',
1006 - 'vot' : 'fi',
1007 - 'ii' : 'zh-cn',
1008 - 'ku-arab' : 'ckb-arab',
1009 - 'xmf' : 'ka',
1010 - 'vmf' : 'de',
1011 - 'zh-min-nan' : 'nan',
1012 - 'bcc' : 'fa',
1013 - 'an' : 'es',
1014 - 'rgn' : 'it',
1015 - 'qu' : 'es',
1016 - 'nb' : 'no',
1017 - 'bar' : 'de',
1018 - 'lbe' : 'ru',
1019 - 'su' : 'id',
1020 - 'pcd' : 'fr',
1021 - 'glk' : 'fa',
1022 - 'lb' : 'de',
1023 - 'kk-kz' : 'kk-cyrl',
1024 - 'kk-tr' : 'kk-latn',
1025 - 'inh' : 'ru',
1026 - 'mai' : 'hi',
1027 - 'tp' : 'tokipona',
1028 - 'kk-latn' : 'kk-cyrl',
1029 - 'ba' : 'ru',
1030 - 'nap' : 'it',
1031 - 'ruq' : 'ruq-latn',
1032 - 'tt-cyrl' : 'ru',
1033 - 'lad' : 'es',
1034 - 'dk' : 'da',
1035 - 'de-ch' : 'de',
1036 - 'be-x-old' : 'be-tarask',
1037 - 'za' : 'zh-hans',
1038 - 'kk-cn' : 'kk-arab',
1039 - 'shi' : 'ar',
1040 - 'crh' : 'crh-latn',
1041 - 'yi' : 'he',
1042 - 'pdc' : 'de',
1043 - 'eml' : 'it',
1044 - 'uk' : 'ru',
1045 - 'kv' : 'ru',
1046 - 'koi' : 'ru',
1047 - 'cv' : 'ru',
1048 - 'zh-cn' : 'zh-hans',
1049 - 'de-at' : 'de',
1050 - 'jut' : 'da',
1051 - 'vec' : 'it',
1052 - 'zh-mo' : 'zh-hk',
1053 - 'fiu-vro' : 'vro',
1054 - 'frp' : 'fr',
1055 - 'mg' : 'fr',
1056 - 'ruq-latn' : 'ro',
1057 - 'sa' : 'hi',
1058 - 'lmo' : 'it',
1059 - 'kiu' : 'tr',
1060 - 'tcy' : 'kn',
1061 - 'srn' : 'nl',
1062 - 'jv' : 'id',
1063 - 'vls' : 'nl',
1064 - 'zea' : 'nl',
1065 - 'ty' : 'fr',
1066 - 'szl' : 'pl',
1067 - 'rmy' : 'ro',
1068 - 'wo' : 'fr',
1069 - 'vro' : 'et',
1070 - 'udm' : 'ru',
1071 - 'bpy' : 'bn',
1072 - 'mrj' : 'ru',
1073 - 'ckb' : 'ckb-arab',
1074 - 'xal' : 'ru',
1075 - 'de-formal' : 'de',
1076 - 'myv' : 'ru',
1077 - 'ku' : 'ku-latn',
1078 - 'crh-cyrl' : 'ru',
1079 - 'gsw' : 'de',
1080 - 'rue' : 'uk',
1081 - 'iu' : 'ike-cans',
1082 - 'stq' : 'de',
1083 - 'gan-hans' : 'zh-hans',
1084 - 'scn' : 'it',
1085 - 'arn' : 'es',
1086 - 'ht' : 'fr',
1087 - 'zh-sg' : 'zh-hans',
1088 - 'bat-smg' : 'lt',
1089 - 'aln' : 'sq',
1090 - 'tg' : 'tg-cyrl',
1091 - 'li' : 'nl',
1092 - 'simple' : 'en',
1093 - 'os' : 'ru',
1094 - 'ln' : 'fr',
1095 - 'als' : 'gsw',
1096 - 'zh-classical' : 'lzh',
1097 - 'arz' : 'ar',
1098 - 'wa' : 'fr'
1099 - };
1100 -
1101 -
1102 -}) ( window.mw );
1103 -
1104 -
1105 -// Load in js2 stopgap global msgs into proper location:
1106 -if ( typeof gMsg != 'undefined' ) {
1107 - mw.addMessages( gMsg )
1108 -}
1109 -
1110 -// Set global gM shortcut:
1111 -window[ 'gM' ] = mw.getMsg;
1112 -
1113 -
1114 -/**
1115 -* Add the core mvEmbed Messages ( will be localized by script server )
1116 -*/
1117 -mw.addMessages( {
1118 - "mwe-loading_txt" : "Loading ...",
1119 - "mwe-size-gigabytes" : "$1 GB",
1120 - "mwe-size-megabytes" : "$1 MB",
1121 - "mwe-size-kilobytes" : "$1 K",
1122 - "mwe-size-bytes" : "$1 B",
1123 - "mwe-error_load_lib" : "Error: JavaScript $1 was not retrievable or does not define $2",
1124 - "mwe-apiproxy-setup" : "Setting up API proxy",
1125 - "mwe-load-drag-item" : "Loading dragged item",
1126 - "mwe-ok" : "OK",
1127 - "mwe-cancel" : "Cancel",
1128 - "mwe-enable-gadget" : "Enable multimedia beta ( mwEmbed ) for all pages",
1129 - "mwe-enable-gadget-done" : "multimedia beta gadget has been enabled",
1130 - "mwe-must-login-gadget" : "To enable gadget you must <a target=\"_new\" href=\"$1\">login</a>",
1131 - "mwe-test-plural" : "I ran {{PLURAL:$1|$1 test|$1 tests}}"
1132 -} );
\ No newline at end of file
Index: trunk/extensions/MwEmbed/MwEmbed/components/mw.jQueryUtil.js
@@ -0,0 +1,158 @@
 2+/**
 3+ * mwEmbed jQuery utility function
 4+ */
 5+
 6+( function( $ ) {
 7+
 8+ /**
 9+ * Set a given selector html to the loading spinner:
 10+ */
 11+ $.fn.loadingSpinner = function( ) {
 12+ if ( this ) {
 13+ $j( this ).html(
 14+ $j( '<div />' )
 15+ .addClass( "loadingSpinner" )
 16+ );
 17+ }
 18+ return this;
 19+ };
 20+ /**
 21+ * Add an absolute overlay spinner useful for cases where the
 22+ * element does not display child elements, ( images, video )
 23+ */
 24+ $.fn.getAbsoluteOverlaySpinner = function(){
 25+ var pos = $j( this ).offset();
 26+ var posLeft = ( $j( this ).width() ) ?
 27+ parseInt( pos.left + ( .5 * $j( this ).width() ) -16 ) :
 28+ pos.left + 30;
 29+
 30+ var posTop = ( $j( this ).height() ) ?
 31+ parseInt( pos.top + ( .5 * $j( this ).height() ) -16 ) :
 32+ pos.top + 30;
 33+
 34+ var $spinner = $j('<div />')
 35+ .loadingSpinner()
 36+ .css({
 37+ 'width' : 32,
 38+ 'height' : 32,
 39+ 'position': 'absolute',
 40+ 'top' : posTop + 'px',
 41+ 'left' : posLeft + 'px'
 42+ });
 43+ $j('body').append( $spinner );
 44+ return $spinner;
 45+ };
 46+
 47+ /**
 48+ * dragDrop file loader
 49+ */
 50+ $.fn.dragFileUpload = function ( conf ) {
 51+ if ( this.selector ) {
 52+ var _this = this;
 53+ // load the dragger and "setup"
 54+ mw.load( ['$j.fn.dragDropFile'], function() {
 55+ $j( _this.selector ).dragDropFile();
 56+ } );
 57+ }
 58+ };
 59+
 60+ /**
 61+ * Shortcut to a themed button Should be depreciated for $.button
 62+ * bellow
 63+ */
 64+ $.btnHtml = function( msg, styleClass, iconId, opt ) {
 65+ if ( !opt )
 66+ opt = { };
 67+ var href = ( opt.href ) ? opt.href : '#';
 68+ var target_attr = ( opt.target ) ? ' target="' + opt.target + '" ' : '';
 69+ var style_attr = ( opt.style ) ? ' style="' + opt.style + '" ' : '';
 70+ return '<a href="' + href + '" ' + target_attr + style_attr +
 71+ ' class="ui-state-default ui-corner-all ui-icon_link ' +
 72+ styleClass + '"><span class="ui-icon ui-icon-' + iconId + '" ></span>' +
 73+ '<span class="btnText">' + msg + '</span></a>';
 74+ };
 75+
 76+ // Shortcut to jQuery button ( should replace all btnHtml with
 77+ // button )
 78+ var mw_default_button_options = {
 79+ // The class name for the button link
 80+ 'class' : '',
 81+
 82+ // The style properties for the button link
 83+ 'style' : { },
 84+
 85+ // The text of the button link
 86+ 'text' : '',
 87+
 88+ // The icon id that precedes the button link:
 89+ 'icon' : 'carat-1-n'
 90+ };
 91+
 92+ $.button = function( options ) {
 93+ var options = $j.extend( {}, mw_default_button_options, options);
 94+
 95+ // Button:
 96+ var $button = $j('<a />')
 97+ .attr('href', '#')
 98+ .addClass( 'ui-state-default ui-corner-all ui-icon_link' );
 99+ // Add css if set:
 100+ if( options.css ) {
 101+ $button.css( options.css );
 102+ }
 103+
 104+ if( options['class'] ) {
 105+ $button.addClass( options['class'] );
 106+ }
 107+
 108+
 109+ // return the button:
 110+ $button.append(
 111+ $j('<span />').addClass( 'ui-icon ui-icon-' + options.icon ),
 112+ $j('<span />').addClass( 'btnText' )
 113+ .text( options.text )
 114+ )
 115+ .buttonHover(); // add buttonHover binding;
 116+ if( !options.text ){
 117+ $button.css('padding', '1em');
 118+ }
 119+ return $button;
 120+ };
 121+
 122+ // Shortcut to bind hover state
 123+ $.fn.buttonHover = function() {
 124+ $j( this ).hover(
 125+ function() {
 126+ $j( this ).addClass( 'ui-state-hover' );
 127+ },
 128+ function() {
 129+ $j( this ).removeClass( 'ui-state-hover' );
 130+ }
 131+ );
 132+ return this;
 133+ };
 134+
 135+ /**
 136+ * Resize a dialog to fit the window
 137+ *
 138+ * @param {Object}
 139+ * options horizontal and vertical space ( default 50 )
 140+ */
 141+ $.fn.dialogFitWindow = function( options ) {
 142+ var opt_default = { 'hspace':50, 'vspace':50 };
 143+ if ( !options )
 144+ var options = { };
 145+ options = $j.extend( opt_default, options );
 146+ $j( this.selector ).dialog( 'option', 'width', $j( window ).width() - options.hspace );
 147+ $j( this.selector ).dialog( 'option', 'height', $j( window ).height() - options.vspace );
 148+ $j( this.selector ).dialog( 'option', 'position', 'center' );
 149+ // update the child position: (some of this should be pushed
 150+ // up-stream via dialog config options
 151+ $j( this.selector + '~ .ui-dialog-buttonpane' ).css( {
 152+ 'position':'absolute',
 153+ 'left':'0px',
 154+ 'right':'0px',
 155+ 'bottom':'0px'
 156+ } );
 157+ };
 158+
 159+} )( jQuery );
\ No newline at end of file
Property changes on: trunk/extensions/MwEmbed/MwEmbed/components/mw.jQueryUtil.js
___________________________________________________________________
Added: svn:mime-type
1160 + text/plain
Index: trunk/extensions/MwEmbed/MwEmbed/modules/ApiEmbed/mw.ApiProxy.js
@@ -0,0 +1,1024 @@
 2+/**
 3+*
 4+* Api proxy system
 5+*
 6+* Supports cross domain uploading, and api actions for a approved set of domains.
 7+*
 8+* All cross domain communication is done with iframe children ( Avoids polling
 9+* which is resource intensive and can lose messages )
 10+*
 11+* The framework ~will eventually~ support a request approval system for per-user domain approval
 12+* and a central blacklisting of domains controlled by the site
 13+*
 14+* NOTE: If the browser supports it we should pass msgs with postMessage API
 15+* http://ejohn.org/blog/cross-window-messaging/ ( rather than using these iframes )
 16+*
 17+* NOTE: refactor efforts will include separating out "core" proxy functions and
 18+* having a separate class for "server" and "client" api usage
 19+*
 20+*/
 21+
 22+mw.includeAllModuleMessages();
 23+
 24+/**
 25+ * apiProxy jQuery binding
 26+ *
 27+ * Note: probably should split up "server" and "client" binding
 28+ *
 29+ * @param {String} mode Mode is either 'server' or 'client'
 30+ * @param {Object} proxyConfig Proxy configuration
 31+ * @param {Function} callback The function called once proxy request is done
 32+ */
 33+
 34+ /**
 35+ * Set the base API Proxy object
 36+ *
 37+ */
 38+mw.ApiProxy = { };
 39+
 40+// ApiProxy scoped functions:
 41+( function( $ ) {
 42+
 43+ // Proxy Context stores an array of proxy context requests
 44+ // this enables multiple simultaneous requests to be processed.
 45+ var proxyContext = [];
 46+
 47+ /**
 48+ * Takes a requestQuery, executes the query and then calls the callback
 49+ * sets the local callback to be called once requestQuery completes
 50+ *
 51+ * @param {String} apiUrl Url to the api we want to do the request on.
 52+ * @param {Object} requestQuery Api request object
 53+ * @param {Function} callback Function called once the request is complete
 54+ * @param {Function} [callbackTimeout] Optional Function called on api timeout
 55+ */
 56+ $.doRequest = function( apiUrl, requestQuery, callback , callbackTimeout ) {
 57+ // Sanity check:
 58+ if ( mw.isLocalDomain( apiUrl ) ) {
 59+ mw.log( "Error: trying to proxy local domain? " );
 60+ return false;
 61+ }
 62+
 63+ // Generate a new context object: (its oky that optional arguments are null )
 64+ var context = createContext({
 65+ 'apiUrl' : apiUrl, // currentServerApiUrl
 66+ 'apiReq' : requestQuery,
 67+ 'callback' : callback,
 68+ 'timeoutCb' : callbackTimeout
 69+ } );
 70+
 71+ mw.log( "doRequest:: " + JSON.stringify( requestQuery ) );
 72+
 73+ // Do the proxy req:
 74+ doFrameProxy( context );
 75+ };
 76+
 77+ /**
 78+ * Generates a remote browse file iframe window
 79+ * usefull for "uploading" cross domain
 80+ *
 81+ * @param {Function} callback Function to host the
 82+ */
 83+ $.browseFile = function( options ) {
 84+ if( ! options ) {
 85+ options = {};
 86+ }
 87+
 88+ if( ! options.target ) {
 89+ mw.log( "Error: no target for file browse iframe" ) ;
 90+ return false;
 91+ }
 92+
 93+ if( !options.token ){
 94+ mw.log( "Error: no token for file browse ");
 95+ return false;
 96+ }
 97+
 98+ if( ! options.apiUrl ) {
 99+ mw.log( "Error: no api url to target" );
 100+ return false;
 101+ }
 102+ mw.log( 'Setup uploadDialogInterface' );
 103+
 104+ // Make sure we have the dialog interface:
 105+ var uploadDialogInterface = new mw.UploadDialogInterface( {
 106+ 'uploadHandlerAction' : function( action ){
 107+ mw.log( 'apiProxy uploadActionHandler:: ' + action );
 108+
 109+ // Handle actions that don't need to go to the iframe:
 110+ switch ( action ){
 111+ case 'returnToFormCb':
 112+ if( options.returnToFormCb ){
 113+ options.returnToFormCb();
 114+ }
 115+ return ;
 116+ break;
 117+ }
 118+
 119+ // Handle actions that get sent to the remote frame
 120+ mw.ApiProxy.sendServerMsg( {
 121+ 'apiUrl' : options.apiUrl,
 122+ 'frameName' : iFrameName,
 123+ 'frameMsg' : {
 124+ 'action' : 'uploadHandlerAction',
 125+ 'uiAction' : action
 126+ }
 127+ } );
 128+ }
 129+ } );
 130+
 131+ // Setup the context with the callback in the current closure
 132+ var context = createContext( {
 133+ 'apiUrl' : options.apiUrl,
 134+ // Setup the callback to process iframeData
 135+ 'callback' : function( iframeData ) {
 136+ // Process fileBrowse callbacks ::
 137+
 138+ // check for basic status "ok"
 139+ if( iframeData['status'] == 'ok' ) {
 140+ // Hide the loading spinner
 141+ $j( options.target ).find('.loadingSpinner').fadeOut('fast');
 142+ mw.log("iframe ready callback");
 143+ $j( '#' + iFrameName ).fadeIn( 'fast' );
 144+ return ;
 145+ }
 146+ mw.log( '~browseFile Callback~ event type: ' + iframeData['event'] );
 147+
 148+ // Handle events:
 149+ if( iframeData['event'] ) {
 150+ switch( iframeData['event'] ) {
 151+ case 'selectFileCb':
 152+ if( options.selectFileCb ) {
 153+ options.selectFileCb( iframeData[ 'fileName' ] );
 154+ }
 155+ break;
 156+ // Set the doneUploadCb if set in the browseFile options
 157+ case 'doneUploadCb':
 158+ mw.log( "should call cb: " + options.doneUploadCb );
 159+ if( options.doneUploadCb ) {
 160+ options.doneUploadCb( iframeData[ 'apiResult' ] );
 161+ return true;
 162+ }else{
 163+ return false;
 164+ }
 165+ break;
 166+ case 'uploadUI':
 167+ if( uploadDialogInterface[ iframeData[ 'method' ] ] ){
 168+ var args = iframeData['arguments'];
 169+ mw.log( "Do dialog interface: " + iframeData['method'] + ' args: ' + args[0] + ', ' + args[1] + ', ' + args[2] );
 170+ uploadDialogInterface[ iframeData['method'] ](
 171+ args[0], args[1], args[2]
 172+ );
 173+ }
 174+ break;
 175+ default:
 176+ mw.log(" Error unreconginzed event " + iframeData['event'] );
 177+ }
 178+ }
 179+ }
 180+ });
 181+
 182+ // Setup the default width and height:
 183+ if( ! options.width ) {
 184+ options.width = 270;
 185+ }
 186+ if( ! options.height ) {
 187+ options.height = 27;
 188+ }
 189+
 190+ var iFrameName = ( options.iframeName ) ? options.iframeName : 'fileBrowse_' + $j('iframe').length;
 191+ // Setup an object to be packaged into the frame
 192+ var iFrameRequest = {
 193+ 'clientFrame' : getClientFrame( context ),
 194+ 'action' : 'browseFile',
 195+ 'token' : options.token
 196+ };
 197+
 198+ var frameStyle = 'display:none;border:none;overflow:hidden;'
 199+ + 'width:'+ parseInt( options.width ) + 'px;'
 200+ + 'height:' + parseInt( options.height ) +'px';
 201+
 202+ // Empty the target ( so that the iframe can be put there )
 203+ $j( options.target ).empty();
 204+
 205+ mw.log( 'append spinner');
 206+ // Add a loading spinner to the target
 207+ $j( options.target ).append(
 208+ $j( '<div />' ).loadingSpinner()
 209+ );
 210+
 211+ // Append the browseFile iframe to the target:
 212+ appendIframe( {
 213+ 'context' : context,
 214+ 'persist' : true,
 215+ 'style' : frameStyle,
 216+ 'name' : iFrameName,
 217+ 'request' : iFrameRequest,
 218+ 'target' : options.target
 219+ } );
 220+
 221+ // Return the name of the browseFile frame
 222+ return iFrameName;
 223+ };
 224+
 225+ /**
 226+ * Output a server msg to a server iFrame
 227+ * ( such as a hosted browse file or dialog prompt )
 228+ *
 229+ * @param {Object} options Arguments to setup send server msg
 230+ * apiUrl The api url of the server to send the frame msg to
 231+ * frameName The frame name to send the msg to
 232+ * frameMsg The msg object to send to frame
 233+ */
 234+ $.sendServerMsg = function( options ){
 235+ if( !options.apiUrl || ! options.frameMsg || !options.frameName ){
 236+ mw.log( "Error missing required option");
 237+ return false;
 238+ }
 239+
 240+ //Setup a new context
 241+ var context = createContext( {
 242+ 'apiUrl' : options.apiUrl
 243+ } );
 244+
 245+ // Send a msg to the server frameName from the server domain
 246+ // Setup an object to be packaged into the frame
 247+ var iFrameRequest = {
 248+ 'clientFrame' : getClientFrame( context ),
 249+ 'action' : 'sendFrameMsg',
 250+ 'frameName' : options.frameName,
 251+ 'frameMsg' : options.frameMsg
 252+ };
 253+
 254+ // Send the iframe request:
 255+ appendIframe( {
 256+ 'persist' : true,
 257+ 'context' : context,
 258+ 'request' : iFrameRequest,
 259+ 'target' : options.target
 260+ }, function( ) {
 261+ mw.log( "sendServerMsg iframe done loading" );
 262+ } );
 263+ };
 264+
 265+ /**
 266+ * The nested iframe action that passes its result back up to the top frame instance
 267+ *
 268+ * Entry point for hashResult from nested iframe
 269+ *
 270+ * @param {Object} hashResult Value to be sent to parent frame
 271+ */
 272+ $.nested = function( hashResult ) {
 273+ // Close the loader if present:
 274+ //mw.closeLoaderDialog();
 275+
 276+ mw.log( '$.proxy.nested callback :: ' + decodeURIComponent( hashResult ) );
 277+
 278+ // Try to parse the hash result
 279+ try {
 280+ var resultObject = JSON.parse( decodeURIComponent( hashResult ) );
 281+ } catch ( e ) {
 282+ mw.log( "Error could not parse hashResult" );
 283+ }
 284+
 285+ // Check for the contextKey
 286+ if ( ! resultObject.contextKey ) {
 287+ mw.log( "Error missing context key in nested callback" );
 288+ return false;
 289+ }
 290+
 291+ // Get the context via contextKey
 292+ var context = getContext( resultObject.contextKey );
 293+
 294+ // Set the loaded flag to true. ( avoids timeout calls )
 295+ context[ 'proxyLoaded' ] = true;
 296+
 297+ // Special callback to quickly establish a valid proxy connection.
 298+ // If the proxyed "request" takes more time it does not
 299+ // count against the proxy connection being established.
 300+ if ( resultObject.state == 'ok' ) {
 301+ return ;
 302+ }
 303+
 304+ // Check for the context callback:
 305+ if( context.callback ){
 306+ context.callback( resultObject );
 307+ }
 308+ };
 309+
 310+
 311+ /**
 312+ * Handle a server msg
 313+ *
 314+ * @param {Object} frameMsg
 315+ */
 316+ $.handleServerMsg = function( frameMsg ){
 317+ mw.log( "handleServerMsg:: " + JSON.stringify( frameMsg ) );
 318+ if( ! frameMsg.action ) {
 319+ mw.log(" missing frameMsg action " );
 320+ return false;
 321+ }
 322+ switch( frameMsg.action ) {
 323+ case 'fileSubmit':
 324+ serverSubmitFile( frameMsg.formData );
 325+ break;
 326+ case 'uploadHandlerAction':
 327+ serverSendUploadHandlerAction( frameMsg.uiAction );
 328+ break;
 329+ }
 330+ };
 331+
 332+ /**
 333+ * Api server proxy entry point:
 334+ * validates the server frame request
 335+ * and process the request type
 336+ */
 337+ $.server = function() {
 338+ // Validate the server request:
 339+ if( ! validateIframeRequest() ) {
 340+ mw.log( "Not a valid iframe request");
 341+ return false;
 342+ }
 343+ // Inform the client frame that we passed validation
 344+ sendClientMsg( { 'state':'ok' } );
 345+
 346+ return serverHandleRequest();
 347+ }
 348+
 349+ /**
 350+ * Local scoped helper functions:
 351+ */
 352+
 353+ /**
 354+ * Creates a new context stored in the proxyContext local global
 355+ * @param {Object} contextVars Initial contextVars
 356+ */
 357+ function createContext ( contextVars ) {
 358+ // Create a ~ sufficiently ~ unique context key
 359+ var contextKey = new Date().getTime() * Math.random();
 360+ proxyContext [ contextKey ] = contextVars;
 361+
 362+ // Setup the proxy loaded flag for this context:
 363+ proxyContext[ contextKey ][ 'proxyLoaded' ] = false;
 364+
 365+ // Set a local pointer to the contextKey
 366+ proxyContext[ contextKey ]['contextKey' ] = contextKey;
 367+
 368+ mw.log( "created context with key:" + contextKey );
 369+
 370+ // Return the proxy context
 371+ return proxyContext [ contextKey ];
 372+ };
 373+
 374+ /**
 375+ * Get a context from a contextKey
 376+ * @param {String} [optional] contextKey Key of the context object to be returned
 377+ * @return context object
 378+ * false if context object can not be found
 379+ */
 380+ function getContext ( contextKey ) {
 381+ if( ! proxyContext [ contextKey ] ){
 382+ mw.log( "Error: contextKey not found:: " + contextKey );
 383+ return false;
 384+ }
 385+ return proxyContext [ contextKey ];;
 386+ };
 387+
 388+ /**
 389+ * Get the client frame path
 390+ */
 391+ function getClientFrame( context ) {
 392+ // Check if the mwEmbed is on the same server as we are
 393+ if( mw.isLocalDomain( mw.getMwEmbedPath() ) ){
 394+ return mw.getMwEmbedPath() + 'modules/ApiProxy/NestedCallbackIframe.html';
 395+ } else {
 396+ // Use the nested callback function ( server frame point back )
 397+ nestedServerFrame = getServerFrame( {
 398+ 'apiUrl' : mw.getLocalApiUrl(),
 399+ 'pageName' : 'ApiProxyNestedCb'
 400+ } );
 401+ // Update the context to include the nestedCallbackFlag flag in the request
 402+ return nestedServerFrame;
 403+ }
 404+ };
 405+
 406+ /**
 407+ * Get the server Frame path per requested Api url
 408+ * (presently hard coded to MediaWiki:ApiProxy per /remotes/medaiWiki.js )
 409+ *
 410+ * NOTE: we should have a Hosted page once we deploy mwEmbed on the servers.
 411+ * A hosted page would be much faster since it would not have to load all the
 412+ * normal page view assets prior to being rewrite for api proxy usage.
 413+ *
 414+ * NOTE: We add the gadget incase the user has not enabled the gadget on the
 415+ * domain they want to iframe to. There is no cost if they already have the
 416+ * gadget on. This can be removed once deployed as well.
 417+ *
 418+ * @param {URL} apiUrl The url of the api server
 419+ */
 420+ // Include gadget js ( in case the user has not enabled the gadget on that domain )
 421+
 422+ //var gadgetWithJS = '';
 423+
 424+ function getServerFrame( context ) {
 425+ if( ! context || ! context.apiUrl ){
 426+ mw.log( "Error no context api url " );
 427+ return false;
 428+ }
 429+ var parsedUrl = mw.parseUri( context.apiUrl );
 430+
 431+ var pageName = ( context.pageName ) ? context.pageName : 'ApiProxy';
 432+
 433+ var pageUrl = parsedUrl.protocol + '://' + parsedUrl.authority
 434+ + '/w/index.php/MediaWiki:' + pageName;
 435+
 436+ if( mw.getConfig( 'Mw.AppendWithJS' ) ){
 437+ pageUrl+= '?' + mw.getConfig( 'Mw.AppendWithJS' );
 438+ }
 439+ return pageUrl;
 440+ }
 441+
 442+ /**
 443+ * Do the frame proxy
 444+ * Sets up a frame proxy request
 445+ *
 446+ * @param {Object} context ( the context of the current doFrameProxy call )
 447+ * @param {Object} requestQuery The api request object
 448+ */
 449+ function doFrameProxy ( context ) {
 450+
 451+ var iframeRequest = {
 452+ // Client domain frame ( will be approved by the server before sending and receiving msgs )
 453+ 'clientFrame' : getClientFrame( context ),
 454+ 'action' : 'apiRequest',
 455+ 'request' : context[ 'apiReq' ]
 456+ }
 457+
 458+ mw.log( "Do frame proxy request on src: \n" + getServerFrame( context ) + "\n" + JSON.stringify( context[ 'apiReq' ] ) );
 459+ appendIframe( {
 460+ 'persist' : true,
 461+ 'request' : iframeRequest,
 462+ 'context' : context
 463+ } )
 464+ }
 465+
 466+ /**
 467+ * Validate an iframe request
 468+ * checks the url hash for required parameters
 469+ * checks master_blacklist
 470+ * checks master_whitelist
 471+ */
 472+ function validateIframeRequest() {
 473+ var clientRequest = getClientRequest();
 474+
 475+ if ( !clientRequest || !clientRequest.clientFrame ) {
 476+ mw.log( "Error: no client domain provided " );
 477+ $j( 'body' ).append( "no client frame provided" );
 478+ return false;
 479+ }
 480+
 481+ // Make sure we are logged in
 482+ // (its a normal mediaWiki page so all site vars should be defined)
 483+ if ( typeof wgUserName != 'undefined' && !wgUserName ) {
 484+ mw.log( 'Error Not logged in' );
 485+ return false;
 486+ }
 487+
 488+ mw.log( "Setup server on: " + mw.parseUri( document.URL ).host );
 489+ mw.log('Client frame: ' + clientRequest.clientFrame );
 490+
 491+ /**
 492+ * CHECK IF THE DOMAIN IS ALLOWED per the ApiProxy config:
 493+ */
 494+ return isAllowedClientFrame( clientRequest.clientFrame );;
 495+ }
 496+
 497+ /**
 498+ * Check if a domain is allowed.
 499+ * @param {Object} clientFrame
 500+ */
 501+ function isAllowedClientFrame( clientFrame ) {
 502+ var clientDomain = mw.parseUri( clientFrame ).host ;
 503+ // Get the proxy config
 504+
 505+ // Check master blacklist
 506+ if( mw.getConfig('ApiProxy.DomainBlackList') && mw.getConfig('ApiProxy.DomainBlackList').length ){
 507+ var domainBlackList = mw.getConfig('ApiProxy.DomainBlackList');
 508+ for ( var i =0; i < domainBlackList.length; i++ ) {
 509+ var blackDomain = domainBlackList[i];
 510+ // Check if domain check is a RegEx:
 511+ if( typeof blackDomain == 'object' ){
 512+ if( clientDomain.match( blackDomain ) ){
 513+ return false;
 514+ }
 515+ } else {
 516+ // just do a direct domain check:
 517+ if( clientDomain == blackDomain ){
 518+ return false;
 519+ }
 520+ }
 521+ }
 522+ }
 523+
 524+ // Check the master whitelist:
 525+ if( mw.getConfig('ApiProxy.DomainWhiteList') && mw.getConfig('ApiProxy.DomainWhiteList').length ){
 526+ var domainWhiteList = mw.getConfig('ApiProxy.DomainWhiteList');
 527+ for ( var i =0; i < domainWhiteList.length; i++ ) {
 528+ whiteDomain = domainWhiteList[i];
 529+ // Check if domain check is a RegEx:
 530+ if( typeof whiteDomain == 'object' ){
 531+ if( clientDomain.match( whiteDomain ) ) {
 532+ return true;
 533+ }
 534+ } else {
 535+ if( clientDomain == whiteDomain ){
 536+ return true;
 537+ }
 538+ }
 539+ }
 540+ }
 541+
 542+ // FIXME Add in user based approval ::
 543+
 544+ // FIXME offer the user the ability to "approve" requested domain save to
 545+ // their user preference setup )
 546+
 547+ // FIXME grab and check domain against the users whitelist and permissions
 548+
 549+ // for now just return false if the domain is not in the approved list
 550+ return false;
 551+ };
 552+
 553+ /**
 554+ * Get the client request from the document hash
 555+ * @return {Object} the object result of parsing the document anchor msg
 556+ */
 557+ function getClientRequest() {
 558+ // Read the anchor data package from the requesting url
 559+ var hashMsg = unescape( mw.parseUri( document.URL ).anchor );
 560+ try {
 561+ return JSON.parse( hashMsg );
 562+ } catch ( e ) {
 563+ mw.log( "ProxyServer:: could not parse anchor" );
 564+ return false;
 565+ }
 566+ };
 567+
 568+ /**
 569+ * Dialog to send the user if a proxy to the remote server could not be created
 570+ * @param {Object} context
 571+ */
 572+ function proxyNotReadyTimeout( context ) {
 573+ mw.log( "Error:: api proxy timeout " + context.contextKey );
 574+
 575+ // See if we have a callback function to call ( do not display the dialog )
 576+ if( context[ 'timeoutCb' ] && typeof context[ 'timeoutCb' ] == 'function' ) {
 577+ context[ 'timeoutCb' ] ( );
 578+ return true;
 579+ }
 580+
 581+ var buttons = { };
 582+ buttons[ gM( 'mwe-re-try' ) ] = function() {
 583+ mw.addLoaderDialog( gM( 'mwe-re-trying' ) );
 584+ // Re try the same context request:
 585+ doFrameProxy( context );
 586+ };
 587+ buttons[ gM( 'mwe-cancel' ) ] = function() {
 588+ mw.closeLoaderDialog ( );
 589+ };
 590+
 591+ // Setup the login link:
 592+ var pUri = mw.parseUri( getServerFrame( context ) );
 593+ var login_url = pUri.protocol + '://' + pUri.host;
 594+ login_url += pUri.path.replace( 'MediaWiki:ApiProxy', 'Special:UserLogin' );
 595+
 596+ var $dialogMsg = $j('<p />');
 597+ $dialogMsg.append(
 598+ gM( 'mwe-please-login',
 599+ pUri.host,
 600+
 601+ // Add log-in link:
 602+ $j( '<a />')
 603+ .attr( {
 604+ 'href' : login_url,
 605+ 'target' : '_new'
 606+ } )
 607+ .text( gM('mwe-log-in-link') )
 608+ )
 609+ )
 610+ // Add the security note as well:
 611+ $dialogMsg.append(
 612+ $j('<br />'),
 613+ gM( 'mwe-remember-loging' )
 614+ )
 615+
 616+ mw.addDialog( {
 617+ 'title' : gM( 'mwe-proxy-not-ready' ),
 618+ 'content' : $dialogMsg,
 619+ 'buttons' : buttons
 620+ })
 621+ };
 622+
 623+ /**
 624+ * API iFrame Server::
 625+ *
 626+ * Handles the server side proxy of requests
 627+ * it adds child frames pointing to the parent "blank" frames
 628+ */
 629+
 630+ /**
 631+ * serverHandleRequest handle a given request from the client
 632+ * maps the request to serverBrowseFile or serverApiRequest
 633+ *
 634+ * NOTE: mw.ApiProxy.server entry point validates the request
 635+ */
 636+ function serverHandleRequest( ) {
 637+ var clientRequest = getClientRequest();
 638+ mw.log(" Handle client request :: " + JSON.stringify( clientRequest ) );
 639+ // Process request type:
 640+ switch( clientRequest[ 'action' ] ){
 641+ case 'browseFile':
 642+ return serverBrowseFile();
 643+ break;
 644+ case 'apiRequest':
 645+ return serverApiRequest();
 646+ break;
 647+ case 'sendFrameMsg':
 648+ return serverSendFrameMsg();
 649+ break;
 650+ }
 651+ mw.log( "Error could not handle client request" );
 652+ return false;
 653+ };
 654+
 655+ /**
 656+ * Api iFrame request:
 657+ */
 658+ function serverApiRequest( ) {
 659+ // Get the client request
 660+ var clientRequest = getClientRequest();
 661+
 662+ // Make sure its a json format
 663+ clientRequest.request[ 'format' ] = 'json';
 664+
 665+ mw.log(" do post request to: " + wgScriptPath + '/api' + wgScriptExtension );
 666+
 667+ // Process the API request. We don't use mw.getJSON since we need to "post"
 668+ $j.post( wgScriptPath + '/api' + wgScriptExtension,
 669+ clientRequest.request,
 670+ function( data ) {
 671+ // Make sure data is in JSON data format ( not a string )
 672+ if( typeof data != 'object' ){
 673+ data = JSON.parse( data );
 674+ }
 675+ mw.log(" server api request got data: " + JSON.stringify( data ) );
 676+ // Send the result data to the client
 677+ sendClientMsg( data );
 678+ }
 679+ );
 680+ }
 681+
 682+ /**
 683+ * Send a msg to a server frame
 684+ *
 685+ * Server frame instances that handle msgs
 686+ * should accept processMsg calls
 687+ */
 688+ function serverSendFrameMsg( ){
 689+ var clientRequest = getClientRequest();
 690+
 691+ // Make sure the requested frame exists:
 692+ if( ! clientRequest.frameMsg || ! clientRequest.frameName ) {
 693+ mw.log("Error serverSendFrameMsg without frame msg or frameName" );
 694+ return false;
 695+ }
 696+
 697+ // Send the message to the target frame
 698+ top[ clientRequest.frameName ].mw.ApiProxy.handleServerMsg( clientRequest.frameMsg );
 699+ }
 700+
 701+ /**
 702+ * Setup the browse file proxy on the "server"
 703+ *
 704+ * Sets the page content to browser file
 705+ */
 706+ function serverBrowseFile( ) {
 707+
 708+ // If wgEnableFirefogg is not boolean false, set to true
 709+ if ( typeof wgEnableFirefogg == 'undefined' ) {
 710+ wgEnableFirefogg = true;
 711+ }
 712+
 713+ // Setup the browse file html
 714+ serverBrowseFileSetup();
 715+
 716+ // Load the mw.upload library with iframe interface (similar to uploadPage.js)
 717+ // Check if firefogg is enabled:
 718+ // NOTE: the binding function should be made identical.
 719+ if( wgEnableFirefogg ) {
 720+ mw.load( 'AddMedia.firefogg', function() {
 721+ $j( '#wpUploadFile' ).firefogg( getUploadFileConfig() );
 722+
 723+ // Update status
 724+ sendClientMsg( {'status':'ok'} );
 725+ });
 726+ } else {
 727+ mw.load( 'AddMedia.UploadHandler', function() {
 728+ var uploadConfig = getUploadFileConfig();
 729+
 730+ $j( '#mw-upload-form' ).uploadHandler( getUploadFileConfig() );
 731+
 732+ // Update status
 733+ sendClientMsg( {'status':'ok'} );
 734+ });
 735+ }
 736+ };
 737+
 738+ /**
 739+ * Setup the browse file html
 740+ * @return browse file config
 741+ */
 742+ function serverBrowseFileSetup( ){
 743+ // Get the client request config
 744+ var clientRequest = getClientRequest();
 745+
 746+ // Check for fw ( file width )
 747+ if( ! clientRequest.fileWidth ) {
 748+ clientRequest.fileWidth = 130;
 749+ }
 750+ // Check for the token
 751+ if( ! clientRequest.token ){
 752+ mw.log("Error server browse file setup without token")
 753+ return false;
 754+ }
 755+
 756+ //Build a form with bindings similar to uploadPage.js ( but only the browse button )
 757+ $j('body').html(
 758+ $j('<form />')
 759+ .attr( {
 760+ 'name' : "mw-upload-form",
 761+ 'id' : "mw-upload-form",
 762+ 'enctype' : "multipart/form-data",
 763+ 'method' : "post",
 764+ // Submit to the local domain
 765+ 'action' : mw.getLocalApiUrl()
 766+ } )
 767+ .append(
 768+ //Add the "browse for file" button
 769+ $j('<input />')
 770+ .attr({
 771+ 'type' : "file",
 772+ 'name' : "wpUploadFile",
 773+ 'id' : "wpUploadFile"
 774+ })
 775+ .css({
 776+ 'width' : clientRequest.fileWidth
 777+ }),
 778+
 779+ // Append the token
 780+ $j('<input />')
 781+ .attr({
 782+ 'type' : 'hidden',
 783+ 'id' : "wpEditToken",
 784+ 'name' : 'token'
 785+ })
 786+ .val( clientRequest.token )
 787+ )
 788+ );
 789+ }
 790+
 791+ /**
 792+ * Browse file upload config generator
 793+ */
 794+ function getUploadFileConfig(){
 795+
 796+ // Setup the upload iframeUI
 797+ var uploadIframeUI = new mw.UploadIframeUI( function( method ){
 798+ // Get all the arguments after the "method"
 799+ var args = $j.makeArray( arguments ).splice( 1 );
 800+ // Send the client the msg:
 801+ sendClientMsg( {
 802+ 'event' : 'uploadUI',
 803+ 'method' : method,
 804+ // Get all the arguments after the "method"
 805+ 'arguments' : args
 806+ } );
 807+ } );
 808+
 809+ var uploadConfig = {
 810+ // Set the interface type
 811+ 'ui' : uploadIframeUI,
 812+
 813+ // Set the select file callback to update clientFrame
 814+ 'selectFileCb' : function( fileName ) {
 815+ sendClientMsg( {
 816+ 'event': 'selectFileCb',
 817+ 'fileName' : fileName
 818+ } );
 819+ },
 820+ // The return to form cb:
 821+ 'returnToFormCb' : function (){
 822+ sendClientMsg( {
 823+ 'event': 'returnToFormCb'
 824+ } );
 825+ },
 826+ // Api proxy does not handle descriptionText rewrite
 827+ 'rewriteDescriptionText' : false,
 828+
 829+ // Don't show firefogg upload warning
 830+ 'showFoggWarningFlag' : false,
 831+
 832+ // Set the doneUploadCb if set in the browseFile options
 833+ 'doneUploadCb' : function ( apiResult ){
 834+ sendClientMsg( {
 835+ 'event': 'doneUploadCb',
 836+ 'apiResult' : apiResult
 837+ } );
 838+ }
 839+ }
 840+
 841+ return uploadConfig;
 842+ }
 843+
 844+ /**
 845+ * Server send interface action
 846+ */
 847+ function serverSendUploadHandlerAction( action ) {
 848+ // Get a refrence to the uploadHandler:
 849+ // NOTE: both firefogg and upload form should save upload target in a similar way
 850+ var selector = ( wgEnableFirefogg ) ? '#wpUploadFile' : '#mw-upload-form';
 851+ var uploadHandler = $j( selector ).get(0).uploadHandler;
 852+ if( uploadHandler ){
 853+ uploadHandler.uploadHandlerAction( action );
 854+ } else {
 855+ mw.log( "Error: could not find upload handler" );
 856+ }
 857+ }
 858+
 859+ /**
 860+ * Server submit file
 861+ * @param {Object} options Options for submiting file
 862+ */
 863+ function serverSubmitFile( formData ){
 864+ mw.log("Submit form with fname:" + formData.filename + "\n :: " + formData.comment)
 865+ // Add the FileName and and the description to the form
 866+ var $form = $j('#mw-upload-form');
 867+ var formApiFields = [ 'filename', 'comment', 'watch', 'ignorewarnings', 'token' ];
 868+
 869+ for( var i=0; i < formApiFields.length ; i++ ){
 870+ var fieldName = formApiFields[ i ];
 871+ if( typeof formData[ fieldName ] == 'string' ) {
 872+ // Add the input field if not already there:
 873+ if( ! $form.find("[name='" + fieldName + "']" ).length ){
 874+ $form.append(
 875+ $j( '<input />' )
 876+ .attr( {
 877+ 'name' : fieldName,
 878+ 'type' : 'hidden'
 879+ } )
 880+ )
 881+ }
 882+ // Add the value if set:
 883+ $form.find("[name='" + fieldName + "']" ).val( formData[ fieldName ] );
 884+ }
 885+ }
 886+ // Do submit the form
 887+ $form.submit();
 888+ };
 889+
 890+ /**
 891+ * Outputs the result object to the client domain
 892+ *
 893+ * @param {msgObj} msgObj Msg to send to client domain
 894+ */
 895+ function sendClientMsg( msgObj ) {
 896+
 897+ // Get the client Request:
 898+ var clientRequest = getClientRequest();
 899+
 900+ // Get a local reference to the client request
 901+ var clientFrame = clientRequest[ 'clientFrame' ];
 902+
 903+ // Double check that the client is an approved domain before outputting the iframe
 904+ if( ! isAllowedClientFrame ( clientFrame ) ) {
 905+ mw.log( "Cant send msg to " + clientFrame );
 906+ return false;
 907+ }
 908+
 909+ // Double check we have a context key:
 910+ if( ! clientRequest.contextKey ) {
 911+ mw.log( "Error: missing context key " );
 912+ return false;
 913+ }
 914+
 915+ var nestName = 'NestedFrame_' + $j( 'iframe' ).length;
 916+
 917+ // Append the iframe to body
 918+ appendIframe( {
 919+ 'src' : clientFrame,
 920+ 'request' : msgObj,
 921+ // Client msgs just have the contextKey ( not the full context )
 922+ 'context' : {
 923+ 'contextKey' : clientRequest.contextKey
 924+ }
 925+ } );
 926+ };
 927+
 928+ /**
 929+ * Appends an iframe to the body from a given set of options
 930+ *
 931+ * NOTE: this uses string html building instead of jquery build-out
 932+ * because IE does not allow setting of iframe attributes
 933+ *
 934+ * @param {Object} options Iframe attribute options
 935+ * name - the name of the iframe
 936+ * src - the url for the iframe
 937+ * request - the request object to be packaged into the hash url
 938+ * persist - set to true if the iframe should not
 939+ * be removed from the dom after its done loading
 940+ */
 941+ function appendIframe( options ){
 942+
 943+ // Build out iframe in string since IE throws away attributes of
 944+ // jQuery iframe buildout
 945+ var s = '<iframe ';
 946+
 947+ // Check for context
 948+ if( ! options[ 'context' ] ) {
 949+ mw.log("Error missing context");
 950+ return false;
 951+ }else{
 952+ var context = options[ 'context' ];
 953+ }
 954+
 955+ if( ! options[ 'src' ] ) {
 956+ options[ 'src' ] = getServerFrame( context );
 957+ }
 958+
 959+ // Check for frame name:
 960+ if( ! options[ 'name' ] ) {
 961+ options[ 'name' ] = 'mwApiProxyFrame_' + $j( 'iframe' ).length;
 962+ }
 963+
 964+ // Add the frame name / id:
 965+ s += 'name="' + mw.escapeQuotes( options[ 'name' ] ) + '" ';
 966+ s += 'id="' + mw.escapeQuotes( options[ 'name' ] ) + '" ';
 967+
 968+ // Check for style:
 969+ if( ! options['style'] ) {
 970+ options['style'] = 'display:none';
 971+ }
 972+
 973+ // Add style attribute:
 974+ s += 'style="' + mw.escapeQuotes( options[ 'style' ] ) + '" ';
 975+
 976+ // Special handler for src and packaged hash request:
 977+ if( options.src ) {
 978+ s += 'src="' + mw.escapeQuotes( options.src );
 979+ if( options.request ) {
 980+
 981+ // Add the contextKey to the request
 982+ options.request[ 'contextKey' ] = context.contextKey;
 983+
 984+ // Add the escaped version of the request:
 985+ s += '#' + encodeURIComponent( JSON.stringify( options.request ) );
 986+ }
 987+ s += '" ';
 988+ }
 989+
 990+ // Close up the iframe:
 991+ s += '></iframe>';
 992+
 993+ // Check for the iframe append target ( default "body" tag )
 994+ if( ! options[ 'target' ] ){
 995+ options[ 'target' ] = 'body';
 996+ }
 997+ var targetName = ( typeof options[ 'target' ] == 'string') ? options[ 'target' ] : $j( options[ 'target' ]).length ;
 998+
 999+ mw.log( "Append iframe:" + options[ 'src' ] + ' to: ' + targetName + " \n with data: " + JSON.stringify( options.request ) );
 1000+
 1001+ // Append to target
 1002+ $j( options[ 'target' ] ).append( s );
 1003+
 1004+ // Setup the onload callback
 1005+ $j( '#' + options[ 'name' ] ).get( 0 ).onload = function() {
 1006+ if( ! options.persist ){
 1007+ // Schedule the removal of the iframe
 1008+ // We don't call remove directly since some browsers seem to call "ready"
 1009+ // before blocking javascript code is done running
 1010+ setTimeout( function() {
 1011+ $j('#' + options[ 'name' ] ).remove();
 1012+ }, 10 );
 1013+ }
 1014+ };
 1015+
 1016+ // Setupt the timeout check:
 1017+ setTimeout( function() {
 1018+ if ( context[ 'proxyLoaded' ] === false ) {
 1019+ // We timed out no api proxy (should make sure the user is "logged in")
 1020+ proxyNotReadyTimeout( context );
 1021+ }
 1022+ }, mw.getConfig( 'defaultRequestTimeout') * 1000 );
 1023+ }
 1024+
 1025+} )( window.mw.ApiProxy );
Property changes on: trunk/extensions/MwEmbed/MwEmbed/modules/ApiEmbed/mw.ApiProxy.js
___________________________________________________________________
Added: svn:mime-type
11026 + text/plain
Index: trunk/extensions/MwEmbed/MwEmbed/modules/ApiEmbed/README
@@ -0,0 +1 @@
 2+Probably have to move this to an extension
\ No newline at end of file
Index: trunk/extensions/MwEmbed/MwEmbed/modules/ApiEmbed/ApiEmbed.resourceList.php
@@ -0,0 +1,10 @@
 2+<?php
 3+/**
 4+ * MwEmebed ApiEmbed resource list array
 5+ */
 6+
 7+return array(
 8+ 'ApiEmbed' => array(
 9+ 'loader' => array() // @@FIXME add in apiSupport
 10+ )
 11+)
\ No newline at end of file
Index: trunk/extensions/MwEmbed/MwEmbed/modules/ApiEmbed/ApiProxy.i18n.php
@@ -0,0 +1,195 @@
 2+<?php
 3+/*
 4+ * Internationalisation for ApiProxy
 5+ *
 6+ * @file
 7+ * @ingroup Extensions
 8+ */
 9+
 10+$messages = array();
 11+$messages['en'] = array(
 12+ 'mwe-setting-up-proxy' => 'Setting up proxy...',
 13+ 'mwe-re-try' => 'Retry API request',
 14+ 'mwe-re-trying' => 'Retrying API request...',
 15+ 'mwe-proxy-not-ready' => 'Proxy is not configured',
 16+ 'mwe-please-login' => 'The request failed. Are you logged in on $1 ? Please $2 and try again',
 17+ 'mwe-log-in-link' => 'log in',
 18+ 'mwe-remember-loging' => 'General security reminder: Only login to web sites when your address bar displays that site\'s address.',
 19+);
 20+$messages['ar'] = array(
 21+ 'mwe-re-try' => 'أعد طلب الواجهة البرمجية',
 22+ 'mwe-re-trying' => 'يعيد طلب الواجهة البرمجية...',
 23+);
 24+$messages['be-tarask'] = array(
 25+ 'mwe-setting-up-proxy' => 'Наладка проксі...',
 26+ 'mwe-re-try' => 'Паўтарыць API-запыт',
 27+ 'mwe-re-trying' => 'Паўторны API-запыт…',
 28+ 'mwe-proxy-not-ready' => 'Проксі не сканфігураваны',
 29+ 'mwe-please-login' => 'Вы не <a target="_new" href="$1">ўвайшлі ў сыстэму</a> $2 альбо mwEmbed ня быў уключаны. Вырашыце гэтую праблему і потым паўтарыце запыт.',
 30+ 'mwe-remember-loging' => 'Агульны напамін бясьпекі: Уваходзьце ў сыстэму толькі ў тым выпадку, калі ў радку адраса адлюстроўваецца адрас сайту, які чакаецца.',
 31+);
 32+$messages['br'] = array(
 33+ 'mwe-setting-up-proxy' => 'Arventenniñ ar proksi...',
 34+);
 35+$messages['bs'] = array(
 36+ 'mwe-re-try' => 'Pokušaj API zahtjev',
 37+);
 38+$messages['de'] = array(
 39+ 'mwe-setting-up-proxy' => 'Proxy-Einstellung …',
 40+ 'mwe-re-try' => 'Wiederhole API-Anfrage',
 41+ 'mwe-re-trying' => 'Wiederholung der API-Anfrage …',
 42+ 'mwe-proxy-not-ready' => 'Proxy nicht konfiguriert',
 43+ 'mwe-please-login' => 'Du bist auf $2 nicht <a target="_new" href="$1">angemeldet</a> oder mwEmbed ist nicht aktiviert. Löse das Problem und wiederhole deine Anfrage.',
 44+ 'mwe-remember-loging' => 'Allgemeiner Sicherheitshinweis: Websiteanmeldung nur, wenn deine Adressleiste die Websiteadresse anzeigt.',
 45+);
 46+$messages['diq'] = array(
 47+ 'mwe-setting-up-proxy' => 'proxy bar beno...',
 48+ 'mwe-re-try' => 'waştışê Retry API\'yi',
 49+ 'mwe-re-trying' => 'newe ra waştışê Retry API\'yi...',
 50+ 'mwe-proxy-not-ready' => 'proxy nêvıraziyayo/ro nêniyayo',
 51+ 'mwe-please-login' => '<a target="_new" href="$1">logged in</a> on $2 aktif nêbiyo, newe ra tesel bıkerê.',
 52+ 'mwe-remember-loging' => 'virrardışê pawıtışê umumiyi: adresê keyepeli têna wextê cıkewetışi de aseni',
 53+);
 54+$messages['dsb'] = array(
 55+ 'mwe-setting-up-proxy' => 'Proksy se pśihotujo...',
 56+ 'mwe-re-try' => 'Napšašowanje API wóspjetowaś',
 57+ 'mwe-re-trying' => 'Napšašowanje API so wóspjetujo...',
 58+ 'mwe-proxy-not-ready' => 'Proksy njejo konfigěrowany',
 59+ 'mwe-please-login' => 'Njejsy na $2 <a target="_new" href="$1">pśizjawjony</a> abo mwEmbed njejo zmóžnjony. Rozwěž tuś ten problem a wóspjetuj pótom napšašowanje.',
 60+ 'mwe-remember-loging' => 'Powšykne wěstotne dopominanje: Pśizjaw se jano na websedłach, gaž twójo adresowe pólo zwobraznjujo adresu togo sedła.',
 61+);
 62+$messages['es'] = array(
 63+ 'mwe-re-try' => 'Reintentar solicitud de API',
 64+ 'mwe-re-trying' => 'Reintentando solicitud de API',
 65+ 'mwe-proxy-not-ready' => 'Proxy no configurado',
 66+ 'mwe-remember-loging' => 'Recordatorio general de seguridad: Accede a los sitios web sólo cuando la barra de direcciones muestre esa dirección del sitio.',
 67+);
 68+$messages['fr'] = array(
 69+ 'mwe-setting-up-proxy' => 'Paramétrage du proxy...',
 70+ 'mwe-re-try' => 'Réessayer la requête API',
 71+ 'mwe-re-trying' => 'Nouvelle tentative de requête API...',
 72+ 'mwe-proxy-not-ready' => 'Le proxy n’est pas configuré',
 73+ 'mwe-please-login' => 'Vous n’êtes pas <a target="_new" href="$1">connecté</a> sur $2 ou mwEmbed n’a pas été activé. Corrigez le problème, puis retentez votre requête.',
 74+ 'mwe-remember-loging' => 'Rappel de sécurité : ne vous connectez à un site internet que lorsque l’adresse de ce site est affichée dans votre barre d’adresse.',
 75+);
 76+$messages['gl'] = array(
 77+ 'mwe-setting-up-proxy' => 'Configurando o proxy...',
 78+ 'mwe-re-try' => 'Reintentar a solicitude API',
 79+ 'mwe-re-trying' => 'Reintentando a solicitude API...',
 80+ 'mwe-proxy-not-ready' => 'O proxy non está configurado',
 81+ 'mwe-please-login' => 'Non <a target="_new" href="$1">accedeu ao sistema</a> de $2 ou o mwEmbed non está activado. Resolva o problema e intente de novo a solicitude.',
 82+ 'mwe-remember-loging' => 'Advertencia de seguridade xeral: non acceda ao sistema de ningunha páxina web cando a súa barra de enderezos mostre outro enderezo que non se corresponda co dese sitio.',
 83+);
 84+$messages['gsw'] = array(
 85+ 'mwe-setting-up-proxy' => 'Am Yystelle vun eme Proxy ...',
 86+ 'mwe-re-try' => 'API-Aafrog widerhole',
 87+ 'mwe-re-trying' => 'Am Widerhole vun ere API-Aafrog ...',
 88+ 'mwe-proxy-not-ready' => 'Proxy isch nit konfiguriert',
 89+ 'mwe-please-login' => 'Du bisch nit <a target="_new" href="$1">aagmäldet</a> uf $2 oder mwEmbed isch nit aagschalte. Les s Probläm un versuech d Aafrog derno nonemol.',
 90+ 'mwe-remember-loging' => 'Generälli Sicherheits-Erinnerig: Mäld di numme uf Websyte aa, wänn Dyyni Adrässleischte d Adrässe vu däre Syte aazeigt.',
 91+);
 92+$messages['hsb'] = array(
 93+ 'mwe-setting-up-proxy' => 'Proksy so připrawja...',
 94+ 'mwe-re-try' => 'Naprašowanje API wospjetować',
 95+ 'mwe-re-trying' => 'Naprašowanje API so wospjetuje...',
 96+ 'mwe-proxy-not-ready' => 'Proksy njeje konfigurowany',
 97+ 'mwe-please-login' => 'Njejsy na $2 <a target="_new" href="$1">přizjewjeny</a> abo mwEmbed njeje zmóžnjeny. Rozrisaj tutón problem a wospjetuj potom naprašowanje.',
 98+ 'mwe-remember-loging' => 'Powšitkowne wěstotne dopomnjeće: Přizjew so jenož na websydłach, hdyž twoje adresowe polo adresu sydła zwobraznjuje.',
 99+);
 100+$messages['hu'] = array(
 101+ 'mwe-setting-up-proxy' => 'Proxy beállítása…',
 102+ 'mwe-re-try' => 'API kérés újrapróbálása',
 103+ 'mwe-re-trying' => 'API kérés újraküldése…',
 104+ 'mwe-proxy-not-ready' => 'A proxy nincs beállítva',
 105+ 'mwe-please-login' => 'Nem vagy <a target="_new" href="$1">bejelentkezve</a> a(z) $2 wikire, vagy az mwEmbed nincs engedélyezve. Orvosold a problémát, majd próbáld újra a kérést.',
 106+ 'mwe-remember-loging' => 'Általános biztonsági emlékeztető: csak akkor jelentkezz be egy weboldalra, ha a böngésződ címsorában annak az oldalnak a címét látod.',
 107+);
 108+$messages['ia'] = array(
 109+ 'mwe-setting-up-proxy' => 'Configuration del proxy...',
 110+ 'mwe-re-try' => 'Reprobar requesta API',
 111+ 'mwe-re-trying' => 'Reproba requesta API...',
 112+ 'mwe-proxy-not-ready' => 'Le proxy non es configurate',
 113+ 'mwe-please-login' => 'Tu non es <a target="_new" href="$1">identificate</a> in $2 o mwEmbed non ha essite activate. Resolve le problema, alora reproba le requesta.',
 114+ 'mwe-remember-loging' => 'Promemoria general de securitate: Solmente identifica te a sitos web si tu barra de adresse monstra le adresse del sito in question.',
 115+);
 116+$messages['id'] = array(
 117+ 'mwe-setting-up-proxy' => 'Menyiapkan proksi...',
 118+ 'mwe-re-try' => 'Ulangi permintaan API',
 119+ 'mwe-re-trying' => 'Mengulangi permintaan API...',
 120+ 'mwe-proxy-not-ready' => 'Proksi tak dapat dikonfigurasi',
 121+ 'mwe-please-login' => 'Anda tidak <a target="_new" href="$1">masuk log</a> di $2 atau mwEmbed belum diaktifkan. Perbaiki masalah ini, dan ulangi permintaan.',
 122+ 'mwe-remember-loging' => 'Pengingat keamanan umum: Hanya masuk log ke situs web sewaktu bilah alamat Anda menampilkan alamat situs tersebut.',
 123+);
 124+$messages['it'] = array(
 125+ 'mwe-setting-up-proxy' => 'Installazione del proxy in corso...',
 126+ 'mwe-proxy-not-ready' => 'Il Proxy non è configurato',
 127+);
 128+$messages['ja'] = array(
 129+ 'mwe-setting-up-proxy' => 'プロキシをセットアップ中…',
 130+ 'mwe-re-try' => 'API 要求を再試行',
 131+ 'mwe-re-trying' => 'API 要求を再試行中…',
 132+ 'mwe-proxy-not-ready' => 'プロキシが設定されていません',
 133+ 'mwe-please-login' => 'あなたが $2 へ<a target="_new" href="$1">ログイン</a>していないか、mwEmbed が有効化されていません。この問題を解決し、それから要求を再試行してください。',
 134+ 'mwe-remember-loging' => '一般的に、セキュリティーのためにはアドレスバーにそのサイトのアドレスが表示されるウェブサイトにのみログインしてください。',
 135+);
 136+$messages['ksh'] = array(
 137+ 'mwe-remember-loging' => 'Opjepaß: För sescher ze sinn, donn bloß dann ööhnßwoh enlogge,wann Dinge Brauser dä ßait ier Addräß en singem Feld för de Addräß aanzeijsch!',
 138+);
 139+$messages['lb'] = array(
 140+ 'mwe-setting-up-proxy' => 'Proxy astellen ...',
 141+ 'mwe-re-try' => 'Api-Ufro widderhuelen',
 142+ 'mwe-re-trying' => 'UPI-Ufro gëtt widderholl.',
 143+ 'mwe-proxy-not-ready' => 'De Proxy ass net agestallt',
 144+);
 145+$messages['ml'] = array(
 146+ 'mwe-setting-up-proxy' => 'പ്രോക്സി സജ്ജീകരിക്കുന്നു...',
 147+ 'mwe-proxy-not-ready' => 'പ്രോക്സി ക്രമീകരിക്കപ്പെട്ടിട്ടില്ല.',
 148+ 'mwe-please-login' => 'താങ്കൾ $2 സംരംഭത്തിൽ <a target="_new" href="$1">പ്രവേശിച്ചിട്ടില്ല</a> അല്ലങ്കിൽ mwEmbed സജ്ജമാക്കിയിട്ടില്ല. ഈ പ്രശ്നം പരിഹരിച്ച ശേഷം വീണ്ടും ശ്രമിക്കൂ.',
 149+ 'mwe-remember-loging' => 'പൊതു സുരക്ഷാ ഓർമ്മക്കുറിപ്പ്: സൈറ്റിന്റെ വിലാസം അഡ്രസ് ബാറിൽ കാണുകയാണെങ്കിൽ മാത്രം ലോഗിൻ ചെയ്യുക.',
 150+);
 151+$messages['nl'] = array(
 152+ 'mwe-setting-up-proxy' => 'Bezig met het opzetten van een proxy...',
 153+ 'mwe-re-try' => 'API-verzoek opnieuw uitvoeren',
 154+ 'mwe-re-trying' => 'Bezig met het opnieuw uitvoeren van het API-verzoek...',
 155+ 'mwe-proxy-not-ready' => 'De proxy is niet ingesteld',
 156+ 'mwe-please-login' => 'U bent niet <a target="_new" href="$1">aangemeld</a> by $2 of mwEmbed is niet ingeschakeld. Los het probleem op, en voer het verzoek daarna opnieuw uit.',
 157+ 'mwe-remember-loging' => 'Algemene beveiligingswaarschuwing: meld u zich alleen aan bij websites waarvan het adres in de adresbalk overeenkomt met het webadres van de site.',
 158+);
 159+$messages['oc'] = array(
 160+ 'mwe-setting-up-proxy' => 'Parametratge del proxy...',
 161+ 'mwe-re-try' => 'Tornar ensajar la requèsta API',
 162+ 'mwe-re-trying' => 'Novèla temptativa de requèsta API...',
 163+ 'mwe-proxy-not-ready' => 'Lo proxy es pas configurat',
 164+ 'mwe-please-login' => 'Sètz pas <a target="_new" href="$1">connectat</a> sus $2 o mwEmbed es pas estat activat. Corregissètz lo problèma, puèi ensajatz tornamai vòstra requèsta.',
 165+ 'mwe-remember-loging' => 'Rapèl de seguretat : vos connectetz pas a un site internet que quand l’adreça d\'aquel site es afichada dins vòstra barra d’adreça.',
 166+);
 167+$messages['pt'] = array(
 168+ 'mwe-setting-up-proxy' => 'A preparar o \'\'proxy\'\'...',
 169+ 'mwe-re-try' => 'Repetir pedido API',
 170+ 'mwe-re-trying' => 'A repetir pedido API...',
 171+ 'mwe-proxy-not-ready' => 'O \'\'proxy\'\' não está configurado',
 172+ 'mwe-please-login' => 'Não está <a target="_new" href="$1">autenticado</a> em $2 ou o mwEmbed não foi activado. Resolva o problema e depois repita o pedido.',
 173+ 'mwe-remember-loging' => 'Recomendação geral de segurança: Ao entrar em sítios na internet, certifique-se de que a barra do endereço mostra o endereço do sítio.',
 174+);
 175+$messages['ru'] = array(
 176+ 'mwe-setting-up-proxy' => 'Настройка прокси…',
 177+ 'mwe-re-try' => 'Повторить API-запрос',
 178+ 'mwe-re-trying' => 'Повторение API-запроса…',
 179+ 'mwe-proxy-not-ready' => 'Прокси не настроен',
 180+ 'mwe-please-login' => 'Вы не <a target="_new" href="$1">представились системе</a> $2 или mwEmbed не был включён. Решите проблему и затем повторите запрос.',
 181+ 'mwe-remember-loging' => 'Общее напоминание о безопасности. Представляйтесь системе только в том случае, если в строке адреса отображается адрес ожидаемого сайта.',
 182+);
 183+$messages['sv'] = array(
 184+ 'mwe-proxy-not-ready' => 'Proxy är inte konfigurerad',
 185+);
 186+$messages['tr'] = array(
 187+ 'mwe-setting-up-proxy' => 'Vekil ayarlanıyor...',
 188+ 'mwe-re-try' => 'API isteğini tekrar dene',
 189+ 'mwe-re-trying' => 'API isteği tekrar deneniyor...',
 190+ 'mwe-proxy-not-ready' => 'Vekil ayarlanmadı',
 191+ 'mwe-please-login' => '$2 sitesinde <a target="_new" href="$1">oturum açmadınız</a> ya da mwEmbed henüz etkinleştirilmedi.Sorunu çözün, ve sonra isteği tekrar deneyin.',
 192+ 'mwe-remember-loging' => 'Genel güvenlik hatırlatıcısı: Sadece adres çubuğunuz sitenin adresini gösterirse sitlere giriş yapın.',
 193+);
 194+$messages['vec'] = array(
 195+ 'mwe-proxy-not-ready' => 'El proxy no\'l xe mia configurà',
 196+);
Property changes on: trunk/extensions/MwEmbed/MwEmbed/modules/ApiEmbed/ApiProxy.i18n.php
___________________________________________________________________
Added: svn:executable
1197 + *
Index: trunk/extensions/MwEmbed/MwEmbed/modules/ApiEmbed/loader.js
@@ -0,0 +1,18 @@
 2+/* apiProxy Loader / config */
 3+
 4+// Wrap in mw to not pollute global namespace
 5+( function( mw ) {
 6+
 7+ // Set the default allowable domains for api proxy
 8+ mw.setDefaultConfig({
 9+ // Black list domains
 10+ 'ApiProxy.DomainBlackList' : [],
 11+
 12+ // White list domains
 13+ 'ApiProxy.DomainWhiteList' : [
 14+ 'localhost',
 15+ '127.1.1.100'
 16+ ]
 17+ });
 18+
 19+} )( window.mw );
\ No newline at end of file
Property changes on: trunk/extensions/MwEmbed/MwEmbed/modules/ApiEmbed/loader.js
___________________________________________________________________
Added: svn:mime-type
120 + text/plain
Added: svn:executable
221 + *
Index: trunk/extensions/MwEmbed/MwEmbed/modules/ApiEmbed/tests/testApiProxy.html
@@ -0,0 +1,190 @@
 2+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 3+<html>
 4+<head>
 5+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 6+<title>Api Proxy Test</title>
 7+ <script type="text/javascript" src="../../../mwEmbed.js?debug=true"></script>
 8+ <!-- <script type="text/javascript" src="../../../ResourceLoader.php?class=window.jQuery,mwEmbed"></script> -->
 9+<script type="text/javascript" >
 10+//HARD coded local test:
 11+var remote_wiki_host = 'http://commons.wikimedia.org';
 12+var remote_script_path = '/w';
 13+var remote_apiUrl = remote_wiki_host + remote_script_path + '/api.php';
 14+
 15+mw.ready( function(){
 16+ $j('#hostName').text( remote_wiki_host );
 17+ //callback function here:
 18+ $j('#setupDone').show('slow');
 19+ $j('#doHello').click( doHello );
 20+ $j('#doAppend').click( doAppend );
 21+ $j('#doFileBrowse').click( doFileUpload );
 22+});
 23+
 24+function doHello(){
 25+ mw.log('to a hello user');
 26+ $j('#helloTarget').loadingSpinner();
 27+ //first get the user name:
 28+ getUserName( function( user_name ){
 29+ $j('#helloTarget').addClass('UserNameFound').hide().text( user_name ).fadeIn('slow');
 30+ } );
 31+ return false;
 32+}
 33+function getUserName( callback ){
 34+ var rObj = {
 35+ 'action':'query',
 36+ 'meta':'userinfo'
 37+ }
 38+ // Do request ( will automatically invoke proxy because its a proxy action and remote url )
 39+ mw.getJSON( remote_apiUrl, rObj, function( data ){
 40+ //now we get the data back for that domain
 41+ if( !data.query || !data.query.userinfo ){
 42+ mw.log("Error no query.userinfo ");
 43+ return false;
 44+ }
 45+ callback( data.query.userinfo.name );
 46+ }
 47+ );
 48+}
 49+
 50+// Simple "hello from api proxy" append on talk page
 51+function doAppend(){
 52+ $j('#appendTarget').loadingSpinner();
 53+ //get user name
 54+ getUserName( function( userName ){
 55+ var eTitle = 'User_talk:' + userName;
 56+ // Get a edit token
 57+ mw.getToken( remote_apiUrl, eTitle, function( token ) {
 58+ mw.log("got token: " + token) ;
 59+ var request = {
 60+ 'action':'edit',
 61+ 'title': eTitle,
 62+ 'summary': "Api proxy test edit",
 63+ 'appendtext': "\n\n==== Hello from Api proxy At: " + Date() + " ====",
 64+ 'token': token
 65+ }
 66+ mw.getJSON( remote_apiUrl, request, function( result ){
 67+ if(result.edit && result.edit.newrevid){
 68+ $j('#appendTarget').html( "success: " + JSON.stringify ( result) );
 69+ url = remote_wiki_host + remote_script_path + '/index.php/';
 70+ url+= result.edit.title.replace(' ', '_');
 71+ $j('#appendTarget').append( '<br><a target="_new" href="' + url + '">visit page</a>' );
 72+ }else{
 73+ $j('#appendTarget').html( "falied: " + JSON.stringify ( result) );
 74+ }
 75+ });
 76+
 77+ });
 78+ });
 79+}
 80+
 81+function doFileUpload(){
 82+ $j('#file-upload-container').fadeIn( 'slow' );
 83+ $j('#browseTarget').loadingSpinner();
 84+ // Load firefogg lib
 85+ mw.load('AddMedia.firefogg', function( ) {
 86+ // Load proxy lib
 87+ mw.load( 'ApiProxy', function( ) {
 88+ // Get a token for the upload:
 89+ mw.getToken( remote_apiUrl, 'File:MyRandomFileTokenCheck.jpg', function( eToken ) {
 90+ mw.log(" got token :: " + eToken);
 91+ // Add the token to the dom:
 92+ $j( '#file-name' ).append(
 93+ $j('<input />')
 94+ .attr({
 95+ 'type': 'hidden',
 96+ 'id' : 'wpEditToken',
 97+ 'name' : 'token'
 98+ })
 99+ .val( eToken )
 100+ );
 101+ var fileIframeName = mw.ApiProxy.browseFile( {
 102+ //Target div to put the iframe browser button:
 103+ 'target' : '#browseTarget',
 104+
 105+ // Set the token
 106+ 'token' : eToken,
 107+
 108+ // Api url to upload to
 109+ 'apiUrl' : remote_apiUrl,
 110+
 111+ // File Destination Name change callback:
 112+ 'selectFileCb' : function( fname ){
 113+ // Update our local target:
 114+ $j('#file-name').val( fname );
 115+ // Run a destination file name check on the remote target
 116+ $j('#file-name').doDestCheck( {
 117+ 'apiUrl' : remote_apiUrl,
 118+ 'warn_target': '#file-warning'
 119+ } );
 120+ },
 121+ 'doneUploadCb' : function( apiResult ){
 122+ alert(' upload done' );
 123+ }
 124+ } );
 125+
 126+ //Setup submit binding:
 127+ $j('#uploadButton').click( function( ){
 128+ // Build the output and send upload request to fileProxy
 129+ mw.ApiProxy.sendServerMsg( {
 130+ 'apiUrl' : remote_apiUrl,
 131+ 'frameName' : fileIframeName,
 132+ 'frameMsg' : {
 133+ 'action' : 'fileSubmit',
 134+ 'formData' : {
 135+ 'filename' : $j('#file-name').val(),
 136+ 'comment' : $j('#file-desc').val()
 137+ }
 138+ }
 139+ } );
 140+ // Maybe set loading to spinner
 141+ } );
 142+
 143+
 144+ // Setup doDestCheck on change
 145+ $j('#file-name').change(function(){
 146+ $j('#file-name').doDestCheck( {
 147+ 'apiUrl' : remote_apiUrl,
 148+ 'warn_target': '#file-warning'
 149+ } );
 150+ });
 151+ });
 152+ })
 153+ });
 154+};
 155+
 156+</script>
 157+
 158+</head>
 159+<body>
 160+<h3> Simple API proxy testing system </h3>
 161+
 162+<div id="setupProxy">Proxy for: <span id="hostName"></span> <br>
 163+<span style="font-size:small"> this proxy will only work on a limited set of domains that the gadget allows proxy request from </span></div>
 164+<div id="setupDone" style="display:none;">
 165+ <br> <a href="#" id="doHello" >Hello User:</a> <span style="width:200px" id="helloTarget"></span>
 166+
 167+ <br><br><br> <a href="#" id="doAppend">Append Msg to Talk page:</a>
 168+ <div id="appendTarget"></div>
 169+
 170+ <br><br><a href="#" id="doFileBrowse">Upload a file to remote:</a>
 171+ <div id="file-upload-container" style="display:none">
 172+ <div style="background:#FEF;margin:20px;">
 173+ <h3> Local input </h3>
 174+ Target file name: <input id="file-name" type="text" size="15" />
 175+ <div id="file-warning"></div>
 176+ <BR>
 177+ Target desc: <input id="file-desc" type="text" size="20" value="test proxy desc"/>
 178+ </div>
 179+ <div style="background:#CEF;margin:20px;">
 180+ <h3> Browse File Served From Remote: </h3>
 181+ <div id="browseTarget"></div>
 182+ </div>
 183+ <div style="background:#FEF;margin:20px;">
 184+ <h3> Local submit </h3>
 185+ <input id="uploadButton" type="submit" size="10" value="upload" />
 186+ </div>
 187+ </div>
 188+</div>
 189+
 190+</body>
 191+</html>
\ No newline at end of file
Property changes on: trunk/extensions/MwEmbed/MwEmbed/modules/ApiEmbed/tests/testApiProxy.html
___________________________________________________________________
Added: svn:mime-type
1192 + text/plain
Index: trunk/extensions/MwEmbed/MwEmbed/modules/ApiEmbed/ApiProxyPage.js
@@ -0,0 +1,22 @@
 2+/**
 3+* mwProxy js2 page system.
 4+*
 5+* Invokes the apiProxy system
 6+*/
 7+
 8+/*
 9+ * Since this is proxy server set a pre-append debug flag to know which debug msgs are coming from where
 10+ */
 11+
 12+mw.setConfig( 'Mw.LogPrepend', 'Proxy:');
 13+
 14+// The default allowable domain list is stored in the loader.js configuration.
 15+
 16+mw.ready( function() {
 17+ mw.log( 'load ApiProxy' );
 18+ mw.load( 'ApiProxy', function() {
 19+ // Clear out the page content ( not needed for iframe proxy )
 20+ $j( 'body' ).html( '' );
 21+ mw.ApiProxy.server();
 22+ } );
 23+} );
Property changes on: trunk/extensions/MwEmbed/MwEmbed/modules/ApiEmbed/ApiProxyPage.js
___________________________________________________________________
Added: svn:mime-type
124 + text/plain
Added: svn:executable
225 + *
Index: trunk/extensions/MwEmbed/MwEmbed/modules/ApiEmbed/NestedCallbackIframe.html
@@ -0,0 +1,16 @@
 2+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 3+<html>
 4+<head>
 5+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 6+<title>Simple nested iframe callback page</title>
 7+<script type="text/javascript">
 8+window.onload = function () {
 9+ //call the nested callback in top most frame:
 10+ top.mw.ApiProxy.nested( window.location.href.split("#")[1] || false );
 11+}
 12+</script>
 13+</head>
 14+<body>
 15+Nested Iframe callback
 16+</body>
 17+</html>
\ No newline at end of file
Property changes on: trunk/extensions/MwEmbed/MwEmbed/modules/ApiEmbed/NestedCallbackIframe.html
___________________________________________________________________
Added: svn:mime-type
118 + text/plain
Index: trunk/extensions/MwEmbed/MwEmbed/modules/ApiEmbed/mw.Api.js
@@ -0,0 +1,370 @@
 2+/**
 3+* API Helper functions
 4+*/
 5+
 6+( function( mw ) {
 7+ // xxx note we should namespace the following helper functions into Api class.
 8+ mw.Api = {};
 9+
 10+ /**
 11+ *
 12+ * Helper function to get revision text for a given title
 13+ *
 14+ * Assumes "follow redirects"
 15+ *
 16+ * $j.getTitleText( [apiUrl], title, callback )
 17+ *
 18+ * @param {String} url or title key
 19+ * @parma {Mixed} title or callback function
 20+ * @param {Function} callback Function or NULL
 21+ *
 22+ * @return callback is called with:
 23+ * {Boolean} false if no page found
 24+ * {String} text of wiki page
 25+ */
 26+ mw.getTitleText = function( apiUrl, title, callback ) {
 27+ // Check if optional apiURL was not included
 28+ if( !callback ) {
 29+ title = apiUrl;
 30+ callback = title;
 31+ apiUrl = mw.getLocalApiUrl();
 32+ }
 33+ var request = {
 34+ // Normalize the File NS (ie sometimes its present in apiTitleKey other times not
 35+ 'titles' : title,
 36+ 'prop' : 'revisions',
 37+ 'rvprop' : 'content'
 38+ };
 39+
 40+ mw.getJSON( apiUrl , request, function( data ) {
 41+ if( !data || !data.query || !data.query.pages ) {
 42+ callback( false );
 43+ }
 44+ var pages = data.query.pages;
 45+ for(var i in pages) {
 46+ page = pages[ i ];
 47+ if( page[ 'revisions' ] && page[ 'revisions' ][0]['*'] ) {
 48+ callback( page[ 'revisions' ][0]['*'] );
 49+ }
 50+ }
 51+ } );
 52+ }
 53+
 54+ /**
 55+ * Issues the wikitext parse call
 56+ *
 57+ * @param {String} wikitext Wiki Text to be parsed by mediaWiki api call
 58+ * @param {String} title Context title of the content to be parsed
 59+ * @param {Function} callback Function called with api parser output
 60+ */
 61+ mw.parseWikiText = function( wikitext, title, callback ) {
 62+ mw.log("mw.parseWikiText text length: " + wikitext.length + ' title context: ' + title );
 63+ mw.load( 'JSON', function(){
 64+ $j.ajax({
 65+ type: 'POST',
 66+ url: mw.getLocalApiUrl(),
 67+ // Give the wiki 60 seconds to parse the wiki-text
 68+ timeout : 60000,
 69+ data: {
 70+ 'action': 'parse',
 71+ 'format': 'json',
 72+ 'title' : title,
 73+ 'text': wikitext
 74+ },
 75+ dataType: 'text',
 76+ success: function( data ) {
 77+ var jsonData = JSON.parse( data ) ;
 78+ // xxx should handle other failures
 79+ callback( jsonData.parse.text['*'] );
 80+ },
 81+ error: function( XMLHttpRequest, textStatus, errorThrown ){
 82+ // xxx should better handle failures
 83+ mw.log( "Error: mw.parseWikiText:" + textStatus );
 84+ callback( "Error: failed to parse wikitext " );
 85+ }
 86+ });
 87+ });
 88+ }
 89+
 90+ /**
 91+ * mediaWiki JSON a wrapper for jQuery getJSON:
 92+ * ( could also be named mw.apiRequest )
 93+ *
 94+ * The mwEmbed version lets you skip the url part
 95+ * mw.getJSON( [url], data, callback, [timeoutCallback] );
 96+ *
 97+ * Lets you assume:
 98+ * url is optional
 99+ * ( If the first argument is not a string we assume a local mediaWiki api request )
 100+ * callback parameter is not needed for the request data
 101+ * url param 'action'=>'query' is assumed ( if not set to something else in the "data" param
 102+ * format is set to "json" automatically
 103+ * automatically issues request over "POST" if the request api post type
 104+ * automatically will setup apiProxy where request is cross domain
 105+ *
 106+ * @param {Mixed} url or data request
 107+ * @param {Mixed} data or callback
 108+ * @param {Function} callbcak function called on success
 109+ * @param {Function} callbackTimeout - optional function called on timeout
 110+ * Setting timeout callback also avoids default timed-out dialog for proxy requests
 111+ */
 112+ mw.getJSON = function() {
 113+ // Process the arguments:
 114+
 115+ // Set up the url
 116+ var url = false;
 117+ url = ( typeof arguments[0] == 'string' ) ? arguments[0] : mw.getLocalApiUrl();
 118+
 119+ // Set up the data:
 120+ var data = null;
 121+ data = ( typeof arguments[0] == 'object' ) ? arguments[0] : null;
 122+ if( !data && typeof arguments[1] == 'object' ) {
 123+ data = arguments[1];
 124+ }
 125+
 126+ // Setup the callback
 127+ var callback = false;
 128+ callback = ( typeof arguments[1] == 'function') ? arguments[1] : false;
 129+ var cbinx = 1;
 130+ if( ! callback && ( typeof arguments[2] == 'function') ) {
 131+ callback = arguments[2];
 132+ cbinx = 2;
 133+ }
 134+
 135+ // Setup the timeoutCallback ( function after callback index )
 136+ var timeoutCallback = false;
 137+ timeoutCallback = ( typeof arguments[ cbinx + 1 ] == 'function' ) ? arguments[ cbinx + 1 ] : false;
 138+
 139+ // Make sure we got a url:
 140+ if( !url ) {
 141+ mw.log( 'Error: no api url for api request' );
 142+ return false;
 143+ }
 144+
 145+ // Add default action if unset:
 146+ if( !data['action'] ) {
 147+ data['action'] = 'query';
 148+ }
 149+
 150+ // Add default format if not set:
 151+ if( !data['format'] ) {
 152+ data['format'] = 'json';
 153+ }
 154+
 155+ // Setup callback wrapper for timeout
 156+ var requestTimeOutFlag = false;
 157+ var ranCallback = false;
 158+
 159+ /**
 160+ * local callback function to control timeout
 161+ * @param {Object} data Result data
 162+ */
 163+ var myCallback = function( data ){
 164+ if( ! requestTimeOutFlag ){
 165+ ranCallback = true;
 166+ callback( data );
 167+ }
 168+ }
 169+ // Set the local timeout call based on defaultRequestTimeout
 170+ setTimeout( function( ) {
 171+ if( ! ranCallback ) {
 172+ requestTimeOutFlag = true;
 173+ mw.log( "Error:: request timed out: " + url );
 174+ if( timeoutCallback ){
 175+ timeoutCallback();
 176+ }
 177+ }
 178+ }, mw.getConfig( 'defaultRequestTimeout' ) * 1000 );
 179+
 180+ mw.log("run getJSON: " + mw.replaceUrlParams( url, data ) );
 181+
 182+ // Check if the request requires a "post"
 183+ if( mw.checkRequestPost( data ) ) {
 184+
 185+ // Check if we need to setup a proxy
 186+ if( ! mw.isLocalDomain( url ) ) {
 187+
 188+ //Set local scope ranCallback to true
 189+ // ( ApiProxy handles timeouts internally )
 190+ ranCallback = true;
 191+
 192+ // Load the proxy and issue the request
 193+ mw.load( 'ApiProxy', function( ) {
 194+ mw.ApiProxy.doRequest( url, data, callback, timeoutCallback);
 195+ } );
 196+
 197+ } else {
 198+
 199+ // Do the request an ajax post
 200+ $j.post( url, data, myCallback, 'json');
 201+ }
 202+ return ;
 203+ }
 204+
 205+ // If cross domain setup a callback:
 206+ if( ! mw.isLocalDomain( url ) ) {
 207+ if( url.indexOf( 'callback=' ) == -1 || data[ 'callback' ] == -1 ) {
 208+ // jQuery specific jsonp format: ( second ? is replaced with the callback )
 209+ url += ( url.indexOf('?') == -1 ) ? '?callback=?' : '&callback=?';
 210+ }
 211+ }
 212+ // Pass off the jQuery getJSON request:
 213+ $j.getJSON( url, data, myCallback );
 214+ }
 215+
 216+ /**
 217+ * Checks if a mw request data requires a post request or not
 218+ * @param {Object}
 219+ * @return {Boolean}
 220+ * true if the request requires a post request
 221+ * false if the request does not
 222+ */
 223+ mw.checkRequestPost = function ( data ) {
 224+ if( $j.inArray( data['action'], mw.getConfig( 'apiPostActions' ) ) != -1 ) {
 225+ return true;
 226+ }
 227+ if( data['prop'] == 'info' && data['intoken'] ) {
 228+ return true;
 229+ }
 230+ if( data['meta'] == 'userinfo' ) {
 231+ return true;
 232+ }
 233+ return false;
 234+ }
 235+
 236+ /**
 237+ * Check if the url is a request for the local domain
 238+ * relative paths are "local" domain
 239+ * @param {String} url Url for local domain
 240+ * @return {Boolean}
 241+ * true if url domain is local or relative
 242+ * false if the domain is
 243+ */
 244+ mw.isLocalDomain = function( url ) {
 245+ if( mw.parseUri( document.URL ).host == mw.parseUri( url ).host
 246+ || url.indexOf( '://' ) == -1 )
 247+ {
 248+ return true;
 249+ }
 250+ return false;
 251+ }
 252+
 253+ /**
 254+ * Api helper to grab an edit token
 255+ *
 256+ * @param {String} [apiUrl] Optional target API URL (uses default local api if unset)
 257+ * @param {String} title The wiki page title you want to edit
 258+ * @param {callback} callback Function to pass the token to.
 259+ * issues callback with "false" if token not retrieved
 260+ */
 261+ mw.getToken = function( apiUrl, title, callback ) {
 262+ // Make the apiUrl be optional:
 263+ if( typeof title == 'function' ) {
 264+ callback = title;
 265+ title = apiUrl;
 266+ apiUrl = mw.getLocalApiUrl();
 267+ }
 268+
 269+ mw.log( 'mw:getToken' );
 270+
 271+ var request = {
 272+ 'prop': 'info',
 273+ 'intoken': 'edit',
 274+ 'titles': title
 275+ };
 276+ mw.getJSON( apiUrl, request, function( data ) {
 277+ for ( var i in data.query.pages ) {
 278+ if ( data.query.pages[i]['edittoken'] ) {
 279+ callback ( data.query.pages[i]['edittoken'] );
 280+ return ;
 281+ }
 282+ }
 283+ // No token found:
 284+ callback ( false );
 285+ } );
 286+ }
 287+
 288+ /**
 289+ * Api helper to grab the username
 290+ * @param {String} [apiUrl] Optional target API url (uses default local api if unset)
 291+ * @param {Function} callback Function to callback with username or false if not found
 292+ * @param {Boolean} fresh A fresh check is issued.
 293+ */
 294+ // Stub feature apiUserNameCache to avoid multiple calls
 295+ // ( a more general api framework should be developed )
 296+ var apiUserNameCache = {};
 297+ mw.getUserName = function( apiUrl, callback, fresh ){
 298+ if( typeof apiUrl == 'function' ){
 299+ var callback = apiUrl;
 300+ var apiUrl = mw.getLocalApiUrl();
 301+ }
 302+
 303+ // If apiUrl is local check wgUserName global
 304+ // before issuing the api request.
 305+ if( mw.isLocalDomain( apiUrl ) ){
 306+ if( typeof wgUserName != 'undefined' && wgUserName !== null ) {
 307+ callback( wgUserName )
 308+ // In case someone called this function without a callback
 309+ return wgUserName;
 310+ }
 311+ }
 312+ if( ! fresh && apiUserNameCache[ apiUrl ] ) {
 313+ callback( apiUserNameCache[ apiUrl ] );
 314+ return ;
 315+ }
 316+
 317+ // Setup the api request
 318+ var request = {
 319+ 'action':'query',
 320+ 'meta':'userinfo'
 321+ }
 322+
 323+ // Do request
 324+ mw.getJSON( apiUrl, request, function( data ) {
 325+ if( !data || !data.query || !data.query.userinfo || !data.query.userinfo.name ){
 326+ // Could not get user name user is not-logged in
 327+ mw.log( " No userName in response " );
 328+ callback( false );
 329+ return ;
 330+ }
 331+ // Check for "not logged in" id == 0
 332+ if( data.query.userinfo.id == 0 ){
 333+ callback( false );
 334+ return ;
 335+ }
 336+ apiUserNameCache[ apiUrl ] = data.query.userinfo.name;
 337+ // Else return the username:
 338+ callback( data.query.userinfo.name );
 339+ }, function(){
 340+ // Timeout also results in callback( false ) ( no user found)
 341+ callback( false );
 342+ } );
 343+ }
 344+
 345+ /**
 346+ * Get the api url for a given content provider key
 347+ * @return {Mixed}
 348+ * url for the provider
 349+ * local wiki api if no apiProvider is set
 350+ */
 351+ mw.getApiProviderURL = function( providerId ) {
 352+ if( mw.getConfig( providerId + '_apiurl') ) {
 353+ return mw.getConfig( providerId + '_apiurl');
 354+ }
 355+ return mw.getLocalApiUrl();
 356+ };
 357+
 358+ /**
 359+ * Get Api URL from mediaWiki page defined variables
 360+ * @return {Mixed}
 361+ * api url
 362+ * false
 363+ */
 364+ mw.getLocalApiUrl = function() {
 365+ if ( typeof wgServer != 'undefined' && typeof wgScriptPath != 'undefined' ) {
 366+ return wgServer + wgScriptPath + '/api.php';
 367+ }
 368+ return false;
 369+ };
 370+
 371+}) ( window.mw );
\ No newline at end of file
Property changes on: trunk/extensions/MwEmbed/MwEmbed/modules/ApiEmbed/mw.Api.js
___________________________________________________________________
Added: svn:mime-type
1372 + text/plain
Added: svn:executable
2373 + *
Index: trunk/extensions/MwEmbed/MwEmbed/modules/README
@@ -0,0 +1,2 @@
 2+If an mwEmbed module is used by Two or more sub components the module could be moved into this mwEmbed support extension
 3+
Index: trunk/extensions/MwEmbed/MwEmbed/mwEmbed.old.js
@@ -0,0 +1,2653 @@
 2+// Add support for html5 / mwEmbed elements to browsers that do not support the elements natively
 3+// For discussion and comments, see: http://ejohn.org/blog/html5-shiv/
 4+'video audio source track'.replace(/\w+/g, function(n){ document.createElement(n); });
 5+
 6+/**
 7+ * @license
 8+ * mwEmbed
 9+ * Dual licensed under the MIT or GPL Version 2 licenses.
 10+ *
 11+ * @copyright (C) 2010 Kaltura
 12+ * @author Michael Dale ( michael.dale at kaltura.com )
 13+ *
 14+ * @url http://www.kaltura.org/project/HTML5_Video_Media_JavaScript_Library
 15+ *
 16+ * Libraries used include code license in headers
 17+ */
 18+
 19+/**
 20+ * Setup the "mw" global:
 21+ */
 22+if ( typeof window.mw == 'undefined' ) {
 23+ window.mw = { };
 24+}
 25+
 26+/**
 27+ * Set the mwEmbedVersion
 28+ */
 29+var MW_EMBED_VERSION = '1.1h';
 30+
 31+// Globals to pre-set ready functions in dynamic loading of mwEmbed
 32+if( typeof preMwEmbedReady == 'undefined'){
 33+ var preMwEmbedReady = [];
 34+}
 35+// Globals to pre-set config values in dynamic loading of mwEmbed
 36+if( typeof preMwEmbedConfig == 'undefined') {
 37+ var preMwEmbedConfig = [];
 38+}
 39+
 40+/**
 41+ * The global mw object:
 42+ */
 43+( function( mw ) {
 44+ // The version of mwEmbed
 45+ mw.version = MW_EMBED_VERSION;
 46+
 47+ // List valid skins here:
 48+ mw.validSkins = [ 'mvpcf', 'kskin' ];
 49+
 50+ // Storage variable for loaded style sheet keys
 51+ if( ! mw.style ){
 52+ mw.style = { };
 53+ }
 54+
 55+ /**
 56+ * Configuration System:
 57+ */
 58+
 59+ // Local scope configuration var:
 60+ if( !mwConfig ){
 61+ var mwConfig = { };
 62+ }
 63+
 64+ // mw scope mwUserConfig var. Stores user configuration
 65+ var mwUserConfig = { };
 66+
 67+ /**
 68+ * Setter for configuration values
 69+ *
 70+ * @param [Mixed]
 71+ * name Name of configuration value {Object} Will iderate through
 72+ * each key and call setConfig {String} Will set configuration by
 73+ * string name to value
 74+ * @param {String}
 75+ * value Value of configuration name {Object} value Set of values
 76+ * to be merged
 77+ */
 78+ mw.setConfig = function ( name, value ) {
 79+ if( typeof name == 'object' ) {
 80+ for( var i in name ) {
 81+ mw.setConfig( i, name[ i ] );
 82+ }
 83+ return ;
 84+ }
 85+ // Check if we should "merge" the config
 86+ if( typeof value == 'object' && typeof mwConfig[ name ] == 'object' ) {
 87+ if ( value.constructor.toString().indexOf("Array") == -1 ){
 88+ for( var i in value ){
 89+ mwConfig[ name ][ i ] = value[ i ];
 90+ }
 91+ } else {
 92+ // merge in the array
 93+ mwConfig[ name ] = mwConfig[ name ].concat( value );
 94+ }
 95+ } else {
 96+ mwConfig[ name ] = value;
 97+ }
 98+ };
 99+
 100+ /**
 101+ * Set a default config value Will only update configuration if no value is
 102+ * present
 103+ *
 104+ * @param [Mixed]
 105+ * value Set configuration name to value {Object} Will iderate
 106+ * through each key and call setDefaultConfig {String} Will set
 107+ * configuration by string name to value
 108+ */
 109+ mw.setDefaultConfig = function( name, value ) {
 110+ if( typeof name == 'object' ) {
 111+ for( var i in name ) {
 112+ mw.setDefaultConfig( i, name[ i ] );
 113+ }
 114+ return ;
 115+ }
 116+ // Only update the controls if undefined
 117+
 118+ if( typeof mwConfig[ name ] == 'undefined' ) {
 119+ mwConfig[ name ] = value;
 120+ return ;
 121+ }
 122+ // Check if we should "merge" the config
 123+ if( typeof value == 'object' && typeof mwConfig[ name ] == 'object' ) {
 124+ if ( value.constructor.toString().indexOf("Array") == -1 ){
 125+ for( var i in value ){
 126+ if( typeof mwConfig[ name ][ i ] == 'undefined' ){
 127+ mwConfig[ name ][ i ] = value[ i ];
 128+ }
 129+ }
 130+ } else {
 131+ // merge in the array
 132+ mwConfig[ name ] = mwConfig[ name ].concat( value);
 133+ }
 134+ }
 135+ };
 136+
 137+ /**
 138+ * Getter for configuration values
 139+ *
 140+ * @param {String}
 141+ * name of configuration value to get
 142+ * @return {Mixed} value of configuration key returns "false" if key not
 143+ * found
 144+ */
 145+ mw.getConfig = function ( name ) {
 146+ if( mwConfig[ name ] )
 147+ return mwConfig[ name ];
 148+ return false;
 149+ };
 150+
 151+ /**
 152+ * Loads the mwUserConfig from a cookie.
 153+ *
 154+ * Modules that want to use "User Config" should call this setup function in
 155+ * their moduleLoader code.
 156+ *
 157+ * For performance interfaces using "user config" should load '$j.cookie' &
 158+ * 'JSON' in their module loader
 159+ *
 160+ * By abstracting user preference we could eventually integrate a persistent
 161+ * per-account preference system on the server.
 162+ *
 163+ * @parma {Function} callback Function to be called once userPrefrences are
 164+ * loaded
 165+ */
 166+ var setupUserConfigFlag = false;
 167+ mw.setupUserConfig = function( callback ) {
 168+ if( setupUserConfigFlag ) {
 169+ if( callback ) {
 170+ callback();
 171+ }
 172+ return ;
 173+ }
 174+ // Do Setup user config:
 175+ mw.load( [ '$j.cookie', 'JSON' ], function() {
 176+ if( $j.cookie( 'mwUserConfig' ) ) {
 177+ mwUserConfig = JSON.parse( $j.cookie( 'mwUserConfig' ) );
 178+ }
 179+ setupUserConfigFlag = true;
 180+ if( callback ) {
 181+ callback();
 182+ }
 183+ });
 184+ };
 185+
 186+ /**
 187+ * Save a user configuration var to a cookie & local global variable Loads
 188+ * the cookie plugin if not already loaded
 189+ *
 190+ * @param {String}
 191+ * name Name of user configuration value
 192+ * @param {String}
 193+ * value Value of configuration name
 194+ */
 195+ mw.setUserConfig = function ( name, value, cookieOptions ) {
 196+ if( ! setupUserConfigFlag ) {
 197+ mw.log( "Error: userConfig not setup" );
 198+ return false;
 199+ }
 200+ // Update local value
 201+ mwUserConfig[ name ] = value;
 202+
 203+ // Update the cookie ( '$j.cookie' & 'JSON' should already be loaded )
 204+ $j.cookie( 'mwUserConfig', JSON.stringify( mwUserConfig ) );
 205+ };
 206+
 207+ /**
 208+ * Save a user configuration var to a cookie & local global variable
 209+ *
 210+ * @param {String}
 211+ * name Name of user configuration value
 212+ * @return value of the configuration name false if the configuration name
 213+ * could not be found
 214+ */
 215+ mw.getUserConfig = function ( name ) {
 216+ if( mwUserConfig[ name ] )
 217+ return mwUserConfig[ name ];
 218+ return false;
 219+ };
 220+
 221+ /**
 222+ * Add a hook system for a target object / interface
 223+ *
 224+ * depricated you should instead use jQuery's bind and trigger
 225+ *
 226+ * @param {Object}
 227+ * targetObj Interface Object to add hook system to.
 228+ */
 229+ mw.addHookSystem = function( targetObj ) {
 230+
 231+ // Setup the target object hook holder:
 232+ targetObj[ 'hooks' ] = { };
 233+
 234+ /**
 235+ * Adds a hook to the target object
 236+ *
 237+ * Should be called by clients to setup named hooks
 238+ *
 239+ * @param {String}
 240+ * hookName Name of hook to be added
 241+ * @param {Function}
 242+ * hookFunction Function to be called at hook time
 243+ */
 244+ targetObj.addHook = function( hookName, hookFunction ) {
 245+ if( ! this.hooks[ hookName ] ) {
 246+ this.hooks[ hookName ] = [ ];
 247+ }
 248+ this.hooks[ hookName ].push( hookFunction );
 249+ };
 250+
 251+ /**
 252+ * Runs all the hooks by a given name with reference to the host object
 253+ *
 254+ * Should be called by the host object at named execution points
 255+ *
 256+ * @param {String}
 257+ * hookName Name of hook to be called
 258+ * @return Value of hook result true interface should continue function
 259+ * execution false interface should stop or return from method
 260+ */
 261+ targetObj.runHook = function( hookName, options ) {
 262+ if( this.hooks[ hookName ] ) {
 263+ for( var i =0; i < this.hooks[ hookName ].length; i ++ ) {
 264+ if( typeof( this.hooks[ hookName ][ i ] ) == 'function' ) {
 265+ this.hooks[ hookName ][ i ]( options );
 266+ }
 267+ }
 268+ }
 269+ };
 270+ };
 271+
 272+ // Add hooks system to the core "mw" object
 273+ mw.addHookSystem( mw );
 274+
 275+ // Stores callbacks for resource loader loading
 276+ var mwLoadDoneCB = { };
 277+
 278+
 279+ /**
 280+ * Top level loader prototype:
 281+ */
 282+ mw.loader = {
 283+ /**
 284+ * Javascript Module Loader functions
 285+ *
 286+ * @key Name of Module
 287+ * @value function code to load module
 288+ */
 289+ moduleLoaders : [],
 290+
 291+ /**
 292+ * Module resource list queue.
 293+ *
 294+ * @key Name of Module
 295+ * @value .resourceList list of resources to be loaded .functionQueue
 296+ * list of functions to be run once module is ready
 297+ */
 298+ moduleLoadQueue: { },
 299+
 300+ /**
 301+ * Javascript Class Paths
 302+ *
 303+ * @key Name of resource
 304+ * @value Class file path
 305+ */
 306+ resourcePaths : { },
 307+
 308+ /**
 309+ * Stores resources that have been requested ( to avoid re-requesting the same resources )
 310+ * in concurrent requests )
 311+ */
 312+ requestedResourceQueue: { },
 313+
 314+ /**
 315+ * javascript Resource Paths
 316+ *
 317+ * @key Name of resource
 318+ * @value Name of depenent style sheet
 319+ */
 320+ resourceStyleDependency: { },
 321+
 322+ /**
 323+ * Core load function:
 324+ *
 325+ * @param {Mixed}
 326+ * loadRequest:
 327+ *
 328+ * {String} Name of a module to be loaded Modules are added via
 329+ * addModuleLoader and can define custom code needed to check config and
 330+ * return a list of resources to be loaded
 331+ *
 332+ * {String} Name of a resource to loaded. Resources are added via
 333+ * addResourcePaths function Using defined resource names avoids loading
 334+ * the same resource twice by first checking if the named resource is
 335+ * defined in the global javascript scope variable
 336+ *
 337+ * {String} Absolute or relative to url path The same file won't be
 338+ * loaded twice
 339+ *
 340+ * {Array} can be an array of any combination of the above strings. Will
 341+ * be loaded in-order or in a single resource loader request if
 342+ * scriptLoader is available.
 343+ *
 344+ * {Array} {Array} Can be a set of Arrays for loading. Some browsers
 345+ * execute included scripts out of order. This lets you chain sets of
 346+ * request for those browsers. If using the server side resource loader
 347+ * order is preserved in output and a single request will be used.
 348+ *
 349+ * @param {Function}
 350+ * callback Function called once loading is complete
 351+ *
 352+ */
 353+ load: function( loadRequest, instanceCallback ) {
 354+ // mw.log("mw.load:: " + loadRequest );
 355+ var _this = this;
 356+
 357+ // Throw out any loadRequests that are not strings
 358+ loadRequest = this.cleanLoadRequest( loadRequest );
 359+
 360+ // Ensure the callback is only called once per load instance
 361+ var callback = function(){
 362+ // mw.log( 'instanceCallback::running callback: ' +
 363+ // instanceCallback );
 364+ if( instanceCallback ){
 365+ // We pass the loadRequest back to the callback for easy
 366+ // debugging of concurrency issues.
 367+ // ( normally its not used )
 368+ instanceCallback( loadRequest );
 369+ instanceCallback = null;
 370+ }
 371+ };
 372+
 373+ // Check for empty loadRequest ( directly return the callback )
 374+ if( mw.isEmpty( loadRequest ) ) {
 375+ mw.log( 'Empty load request: ( ' + loadRequest + ' ) ' );
 376+ callback( loadRequest );
 377+ return ;
 378+ }
 379+
 380+
 381+ // Check if its a multi-part request:
 382+ if( typeof loadRequest == 'object' ) {
 383+ if( loadRequest.length > 1 ) {
 384+ this.loadMany ( loadRequest, callback );
 385+ return ;
 386+ }else{
 387+ // If an array of length 1 set as first element
 388+ loadRequest = loadRequest[0];
 389+ }
 390+ }
 391+
 392+ // Check for the module name loader function
 393+ if( this.moduleLoaders[ loadRequest ] ) {
 394+ var resourceSet = this.getModuleResourceSet( loadRequest );
 395+ if( !resourceSet ){
 396+ mw.log( "mw.load:: Error with module loader: " + loadRequest + ' ( no resource set defined )' );
 397+ return ;
 398+ }
 399+
 400+ // xxx should use refactor "ready" stuff into a "domReady" class
 401+ // So we would not have local scope globals like this:
 402+ if ( mwReadyFlag ) {
 403+ // Load the module directly if load request is after
 404+ // mw.ready has run
 405+ this.load( resourceSet, callback );
 406+ } else {
 407+ this.addToModuleLoaderQueue(
 408+ loadRequest,
 409+ resourceSet,
 410+ callback
 411+ );
 412+ }
 413+ return ;
 414+ }
 415+
 416+ // Check for javascript resource
 417+ if( this.getResourcePath( loadRequest ) ) {
 418+ this.loadResource( loadRequest, callback );
 419+ return ;
 420+ }
 421+
 422+ // Try loading as a "file" or via ScriptLoader
 423+ if( loadRequest ) {
 424+ // Check if this resource was already requested
 425+ if( typeof this.requestedResourceQueue[ loadRequest ] == 'object' ){
 426+ this.requestedResourceQueue[ loadRequest ].push( callback );
 427+ return ;
 428+ } else {
 429+ this.requestedResourceQueue[ loadRequest ] = [];
 430+ }
 431+
 432+ if( loadRequest.indexOf( '.js' ) == -1 && !mw.getResourceLoaderPath() ) {
 433+ mw.log( 'Error: are you sure ' + loadRequest + ' is a file ( is it missing a resource path? ) ' );
 434+ }
 435+ mw.getScript( loadRequest, function(){
 436+ // Check if we have requestedResources queue items:
 437+ while( _this.requestedResourceQueue[ loadRequest ].length ){
 438+ _this.requestedResourceQueue[ loadRequest ].shift()( loadRequest );
 439+ }
 440+ callback( loadRequest );
 441+ // empty the load request queue:
 442+ _this.requestedResourceQueue[ loadRequest ] = [];
 443+ });
 444+ return ;
 445+ }
 446+
 447+ // Possible error?
 448+ mw.log( "Error could not handle load request: " + loadRequest );
 449+ },
 450+
 451+ getModuleResourceSet: function( moduleName ){
 452+ // Check if the module loader is a function ~run that function~
 453+ if( typeof ( this.moduleLoaders[ moduleName ] ) == 'function' ) {
 454+ // Add the result of the module loader function
 455+ return this.moduleLoaders[ moduleName ]();
 456+ } else if( typeof ( this.moduleLoaders[ moduleName ] ) == 'object' ){
 457+ // set resourceSet directly
 458+ return this.moduleLoaders[ moduleName ];
 459+ }
 460+ return false;
 461+ },
 462+
 463+ /**
 464+ * Clean the loadRequest ( throw out any non-string items )
 465+ */
 466+ cleanLoadRequest: function( loadRequest ){
 467+ var cleanRequest = [];
 468+ if( typeof loadRequest == 'string' )
 469+ return loadRequest;
 470+ for( var i =0;i < loadRequest.length; i++ ){
 471+ if( typeof loadRequest[i] == 'object' ) {
 472+ cleanRequest[i] = this.cleanLoadRequest( loadRequest[i] );
 473+ } else if( typeof loadRequest[i] == 'string' ){
 474+ cleanRequest[i] = $j.trim( loadRequest[i] );
 475+ } else{
 476+ // bad request type skip
 477+ }
 478+ }
 479+ return cleanRequest;
 480+ },
 481+ /**
 482+ * Load a set of scripts. Will issue many load requests or package the
 483+ * request for the resource loader
 484+ *
 485+ * @param {Object}
 486+ * loadSet Set of scripts to be loaded
 487+ * @param {Function}
 488+ * callback Function to call once all scripts are loaded.
 489+ */
 490+ loadMany: function( loadSet, callback ) {
 491+ var _this = this;
 492+ // Setup up the local "loadStates"
 493+ var loadStates = { };
 494+
 495+ // Check if we can load via the "resource loader" ( mwEmbed was
 496+ // included via scriptLoader )
 497+ if( mw.getResourceLoaderPath() ) {
 498+ // Get the grouped loadStates variable
 499+ loadStates = this.getGroupLoadState( loadSet );
 500+ if( mw.isEmpty( loadStates ) ) {
 501+ // mw.log( 'loadMany:all resources already loaded');
 502+ callback();
 503+ return ;
 504+ }
 505+ }else{
 506+ // Check if its a dependency set ( nested objects )
 507+ if( typeof loadSet [ 0 ] == 'object' ) {
 508+ _this.dependencyChainCallFlag[ loadSet ] = false;
 509+ // Load sets of resources ( to preserver order for some
 510+ // browsers )
 511+ _this.loadDependencyChain( loadSet, callback );
 512+ return ;
 513+ }
 514+
 515+ // Set the initial load state for every item in the loadSet
 516+ for( var i = 0; i < loadSet.length ; i++ ) {
 517+ var loadName = loadSet[ i ];
 518+ loadStates[ loadName ] = 0;
 519+ }
 520+ }
 521+
 522+ // We are infact loading many:
 523+ //mw.log("mw.load: LoadMany:: " + loadSet );
 524+
 525+ // Issue the load request check check loadStates to see if we are
 526+ // "done"
 527+ for( var loadName in loadStates ) {
 528+ //mw.log("loadMany: load: " + loadName );
 529+ this.load( loadName, function ( loadName ) {
 530+ loadStates[ loadName ] = 1;
 531+
 532+ /*
 533+ * for( var i in loadStates ) { mw.log( loadName + '
 534+ * finished of: ' + i + ' : ' + loadStates[i] ); }
 535+ */
 536+
 537+ // Check if all load request states are set 1
 538+ var loadDone = true;
 539+ for( var j in loadStates ) {
 540+ if( loadStates[ j ] === 0 )
 541+ loadDone = false;
 542+ }
 543+ // Run the parent scope callback for "loadMany"
 544+ if( loadDone ) {
 545+ callback( loadName );
 546+ }
 547+ } );
 548+ }
 549+ },
 550+
 551+ /**
 552+ * Get grouped load state for script loader
 553+ *
 554+ * Groups the scriptRequest where possible: Modules include "loader
 555+ * code" so they are separated into pre-condition code to be run for
 556+ * subsequent requests
 557+ *
 558+ * @param {Object}
 559+ * loadSet Loadset to return grouped
 560+ * @return {Object} grouped loadSet
 561+ */
 562+ getGroupLoadState: function( loadSet ) {
 563+ var groupedLoadSet = [];
 564+ var loadStates = { };
 565+ // Merge load set into new groupedLoadSet
 566+ if( typeof loadSet[0] == 'object' ) {
 567+ for( var i = 0; i < loadSet.length ; i++ ) {
 568+ for( var j = 0; j < loadSet[i].length ; j++ ) {
 569+ // Make sure we have not already included it:
 570+ groupedLoadSet.push( loadSet[i][j] );
 571+ }
 572+ }
 573+ } else {
 574+ // Use the loadSet directly:
 575+ groupedLoadSet = loadSet;
 576+ }
 577+
 578+ // Setup grouped loadStates Set:
 579+ var groupClassKey = '';
 580+ var coma = '';
 581+ var uniqueResourceName = {};
 582+ for( var i=0; i < groupedLoadSet.length; i++ ) {
 583+ var loadName = groupedLoadSet[ i ];
 584+ if( this.getResourcePath( loadName ) ) {
 585+ // Check if not already in request queue and not defined in global namespace
 586+ if( !mw.isset( loadName ) && ! uniqueResourceName[ loadName] ){
 587+ groupClassKey += coma + loadName;
 588+ coma = ',';
 589+
 590+ // Check for style sheet dependencies
 591+ if( this.resourceStyleDependency[ loadName ] ){
 592+ groupClassKey += coma + this.resourceStyleDependency[ loadName ];
 593+ }
 594+ }
 595+ } else if ( this.moduleLoaders[ loadName ] ) {
 596+
 597+ // Module loaders break up grouped script requests ( add the
 598+ // current groupClassKey )
 599+ if( groupClassKey != '' ) {
 600+ loadStates[ groupClassKey ] = 0;
 601+ groupClassKey = coma = '';
 602+ }
 603+ if( ! uniqueResourceName[ loadName] ){
 604+ // Add the module to the loadSate
 605+ loadStates[ loadName ] = 0;
 606+ }
 607+ }
 608+ uniqueResourceName[ loadName] = true;
 609+ }
 610+
 611+ // Add groupClassKey if set:
 612+ if( groupClassKey != '' ) {
 613+ loadStates [ groupClassKey ] = 0;
 614+ }
 615+
 616+ return loadStates;
 617+ },
 618+
 619+ // Array to register that a callback has been called
 620+ dependencyChainCallFlag: { },
 621+
 622+ /**
 623+ * Load a sets of scripts satisfy dependency order for browsers that
 624+ * execute dynamically included scripts out of order
 625+ *
 626+ * @param {Object}
 627+ * loadChain A set of javascript arrays to be loaded. Sets
 628+ * are requested in array order.
 629+ */
 630+ loadDependencyChain: function( loadChain, callback ) {
 631+ var _this = this;
 632+ // Load with dependency checks
 633+ var callSet = loadChain.shift();
 634+ this.load( callSet, function( cbname ) {
 635+ if ( loadChain.length != 0 ) {
 636+ _this.loadDependencyChain( loadChain, callback );
 637+ } else {
 638+ // NOTE: IE gets called twice so we have check the
 639+ // dependencyChainCallFlag before calling the callback
 640+ if( _this.dependencyChainCallFlag[ callSet ] == callback ) {
 641+ mw.log("... already called this callback for " + callSet );
 642+ return ;
 643+ }
 644+ _this.dependencyChainCallFlag[ callSet ] = callback;
 645+ callback( );
 646+ }
 647+ } );
 648+ },
 649+
 650+ /**
 651+ * Add to the module loader queue
 652+ */
 653+ addToModuleLoaderQueue: function( moduleName, resourceSet, callback ) {
 654+ mw.log(" addToModuleLoaderQueue:: " + moduleName + ' resourceSet: ' + resourceSet );
 655+ if( this.moduleLoadQueue[ moduleName ] ){
 656+ // If the module is already in the queue just add its callback:
 657+ this.moduleLoadQueue[ moduleName ].functionQueue.push( callback );
 658+ } else {
 659+ // create the moduleLoadQueue item
 660+ this.moduleLoadQueue[ moduleName ] = {
 661+ 'resourceSet' : resourceSet,
 662+ 'functionQueue' : [ callback ],
 663+ 'loaded' : false
 664+ };
 665+ }
 666+ },
 667+
 668+ /**
 669+ * Loops over all modules in queue, builds request sets based on config
 670+ * request type
 671+ */
 672+ runModuleLoadQueue: function(){
 673+ var _this = this;
 674+ mw.log( "mw.runModuleLoadQueue:: " );
 675+ var runModuleFunctionQueue = function(){
 676+ // Run all the callbacks
 677+ for( var moduleName in _this.moduleLoadQueue ){
 678+ while( _this.moduleLoadQueue[moduleName].functionQueue.length ) {
 679+ _this.moduleLoadQueue[moduleName].functionQueue.shift()();
 680+ }
 681+ }
 682+ };
 683+
 684+ // Check for single request or javascript debug based loading:
 685+ if( !mw.getResourceLoaderPath() || mw.getConfig( 'loader.groupStrategy' ) == 'single' ){
 686+ // if not using the resource load just do a normal array merge
 687+ // ( for browsers like IE that don't follow first append first
 688+ // execute rule )
 689+ var fullResourceList = [];
 690+ for( var moduleName in this.moduleLoadQueue ) {
 691+ var resourceSet = this.moduleLoadQueue[ moduleName ].resourceSet;
 692+ // Lets try a global merge
 693+ fullResourceList = $j.merge( fullResourceList, resourceSet );
 694+ }
 695+ mw.load( fullResourceList, function(){
 696+ runModuleFunctionQueue();
 697+ });
 698+ return ;
 699+ }
 700+
 701+ // Else do per module group loading
 702+ if( mw.getConfig( 'loader.groupStrategy' ) == 'module' ) {
 703+ var fullResourceList = [];
 704+ var sharedResourceList = [];
 705+
 706+ for( var moduleName in this.moduleLoadQueue ) {
 707+ // Build a shared dependencies list and load that separately
 708+ // "first"
 709+ // ( in IE we have to wait until its "ready" since it does
 710+ // not follow dom order )
 711+ var moduleResourceList = this.getFlatModuleResourceList( moduleName );
 712+ // Build the sharedResourceList
 713+ for( var i=0; i < moduleResourceList.length; i++ ){
 714+ var moduleResource = moduleResourceList[i];
 715+ // Check if already in the full resource list if so add
 716+ // to shared.
 717+ if( fullResourceList[ moduleResource ] ){
 718+ if( $j.inArray( moduleResource, sharedResourceList ) == -1 ){
 719+ sharedResourceList.push( moduleResource );
 720+ }
 721+ }
 722+ // Add to the fullResourceList
 723+ fullResourceList[ moduleResource ] = true;
 724+ }
 725+ }
 726+
 727+ // Local module request set ( stores the actual request we will
 728+ // make after grouping shared resources
 729+ var moduleRequestSet = {};
 730+
 731+ // Only add non-shared to respective modules load requests
 732+ for( var moduleName in this.moduleLoadQueue ) {
 733+ moduleRequestSet[ moduleName ] = [];
 734+ var moduleResourceList = this.getFlatModuleResourceList( moduleName );
 735+ for( var i =0; i < moduleResourceList.length; i++ ){
 736+ var moduleResource = moduleResourceList[i];
 737+ if( $j.inArray( moduleResource, sharedResourceList ) == -1 ){
 738+ moduleRequestSet[ moduleName ].push( moduleResource );
 739+ }
 740+ }
 741+ }
 742+ var sharedResourceLoadDone = false;
 743+ // Check if modules are done
 744+ var checkModulesDone = function(){
 745+ if( !sharedResourceLoadDone ){
 746+ return false;
 747+ }
 748+ for( var moduleName in _this.moduleLoadQueue ) {
 749+ if( ! _this.moduleLoadQueue[ moduleName ].loaded ){
 750+ return false;
 751+ }
 752+ }
 753+ runModuleFunctionQueue();
 754+ };
 755+ // Local instance of load requests to retain resourceSet
 756+ // context:
 757+ var localLoadCallInstance = function( moduleName, resourceSet ){
 758+ mw.load( resourceSet, function(){
 759+ _this.moduleLoadQueue[ moduleName ].loaded = true;
 760+ checkModulesDone();
 761+ });
 762+ };
 763+
 764+ // Load the shared resources
 765+ mw.load( sharedResourceList, function(){
 766+ // mw.log("Shared Resources loaded");
 767+ // xxx check if we are in "IE" and dependencies need to be
 768+ // loaded "first"
 769+ sharedResourceLoadDone = true;
 770+ checkModulesDone();
 771+ });
 772+ // Load all module Request Set
 773+ for( var moduleName in moduleRequestSet ){
 774+ localLoadCallInstance( moduleName, moduleRequestSet[ moduleName ] );
 775+ }
 776+ }
 777+ // xxx Here we could also do some "intelligent" grouping
 778+ },
 779+
 780+ getFlatModuleResourceList: function( moduleName ){
 781+ var moduleList = [];
 782+ for( var j in this.moduleLoadQueue[moduleName].resourceSet ){
 783+ // Check if we have a multi-set array:
 784+ if( typeof this.moduleLoadQueue[moduleName].resourceSet[j] == 'object' ){
 785+ moduleList = $j.merge( moduleList, this.moduleLoadQueue[moduleName].resourceSet[j] );
 786+ } else {
 787+ moduleList = $j.merge( moduleList, [ this.moduleLoadQueue[moduleName].resourceSet[j] ] );
 788+ }
 789+ }
 790+ return moduleList;
 791+ },
 792+ /**
 793+ * Loads javascript or css associated with a resourceName
 794+ *
 795+ * @param {String}
 796+ * resourceName Name of resource to load
 797+ * @param {Function}
 798+ * callback Function to run once resource is loaded
 799+ */
 800+ loadResource: function( resourceName , callback) {
 801+ // mw.log("LoadResource:" + resourceName );
 802+ var _this = this;
 803+
 804+ // Check for css dependency on resource name
 805+ if( this.resourceStyleDependency[ resourceName ] ) {
 806+ if( ! mw.isset( this.resourceStyleDependency[ resourceName ] )){
 807+ mw.log("loadResource:: dependent css resource: " + this.resourceStyleDependency[ resourceName ] );
 808+ _this.loadResource( this.resourceStyleDependency[ resourceName ] , function() {
 809+ // Continue the original loadResource request.
 810+ _this.loadResource( resourceName, callback );
 811+ });
 812+ return ;
 813+ }
 814+ }
 815+
 816+ // Make sure the resource is not already defined:
 817+ if ( mw.isset( resourceName ) ) {
 818+ // mw.log( 'Class ( ' + resourceName + ' ) already defined ' );
 819+ callback( resourceName );
 820+ return ;
 821+ }
 822+
 823+ // Setup the Script Request var:
 824+ var scriptRequest = null;
 825+
 826+
 827+ // If the scriptloader is enabled use the resourceName as the
 828+ // scriptRequest:
 829+ if( mw.getResourceLoaderPath() ) {
 830+ scriptRequest = resourceName;
 831+ }else{
 832+ // Get the resource url:
 833+ var baseClassPath = this.getResourcePath( resourceName );
 834+ // Add the mwEmbed path if not a root path or a full url
 835+ if( baseClassPath.indexOf( '/' ) !== 0 &&
 836+ baseClassPath.indexOf( '://' ) === -1 ) {
 837+ scriptRequest = mw.getMwEmbedPath() + baseClassPath;
 838+ }else{
 839+ scriptRequest = baseClassPath;
 840+ }
 841+ if( ! scriptRequest ) {
 842+ mw.log( "Error Could not get url for resource " + resourceName );
 843+ return false;
 844+ }
 845+ }
 846+ // Include resource defined check for older browsers
 847+ var resourceDone = false;
 848+
 849+ // Set the loadDone callback per the provided resourceName
 850+ mw.setLoadDoneCB( resourceName, callback );
 851+ // Issue the request to load the resource (include resource name in
 852+ // result callback:
 853+ mw.getScript( scriptRequest, function( scriptRequest ) {
 854+ // If its a "style sheet" manually set its resource to true
 855+ var ext = scriptRequest.substr( scriptRequest.split('?')[0].lastIndexOf( '.' ), 4 ).toLowerCase();
 856+ if( ext == '.css' && resourceName.substr(0,8) == 'mw.style' ){
 857+ mw.style[ resourceName.substr( 9 ) ] = true;
 858+ }
 859+
 860+ // Send warning if resourceName is not defined
 861+ if(! mw.isset( resourceName )
 862+ && mwLoadDoneCB[ resourceName ] != 'done' ) {
 863+ mw.log( 'Possible Error: ' + resourceName +' not set in time, or not defined in:' + "\n"
 864+ + _this.getResourcePath( resourceName ) );
 865+ }
 866+
 867+ // If ( debug mode ) and the script include is missing resource
 868+ // messages
 869+ // do a separate request to retrieve the msgs
 870+ if( mw.currentClassMissingMessages ) {
 871+ mw.log( " resourceName " + resourceName + " is missing messages" );
 872+ // Reset the currentClassMissingMessages flag
 873+ mw.currentClassMissingMessages = false;
 874+
 875+ // Load msgs for this resource:
 876+ mw.loadResourceMessages( resourceName, function() {
 877+ // Run the onDone callback
 878+ mw.loadDone( resourceName );
 879+ } );
 880+ } else {
 881+ // If not using the resource loader make sure the
 882+ // resourceName is available before firing the loadDone
 883+ if( !mw.getResourceLoaderPath() ) {
 884+ mw.waitForObject( resourceName, function( resourceName ) {
 885+ // Once object is ready run loadDone
 886+ mw.loadDone( resourceName );
 887+ } );
 888+ } else {
 889+ // loadDone should be appended to the bottom of the
 890+ // resource loader response
 891+ // mw.loadDone( resourceName );
 892+ }
 893+ }
 894+ } );
 895+ },
 896+
 897+ /**
 898+ * Adds a module to the mwLoader object
 899+ *
 900+ * @param {String}
 901+ * name Name of module
 902+ * @param {Function}
 903+ * moduleLoader Function that loads dependencies for a module
 904+ */
 905+ addModuleLoader: function( name, moduleLoader ) {
 906+ this.moduleLoaders [ name ] = moduleLoader;
 907+ },
 908+
 909+ /**
 910+ * Adds resource file path key value pairs
 911+ *
 912+ * @param {Object}
 913+ * resourceSet JSON formated list of resource name file path
 914+ * pairs.
 915+ *
 916+ * resourceSet must be strict JSON to allow the php scriptLoader to
 917+ * parse the file paths.
 918+ */
 919+ addResourcePaths: function( resourceSet ) {
 920+ var prefix = ( mw.getConfig( 'loaderContext' ) )?
 921+ mw.getConfig( 'loaderContext' ): '';
 922+
 923+ for( var i in resourceSet ) {
 924+ this.resourcePaths[ i ] = prefix + resourceSet[ i ];
 925+ }
 926+ },
 927+
 928+ /*
 929+ * Adds a named style sheet dependency to a named resource
 930+ *
 931+ * @parma {Object} resourceSet JSON formated list of resource names and
 932+ * associated style sheet names
 933+ */
 934+ addStyleResourceDependency: function( resourceSet ){
 935+ for( var i in resourceSet ){
 936+ this.resourceStyleDependency[ i ] = resourceSet[i];
 937+ }
 938+ },
 939+
 940+ /**
 941+ * Get a resource path from a resourceName if no resource found return
 942+ * false
 943+ */
 944+ getResourcePath: function( resourceName ) {
 945+ if( this.resourcePaths[ resourceName ] )
 946+ return this.resourcePaths[ resourceName ];
 947+ return false;
 948+ }
 949+ };
 950+
 951+ /**
 952+ * Load done callback for script loader
 953+ *
 954+ * @param {String}
 955+ * requestName Name of the load request
 956+ */
 957+ mw.loadDone = function( requestName ) {
 958+ if( !mwLoadDoneCB[ requestName ] ) {
 959+ return true;
 960+ }
 961+ while( mwLoadDoneCB[ requestName ].length ) {
 962+ // check if mwLoadDoneCB is already "done"
 963+ // the function list is not an object
 964+ if( typeof mwLoadDoneCB[ requestName ] != 'object' )
 965+ {
 966+ break;
 967+ }
 968+ var func = mwLoadDoneCB[ requestName ].pop();
 969+ if( typeof func == 'function' ) {
 970+ // mw.log( "LoadDone: " + requestName + ' run callback::' +
 971+ // func);
 972+ func( requestName );
 973+ }else{
 974+ mw.log('mwLoadDoneCB: Error non callback function on stack');
 975+ }
 976+ }
 977+ // Set the load request name to done
 978+ mwLoadDoneCB[ requestName ] = 'done';
 979+ };
 980+
 981+ /**
 982+ * Set a load done callback
 983+ *
 984+ * @param {String}
 985+ * requestName Name of resource or request set
 986+ * @param {Function}
 987+ * callback Function called once requestName is ready
 988+ */
 989+ mw.setLoadDoneCB = function( requestName, callback ) {
 990+ // If the requestName is already done loading just callback
 991+ if( mwLoadDoneCB[ requestName ] == 'done' ) {
 992+ callback( requestName );
 993+ }
 994+ // Setup the function queue if unset
 995+ if( typeof mwLoadDoneCB[ requestName ] != 'object' ) {
 996+ mwLoadDoneCB[ requestName ] = [];
 997+ }
 998+ mwLoadDoneCB[ requestName ].push( callback );
 999+ };
 1000+
 1001+ /**
 1002+ * Shortcut entry points / convenience functions: Lets you write mw.load()
 1003+ * instead of mw.loader.load() only these entry points should be used.
 1004+ *
 1005+ * future closure optimizations could minify internal function names
 1006+ */
 1007+
 1008+ /**
 1009+ * Load Object entry point: Loads a requested set of javascript
 1010+ */
 1011+ mw.load = function( loadRequest, callback ) {
 1012+ return mw.loader.load( loadRequest, callback );
 1013+ };
 1014+
 1015+ /**
 1016+ * Add module entry point: Adds a module to the mwLoader object
 1017+ */
 1018+ mw.addModuleLoader = function ( name, loaderFunction ) {
 1019+ return mw.loader.addModuleLoader( name, loaderFunction );
 1020+ };
 1021+
 1022+ /**
 1023+ * Add Class File Paths entry point:
 1024+ */
 1025+ mw.addResourcePaths = function ( resourceSet ) {
 1026+ return mw.loader.addResourcePaths( resourceSet );
 1027+ };
 1028+
 1029+ mw.addStyleResourceDependency = function ( resourceSet ) {
 1030+ return mw.loader.addStyleResourceDependency( resourceSet );
 1031+ };
 1032+
 1033+ /**
 1034+ * Get Class File Path entry point:
 1035+ */
 1036+ mw.getResourcePath = function( resourceName ) {
 1037+ return mw.loader.getResourcePath( resourceName );
 1038+ };
 1039+
 1040+
 1041+ /**
 1042+ * Utility Functions
 1043+ */
 1044+
 1045+ /**
 1046+ * addLoaderDialog small helper for displaying a loading dialog
 1047+ *
 1048+ * @param {String}
 1049+ * dialogHtml text Html of the loader msg
 1050+ */
 1051+ mw.addLoaderDialog = function( dialogHtml ) {
 1052+ if( typeof dialogHtml == 'undefined'){
 1053+ dialogHtml ='';
 1054+ }
 1055+ var $dialog = mw.addDialog( {
 1056+ 'title' : dialogHtml,
 1057+ 'content' : dialogHtml + '<br>' +
 1058+ $j('<div />')
 1059+ .loadingSpinner()
 1060+ .html()
 1061+ });
 1062+ return $dialog;
 1063+ };
 1064+
 1065+ /**
 1066+ * Close the loader dialog created with addLoaderDialog
 1067+ */
 1068+ mw.closeLoaderDialog = function() {
 1069+ // Make sure the dialog resource is present
 1070+ if( !mw.isset( '$j.ui.dialog' ) ) {
 1071+ return false;
 1072+ }
 1073+ // Close with timeout since jquery ui binds with timeout:
 1074+ // ui dialog line 530
 1075+ setTimeout( function(){
 1076+ $j( '#mwTempLoaderDialog' )
 1077+ .dialog( 'destroy' );
 1078+ } , 10);
 1079+ };
 1080+
 1081+ /**
 1082+ * Add a (temporary) dialog window:
 1083+ *
 1084+ * @param {Object} with following keys:
 1085+ * title: {String} Title string for the dialog
 1086+ * content: {String} to be inserted in msg box
 1087+ * buttons: {Object} A button object for the dialog Can be a string
 1088+ * for the close button
 1089+ * any jquery.ui.dialog option
 1090+ */
 1091+ mw.addDialog = function ( options ) {
 1092+ // Remove any other dialog
 1093+ $j( '#mwTempLoaderDialog' ).remove();
 1094+
 1095+ if( !options){
 1096+ options = {};
 1097+ }
 1098+
 1099+ // Extend the default options with provided options
 1100+ var options = $j.extend({
 1101+ 'bgiframe': true,
 1102+ 'draggable': true,
 1103+ 'resizable': false,
 1104+ 'modal': true,
 1105+ 'position' : ['center', 'center']
 1106+ }, options );
 1107+
 1108+ if( ! options.title || ! options.content ){
 1109+ mw.log("Error: mwEmbed addDialog missing required options ( title, content ) ");
 1110+ return ;
 1111+ }
 1112+
 1113+ // Append the dialog div on top:
 1114+ $j( 'body' ).append(
 1115+ $j('<div />')
 1116+ .attr( {
 1117+ 'id' : "mwTempLoaderDialog",
 1118+ 'title' : options.title
 1119+ })
 1120+ .hide()
 1121+ .append( options.content )
 1122+ );
 1123+
 1124+ // Build the uiRequest
 1125+ var uiRequest = [ '$j.ui.dialog' ];
 1126+ if( options.draggable ){
 1127+ uiRequest.push( '$j.ui.mouse' );
 1128+ uiRequest.push( '$j.ui.draggable' );
 1129+ }
 1130+ if( options.resizable ){
 1131+ uiRequest.push( '$j.ui.resizable' );
 1132+ }
 1133+
 1134+ // Special button string
 1135+ if ( typeof options.buttons == 'string' ) {
 1136+ var buttonMsg = options.buttons;
 1137+ buttons = { };
 1138+ options.buttons[ buttonMsg ] = function() {
 1139+ $j( this ).dialog( 'close' );
 1140+ };
 1141+ }
 1142+
 1143+ // Load the dialog resources
 1144+ mw.load([
 1145+ [
 1146+ '$j.ui',
 1147+ '$j.widget',
 1148+ '$j.ui.mouse',
 1149+ '$j.ui.position'
 1150+ ],
 1151+ uiRequest
 1152+ ], function() {
 1153+ var $dialog = $j( '#mwTempLoaderDialog' ).show().dialog( options );
 1154+ // center the dialog
 1155+ // xxx figure out why jquery ui is messing up here
 1156+ /*$j( '#mwTempLoaderDialog' ).parent('.ui-dialog').css({
 1157+ 'position' : 'absolute',
 1158+ 'left' : '50%',
 1159+ 'margin-left': -1 * $dialog.width()/2,
 1160+ 'top' : '50%',
 1161+ 'margin-top': -1 * $dialog.height()/2
 1162+ }); */
 1163+ } );
 1164+ return $j( '#mwTempLoaderDialog' );
 1165+ };
 1166+
 1167+ /**
 1168+ * Mobile HTML5 has special properties for html5 video::
 1169+ *
 1170+ * NOTE: should be phased out in favor of browser feature detection where possible
 1171+ */
 1172+ mw.isMobileHTML5 = function() {
 1173+ // check mobile safari foce ( for debug )
 1174+ if( mw.getConfig( 'forceMobileHTML5' ) || document.URL.indexOf('forceMobileHTML5') != -1 ){
 1175+ return true;
 1176+ }
 1177+ if (( navigator.userAgent.indexOf('iPhone') != -1) ||
 1178+ ( navigator.userAgent.indexOf('iPod') != -1) ||
 1179+ ( navigator.userAgent.indexOf('iPad') != -1) ||
 1180+ ( mw.isAndroid2() )
 1181+ ) {
 1182+ return true;
 1183+ }
 1184+ return false;
 1185+ };
 1186+ // Android 2 has some restrictions vs other mobile platforms
 1187+ mw.isAndroid2 = function(){
 1188+ if ( navigator.userAgent.indexOf('Android 2.') != -1) {
 1189+ return true;
 1190+ }
 1191+ return false;
 1192+ };
 1193+
 1194+ /**
 1195+ * Similar to php isset function checks if the variable exists. Does a safe
 1196+ * check of a descendant method or variable
 1197+ *
 1198+ * @param {String}
 1199+ * objectPath
 1200+ * @return {Boolean} true if objectPath exists false if objectPath is
 1201+ * undefined
 1202+ */
 1203+ mw.isset = function( objectPath ) {
 1204+ if ( !objectPath || typeof objectPath != 'string') {
 1205+ return false;
 1206+ }
 1207+ var pathSet = objectPath.split( '.' );
 1208+ var cur_path = '';
 1209+
 1210+ for ( var p = 0; p < pathSet.length; p++ ) {
 1211+ cur_path = ( cur_path == '' ) ? cur_path + pathSet[p] : cur_path + '.' + pathSet[p];
 1212+ eval( 'var ptest = typeof ( ' + cur_path + ' ); ' );
 1213+ if ( ptest == 'undefined' ) {
 1214+ return false;
 1215+ }
 1216+ }
 1217+ return true;
 1218+ };
 1219+
 1220+ /**
 1221+ * Wait for a object to be defined and the call the callback
 1222+ *
 1223+ * @param {Object}
 1224+ * objectName Name of object to be defined
 1225+ * @param {Function}
 1226+ * callback Function to call once object is defined
 1227+ * @param {Null}
 1228+ * callNumber Used internally to keep track of number of times
 1229+ * waitForObject has been called
 1230+ */
 1231+ var waitTime = 1200; // About 30 seconds
 1232+ mw.waitForObject = function( objectName, callback, _callNumber) {
 1233+ // mw.log( 'waitForObject: ' + objectName + ' cn: ' + _callNumber);
 1234+
 1235+ // Increment callNumber:
 1236+ if( !_callNumber ) {
 1237+ _callNumber = 1;
 1238+ } else {
 1239+ _callNumber++;
 1240+ }
 1241+
 1242+ if( _callNumber > waitTime ) {
 1243+ mw.log( "Error: waiting for object: " + objectName + ' timeout ' );
 1244+ callback( false );
 1245+ return ;
 1246+ }
 1247+
 1248+ // If the object is defined ( or we are done loading from a callback )
 1249+ if ( mw.isset( objectName ) || mwLoadDoneCB[ objectName ] == 'done' ) {
 1250+ callback( objectName );
 1251+ }else{
 1252+ setTimeout( function( ) {
 1253+ mw.waitForObject( objectName, callback, _callNumber);
 1254+ }, 25);
 1255+ }
 1256+ };
 1257+
 1258+ /**
 1259+ * Check if an object is empty or if its an empty string.
 1260+ *
 1261+ * @param {Object}
 1262+ * object Object to be checked
 1263+ */
 1264+ mw.isEmpty = function( object ) {
 1265+ if( typeof object == 'string' ) {
 1266+ if( object == '' ) return true;
 1267+ // Non empty string:
 1268+ return false;
 1269+ }
 1270+
 1271+ // If an array check length:
 1272+ if( Object.prototype.toString.call( object ) === "[object Array]"
 1273+ && object.length == 0 ) {
 1274+ return true;
 1275+ }
 1276+
 1277+ // Else check as an object:
 1278+ for( var i in object ) { return false; }
 1279+
 1280+ // Else object is empty:
 1281+ return true;
 1282+ };
 1283+
 1284+ /**
 1285+ * Log a string msg to the console
 1286+ *
 1287+ * all mw.log statements will be removed on minification so lots of mw.log
 1288+ * calls will not impact performance in non debug mode
 1289+ *
 1290+ * @param {String}
 1291+ * string String to output to console
 1292+ */
 1293+ mw.log = function( string ) {
 1294+ // Add any prepend debug strings if necessary
 1295+ if ( mw.getConfig( 'Mw.LogPrepend' ) ){
 1296+ string = mw.getConfig( 'Mw.LogPrepend' ) + string;
 1297+ }
 1298+
 1299+ if ( window.console ) {
 1300+ window.console.log( string );
 1301+ } else {
 1302+ /**
 1303+ * Old IE and non-Firebug debug: ( commented out for now )
 1304+ */
 1305+
 1306+ /*var log_elm = document.getElementById('mv_js_log');
 1307+ if(!log_elm) {
 1308+ document.getElementsByTagName("body")[0].innerHTML += '<div ' +
 1309+ 'style="position:absolute;z-index:500;bottom:0px;left:0px;right:0px;height:200px;">' +
 1310+ '<textarea id="mv_js_log" cols="120" rows="12"></textarea>' +
 1311+ '</div>';
 1312+ }
 1313+ var log_elm = document.getElementById('mv_js_log');
 1314+ if(log_elm) {
 1315+ log_elm.value+=string+"\n";
 1316+ // scroll to bottom:
 1317+ log_elm.scrollTop = log_elm.scrollHeight;
 1318+ }*/
 1319+ }
 1320+ };
 1321+
 1322+ // Setup the local mwOnLoadFunctions array:
 1323+ var mwOnLoadFunctions = [];
 1324+
 1325+ // mw Ready flag ( set once mwEmbed is ready )
 1326+ var mwReadyFlag = false;
 1327+
 1328+ /**
 1329+ * Enables load hooks to run once mwEmbeed is "ready" Will ensure jQuery is
 1330+ * available, is in the $j namespace and mw interfaces and configuration has
 1331+ * been loaded and applied
 1332+ *
 1333+ * This is different from jQuery(document).ready() ( jQuery ready is not
 1334+ * friendly with dynamic includes and not friendly with core interface
 1335+ * asynchronous build out. )
 1336+ *
 1337+ * @param {Function}
 1338+ * callback Function to run once DOM and jQuery are ready
 1339+ */
 1340+ mw.ready = function( callback ) {
 1341+ if( mwReadyFlag === false ) {
 1342+ // Add the callbcak to the onLoad function stack
 1343+ mwOnLoadFunctions.push ( callback );
 1344+ } else {
 1345+ // If mwReadyFlag is already "true" issue the callback directly:
 1346+ callback();
 1347+ }
 1348+ };
 1349+
 1350+ /**
 1351+ * Runs all the queued functions called by mwEmbedSetup
 1352+ */
 1353+ mw.runReadyFunctions = function ( ) {
 1354+ mw.log('mw.runReadyFunctions: ' + mwOnLoadFunctions.length );
 1355+ // Run any pre-setup ready functions
 1356+ while( preMwEmbedReady.length ){
 1357+ preMwEmbedReady.shift()();
 1358+ }
 1359+ // Run all the queued functions:
 1360+ while( mwOnLoadFunctions.length ) {
 1361+ mwOnLoadFunctions.shift()();
 1362+ }
 1363+
 1364+ // Sets mwReadyFlag to true so that future mw.ready run the
 1365+ // callback directly
 1366+ mwReadyFlag = true;
 1367+
 1368+ // Once we have run all the queued functions
 1369+ mw.loader.runModuleLoadQueue();
 1370+
 1371+ };
 1372+
 1373+
 1374+ /**
 1375+ * Wrapper for jQuery getScript, Uses the scriptLoader if enabled
 1376+ *
 1377+ *
 1378+ * @param {String}
 1379+ * scriptRequest The requested path or resourceNames for the
 1380+ * scriptLoader
 1381+ * @param {Function}
 1382+ * callback Function to call once script is loaded
 1383+ */
 1384+ mw.getScript = function( scriptRequest, callback ) {
 1385+ // mw.log( "mw.getScript::" + scriptRequest );
 1386+ // Setup the local scope callback instace
 1387+ var myCallback = function(){
 1388+ if( callback ) {
 1389+ callback( scriptRequest );
 1390+ }
 1391+ };
 1392+ // Set the base url based scriptLoader availability & type of
 1393+ // scriptRequest
 1394+ // ( presently script loader only handles "classes" not relative urls:
 1395+ var scriptLoaderPath = mw.getResourceLoaderPath();
 1396+
 1397+ // Check if its a resource name, ( ie does not start with "/" and does
 1398+ // not include ://
 1399+ var isResourceName = ( scriptRequest.indexOf('://') == -1 && scriptRequest.indexOf('/') !== 0 )? true : false;
 1400+
 1401+ var ext = scriptRequest.substr( scriptRequest.lastIndexOf( '.' ), 4 ).toLowerCase();
 1402+ var isCssFile = ( ext == '.css') ? true : false ;
 1403+
 1404+ if( scriptLoaderPath && isResourceName ) {
 1405+ url = scriptLoaderPath + '?class=' + scriptRequest ;
 1406+ } else {
 1407+ // Add the mwEmbed path if a relative path request
 1408+ url = ( isResourceName ) ? mw.getMwEmbedPath() : '';
 1409+ url+= scriptRequest;
 1410+ }
 1411+
 1412+ // Add on the request parameters to the url:
 1413+ url += ( url.indexOf( '?' ) == -1 )? '?' : '&';
 1414+ url += mw.getUrlParam();
 1415+
 1416+ // Only log sciprts ( Css is logged via "add css" )
 1417+ if( !isCssFile ){
 1418+ mw.log( 'mw.getScript: ' + url );
 1419+ }
 1420+
 1421+ // If jQuery is available and debug is off load the script via jQuery
 1422+ // ( will use XHR if on same domain )
 1423+ if( mw.isset( 'window.jQuery' )
 1424+ && mw.getConfig( 'debug' ) === false
 1425+ && typeof $j != 'undefined'
 1426+ && mw.parseUri( url ).protocal != 'file'
 1427+ && !isCssFile )
 1428+ {
 1429+ $j.getScript( url, myCallback);
 1430+ return ;
 1431+ }
 1432+
 1433+ /**
 1434+ * No jQuery OR In debug mode OR Is css file
 1435+ * :: inject the script instead of doing an XHR eval
 1436+ */
 1437+
 1438+ // load style sheet directly if requested loading css
 1439+ if( isCssFile ){
 1440+ mw.getStyleSheet( url, myCallback);
 1441+ return ;
 1442+ }
 1443+
 1444+ // Load and bind manually: ( copied from jQuery ajax function )
 1445+ var head = document.getElementsByTagName("head")[ 0 ];
 1446+ var script = document.createElement("script");
 1447+ script.setAttribute( 'src', url );
 1448+
 1449+ // Attach handlers ( if using script loader it issues onDone callback as
 1450+ // well )
 1451+ script.onload = script.onreadystatechange = function() {
 1452+ if (!this.readyState || this.readyState == "loaded" || this.readyState == "complete") {
 1453+ myCallback();
 1454+ }
 1455+ };
 1456+ // mw.log(" append script: " + script.src );
 1457+ // Append the script to the DOM:
 1458+ head.appendChild( script );
 1459+ };
 1460+
 1461+ /**
 1462+ * Add a style sheet string to the document head
 1463+ *
 1464+ * @param {String}
 1465+ * cssResourceName Name of style sheet that has been defined
 1466+ * @param {String}
 1467+ * cssString Css Payload to be added to head of document
 1468+ */
 1469+ mw.addStyleString = function( cssResourceName, cssString ) {
 1470+ if( mw.style[ cssResourceName ] ) {
 1471+ mw.log(" Style: ( " + cssResourceName + ' ) already set' );
 1472+ return true;
 1473+ }
 1474+ // Set the style to true ( to not request it again )
 1475+ mw.style[ cssResourceName ] = true;
 1476+ // Add the spinner directly ( without jQuery in case we have to
 1477+ // dynamically load jQuery )
 1478+ mw.log( 'Adding style:' + cssResourceName + " to dom " );
 1479+ var styleNode = document.createElement('style');
 1480+ styleNode.type = "text/css";
 1481+ // Use cssText or createTextNode depending on browser:
 1482+ if( ( window.attachEvent && !window.opera ) ) {
 1483+ styleNode.styleSheet.cssText = cssString;
 1484+ } else {
 1485+ var styleText = document.createTextNode( cssString );
 1486+ styleNode.appendChild( styleText );
 1487+ }
 1488+ var head = document.getElementsByTagName("head")[0];
 1489+ head.appendChild( styleNode );
 1490+ };
 1491+
 1492+ /**
 1493+ * Get a style sheet and append the style sheet to the DOM
 1494+ *
 1495+ * @param {Mixed}
 1496+ * {String} url Url of the style sheet to be loaded {Function}
 1497+ * callback Function called once sheet is ready
 1498+ */
 1499+ mw.getStyleSheet = function( url , callback) {
 1500+ // Add URL params ( if not already included )
 1501+ if ( url.indexOf( '?' ) == -1 ) {
 1502+ url += '?' + mw.getUrlParam();
 1503+ }
 1504+
 1505+ // Check if style sheet is already included:
 1506+ var foundSheet = false;
 1507+ $j( 'link' ).each( function() {
 1508+ var currentSheet = $j( this) .attr( 'href' );
 1509+ var sheetParts = currentSheet.split('?');
 1510+ var urlParts = url.split('?');
 1511+ // if the base url's match check the parameters:
 1512+ if( sheetParts[0] == urlParts[0] && sheetParts[1]) {
 1513+ // Check if url params match ( sort to do string compare )
 1514+ if( sheetParts[1].split( '&' ).sort().join('') ==
 1515+ urlParts[1].split('&').sort().join('') ) {
 1516+ foundSheet = true;
 1517+ }
 1518+ }
 1519+ } );
 1520+ if( foundSheet ) {
 1521+ mw.log( 'skiped sheet: ' + url);
 1522+ if( callback) {
 1523+ callback();
 1524+ }
 1525+ return ;
 1526+ }
 1527+
 1528+ mw.log( ' add css: ' + url );
 1529+ $j( 'head' ).append(
 1530+ $j('<link />').attr( {
 1531+ 'rel' : 'stylesheet',
 1532+ 'type' : 'text/css',
 1533+ 'href' : url
 1534+ } )
 1535+ );
 1536+ // No easy way to check css "onLoad" attribute
 1537+ // In production sheets are loaded via resource loader and fire the
 1538+ // onDone function call.
 1539+ if( callback ) {
 1540+ callback();
 1541+ }
 1542+ };
 1543+
 1544+ mw.getRelativeMwEmbedPath = function(){
 1545+ return mw.getMwEmbedPath(true);
 1546+ };
 1547+ /**
 1548+ * Get the path to the mwEmbed folder
 1549+ */
 1550+ mw.getMwEmbedPath = function( relativePath ) {
 1551+ // Get mwEmbed src:
 1552+ var src = mw.getMwEmbedSrc();
 1553+ var mwpath = null;
 1554+
 1555+ // Check for direct include of the mwEmbed.js
 1556+ if ( src.indexOf( 'mwEmbed.js' ) !== -1 ) {
 1557+ mwpath = src.substr( 0, src.indexOf( 'mwEmbed.js' ) );
 1558+ }
 1559+
 1560+ // Check for scriptLoader include of mwEmbed:
 1561+ if ( src.indexOf( 'mwResourceLoader.php' ) !== -1 ) {
 1562+ // Script loader is in the root of MediaWiki, Include the default
 1563+ // mwEmbed extension path:
 1564+ mwpath = src.substr( 0, src.indexOf( 'mwResourceLoader.php' ) ) + mw.getConfig( 'mediaWikiEmbedPath' );
 1565+ }
 1566+
 1567+ // resource loader has ResourceLoader name when local:
 1568+ if( src.indexOf( 'ResourceLoader.php' ) !== -1 ) {
 1569+ mwpath = src.substr( 0, src.indexOf( 'ResourceLoader.php' ) );
 1570+ }
 1571+
 1572+ // For static packages mwEmbed packages start with: "mwEmbed-"
 1573+ if( src.indexOf( 'mwEmbed-' ) !== -1 && src.indexOf( '-static' ) !== -1 ) {
 1574+ mwpath = src.substr( 0, src.indexOf( 'mwEmbed-' ) );
 1575+ }
 1576+
 1577+ // Error out if we could not get the path:
 1578+ if( mwpath === null ) {
 1579+ mw.log( "Error could not get mwEmbed path " );
 1580+ return ;
 1581+ }
 1582+
 1583+ // Update the cached var with the absolute path:
 1584+ if( !relativePath ){
 1585+ mwpath = mw.absoluteUrl( mwpath ) ;
 1586+ }
 1587+ return mwpath;
 1588+ };
 1589+
 1590+ /**
 1591+ * Get Script loader path
 1592+ *
 1593+ * @returns {String}|{Boolean} Url of the scriptLodaer false if the
 1594+ * scriptLoader is not used
 1595+ */
 1596+ mw.getResourceLoaderPath = function( ) {
 1597+ var src = mw.getMwEmbedSrc();
 1598+ if ( src.indexOf( 'mwResourceLoader.php' ) !== -1 ||
 1599+ src.indexOf( 'ResourceLoader.php' ) !== -1 )
 1600+ {
 1601+ // Return just the script part of the url
 1602+ return src.split('?')[0];
 1603+ }
 1604+ return false;
 1605+ };
 1606+
 1607+ /**
 1608+ * Given a float number of seconds, returns npt format response. ( ignore
 1609+ * days for now )
 1610+ *
 1611+ * @param {Float}
 1612+ * sec Seconds
 1613+ * @param {Boolean}
 1614+ * verbose If hours and milliseconds should padded be displayed.
 1615+ * @return {Float} String npt format
 1616+ */
 1617+ mw.seconds2npt = function( sec, verbose ) {
 1618+ if ( isNaN( sec ) ) {
 1619+ mw.log("Warning: trying to get npt time on NaN:" + sec);
 1620+ return '0:00:00';
 1621+ }
 1622+
 1623+ var tm = mw.seconds2Measurements( sec );
 1624+
 1625+ // Round the number of seconds to the required number of significant
 1626+ // digits
 1627+ if ( verbose ) {
 1628+ tm.seconds = Math.round( tm.seconds * 1000 ) / 1000;
 1629+ } else {
 1630+ tm.seconds = Math.round( tm.seconds );
 1631+ }
 1632+ if ( tm.seconds < 10 ){
 1633+ tm.seconds = '0' + tm.seconds;
 1634+ }
 1635+ if( tm.hours == 0 && !verbose ){
 1636+ hoursStr = '';
 1637+ } else {
 1638+ if ( tm.minutes < 10 && verbose) {
 1639+ tm.minutes = '0' + tm.minutes;
 1640+ }
 1641+
 1642+ if( tm.hours < 10 && verbose){
 1643+ tm.hours = '0' + tm.hours;
 1644+ }
 1645+
 1646+ hoursStr = tm.hours + ':';
 1647+ }
 1648+ return hoursStr + tm.minutes + ":" + tm.seconds;
 1649+ };
 1650+
 1651+ /**
 1652+ * Given seconds return array with 'days', 'hours', 'min', 'seconds'
 1653+ *
 1654+ * @param {float}
 1655+ * sec Seconds to be converted into time measurements
 1656+ */
 1657+ mw.seconds2Measurements = function ( sec ){
 1658+ var tm = {};
 1659+ tm.days = Math.floor( sec / ( 3600 * 24 ) );
 1660+ tm.hours = Math.floor( sec / 3600 );
 1661+ tm.minutes = Math.floor( ( sec / 60 ) % 60 );
 1662+ tm.seconds = sec % 60;
 1663+ return tm;
 1664+ };
 1665+
 1666+ /**
 1667+ * Take hh:mm:ss,ms or hh:mm:ss.ms input, return the number of seconds
 1668+ *
 1669+ * @param {String}
 1670+ * npt_str NPT time string
 1671+ * @return {Float} Number of seconds
 1672+ */
 1673+ mw.npt2seconds = function ( npt_str ) {
 1674+ if ( !npt_str ) {
 1675+ // mw.log('npt2seconds:not valid ntp:'+ntp);
 1676+ return false;
 1677+ }
 1678+ // Strip {npt:}01:02:20 or 32{s} from time if present
 1679+ npt_str = npt_str.replace( /npt:|s/g, '' );
 1680+
 1681+ var hour = 0;
 1682+ var min = 0;
 1683+ var sec = 0;
 1684+
 1685+ times = npt_str.split( ':' );
 1686+ if ( times.length == 3 ) {
 1687+ sec = times[2];
 1688+ min = times[1];
 1689+ hour = times[0];
 1690+ } else if ( times.length == 2 ) {
 1691+ sec = times[1];
 1692+ min = times[0];
 1693+ } else {
 1694+ sec = times[0];
 1695+ }
 1696+ // Sometimes a comma is used instead of period for ms
 1697+ sec = sec.replace( /,\s?/, '.' );
 1698+ // Return seconds float
 1699+ return parseInt( hour * 3600 ) + parseInt( min * 60 ) + parseFloat( sec );
 1700+ };
 1701+
 1702+ // Local mwEmbedSrc variable ( for cache of mw.getMwEmbedSrc )
 1703+ var mwEmbedSrc = null;
 1704+
 1705+ /**
 1706+ * Gets the mwEmbed script src attribute
 1707+ */
 1708+ mw.getMwEmbedSrc = function() {
 1709+ if ( mwEmbedSrc ) {
 1710+ return mwEmbedSrc;
 1711+ }
 1712+
 1713+ // Get all the javascript includes:
 1714+ var js_elements = document.getElementsByTagName( "script" );
 1715+ for ( var i = 0; i < js_elements.length; i++ ) {
 1716+ // Check for mwEmbed.js and/or script loader
 1717+ var src = js_elements[i].getAttribute( "src" );
 1718+ if ( src ) {
 1719+ if ( // Check for mwEmbed.js ( debug mode )
 1720+ ( src.indexOf( 'mwEmbed.js' ) !== -1 && src.indexOf( 'MediaWiki:Gadget') == -1 )
 1721+ || // Check for resource loader
 1722+ (
 1723+ ( src.indexOf( 'mwResourceLoader.php' ) !== -1 || src.indexOf( 'ResourceLoader.php' ) !== -1 )
 1724+ &&
 1725+ src.indexOf( 'mwEmbed' ) !== -1
 1726+ )
 1727+ || // Check for static mwEmbed package
 1728+ ( src.indexOf( 'mwEmbed' ) !== -1 && src.indexOf( 'static' ) !== -1 )
 1729+ ) {
 1730+ mwEmbedSrc = src;
 1731+ return mwEmbedSrc;
 1732+ }
 1733+ }
 1734+ }
 1735+ mw.log( 'Error: getMwEmbedSrc failed to get script path' );
 1736+ return false;
 1737+ };
 1738+
 1739+ // Local mwUrlParam variable ( for cache of mw.getUrlParam )
 1740+ var mwUrlParam = null;
 1741+
 1742+ /**
 1743+ * Get URL Parameters per parameters in the host script include
 1744+ */
 1745+ mw.getUrlParam = function() {
 1746+ if ( mwUrlParam ) {
 1747+ return mwUrlParam;
 1748+ }
 1749+
 1750+ var mwEmbedSrc = mw.getMwEmbedSrc();
 1751+ var req_param = '';
 1752+
 1753+ // If we already have a URI, add it to the param request:
 1754+ var urid = mw.parseUri( mwEmbedSrc ).queryKey['urid'];
 1755+
 1756+ // If we're in debug mode, get a fresh unique request key and pass on
 1757+ // "debug" param
 1758+ if ( mw.parseUri( mwEmbedSrc ).queryKey['debug'] == 'true' ) {
 1759+ mw.setConfig( 'debug', true );
 1760+ var d = new Date();
 1761+ req_param += 'urid=' + d.getTime() + '&debug=true';
 1762+
 1763+ } else if ( urid ) {
 1764+ // Just pass on the existing urid:
 1765+ req_param += 'urid=' + urid;
 1766+ } else {
 1767+ // Otherwise, Use the mwEmbed version
 1768+ req_param += 'urid=' + mw.version;
 1769+ }
 1770+
 1771+ // Add the language param if present:
 1772+ var langKey = mw.parseUri( mwEmbedSrc ).queryKey['uselang'];
 1773+ if ( langKey )
 1774+ req_param += '&uselang=' + langKey;
 1775+
 1776+ // Update the local cache and return the value
 1777+ mwUrlParam = req_param;
 1778+ return mwUrlParam;
 1779+ };
 1780+
 1781+ /**
 1782+ * Replace url parameters via newParams key value pairs
 1783+ *
 1784+ * @param {String}
 1785+ * url Source url to be updated
 1786+ * @param {Object}
 1787+ * newParams key, value paris to swap in
 1788+ * @return {String} the updated url
 1789+ */
 1790+ mw.replaceUrlParams = function( url, newParams ) {
 1791+ var parsedUrl = mw.parseUri( url );
 1792+
 1793+ if ( parsedUrl.protocol != '' ) {
 1794+ var new_url = parsedUrl.protocol + '://' + parsedUrl.authority + parsedUrl.path + '?';
 1795+ } else {
 1796+ var new_url = parsedUrl.path + '?';
 1797+ }
 1798+
 1799+ // Merge new params:
 1800+ for( var key in newParams ) {
 1801+ parsedUrl.queryKey[ key ] = newParams[ key ];
 1802+ }
 1803+
 1804+ // Output to new_url
 1805+ var amp = '';
 1806+ for ( var key in parsedUrl.queryKey ) {
 1807+ var val = parsedUrl.queryKey[ key ];
 1808+ new_url += amp + key + '=' + val;
 1809+ amp = '&';
 1810+ }
 1811+ return new_url;
 1812+ };
 1813+
 1814+ /**
 1815+ * parseUri 1.2.2 (c) Steven Levithan <stevenlevithan.com> MIT License
 1816+ */
 1817+ mw.parseUri = function (str) {
 1818+ var o = mw.parseUri.options,
 1819+ m = o.parser[o.strictMode ? "strict" : "loose"].exec(str),
 1820+ uri = {},
 1821+ i = 14;
 1822+
 1823+ while (i--) uri[o.key[i]] = m[i] || "";
 1824+
 1825+ uri[o.q.name] = {};
 1826+ uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) {
 1827+ if ($1) uri[o.q.name][$1] = $2;
 1828+ });
 1829+
 1830+ return uri;
 1831+ };
 1832+
 1833+ /**
 1834+ * Parse URI function
 1835+ *
 1836+ * For documentation on its usage see:
 1837+ * http://stevenlevithan.com/demo/parseuri/js/
 1838+ */
 1839+ mw.parseUri.options = {
 1840+ strictMode: false,
 1841+ key: ["source", "protocol", "authority", "userInfo", "user", "password", "host",
 1842+ "port", "relative", "path", "directory", "file", "query", "anchor"],
 1843+ q: {
 1844+ name: "queryKey",
 1845+ parser: /(?:^|&)([^&=]*)=?([^&]*)/g
 1846+ },
 1847+ parser: {
 1848+ strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
 1849+ loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
 1850+ }
 1851+ };
 1852+
 1853+ /**
 1854+ * getAbsoluteUrl takes a src and returns the absolute location given the
 1855+ * document.URL or a contextUrl param
 1856+ *
 1857+ * @param {String} src path or url
 1858+ * @param {String} contextUrl The domain / context for creating an absolute url
 1859+ * from a relative path
 1860+ * @return {String} absolute url
 1861+ */
 1862+mw.absoluteUrl = function( src, contextUrl ) {
 1863+
 1864+ var parsedSrc = mw.parseUri( src );
 1865+
 1866+ // Source is already absolute return:
 1867+ if( parsedSrc.protocol != '') {
 1868+ return src;
 1869+ }
 1870+
 1871+ // Get parent Url location the context URL
 1872+ if( !contextUrl ) {
 1873+ contextUrl = document.URL;
 1874+ }
 1875+ var parsedUrl = mw.parseUri( contextUrl );
 1876+
 1877+ // Check for IE local file that does not flip the slashes
 1878+ if( parsedUrl.directory == '' && parsedUrl.protocol == 'file' ){
 1879+ // pop off the file
 1880+ var fileUrl = contextUrl.split( '\\');
 1881+ fileUrl.pop();
 1882+ return fileUrl.join('\\') + '\\' + src;
 1883+ }
 1884+
 1885+ // Check for leading slash:
 1886+ if( src.indexOf( '/' ) === 0 ) {
 1887+ return parsedUrl.protocol + '://' + parsedUrl.authority + src;
 1888+ }else{
 1889+ return parsedUrl.protocol + '://' + parsedUrl.authority + parsedUrl.directory + src;
 1890+ }
 1891+ };
 1892+ /**
 1893+ * Check if a given source string is likely a url
 1894+ *
 1895+ * @return {boolean}
 1896+ * true if a url
 1897+ * false if a string
 1898+ */
 1899+ mw.isUrl = function( src ){
 1900+ var parsedSrc = mw.parseUri( src );
 1901+ // if the url is just a string source and host will match
 1902+ return ( parsedSrc.host != parsedSrc.source );
 1903+ };
 1904+
 1905+ /**
 1906+ * Escape quotes in a text string
 1907+ *
 1908+ * @param {String}
 1909+ * text String to be escaped
 1910+ * @return {string} escaped text string
 1911+ */
 1912+ mw.escapeQuotes = function( text ) {
 1913+ var re = new RegExp("'","g");
 1914+ text = text.replace(re,"\\'");
 1915+ re = new RegExp("\\n","g");
 1916+ text = text.replace(re,"\\n");
 1917+ return mw.escapeQuotesHTML(text);
 1918+ };
 1919+
 1920+ /**
 1921+ * Escape an HTML text string
 1922+ *
 1923+ * @param {String}
 1924+ * text String to be escaped
 1925+ * @return {string} escaped text html string
 1926+ */
 1927+ mw.escapeQuotesHTML = function( text ) {
 1928+ var replaceMap = {
 1929+ "&" : "&amp;",
 1930+ '"' : "&quot;",
 1931+ '<' : "&lt;",
 1932+ '>' : "&gt;"
 1933+ };
 1934+ for( var i in replaceMap ){
 1935+ text = text.split(i).join( replaceMap[i]);
 1936+ }
 1937+ return text;
 1938+ };
 1939+
 1940+
 1941+ // Array of setup functions
 1942+ var mwSetupFunctions = [];
 1943+
 1944+ /**
 1945+ * Add a function to be run during setup ( prior to mw.ready) this is useful
 1946+ * for building out interfaces that should be ready before mw.ready is
 1947+ * called.
 1948+ *
 1949+ * @param {callback}
 1950+ * Function Callback function must accept a ready function
 1951+ * callback to be called once setup is done
 1952+ */
 1953+ mw.addSetupHook = function( callback ) {
 1954+ mwSetupFunctions.push ( callback ) ;
 1955+ };
 1956+
 1957+ /**
 1958+ * One time "setup" for mwEmbed run onDomReady ( so calls to setConfg apply
 1959+ * to setup )
 1960+ */
 1961+ // Flag to ensure setup is only run once:
 1962+ var mwSetupFlag = false;
 1963+ mw.setupMwEmbed = function ( ) {
 1964+ // Only run the setup once:
 1965+ if( mwSetupFlag ) {
 1966+ return ;
 1967+ }
 1968+ mwSetupFlag = true;
 1969+
 1970+ // Apply any pre-setup config:
 1971+ mw.setConfig( preMwEmbedConfig );
 1972+
 1973+
 1974+ mw.log( 'mw:setupMwEmbed SRC:: ' + mw.getMwEmbedSrc() );
 1975+
 1976+ // Check core mwEmbed loader.js file ( to get configuration and paths )
 1977+ mw.checkCoreLoaderFile( function(){
 1978+ // Make sure we have jQuery
 1979+ mw.load( 'window.jQuery', function() {
 1980+
 1981+ // Add jQuery to $j var.
 1982+ if ( ! window[ '$j' ] ) {
 1983+ window[ '$j' ] = jQuery.noConflict();
 1984+ }
 1985+ // Setup user config:
 1986+ mw.setupUserConfig( function(){
 1987+ // Get module loader.js, and language files
 1988+ // ( will hit callback directly if set via resource loader )
 1989+ mw.checkModuleLoaderFiles( function() {
 1990+
 1991+ // Set the User language
 1992+ if( typeof wgUserLanguage != 'undefined' && mw.isValidLang( wgUserLanguage) ) {
 1993+ mw.setConfig( 'userLanguage', wgUserLanguage );
 1994+ }else{
 1995+ // Grab it from the included url
 1996+ var langKey = mw.parseUri( mw.getMwEmbedSrc() ).queryKey['uselang'];
 1997+ if ( langKey && mw.isValidLang( langKey ) ) {
 1998+ mw.setConfig( 'userLanguage', langKey);
 1999+ }
 2000+ }
 2001+
 2002+ // Update the image path
 2003+ mw.setConfig( 'imagesPath', mw.getMwEmbedPath() + 'skins/common/images/' );
 2004+
 2005+ // Set up AJAX to not send dynamic URLs for loading scripts
 2006+ $j.ajaxSetup( {
 2007+ cache: true
 2008+ } );
 2009+
 2010+ // Update the magic keywords
 2011+ mw.Language.magicSetup();
 2012+
 2013+ // Set up mvEmbed utility jQuery bindings
 2014+ mw.dojQueryBindings();
 2015+
 2016+
 2017+ // Special Hack for conditional jquery ui inclusion ( once
 2018+ // Usability extension
 2019+ // registers the jquery.ui skin in mw.style
 2020+ if( mw.hasJQueryUiCss() ){
 2021+ mw.style[ 'ui_' + mw.getConfig( 'jQueryUISkin' ) ] = true;
 2022+ }
 2023+
 2024+
 2025+ // Make sure style sheets are loaded:
 2026+ mw.load( ['mw.style.mwCommon'] , function(){
 2027+ // Run all the setup function hooks
 2028+ // NOTE: setup functions are added via addSetupHook
 2029+ // calls
 2030+ // and must include a callback.
 2031+ //
 2032+ // Once complete we can run .ready() queued functions
 2033+ function runSetupFunctions() {
 2034+ if( mwSetupFunctions.length ) {
 2035+ mwSetupFunctions.shift()( function() {
 2036+ runSetupFunctions();
 2037+ } );
 2038+ }else{
 2039+ mw.runReadyFunctions();
 2040+ }
 2041+ }
 2042+ runSetupFunctions();
 2043+ } );
 2044+
 2045+ } );
 2046+ });
 2047+ });
 2048+ });
 2049+ };
 2050+
 2051+ /**
 2052+ * Checks for jquery ui css by name jquery-ui-1.7.2.css NOTE: this is a hack
 2053+ * for usability jquery-ui in the future usability should register a
 2054+ * resource in mw.skin
 2055+ *
 2056+ * @return true if found, return false if not found
 2057+ */
 2058+ mw.hasJQueryUiCss = function(){
 2059+ var hasUiCss = false;
 2060+ var cssStyleSheetNames = ['jquery-ui-1.7.2.css', 'jquery-ui.css'];
 2061+ // Load the jQuery ui skin if usability skin not set
 2062+ $j( 'link' ).each( function( na, linkNode ){
 2063+ $j.each( cssStyleSheetNames, function(inx, sheetName ){
 2064+ if( $j( linkNode ).attr( 'href' ).indexOf( sheetName ) != -1 ){
 2065+ hasUiCss = true;
 2066+ return true;
 2067+ }
 2068+ });
 2069+ } );
 2070+ // Check all the "style" nodes for @import for sheet name
 2071+ // xxx Note: we could do this a bit cleaner with regEx
 2072+ $j( 'style' ).each( function( na, styleNode ){
 2073+ $j.each( cssStyleSheetNames, function(inx, sheetName ){
 2074+ if( $j( styleNode ).text().indexOf( '@import' ) != -1
 2075+ &&
 2076+ $j( styleNode ).text().indexOf( sheetName ) != -1 )
 2077+ {
 2078+ hasUiCss=true;
 2079+ return true;
 2080+ }
 2081+ });
 2082+ });
 2083+ return hasUiCss;
 2084+ };
 2085+
 2086+ /**
 2087+ * Loads the core mwEmbed "loader.js" file config
 2088+ *
 2089+ * NOTE: if using the ScriptLoader all the loaders and localization
 2090+ * converters are included automatically
 2091+ *
 2092+ * @param {Function}
 2093+ * callback Function called once core loader file is loaded
 2094+ */
 2095+ mw.checkCoreLoaderFile = function( callback ) {
 2096+ // Check if we are using scriptloader ( handles loader include
 2097+ // automatically )
 2098+ if( mw.getResourceLoaderPath() ) {
 2099+ callback();
 2100+ return ;
 2101+ }
 2102+
 2103+ // Check if we are using a static package ( mwEmbed path includes
 2104+ // -static )
 2105+ if( mw.isStaticPackge() ){
 2106+ callback();
 2107+ return ;
 2108+ }
 2109+
 2110+ // Add the Core loader to the request
 2111+ // The follow code is ONLY RUN in debug / raw file mode
 2112+ mw.load( 'loader.js', callback );
 2113+ };
 2114+
 2115+ /**
 2116+ * Checks if the javascript is a static package ( not using resource loader )
 2117+ *
 2118+ * @return {boolean} true the included script is static false the included
 2119+ * script
 2120+ */
 2121+ mw.isStaticPackge = function(){
 2122+ var src = mw.getMwEmbedSrc();
 2123+ if( src.indexOf('-static') !== -1 ){
 2124+ return true;
 2125+ }
 2126+ return false;
 2127+ };
 2128+
 2129+ /**
 2130+ * Check for resource loader module loaders, and localization files
 2131+ *
 2132+ * NOTE: if using the ScriptLoader all the loaders and localization
 2133+ * converters are included automatically.
 2134+ */
 2135+ mw.checkModuleLoaderFiles = function( callback ) {
 2136+ mw.log( 'doLoaderCheck::' );
 2137+
 2138+ // Check if we are using scriptloader ( handles loader include
 2139+ // automatically )
 2140+ // Or if mwEmbed is a static package ( all resources are already loaded
 2141+ // )
 2142+ if( mw.getResourceLoaderPath() || mw.isStaticPackge() ) {
 2143+ callback();
 2144+ return ;
 2145+ }
 2146+
 2147+ // Load the configured modules / components
 2148+ // The follow code is ONLY RUN in debug / raw file mode
 2149+ var loaderRequest = [];
 2150+
 2151+ // Load enabled components
 2152+ var enabledComponents = mw.getConfig( 'coreComponents' );
 2153+ function loadEnabledComponents( enabledComponents ){
 2154+ if( ! enabledComponents.length ){
 2155+ // If no more components load modules::
 2156+
 2157+ // Add the enabledModules loaders:
 2158+ var enabledModules = mw.getConfig( 'enabledModules' );
 2159+ loadEnabledModules( enabledModules );
 2160+ return ;
 2161+ }
 2162+ var componentName = enabledComponents.shift();
 2163+ mw.load( componentName, function(){
 2164+ loadEnabledComponents( enabledComponents );
 2165+ } );
 2166+ }
 2167+ loadEnabledComponents( enabledComponents );
 2168+
 2169+
 2170+ // Set the loader context and get each loader individually
 2171+ function loadEnabledModules( enabledModules ){
 2172+ if( ! enabledModules.length ){
 2173+ // If no more modules left load the LanguageFile
 2174+ addLanguageFile();
 2175+ return ;
 2176+ }
 2177+ var moduleName = enabledModules.shift();
 2178+ mw.setConfig( 'loaderContext', 'modules/' + moduleName + '/' );
 2179+ mw.load( 'modules/' + moduleName + '/loader.js', function(){
 2180+ loadEnabledModules( enabledModules );
 2181+ } );
 2182+ }
 2183+
 2184+ function addLanguageFile(){
 2185+ // Add the language file
 2186+ var langLoaderRequest = [];
 2187+
 2188+ if( mw.getConfig( 'userLanguage' ) ) {
 2189+ var langCode = mw.getConfig( 'userLanguage' );
 2190+
 2191+ // Load the language resource if not default 'en'
 2192+ var transformKey = mw.getLangTransformKey( langCode );
 2193+ if( transformKey != 'en' ){
 2194+ // Upper case the first letter:
 2195+ langCode = langCode.substr(0,1).toUpperCase() + langCode.substr( 1, langCode.length );
 2196+ langLoaderRequest.push( 'languages/classes/Language' +
 2197+ langCode + '.js' );
 2198+ }
 2199+
 2200+ }
 2201+ if ( ! langLoaderRequest.length ) {
 2202+ addLocalSettings();
 2203+ return ;
 2204+ }
 2205+
 2206+ // Load the language if set
 2207+ mw.load( langLoaderRequest, function(){
 2208+ mw.log( 'Done moduleLoaderCheck request' );
 2209+ addLocalSettings();
 2210+ } );
 2211+ }
 2212+ function addLocalSettings(){
 2213+ var continueCallback = function(){
 2214+ // Set the mwModuleLoaderCheckFlag flag to true
 2215+ mwModuleLoaderCheckFlag = true;
 2216+ callback();
 2217+ };
 2218+ if( mw.getConfig( 'LoadLocalSettings') != true ){
 2219+ continueCallback();
 2220+ return;
 2221+ }
 2222+ mw.log("Load loacal settings");
 2223+ mw.load( 'localSettings.js', function(){
 2224+ continueCallback();
 2225+ });
 2226+ }
 2227+
 2228+ };
 2229+
 2230+ /**
 2231+ * Checks if a css style rule exists
 2232+ *
 2233+ * On a page with lots of rules it can take some time so avoid calling this
 2234+ * function where possible and cache its result
 2235+ *
 2236+ * NOTE: this only works for style sheets on the same domain :(
 2237+ *
 2238+ * @param {String}
 2239+ * styleRule Style rule name to check
 2240+ * @return {Boolean} true if the rule exists false if the rule does not
 2241+ * exist
 2242+ */
 2243+ mw.styleRuleExists = function ( styleRule ) {
 2244+ // Set up the skin paths configuration
 2245+ for( var i=0 ; i < document.styleSheets.length ; i++ ) {
 2246+ var rules = null;
 2247+ try{
 2248+ if ( document.styleSheets[i].cssRules )
 2249+ rules = document.styleSheets[i].cssRules;
 2250+ else if (document.styleSheets[0].rules)
 2251+ rules = document.styleSheets[i].rules;
 2252+ for(var j=0 ; j < rules.length ; j++ ) {
 2253+ var rule = rules[j].selectorText;
 2254+ if( rule && rule.indexOf( styleRule ) != -1 ) {
 2255+ return true;
 2256+ }
 2257+ }
 2258+ }catch ( e ) {
 2259+ mw.log( 'Error: cant check rule on cross domain style sheet:' + document.styleSheets[i].href );
 2260+ }
 2261+ }
 2262+ return false;
 2263+ };
 2264+
 2265+ // Flag to register the domReady has been called
 2266+ var mwDomReadyFlag = false;
 2267+
 2268+ // Flag to register if the domreadyHooks have been called
 2269+ var mwModuleLoaderCheckFlag = false;
 2270+
 2271+ /**
 2272+ * This will get called when the DOM is ready Will check configuration and
 2273+ * issue a mw.setupMwEmbed call if needed
 2274+ */
 2275+ mw.domReady = function ( ) {
 2276+ if( mwDomReadyFlag ) {
 2277+ return ;
 2278+ }
 2279+ mw.log( 'run:domReady:: ' + document.getElementsByTagName('video').length );
 2280+ // Set the onDomReady Flag
 2281+ mwDomReadyFlag = true;
 2282+
 2283+ // Give us a chance to get to the bottom of the script.
 2284+ // When loading mwEmbed asynchronously the dom ready gets called
 2285+ // directly and in some browsers beets the $j = jQuery.noConflict();
 2286+ // call
 2287+ // and causes symbol undefined errors.
 2288+ setTimeout(function(){
 2289+ mw.setupMwEmbed();
 2290+ },1);
 2291+ };
 2292+
 2293+ /**
 2294+ * A version comparison utility function Handles version of types
 2295+ * {Major}.{MinorN}.{Patch}
 2296+ *
 2297+ * Note this just handles version numbers not patch letters.
 2298+ *
 2299+ * @param {String}
 2300+ * minVersion Minnium version needed
 2301+ * @param {String}
 2302+ * clientVersion Client version to be checked
 2303+ *
 2304+ * @return true if the version is at least of minVersion false if the
 2305+ * version is less than minVersion
 2306+ */
 2307+ mw.versionIsAtLeast = function( minVersion, clientVersion ) {
 2308+ var minVersionParts = minVersion.split('.');
 2309+ var clientVersionParts = clientVersion.split('.');
 2310+ for( var i =0; i < minVersionParts.length; i++ ) {
 2311+ if( parseInt( clientVersionParts[i] ) > parseInt( minVersionParts[i] ) ) {
 2312+ return true;
 2313+ }
 2314+ if( parseInt( clientVersionParts[i] ) < parseInt( minVersionParts[i] ) ) {
 2315+ return false;
 2316+ }
 2317+ }
 2318+ // Same version:
 2319+ return true;
 2320+ };
 2321+
 2322+ /**
 2323+ * Runs all the triggers on a given object with a single "callback"
 2324+ *
 2325+ * Normal tirgger calls will run the callback directly multiple times for
 2326+ * every binded function.
 2327+ *
 2328+ * With runTriggersCallback() callback is not called until all the binded
 2329+ * events have been run.
 2330+ *
 2331+ * @param {object}
 2332+ * targetObject Target object to run triggers on
 2333+ * @param {string}
 2334+ * triggerName Name of trigger to be run
 2335+ * @param {function}
 2336+ * callback Function called once all triggers have been run
 2337+ *
 2338+ */
 2339+ mw.runTriggersCallback = function( targetObject, triggerName, callback ){
 2340+ mw.log( 'mw.runTriggersCallback:: ' + triggerName );
 2341+ // If events are not present directly run callback
 2342+ if( ! $j( targetObject ).data( 'events' ) ||
 2343+ ! $j( targetObject ).data( 'events' )[ triggerName ] ) {
 2344+ mw.log( ' trigger name not found: ' + triggerName );
 2345+ callback();
 2346+ return ;
 2347+ }
 2348+ var callbackSet = $j( targetObject ).data( 'events' )[ triggerName ];
 2349+ if( !callbackSet || callbackSet.length === 0 ){
 2350+ mw.log( ' No events run the callback directly: ' + triggerName );
 2351+ // No events run the callback directly
 2352+ callback();
 2353+ return ;
 2354+ }
 2355+ // Set the callbackCount
 2356+ var callbackCount = ( callbackSet.length )? callbackSet.length : 1;
 2357+
 2358+ mw.log(" runTriggersCallback:: " + callbackCount );
 2359+ var callInx = 0;
 2360+ $j( targetObject ).trigger( triggerName, function() {
 2361+ callInx++;
 2362+ if( callInx == callbackCount ){
 2363+ //mw.log(" callbackCountReached run:: " + callback);
 2364+ // Run callback
 2365+ callback();
 2366+ }
 2367+ } );
 2368+ };
 2369+ /**
 2370+ * Utility jQuery bindings Setup after jQuery is available ).
 2371+ */
 2372+ mw.dojQueryBindings = function() {
 2373+ mw.log( 'mw.dojQueryBindings' );
 2374+ ( function( $ ) {
 2375+
 2376+ /**
 2377+ * Set a given selector html to the loading spinner:
 2378+ */
 2379+ $.fn.loadingSpinner = function( ) {
 2380+ if ( this ) {
 2381+ $j( this ).html(
 2382+ $j( '<div />' )
 2383+ .addClass( "loadingSpinner" )
 2384+ );
 2385+ }
 2386+ return this;
 2387+ };
 2388+ /**
 2389+ * Add an absolute overlay spinner useful for cases where the
 2390+ * element does not display child elements, ( images, video )
 2391+ */
 2392+ $.fn.getAbsoluteOverlaySpinner = function(){
 2393+ var pos = $j( this ).offset();
 2394+ var posLeft = ( $j( this ).width() ) ?
 2395+ parseInt( pos.left + ( .5 * $j( this ).width() ) -16 ) :
 2396+ pos.left + 30;
 2397+
 2398+ var posTop = ( $j( this ).height() ) ?
 2399+ parseInt( pos.top + ( .5 * $j( this ).height() ) -16 ) :
 2400+ pos.top + 30;
 2401+
 2402+ var $spinner = $j('<div />')
 2403+ .loadingSpinner()
 2404+ .css({
 2405+ 'width' : 32,
 2406+ 'height' : 32,
 2407+ 'position': 'absolute',
 2408+ 'top' : posTop + 'px',
 2409+ 'left' : posLeft + 'px'
 2410+ });
 2411+ $j('body').append( $spinner );
 2412+ return $spinner;
 2413+ };
 2414+
 2415+ /**
 2416+ * dragDrop file loader
 2417+ */
 2418+ $.fn.dragFileUpload = function ( conf ) {
 2419+ if ( this.selector ) {
 2420+ var _this = this;
 2421+ // load the dragger and "setup"
 2422+ mw.load( ['$j.fn.dragDropFile'], function() {
 2423+ $j( _this.selector ).dragDropFile();
 2424+ } );
 2425+ }
 2426+ };
 2427+
 2428+ /**
 2429+ * Shortcut to a themed button Should be depreciated for $.button
 2430+ * bellow
 2431+ */
 2432+ $.btnHtml = function( msg, styleClass, iconId, opt ) {
 2433+ if ( !opt )
 2434+ opt = { };
 2435+ var href = ( opt.href ) ? opt.href : '#';
 2436+ var target_attr = ( opt.target ) ? ' target="' + opt.target + '" ' : '';
 2437+ var style_attr = ( opt.style ) ? ' style="' + opt.style + '" ' : '';
 2438+ return '<a href="' + href + '" ' + target_attr + style_attr +
 2439+ ' class="ui-state-default ui-corner-all ui-icon_link ' +
 2440+ styleClass + '"><span class="ui-icon ui-icon-' + iconId + '" ></span>' +
 2441+ '<span class="btnText">' + msg + '</span></a>';
 2442+ };
 2443+
 2444+ // Shortcut to jQuery button ( should replace all btnHtml with
 2445+ // button )
 2446+ var mw_default_button_options = {
 2447+ // The class name for the button link
 2448+ 'class' : '',
 2449+
 2450+ // The style properties for the button link
 2451+ 'style' : { },
 2452+
 2453+ // The text of the button link
 2454+ 'text' : '',
 2455+
 2456+ // The icon id that precedes the button link:
 2457+ 'icon' : 'carat-1-n'
 2458+ };
 2459+
 2460+ $.button = function( options ) {
 2461+ var options = $j.extend( {}, mw_default_button_options, options);
 2462+
 2463+ // Button:
 2464+ var $button = $j('<a />')
 2465+ .attr('href', '#')
 2466+ .addClass( 'ui-state-default ui-corner-all ui-icon_link' );
 2467+ // Add css if set:
 2468+ if( options.css ) {
 2469+ $button.css( options.css );
 2470+ }
 2471+
 2472+ if( options['class'] ) {
 2473+ $button.addClass( options['class'] );
 2474+ }
 2475+
 2476+
 2477+ // return the button:
 2478+ $button.append(
 2479+ $j('<span />').addClass( 'ui-icon ui-icon-' + options.icon ),
 2480+ $j('<span />').addClass( 'btnText' )
 2481+ .text( options.text )
 2482+ )
 2483+ .buttonHover(); // add buttonHover binding;
 2484+ if( !options.text ){
 2485+ $button.css('padding', '1em');
 2486+ }
 2487+ return $button;
 2488+ };
 2489+
 2490+ // Shortcut to bind hover state
 2491+ $.fn.buttonHover = function() {
 2492+ $j( this ).hover(
 2493+ function() {
 2494+ $j( this ).addClass( 'ui-state-hover' );
 2495+ },
 2496+ function() {
 2497+ $j( this ).removeClass( 'ui-state-hover' );
 2498+ }
 2499+ );
 2500+ return this;
 2501+ };
 2502+
 2503+ /**
 2504+ * Resize a dialog to fit the window
 2505+ *
 2506+ * @param {Object}
 2507+ * options horizontal and vertical space ( default 50 )
 2508+ */
 2509+ $.fn.dialogFitWindow = function( options ) {
 2510+ var opt_default = { 'hspace':50, 'vspace':50 };
 2511+ if ( !options )
 2512+ var options = { };
 2513+ options = $j.extend( opt_default, options );
 2514+ $j( this.selector ).dialog( 'option', 'width', $j( window ).width() - options.hspace );
 2515+ $j( this.selector ).dialog( 'option', 'height', $j( window ).height() - options.vspace );
 2516+ $j( this.selector ).dialog( 'option', 'position', 'center' );
 2517+ // update the child position: (some of this should be pushed
 2518+ // up-stream via dialog config options
 2519+ $j( this.selector + '~ .ui-dialog-buttonpane' ).css( {
 2520+ 'position':'absolute',
 2521+ 'left':'0px',
 2522+ 'right':'0px',
 2523+ 'bottom':'0px'
 2524+ } );
 2525+ };
 2526+
 2527+ } )( $j );
 2528+ };
 2529+
 2530+} )( window.mw );
 2531+
 2532+
 2533+/**
 2534+ * Set DOM-ready call We copy jQuery( document ).ready here since sometimes
 2535+ * mwEmbed.js is included without jQuery and we need our own "ready" system so
 2536+ * that mwEmbed interfaces can support async built out and the include of
 2537+ * jQuery.
 2538+ */
 2539+var mwDomIsReady = false;
 2540+function runMwDomReady(){
 2541+ mwDomIsReady = true;
 2542+ if( mw.domReady ){
 2543+ mw.domReady();
 2544+ }
 2545+}
 2546+// Check if already ready:
 2547+if ( document.readyState === "complete" ) {
 2548+ runMwDomReady();
 2549+}
 2550+
 2551+// Cleanup functions for the document ready method
 2552+if ( document.addEventListener ) {
 2553+ DOMContentLoaded = function() {
 2554+ document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
 2555+ runMwDomReady();
 2556+ };
 2557+
 2558+} else if ( document.attachEvent ) {
 2559+ DOMContentLoaded = function() {
 2560+ // Make sure body exists, at least, in case IE gets a little overzealous
 2561+ // (ticket #5443).
 2562+ if ( document.readyState === "complete" ) {
 2563+ document.detachEvent( "onreadystatechange", DOMContentLoaded );
 2564+ runMwDomReady();
 2565+ }
 2566+ };
 2567+}
 2568+// Mozilla, Opera and webkit nightlies currently support this event
 2569+if ( document.addEventListener ) {
 2570+ // Use the handy event callback
 2571+ document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
 2572+
 2573+ // A fallback to window.onload, that will always work
 2574+ window.addEventListener( "load", mw.domReady, false );
 2575+
 2576+// If IE event model is used
 2577+} else if ( document.attachEvent ) {
 2578+ // ensure firing before onload,
 2579+ // maybe late but safe also for iframes
 2580+ document.attachEvent("onreadystatechange", DOMContentLoaded);
 2581+
 2582+ // A fallback to window.onload, that will always work
 2583+ window.attachEvent( "onload", runMwDomReady );
 2584+
 2585+ // If IE and not a frame
 2586+ // continually check to see if the document is ready
 2587+ var toplevel = false;
 2588+
 2589+ try {
 2590+ toplevel = window.frameElement == null;
 2591+ } catch(e) {}
 2592+
 2593+ if ( document.documentElement.doScroll && toplevel ) {
 2594+ doScrollCheck();
 2595+ }
 2596+}
 2597+// The DOM ready check for Internet Explorer
 2598+function doScrollCheck() {
 2599+ if ( mwDomIsReady ) {
 2600+ return;
 2601+ }
 2602+
 2603+ try {
 2604+ // If IE is used, use the trick by Diego Perini
 2605+ // http://javascript.nwbox.com/IEContentLoaded/
 2606+ document.documentElement.doScroll("left");
 2607+ } catch( error ) {
 2608+ setTimeout( doScrollCheck, 1 );
 2609+ return;
 2610+ }
 2611+
 2612+ // and execute any waiting functions
 2613+ runMwDomReady();
 2614+}
 2615+
 2616+
 2617+// If using the resource loader and jQuery has not been set give a warning to
 2618+// the user:
 2619+// (this is needed because packaged loader.js files could refrence jQuery )
 2620+if( mw.getResourceLoaderPath() && !window.jQuery ) {
 2621+ mw.log( 'Error: jQuery is required for mwEmbed, please update your resource loader request' );
 2622+}
 2623+
 2624+if( mw.isStaticPackge() && !window.jQuery ){
 2625+ alert( 'Error: jQuery is required for mwEmbed ');
 2626+}
 2627+
 2628+/**
 2629+ * Hack to keep jQuery in $ when its already there, but also use noConflict to
 2630+ * get $j = jQuery
 2631+ *
 2632+ * This way sites that use $ for jQuery continue to work after including mwEmbed
 2633+ * javascript.
 2634+ *
 2635+ * Also if jQuery is included prior to mwEmbed we ensure $j is set
 2636+ */
 2637+
 2638+if( window.jQuery ){
 2639+ if( ! mw.versionIsAtLeast( '1.4.0', jQuery.fn.jquery ) ){
 2640+ if( window.console && window.console.log ) {
 2641+ console.log( 'Error mwEmbed requires jQuery 1.4 or above' );
 2642+ }
 2643+ }
 2644+ var dollarFlag = false;
 2645+ if( $ && $.fn && $.fn.jquery ) {
 2646+ // NOTE we could check the version of
 2647+ // jQuery and do a removal call if too old
 2648+ dollarFlag = true;
 2649+ }
 2650+ window[ '$j' ] = jQuery.noConflict();
 2651+ if( dollarFlag ) {
 2652+ window[ '$' ] = jQuery.noConflict();
 2653+ }
 2654+}
Property changes on: trunk/extensions/MwEmbed/MwEmbed/mwEmbed.old.js
___________________________________________________________________
Added: svn:eol-style
12655 + native
Index: trunk/extensions/MwEmbed/MwEmbed/mwEmbed.js
@@ -1,2535 +1,9 @@
2 -// Add support for html5 / mwEmbed elements to IE ( comment must come before js code )
3 -// For discussion and comments, see: http://remysharp.com/2009/01/07/html5-enabling-script/
4 -/*@cc_on@if(@_jscript_version<9){'video audio source track'.replace(/\w+/g,function(n){document.createElement(n)})}@end@*/
5 -
62 /**
7 - * @license
8 - * mwEmbed
9 - * Dual licensed under the MIT or GPL Version 2 licenses.
10 - *
11 - * @copyright (C) 2010 Kaltura
12 - * @author Michael Dale ( michael.dale at kaltura.com )
13 - *
14 - * @url http://www.kaltura.org/project/HTML5_Video_Media_JavaScript_Library
15 - *
16 - * Libraries used include code license in headers
17 - */
18 -
19 -/**
20 - * Setup the "mw" global:
21 - */
22 -if ( typeof window.mw == 'undefined' ) {
23 - window.mw = { };
24 -}
25 -
26 -/**
27 - * Set the mwEmbedVersion
28 - */
29 -var MW_EMBED_VERSION = '1.1g';
30 -
31 -// Globals to pre-set ready functions in dynamic loading of mwEmbed
32 -if( typeof preMwEmbedReady == 'undefined'){
33 - var preMwEmbedReady = [];
34 -}
35 -// Globals to pre-set config values in dynamic loading of mwEmbed
36 -if( typeof preMwEmbedConfig == 'undefined') {
37 - var preMwEmbedConfig = [];
38 -}
39 -
40 -/**
41 - * The global mw object:
42 - */
43 -( function( mw ) {
44 - // The version of mwEmbed
45 - mw.version = MW_EMBED_VERSION
46 -
47 - // List valid skins here:
48 - mw.validSkins = [ 'mvpcf', 'kskin' ];
49 -
50 - // Storage variable for loaded style sheet keys
51 - mw.style = { };
52 -
53 - /**
54 - * Configuration System:
55 - */
56 -
57 - // Local scope configuration var:
58 - if( !mwConfig ){
59 - var mwConfig = { };
60 - }
61 -
62 - // Local scope mwUserConfig var. Stores user configuration
63 - var mwUserConfig = { };
64 -
65 - /**
66 - * Setter for configuration values
67 - *
68 - * @param [Mixed]
69 - * name Name of configuration value {Object} Will iderate through
70 - * each key and call setConfig {String} Will set configuration by
71 - * string name to value
72 - * @param {String}
73 - * value Value of configuration name {Object} value Set of values
74 - * to be merged
75 - */
76 - mw.setConfig = function ( name, value ) {
77 - if( typeof name == 'object' ) {
78 - for( var i in name ) {
79 - mw.setConfig( i, name[ i ] );
80 - }
81 - return ;
82 - }
83 - // Check if we should "merge" the config
84 - if( typeof value == 'object' && typeof mwConfig[ name ] == 'object' ) {
85 - for( var i in value ){
86 - mwConfig[ name ][ i ] = value[ i ];
87 - }
88 - } else {
89 - mwConfig[ name ] = value;
90 - }
91 - }
92 -
93 - /**
94 - * Set a default config value Will only update configuration if no value is
95 - * present
96 - *
97 - * @param [Mixed]
98 - * value Set configuration name to value {Object} Will iderate
99 - * through each key and call setDefaultConfig {String} Will set
100 - * configuration by string name to value
101 - */
102 - mw.setDefaultConfig = function( name, value ) {
103 - if( typeof name == 'object' ) {
104 - for( var i in name ) {
105 - mw.setDefaultConfig( i, name[ i ] );
106 - }
107 - return ;
108 - }
109 - // Only update the controls if undefined ( ie don't override false
110 - // properties )
111 - if( typeof mwConfig[ name ] == 'undefined') {
112 - mwConfig[ name ] = value;
113 - }
114 - }
115 -
116 - /**
117 - * Getter for configuration values
118 - *
119 - * @param {String}
120 - * name of configuration value to get
121 - * @return {Mixed} value of configuration key returns "false" if key not
122 - * found
123 - */
124 - mw.getConfig = function ( name ) {
125 - if( mwConfig[ name ] )
126 - return mwConfig[ name ];
127 - return false;
128 - }
129 -
130 - /**
131 - * Loads the mwUserConfig from a cookie.
132 - *
133 - * Modules that want to use "User Config" should call this setup function in
134 - * their moduleLoader code.
135 - *
136 - * For performance interfaces using "user config" should load '$j.cookie' &
137 - * 'JSON' in their module loader
138 - *
139 - * By abstracting user preference we could eventually integrate a persistent
140 - * per-account preference system on the server.
141 - *
142 - * @parma {Function} callback Function to be called once userPrefrences are
143 - * loaded
144 - */
145 - var setupUserConfigFlag = false;
146 - mw.setupUserConfig = function( callback ) {
147 - if( setupUserConfigFlag ) {
148 - if( callback ) {
149 - callback();
150 - }
151 - return ;
152 - }
153 - // Do Setup user config:
154 - mw.load( [ '$j.cookie', 'JSON' ], function() {
155 - if( $j.cookie( 'mwUserConfig' ) ) {
156 - mwUserConfig = JSON.parse( $j.cookie( 'mwUserConfig' ) );
157 - }
158 - setupUserConfigFlag = true;
159 - if( callback ) {
160 - callback();
161 - }
162 - });
163 - }
164 -
165 - /**
166 - * Save a user configuration var to a cookie & local global variable Loads
167 - * the cookie plugin if not already loaded
168 - *
169 - * @param {String}
170 - * name Name of user configuration value
171 - * @param {String}
172 - * value Value of configuration name
173 - */
174 - mw.setUserConfig = function ( name, value, cookieOptions ) {
175 - if( ! setupUserConfigFlag ) {
176 - mw.log( "Error: userConfig not setup" );
177 - return false;
178 - }
179 - // Update local value
180 - mwUserConfig[ name ] = value;
181 -
182 - // Update the cookie ( '$j.cookie' & 'JSON' should already be loaded )
183 - $j.cookie( 'mwUserConfig', JSON.stringify( mwUserConfig ) );
184 - }
185 -
186 - /**
187 - * Save a user configuration var to a cookie & local global variable
188 - *
189 - * @param {String}
190 - * name Name of user configuration value
191 - * @return value of the configuration name false if the configuration name
192 - * could not be found
193 - */
194 - mw.getUserConfig = function ( name ) {
195 - if( mwUserConfig[ name ] )
196 - return mwUserConfig[ name ];
197 - return false;
198 - }
199 -
200 - /**
201 - * Add a hook system for a target object / interface
202 - *
203 - * depricated you should instead use jQuery's bind and trigger
204 - *
205 - * @param {Object}
206 - * targetObj Interface Object to add hook system to.
207 - */
208 - mw.addHookSystem = function( targetObj ) {
209 -
210 - // Setup the target object hook holder:
211 - targetObj[ 'hooks' ] = { };
212 -
213 - /**
214 - * Adds a hook to the target object
215 - *
216 - * Should be called by clients to setup named hooks
217 - *
218 - * @param {String}
219 - * hookName Name of hook to be added
220 - * @param {Function}
221 - * hookFunction Function to be called at hook time
222 - */
223 - targetObj.addHook = function( hookName, hookFunction ) {
224 - if( ! this.hooks[ hookName ] ) {
225 - this.hooks[ hookName ] = [ ];
226 - }
227 - this.hooks[ hookName ].push( hookFunction )
228 - }
229 -
230 - /**
231 - * Runs all the hooks by a given name with reference to the host object
232 - *
233 - * Should be called by the host object at named execution points
234 - *
235 - * @param {String}
236 - * hookName Name of hook to be called
237 - * @return Value of hook result true interface should continue function
238 - * execution false interface should stop or return from method
239 - */
240 - targetObj.runHook = function( hookName, options ) {
241 - if( this.hooks[ hookName ] ) {
242 - for( var i =0; i < this.hooks[ hookName ].length; i ++ ) {
243 - if( typeof( this.hooks[ hookName ][ i ] ) == 'function' ) {
244 - this.hooks[ hookName ][ i ]( options );
245 - }
246 - }
247 - }
248 - }
249 - }
250 -
251 - // Add hooks system to the core "mw" object
252 - mw.addHookSystem( mw );
253 -
254 - // Stores callbacks for resource loader loading
255 - var mwLoadDoneCB = { };
256 -
257 -
258 - /**
259 - * Top level loader prototype:
260 - */
261 - mw.loader = {
262 - /**
263 - * Javascript Module Loader functions
264 - *
265 - * @key Name of Module
266 - * @value function code to load module
267 - */
268 - moduleLoaders : [],
269 -
270 - /**
271 - * Module resource list queue.
272 - *
273 - * @key Name of Module
274 - * @value .resourceList list of resources to be loaded .functionQueue
275 - * list of functions to be run once module is ready
276 - */
277 - moduleLoadQueue: { },
278 -
279 - /**
280 - * Javascript Class Paths
281 - *
282 - * @key Name of resource
283 - * @value Class file path
284 - */
285 - resourcePaths : { },
286 -
287 - /**
288 - * javascript Resource Paths
289 - *
290 - * @key Name of resource
291 - * @value Name of depenent style sheet
292 - */
293 - resourceStyleDependency: { },
294 -
295 - /**
296 - * Core load function:
297 - *
298 - * @param {Mixed}
299 - * loadRequest:
300 - *
301 - * {String} Name of a module to be loaded Modules are added via
302 - * addModuleLoader and can define custom code needed to check config and
303 - * return a list of resources to be loaded
304 - *
305 - * {String} Name of a resource to loaded. Resources are added via
306 - * addResourcePaths function Using defined resource names avoids loading
307 - * the same resource twice by first checking if the named resource is
308 - * defined in the global javascript scope variable
309 - *
310 - * {String} Absolute or relative to url path The same file won't be
311 - * loaded twice
312 - *
313 - * {Array} can be an array of any combination of the above strings. Will
314 - * be loaded in-order or in a single resource loader request if
315 - * scriptLoader is available.
316 - *
317 - * {Array} {Array} Can be a set of Arrays for loading. Some browsers
318 - * execute included scripts out of order. This lets you chain sets of
319 - * request for those browsers. If using the server side resource loader
320 - * order is preserved in output and a single request will be used.
321 - *
322 - * @param {Function}
323 - * callback Function called once loading is complete
324 - *
325 - */
326 - load: function( loadRequest, instanceCallback ) {
327 - // mw.log("mw.load:: " + loadRequest );
328 -
329 - // Throw out any loadRequests that are not strings
330 - loadRequest = this.cleanLoadRequest( loadRequest );
331 -
332 - // Ensure the callback is only called once per load instance
333 - var callback = function(){
334 - // mw.log( 'instanceCallback::running callback: ' +
335 - // instanceCallback );
336 - if( instanceCallback ){
337 - // We pass the loadRequest back to the callback for easy
338 - // debugging of concurrency issues.
339 - // ( normally its not used )
340 - instanceCallback( loadRequest );
341 - instanceCallback = null;
342 - }
343 - }
344 -
345 - // Check for empty loadRequest ( directly return the callback )
346 - if( mw.isEmpty( loadRequest ) ) {
347 - mw.log( 'Empty load request: ( ' + loadRequest + ' ) ' );
348 - callback( loadRequest );
349 - return ;
350 - }
351 -
352 -
353 - // Check if its a multi-part request:
354 - if( typeof loadRequest == 'object' ) {
355 - if( loadRequest.length > 1 ) {
356 - this.loadMany ( loadRequest, callback );
357 - return ;
358 - }else{
359 - // If an array of length 1 set as first element
360 - loadRequest = loadRequest[0];
361 - }
362 - }
363 -
364 - // Check for the module name loader function
365 - if( this.moduleLoaders[ loadRequest ] ) {
366 - var resourceSet = this.getModuleResourceSet( loadRequest );
367 - if( !resourceSet ){
368 - mw.log( "mw.load:: Error with module loader: " + loadRequest + ' ( no resource set defined )' );
369 - return ;
370 - }
371 -
372 - // xxx should use refactor "ready" stuff into a "domReady" class
373 - // So we would not have local scope globals like this:
374 - if ( mwReadyFlag ) {
375 - // Load the module directly if load request is after
376 - // mw.ready has run
377 - this.load( resourceSet, callback );
378 - } else {
379 - this.addToModuleLoaderQueue(
380 - loadRequest,
381 - resourceSet,
382 - callback
383 - );
384 - }
385 - return ;
386 - }
387 -
388 - // Check for javascript resource
389 - if( this.getResourcePath( loadRequest ) ) {
390 - this.loadResource( loadRequest, callback );
391 - return ;
392 - }
393 -
394 - // Try loading as a "file" or via ScriptLoader
395 - if( loadRequest ) {
396 - if( loadRequest.indexOf( '.js' ) == -1 && !mw.getResourceLoaderPath() ) {
397 - mw.log( 'Error: are you sure ' + loadRequest + ' is a file ( is it missing a resource path? ) ' );
398 - }
399 - mw.getScript( loadRequest, callback );
400 - return ;
401 - }
402 -
403 - // Possible error?
404 - mw.log( "Error could not handle load request: " + loadRequest );
405 - },
406 -
407 - getModuleResourceSet: function( moduleName ){
408 - // Check if the module loader is a function ~run that function~
409 - if( typeof ( this.moduleLoaders[ moduleName ] ) == 'function' ) {
410 - // Add the result of the module loader function
411 - return this.moduleLoaders[ moduleName ]();
412 - } else if( typeof ( this.moduleLoaders[ moduleName ] ) == 'object' ){
413 - // set resourceSet directly
414 - return this.moduleLoaders[ moduleName ];
415 - }
416 - return false;
417 - },
418 -
419 - /**
420 - * Clean the loadRequest ( throw out any non-string items )
421 - */
422 - cleanLoadRequest: function( loadRequest ){
423 - var cleanRequest = [];
424 - if( typeof loadRequest == 'string' )
425 - return loadRequest;
426 - for( var i =0;i < loadRequest.length; i++ ){
427 - if( typeof loadRequest[i] == 'object' ) {
428 - cleanRequest[i] = this.cleanLoadRequest( loadRequest[i] );
429 - } else if( typeof loadRequest[i] == 'string' ){
430 - cleanRequest[i] = $j.trim( loadRequest[i] );
431 - } else{
432 - // bad request type skip
433 - }
434 - }
435 - return cleanRequest;
436 - },
437 - /**
438 - * Load a set of scripts. Will issue many load requests or package the
439 - * request for the resource loader
440 - *
441 - * @param {Object}
442 - * loadSet Set of scripts to be loaded
443 - * @param {Function}
444 - * callback Function to call once all scripts are loaded.
445 - */
446 - loadMany: function( loadSet, callback ) {
447 - var _this = this;
448 - // Setup up the local "loadStates"
449 - var loadStates = { };
450 -
451 - // Check if we can load via the "resource loader" ( mwEmbed was
452 - // included via scriptLoader )
453 - if( mw.getResourceLoaderPath() ) {
454 - // Get the grouped loadStates variable
455 - loadStates = this.getGroupLoadState( loadSet );
456 - if( mw.isEmpty( loadStates ) ) {
457 - // mw.log( 'loadMany:all resources already loaded');
458 - callback();
459 - return ;
460 - }
461 - }else{
462 - // Check if its a dependency set ( nested objects )
463 - if( typeof loadSet [ 0 ] == 'object' ) {
464 - _this.dependencyChainCallFlag[ loadSet ] = false;
465 - // Load sets of resources ( to preserver order for some
466 - // browsers )
467 - _this.loadDependencyChain( loadSet, callback );
468 - return ;
469 - }
470 -
471 - // Set the initial load state for every item in the loadSet
472 - for( var i = 0; i < loadSet.length ; i++ ) {
473 - var loadName = loadSet[ i ];
474 - loadStates[ loadName ] = 0;
475 - }
476 - }
477 -
478 - // We are infact loading many:
479 - mw.log("mw.load: LoadMany:: " + loadSet );
480 -
481 - // Issue the load request check check loadStates to see if we are
482 - // "done"
483 - for( var loadName in loadStates ) {
484 - // mw.log("loadMany: load: " + loadName );
485 - this.load( loadName, function ( loadName ) {
486 - loadStates[ loadName ] = 1;
487 -
488 - /*
489 - * for( var i in loadStates ) { mw.log( loadName + '
490 - * finished of: ' + i + ' : ' + loadStates[i] ); }
491 - */
492 -
493 - // Check if all load request states are set 1
494 - var loadDone = true;
495 - for( var j in loadStates ) {
496 - if( loadStates[ j ] === 0 )
497 - loadDone = false;
498 - }
499 - // Run the parent scope callback for "loadMany"
500 - if( loadDone ) {
501 - callback( loadName );
502 - }
503 - } );
504 - }
505 - },
506 -
507 - /**
508 - * Get grouped load state for script loader
509 - *
510 - * Groups the scriptRequest where possible: Modules include "loader
511 - * code" so they are separated into pre-condition code to be run for
512 - * subsequent requests
513 - *
514 - * @param {Object}
515 - * loadSet Loadset to return grouped
516 - * @return {Object} grouped loadSet
517 - */
518 - getGroupLoadState: function( loadSet ) {
519 - var groupedLoadSet = [];
520 - var loadStates = { };
521 - // Merge load set into new groupedLoadSet
522 - if( typeof loadSet[0] == 'object' ) {
523 - for( var i = 0; i < loadSet.length ; i++ ) {
524 - for( var j = 0; j < loadSet[i].length ; j++ ) {
525 - // Make sure we have not already included it:
526 - groupedLoadSet.push( loadSet[i][j] );
527 - }
528 - }
529 - } else {
530 - // Use the loadSet directly:
531 - groupedLoadSet = loadSet;
532 - }
533 -
534 - // Setup grouped loadStates Set:
535 - var groupClassKey = '';
536 - var coma = '';
537 - for( var i=0; i < groupedLoadSet.length; i++ ) {
538 - var loadName = groupedLoadSet[ i ];
539 -
540 -
541 - if( this.getResourcePath( loadName ) ) {
542 - // Only add to group request if not already set:
543 - if ( !mw.isset( loadName ) ) {
544 - groupClassKey += coma + loadName
545 - coma = ',';
546 -
547 - // Check for style sheet dependencies
548 - if( this.resourceStyleDependency[ loadName ] ){
549 - groupClassKey += coma + this.resourceStyleDependency[ loadName ];
550 - }
551 - }
552 - } else if ( this.moduleLoaders[ loadName ] ) {
553 -
554 - // Module loaders break up grouped script requests ( add the
555 - // current groupClassKey )
556 - if( groupClassKey != '' ) {
557 - loadStates[ groupClassKey ] = 0;
558 - groupClassKey = coma = '';
559 - }
560 - // Add the module to the loadSate
561 - loadStates[ loadName ] = 0;
562 - }
563 - }
564 -
565 - // Add groupClassKey if set:
566 - if( groupClassKey != '' ) {
567 - loadStates [ groupClassKey ] = 0;
568 - }
569 -
570 - return loadStates;
571 - },
572 -
573 - // Array to register that a callback has been called
574 - dependencyChainCallFlag: { },
575 -
576 - /**
577 - * Load a sets of scripts satisfy dependency order for browsers that
578 - * execute dynamically included scripts out of order
579 - *
580 - * @param {Object}
581 - * loadChain A set of javascript arrays to be loaded. Sets
582 - * are requested in array order.
583 - */
584 - loadDependencyChain: function( loadChain, callback ) {
585 - var _this = this;
586 - // Load with dependency checks
587 - var callSet = loadChain.shift();
588 - this.load( callSet, function( cbname ) {
589 - if ( loadChain.length != 0 ) {
590 - _this.loadDependencyChain( loadChain, callback );
591 - } else {
592 - // NOTE: IE gets called twice so we have check the
593 - // dependencyChainCallFlag before calling the callback
594 - if( _this.dependencyChainCallFlag[ callSet ] == callback ) {
595 - mw.log("... already called this callback for " + callSet );
596 - return ;
597 - }
598 - _this.dependencyChainCallFlag[ callSet ] = callback;
599 - callback( );
600 - }
601 - } );
602 - },
603 -
604 - /**
605 - * Add to the module loader queue
606 - */
607 - addToModuleLoaderQueue: function( moduleName, resourceSet, callback ) {
608 - mw.log(" addToModuleLoaderQueue:: " + moduleName + ' resourceSet: ' + resourceSet );
609 - if( this.moduleLoadQueue[ moduleName ] ){
610 - // If the module is already in the queue just add its callback:
611 - this.moduleLoadQueue[ moduleName ].functionQueue.push( callback );
612 - } else {
613 - // create the moduleLoadQueue item
614 - this.moduleLoadQueue[ moduleName ] = {
615 - 'resourceSet' : resourceSet,
616 - 'functionQueue' : [ callback ],
617 - 'loaded' : false
618 - };
619 - }
620 - },
621 -
622 - /**
623 - * Loops over all modules in queue, builds request sets based on config
624 - * request type
625 - */
626 - runModuleLoadQueue: function(){
627 - var _this = this;
628 - mw.log( "mw.runModuleLoadQueue:: " );
629 - var runModuleFunctionQueue = function(){
630 - // Run all the callbacks
631 - for( var moduleName in _this.moduleLoadQueue ){
632 - while( _this.moduleLoadQueue[moduleName].functionQueue.length ) {
633 - _this.moduleLoadQueue[moduleName].functionQueue.shift()();
634 - }
635 - }
636 - }
637 -
638 - // Check for single request or javascript debug based loading:
639 - if( !mw.getResourceLoaderPath() || mw.getConfig( 'loader.groupStrategy' ) == 'single' ){
640 - // if not using the resource load just do a normal array merge
641 - // ( for browsers like IE that don't follow first append first
642 - // execute rule )
643 - var fullResourceList = [];
644 - for( var moduleName in this.moduleLoadQueue ) {
645 - var resourceSet = this.moduleLoadQueue[ moduleName ].resourceSet;
646 - // Lets try a global merge
647 - fullResourceList = $j.merge( fullResourceList, resourceSet );
648 - }
649 - mw.load( fullResourceList, function(){
650 - runModuleFunctionQueue();
651 - });
652 - return ;
653 - }
654 -
655 - // Else do per module group loading
656 - if( mw.getConfig( 'loader.groupStrategy' ) == 'module' ) {
657 - var fullResourceList = [];
658 - var sharedResourceList = [];
659 -
660 - for( var moduleName in this.moduleLoadQueue ) {
661 - // Build a shared dependencies list and load that separately
662 - // "first"
663 - // ( in IE we have to wait until its "ready" since it does
664 - // not follow dom order )
665 - var moduleResourceList = this.getFlatModuleResourceList( moduleName );
666 - // Build the sharedResourceList
667 - for( var i=0; i < moduleResourceList.length; i++ ){
668 - var moduleResource = moduleResourceList[i];
669 - // Check if already in the full resource list if so add
670 - // to shared.
671 - if( fullResourceList[ moduleResource ] ){
672 - if( $j.inArray( moduleResource, sharedResourceList ) == -1 ){
673 - sharedResourceList.push( moduleResource );
674 - }
675 - }
676 - // Add to the fullResourceList
677 - fullResourceList[ moduleResource ] = true;
678 - }
679 - }
680 -
681 - // Local module request set ( stores the actual request we will
682 - // make after grouping shared resources
683 - var moduleRequestSet = {};
684 -
685 - // Only add non-shared to respective modules load requests
686 - for( var moduleName in this.moduleLoadQueue ) {
687 - moduleRequestSet[ moduleName ] = [];
688 - var moduleResourceList = this.getFlatModuleResourceList( moduleName );
689 - for( var i =0; i < moduleResourceList.length; i++ ){
690 - var moduleResource = moduleResourceList[i];
691 - if( $j.inArray( moduleResource, sharedResourceList ) == -1 ){
692 - moduleRequestSet[ moduleName ].push( moduleResource );
693 - }
694 - }
695 - }
696 - var sharedResourceLoadDone = false;
697 - // Check if modules are done
698 - var checkModulesDone = function(){
699 - if( !sharedResourceLoadDone ){
700 - return false;
701 - }
702 - for( var moduleName in _this.moduleLoadQueue ) {
703 - if( ! _this.moduleLoadQueue[ moduleName ].loaded ){
704 - return false;
705 - }
706 - }
707 - runModuleFunctionQueue();
708 - }
709 - // Local instance of load requests to retain resourceSet
710 - // context:
711 - var localLoadCallInstance = function( moduleName, resourceSet ){
712 - mw.load( resourceSet, function(){
713 - _this.moduleLoadQueue[ moduleName ].loaded = true;
714 - checkModulesDone();
715 - });
716 - }
717 -
718 - // Load the shared resources
719 - mw.load( sharedResourceList, function(){
720 - // mw.log("Shared Resources loaded");
721 - // xxx check if we are in "IE" and dependencies need to be
722 - // loaded "first"
723 - sharedResourceLoadDone = true;
724 - checkModulesDone();
725 - });
726 - // Load all module Request Set
727 - for( var moduleName in moduleRequestSet ){
728 - localLoadCallInstance( moduleName, moduleRequestSet[ moduleName ] );
729 - }
730 - }
731 - // xxx Here we could also do some "intelligent" grouping
732 - },
733 -
734 - getFlatModuleResourceList: function( moduleName ){
735 - var moduleList = [];
736 - for( var j in this.moduleLoadQueue[moduleName].resourceSet ){
737 - // Check if we have a multi-set array:
738 - if( typeof this.moduleLoadQueue[moduleName].resourceSet[j] == 'object' ){
739 - moduleList = $j.merge( moduleList, this.moduleLoadQueue[moduleName].resourceSet[j] );
740 - } else {
741 - moduleList = $j.merge( moduleList, [ this.moduleLoadQueue[moduleName].resourceSet[j] ] );
742 - }
743 - }
744 - return moduleList;
745 - },
746 - /**
747 - * Loads javascript or css associated with a resourceName
748 - *
749 - * @param {String}
750 - * resourceName Name of resource to load
751 - * @param {Function}
752 - * callback Function to run once resource is loaded
753 - */
754 - loadResource: function( resourceName , callback) {
755 - // mw.log("LoadResource:" + resourceName );
756 - var _this = this;
757 -
758 - // Check for css dependency on resource name
759 - if( this.resourceStyleDependency[ resourceName ] ) {
760 - if( ! mw.isset( this.resourceStyleDependency[ resourceName ] )){
761 - mw.log("loadResource:: dependent css resource: " + this.resourceStyleDependency[ resourceName ] );
762 - _this.loadResource( this.resourceStyleDependency[ resourceName ] , function() {
763 - // Continue the original loadResource request.
764 - _this.loadResource( resourceName, callback );
765 - });
766 - return ;
767 - }
768 - }
769 -
770 - // Make sure the resource is not already defined:
771 - if ( mw.isset( resourceName ) ) {
772 - // mw.log( 'Class ( ' + resourceName + ' ) already defined ' );
773 - callback( resourceName );
774 - return ;
775 - }
776 -
777 - // Setup the Script Request var:
778 - var scriptRequest = null;
779 -
780 -
781 - // If the scriptloader is enabled use the resourceName as the
782 - // scriptRequest:
783 - if( mw.getResourceLoaderPath() ) {
784 - scriptRequest = resourceName;
785 - }else{
786 - // Get the resource url:
787 - var baseClassPath = this.getResourcePath( resourceName );
788 - // Add the mwEmbed path if not a root path or a full url
789 - if( baseClassPath.indexOf( '/' ) !== 0 &&
790 - baseClassPath.indexOf( '://' ) === -1 ) {
791 - scriptRequest = mw.getMwEmbedPath() + baseClassPath;
792 - }else{
793 - scriptRequest = baseClassPath;
794 - }
795 - if( ! scriptRequest ) {
796 - mw.log( "Error Could not get url for resource " + resourceName );
797 - return false;
798 - }
799 - }
800 - // Include resource defined check for older browsers
801 - var resourceDone = false;
802 -
803 - // Set the loadDone callback per the provided resourceName
804 - mw.setLoadDoneCB( resourceName, callback );
805 - // Issue the request to load the resource (include resource name in
806 - // result callback:
807 - mw.getScript( scriptRequest, function( scriptRequest ) {
808 - // If its a "style sheet" manually set its resource to true
809 - var ext = scriptRequest.substr( scriptRequest.split('?')[0].lastIndexOf( '.' ), 4 ).toLowerCase();
810 - if( ext == '.css' && resourceName.substr(0,8) == 'mw.style' ){
811 - mw.style[ resourceName.substr( 9 ) ] = true;
812 - }
813 -
814 - // Send warning if resourceName is not defined
815 - if(! mw.isset( resourceName )
816 - && mwLoadDoneCB[ resourceName ] != 'done' ) {
817 - mw.log( 'Possible Error: ' + resourceName +' not set in time, or not defined in:' + "\n"
818 - + _this.getResourcePath( resourceName ) );
819 - }
820 -
821 - // If ( debug mode ) and the script include is missing resource
822 - // messages
823 - // do a separate request to retrieve the msgs
824 - if( mw.currentClassMissingMessages ) {
825 - mw.log( " resourceName " + resourceName + " is missing messages" );
826 - // Reset the currentClassMissingMessages flag
827 - mw.currentClassMissingMessages = false;
828 -
829 - // Load msgs for this resource:
830 - mw.loadResourceMessages( resourceName, function() {
831 - // Run the onDone callback
832 - mw.loadDone( resourceName );
833 - } );
834 - } else {
835 - // If not using the resource loader make sure the
836 - // resourceName is available before firing the loadDone
837 - if( !mw.getResourceLoaderPath() ) {
838 - mw.waitForObject( resourceName, function( resourceName ) {
839 - // Once object is ready run loadDone
840 - mw.loadDone( resourceName );
841 - } );
842 - } else {
843 - // loadDone should be appended to the bottom of the
844 - // resource loader response
845 - // mw.loadDone( resourceName );
846 - }
847 - }
848 - } );
849 - },
850 -
851 - /**
852 - * Adds a module to the mwLoader object
853 - *
854 - * @param {String}
855 - * name Name of module
856 - * @param {Function}
857 - * moduleLoader Function that loads dependencies for a module
858 - */
859 - addModuleLoader: function( name, moduleLoader ) {
860 - this.moduleLoaders [ name ] = moduleLoader;
861 - },
862 -
863 - /**
864 - * Adds resource file path key value pairs
865 - *
866 - * @param {Object}
867 - * resourceSet JSON formated list of resource name file path
868 - * pairs.
869 - *
870 - * resourceSet must be strict JSON to allow the php scriptLoader to
871 - * parse the file paths.
872 - */
873 - addResourcePaths: function( resourceSet ) {
874 - var prefix = ( mw.getConfig( 'loaderContext' ) )?
875 - mw.getConfig( 'loaderContext' ): '';
876 -
877 - for( var i in resourceSet ) {
878 - this.resourcePaths[ i ] = prefix + resourceSet[ i ];
879 - }
880 - },
881 -
882 - /*
883 - * Adds a named style sheet dependency to a named resource
884 - *
885 - * @parma {Object} resourceSet JSON formated list of resource names and
886 - * associated style sheet names
887 - */
888 - addStyleResourceDependency: function( resourceSet ){
889 - for( var i in resourceSet ){
890 - this.resourceStyleDependency[ i ] = resourceSet[i];
891 - }
892 - },
893 -
894 - /**
895 - * Get a resource path from a resourceName if no resource found return
896 - * false
897 - */
898 - getResourcePath: function( resourceName ) {
899 - if( this.resourcePaths[ resourceName ] )
900 - return this.resourcePaths[ resourceName ]
901 - return false;
902 - }
903 - }
904 -
905 - /**
906 - * Load done callback for script loader
907 - *
908 - * @param {String}
909 - * requestName Name of the load request
910 - */
911 - mw.loadDone = function( requestName ) {
912 - if( !mwLoadDoneCB[ requestName ] ) {
913 - return true;
914 - }
915 - while( mwLoadDoneCB[ requestName ].length ) {
916 - // check if mwLoadDoneCB is already "done"
917 - // the function list is not an object
918 - if( typeof mwLoadDoneCB[ requestName ] != 'object' )
919 - {
920 - break;
921 - }
922 - var func = mwLoadDoneCB[ requestName ].pop();
923 - if( typeof func == 'function' ) {
924 - // mw.log( "LoadDone: " + requestName + ' run callback::' +
925 - // func);
926 - func( requestName );
927 - }else{
928 - mw.log('mwLoadDoneCB: Error non callback function on stack');
929 - }
930 - }
931 - // Set the load request name to done
932 - mwLoadDoneCB[ requestName ] = 'done';
933 - };
934 -
935 - /**
936 - * Set a load done callback
937 - *
938 - * @param {String}
939 - * requestName Name of resource or request set
940 - * @param {Function}
941 - * callback Function called once requestName is ready
942 - */
943 - mw.setLoadDoneCB = function( requestName, callback ) {
944 - // If the requestName is already done loading just callback
945 - if( mwLoadDoneCB[ requestName ] == 'done' ) {
946 - callback( requestName )
947 - }
948 - // Setup the function queue if unset
949 - if( typeof mwLoadDoneCB[ requestName ] != 'object' ) {
950 - mwLoadDoneCB[ requestName ] = [];
951 - }
952 - mwLoadDoneCB[ requestName ].push( callback );
953 - };
954 -
955 - /**
956 - * Shortcut entry points / convenience functions: Lets you write mw.load()
957 - * instead of mw.loader.load() only these entry points should be used.
958 - *
959 - * future closure optimizations could minify internal function names
960 - */
961 -
962 - /**
963 - * Load Object entry point: Loads a requested set of javascript
964 - */
965 - mw.load = function( loadRequest, callback ) {
966 - return mw.loader.load( loadRequest, callback );
967 - }
968 -
969 - /**
970 - * Add module entry point: Adds a module to the mwLoader object
971 - */
972 - mw.addModuleLoader = function ( name, loaderFunction ) {
973 - return mw.loader.addModuleLoader( name, loaderFunction );
974 - }
975 -
976 - /**
977 - * Add Class File Paths entry point:
978 - */
979 - mw.addResourcePaths = function ( resourceSet ) {
980 - return mw.loader.addResourcePaths( resourceSet );
981 - }
982 -
983 - mw.addStyleResourceDependency = function ( resourceSet ) {
984 - return mw.loader.addStyleResourceDependency( resourceSet );
985 - }
986 -
987 - /**
988 - * Get Class File Path entry point:
989 - */
990 - mw.getResourcePath = function( resourceName ) {
991 - return mw.loader.getResourcePath( resourceName );
992 - }
993 -
994 -
995 - /**
996 - * Utility Functions
997 - */
998 -
999 - /**
1000 - * addLoaderDialog small helper for displaying a loading dialog
1001 - *
1002 - * @param {String}
1003 - * dialogHtml text Html of the loader msg
1004 - */
1005 - mw.addLoaderDialog = function( dialogHtml ) {
1006 - $dialog = mw.addDialog( {
1007 - 'title' : dialogHtml,
1008 - 'content' : dialogHtml + '<br>' +
1009 - $j('<div />')
1010 - .loadingSpinner()
1011 - .html()
1012 - });
1013 - return $dialog;
1014 - }
1015 -
1016 - /**
1017 - * Mobile Safari has special properties for html5 video::
1018 - *
1019 - * NOTE: should be moved to browser detection script
1020 - */
1021 - mw.isMobileSafari = function() {
1022 - // check mobile safari foce ( for debug )
1023 - if( mw.getConfig( 'forceMobileSafari' ) ){
1024 - return true;
1025 - }
1026 - if ((navigator.userAgent.indexOf('iPhone') != -1) ||
1027 - (navigator.userAgent.indexOf('iPod') != -1) ||
1028 - (navigator.userAgent.indexOf('iPad') != -1)) {
1029 - return true;
1030 - }
1031 - return false;
1032 - }
1033 -
1034 - /**
1035 - * Add a (temporary) dialog window:
1036 - *
1037 - * @param {Object} with following keys:
1038 - * title: {String} Title string for the dialog
1039 - * content: {String} to be inserted in msg box
1040 - * buttons: {Object} A button object for the dialog Can be a string
1041 - * for the close button
1042 - * any jquery.ui.dialog option
1043 - */
1044 - mw.addDialog = function ( options ) {
1045 - // Remove any other dialog
1046 - $j( '#mwTempLoaderDialog' ).remove();
1047 -
1048 - if( !options){
1049 - options = {};
1050 - }
1051 -
1052 - // Extend the default options with provided options
1053 - var options = $j.extend({
1054 - 'bgiframe': true,
1055 - 'draggable': true,
1056 - 'resizable': false,
1057 - 'modal': true
1058 - }, options );
1059 -
1060 - if( ! options.title || ! options.content ){
1061 - mw.log("Error: mwEmbed addDialog missing required options ( title, content ) ")
1062 - return ;
1063 - }
1064 -
1065 - // Append the dialog div on top:
1066 - $j( 'body' ).append(
1067 - $j('<div />')
1068 - .attr( {
1069 - 'id' : "mwTempLoaderDialog",
1070 - 'title' : options.title
1071 - })
1072 - .css({
1073 - 'display': 'none'
1074 - })
1075 - .append( options.content )
1076 - );
1077 -
1078 - // Build the uiRequest
1079 - var uiRequest = [ '$j.ui.dialog' ];
1080 - if( options.draggable ){
1081 - uiRequest.push( '$j.ui.draggable' )
1082 - }
1083 - if( options.resizable ){
1084 - uiRequest.push( '$j.ui.resizable' );
1085 - }
1086 -
1087 - // Special button string
1088 - if ( typeof options.buttons == 'string' ) {
1089 - var buttonMsg = options.buttons;
1090 - buttons = { };
1091 - options.buttons[ buttonMsg ] = function() {
1092 - $j( this ).dialog( 'close' );
1093 - }
1094 - }
1095 -
1096 - // Load the dialog resources
1097 - mw.load([
1098 - [
1099 - '$j.ui'
1100 - ],
1101 - uiRequest
1102 - ], function() {
1103 - $j( '#mwTempLoaderDialog' ).dialog( options );
1104 - } );
1105 - return $j( '#mwTempLoaderDialog' );
1106 - }
1107 -
1108 - /**
1109 - * Close the loader dialog created with addLoaderDialog
1110 - */
1111 - mw.closeLoaderDialog = function() {
1112 - // Make sure the dialog resource is present
1113 - if( !mw.isset( '$j.ui.dialog' ) ) {
1114 - return false;
1115 - }
1116 - $j( '#mwTempLoaderDialog' ).dialog( 'destroy' ).remove();
1117 - }
1118 -
1119 -
1120 - /**
1121 - * Similar to php isset function checks if the variable exists. Does a safe
1122 - * check of a descendant method or variable
1123 - *
1124 - * @param {String}
1125 - * objectPath
1126 - * @return {Boolean} true if objectPath exists false if objectPath is
1127 - * undefined
1128 - */
1129 - mw.isset = function( objectPath ) {
1130 - if ( !objectPath ) {
1131 - return false;
1132 - }
1133 - var pathSet = objectPath.split( '.' );
1134 - var cur_path = '';
1135 -
1136 - for ( var p = 0; p < pathSet.length; p++ ) {
1137 - cur_path = ( cur_path == '' ) ? cur_path + pathSet[p] : cur_path + '.' + pathSet[p];
1138 - eval( 'var ptest = typeof ( ' + cur_path + ' ); ' );
1139 - if ( ptest == 'undefined' ) {
1140 - return false;
1141 - }
1142 - }
1143 - return true;
1144 - }
1145 -
1146 - /**
1147 - * Wait for a object to be defined and the call the callback
1148 - *
1149 - * @param {Object}
1150 - * objectName Name of object to be defined
1151 - * @param {Function}
1152 - * callback Function to call once object is defined
1153 - * @param {Null}
1154 - * callNumber Used internally to keep track of number of times
1155 - * waitForObject has been called
1156 - */
1157 - var waitTime = 1200; // About 30 seconds
1158 - mw.waitForObject = function( objectName, callback, _callNumber) {
1159 - // mw.log( 'waitForObject: ' + objectName + ' cn: ' + _callNumber);
1160 -
1161 - // Increment callNumber:
1162 - if( !_callNumber ) {
1163 - _callNumber = 1;
1164 - } else {
1165 - _callNumber++;
1166 - }
1167 -
1168 - if( _callNumber > waitTime ) {
1169 - mw.log( "Error: waiting for object: " + objectName + ' timeout ' );
1170 - callback( false );
1171 - return ;
1172 - }
1173 -
1174 - // If the object is defined ( or we are done loading from a callback )
1175 - if ( mw.isset( objectName ) || mwLoadDoneCB[ objectName ] == 'done' ) {
1176 - callback( objectName )
1177 - }else{
1178 - setTimeout( function( ) {
1179 - mw.waitForObject( objectName, callback, _callNumber);
1180 - }, 25);
1181 - }
1182 - }
1183 -
1184 - /**
1185 - * Check if an object is empty or if its an empty string.
1186 - *
1187 - * @param {Object}
1188 - * object Object to be checked
1189 - */
1190 - mw.isEmpty = function( object ) {
1191 - if( typeof object == 'string' ) {
1192 - if( object == '' ) return true;
1193 - // Non empty string:
1194 - return false;
1195 - }
1196 -
1197 - // If an array check length:
1198 - if( Object.prototype.toString.call( object ) === "[object Array]"
1199 - && object.length == 0 ) {
1200 - return true;
1201 - }
1202 -
1203 - // Else check as an object:
1204 - for( var i in object ) { return false; }
1205 -
1206 - // Else object is empty:
1207 - return true;
1208 - }
1209 -
1210 - /**
1211 - * Log a string msg to the console
1212 - *
1213 - * all mw.log statements will be removed on minification so lots of mw.log
1214 - * calls will not impact performance in non debug mode
1215 - *
1216 - * @param {String}
1217 - * string String to output to console
1218 - */
1219 - mw.log = function( string ) {
1220 - // Add any prepend debug strings if necessary
1221 - if ( mw.getConfig( 'pre-append-log' ) ){
1222 - string = mw.getConfig( 'pre-append-log' ) + string;
1223 - }
1224 -
1225 - if ( window.console ) {
1226 - window.console.log( string );
1227 - } else {
1228 - /**
1229 - * Old IE and non-Firebug debug: ( commented out for now )
1230 - */
1231 - /*var log_elm = document.getElementById('mv_js_log');
1232 - if(!log_elm) {
1233 - document.getElementsByTagName("body")[0].innerHTML += '<div ' +
1234 - 'style="position:absolute;z-index:500;bottom:0px;left:0px;right:0px;height:200px;">' +
1235 - '<textarea id="mv_js_log" cols="120" rows="12"></textarea>' +
1236 - '</div>';
1237 - }
1238 - var log_elm = document.getElementById('mv_js_log');
1239 - if(log_elm) {
1240 - log_elm.value+=string+"\n";
1241 - }*/
1242 - }
1243 - }
1244 -
1245 - // Setup the local mwOnLoadFunctions array:
1246 - var mwOnLoadFunctions = [];
1247 -
1248 - // mw Ready flag ( set once mwEmbed is ready )
1249 - var mwReadyFlag = false;
1250 -
1251 - /**
1252 - * Enables load hooks to run once mwEmbeed is "ready" Will ensure jQuery is
1253 - * available, is in the $j namespace and mw interfaces and configuration has
1254 - * been loaded and applied
1255 - *
1256 - * This is different from jQuery(document).ready() ( jQuery ready is not
1257 - * friendly with dynamic includes and not friendly with core interface
1258 - * asynchronous build out. )
1259 - *
1260 - * @param {Function}
1261 - * callback Function to run once DOM and jQuery are ready
1262 - */
1263 - mw.ready = function( callback ) {
1264 - if( mwReadyFlag === false ) {
1265 - // Add the callbcak to the onLoad function stack
1266 - mwOnLoadFunctions.push ( callback );
1267 - } else {
1268 - // If mwReadyFlag is already "true" issue the callback directly:
1269 - callback();
1270 - }
1271 - }
1272 -
1273 - /**
1274 - * Runs all the queued functions called by mwEmbedSetup
1275 - */
1276 - mw.runReadyFunctions = function ( ) {
1277 - mw.log('mw.runReadyFunctions: ' + mwOnLoadFunctions.length );
1278 - // Run any pre-setup ready functions
1279 - while( preMwEmbedReady.length ){
1280 - preMwEmbedReady.shift()();
1281 - }
1282 - // Run all the queued functions:
1283 - while( mwOnLoadFunctions.length ) {
1284 - mwOnLoadFunctions.shift()();
1285 - }
1286 -
1287 - // Sets mwReadyFlag to true so that future mw.ready run the
1288 - // callback directly
1289 - mwReadyFlag = true;
1290 -
1291 - // Once we have run all the queued functions
1292 - mw.loader.runModuleLoadQueue();
1293 -
1294 - }
1295 -
1296 -
1297 - /**
1298 - * Wrapper for jQuery getScript, Uses the scriptLoader if enabled
1299 - *
1300 - *
1301 - * @param {String}
1302 - * scriptRequest The requested path or resourceNames for the
1303 - * scriptLoader
1304 - * @param {Function}
1305 - * callback Function to call once script is loaded
1306 - */
1307 - mw.getScript = function( scriptRequest, callback ) {
1308 - // mw.log( "mw.getScript::" + scriptRequest );
1309 - // Setup the local scope callback instace
1310 - var myCallback = function(){
1311 - if( callback ) {
1312 - callback( scriptRequest );
1313 - }
1314 - }
1315 - // Set the base url based scriptLoader availability & type of
1316 - // scriptRequest
1317 - // ( presently script loader only handles "classes" not relative urls:
1318 - var scriptLoaderPath = mw.getResourceLoaderPath();
1319 -
1320 - // Check if its a resource name, ( ie does not start with "/" and does
1321 - // not include ://
1322 - var isResourceName = ( scriptRequest.indexOf('://') == -1 && scriptRequest.indexOf('/') !== 0 )? true : false;
1323 -
1324 - var ext = scriptRequest.substr( scriptRequest.lastIndexOf( '.' ), 4 ).toLowerCase();
1325 - var isCssFile = ( ext == '.css') ? true : false ;
1326 -
1327 - if( scriptLoaderPath && isResourceName ) {
1328 - url = scriptLoaderPath + '?class=' + scriptRequest;
1329 - } else {
1330 - // Add the mwEmbed path if a relative path request
1331 - url = ( isResourceName ) ? mw.getMwEmbedPath() : '';
1332 - url+= scriptRequest;
1333 - }
1334 -
1335 - // Add on the request parameters to the url:
1336 - url += ( url.indexOf( '?' ) == -1 )? '?' : '&';
1337 - url += mw.getUrlParam();
1338 -
1339 - // Only log sciprts ( Css is logged via "add css" )
1340 - if( !isCssFile ){
1341 - mw.log( 'mw.getScript: ' + url );
1342 - }
1343 -
1344 - // If jQuery is available and debug is off load the scirpt via jQuery
1345 - // ( will use XHR if on same domain )
1346 - if( mw.isset( 'window.jQuery' )
1347 - && mw.getConfig( 'debug' ) === false
1348 - && typeof $j != 'undefined'
1349 - && !isCssFile )
1350 - {
1351 - $j.getScript( url, myCallback);
1352 - return ;
1353 - }
1354 -
1355 - /**
1356 - * No jQuery OR In debug mode OR Is css file
1357 - * :: inject the script instead of doing an XHR eval
1358 - */
1359 -
1360 - // load style sheet directly if requested loading css
1361 - if( isCssFile ){
1362 - mw.getStyleSheet( url, myCallback);
1363 - return ;
1364 - }
1365 -
1366 - // Load and bind manually: ( copied from jQuery ajax function )
1367 - var head = document.getElementsByTagName("head")[ 0 ];
1368 - var script = document.createElement("script");
1369 - script.setAttribute( 'src', url );
1370 -
1371 - // Attach handlers ( if using script loader it issues onDone callback as
1372 - // well )
1373 - script.onload = script.onreadystatechange = function() {
1374 - if (!this.readyState || this.readyState == "loaded" || this.readyState == "complete") {
1375 - myCallback();
1376 - }
1377 - };
1378 - // mw.log(" append script: " + script.src );
1379 - // Append the script to the DOM:
1380 - head.appendChild( script );
1381 - };
1382 -
1383 - /**
1384 - * Add a style sheet string to the document head
1385 - *
1386 - * @param {String}
1387 - * cssResourceName Name of style sheet that has been defined
1388 - * @param {String}
1389 - * cssString Css Payload to be added to head of document
1390 - */
1391 - mw.addStyleString = function( cssResourceName, cssString ) {
1392 - if( mw.style[ cssResourceName ] ) {
1393 - mw.log(" Style: ( " + cssResourceName + ' ) already set' );
1394 - return true;
1395 - }
1396 - // Set the style to true ( to not request it again )
1397 - mw.style[ cssResourceName ] = true;
1398 - // Add the spinner directly ( without jQuery in case we have to
1399 - // dynamically load jQuery )
1400 - mw.log( 'Adding style:' + cssResourceName + " to dom " );
1401 - var styleNode = document.createElement('style');
1402 - styleNode.type = "text/css";
1403 - // Use cssText or createTextNode depending on browser:
1404 - if( ( window.attachEvent && !window.opera ) ) {
1405 - styleNode.styleSheet.cssText = cssString;
1406 - } else {
1407 - var styleText = document.createTextNode( cssString );
1408 - styleNode.appendChild( styleText );
1409 - }
1410 - var head = document.getElementsByTagName("head")[0];
1411 - head.appendChild( styleNode );
1412 - };
1413 -
1414 - /**
1415 - * Get a style sheet and append the style sheet to the DOM
1416 - *
1417 - * @param {Mixed}
1418 - * {String} url Url of the style sheet to be loaded {Function}
1419 - * callback Function called once sheet is ready
1420 - */
1421 - mw.getStyleSheet = function( url , callback) {
1422 - // Add URL params ( if not already included )
1423 - if ( url.indexOf( '?' ) == -1 ) {
1424 - url += '?' + mw.getUrlParam();
1425 - }
1426 -
1427 - // Check if style sheet is already included:
1428 - var foundSheet = false;
1429 - $j( 'link' ).each( function() {
1430 - var currentSheet = $j( this) .attr( 'href' );
1431 - var sheetParts = currentSheet.split('?');
1432 - var urlParts = url.split('?');
1433 - // if the base url's match check the parameters:
1434 - if( sheetParts[0] == urlParts[0] && sheetParts[1]) {
1435 - // Check if url params match ( sort to do string compare )
1436 - if( sheetParts[1].split( '&' ).sort().join('') ==
1437 - urlParts[1].split('&').sort().join('') ) {
1438 - foundSheet = true;
1439 - }
1440 - }
1441 - } );
1442 - if( foundSheet ) {
1443 - mw.log( 'skiped sheet: ' + url);
1444 - if( callback) {
1445 - callback();
1446 - }
1447 - return ;
1448 - }
1449 -
1450 - mw.log( ' add css: ' + url );
1451 - $j( 'head' ).append(
1452 - $j('<link />').attr( {
1453 - 'rel' : 'stylesheet',
1454 - 'type' : 'text/css',
1455 - 'href' : url
1456 - } )
1457 - );
1458 - // No easy way to check css "onLoad" attribute
1459 - // In production sheets are loaded via resource loader and fire the
1460 - // onDone function call.
1461 - if( callback ) {
1462 - callback();
1463 - }
1464 - };
1465 -
1466 -
1467 - // Local mwEmbedPath variable ( for cache of mw.getMwEmbedPath )
1468 - var mwEmbedPath = null;
1469 -
1470 - /**
1471 - * Get the path to the mwEmbed folder
1472 - */
1473 - mw.getMwEmbedPath = function() {
1474 - if ( mwEmbedPath ) {
1475 - return mwEmbedPath;
1476 - }
1477 -
1478 - // Get mwEmbed src:
1479 - var src = mw.getMwEmbedSrc();
1480 - var mwpath = null;
1481 -
1482 - // Check for direct include of the mwEmbed.js
1483 - if ( src.indexOf( 'mwEmbed.js' ) !== -1 ) {
1484 - mwpath = src.substr( 0, src.indexOf( 'mwEmbed.js' ) );
1485 - }
1486 -
1487 - // Check for scriptLoader include of mwEmbed:
1488 - if ( src.indexOf( 'mwResourceLoader.php' ) !== -1 ) {
1489 - // Script loader is in the root of MediaWiki, Include the default
1490 - // mwEmbed extension path:
1491 - mwpath = src.substr( 0, src.indexOf( 'mwResourceLoader.php' ) ) + mw.getConfig( 'mediaWikiEmbedPath' );
1492 - }
1493 -
1494 - // resource loader has ResourceLoader name when local:
1495 - if( src.indexOf( 'ResourceLoader.php' ) !== -1 ) {
1496 - mwpath = src.substr( 0, src.indexOf( 'ResourceLoader.php' ) );
1497 - }
1498 -
1499 - // For static packages mwEmbed packages start with: "mwEmbed-"
1500 - if( src.indexOf( 'mwEmbed-' ) !== -1 && src.indexOf( '-static' ) !== -1 ) {
1501 - mwpath = src.substr( 0, src.indexOf( 'mwEmbed-' ) );
1502 - }
1503 -
1504 - // Error out if we could not get the path:
1505 - if( mwpath === null ) {
1506 - mw.log( "Error could not get mwEmbed path " );
1507 - return ;
1508 - }
1509 -
1510 - // Update the cached var with the absolute path:
1511 - mwEmbedPath = mw.absoluteUrl( mwpath ) ;
1512 - return mwEmbedPath;
1513 - }
1514 -
1515 - /**
1516 - * Get Script loader path
1517 - *
1518 - * @returns {String}|{Boolean} Url of the scriptLodaer false if the
1519 - * scriptLoader is not used
1520 - */
1521 - mw.getResourceLoaderPath = function( ) {
1522 - var src = mw.getMwEmbedSrc();
1523 - if ( src.indexOf( 'mwResourceLoader.php' ) !== -1 ||
1524 - src.indexOf( 'ResourceLoader.php' ) !== -1 )
1525 - {
1526 - // Return just the script part of the url
1527 - return src.split('?')[0];
1528 - }
1529 - return false;
1530 - }
1531 -
1532 - /**
1533 - * Given a float number of seconds, returns npt format response. ( ignore
1534 - * days for now )
1535 - *
1536 - * @param {Float}
1537 - * sec Seconds
1538 - * @param {Boolean}
1539 - * show_ms If milliseconds should be displayed.
1540 - * @return {Float} String npt format
1541 - */
1542 - mw.seconds2npt = function( sec, show_ms ) {
1543 - if ( isNaN( sec ) ) {
1544 - mw.log("Warning: trying to get npt time on NaN:" + sec);
1545 - return '0:00:00';
1546 - }
1547 -
1548 - var tm = mw.seconds2Measurements( sec )
1549 -
1550 - // Round the number of seconds to the required number of significant
1551 - // digits
1552 - if ( show_ms ) {
1553 - tm.seconds = Math.round( tm.seconds * 1000 ) / 1000;
1554 - } else {
1555 - tm.seconds = Math.round( tm.seconds );
1556 - }
1557 - if ( tm.seconds < 10 ){
1558 - tm.seconds = '0' + tm.seconds;
1559 - }
1560 - if( tm.hours == 0 ){
1561 - hoursStr = ''
1562 - } else {
1563 - if ( tm.minutes < 10 )
1564 - tm.minutes = '0' + tm.minutes;
1565 -
1566 - hoursStr = tm.hours + ":";
1567 - }
1568 - return hoursStr + tm.minutes + ":" + tm.seconds;
1569 - }
1570 -
1571 - /**
1572 - * Given seconds return array with 'days', 'hours', 'min', 'seconds'
1573 - *
1574 - * @param {float}
1575 - * sec Seconds to be converted into time measurements
1576 - */
1577 - mw.seconds2Measurements = function ( sec ){
1578 - var tm = {};
1579 - tm.days = Math.floor( sec / ( 3600 * 24 ) )
1580 - tm.hours = Math.floor( sec / 3600 );
1581 - tm.minutes = Math.floor( ( sec / 60 ) % 60 );
1582 - tm.seconds = sec % 60;
1583 - return tm;
1584 - }
1585 -
1586 - /**
1587 - * Take hh:mm:ss,ms or hh:mm:ss.ms input, return the number of seconds
1588 - *
1589 - * @param {String}
1590 - * npt_str NPT time string
1591 - * @return {Float} Number of seconds
1592 - */
1593 - mw.npt2seconds = function ( npt_str ) {
1594 - if ( !npt_str ) {
1595 - // mw.log('npt2seconds:not valid ntp:'+ntp);
1596 - return false;
1597 - }
1598 - // Strip {npt:}01:02:20 or 32{s} from time if present
1599 - npt_str = npt_str.replace( /npt:|s/g, '' );
1600 -
1601 - var hour = 0;
1602 - var min = 0;
1603 - var sec = 0;
1604 -
1605 - times = npt_str.split( ':' );
1606 - if ( times.length == 3 ) {
1607 - sec = times[2];
1608 - min = times[1];
1609 - hour = times[0];
1610 - } else if ( times.length == 2 ) {
1611 - sec = times[1];
1612 - min = times[0];
1613 - } else {
1614 - sec = times[0];
1615 - }
1616 - // Sometimes a comma is used instead of period for ms
1617 - sec = sec.replace( /,\s?/, '.' );
1618 - // Return seconds float
1619 - return parseInt( hour * 3600 ) + parseInt( min * 60 ) + parseFloat( sec );
1620 - }
1621 -
1622 - // Local mwEmbedSrc variable ( for cache of mw.getMwEmbedSrc )
1623 - var mwEmbedSrc = null;
1624 -
1625 - /**
1626 - * Gets the mwEmbed script src attribute
1627 - */
1628 - mw.getMwEmbedSrc = function() {
1629 - if ( mwEmbedSrc ) {
1630 - return mwEmbedSrc;
1631 - }
1632 -
1633 - // Get all the javascript includes:
1634 - var js_elements = document.getElementsByTagName( "script" );
1635 - for ( var i = 0; i < js_elements.length; i++ ) {
1636 - // Check for mwEmbed.js and/or script loader
1637 - var src = js_elements[i].getAttribute( "src" );
1638 - if ( src ) {
1639 - if ( // Check for mwEmbed.js ( debug mode )
1640 - ( src.indexOf( 'mwEmbed.js' ) !== -1 && src.indexOf( 'MediaWiki:Gadget') == -1 )
1641 - || // Check for resource loader
1642 - (
1643 - ( src.indexOf( 'mwResourceLoader.php' ) !== -1 || src.indexOf( 'ResourceLoader.php' ) !== -1 )
1644 - &&
1645 - src.indexOf( 'mwEmbed' ) !== -1
1646 - )
1647 - || // Check for static mwEmbed package
1648 - ( src.indexOf( 'mwEmbed' ) !== -1 && src.indexOf( 'static' ) !== -1 )
1649 - ) {
1650 - mwEmbedSrc = src;
1651 - return mwEmbedSrc;
1652 - }
1653 - }
1654 - }
1655 - mw.log( 'Error: getMwEmbedSrc failed to get script path' );
1656 - return false;
1657 - }
1658 -
1659 - // Local mwUrlParam variable ( for cache of mw.getUrlParam )
1660 - var mwUrlParam = null;
1661 -
1662 - /**
1663 - * Get URL Parameters per parameters in the host script include
1664 - */
1665 - mw.getUrlParam = function() {
1666 - if ( mwUrlParam ) {
1667 - return mwUrlParam;
1668 - }
1669 -
1670 - var mwEmbedSrc = mw.getMwEmbedSrc();
1671 - var req_param = '';
1672 -
1673 - // If we already have a URI, add it to the param request:
1674 - var urid = mw.parseUri( mwEmbedSrc ).queryKey['urid']
1675 -
1676 - // If we're in debug mode, get a fresh unique request key and pass on
1677 - // "debug" param
1678 - if ( mw.parseUri( mwEmbedSrc ).queryKey['debug'] == 'true' ) {
1679 - mw.setConfig( 'debug', true );
1680 - var d = new Date();
1681 - req_param += 'urid=' + d.getTime() + '&debug=true';
1682 -
1683 - } else if ( urid ) {
1684 - // Just pass on the existing urid:
1685 - req_param += 'urid=' + urid;
1686 - } else {
1687 - // Otherwise, Use the mwEmbed version
1688 - req_param += 'urid=' + mw.version;
1689 - }
1690 -
1691 - // Add the language param if present:
1692 - var langKey = mw.parseUri( mwEmbedSrc ).queryKey['uselang'];
1693 - if ( langKey )
1694 - req_param += '&uselang=' + langKey;
1695 -
1696 - // Update the local cache and return the value
1697 - mwUrlParam = req_param;
1698 - return mwUrlParam;
1699 - }
1700 -
1701 - /**
1702 - * Replace url parameters via newParams key value pairs
1703 - *
1704 - * @param {String}
1705 - * url Source url to be updated
1706 - * @param {Object}
1707 - * newParams key, value paris to swap in
1708 - * @return {String} the updated url
1709 - */
1710 - mw.replaceUrlParams = function( url, newParams ) {
1711 - var parsedUrl = mw.parseUri( url );
1712 -
1713 - if ( parsedUrl.protocol != '' ) {
1714 - var new_url = parsedUrl.protocol + '://' + parsedUrl.authority + parsedUrl.path + '?';
1715 - } else {
1716 - var new_url = parsedUrl.path + '?';
1717 - }
1718 -
1719 - // Merge new params:
1720 - for( var key in newParams ) {
1721 - parsedUrl.queryKey[ key ] = newParams[ key ];
1722 - }
1723 -
1724 - // Output to new_url
1725 - var amp = '';
1726 - for ( var key in parsedUrl.queryKey ) {
1727 - var val = parsedUrl.queryKey[ key ];
1728 - new_url += amp + key + '=' + val;
1729 - amp = '&';
1730 - }
1731 - return new_url;
1732 - }
1733 -
1734 - /**
1735 - * parseUri 1.2.2 (c) Steven Levithan <stevenlevithan.com> MIT License
1736 - */
1737 - mw.parseUri = function (str) {
1738 - var o = mw.parseUri.options,
1739 - m = o.parser[o.strictMode ? "strict" : "loose"].exec(str),
1740 - uri = {},
1741 - i = 14;
1742 -
1743 - while (i--) uri[o.key[i]] = m[i] || "";
1744 -
1745 - uri[o.q.name] = {};
1746 - uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) {
1747 - if ($1) uri[o.q.name][$1] = $2;
1748 - });
1749 -
1750 - return uri;
1751 - };
1752 -
1753 - /**
1754 - * Parse URI function
1755 - *
1756 - * For documentation on its usage see:
1757 - * http://stevenlevithan.com/demo/parseuri/js/
1758 - */
1759 - mw.parseUri.options = {
1760 - strictMode: false,
1761 - key: ["source", "protocol", "authority", "userInfo", "user", "password", "host",
1762 - "port", "relative", "path", "directory", "file", "query", "anchor"],
1763 - q: {
1764 - name: "queryKey",
1765 - parser: /(?:^|&)([^&=]*)=?([^&]*)/g
1766 - },
1767 - parser: {
1768 - strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
1769 - loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
1770 - }
1771 - };
1772 -
1773 - /**
1774 - * getAbsoluteUrl takes a src and returns the absolute location given the
1775 - * document.URL
1776 - *
1777 - * @param {String}
1778 - * src path or url
1779 - * @return {String} absolute url
1780 - */
1781 - mw.absoluteUrl = function( src, contextUrl ) {
1782 - var parsedSrc = mw.parseUri( src );
1783 - // Source is already absolute return:
1784 - if( parsedSrc.protocol != '') {
1785 - return src;
1786 - }
1787 -
1788 - // Get parent Url location the context URL
1789 - if( contextUrl) {
1790 - var parsedUrl = mw.parseUri( contextUrl );
1791 - } else {
1792 - var parsedUrl = mw.parseUri( document.URL );
1793 - }
1794 -
1795 - // Check for leading slash:
1796 - if( src.indexOf( '/' ) === 0 ) {
1797 - return parsedUrl.protocol + '://' + parsedUrl.authority + src;
1798 - }else{
1799 - return parsedUrl.protocol + '://' + parsedUrl.authority + parsedUrl.directory + src;
1800 - }
1801 - };
1802 -
1803 - /**
1804 - * Escape quotes in a text string
1805 - *
1806 - * @param {String}
1807 - * text String to be escaped
1808 - * @return {string} escaped text string
1809 - */
1810 - mw.escapeQuotes = function( text ) {
1811 - var re = new RegExp("'","g");
1812 - text = text.replace(re,"\\'");
1813 - re = new RegExp("\\n","g");
1814 - text = text.replace(re,"\\n");
1815 - return mw.escapeQuotesHTML(text);
1816 - };
1817 -
1818 - /**
1819 - * Escape an HTML text string
1820 - *
1821 - * @param {String}
1822 - * text String to be escaped
1823 - * @return {string} escaped text html string
1824 - */
1825 - mw.escapeQuotesHTML = function( text ) {
1826 - var replaceMap = {
1827 - "&" : "&amp;",
1828 - '"' : "&quot;",
1829 - '<' : "&lt;",
1830 - '>' : "&gt;"
1831 - }
1832 - for( var i in replaceMap ){
1833 - text = text.split(i).join( replaceMap[i]);
1834 - }
1835 - return text;
1836 - };
1837 -
1838 - // Array of setup functions
1839 - var mwSetupFunctions = [];
1840 -
1841 - /**
1842 - * Add a function to be run during setup ( prior to mw.ready) this is useful
1843 - * for building out interfaces that should be ready before mw.ready is
1844 - * called.
1845 - *
1846 - * @param {callback}
1847 - * Function Callback function must accept a ready function
1848 - * callback to be called once setup is done
1849 - */
1850 - mw.addSetupHook = function( callback ) {
1851 - mwSetupFunctions.push ( callback ) ;
1852 - };
1853 -
1854 - /**
1855 - * One time "setup" for mwEmbed run onDomReady ( so calls to setConfg apply
1856 - * to setup )
1857 - */
1858 - // Flag to ensure setup is only run once:
1859 - var mwSetupFlag = false;
1860 - mw.setupMwEmbed = function ( ) {
1861 - // Only run the setup once:
1862 - if( mwSetupFlag ) {
1863 - return ;
1864 - }
1865 - mwSetupFlag = true;
1866 -
1867 - // Apply any pre-setup config:
1868 - mw.setConfig( preMwEmbedConfig );
1869 -
1870 -
1871 - mw.log( 'mw:setupMwEmbed SRC:: ' + mw.getMwEmbedSrc() );
1872 -
1873 - // Check core mwEmbed loader.js file ( to get configuration and paths )
1874 - mw.checkCoreLoaderFile( function(){
1875 - // Make sure we have jQuery
1876 - mw.load( 'window.jQuery', function() {
1877 -
1878 - // Add jQuery to $j var.
1879 - if ( ! window[ '$j' ] ) {
1880 - window[ '$j' ] = jQuery.noConflict();
1881 - }
1882 -
1883 - // Get module loader.js, and language files
1884 - // ( will hit callback directly if set via resource loader )
1885 - mw.checkModuleLoaderFiles( function() {
1886 -
1887 - // Set the User language
1888 - if( typeof wgUserLanguage != 'undefined' && mw.isValidLang( wgUserLanguage) ) {
1889 - mw.setConfig( 'userLanguage', wgUserLanguage )
1890 - }else{
1891 - // Grab it from the included url
1892 - var langKey = mw.parseUri( mw.getMwEmbedSrc() ).queryKey['uselang'];
1893 - if ( langKey && mw.isValidLang( langKey ) ) {
1894 - mw.setConfig( 'userLanguage', langKey);
1895 - }
1896 - }
1897 -
1898 - // Update the image path
1899 - mw.setConfig( 'imagesPath', mw.getMwEmbedPath() + 'skins/common/images/' );
1900 -
1901 - // Set up AJAX to not send dynamic URLs for loading scripts
1902 - $j.ajaxSetup( {
1903 - cache: true
1904 - } );
1905 -
1906 - // Update the magic keywords
1907 - mw.Language.magicSetup();
1908 -
1909 - // Set up mvEmbed utility jQuery bindings
1910 - mw.dojQueryBindings();
1911 -
1912 -
1913 - // Special Hack for conditional jquery ui inclusion ( once
1914 - // Usability extension
1915 - // registers the jquery.ui skin in mw.style
1916 - if( mw.hasJQueryUiCss() ){
1917 - mw.style[ 'ui_' + mw.getConfig( 'jQueryUISkin' ) ] = true;
1918 - }
1919 -
1920 -
1921 - // Make sure style sheets are loaded:
1922 - mw.load( ['mw.style.mwCommon'] , function(){
1923 - // Run all the setup function hooks
1924 - // NOTE: setup functions are added via addSetupHook
1925 - // calls
1926 - // and must include a callback.
1927 - //
1928 - // Once complete we can run .ready() queued functions
1929 - function runSetupFunctions() {
1930 - if( mwSetupFunctions.length ) {
1931 - mwSetupFunctions.shift()( function() {
1932 - runSetupFunctions();
1933 - } );
1934 - }else{
1935 - mw.runReadyFunctions();
1936 - }
1937 - }
1938 - runSetupFunctions();
1939 - } );
1940 -
1941 - } );
1942 - });
1943 - });
1944 - };
1945 -
1946 - /**
1947 - * Checks for jquery ui css by name jquery-ui-1.7.2.css NOTE: this is a hack
1948 - * for usability jquery-ui in the future usability should register a
1949 - * resource in mw.skin
1950 - *
1951 - * @return true if found, return false if not found
1952 - */
1953 - mw.hasJQueryUiCss = function(){
1954 - var hasUiCss = false;
1955 - // Load the jQuery ui skin if usability skin not set
1956 - $j( 'link' ).each( function( na, linkNode ){
1957 - if( $j( linkNode ).attr( 'href' ).indexOf( 'jquery-ui-1.7.2.css' ) != -1 ) {
1958 - hasUiCss = true;
1959 - return true;
1960 - }
1961 - } );
1962 - // Check all the "style" nodes for @import of jquery-ui-1.7.2.css
1963 - // xxx Note: we could do this a bit cleaner with regEx
1964 - $j( 'style' ).each( function( na, styleNode ){
1965 - if( $j( styleNode ).text().indexOf( '@import' ) != -1
1966 - && $j( styleNode ).text().indexOf( 'jquery-ui-1.7.2.css' ) != -1 ){
1967 - hasUiCss=true;
1968 - }
1969 - });
1970 -
1971 - return hasUiCss;
1972 - }
1973 -
1974 - /**
1975 - * Loads the core mwEmbed "loader.js" file config
1976 - *
1977 - * NOTE: if using the ScriptLoader all the loaders and localization
1978 - * converters are included automatically
1979 - *
1980 - * @param {Function}
1981 - * callback Function called once core loader file is loaded
1982 - */
1983 - mw.checkCoreLoaderFile = function( callback ) {
1984 - // Check if we are using scriptloader ( handles loader include
1985 - // automatically )
1986 - if( mw.getResourceLoaderPath() ) {
1987 - callback();
1988 - return ;
1989 - }
1990 -
1991 - // Check if we are using a static package ( mwEmbed path includes
1992 - // -static )
1993 - if( mw.isStaticPackge() ){
1994 - callback();
1995 - return ;
1996 - }
1997 -
1998 - // Add the Core loader to the request
1999 - // The follow code is ONLY RUN in debug / raw file mode
2000 - mw.load( 'loader.js', callback );
2001 - }
2002 -
2003 - /**
2004 - * Checks if the javascript is a static package ( not using resource loader )
2005 - *
2006 - * @return {boolean} true the included script is static false the included
2007 - * script
2008 - */
2009 - mw.isStaticPackge = function(){
2010 - var src = mw.getMwEmbedSrc();
2011 - if( src.indexOf('-static') !== -1 ){
2012 - return true;
2013 - }
2014 - return false;
2015 - }
2016 -
2017 - /**
2018 - * Check for resource loader module loaders, and localization files
2019 - *
2020 - * NOTE: if using the ScriptLoader all the loaders and localization
2021 - * converters are included automatically.
2022 - */
2023 - mw.checkModuleLoaderFiles = function( callback ) {
2024 - mw.log( 'doLoaderCheck::' );
2025 -
2026 - // Check if we are using scriptloader ( handles loader include
2027 - // automatically )
2028 - // Or if mwEmbed is a static package ( all resources are already loaded
2029 - // )
2030 - if( mw.getResourceLoaderPath() || mw.isStaticPackge() ) {
2031 - callback();
2032 - return ;
2033 - }
2034 -
2035 - // Load the configured modules / components
2036 - // The follow code is ONLY RUN in debug / raw file mode
2037 - var loaderRequest = [];
2038 -
2039 - // Load enabled components
2040 - var enabledComponents = mw.getConfig( 'coreComponents' );
2041 - function loadEnabledComponents( enabledComponents ){
2042 - if( ! enabledComponents.length ){
2043 - // If no more components load modules::
2044 -
2045 - // Add the enabledModules loaders:
2046 - var enabledModules = mw.getConfig( 'enabledModules' );
2047 - loadEnabledModules( enabledModules );
2048 - return ;
2049 - }
2050 - var componentName = enabledComponents.shift();
2051 - mw.load( componentName, function(){
2052 - loadEnabledComponents( enabledComponents );
2053 - } );
2054 - }
2055 - loadEnabledComponents( enabledComponents );
2056 -
2057 -
2058 - // Set the loader context and get each loader individually
2059 - function loadEnabledModules( enabledModules ){
2060 - if( ! enabledModules.length ){
2061 - // If no more modules left load the LanguageFile
2062 - addLanguageFile();
2063 - return ;
2064 - }
2065 - var moduleName = enabledModules.shift();
2066 - mw.setConfig( 'loaderContext', 'modules/' + moduleName + '/' );
2067 - mw.load( 'modules/' + moduleName + '/loader.js', function(){
2068 - loadEnabledModules( enabledModules );
2069 - } );
2070 - }
2071 -
2072 - function addLanguageFile(){
2073 - // Add the language file
2074 - var langLoaderRequest = [];
2075 -
2076 - if( mw.getConfig( 'userLanguage' ) ) {
2077 - var langCode = mw.getConfig( 'userLanguage' );
2078 -
2079 - // Load the language resource if not default 'en'
2080 - var transformKey = mw.getLangTransformKey( langCode );
2081 - if( transformKey != 'en' ){
2082 - // Upper case the first letter:
2083 - langCode = langCode.substr(0,1).toUpperCase() + langCode.substr( 1, langCode.length );
2084 - langLoaderRequest.push( 'languages/classes/Language' +
2085 - langCode + '.js' );
2086 - }
2087 -
2088 - }
2089 - if ( ! langLoaderRequest.length ) {
2090 - callback();
2091 - return ;
2092 - }
2093 -
2094 - // Load the launage if set
2095 - mw.load( langLoaderRequest, function(){
2096 - mw.log( 'Done moduleLoaderCheck request' );
2097 - // Set the mwModuleLoaderCheckFlag flag to true
2098 - mwModuleLoaderCheckFlag = true;
2099 - callback();
2100 - } );
2101 - }
2102 -
2103 - }
2104 -
2105 - /**
2106 - * Checks if a css style rule exists
2107 - *
2108 - * On a page with lots of rules it can take some time so avoid calling this
2109 - * function where possible and cache its result
2110 - *
2111 - * NOTE: this only works for style sheets on the same domain :(
2112 - *
2113 - * @param {String}
2114 - * styleRule Style rule name to check
2115 - * @return {Boolean} true if the rule exists false if the rule does not
2116 - * exist
2117 - */
2118 - mw.styleRuleExists = function ( styleRule ) {
2119 - // Set up the skin paths configuration
2120 - for( var i=0 ; i < document.styleSheets.length ; i++ ) {
2121 - var rules = null;
2122 - try{
2123 - if ( document.styleSheets[i].cssRules )
2124 - rules = document.styleSheets[i].cssRules
2125 - else if (document.styleSheets[0].rules)
2126 - rules = document.styleSheets[i].rules
2127 - for(var j=0 ; j < rules.length ; j++ ) {
2128 - var rule = rules[j].selectorText;
2129 - if( rule && rule.indexOf( styleRule ) != -1 ) {
2130 - return true;
2131 - }
2132 - }
2133 - }catch ( e ) {
2134 - mw.log( 'Error: cant check rule on cross domain style sheet:' + document.styleSheets[i].href );
2135 - }
2136 - }
2137 - return false;
2138 - }
2139 -
2140 - // Flag to register the domReady has been called
2141 - var mwDomReadyFlag = false;
2142 -
2143 - // Flag to register if the domreadyHooks have been called
2144 - var mwModuleLoaderCheckFlag = false;
2145 -
2146 - /**
2147 - * This will get called when the DOM is ready Will check configuration and
2148 - * issue a mw.setupMwEmbed call if needed
2149 - */
2150 - mw.domReady = function ( ) {
2151 - if( mwDomReadyFlag ) {
2152 - return ;
2153 - }
2154 - mw.log( 'run:domReady:: ' + document.getElementsByTagName('video').length );
2155 - // Set the onDomReady Flag
2156 - mwDomReadyFlag = true;
2157 -
2158 - // Give us a chance to get to the bottom of the script.
2159 - // When loading mwEmbed asynchronously the dom ready gets called
2160 - // directly and in some browsers beets the $j = jQuery.noConflict();
2161 - // call
2162 - // and causes symbol undefined errors.
2163 - setTimeout(function(){
2164 - mw.setupMwEmbed();
2165 - },1);
2166 - }
2167 -
2168 - /**
2169 - * A version comparison utility function Handles version of types
2170 - * {Major}.{MinorN}.{Patch}
2171 - *
2172 - * Note this just handles version numbers not patch letters.
2173 - *
2174 - * @param {String}
2175 - * minVersion Minnium version needed
2176 - * @param {String}
2177 - * clientVersion Client version to be checked
2178 - *
2179 - * @return true if the version is at least of minVersion false if the
2180 - * version is less than minVersion
2181 - */
2182 - mw.versionIsAtLeast = function( minVersion, clientVersion ) {
2183 - var minVersionParts = minVersion.split('.')
2184 - var clientVersionParts = clientVersion.split('.');
2185 - for( var i =0; i < minVersionParts.length; i++ ) {
2186 - if( parseInt( clientVersionParts[i] ) > parseInt( minVersionParts[i] ) ) {
2187 - return true;
2188 - }
2189 - if( parseInt( clientVersionParts[i] ) < parseInt( minVersionParts[i] ) ) {
2190 - return false;
2191 - }
2192 - }
2193 - // Same version:
2194 - return true;
2195 - }
2196 -
2197 - /**
2198 - * Runs all the triggers on a given object with a single "callback"
2199 - *
2200 - * Normal tirgger calls will run the callback directly multiple times for
2201 - * every binded function.
2202 - *
2203 - * With runTriggersCallback() callback is not called until all the binded
2204 - * events have been run.
2205 - *
2206 - * @param {object}
2207 - * targetObject Target object to run triggers on
2208 - * @param {string}
2209 - * triggerName Name of trigger to be run
2210 - * @param {function}
2211 - * callback Function called once all triggers have been run
2212 - *
2213 - */
2214 - mw.runTriggersCallback = function( targetObject, triggerName, callback ){
2215 - mw.log( ' runTriggersCallback:: ' + triggerName );
2216 - // If events are not present directly run callback
2217 - if( ! $j( targetObject ).data( 'events' ) ||
2218 - ! $j( targetObject ).data( 'events' )[ triggerName ] ) {
2219 - mw.log( ' trigger name not found: ' + triggerName );
2220 - callback();
2221 - return ;
2222 - }
2223 - var callbackSet = $j( targetObject ).data( 'events' )[ triggerName ];
2224 - if( !callbackSet || callbackSet.length === 0 ){
2225 - mw.log( ' No events run the callback directly: ' + triggerName );
2226 - // No events run the callback directly
2227 - callback();
2228 - return ;
2229 - }
2230 - // Set the callbackCount
2231 - var callbackCount = ( callbackSet.length )? callbackSet.length : 1;
2232 -
2233 - mw.log(" runTriggersCallback:: " + callbackCount );
2234 - var callInx = 0;
2235 - $j( targetObject ).trigger( triggerName, function() {
2236 - callInx++;
2237 - if( callInx == callbackCount ){
2238 - // Run callback
2239 - callback();
2240 - }
2241 - } );
2242 - }
2243 - /**
2244 - * Utility jQuery bindings Setup after jQuery is available ).
2245 - */
2246 - mw.dojQueryBindings = function() {
2247 - mw.log( 'mw.dojQueryBindings' );
2248 - ( function( $ ) {
2249 -
2250 - /**
2251 - * Set a given selector html to the loading spinner:
2252 - */
2253 - $.fn.loadingSpinner = function( ) {
2254 - if ( this ) {
2255 - $j( this ).html(
2256 - $j( '<div />' )
2257 - .addClass( "loadingSpinner" )
2258 - );
2259 - }
2260 - /*
2261 - * //var csstransforms = false; if ( Modernizr.csstransforms ) {
2262 - * var barNumber = 7; var barContent = ''; var barSpacingDegrees =
2263 - * 360 / barNumber; var barOpacityDelta = 1 / (barNumber); for
2264 - * (i = 1; i < barNumber+1; i++) { barContent += '<div
2265 - * class="bar' + i + '" style="-moz-transform:rotate(' + (i-1) *
2266 - * barSpacingDegrees + 'deg) translate(0,
2267 - * -40px);-webkit-transform:rotate(' + (i-1) * barSpacingDegrees +
2268 - * 'deg) translate(0, -40px);opacity:' + (i) * barOpacityDelta + ';
2269 - * background:#000"/>'; } $j( this ).html( $j( '<div />' )
2270 - * .addClass( "cssLoadingSpinner" ) .html( barContent ) ); var
2271 - * rotations = 0; setInterval( function ( ) {
2272 - * $j('.cssLoadingSpinner')
2273 - * .css('-moz-transform','rotate('+rotations+'deg)')
2274 - * .css('-webkit-transform','rotate('+rotations+'deg)'); if(
2275 - * rotations == 360 ) { rotations = 0; } rotations += 5; }, 25); }
2276 - */
2277 - return this;
2278 - }
2279 - /**
2280 - * Add an absolute overlay spinner useful for cases where the
2281 - * element does not display child elements, ( images, video )
2282 - */
2283 - $.fn.getAbsoluteOverlaySpinner = function(){
2284 - var pos = $j( this ).offset();
2285 - var posLeft = ( $j( this ).width() ) ?
2286 - parseInt( pos.left + ( .4 * $j( this ).width() ) ) :
2287 - pos.left + 30;
2288 -
2289 - var posTop = ( $j( this ).height() ) ?
2290 - parseInt( pos.top + ( .4 * $j( this ).height() ) ) :
2291 - pos.top + 30;
2292 -
2293 - var $spinner = $j('<div />')
2294 - .loadingSpinner()
2295 - .css({
2296 - 'width' : 32,
2297 - 'height' : 32,
2298 - 'position': 'absolute',
2299 - 'top' : posTop + 'px',
2300 - 'left' : posLeft + 'px'
2301 - });
2302 - $j('body').append( $spinner );
2303 - return $spinner;
2304 - }
2305 -
2306 - /**
2307 - * dragDrop file loader
2308 - */
2309 - $.fn.dragFileUpload = function ( conf ) {
2310 - if ( this.selector ) {
2311 - var _this = this;
2312 - // load the dragger and "setup"
2313 - mw.load( ['$j.fn.dragDropFile'], function() {
2314 - $j( _this.selector ).dragDropFile();
2315 - } );
2316 - }
2317 - }
2318 -
2319 - /**
2320 - * Shortcut to a themed button Should be depreciated for $.button
2321 - * bellow
2322 - */
2323 - $.btnHtml = function( msg, styleClass, iconId, opt ) {
2324 - if ( !opt )
2325 - opt = { };
2326 - var href = ( opt.href ) ? opt.href : '#';
2327 - var target_attr = ( opt.target ) ? ' target="' + opt.target + '" ' : '';
2328 - var style_attr = ( opt.style ) ? ' style="' + opt.style + '" ' : '';
2329 - return '<a href="' + href + '" ' + target_attr + style_attr +
2330 - ' class="ui-state-default ui-corner-all ui-icon_link ' +
2331 - styleClass + '"><span class="ui-icon ui-icon-' + iconId + '" ></span>' +
2332 - '<span class="btnText">' + msg + '</span></a>';
2333 - };
2334 -
2335 - // Shortcut to jQuery button ( should replace all btnHtml with
2336 - // button )
2337 - var mw_default_button_options = {
2338 - // The class name for the button link
2339 - 'class' : '',
2340 -
2341 - // The style properties for the button link
2342 - 'style' : { },
2343 -
2344 - // The text of the button link
2345 - 'text' : '',
2346 -
2347 - // The icon id that precedes the button link:
2348 - 'icon_id' : 'carat-1-n'
2349 - };
2350 -
2351 - $.button = function( options ) {
2352 - var options = $j.extend( mw_default_button_options, options);
2353 -
2354 - // Button:
2355 - var $btn = $j('<a />')
2356 - .attr('href', '#')
2357 - .addClass( 'ui-state-default ui-corner-all ui-icon_link' );
2358 - // Add css if set:
2359 - if( options.css ) {
2360 - $btn.css( options.css )
2361 - }
2362 -
2363 - if( options['class'] ) {
2364 - $btn.addClass( options['class'] )
2365 - }
2366 -
2367 -
2368 - // return the button:
2369 - return $btn.append(
2370 - $j('<span />').addClass( 'ui-icon ui-icon-' + options.icon_id ),
2371 - $j('<span />').addClass( 'btnText' )
2372 - .text( options.text )
2373 - )
2374 - .buttonHover(); // add buttonHover binding;
2375 - };
2376 -
2377 - // Shortcut to bind hover state
2378 - $.fn.buttonHover = function() {
2379 - $j( this ).hover(
2380 - function() {
2381 - $j( this ).addClass( 'ui-state-hover' );
2382 - },
2383 - function() {
2384 - $j( this ).removeClass( 'ui-state-hover' );
2385 - }
2386 - )
2387 - return this;
2388 - };
2389 -
2390 - /**
2391 - * Resize a dialog to fit the window
2392 - *
2393 - * @param {Object}
2394 - * options horizontal and vertical space ( default 50 )
2395 - */
2396 - $.fn.dialogFitWindow = function( options ) {
2397 - var opt_default = { 'hspace':50, 'vspace':50 };
2398 - if ( !options )
2399 - var options = { };
2400 - options = $j.extend( opt_default, options );
2401 - $j( this.selector ).dialog( 'option', 'width', $j( window ).width() - options.hspace );
2402 - $j( this.selector ).dialog( 'option', 'height', $j( window ).height() - options.vspace );
2403 - $j( this.selector ).dialog( 'option', 'position', 'center' );
2404 - // update the child position: (some of this should be pushed
2405 - // up-stream via dialog config options
2406 - $j( this.selector + '~ .ui-dialog-buttonpane' ).css( {
2407 - 'position':'absolute',
2408 - 'left':'0px',
2409 - 'right':'0px',
2410 - 'bottom':'0px'
2411 - } );
2412 - };
2413 -
2414 - } )( $j );
2415 - }
2416 -
2417 -} )( window.mw );
2418 -
2419 -
2420 -/**
2421 - * Set DOM-ready call We copy jQuery( document ).ready here since sometimes
2422 - * mwEmbed.js is included without jQuery and we need our own "ready" system so
2423 - * that mwEmbed interfaces can support async built out and the include of
2424 - * jQuery.
2425 - */
2426 -var mwDomIsReady = false;
2427 -function runMwDomReady(){
2428 - mwDomIsReady = true;
2429 - if( mw.domReady ){
2430 - mw.domReady()
2431 - }
2432 -}
2433 -// Check if already ready:
2434 -if ( document.readyState === "complete" ) {
2435 - runMwDomReady();
2436 -}
2437 -
2438 -// Cleanup functions for the document ready method
2439 -if ( document.addEventListener ) {
2440 - DOMContentLoaded = function() {
2441 - document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
2442 - runMwDomReady();
2443 - };
2444 -
2445 -} else if ( document.attachEvent ) {
2446 - DOMContentLoaded = function() {
2447 - // Make sure body exists, at least, in case IE gets a little overzealous
2448 - // (ticket #5443).
2449 - if ( document.readyState === "complete" ) {
2450 - document.detachEvent( "onreadystatechange", DOMContentLoaded );
2451 - runMwDomReady();
2452 - }
2453 - };
2454 -}
2455 -// Mozilla, Opera and webkit nightlies currently support this event
2456 -if ( document.addEventListener ) {
2457 - // Use the handy event callback
2458 - document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
2459 -
2460 - // A fallback to window.onload, that will always work
2461 - window.addEventListener( "load", mw.domReady, false );
2462 -
2463 -// If IE event model is used
2464 -} else if ( document.attachEvent ) {
2465 - // ensure firing before onload,
2466 - // maybe late but safe also for iframes
2467 - document.attachEvent("onreadystatechange", DOMContentLoaded);
2468 -
2469 - // A fallback to window.onload, that will always work
2470 - window.attachEvent( "onload", runMwDomReady );
2471 -
2472 - // If IE and not a frame
2473 - // continually check to see if the document is ready
2474 - var toplevel = false;
2475 -
2476 - try {
2477 - toplevel = window.frameElement == null;
2478 - } catch(e) {}
2479 -
2480 - if ( document.documentElement.doScroll && toplevel ) {
2481 - doScrollCheck();
2482 - }
2483 -}
2484 -// The DOM ready check for Internet Explorer
2485 -function doScrollCheck() {
2486 - if ( mwDomIsReady ) {
2487 - return;
2488 - }
2489 -
2490 - try {
2491 - // If IE is used, use the trick by Diego Perini
2492 - // http://javascript.nwbox.com/IEContentLoaded/
2493 - document.documentElement.doScroll("left");
2494 - } catch( error ) {
2495 - setTimeout( doScrollCheck, 1 );
2496 - return;
2497 - }
2498 -
2499 - // and execute any waiting functions
2500 - runMwDomReady();
2501 -}
2502 -
2503 -
2504 -// If using the resource loader and jQuery has not been set give a warning to
2505 -// the user:
2506 -// (this is needed because packaged loader.js files could refrence jQuery )
2507 -if( mw.getResourceLoaderPath() && !window.jQuery ) {
2508 - mw.log( 'Error: jQuery is required for mwEmbed, please update your resource loader request' );
2509 -}
2510 -
2511 -if( mw.isStaticPackge() && !window.jQuery ){
2512 - alert( 'Error: jQuery is required for mwEmbed ');
2513 -}
2514 -
2515 -/**
2516 - * Hack to keep jQuery in $ when its already there, but also use noConflict to
2517 - * get $j = jQuery
2518 - *
2519 - * This way sites that use $ for jQuery continue to work after including mwEmbed
2520 - * javascript.
2521 - *
2522 - * Also if jQuery is included prior to mwEmbed we ensure $j is set
2523 - */
2524 -
2525 -if( window.jQuery ){
2526 - var dollarFlag = false;
2527 - if( $ && $.fn && $.fn.jquery ) {
2528 - // NOTE we could check the version of
2529 - // jQuery and do a removal call if too old
2530 - dollarFlag = true;
2531 - }
2532 - window[ '$j' ] = jQuery.noConflict();
2533 - if( dollarFlag ) {
2534 - window[ '$' ] = jQuery.noConflict();
2535 - }
2536 -}
 3+* MwEmbed.js is a meta package for the mwEmbed platform.
 4+*
 5+* For legacy support, this file invokes the mwEmbed platform with debug mode enabled.
 6+*
 7+* This mode has been deprecated, you should instead directly request the debug package
 8+*
 9+* When using mwEmbed in mediaWiki, this file will never be accessed.
 10+*/
Index: trunk/extensions/TimedMediaHandler/TimedText/TimedText.resourceList.php
@@ -1,16 +0,0 @@
2 -<?php
3 -
4 -/**
5 - * EmbedPlayer module resource list array
6 - */
7 -
8 -return array(
9 - // Top level TimedText name:
10 - "mw.TimedText" => array( "scripts" => "mw.TimedText.js" ),
11 - "mw.style.TimedText" => array( "scripts" => "css/mw.style.TimedText.css"),
12 -
13 - "mw.TimedTextEdit" => array( "scripts" => "mw.TimedTextEdit.js"),
14 - "mw.style.TimedTextEdit" => array( "scripts" => "css/mw.style.TimedTextEdit.css"),
15 -
16 - "RemoteMwTimedText" => array( "scripts" => "remotes/RemoteMwTimedText.js")
17 -);
\ No newline at end of file
Index: trunk/extensions/TimedMediaHandler/TimedText/remotes/RemoteMwTimedText.js
@@ -0,0 +1,188 @@
 2+/**
 3+* Stop-gap for mediaWiki php based timed text support
 4+*
 5+* Does some transformations to normal wiki timed Text pages to make them look
 6+* like the php output that we will eventually want to have
 7+*/
 8+
 9+mw.addMessageKeys( [
 10+ "mwe-timedtext-language-subtitles-for-clip",
 11+ "mwe-timedtext-language-no-subtitles-for-clip"
 12+]);
 13+
 14+RemoteMwTimedText = function( options ) {
 15+ return this.init( options );
 16+}
 17+mw_default_remote_text_options = [
 18+ 'action',
 19+ 'title',
 20+ 'target',
 21+ 'orgBody'
 22+];
 23+RemoteMwTimedText.prototype = {
 24+
 25+ init: function( options ) {
 26+ for(var i in mw_default_remote_text_options) {
 27+ var opt = mw_default_remote_text_options[i]
 28+ if( options[ opt ] ) {
 29+ this[ opt ] = options[ opt ];
 30+ }
 31+ }
 32+ },
 33+ updateUI: function() {
 34+ // Check page type
 35+ if( this.action == 'view' ) {
 36+ this.showViewUI();
 37+ }else{
 38+ //restore
 39+ }
 40+ },
 41+ showViewUI: function() {
 42+ var _this = this;
 43+ var fileTitleKey = this.title.split('.');
 44+ this.extension = fileTitleKey.pop();
 45+ this.langKey = fileTitleKey.pop();
 46+ this.fileTitleKey = fileTitleKey.join('.');
 47+
 48+ this.getTitleResource( this.fileTitleKey, function( resource ) {
 49+ _this.embedViewUI( resource );
 50+ });
 51+ },
 52+ embedViewUI: function( resource ) {
 53+ var _this = this;
 54+ // Load the player module:
 55+ mw.load( 'EmbedPlayer', function() {
 56+ // Add the embed code: ( jquery wrapping of "video" fails )
 57+ $j( _this.target ).append(
 58+ $j( '<div class="videoLoading">').html(
 59+ '<video id="timed-text-player-embed" '+
 60+ 'style="width:' + resource.width + 'px;height:' + resource.height + 'px;" '+
 61+ 'class="kskin" ' + //We need to centrally store this config somewhere
 62+ 'poster="' + resource.poster + '" ' +
 63+ 'src="' + resource.src + '" ' +
 64+ 'apiTitleKey="' + resource.apiTitleKey + '" >' +
 65+ '</video><br><br><br><br>'
 66+ )
 67+ );
 68+ $j('.videoLoading').hide();
 69+ // embed the player with the pre-selected langauge:
 70+ _this.embedPlayerLang();
 71+ });
 72+ },
 73+ /*
 74+ * embeds a player with the current language key pre selected
 75+ */
 76+ embedPlayerLang: function() {
 77+ var _this = this;
 78+ if( wgArticlePath ) {
 79+ var $fileLink = $j('<div>').append(
 80+ $j('<a>').attr({
 81+ 'href' : wgArticlePath.replace( '$1', 'File:' + _this.fileTitleKey)
 82+ })
 83+ .text( _this.fileTitleKey.replace('_', ' ') )
 84+ )
 85+ }
 86+
 87+ // Rewrite the player (any video tags on the page)
 88+ $j('#timed-text-player-embed').embedPlayer( function() {
 89+ //Select the timed text for the page:
 90+
 91+ //remove the loader
 92+ $j('.loadingSpinner').remove();
 93+
 94+ var player = $j('#timed-text-player-embed').get(0);
 95+
 96+
 97+ if( !player.timedText ) {
 98+ mw.log("Error: no timedText method on embedPlayer" );
 99+ return ;
 100+ }
 101+ // Set the userLanguage:
 102+ player.timedText.config.userLanugage = this.langKey;
 103+
 104+ // Make sure the timed text sources are loaded:
 105+ player.timedText.setupTextSources( function() {
 106+
 107+ var source = player.timedText.getSourceByLanguage( _this.langKey );
 108+ var pageMsgKey = 'mwe-timedtext-language-subtitles-for-clip';
 109+ if( ! source ) {
 110+ pageMsgKey = "mwe-timedtext-language-no-subtitles-for-clip"
 111+ }
 112+ // Add the page msg to the top
 113+ $j( _this.target ).prepend(
 114+ $j('<h3>')
 115+ .html(
 116+ gM(pageMsgKey, [ unescape( mw.Language.names[ _this.langKey ] ), $fileLink.html() ] )
 117+ )
 118+ );
 119+ // Select the language if possible:
 120+ if( source ) {
 121+ player.timedText.selectTextSource( source );
 122+ }
 123+ // Un-hide the player
 124+ $j('.videoLoading').show();
 125+ } );
 126+ } );
 127+ },
 128+
 129+ /**
 130+ * Gets the properties of a given title as a resource
 131+ * @param {String} fileTitle Title of media asset to embed
 132+ * @param {Function} callback [Optional] Function to call once asset is embedded
 133+ */
 134+ getTitleResource: function( fileTitle, callback ) {
 135+ var _this = this;
 136+ // Get all the embed details:
 137+ var request = {
 138+ 'titles' : 'File:' + fileTitle,
 139+ 'prop' : 'imageinfo|revisions',
 140+ 'iiprop' : 'url|mime|size',
 141+ 'iiurlwidth' : mw.getConfig( 'EmbedPlayer.DefaultSize').split('x').pop(),
 142+ 'rvprop' : 'content'
 143+ }
 144+ // (only works for commons right now)
 145+ mw.getJSON( request, function( data ) {
 146+ // Check for "page not found"
 147+ if( data.query.pages['-1'] ) {
 148+ //restore content:
 149+ $j(_this.target).html( _this.orgBody );
 150+ return ;
 151+ }
 152+ // Check for redirect
 153+ for ( var i in data.query.pages ) {
 154+ var page = data.query.pages[i];
 155+ if ( page.revisions[0]['*'] && page.revisions[0]['*'].indexOf( '#REDIRECT' ) === 0 ) {
 156+ var re = new RegExp( /[^\[]*\[\[([^\]]*)/ );
 157+ var pt = page.revisions[0]['*'].match( re );
 158+ if ( pt[1] ) {
 159+ mw.log( 'found redirect tyring: ' + pt[1] )
 160+ _this.embedByTitle( pt[1], callback);
 161+ return ;
 162+ } else {
 163+ mw.log( 'Error: getTitleResource could not process redirect' );
 164+ callback( false );
 165+ return false;
 166+ }
 167+ }
 168+ mw.log( "should process data result" );
 169+ // Else process the result
 170+ var resource = _this.getResource( page );
 171+ callback( resource );
 172+ }
 173+ } );
 174+ },
 175+
 176+ /**
 177+ * Get the embed code from response resource and sends it a callback
 178+ */
 179+ getResource: function( page ) {
 180+ return {
 181+ 'apiTitleKey' : page.title.replace(/File:/ig, '' ),
 182+ 'link' : page.imageinfo[0].descriptionurl,
 183+ 'poster' : page.imageinfo[0].thumburl,
 184+ 'src' : page.imageinfo[0].url,
 185+ 'width' : page.imageinfo[0].width,
 186+ 'height': page.imageinfo[0].height
 187+ };
 188+ }
 189+};
Property changes on: trunk/extensions/TimedMediaHandler/TimedText/remotes/RemoteMwTimedText.js
___________________________________________________________________
Added: svn:mime-type
1190 + text/plain
Added: svn:executable
2191 + *
Index: trunk/extensions/TimedMediaHandler/TimedText/tests/Player_Timed_Text.html
@@ -0,0 +1,182 @@
 2+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
 3+"http://www.w3.org/TR/html4/loose.dtd">
 4+<html>
 5+<head>
 6+ <title>sample mv embed</title>
 7+ <!-- <script type="text/javascript" src="../../../mwEmbed.js?debug=true"></script> -->
 8+ <script type="text/javascript" src="../../../ResourceLoader.php?class=window.jQuery,mwEmbed&debug=true"></script>
 9+ <script type="text/javascript">
 10+ $j( document ).ready(function(){
 11+ $j('#inlineTracksTextArea').text(
 12+ $j.trim( $j('#inlineTracks').html() )
 13+ );
 14+ $j('#apiExampleTextArea').text(
 15+ $j.trim( $j('#apiExample').html() )
 16+ )
 17+ });
 18+
 19+ </script>
 20+</head>
 21+<body>
 22+<h3> mwEmbed Timed Text Examples:</h3>
 23+Click on the little lower right "CC" icon to expose the timed text
 24+ <table border="1" cellpadding="6" width="950">
 25+
 26+ <tr>
 27+ <td id="apiExample" valign="top" width="410">
 28+ <video
 29+ style="width:512px;height:288px"
 30+ durationHint="7:52"
 31+ apiTitleKey="Yochai_Benkler_-_On_Autonomy,_Control_and_Cultural_Experience.ogg"
 32+ apiProvider="commons"
 33+ class="kskin"></video>
 34+ <td valign="top">
 35+ Commons Video API based timedText discovery<br>
 36+
 37+ <textarea id="apiExampleTextArea" style="width:600px;height:180px"></textarea>
 38+ </td>
 39+ </tr>
 40+
 41+
 42+ <tr>
 43+ <td id="inlineTracks" valign="top" width="410">
 44+
 45+ <video style="width:544px;height:304px;"
 46+ poster="http://upload.wikimedia.org/wikipedia/commons/thumb/b/bd/Elephants_Dream.ogg/seek%3D13-Elephants_Dream.ogg.jpg"
 47+ duration="10:53"
 48+ linkback="http://www.elephantsdream.org/" >
 49+ <source type="video/ogg" src="http://upload.wikimedia.org/wikipedia/commons/b/bd/Elephants_Dream.ogg" ></source>
 50+ <source type="video/h264" src="http://www.archive.org/download/ElephantsDream/ed_1024_512kb.mp4"></source>
 51+
 52+
 53+ <!-- Subtitles -->
 54+
 55+ <track kind="subtitles" id="video_af" srclang="af"
 56+ src="media/elephants_dream/elephant.afrikaans.srt"></track>
 57+
 58+ <track kind="subtitles" id="video_ar" srclang="ar"
 59+ src="media/elephants_dream/elephant.arabic.srt"></track>
 60+
 61+ <track kind="subtitles" id="video_bn" srclang="bn"
 62+ src="media/elephants_dream/elephant.bangla.srt"></track>
 63+
 64+ <track kind="subtitles" id="video_br" srclang="br"
 65+ src="media/elephants_dream/elephant.breton.srt"></track>
 66+
 67+ <track kind="subtitles" id="video_bg" srclang="bg"
 68+ src="media/elephants_dream/elephant.bulgarian.srt"></track>
 69+
 70+ <track kind="subtitles" id="video_ca" srclang="ca"
 71+ src="media/elephants_dream/elephant.catalan-utf8.srt"></track>
 72+
 73+ <track kind="subtitles" id="video_zh" srclang="zh"
 74+ src="media/elephants_dream/elephant.chinese.srt"></track>
 75+
 76+ <track kind="subtitles" id="video_cz" srclang="cs"
 77+ src="media/elephants_dream/elephant.czech.srt"></track>
 78+
 79+ <track kind="subtitles" id="video_da" srclang="da"
 80+ src="media/elephants_dream/elephant.danish.srt"></track>
 81+
 82+ <track kind="subtitles" id="video_nl" srclang="nl"
 83+ src="media/elephants_dream/elephant.dutch.srt"></track>
 84+
 85+ <track kind="subtitles" id="video_en" srclang="en"
 86+ src="media/elephants_dream/elephant.english.srt"></track>
 87+
 88+ <track kind="subtitles" id="video_et" srclang="et"
 89+ src="media/elephants_dream/elephant.estonian.srt"></track>
 90+
 91+ <track kind="subtitles" id="video_fi" srclang="fi"
 92+ src="media/elephants_dream/elephant.finnish.srt"></track>
 93+
 94+ <track kind="subtitles" id="video_fr" srclang="fr"
 95+ src="media/elephants_dream/elephant.french.srt"></track>
 96+
 97+ <track kind="subtitles" id="video_de" srclang="de"
 98+ src="media/elephants_dream/elephant.german.srt"></track>
 99+
 100+ <track kind="subtitles" id="video_el" srclang="el"
 101+ src="media/elephants_dream/elephant.greek.srt"></track>
 102+
 103+ <track kind="subtitles" id="video_he" srclang="he"
 104+ src="media/elephants_dream/elephant.hebrew.srt"></track>
 105+
 106+ <track kind="subtitles" id="video_hu" srclang="hu"
 107+ src="media/elephants_dream/elephant.hungarian-utf8.srt"></track>
 108+
 109+ <track kind="subtitles" id="video_it" srclang="it"
 110+ src="media/elephants_dream/elephant.italian.srt"></track>
 111+
 112+ <track kind="subtitles" id="video_ja" srclang="ja"
 113+ src="media/elephants_dream/elephant.japanese.srt"></track>
 114+
 115+ <track kind="subtitles" id="video_ja" srclang="ja"
 116+ src="media/elephants_dream/elephant.japanese-euc.srt"></track>
 117+
 118+ <track kind="subtitles" id="video_mt" srclang="mt"
 119+ src="media/elephants_dream/elephant.maltese_utf8.srt"></track>
 120+
 121+ <track kind="subtitles" id="video_nn" srclang="nn"
 122+ src="media/elephants_dream/elephant.norwegian.srt"></track>
 123+
 124+ <track kind="subtitles" id="video_pl" srclang="pl"
 125+ src="media/elephants_dream/elephant.polish.srt"></track>
 126+
 127+ <track kind="subtitles" id="video_pt" srclang="pt"
 128+ src="media/elephants_dream/elephant.portuguese.srt"></track>
 129+
 130+ <track kind="subtitles" id="video_pt_br" srclang="pt-br"
 131+ src="media/elephants_dream/elephant.brazilian.srt"></track>
 132+
 133+ <track kind="subtitles" id="video_ro" srclang="ro"
 134+ src="media/elephants_dream/elephant.romanian.srt"></track>
 135+
 136+ <track kind="subtitles" id="video_ru" srclang="ru"
 137+ src="media/elephants_dream/elephant.russian.srt"></track>
 138+
 139+
 140+ <!-- Captions -->
 141+ <track kind="captions" id="video_sl" srclang="sl"
 142+ src="media/elephants_dream/elephant.slovenian.srt"></track>
 143+
 144+ <track kind="captions" id="video_es" srclang="es"
 145+ src="media/elephants_dream/elephant.spanish.srt"></track>
 146+
 147+ <track kind="captions" id="video_es_mx" srclang="es-mx"
 148+ src="media/elephants_dream/elephant.spanish-us.srt"></track>
 149+
 150+ <track kind="captions" id="video_sk" srclang="sk"
 151+ src="media/elephants_dream/elephant.slovak.srt"></track>
 152+
 153+ <track kind="captions" id="video_sv" srclang="sv"
 154+ src="media/elephants_dream/elephant.swedish.srt"></track>
 155+
 156+
 157+ <!-- Audio Description -->
 158+ <track kind="descriptions" id="audiodesc" srclang="en"
 159+ src="media/elephants_dream/audiodescription.srt"></track>
 160+
 161+ <!-- Chapters -->
 162+ <track kind="chapters" id="chapters" srclang="en" label="Chapters"
 163+ src="media/elephants_dream/chapters.srt"></track>
 164+
 165+ </video>
 166+
 167+ </td>
 168+
 169+ <td valign="top">
 170+ <h4>Text track inline embed example</h4>
 171+ see: <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#the-track-element">HTML5 timed text spec</a>
 172+ <br><textarea id="inlineTracksTextArea" style="width:600px;height:180px">
 173+
 174+ </textarea>
 175+ </td>
 176+ </tr>
 177+
 178+
 179+ </table>
 180+
 181+</body>
 182+</html>
 183+
Property changes on: trunk/extensions/TimedMediaHandler/TimedText/tests/Player_Timed_Text.html
___________________________________________________________________
Added: svn:mime-type
1184 + text/plain
Index: trunk/extensions/TimedMediaHandler/TimedText/TimedText.resources.php
@@ -0,0 +1,16 @@
 2+<?php
 3+
 4+/**
 5+ * EmbedPlayer module resource list array
 6+ */
 7+
 8+return array(
 9+ // Top level TimedText name:
 10+ "mw.TimedText" => array( "scripts" => "mw.TimedText.js" ),
 11+ "mw.style.TimedText" => array( "scripts" => "css/mw.style.TimedText.css"),
 12+
 13+ "mw.TimedTextEdit" => array( "scripts" => "mw.TimedTextEdit.js"),
 14+ "mw.style.TimedTextEdit" => array( "scripts" => "css/mw.style.TimedTextEdit.css"),
 15+
 16+ "RemoteMwTimedText" => array( "scripts" => "remotes/RemoteMwTimedText.js")
 17+);
\ No newline at end of file
Index: trunk/extensions/TimedMediaHandler/EmbedPlayer/EmbedPlayer.resourceList.php
@@ -1,28 +0,0 @@
2 -<?php
3 -
4 -/**
5 - * EmbedPlayer module resource list array
6 - */
7 -
8 -return array(
9 - "mw.EmbedPlayer" => array( 'scripts'=> "mw.EmbedPlayer.js" ),
10 -
11 - "mw.EmbedPlayerKplayer" => array( 'scripts'=> "mw.EmbedPlayerKplayer.js" ),
12 - "mw.EmbedPlayerGeneric" => array( 'scripts'=> "mw.EmbedPlayerGeneric.js" ),
13 - "mw.EmbedPlayerHtml" => array( 'scripts'=> "mw.EmbedPlayerHtml.js" ),
14 - "mw.EmbedPlayerJava" => array( 'scripts'=> "mw.EmbedPlayerJava.js"),
15 - "mw.EmbedPlayerNative" => array( 'scripts'=> "mw.EmbedPlayerNative.js" ),
16 -
17 - "mw.EmbedPlayerVlc" => array( 'scripts'=> "mw.EmbedPlayerVlc.js" ),
18 -
19 - "mw.PlayerControlBuilder" => array( 'scripts' => "skins/mw.PlayerControlBuilder.js" ),
20 -
21 - "mw.style.EmbedPlayer" => array( 'scripts'=> "skins/mw.style.EmbedPlayer.css" ),
22 -
23 - "mw.style.PlayerSkinKskin" => array( 'scripts' => "skins/kskin/mw.style.PlayerSkinKskin.css" ),
24 -
25 - "mw.PlayerSkinKskin" => array( 'scripts' => "skins/kskin/mw.PlayerSkinKskin.js"),
26 -
27 - "mw.PlayerSkinMvpcf" => array( 'scripts'=> "skins/mvpcf/mw.PlayerSkinMvpcf.js"),
28 - "mw.style.PlayerSkinMvpcf" => array( 'scripts'=> "skins/mvpcf/mw.style.PlayerSkinMvpcf.css"),
29 -);
\ No newline at end of file
Index: trunk/extensions/TimedMediaHandler/EmbedPlayer/mw.EmbedPlayer.js
@@ -194,7 +194,8 @@
195195
196196 // Number of milliseconds between interface updates
197197 'EmbedPlayer.MonitorRate' : 250
198 -}
 198+});
 199+
199200 /**
200201 * The base source attribute checks
201202 * also see: http://dev.w3.org/html5/spec/Overview.html#the-source-element
@@ -2390,7 +2391,7 @@
23912392 mw.getConfig( 'imagesPath' ) + 'vid_default_thumb.jpg';
23922393
23932394 // Poster support is not very consistent in browsers
2394 - // use a jpg poster image:
 2395+ // use a jpeg poster image:
23952396 $j( this ).html(
23962397 $j( '<img />' )
23972398 .css({
Index: trunk/extensions/TimedMediaHandler/EmbedPlayer/skins/mw.PlayerControlBuilder.js
@@ -1757,7 +1757,7 @@
17581758 } );
17591759
17601760 // Up the z-index of the default status indicator:
1761 - $playHead.find( 'ui-slider-handle' ).css( 'z-index', 4 );
 1761+ $playHead.find( '.ui-slider-handle' ).css( 'z-index', 4 );
17621762 $playHead.find( '.ui-slider-range' ).addClass( 'ui-corner-all' ).css( 'z-index', 2 );
17631763
17641764 // Add buffer html:
Index: trunk/extensions/TimedMediaHandler/EmbedPlayer/EmbedPlayer.resources.php
@@ -0,0 +1,28 @@
 2+<?php
 3+
 4+/**
 5+ * EmbedPlayer module resource list array
 6+ */
 7+
 8+return array(
 9+ "mw.EmbedPlayer" => array( 'scripts'=> "mw.EmbedPlayer.js" ),
 10+
 11+ "mw.EmbedPlayerKplayer" => array( 'scripts'=> "mw.EmbedPlayerKplayer.js" ),
 12+ "mw.EmbedPlayerGeneric" => array( 'scripts'=> "mw.EmbedPlayerGeneric.js" ),
 13+ "mw.EmbedPlayerHtml" => array( 'scripts'=> "mw.EmbedPlayerHtml.js" ),
 14+ "mw.EmbedPlayerJava" => array( 'scripts'=> "mw.EmbedPlayerJava.js"),
 15+ "mw.EmbedPlayerNative" => array( 'scripts'=> "mw.EmbedPlayerNative.js" ),
 16+
 17+ "mw.EmbedPlayerVlc" => array( 'scripts'=> "mw.EmbedPlayerVlc.js" ),
 18+
 19+ "mw.PlayerControlBuilder" => array( 'scripts' => "skins/mw.PlayerControlBuilder.js" ),
 20+
 21+ "mw.style.EmbedPlayer" => array( 'scripts'=> "skins/mw.style.EmbedPlayer.css" ),
 22+
 23+ "mw.style.PlayerSkinKskin" => array( 'scripts' => "skins/kskin/mw.style.PlayerSkinKskin.css" ),
 24+
 25+ "mw.PlayerSkinKskin" => array( 'scripts' => "skins/kskin/mw.PlayerSkinKskin.js"),
 26+
 27+ "mw.PlayerSkinMvpcf" => array( 'scripts'=> "skins/mvpcf/mw.PlayerSkinMvpcf.js"),
 28+ "mw.style.PlayerSkinMvpcf" => array( 'scripts'=> "skins/mvpcf/mw.style.PlayerSkinMvpcf.css"),
 29+);
\ No newline at end of file
Index: trunk/extensions/TimedMediaHandler/EmbedPlayer/EmbedPlayer.loader.js
@@ -10,7 +10,7 @@
1111 mw.setDefaultConfig( {
1212 // What tags will be re-written to video player by default
1313 // Set to empty string or null to avoid automatic video tag rewrites to embedPlayer
14 - "EmbedPlayer.RewriteTags" : "video,audio,playlist"
 14+ "EmbedPlayer.RewriteTags" : "video,audio"
1515 } );
1616
1717 /**
@@ -44,7 +44,7 @@
4545 mw.rewritePagePlayerTags = function() {
4646 mw.log( 'EmbedPlayer:: Document::' + mw.documentHasPlayerTags() );
4747 if( mw.documentHasPlayerTags() ) {
48 - var rewriteElementCount = 0;
 48+ var rewriteElementCount = 0;
4949
5050 // Set each player to loading ( as early on as possible )
5151 $j( mw.getConfig( 'EmbedPlayer.RewriteTags' ) ).each( function( index, element ){
Index: trunk/extensions/AddMediaWizard/AddMedia/mw.UploadHandler.js
@@ -82,7 +82,7 @@
8383 myUpload.setupForm( );
8484 }
8585
86 - // Update the selecto to include pointer to upload handler
 86+ // Update the selector to include pointer to upload handler
8787 var selectorElement = $j( this.selector ).get( 0 );
8888 selectorElement[ 'uploadHandler' ] = myUpload;
8989 };
@@ -140,8 +140,13 @@
141141 } else {
142142 // Setup the default DialogInterface UI
143143 this.ui = new mw.UploadDialogInterface();
144 - }
145 -
 144+ }
 145+
 146+ // Don't rewrite on reuploads
 147+ if( $j("[name='wpForReUpload']").val() ) {
 148+ this.rewriteDescriptionText = false;
 149+ }
 150+
146151 // Setup ui uploadHandler pointer
147152 this.ui.uploadHandler = this;
148153
@@ -552,7 +557,7 @@
553558 * @param {String} source The source filed
554559 */
555560 getCommentText: function( comment, license, copyStatus, source ) {
556 - var pageText = '== ' + gM( 'mwe-filedesc' ) + " ==\n" + comment + "\n";
 561+ var pageText = '== ' + mw.Language.msgNoTrans( 'mwe-filedesc' ) + " ==\n" + comment + "\n";
557562 if( copyStatus ){
558563 pageText += '== ' + gM( 'mwe-filestatus' ) + " ==\n" + copyStatus + "\n";
559564 }
@@ -560,8 +565,8 @@
561566 pageText += '== ' + gM( 'mwe-filesource' ) + " ==\n" + source + "\n";
562567 }
563568 if ( license ) {
564 - pageText += '== ' + gM( 'mwe-license-header' ) + " ==\n" + '{{' + license + '}}' + "\n";
565 - }
 569+ pageText += '== ' + mw.Language.msgNoTrans( 'mwe-license-header' ) + " ==\n" + '{{' + license + '}}' + "\n";
 570+ }
566571 return pageText;
567572 },
568573
Index: trunk/extensions/AddMediaWizard/AddMedia/searchLibs/mediaWikiSearch.js
@@ -25,7 +25,7 @@
2626 /**
2727 * Adds a resource by its Title
2828 *
29 - * @param {String} title Title of the resource to be added
 29+ * @param {String} title Title of the resource to be added (in the form of a wgPageName)
3030 * @param {Function} callback Function called once title resource acquired
3131 */
3232 getByTitle:function( title , callback ) {
@@ -47,7 +47,13 @@
4848 callback( _this.addSingleResult( data ) );
4949 });
5050 },
51 -
 51+
 52+ /**
 53+ * Add a resource by its Url
 54+ *
 55+ * @param {String} url The url of the resource to be added
 56+ * @param {Function} callback Function called once the resource is acquired
 57+ */
5258 getResourceFromUrl: function( url, callback ){
5359 var title = this.getTitleKeyFromMwUrl( url );
5460 if( !title) {
@@ -56,21 +62,25 @@
5763 }
5864 this.getByTitle(title , callback );
5965 },
 66+
6067 /**
61 - * Does best effort to get the title key from a mediawiki url
 68+ * Does best effort to get the title key from a mediawiki url
 69+ *
 70+ * @param {String} url The url for which we want to find the title
 71+ * @return {String} The title in a form that should mirror wgPageName
6272 */
6373 getTitleKeyFromMwUrl: function( url ){
6474 // try for title key param
6575 var titleKey = mw.parseUri( url ).queryKey['title'];
6676 if( titleKey ){
67 - return titleKey;
 77+ return decodeURIComponent( titleKey ).replace( / /g, "_");
6878 }
6979 // else try for title url map
7080 titleKey = url.replace( this.provider.detailsUrl.replace( '$1', ''), '' );
7181 if( titleKey != url ){
72 - return titleKey;
 82+ return decodeURI(titleKey).replace( / /g, "_" );;
7383 }
74 - mw.log("Error: mediaWikiSearch:: getResourceFromUrl could not get title form url: " + url );
 84+ mw.log("Error: mediaWikiSearch:: getResourceFromUrl could not get title from url: " + url );
7585 return false;
7686 },
7787
@@ -94,7 +104,7 @@
95105 var pound = '';
96106 // loop over the data and group by title
97107 if ( data.query && data.query.recentchanges ) {
98 - for ( var i in data.query.recentchanges ) {
 108+ for ( var i=0; i < data.query.recentchanges.length; i++ ) {
99109 var rc = data.query.recentchanges[i];
100110 if ( !titleSet[ rc.title ] ) {
101111 titleSet[ rc.title ] = true;
@@ -135,16 +145,17 @@
136146 // Build the image request
137147 var request = {
138148 'action':'query',
139 - 'generator':'search',
140 - 'gsrsearch': search_query ,
141 - 'gsrnamespace':6, // (only search the "file" namespace (audio, video, images)
142 - 'gsrwhat': 'text',
143 - 'gsrlimit': this.provider.limit,
144 - 'gsroffset': this.provider.offset,
145 - 'prop':'imageinfo|revisions|categories',
146 - 'iiprop':'url|mime|size|metadata',
147 - 'iiurlwidth': parseInt( this.rsd.thumb_width ),
148 - 'rvprop':'content'
 149+ 'generator': 'search',
 150+ 'gsrsearch': search_query ,
 151+ 'gsrnamespace': 6, // (only search the "file" namespace (audio, video, images)
 152+ 'gsrwhat': 'text',
 153+ 'gsrlimit': this.provider.limit,
 154+ 'gsroffset': this.provider.offset,
 155+ 'prop': 'imageinfo|revisions|categories',
 156+ 'iiprop': 'url|mime|size|metadata',
 157+ 'iiurlwidth': parseInt( this.rsd.thumb_width ),
 158+ 'rvprop': 'content',
 159+ 'redirects': true
149160 };
150161
151162 // Do the api request:
@@ -183,42 +194,39 @@
184195 if ( data.query && data.query.pages ) {
185196 for ( var page_id in data.query.pages ) {
186197 var page = data.query.pages[ page_id ];
187 -
188 - // Make sure the reop is shared (don't show for now it confusing things)
 198+
 199+ // Make sure the repo is shared (don't show for now it confusing things)
189200 // @@todo support remote repository better
190201 if ( page.imagerepository == 'shared' ) {
191202 continue;
192203 }
193 -
194 - // Make sure the page is not a redirect
195 - if ( page.revisions && page.revisions[0] &&
196 - page.revisions[0]['*'] && page.revisions[0]['*'].indexOf( '#REDIRECT' ) === 0 ) {
197 - // skip page is redirect
198 - continue;
199 - }
200 -
 204+
201205 // Skip if its an empty or missing imageinfo:
202206 if ( !page.imageinfo ){
203207 continue;
204208 }
205 -
 209+
206210 // Get the url safe titleKey from the descriptionurl
207 - var titleKey = page.imageinfo[0].descriptionurl.split( '/' )
208 - ;
 211+<<<<<<< .mine
 212+ var titleKey = page.imageinfo[0].descriptionurl.split( '/' );
209213 titleKey = unescape(
210214 titleKey[ titleKey.length - 1 ]
211215 .replace( 'index.php?title=', '')
212216 );
213217
 218+=======
 219+ var titleKey = page.title.replace( / /g, "_" );
 220+
 221+>>>>>>> .r75107
214222 var resource = {
215223 'id' : page_id,
216224 'titleKey' : titleKey,
217225 'link' : page.imageinfo[0].descriptionurl,
218226 'title' : page.title.replace(/Image:|File:|.jpg|.png|.svg|.ogg|.ogv|.oga/ig, ''),
219227 'poster' : page.imageinfo[0].thumburl,
220 - 'thumbwidth' : page.imageinfo[0].thumbwidth,
221 - 'thumbheight': page.imageinfo[0].thumbheight,
222 - 'width' : page.imageinfo[0].width,
 228+ 'thumbwidth' : page.imageinfo[0].thumbwidth,
 229+ 'thumbheight' : page.imageinfo[0].thumbheight,
 230+ 'width' : page.imageinfo[0].width,
223231 'height' : page.imageinfo[0].height,
224232 'mime' : page.imageinfo[0].mime,
225233 'src' : page.imageinfo[0].url,
@@ -231,7 +239,7 @@
232240 }
233241 };
234242
235 - for( var i in page.imageinfo[0].metadata ){
 243+ for( var i=0; page.imageinfo[0].metadata && i < page.imageinfo[0].metadata.length; i++ ){
236244 if( page.imageinfo[0].metadata[i].name == 'length' ){
237245 resource.duration = page.imageinfo[0].metadata[i].value;
238246 }
@@ -421,4 +429,4 @@
422430 '|Description =' + resource.inlineDesc + "\n" +
423431 '}}';
424432 }
425 -}
\ No newline at end of file
 433+}
Index: trunk/extensions/AddMediaWizard/AddMedia/loader.js
@@ -78,8 +78,8 @@
7979 '$j.ui'
8080 ],
8181 [
 82+ '$j.widget',
8283 '$j.ui.mouse',
83 - '$j.widget',
8484 '$j.ui.progressbar',
8585 '$j.ui.position',
8686 '$j.ui.dialog',
Index: trunk/extensions/AddMediaWizard/AddMedia/mw.RemoteSearchDriver.js
@@ -1439,7 +1439,7 @@
14401440 checkCopyURLApiResult: function( data, callback ) {
14411441 var _this = this;
14421442 // Api checks:
1443 - for ( var i in data.paraminfo.modules[0].parameters ) {
 1443+ for ( var i=0; i < data.paraminfo.modules[0].parameters.length; i++ ) {
14441444 var pname = data.paraminfo.modules[0].parameters[i].name;
14451445 if ( pname == 'url' ) {
14461446 mw.log( 'Autodetect Upload Mode: api: copy by url:: ' );
@@ -1479,7 +1479,7 @@
14801480 'uiprop' : 'rights'
14811481 };
14821482 mw.getJSON( _this.upload_api_target, request, function( data ) {
1483 - for ( var i in data.query.userinfo.rights ) {
 1483+ for ( var i=0; i < data.query.userinfo.rights.length; i++ ) {
14841484 var right = data.query.userinfo.rights[i];
14851485 // mw.log('checking: ' + right ) ;
14861486 if ( right == 'upload_by_url' ) {
@@ -2342,8 +2342,8 @@
23432343
23442344 // Add libraries resizable and hoverIntent to support video edit tools
23452345 var librarySet = [
2346 - 'mw.ClipEdit',
2347 - 'mw.style.ClipEdit',
 2346+ 'mw.ClipEdit',
 2347+ 'mw.style.ClipEdit',
23482348 '$j.ui.resizable'
23492349 ];
23502350 mw.load( librarySet, function() {
@@ -3287,4 +3287,4 @@
32883288 // Run / update search display:
32893289 this.showResults( );
32903290 }
3291 -};
\ No newline at end of file
 3291+};
Index: trunk/extensions/AddMediaWizard/ClipEdit/mw.ClipEdit.js
@@ -2,37 +2,8 @@
33 * mw.ClipEdit handles the edit interfaces for images and video
44 */
55
6 -// set gMsg object:
7 -mw.addMessages( {
8 - "mwe-clipedit-crop" : "Crop image",
9 - "mwe-clipedit-apply_crop" : "Apply crop to image",
10 - "mwe-clipedit-reset_crop" : "Reset crop",
11 - "mwe-clipedit-insert_image_page" : "Insert into page",
12 - "mwe-clipedit-insert_into_sequence" : "Insert into sequence",
13 - "mwe-clipedit-preview_insert" : "Preview insert",
14 - "mwe-clipedit-cancel_image_insert" : "Cancel insert",
15 - "mwe-clipedit-sc_attributes" : "Clip detail edit",
16 - "mwe-clipedit-sc_inoutpoints" : "Set in-out points",
17 - "mwe-clipedit-sc_overlays" : "Overlays",
18 - "mwe-clipedit-sc_audio" : "Audio control",
19 - "mwe-clipedit-sc_duration" : "Duration",
20 - "mwe-clipedit-template_properties" : "Template properties",
21 - "mwe-clipedit-custom_title" : "Custom title",
22 - "mwe-clipedit-edit_properties" : "Edit properties",
23 - "mwe-clipedit-other_properties" : "Other properties",
24 - "mwe-clipedit-resource_page" : "Resource page:",
25 - "mwe-clipedit-set_in_out_points" : "Set in-out points",
26 - "mwe-clipedit-start_time" : "Start time",
27 - "mwe-clipedit-end_time" : "End time",
28 - "mwe-clipedit-preview_inout" : "Preview in-out points",
29 - "mwe-clipedit-edit-tools" : "Edit tools",
30 - "mwe-clipedit-inline-description" : "Caption",
31 - "mwe-clipedit-edit-video-tools" : "Edit video tools:",
32 - "mwe-clipedit-duration" : "Duration:",
33 - "mwe-clipedit-layout" : "Layout",
34 - "mwe-clipedit-layout_right" : "Right side image layout",
35 - "mwe-clipedit-layout_left" : "Left side image layout"
36 -} );
 6+// include all module messages
 7+mw.includeAllModuleMessages();
378
389 /**
3910 * The default clipEdit values

Follow-up revisions

RevisionCommit summaryAuthorDate
r76387Follow-up r75178 for Translatewikiraymond12:58, 9 November 2010

Comments

#Comment by TheDJ (talk | contribs)   22:14, 29 October 2010

Earlier attempt was r74986

Status & tagging log