r80757 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r80756‎ | r80757 | r80758 >
Date:17:23, 22 January 2011
Author:dale
Status:deferred
Tags:
Comment:
* added mwEmbedSupport folder to differentiate shared mwEmbed code from mediaWiki specific apis and page support.
* some restructuring of configuration
( still lots of things in transition / broken )
Modified paths:
  • /branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/LocalSettings.php (modified) (history)
  • /branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/includes/DefaultSettings.php (modified) (history)
  • /branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/includes/MwEmbedResourceManager.php (modified) (history)
  • /branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/includes/MwEmbedWebStartSetup.php (modified) (history)
  • /branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/AddMedia/mw.RemoteSearchDriver.js (modified) (history)
  • /branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/EmbedPlayer/EmbedPlayer.config.php (added) (history)
  • /branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/EmbedPlayer/EmbedPlayer.loader.js (added) (history)
  • /branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/EmbedPlayer/EmbedPlayer.php (modified) (history)
  • /branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/EmbedPlayer/loader.js (deleted) (history)
  • /branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/EmbedPlayer/mw.EmbedPlayer.js (modified) (history)
  • /branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/EmbedPlayer/mw.EmbedPlayerKplayer.js (modified) (history)
  • /branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/EmbedPlayer/mw.EmbedPlayerNative.js (modified) (history)
  • /branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/EmbedPlayer/mw.IFramePlayerApiClient.js (modified) (history)
  • /branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/EmbedPlayer/mw.IFramePlayerApiServer.js (modified) (history)
  • /branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/MediaWikiSupport/jQueryPlugins (deleted) (history)
  • /branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/MediaWikiSupport/mwEmbed.js (deleted) (history)
  • /branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/MwEmbedSupport (added) (history)
  • /branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/MwEmbedSupport/MwEmbedSupport.i18n.php (added) (history)
  • /branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/MwEmbedSupport/MwEmbedSupport.php (added) (history)
  • /branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/MwEmbedSupport/README (added) (history)
  • /branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/MwEmbedSupport/jquery (added) (history)
  • /branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/MwEmbedSupport/jquery.menu (added) (history)
  • /branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/MwEmbedSupport/jquery.menu/jquery.menu.css (added) (history)
  • /branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/MwEmbedSupport/jquery.menu/jquery.menu.js (added) (history)
  • /branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/MwEmbedSupport/jquery/README (added) (history)
  • /branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/MwEmbedSupport/jquery/jquery.triggerQueueCallback.js (added) (history)
  • /branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/MwEmbedSupport/mwEmbed.core.js (added) (history)
  • /branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/MwEmbedSupport/mwEmbed.old.js (added) (history)
  • /branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/PlayerThemer/loader.js (modified) (history)
  • /branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/Sequencer/loader.js (modified) (history)
  • /branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/SmilPlayer/loader.js (modified) (history)
  • /branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/SwarmTransport/loader.js (modified) (history)
  • /branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/TimedText/loader.js (modified) (history)
  • /branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/resources/README (added) (history)
  • /branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/tests/README (modified) (history)

Diff [purge]

Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/LocalSettings.php
@@ -2,7 +2,11 @@
33 /**
44 * This file store all of mwEmbed local configuration ( in a default svn check out this file is empty )
55 *
6 - * See includes/DefaultSettings.php for a configuration options
 6+ * For core configuration see: includes/DefaultSettings.php f
 7+ *
 8+ * For per module configuration see modules/{moduleName}/{moduleName}.config.php
 9+ * Module configuration options can be set via:
 10+ * $wgMwEmbedModuleConfig[ {ModuleName} ][ {configuration name} ] = value;
711 */
812
913
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/tests/README
@@ -1,2 +1,4 @@
22 This folder contains stand alone tests of js2/mwEmbed components.
3 -The tests folder does not need to be included or exposed in a production environment.
\ No newline at end of file
 3+The tests folder does not need to be included or exposed in a production environment.
 4+
 5+Note these tests have not yet been ported to RL_1_17
\ No newline at end of file
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/includes/MwEmbedWebStartSetup.php
@@ -99,6 +99,7 @@
100100 MwEmbedResourceManager::register( $modulePath );
101101 }
102102 }
 103+
103104 # Add the resource loader hook:
104105 $wgHooks['ResourceLoaderRegisterModules'][] = 'MwEmbedResourceManager::registerModules';
105106
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/includes/MwEmbedResourceManager.php
@@ -35,8 +35,7 @@
3636 $wgExtensionMessagesFiles[ 'MwEmbed.' . $moduleName ] = $fullResourcePath . '/' . $moduleName . '.i18n.php';
3737
3838 // Get the mwEmbed module config
39 - $moduleInfo = require_once( $fullResourcePath . '/' . $moduleName . '.php' );
40 - $resourceList = $moduleInfo['resources'];
 39+ $resourceList = require_once( $fullResourcePath . '/' . $moduleName . '.php' );
4140 // Look for special 'messages' => 'moduleFile' key and load all modules file messages:
4241 foreach( $resourceList as $name => $resources ){
4342 if( isset( $resources['messageFile'] ) && is_file( $fullResourcePath . '/' .$resources['messageFile'] ) ){
@@ -46,12 +45,7 @@
4746 $resourceList[ $name ][ 'messages' ][] = $msgKey;
4847 }
4948 }
50 - };
51 -
52 - // If the module has a loader.js add it to the resource list:
53 - if( is_file( $fullResourcePath . '/loader.js' ) ){
54 - $resourceList[$moduleName. '.loader'] = array( 'loaderScripts' => 'loader.js' );
55 - }
 49+ };
5650 // @@TODO add $moduleInfo['config']
5751
5852 // Add the resource list into the module set with its provided path
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/includes/DefaultSettings.php
@@ -28,6 +28,13 @@
2929 }
3030 }
3131
 32+// Also populate $wgMwEmbedModuleConfig[ {ModuleName} ] array so that LocalSettings.php does not
 33+// get unset array errors
 34+$wgMwEmbedModuleConfig = array();
 35+foreach( $wgMwEmbedEnabledModules as $mwEmbedModuleName ){
 36+ $wgMwEmbedModuleConfig[ $mwEmbedModuleName ] = array();
 37+}
 38+
3239 /**
3340 * Client-side resource modules. Extensions should add their module definitions
3441 * here. The mwEmbed
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/MediaWikiSupport/mwEmbed.js
@@ -1,2800 +0,0 @@
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 mwEmbed Dual licensed under the MIT or GPL Version 2 licenses.
8 - *
9 - * @copyright (C) 2010 Kaltura
10 - * @author Michael Dale ( michael.dale at kaltura.com )
11 - *
12 - * @url http://www.kaltura.org/project/HTML5_Video_Media_JavaScript_Library
13 - *
14 - * Libraries used include code license in headers
15 - */
16 -
17 -/**
18 - * Setup the "mw" global:
19 - */
20 -if ( typeof window.mw == 'undefined' ) {
21 - window.mw = { };
22 -}
23 -/**
24 - * Set the mwEmbedVersion
25 - */
26 -var MW_EMBED_VERSION = '1.1h';
27 -
28 -// Globals to pre-set ready functions in dynamic loading of mwEmbed
29 -if( typeof preMwEmbedReady == 'undefined'){
30 - var preMwEmbedReady = [];
31 -}
32 -// Globals to pre-set config values in dynamic loading of mwEmbed
33 -if( typeof preMwEmbedConfig == 'undefined') {
34 - var preMwEmbedConfig = [];
35 -}
36 -
37 -/**
38 - * The global mw object:
39 - */
40 -( function( mw ) {
41 - // The version of mwEmbed
42 - mw.version = MW_EMBED_VERSION;
43 -
44 - // List valid skins here:
45 - mw.validSkins = [ 'mvpcf', 'kskin' ];
46 -
47 - // Storage variable for loaded style sheet keys
48 - if( ! mw.style ){
49 - mw.style = { };
50 - }
51 -
52 - /**
53 - * Configuration System:
54 - */
55 -
56 - // Local scope configuration var:
57 - if( !mwConfig ){
58 - var mwConfig = { };
59 - }
60 -
61 - if( !mwNonDefaultConfigList ){
62 - var mwNonDefaultConfigList = [];
63 - }
64 -
65 - // mw scope mwUserConfig var. Stores user configuration
66 - var mwUserConfig = { };
67 -
68 - /**
69 - * Setter for configuration values
70 - *
71 - * @param [Mixed]
72 - * name Name of configuration value {Object} Will iderate through
73 - * each key and call setConfig {String} Will set configuration by
74 - * string name to value
75 - * @param {String}
76 - * value Value of configuration name {Object} value Set of values
77 - * to be merged
78 - */
79 - mw.setConfig = function ( name, value ) {
80 - if( typeof name == 'object' ) {
81 - for( var i in name ) {
82 - mw.setConfig( i, name[ i ] );
83 - }
84 - return ;
85 - }
86 - mwConfig[ name ] = value;
87 - mwNonDefaultConfigList.push( name );
88 - };
89 -
90 - // Apply any pre-setup config:
91 - mw.setConfig( preMwEmbedConfig );
92 -
93 - /**
94 - * Merge in a configuration value:
95 - */
96 - mw.mergeConfig = function( name, value ){
97 - if( typeof name == 'object' ) {
98 - $j.each( name, function( inx, val) {
99 - mw.setConfig( inx, val );
100 - });
101 - return ;
102 - }
103 - // Check if we should "merge" the config
104 - if( typeof value == 'object' && typeof mwConfig[ name ] == 'object' ) {
105 - if ( value.constructor.toString().indexOf("Array") != -1 &&
106 - mwConfig[ name ].constructor.toString().indexOf("Array") != -1 ){
107 - // merge in the array
108 - mwConfig[ name ] = $j.merge( mwConfig[ name ], value );
109 - } else {
110 - for( var i in value ){
111 - mwConfig[ name ][ i ] = value[ i ];
112 - }
113 - }
114 - return ;
115 - }
116 - // else do a normal setConfig
117 - mwConfig[ name ] = value;
118 - mwNonDefaultConfigList.push( name );
119 - };
120 -
121 - /**
122 - * Set a default config value Will only update configuration if no value is
123 - * present
124 - *
125 - * @param [Mixed]
126 - * value Set configuration name to value {Object} Will idorate
127 - * through each key and call setDefaultConfig {String} Will set
128 - * configuration by string name to value
129 - */
130 - mw.setDefaultConfig = function( name, value ) {
131 - if( typeof name == 'object' ) {
132 - for( var i in name ) {
133 - mw.setDefaultConfig( i, name[ i ] );
134 - }
135 - return ;
136 - }
137 - if( typeof mwConfig[ name ] == 'undefined' ) {
138 - mwConfig[ name ] = value;
139 - return ;
140 - }
141 - };
142 -
143 - /**
144 - * Getter for configuration values
145 - *
146 - * @param {String}
147 - * name of configuration value to get
148 - * @return {Mixed} value of configuration key returns "false" if key not
149 - * found
150 - */
151 - mw.getConfig = function ( name ) {
152 - if( mwConfig[ name ] )
153 - return mwConfig[ name ];
154 - return false;
155 - };
156 - /**
157 - * Get all the non-default configuration ( useful for passing state to
158 - * iframes in limited hash url length of a few K )
159 - */
160 - mw.getNonDefaultConfigObject = function(){
161 - var nonDefaultConfig = {};
162 - for( var i =0 ; i < mwNonDefaultConfigList.length; i ++){
163 - var configKey = mwNonDefaultConfigList[i];
164 - nonDefaultConfig[ configKey ] = mw.getConfig( configKey );
165 - }
166 - return nonDefaultConfig;
167 - }
168 -
169 - /**
170 - * Loads the mwUserConfig from a cookie.
171 - *
172 - * Modules that want to use "User Config" should call this setup function in
173 - * their moduleLoader code.
174 - *
175 - * For performance interfaces using "user config" should load '$j.cookie' &
176 - * 'JSON' in their module loader
177 - *
178 - * By abstracting user preference we could eventually integrate a persistent
179 - * per-account preference system on the server.
180 - *
181 - * @parma {Function} callback Function to be called once userPrefrences are
182 - * loaded
183 - */
184 - var setupUserConfigFlag = false;
185 - mw.setupUserConfig = function( callback ) {
186 - if( setupUserConfigFlag ) {
187 - if( callback ) {
188 - callback();
189 - }
190 - return ;
191 - }
192 - // Do Setup user config:
193 - mw.load( [ '$j.cookie', 'JSON' ], function() {
194 - if( $j.cookie( 'mwUserConfig' ) ) {
195 - mwUserConfig = JSON.parse( $j.cookie( 'mwUserConfig' ) );
196 - }
197 - setupUserConfigFlag = true;
198 - if( callback ) {
199 - callback();
200 - }
201 - });
202 - };
203 -
204 - /**
205 - * Save a user configuration var to a cookie & local global variable Loads
206 - * the cookie plugin if not already loaded
207 - *
208 - * @param {String}
209 - * name Name of user configuration value
210 - * @param {String}
211 - * value Value of configuration name
212 - */
213 - mw.setUserConfig = function ( name, value, cookieOptions ) {
214 - if( ! setupUserConfigFlag ) {
215 - mw.log( "Error: userConfig not setup" );
216 - return false;
217 - }
218 - // Update local value
219 - mwUserConfig[ name ] = value;
220 -
221 - // Update the cookie ( '$j.cookie' & 'JSON' should already be loaded )
222 - $j.cookie( 'mwUserConfig', JSON.stringify( mwUserConfig ) );
223 - };
224 -
225 - /**
226 - * Save a user configuration var to a cookie & local global variable
227 - *
228 - * @param {String}
229 - * name Name of user configuration value
230 - * @return value of the configuration name false if the configuration name
231 - * could not be found
232 - */
233 - mw.getUserConfig = function ( name ) {
234 - if( mwUserConfig[ name ] )
235 - return mwUserConfig[ name ];
236 - return false;
237 - };
238 -
239 - /**
240 - * Add a hook system for a target object / interface
241 - *
242 - * depricated you should instead use jQuery's bind and trigger
243 - *
244 - * @param {Object}
245 - * targetObj Interface Object to add hook system to.
246 - */
247 - mw.addHookSystem = function( targetObj ) {
248 -
249 - // Setup the target object hook holder:
250 - targetObj[ 'hooks' ] = { };
251 -
252 - /**
253 - * Adds a hook to the target object
254 - *
255 - * Should be called by clients to setup named hooks
256 - *
257 - * @param {String}
258 - * hookName Name of hook to be added
259 - * @param {Function}
260 - * hookFunction Function to be called at hook time
261 - */
262 - targetObj.addHook = function( hookName, hookFunction ) {
263 - if( ! this.hooks[ hookName ] ) {
264 - this.hooks[ hookName ] = [ ];
265 - }
266 - this.hooks[ hookName ].push( hookFunction );
267 - };
268 -
269 - /**
270 - * Runs all the hooks by a given name with reference to the host object
271 - *
272 - * Should be called by the host object at named execution points
273 - *
274 - * @param {String}
275 - * hookName Name of hook to be called
276 - * @return Value of hook result true interface should continue function
277 - * execution false interface should stop or return from method
278 - */
279 - targetObj.runHook = function( hookName, options ) {
280 - if( this.hooks[ hookName ] ) {
281 - for( var i =0; i < this.hooks[ hookName ].length; i ++ ) {
282 - if( typeof( this.hooks[ hookName ][ i ] ) == 'function' ) {
283 - this.hooks[ hookName ][ i ]( options );
284 - }
285 - }
286 - }
287 - };
288 - };
289 -
290 - // Add hooks system to the core "mw" object
291 - mw.addHookSystem( mw );
292 -
293 - // Stores callbacks for resource loader loading
294 - var mwLoadDoneCB = { };
295 -
296 -
297 - /**
298 - * Top level loader prototype:
299 - */
300 - mw.loader = {
301 - /**
302 - * Javascript Module Loader functions
303 - *
304 - * @key Name of Module
305 - * @value function code to load module
306 - */
307 - moduleLoaders : [],
308 -
309 - /**
310 - * Module resource list queue.
311 - *
312 - * @key Name of Module
313 - * @value .resourceList list of resources to be loaded .functionQueue
314 - * list of functions to be run once module is ready
315 - */
316 - moduleLoadQueue: { },
317 -
318 - /**
319 - * Javascript Class Paths
320 - *
321 - * @key Name of resource
322 - * @value Class file path
323 - */
324 - resourcePaths : { },
325 -
326 - /**
327 - * Stores resources that have been requested ( to avoid re-requesting
328 - * the same resources ) in concurrent requests )
329 - */
330 - requestedResourceQueue: { },
331 -
332 - /**
333 - * javascript Resource Paths
334 - *
335 - * @key Name of resource
336 - * @value Name of depenent style sheet
337 - */
338 - resourceStyleDependency: { },
339 -
340 - /**
341 - * Core load function:
342 - *
343 - * @param {Mixed}
344 - * loadRequest:
345 - *
346 - * {String} Name of a module to be loaded Modules are added via
347 - * addModuleLoader and can define custom code needed to check config and
348 - * return a list of resources to be loaded
349 - *
350 - * {String} Name of a resource to loaded. Resources are added via
351 - * addResourcePaths function Using defined resource names avoids loading
352 - * the same resource twice by first checking if the named resource is
353 - * defined in the global javascript scope variable
354 - *
355 - * {String} Absolute or relative to url path The same file won't be
356 - * loaded twice
357 - *
358 - * {Array} can be an array of any combination of the above strings. Will
359 - * be loaded in-order or in a single resource loader request if
360 - * scriptLoader is available.
361 - *
362 - * {Array} {Array} Can be a set of Arrays for loading. Some browsers
363 - * execute included scripts out of order. This lets you chain sets of
364 - * request for those browsers. If using the server side resource loader
365 - * order is preserved in output and a single request will be used.
366 - *
367 - * @param {Function}
368 - * callback Function called once loading is complete
369 - *
370 - */
371 - load: function( loadRequest, instanceCallback ) {
372 - // mw.log("mw.load:: " + loadRequest );
373 - var _this = this;
374 -
375 - // Throw out any loadRequests that are not strings
376 - loadRequest = this.cleanLoadRequest( loadRequest );
377 -
378 - // Ensure the callback is only called once per load instance
379 - var callback = function(){
380 - // mw.log( 'instanceCallback::running callback: ' +
381 - // instanceCallback );
382 - if( instanceCallback ){
383 - // We pass the loadRequest back to the callback for easy
384 - // debugging of concurrency issues.
385 - // ( normally its not used )
386 - instanceCallback( loadRequest );
387 - instanceCallback = null;
388 - }
389 - };
390 -
391 - // Check for empty loadRequest ( directly return the callback )
392 - if( mw.isEmpty( loadRequest ) ) {
393 - mw.log( 'Empty load request: ( ' + loadRequest + ' ) ' );
394 - callback( loadRequest );
395 - return ;
396 - }
397 -
398 -
399 - // Check if its a multi-part request:
400 - if( typeof loadRequest == 'object' ) {
401 - if( loadRequest.length > 1 ) {
402 - this.loadMany ( loadRequest, callback );
403 - return ;
404 - }else{
405 - // If an array of length 1 set as first element
406 - loadRequest = loadRequest[0];
407 - }
408 - }
409 -
410 - // Check for the module name loader function
411 - if( this.moduleLoaders[ loadRequest ] ) {
412 - var resourceSet = this.getModuleResourceSet( loadRequest );
413 - if( !resourceSet ){
414 - mw.log( "mw.load:: Error with module loader: " + loadRequest + ' ( no resource set defined )' );
415 - return ;
416 - }
417 -
418 - // xxx should use refactor "ready" stuff into a "domReady" class
419 - // So we would not have local scope globals like this:
420 - // if ( mwReadyFlag ) {
421 - // Load the module directly if load request is after
422 - // mw.ready has run
423 - this.load( resourceSet, callback );
424 - // } else {
425 - // this.addToModuleLoaderQueue(
426 - // loadRequest,
427 - // resourceSet,
428 - // callback
429 - // );
430 - // }
431 - return ;
432 - }
433 -
434 - // Check for javascript resource
435 - if( this.getResourcePath( loadRequest ) ) {
436 - this.loadResource( loadRequest, callback );
437 - return ;
438 - }
439 -
440 - // Try loading as a "file" or via ScriptLoader
441 - if( loadRequest ) {
442 - // Check if this resource was already requested
443 - if( typeof this.requestedResourceQueue[ loadRequest ] == 'object' ){
444 - this.requestedResourceQueue[ loadRequest ].push( callback );
445 - return ;
446 - } else {
447 - this.requestedResourceQueue[ loadRequest ] = [];
448 - }
449 -
450 - if( loadRequest.indexOf( '.js' ) == -1 && !mw.getResourceLoaderPath() ) {
451 - mw.log( 'Error: are you sure ' + loadRequest + ' is a file ( is it missing a resource path? ) ' );
452 - }
453 - mw.getScript( loadRequest, function(){
454 - // Check if we have requestedResources queue items:
455 - while( _this.requestedResourceQueue[ loadRequest ].length ){
456 - _this.requestedResourceQueue[ loadRequest ].shift()( loadRequest );
457 - }
458 - callback( loadRequest );
459 - // empty the load request queue:
460 - _this.requestedResourceQueue[ loadRequest ] = [];
461 - });
462 - return ;
463 - }
464 -
465 - // Possible error?
466 - mw.log( "Error could not handle load request: " + loadRequest );
467 - },
468 -
469 - getModuleResourceSet: function( moduleName ){
470 - // Check if the module loader is a function ~run that function~
471 - if( typeof ( this.moduleLoaders[ moduleName ] ) == 'function' ) {
472 - // Add the result of the module loader function
473 - return this.moduleLoaders[ moduleName ]();
474 - } else if( typeof ( this.moduleLoaders[ moduleName ] ) == 'object' ){
475 - // set resourceSet directly
476 - return this.moduleLoaders[ moduleName ];
477 - }
478 - return false;
479 - },
480 -
481 - /**
482 - * Clean the loadRequest ( throw out any non-string items )
483 - */
484 - cleanLoadRequest: function( loadRequest ){
485 - var cleanRequest = [];
486 - if( ! loadRequest ){
487 - return [];
488 - }
489 - if( typeof loadRequest == 'string' )
490 - return loadRequest;
491 - for( var i =0;i < loadRequest.length; i++ ){
492 - if( typeof loadRequest[i] == 'object' ) {
493 - cleanRequest[i] = this.cleanLoadRequest( loadRequest[i] );
494 - } else if( typeof loadRequest[i] == 'string' ){
495 - cleanRequest[i] = $j.trim( loadRequest[i] );
496 - } else{
497 - // bad request type skip
498 - }
499 - }
500 - return cleanRequest;
501 - },
502 -
503 - /**
504 - * Load a set of scripts. Will issue many load requests or package the
505 - * request for the resource loader
506 - *
507 - * @param {Object}
508 - * loadSet Set of scripts to be loaded
509 - * @param {Function}
510 - * callback Function to call once all scripts are loaded.
511 - */
512 - loadMany: function( loadSet, callback ) {
513 - var _this = this;
514 - // Setup up the local "loadStates"
515 - var loadStates = { };
516 -
517 - // Check if we can load via the "resource loader" ( mwEmbed was
518 - // included via scriptLoader )
519 - if( mw.getResourceLoaderPath() ) {
520 - // Get the grouped loadStates variable
521 - loadStates = this.getGroupLoadState( loadSet );
522 - if( mw.isEmpty( loadStates ) ) {
523 - // mw.log( 'loadMany:all resources already loaded');
524 - callback();
525 - return ;
526 - }
527 - }else{
528 - // Check if its a dependency set ( nested objects )
529 - if( typeof loadSet [ 0 ] == 'object' ) {
530 - _this.dependencyChainCallFlag[ loadSet ] = false;
531 - // Load sets of resources ( to preserver order for some
532 - // browsers )
533 - _this.loadDependencyChain( loadSet, callback );
534 - return ;
535 - }
536 -
537 - // Set the initial load state for every item in the loadSet
538 - for( var i = 0; i < loadSet.length ; i++ ) {
539 - var loadName = loadSet[ i ];
540 - loadStates[ loadName ] = 0;
541 - }
542 - }
543 -
544 - // We are infact loading many:
545 - // mw.log("mw.load: LoadMany:: " + loadSet );
546 -
547 - // Issue the load request check check loadStates to see if we are
548 - // "done"
549 - for( var loadName in loadStates ) {
550 - // mw.log("loadMany: load: " + loadName );
551 - this.load( loadName, function ( loadName ) {
552 - loadStates[ loadName ] = 1;
553 -
554 - /*
555 - * for( var i in loadStates ) { mw.log( loadName + '
556 - * finished of: ' + i + ' : ' + loadStates[i] ); }
557 - */
558 -
559 - // Check if all load request states are set 1
560 - var loadDone = true;
561 - for( var j in loadStates ) {
562 - if( loadStates[ j ] === 0 )
563 - loadDone = false;
564 - }
565 - // Run the parent scope callback for "loadMany"
566 - if( loadDone ) {
567 - callback( loadName );
568 - }
569 - } );
570 - }
571 - },
572 -
573 - /**
574 - * Get grouped load state for script loader
575 - *
576 - * Groups the scriptRequest where possible: Modules include "loader
577 - * code" so they are separated into pre-condition code to be run for
578 - * subsequent requests
579 - *
580 - * @param {Object}
581 - * loadSet Loadset to return grouped
582 - * @return {Object} grouped loadSet
583 - */
584 - getGroupLoadState: function( loadSet ) {
585 - var groupedLoadSet = [];
586 - var loadStates = { };
587 - // Merge load set into new groupedLoadSet
588 - if( typeof loadSet[0] == 'object' ) {
589 - for( var i = 0; i < loadSet.length ; i++ ) {
590 - for( var j = 0; j < loadSet[i].length ; j++ ) {
591 - // Make sure we have not already included it:
592 - groupedLoadSet.push( loadSet[i][j] );
593 - }
594 - }
595 - } else {
596 - // Use the loadSet directly:
597 - groupedLoadSet = loadSet;
598 - }
599 -
600 - // Setup grouped loadStates Set:
601 - var groupClassKey = '';
602 - var coma = '';
603 - var uniqueResourceName = {};
604 - for( var i=0; i < groupedLoadSet.length; i++ ) {
605 - var loadName = groupedLoadSet[ i ];
606 - if( this.getResourcePath( loadName ) ) {
607 - // Check if not already in request queue and not defined in
608 - // global namespace
609 - if( !mw.isset( loadName ) && ! uniqueResourceName[ loadName] ){
610 - groupClassKey += coma + loadName;
611 - coma = ',';
612 -
613 - // Check for style sheet dependencies
614 - if( this.resourceStyleDependency[ loadName ] ){
615 - groupClassKey += coma + this.resourceStyleDependency[ loadName ];
616 - }
617 - }
618 - } else if ( this.moduleLoaders[ loadName ] ) {
619 -
620 - // Module loaders break up grouped script requests ( add the
621 - // current groupClassKey )
622 - if( groupClassKey != '' ) {
623 - loadStates[ groupClassKey ] = 0;
624 - groupClassKey = coma = '';
625 - }
626 - if( ! uniqueResourceName[ loadName] ){
627 - // Add the module to the loadSate
628 - loadStates[ loadName ] = 0;
629 - }
630 - }
631 - uniqueResourceName[ loadName] = true;
632 - }
633 -
634 - // Add groupClassKey if set:
635 - if( groupClassKey != '' ) {
636 - loadStates [ groupClassKey ] = 0;
637 - }
638 -
639 - return loadStates;
640 - },
641 -
642 - // Array to register that a callback has been called
643 - dependencyChainCallFlag: { },
644 -
645 - /**
646 - * Load a sets of scripts satisfy dependency order for browsers that
647 - * execute dynamically included scripts out of order
648 - *
649 - * @param {Object}
650 - * loadChain A set of javascript arrays to be loaded. Sets
651 - * are requested in array order.
652 - */
653 - loadDependencyChain: function( loadChain, callback ) {
654 - var _this = this;
655 - // Load with dependency checks
656 - var callSet = loadChain.shift();
657 - this.load( callSet, function( cbname ) {
658 - if ( loadChain.length != 0 ) {
659 - _this.loadDependencyChain( loadChain, callback );
660 - } else {
661 - // NOTE: IE gets called twice so we have check the
662 - // dependencyChainCallFlag before calling the callback
663 - if( _this.dependencyChainCallFlag[ callSet ] == callback ) {
664 - mw.log("... already called this callback for " + callSet );
665 - return ;
666 - }
667 - _this.dependencyChainCallFlag[ callSet ] = callback;
668 - callback( );
669 - }
670 - } );
671 - },
672 -
673 - /**
674 - * Add to the module loader queue
675 - */
676 - addToModuleLoaderQueue: function( moduleName, resourceSet, callback ) {
677 - mw.log(" addToModuleLoaderQueue:: " + moduleName + ' resourceSet: ' + resourceSet );
678 - if( this.moduleLoadQueue[ moduleName ] ){
679 - // If the module is already in the queue just add its callback:
680 - this.moduleLoadQueue[ moduleName ].functionQueue.push( callback );
681 - } else {
682 - // create the moduleLoadQueue item
683 - this.moduleLoadQueue[ moduleName ] = {
684 - 'resourceSet' : resourceSet,
685 - 'functionQueue' : [ callback ],
686 - 'loaded' : false
687 - };
688 - }
689 - },
690 -
691 - /**
692 - * Loops over all modules in queue, builds request sets based on config
693 - * request type
694 - */
695 - runModuleLoadQueue: function(){
696 - var _this = this;
697 - mw.log( "mw.runModuleLoadQueue:: " );
698 - var runModuleFunctionQueue = function(){
699 - // Run all the callbacks
700 - for( var moduleName in _this.moduleLoadQueue ){
701 - while( _this.moduleLoadQueue[moduleName].functionQueue.length ) {
702 - _this.moduleLoadQueue[moduleName].functionQueue.shift()();
703 - }
704 - }
705 - };
706 -
707 - // Check for single request or javascript debug based loading:
708 - if( !mw.getResourceLoaderPath() || mw.getConfig( 'loader.groupStrategy' ) == 'single' ){
709 - // if not using the resource load just do a normal array merge
710 - // ( for browsers like IE that don't follow first append first
711 - // execute rule )
712 - var fullResourceList = [];
713 - for( var moduleName in this.moduleLoadQueue ) {
714 - var resourceSet = this.moduleLoadQueue[ moduleName ].resourceSet;
715 - // Lets try a global merge
716 - fullResourceList = $j.merge( fullResourceList, resourceSet );
717 - }
718 - mw.load( fullResourceList, function(){
719 - runModuleFunctionQueue();
720 - });
721 - return ;
722 - }
723 -
724 - // Else do per module group loading
725 - if( mw.getConfig( 'loader.groupStrategy' ) == 'module' ) {
726 - var fullResourceList = [];
727 - var sharedResourceList = [];
728 -
729 - for( var moduleName in this.moduleLoadQueue ) {
730 - // Build a shared dependencies list and load that separately
731 - // "first"
732 - // ( in IE we have to wait until its "ready" since it does
733 - // not follow dom order )
734 - var moduleResourceList = this.getFlatModuleResourceList( moduleName );
735 - // Build the sharedResourceList
736 - for( var i=0; i < moduleResourceList.length; i++ ){
737 - var moduleResource = moduleResourceList[i];
738 - // Check if already in the full resource list if so add
739 - // to shared.
740 - if( fullResourceList[ moduleResource ] ){
741 - if( $j.inArray( moduleResource, sharedResourceList ) == -1 ){
742 - sharedResourceList.push( moduleResource );
743 - }
744 - }
745 - // Add to the fullResourceList
746 - fullResourceList[ moduleResource ] = true;
747 - }
748 - }
749 -
750 - // Local module request set ( stores the actual request we will
751 - // make after grouping shared resources
752 - var moduleRequestSet = {};
753 -
754 - // Only add non-shared to respective modules load requests
755 - for( var moduleName in this.moduleLoadQueue ) {
756 - moduleRequestSet[ moduleName ] = [];
757 - var moduleResourceList = this.getFlatModuleResourceList( moduleName );
758 - for( var i =0; i < moduleResourceList.length; i++ ){
759 - var moduleResource = moduleResourceList[i];
760 - if( $j.inArray( moduleResource, sharedResourceList ) == -1 ){
761 - moduleRequestSet[ moduleName ].push( moduleResource );
762 - }
763 - }
764 - }
765 - var sharedResourceLoadDone = false;
766 - // Check if modules are done
767 - var checkModulesDone = function(){
768 - if( !sharedResourceLoadDone ){
769 - return false;
770 - }
771 - for( var moduleName in _this.moduleLoadQueue ) {
772 - if( ! _this.moduleLoadQueue[ moduleName ].loaded ){
773 - return false;
774 - }
775 - }
776 - runModuleFunctionQueue();
777 - };
778 - // Local instance of load requests to retain resourceSet
779 - // context:
780 - var localLoadCallInstance = function( moduleName, resourceSet ){
781 - mw.load( resourceSet, function(){
782 - _this.moduleLoadQueue[ moduleName ].loaded = true;
783 - checkModulesDone();
784 - });
785 - };
786 -
787 - // Load the shared resources
788 - mw.load( sharedResourceList, function(){
789 - // mw.log("Shared Resources loaded");
790 - // xxx check if we are in "IE" and dependencies need to be
791 - // loaded "first"
792 - sharedResourceLoadDone = true;
793 - checkModulesDone();
794 - });
795 - // Load all module Request Set
796 - for( var moduleName in moduleRequestSet ){
797 - localLoadCallInstance( moduleName, moduleRequestSet[ moduleName ] );
798 - }
799 - }
800 - // xxx Here we could also do some "intelligent" grouping
801 - },
802 -
803 - getFlatModuleResourceList: function( moduleName ){
804 - var moduleList = [];
805 - for( var j in this.moduleLoadQueue[moduleName].resourceSet ){
806 - // Check if we have a multi-set array:
807 - if( typeof this.moduleLoadQueue[moduleName].resourceSet[j] == 'object' ){
808 - moduleList = $j.merge( moduleList, this.moduleLoadQueue[moduleName].resourceSet[j] );
809 - } else {
810 - moduleList = $j.merge( moduleList, [ this.moduleLoadQueue[moduleName].resourceSet[j] ] );
811 - }
812 - }
813 - return moduleList;
814 - },
815 -
816 - /**
817 - * Loads javascript or css associated with a resourceName
818 - *
819 - * @param {String}
820 - * resourceName Name of resource to load
821 - * @param {Function}
822 - * callback Function to run once resource is loaded
823 - */
824 - loadResource: function( resourceName , callback) {
825 - // mw.log("LoadResource:" + resourceName );
826 - var _this = this;
827 -
828 - // Check for css dependency on resource name
829 - if( this.resourceStyleDependency[ resourceName ] ) {
830 - if( ! mw.isset( this.resourceStyleDependency[ resourceName ] )){
831 - mw.log("loadResource:: dependent css resource: " + this.resourceStyleDependency[ resourceName ] );
832 - _this.loadResource( this.resourceStyleDependency[ resourceName ] , function() {
833 - // Continue the original loadResource request.
834 - _this.loadResource( resourceName, callback );
835 - });
836 - return ;
837 - }
838 - }
839 -
840 - // Make sure the resource is not already defined:
841 - if ( mw.isset( resourceName ) ) {
842 - // mw.log( 'Class ( ' + resourceName + ' ) already defined ' );
843 - callback( resourceName );
844 - return ;
845 - }
846 -
847 - // Setup the Script Request var:
848 - var scriptRequest = null;
849 -
850 -
851 - // If the scriptloader is enabled use the resourceName as the
852 - // scriptRequest:
853 - if( mw.getResourceLoaderPath() ) {
854 - scriptRequest = resourceName;
855 - }else{
856 - // Get the resource url:
857 - var baseClassPath = this.getResourcePath( resourceName );
858 - // Add the mwEmbed path if not a root path or a full url
859 - if( baseClassPath.indexOf( '/' ) !== 0 &&
860 - baseClassPath.indexOf( '://' ) === -1 ) {
861 - scriptRequest = mw.getMwEmbedPath() + baseClassPath;
862 - }else{
863 - scriptRequest = baseClassPath;
864 - }
865 - if( ! scriptRequest ) {
866 - mw.log( "Error Could not get url for resource " + resourceName );
867 - return false;
868 - }
869 - }
870 - // Include resource defined check for older browsers
871 - var resourceDone = false;
872 -
873 - // Set the loadDone callback per the provided resourceName
874 - mw.setLoadDoneCB( resourceName, callback );
875 - // Issue the request to load the resource (include resource name in
876 - // result callback:
877 - mw.getScript( scriptRequest, function( scriptRequest ) {
878 - // If its a "style sheet" manually set its resource to true
879 - var ext = scriptRequest.substr( scriptRequest.split('?')[0].lastIndexOf( '.' ), 4 ).toLowerCase();
880 - if( ext == '.css' && resourceName.substr(0,8) == 'mw.style' ){
881 - mw.style[ resourceName.substr( 9 ) ] = true;
882 - }
883 -
884 - // Send warning if resourceName is not defined
885 - if(! mw.isset( resourceName )
886 - && mwLoadDoneCB[ resourceName ] != 'done' ) {
887 - // mw.log( 'Possible Error: ' + resourceName +' not set in
888 - // time, or not defined in:' + "\n"
889 - // + _this.getResourcePath( resourceName ) );
890 - }
891 -
892 - // If ( debug mode ) and the script include is missing resource
893 - // messages
894 - // do a separate request to retrieve the msgs
895 - if( mw.currentClassMissingMessages ) {
896 - mw.log( " resourceName " + resourceName + " is missing messages" );
897 - // Reset the currentClassMissingMessages flag
898 - mw.currentClassMissingMessages = false;
899 -
900 - // Load msgs for this resource:
901 - mw.loadResourceMessages( resourceName, function() {
902 - // Run the onDone callback
903 - mw.loadDone( resourceName );
904 - } );
905 - } else {
906 - // If not using the resource loader make sure the
907 - // resourceName is available before firing the loadDone
908 - if( !mw.getResourceLoaderPath() ) {
909 - mw.waitForObject( resourceName, function( resourceName ) {
910 - // Once object is ready run loadDone
911 - mw.loadDone( resourceName );
912 - } );
913 - } else {
914 - // loadDone should be appended to the bottom of the
915 - // resource loader response
916 - // mw.loadDone( resourceName );
917 - }
918 - }
919 - } );
920 - },
921 -
922 - /**
923 - * Adds a module to the mwLoader object
924 - *
925 - * @param {String}
926 - * name Name of module
927 - * @param {Function}
928 - * moduleLoader Function that loads dependencies for a module
929 - */
930 - addModuleLoader: function( name, moduleLoader ) {
931 - this.moduleLoaders [ name ] = moduleLoader;
932 - },
933 -
934 - /**
935 - * Adds resource file path key value pairs
936 - *
937 - * @param {Object}
938 - * resourceSet JSON formated list of resource name file path
939 - * pairs.
940 - *
941 - * resourceSet must be strict JSON to allow the php scriptLoader to
942 - * parse the file paths.
943 - */
944 - addResourcePaths: function( resourceSet ) {
945 - var prefix = ( mw.getConfig( 'loaderContext' ) )?
946 - mw.getConfig( 'loaderContext' ): '';
947 -
948 - for( var i in resourceSet ) {
949 - this.resourcePaths[ i ] = prefix + resourceSet[ i ];
950 - }
951 - },
952 -
953 - /*
954 - * Adds a named style sheet dependency to a named resource
955 - *
956 - * @parma {Object} resourceSet JSON formated list of resource names and
957 - * associated style sheet names
958 - */
959 - addStyleResourceDependency: function( resourceSet ){
960 - for( var i in resourceSet ){
961 - this.resourceStyleDependency[ i ] = resourceSet[i];
962 - }
963 - },
964 -
965 - /**
966 - * Get a resource path from a resourceName if no resource found return
967 - * false
968 - */
969 - getResourcePath: function( resourceName ) {
970 - if( this.resourcePaths[ resourceName ] )
971 - return this.resourcePaths[ resourceName ];
972 - return false;
973 - }
974 - };
975 -
976 - /**
977 - * Load done callback for script loader
978 - *
979 - * @param {String}
980 - * requestName Name of the load request
981 - */
982 - mw.loadDone = function( requestName ) {
983 - if( !mwLoadDoneCB[ requestName ] ) {
984 - return true;
985 - }
986 - while( mwLoadDoneCB[ requestName ].length ) {
987 - // check if mwLoadDoneCB is already "done"
988 - // the function list is not an object
989 - if( typeof mwLoadDoneCB[ requestName ] != 'object' )
990 - {
991 - break;
992 - }
993 - var func = mwLoadDoneCB[ requestName ].pop();
994 - if( typeof func == 'function' ) {
995 - // mw.log( "LoadDone: " + requestName + ' run callback::' +
996 - // func);
997 - func( requestName );
998 - }else{
999 - mw.log('mwLoadDoneCB: Error non callback function on stack');
1000 - }
1001 - }
1002 - // Set the load request name to done
1003 - mwLoadDoneCB[ requestName ] = 'done';
1004 - };
1005 -
1006 - /**
1007 - * Set a load done callback
1008 - *
1009 - * @param {String}
1010 - * requestName Name of resource or request set
1011 - * @param {Function}
1012 - * callback Function called once requestName is ready
1013 - */
1014 - mw.setLoadDoneCB = function( requestName, callback ) {
1015 - // If the requestName is already done loading just callback
1016 - if( mwLoadDoneCB[ requestName ] == 'done' ) {
1017 - callback( requestName );
1018 - }
1019 - // Setup the function queue if unset
1020 - if( typeof mwLoadDoneCB[ requestName ] != 'object' ) {
1021 - mwLoadDoneCB[ requestName ] = [];
1022 - }
1023 - mwLoadDoneCB[ requestName ].push( callback );
1024 - };
1025 -
1026 - /**
1027 - * Shortcut entry points / convenience functions: Lets you write mw.load()
1028 - * instead of mw.loader.load() only these entry points should be used.
1029 - *
1030 - * future closure optimizations could minify internal function names
1031 - */
1032 -
1033 - /**
1034 - * Load Object entry point: Loads a requested set of javascript
1035 - */
1036 - mw.load = function( loadRequest, callback ) {
1037 - return mw.loader.load( loadRequest, callback );
1038 - };
1039 -
1040 - /**
1041 - * Add module entry point: Adds a module to the mwLoader object
1042 - */
1043 - mw.addModuleLoader = function ( name, loaderFunction ) {
1044 - return mw.loader.addModuleLoader( name, loaderFunction );
1045 - };
1046 -
1047 - /**
1048 - * Add Class File Paths entry point:
1049 - */
1050 - mw.addResourcePaths = function ( resourceSet ) {
1051 - return mw.loader.addResourcePaths( resourceSet );
1052 - };
1053 -
1054 - mw.addStyleResourceDependency = function ( resourceSet ) {
1055 - return mw.loader.addStyleResourceDependency( resourceSet );
1056 - };
1057 -
1058 - /**
1059 - * Get Class File Path entry point:
1060 - */
1061 - mw.getResourcePath = function( resourceName ) {
1062 - return mw.loader.getResourcePath( resourceName );
1063 - };
1064 -
1065 -
1066 - /**
1067 - * Utility Functions
1068 - */
1069 -
1070 - /**
1071 - * addLoaderDialog small helper for displaying a loading dialog
1072 - *
1073 - * @param {String}
1074 - * dialogHtml text Html of the loader msg
1075 - */
1076 - mw.addLoaderDialog = function( dialogHtml ) {
1077 - if( typeof dialogHtml == 'undefined'){
1078 - dialogHtml ='';
1079 - }
1080 - var $dialog = mw.addDialog( {
1081 - 'title' : dialogHtml,
1082 - 'content' : dialogHtml + '<br>' +
1083 - $j('<div />')
1084 - .loadingSpinner()
1085 - .html()
1086 - });
1087 - return $dialog;
1088 - };
1089 -
1090 - /**
1091 - * Close the loader dialog created with addLoaderDialog
1092 - */
1093 - mw.closeLoaderDialog = function() {
1094 - // Make sure the dialog resource is present
1095 - if( !mw.isset( '$j.ui.dialog' ) ) {
1096 - return false;
1097 - }
1098 - // Close with timeout since jquery ui binds with timeout:
1099 - // ui dialog line 530
1100 - setTimeout( function(){
1101 - $j( '#mwTempLoaderDialog' )
1102 - .dialog( 'destroy' );
1103 - } , 10);
1104 - };
1105 -
1106 - /**
1107 - * Add a (temporary) dialog window:
1108 - *
1109 - * @param {Object}
1110 - * with following keys: title: {String} Title string for the
1111 - * dialog content: {String} to be inserted in msg box buttons:
1112 - * {Object} A button object for the dialog Can be a string for
1113 - * the close button any jquery.ui.dialog option
1114 - */
1115 - mw.addDialog = function ( options ) {
1116 - // Remove any other dialog
1117 - $j( '#mwTempLoaderDialog' ).remove();
1118 -
1119 - if( !options){
1120 - options = {};
1121 - }
1122 -
1123 - // Extend the default options with provided options
1124 - var options = $j.extend({
1125 - 'bgiframe': true,
1126 - 'draggable': true,
1127 - 'resizable': false,
1128 - 'modal': true,
1129 - 'position' : ['center', 'center']
1130 - }, options );
1131 -
1132 - if( ! options.title || ! options.content ){
1133 - mw.log("Error: mwEmbed addDialog missing required options ( title, content ) ");
1134 - return ;
1135 - }
1136 -
1137 - // Append the dialog div on top:
1138 - $j( 'body' ).append(
1139 - $j('<div />')
1140 - .attr( {
1141 - 'id' : "mwTempLoaderDialog",
1142 - 'title' : options.title
1143 - })
1144 - .hide()
1145 - .append( options.content )
1146 - );
1147 -
1148 - // Build the uiRequest
1149 - var uiRequest = [ '$j.ui.dialog' ];
1150 - if( options.draggable ){
1151 - uiRequest.push( '$j.ui.mouse' );
1152 - uiRequest.push( '$j.ui.draggable' );
1153 - }
1154 - if( options.resizable ){
1155 - uiRequest.push( '$j.ui.resizable' );
1156 - }
1157 -
1158 - // Special button string
1159 - if ( typeof options.buttons == 'string' ) {
1160 - var buttonMsg = options.buttons;
1161 - buttons = { };
1162 - options.buttons[ buttonMsg ] = function() {
1163 - $j( this ).dialog( 'close' );
1164 - };
1165 - }
1166 -
1167 - // Load the dialog resources
1168 - mw.load([
1169 - [
1170 - '$j.ui',
1171 - '$j.widget',
1172 - '$j.ui.mouse',
1173 - '$j.ui.position'
1174 - ],
1175 - uiRequest
1176 - ], function() {
1177 - var $dialog = $j( '#mwTempLoaderDialog' ).show().dialog( options );
1178 - } );
1179 - return $j( '#mwTempLoaderDialog' );
1180 - };
1181 -
1182 - mw.isIphone = function(){
1183 - return ( navigator.userAgent.indexOf('iPhone') != -1 && ! mw.isIpad() );
1184 - };
1185 - // Uses hack described at:
1186 - // http://www.bdoran.co.uk/2010/07/19/detecting-the-iphone4-and-resolution-with-javascript-or-php/
1187 - mw.isIphone4 = function(){
1188 - return ( mw.isIphone() && ( window.devicePixelRatio && window.devicePixelRatio >= 2 ) );
1189 - };
1190 - mw.isIpod = function(){
1191 - return ( navigator.userAgent.indexOf('iPod') != -1 );
1192 - };
1193 - mw.isIpad = function(){
1194 - return ( navigator.userAgent.indexOf('iPad') != -1 );
1195 - };
1196 - // Android 2 has some restrictions vs other mobile platforms
1197 - mw.isAndroid2 = function(){
1198 - return ( navigator.userAgent.indexOf( 'Android 2.') != -1 );
1199 - };
1200 -
1201 - /**
1202 - * Fallforward system by default prefers flash.
1203 - *
1204 - * This is separate from the EmbedPlayer library detection to provide
1205 - * package loading control NOTE: should be phased out in favor of browser
1206 - * feature detection where possible
1207 - *
1208 - */
1209 - mw.isHTML5FallForwardNative = function(){
1210 - if( mw.isMobileHTML5() ){
1211 - return true;
1212 - }
1213 - // Check for url flag to force html5:
1214 - if( document.URL.indexOf('forceMobileHTML5') != -1 ){
1215 - return true;
1216 - }
1217 - // Fall forward native:
1218 - // if the browser supports flash ( don't use html5 )
1219 - if( mw.supportsFlash() ){
1220 - return false;
1221 - }
1222 - // No flash return true if the browser supports html5 video tag with
1223 - // basic support for canPlayType:
1224 - if( mw.supportsHTML5() ){
1225 - return true;
1226 - }
1227 -
1228 - return false;
1229 - }
1230 -
1231 - mw.isMobileHTML5 = function(){
1232 - // Check for a mobile html5 user agent:
1233 - if ( mw.isIphone() ||
1234 - mw.isIpod() ||
1235 - mw.isIpad() ||
1236 - mw.isAndroid2()
1237 - ){
1238 - return true;
1239 - }
1240 - return false;
1241 - }
1242 - mw.supportsHTML5 = function(){
1243 - // Blackberry is evil in its response to canPlayType calls.
1244 - if( navigator.userAgent.indexOf('BlackBerry') != -1 ){
1245 - return false ;
1246 - }
1247 - var dummyvid = document.createElement( "video" );
1248 - if( dummyvid.canPlayType ) {
1249 - return true;
1250 - }
1251 - return false;
1252 - }
1253 -
1254 - mw.supportsFlash = function(){
1255 - // Check if the client does not have flash and has the video tag
1256 - if ( navigator.mimeTypes && navigator.mimeTypes.length > 0 ) {
1257 - for ( var i = 0; i < navigator.mimeTypes.length; i++ ) {
1258 - var type = navigator.mimeTypes[i].type;
1259 - var semicolonPos = type.indexOf( ';' );
1260 - if ( semicolonPos > -1 ) {
1261 - type = type.substr( 0, semicolonPos );
1262 - }
1263 - if (type == 'application/x-shockwave-flash' ) {
1264 - // flash is installed
1265 - return true;
1266 - }
1267 - }
1268 - }
1269 -
1270 - // for IE:
1271 - var hasObj = true;
1272 - if( typeof ActiveXObject != 'undefined' ){
1273 - try {
1274 - var obj = new ActiveXObject( 'ShockwaveFlash.ShockwaveFlash' );
1275 - } catch ( e ) {
1276 - hasObj = false;
1277 - }
1278 - if( hasObj ){
1279 - return true;
1280 - }
1281 - }
1282 - return false;
1283 - };
1284 - /**
1285 - * Similar to php isset function checks if the variable exists. Does a safe
1286 - * check of a descendant method or variable
1287 - *
1288 - * @param {String}
1289 - * objectPath
1290 - * @return {Boolean} true if objectPath exists false if objectPath is
1291 - * undefined
1292 - */
1293 - mw.isset = function( objectPath ) {
1294 - if ( !objectPath || typeof objectPath != 'string') {
1295 - return false;
1296 - }
1297 - var pathSet = objectPath.split( '.' );
1298 - var cur_path = '';
1299 -
1300 - for ( var p = 0; p < pathSet.length; p++ ) {
1301 - cur_path = ( cur_path == '' ) ? cur_path + pathSet[p] : cur_path + '.' + pathSet[p];
1302 - eval( 'var ptest = typeof ( ' + cur_path + ' ); ' );
1303 - if ( ptest == 'undefined' ) {
1304 - return false;
1305 - }
1306 - }
1307 - return true;
1308 - };
1309 -
1310 - /**
1311 - * Wait for a object to be defined and the call the callback
1312 - *
1313 - * @param {Object}
1314 - * objectName Name of object to be defined
1315 - * @param {Function}
1316 - * callback Function to call once object is defined
1317 - * @param {Null}
1318 - * callNumber Used internally to keep track of number of times
1319 - * waitForObject has been called
1320 - */
1321 - var waitTime = 1200; // About 30 seconds
1322 - mw.waitForObject = function( objectName, callback, _callNumber) {
1323 - // mw.log( 'waitForObject: ' + objectName + ' cn: ' + _callNumber);
1324 -
1325 - // Increment callNumber:
1326 - if( !_callNumber ) {
1327 - _callNumber = 1;
1328 - } else {
1329 - _callNumber++;
1330 - }
1331 -
1332 - if( _callNumber > waitTime ) {
1333 - mw.log( "Error: waiting for object: " + objectName + ' timeout ' );
1334 - callback( false );
1335 - return ;
1336 - }
1337 -
1338 - // If the object is defined ( or we are done loading from a callback )
1339 - if ( mw.isset( objectName ) || mwLoadDoneCB[ objectName ] == 'done' ) {
1340 - callback( objectName );
1341 - }else{
1342 - setTimeout( function( ) {
1343 - mw.waitForObject( objectName, callback, _callNumber);
1344 - }, 25);
1345 - }
1346 - };
1347 -
1348 - /**
1349 - * Check if an object is empty or if its an empty string.
1350 - *
1351 - * @param {Object}
1352 - * object Object to be checked
1353 - */
1354 - mw.isEmpty = function( object ) {
1355 - if( typeof object == 'string' ) {
1356 - if( object == '' ) return true;
1357 - // Non empty string:
1358 - return false;
1359 - }
1360 -
1361 - // If an array check length:
1362 - if( Object.prototype.toString.call( object ) === "[object Array]"
1363 - && object.length == 0 ) {
1364 - return true;
1365 - }
1366 -
1367 - // Else check as an object:
1368 - for( var i in object ) { return false; }
1369 -
1370 - // Else object is empty:
1371 - return true;
1372 - };
1373 -
1374 - /**
1375 - * Log a string msg to the console
1376 - *
1377 - * all mw.log statements will be removed on minification so lots of mw.log
1378 - * calls will not impact performance in non debug mode
1379 - *
1380 - * @param {String}
1381 - * string String to output to console
1382 - */
1383 - mw.log = function( string ) {
1384 - // Add any prepend debug strings if necessary
1385 - if ( mw.getConfig( 'Mw.LogPrepend' ) ){
1386 - string = mw.getConfig( 'Mw.LogPrepend' ) + string;
1387 - }
1388 - // To debug stack size ( useful for iPad / safari that have a 100 call
1389 - // stack limit
1390 - // string = mw.getCallStack().length -1 + ' : ' + string;
1391 -
1392 - if ( window.console ) {
1393 - window.console.log( string );
1394 - } else {
1395 - /**
1396 - * Old IE and non-Firebug debug: ( commented out for now )
1397 - */
1398 -
1399 - /*
1400 - * var log_elm = document.getElementById('mv_js_log'); if(!log_elm) {
1401 - * document.getElementsByTagName("body")[0].innerHTML += '<div ' +
1402 - * 'style="position:absolute;z-index:500;bottom:0px;left:0px;right:0px;height:200px;">' + '<textarea
1403 - * id="mv_js_log" cols="120" rows="12"></textarea>' + '</div>'; }
1404 - * var log_elm = document.getElementById('mv_js_log'); if(log_elm) {
1405 - * log_elm.value+=string+"\n"; // scroll to bottom:
1406 - * log_elm.scrollTop = log_elm.scrollHeight; }
1407 - */
1408 - }
1409 - };
1410 - mw.getCallStack = function(){
1411 - var stringifyArguments = function(args) {
1412 - for (var i = 0; i < args.length; ++i) {
1413 - var arg = args[i];
1414 - if (arg === undefined) {
1415 - args[i] = 'undefined';
1416 - } else if (arg === null) {
1417 - args[i] = 'null';
1418 - } else if (arg.constructor) {
1419 - if (arg.constructor === Array) {
1420 - if (arg.length < 3) {
1421 - args[i] = '[' + stringifyArguments(arg) + ']';
1422 - } else {
1423 - args[i] = '[' + stringifyArguments(Array.prototype.slice.call(arg, 0, 1)) + '...' + stringifyArguments(Array.prototype.slice.call(arg, -1)) + ']';
1424 - }
1425 - } else if (arg.constructor === Object) {
1426 - args[i] = '#object';
1427 - } else if (arg.constructor === Function) {
1428 - args[i] = '#function';
1429 - } else if (arg.constructor === String) {
1430 - args[i] = '"' + arg + '"';
1431 - }
1432 - }
1433 - }
1434 - return args.join(',');
1435 - };
1436 - var getStack = function(curr){
1437 - var ANON = '{anonymous}', fnRE = /function\s*([\w\-$]+)?\s*\(/i,
1438 - stack = [], fn, args, maxStackSize = 100;
1439 -
1440 - while (curr && stack.length < maxStackSize) {
1441 - fn = fnRE.test(curr.toString()) ? RegExp.$1 || ANON : ANON;
1442 - args = Array.prototype.slice.call(curr['arguments']);
1443 - stack[stack.length] = fn + '(' + stringifyArguments(args) + ')';
1444 - curr = curr.caller;
1445 - }
1446 - return stack;
1447 - }
1448 - // Add stack size ( iPad has 100 stack size limit )
1449 - var stack = getStack( arguments.callee );
1450 - return stack;
1451 - }
1452 -
1453 - // Setup the local mwOnLoadFunctions array:
1454 - var mwOnLoadFunctions = [];
1455 -
1456 - // mw Ready flag ( set once mwEmbed is ready )
1457 - var mwReadyFlag = false;
1458 -
1459 - /**
1460 - * Enables load hooks to run once mwEmbeed is "ready" Will ensure jQuery is
1461 - * available, is in the $j namespace and mw interfaces and configuration has
1462 - * been loaded and applied
1463 - *
1464 - * This is different from jQuery(document).ready() ( jQuery ready is not
1465 - * friendly with dynamic includes and not friendly with core interface
1466 - * asynchronous build out. )
1467 - *
1468 - * @param {Function}
1469 - * callback Function to run once DOM and jQuery are ready
1470 - */
1471 - mw.ready = function( callback ) {
1472 - if( mwReadyFlag === false ) {
1473 - // Add the callbcak to the onLoad function stack
1474 - mwOnLoadFunctions.push ( callback );
1475 - } else {
1476 - // If mwReadyFlag is already "true" issue the callback directly:
1477 - callback();
1478 - }
1479 - };
1480 -
1481 - /**
1482 - * Runs all the queued functions called by mwEmbedSetup
1483 - */
1484 - mw.runReadyFunctions = function ( ) {
1485 - mw.log('mw.runReadyFunctions: ' + mwOnLoadFunctions.length );
1486 - // Run any pre-setup ready functions
1487 - while( preMwEmbedReady.length ){
1488 - preMwEmbedReady.shift()();
1489 - }
1490 - // Run all the queued functions:
1491 - while( mwOnLoadFunctions.length ) {
1492 - mwOnLoadFunctions.shift()();
1493 - }
1494 - // Sets mwReadyFlag to true so that future mw.ready run the
1495 - // callback directly
1496 - mwReadyFlag = true;
1497 -
1498 - // Once we have run all the queued functions
1499 - setTimeout(function(){
1500 - mw.loader.runModuleLoadQueue();
1501 - },1);
1502 - };
1503 -
1504 -
1505 - /**
1506 - * Wrapper for jQuery getScript, Uses the scriptLoader if enabled
1507 - *
1508 - *
1509 - * @param {String}
1510 - * scriptRequest The requested path or resourceNames for the
1511 - * scriptLoader
1512 - * @param {Function}
1513 - * callback Function to call once script is loaded
1514 - */
1515 - mw.getScript = function( scriptRequest, callback ) {
1516 - // mw.log( "mw.getScript::" + scriptRequest );
1517 - // Setup the local scope callback instace
1518 - var myCallback = function(){
1519 - if( callback ) {
1520 - callback( scriptRequest );
1521 - }
1522 - };
1523 - // Set the base url based scriptLoader availability & type of
1524 - // scriptRequest
1525 - // ( presently script loader only handles "classes" not relative urls:
1526 - var scriptLoaderPath = mw.getResourceLoaderPath();
1527 -
1528 - // Check if its a resource name, ( ie does not start with "/" and does
1529 - // not include ://
1530 - var isResourceName = ( scriptRequest.indexOf('://') == -1 && scriptRequest.indexOf('/') !== 0 )? true : false;
1531 -
1532 - var ext = scriptRequest.substr( scriptRequest.lastIndexOf( '.' ), 4 ).toLowerCase();
1533 - var isCssFile = ( ext == '.css') ? true : false ;
1534 -
1535 - if( scriptLoaderPath && isResourceName ) {
1536 - url = scriptLoaderPath + '?class=' + scriptRequest ;
1537 - } else {
1538 - // Add the mwEmbed path if a relative path request
1539 - url = ( isResourceName ) ? mw.getMwEmbedPath() : '';
1540 - url+= scriptRequest;
1541 - }
1542 -
1543 - // Add on the request parameters to the url:
1544 - url += ( url.indexOf( '?' ) == -1 )? '?' : '&';
1545 - url += mw.getUrlParam();
1546 -
1547 - // Only log sciprts ( Css is logged via "add css" )
1548 - if( !isCssFile ){
1549 - mw.log( 'mw.getScript: ' + url );
1550 - }
1551 -
1552 - // If jQuery is available and debug is off load the script via jQuery
1553 - // ( will use XHR if on same domain )
1554 - if( mw.isset( 'window.jQuery' )
1555 - && mw.getConfig( 'debug' ) === false
1556 - && typeof $j != 'undefined'
1557 - && mw.parseUri( url ).protocal != 'file'
1558 - && !isCssFile )
1559 - {
1560 - $j.getScript( url, myCallback);
1561 - return ;
1562 - }
1563 -
1564 - /**
1565 - * No jQuery OR In debug mode OR Is css file :: inject the script
1566 - * instead of doing an XHR eval
1567 - */
1568 -
1569 - // load style sheet directly if requested loading css
1570 - if( isCssFile ){
1571 - mw.getStyleSheet( url, myCallback);
1572 - return ;
1573 - }
1574 -
1575 - // Load and bind manually: ( copied from jQuery ajax function )
1576 - var head = document.getElementsByTagName("head")[ 0 ];
1577 - var script = document.createElement("script");
1578 - script.setAttribute( 'src', url );
1579 -
1580 - // Attach handlers ( if using script loader it issues onDone callback as
1581 - // well )
1582 - script.onload = script.onreadystatechange = function() {
1583 - if (!this.readyState || this.readyState == "loaded" || this.readyState == "complete") {
1584 - myCallback();
1585 - }
1586 - };
1587 - // mw.log(" append script: " + script.src );
1588 - // Append the script to the DOM:
1589 - head.appendChild( script );
1590 - };
1591 -
1592 - /**
1593 - * Add a style sheet string to the document head
1594 - *
1595 - * @param {String}
1596 - * cssResourceName Name of style sheet that has been defined
1597 - * @param {String}
1598 - * cssString Css Payload to be added to head of document
1599 - */
1600 - mw.addStyleString = function( cssResourceName, cssString ) {
1601 - if( mw.style[ cssResourceName ] ) {
1602 - mw.log(" Style: ( " + cssResourceName + ' ) already set' );
1603 - return true;
1604 - }
1605 - // Set the style to true ( to not request it again )
1606 - mw.style[ cssResourceName ] = true;
1607 - // Add the spinner directly ( without jQuery in case we have to
1608 - // dynamically load jQuery )
1609 - mw.log( 'Adding style:' + cssResourceName + " to dom " );
1610 - var styleNode = document.createElement('style');
1611 - styleNode.type = "text/css";
1612 - // Use cssText or createTextNode depending on browser:
1613 - if( ( window.attachEvent && !window.opera ) ) {
1614 - styleNode.styleSheet.cssText = cssString;
1615 - } else {
1616 - var styleText = document.createTextNode( cssString );
1617 - styleNode.appendChild( styleText );
1618 - }
1619 - var head = document.getElementsByTagName("head")[0];
1620 - head.appendChild( styleNode );
1621 - };
1622 -
1623 - /**
1624 - * Get a style sheet and append the style sheet to the DOM
1625 - *
1626 - * @param {Mixed}
1627 - * {String} url Url of the style sheet to be loaded {Function}
1628 - * callback Function called once sheet is ready
1629 - */
1630 - mw.getStyleSheet = function( url , callback) {
1631 - // Add URL params ( if not already included )
1632 - if ( url.indexOf( '?' ) == -1 ) {
1633 - url += '?' + mw.getUrlParam();
1634 - }
1635 -
1636 - // Check if style sheet is already included:
1637 - var foundSheet = false;
1638 - $j( 'link' ).each( function() {
1639 - var currentSheet = $j( this) .attr( 'href' );
1640 - var sheetParts = currentSheet.split('?');
1641 - var urlParts = url.split('?');
1642 - // if the base url's match check the parameters:
1643 - if( sheetParts[0] == urlParts[0] && sheetParts[1]) {
1644 - // Check if url params match ( sort to do string compare )
1645 - if( sheetParts[1].split( '&' ).sort().join('') ==
1646 - urlParts[1].split('&').sort().join('') ) {
1647 - foundSheet = true;
1648 - }
1649 - }
1650 - } );
1651 - if( foundSheet ) {
1652 - mw.log( 'skiped sheet: ' + url);
1653 - if( callback) {
1654 - callback();
1655 - }
1656 - return ;
1657 - }
1658 -
1659 - mw.log( ' add css: ' + url );
1660 - $j( 'head' ).append(
1661 - $j('<link />').attr( {
1662 - 'rel' : 'stylesheet',
1663 - 'type' : 'text/css',
1664 - 'href' : url
1665 - } )
1666 - );
1667 - // No easy way to check css "onLoad" attribute
1668 - // In production sheets are loaded via resource loader and fire the
1669 - // onDone function call.
1670 - if( callback ) {
1671 - callback();
1672 - }
1673 - };
1674 -
1675 - mw.getRelativeMwEmbedPath = function(){
1676 - return mw.getMwEmbedPath(true);
1677 - };
1678 - /**
1679 - * Get the path to the mwEmbed folder
1680 - */
1681 - mw.getMwEmbedPath = function( relativePath ) {
1682 - // Get mwEmbed src:
1683 - var src = mw.getMwEmbedSrc();
1684 - var mwpath = null;
1685 -
1686 - // Check for direct include of the mwEmbed.js
1687 - if ( src.indexOf( 'mwEmbed.js' ) !== -1 ) {
1688 - alert( 'Direct Refrece to mwEmbed is no longer suported, please update to ResourceLoader.php?class=window.jQuery,mwEmbed& instead');
1689 - mwpath = src.substr( 0, src.indexOf( 'mwEmbed.js' ) );
1690 - }
1691 -
1692 - // Check for scriptLoader include of mwEmbed:
1693 - if ( src.indexOf( 'mwResourceLoader.php' ) !== -1 ) {
1694 - // Script loader is in the root of MediaWiki, Include the default
1695 - // mwEmbed extension path:
1696 - mwpath = src.substr( 0, src.indexOf( 'mwResourceLoader.php' ) ) + mw.getConfig( 'mediaWikiEmbedPath' );
1697 - }
1698 -
1699 - // resource loader has ResourceLoader name when local:
1700 - if( src.indexOf( 'ResourceLoader.php' ) !== -1 ) {
1701 - mwpath = src.substr( 0, src.indexOf( 'ResourceLoader.php' ) );
1702 - }
1703 -
1704 - // For static packages mwEmbed packages start with: "mwEmbed-"
1705 - if( src.indexOf( 'mwEmbed-' ) !== -1 && src.indexOf( '-static' ) !== -1 ) {
1706 - mwpath = src.substr( 0, src.indexOf( 'mwEmbed-' ) );
1707 - }
1708 -
1709 - // Error out if we could not get the path:
1710 - if( mwpath === null ) {
1711 - mw.log( "Error could not get mwEmbed path " );
1712 - return ;
1713 - }
1714 -
1715 - // Update the cached var with the absolute path:
1716 - if( !relativePath ){
1717 - mwpath = mw.absoluteUrl( mwpath ) ;
1718 - }
1719 - return mwpath;
1720 - };
1721 -
1722 - /**
1723 - * Get Script loader path
1724 - *
1725 - * @returns {String}|{Boolean} Url of the scriptLodaer false if the
1726 - * scriptLoader is not used
1727 - */
1728 - mw.getResourceLoaderPath = function( ) {
1729 - var src = mw.getMwEmbedSrc();
1730 - if ( src.indexOf( 'mwResourceLoader.php' ) !== -1 ||
1731 - src.indexOf( 'ResourceLoader.php' ) !== -1 )
1732 - {
1733 - // Return just the script part of the url
1734 - return src.split('?')[0];
1735 - }
1736 - return false;
1737 - };
1738 - /**
1739 - * Given a float number of seconds, returns npt format response. ( ignore
1740 - * days for now )
1741 - *
1742 - * @param {Float}
1743 - * sec Seconds
1744 - * @param {Boolean}
1745 - * verbose If hours and milliseconds should padded be displayed.
1746 - * @return {Float} String npt format
1747 - */
1748 - mw.seconds2npt = function( sec, verbose ) {
1749 - if ( isNaN( sec ) ) {
1750 - mw.log("Warning: trying to get npt time on NaN:" + sec);
1751 - return '0:00:00';
1752 - }
1753 -
1754 - var tm = mw.seconds2Measurements( sec );
1755 -
1756 - // Round the number of seconds to the required number of significant
1757 - // digits
1758 - if ( verbose ) {
1759 - tm.seconds = Math.round( tm.seconds * 1000 ) / 1000;
1760 - } else {
1761 - tm.seconds = Math.round( tm.seconds );
1762 - }
1763 - if ( tm.seconds < 10 ){
1764 - tm.seconds = '0' + tm.seconds;
1765 - }
1766 - if( tm.hours == 0 && !verbose ){
1767 - hoursStr = '';
1768 - } else {
1769 - if ( tm.minutes < 10 && verbose) {
1770 - tm.minutes = '0' + tm.minutes;
1771 - }
1772 -
1773 - if( tm.hours < 10 && verbose){
1774 - tm.hours = '0' + tm.hours;
1775 - }
1776 -
1777 - hoursStr = tm.hours + ':';
1778 - }
1779 - return hoursStr + tm.minutes + ":" + tm.seconds;
1780 - };
1781 - /**
1782 - * Given seconds return array with 'days', 'hours', 'min', 'seconds'
1783 - *
1784 - * @param {float}
1785 - * sec Seconds to be converted into time measurements
1786 - */
1787 - mw.seconds2Measurements = function ( sec ){
1788 - var tm = {};
1789 - tm.days = Math.floor( sec / ( 3600 * 24 ) );
1790 - tm.hours = Math.floor( sec / 3600 );
1791 - tm.minutes = Math.floor( ( sec / 60 ) % 60 );
1792 - tm.seconds = sec % 60;
1793 - return tm;
1794 - };
1795 -
1796 - /**
1797 - * Given a float number of seconds, returns npt format response. ( ignore
1798 - * days for now )
1799 - *
1800 - * @param {Float}
1801 - * sec Seconds
1802 - * @param {Boolean}
1803 - * verbose If hours and milliseconds should padded be displayed.
1804 - * @return {Float} String npt format
1805 - */
1806 - mw.npt2seconds = function ( npt_str ) {
1807 - if ( !npt_str ) {
1808 - // mw.log('npt2seconds:not valid ntp:'+ntp);
1809 - return false;
1810 - }
1811 - // Strip {npt:}01:02:20 or 32{s} from time if present
1812 - npt_str = npt_str.replace( /npt:|s/g, '' );
1813 -
1814 - var hour = 0;
1815 - var min = 0;
1816 - var sec = 0;
1817 -
1818 - times = npt_str.split( ':' );
1819 - if ( times.length == 3 ) {
1820 - sec = times[2];
1821 - min = times[1];
1822 - hour = times[0];
1823 - } else if ( times.length == 2 ) {
1824 - sec = times[1];
1825 - min = times[0];
1826 - } else {
1827 - sec = times[0];
1828 - }
1829 - // Sometimes a comma is used instead of period for ms
1830 - sec = sec.replace( /,\s?/, '.' );
1831 - // Return seconds float
1832 - return parseInt( hour * 3600 ) + parseInt( min * 60 ) + parseFloat( sec );
1833 - };
1834 -
1835 - // Local mwEmbedSrc variable ( for cache of mw.getMwEmbedSrc )
1836 - var mwEmbedSrc = null;
1837 -
1838 - /**
1839 - * Gets the mwEmbed script src attribute
1840 - */
1841 - mw.getMwEmbedSrc = function() {
1842 - if ( mwEmbedSrc ) {
1843 - return mwEmbedSrc;
1844 - }
1845 -
1846 - // Get all the javascript includes:
1847 - var js_elements = document.getElementsByTagName( "script" );
1848 - for ( var i = 0; i < js_elements.length; i++ ) {
1849 - // Check for mwEmbed.js and/or script loader
1850 - var src = js_elements[i].getAttribute( "src" );
1851 - if ( src ) {
1852 - if ( // Check for mwEmbed.js ( debug mode )
1853 - ( src.indexOf( 'mwEmbed.js' ) !== -1 && src.indexOf( 'MediaWiki:Gadget') == -1 )
1854 - || // Check for resource loader
1855 - (
1856 - ( src.indexOf( 'mwResourceLoader.php' ) !== -1 || src.indexOf( 'ResourceLoader.php' ) !== -1 )
1857 - &&
1858 - src.indexOf( 'mwEmbed' ) !== -1
1859 - )
1860 - || // Check for static mwEmbed package
1861 - ( src.indexOf( 'mwEmbed' ) !== -1 && src.indexOf( 'static' ) !== -1 )
1862 - ) {
1863 - mwEmbedSrc = src;
1864 - return mwEmbedSrc;
1865 - }
1866 - }
1867 - }
1868 - mw.log( 'Error: getMwEmbedSrc failed to get script path' );
1869 - return false;
1870 - };
1871 -
1872 - // Local mwUrlParam variable ( for cache of mw.getUrlParam )
1873 - var mwUrlParam = null;
1874 -
1875 - /**
1876 - * Get URL Parameters per parameters in the host script include
1877 - */
1878 - mw.getUrlParam = function() {
1879 - if ( mwUrlParam ) {
1880 - return mwUrlParam;
1881 - }
1882 -
1883 - var mwEmbedSrc = mw.getMwEmbedSrc();
1884 - var req_param = '';
1885 -
1886 - // If we already have a URI, add it to the param request:
1887 - var urid = mw.parseUri( mwEmbedSrc ).queryKey['urid'];
1888 -
1889 - // If we're in debug mode, get a fresh unique request key and pass on
1890 - // "debug" param
1891 - if ( mw.parseUri( mwEmbedSrc ).queryKey['debug'] == 'true' ) {
1892 - mw.setConfig( 'debug', true );
1893 - var d = new Date();
1894 - req_param += 'urid=' + d.getTime() + '&debug=true';
1895 -
1896 - } else if ( urid ) {
1897 - // Just pass on the existing urid:
1898 - req_param += 'urid=' + urid;
1899 - } else {
1900 - // Otherwise, Use the mwEmbed version
1901 - req_param += 'urid=' + mw.version;
1902 - }
1903 -
1904 - // Add the language param if present:
1905 - var langKey = mw.parseUri( mwEmbedSrc ).queryKey['uselang'];
1906 - if ( langKey )
1907 - req_param += '&uselang=' + langKey;
1908 -
1909 - // Update the local cache and return the value
1910 - mwUrlParam = req_param;
1911 - return mwUrlParam;
1912 - };
1913 -
1914 - /**
1915 - * Replace url parameters via newParams key value pairs
1916 - *
1917 - * @param {String}
1918 - * url Source url to be updated
1919 - * @param {Object}
1920 - * newParams key, value paris to swap in
1921 - * @return {String} the updated url
1922 - */
1923 - mw.replaceUrlParams = function( url, newParams ) {
1924 - var parsedUrl = mw.parseUri( url );
1925 -
1926 - if ( parsedUrl.protocol != '' ) {
1927 - var new_url = parsedUrl.protocol + '://' + parsedUrl.authority + parsedUrl.path + '?';
1928 - } else {
1929 - var new_url = parsedUrl.path + '?';
1930 - }
1931 -
1932 - // Merge new params:
1933 - for( var key in newParams ) {
1934 - parsedUrl.queryKey[ key ] = newParams[ key ];
1935 - }
1936 -
1937 - // Output to new_url
1938 - var amp = '';
1939 - for ( var key in parsedUrl.queryKey ) {
1940 - var val = parsedUrl.queryKey[ key ];
1941 - new_url += amp + key + '=' + val;
1942 - amp = '&';
1943 - }
1944 - return new_url;
1945 - };
1946 -
1947 - /**
1948 - * parseUri 1.2.2 (c) Steven Levithan <stevenlevithan.com> MIT License
1949 - */
1950 - mw.parseUri = function (str) {
1951 - var o = mw.parseUri.options,
1952 - m = o.parser[o.strictMode ? "strict" : "loose"].exec(str),
1953 - uri = {},
1954 - i = 14;
1955 -
1956 - while (i--) uri[o.key[i]] = m[i] || "";
1957 -
1958 - uri[o.q.name] = {};
1959 - uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) {
1960 - if ($1) uri[o.q.name][$1] = $2;
1961 - });
1962 -
1963 - return uri;
1964 - };
1965 -
1966 - /**
1967 - * Parse URI function
1968 - *
1969 - * For documentation on its usage see:
1970 - * http://stevenlevithan.com/demo/parseuri/js/
1971 - */
1972 - mw.parseUri.options = {
1973 - strictMode: false,
1974 - key: ["source", "protocol", "authority", "userInfo", "user", "password", "host",
1975 - "port", "relative", "path", "directory", "file", "query", "anchor"],
1976 - q: {
1977 - name: "queryKey",
1978 - parser: /(?:^|&)([^&=]*)=?([^&]*)/g
1979 - },
1980 - parser: {
1981 - strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
1982 - loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
1983 - }
1984 - };
1985 -
1986 - /**
1987 - * getAbsoluteUrl takes a src and returns the absolute location given the
1988 - * document.URL or a contextUrl param
1989 - *
1990 - * @param {String}
1991 - * src path or url
1992 - * @param {String}
1993 - * contextUrl The domain / context for creating an absolute url
1994 - * from a relative path
1995 - * @return {String} absolute url
1996 - */
1997 -mw.absoluteUrl = function( src, contextUrl ) {
1998 -
1999 - var parsedSrc = mw.parseUri( src );
2000 -
2001 - // Source is already absolute return:
2002 - if( parsedSrc.protocol != '') {
2003 - return src;
2004 - }
2005 -
2006 - // Get parent Url location the context URL
2007 - if( !contextUrl ) {
2008 - contextUrl = document.URL;
2009 - }
2010 - var parsedUrl = mw.parseUri( contextUrl );
2011 -
2012 - // Check for IE local file that does not flip the slashes
2013 - if( parsedUrl.directory == '' && parsedUrl.protocol == 'file' ){
2014 - // pop off the file
2015 - var fileUrl = contextUrl.split( '\\');
2016 - fileUrl.pop();
2017 - return fileUrl.join('\\') + '\\' + src;
2018 - }
2019 -
2020 - // Check for leading slash:
2021 - if( src.indexOf( '/' ) === 0 ) {
2022 - return parsedUrl.protocol + '://' + parsedUrl.authority + src;
2023 - }else{
2024 - return parsedUrl.protocol + '://' + parsedUrl.authority + parsedUrl.directory + src;
2025 - }
2026 - };
2027 - /**
2028 - * Check if a given source string is likely a url
2029 - *
2030 - * @return {boolean} true if a url false if a string
2031 - */
2032 - mw.isUrl = function( src ){
2033 - var parsedSrc = mw.parseUri( src );
2034 - // if the url is just a string source and host will match
2035 - return ( parsedSrc.host != parsedSrc.source );
2036 - };
2037 -
2038 - /**
2039 - * Escape quotes in a text string
2040 - *
2041 - * @param {String}
2042 - * text String to be escaped
2043 - * @return {string} escaped text string
2044 - */
2045 - mw.escapeQuotes = function( text ) {
2046 - var re = new RegExp("'","g");
2047 - text = text.replace(re,"\\'");
2048 - re = new RegExp("\\n","g");
2049 - text = text.replace(re,"\\n");
2050 - return mw.escapeQuotesHTML(text);
2051 - };
2052 -
2053 - /**
2054 - * Escape an HTML text string
2055 - *
2056 - * @param {String}
2057 - * text String to be escaped
2058 - * @return {string} escaped text html string
2059 - */
2060 - mw.escapeQuotesHTML = function( text ) {
2061 - var replaceMap = {
2062 - "&" : "&amp;",
2063 - '"' : "&quot;",
2064 - '<' : "&lt;",
2065 - '>' : "&gt;"
2066 - };
2067 - for( var i in replaceMap ){
2068 - text = text.split(i).join( replaceMap[i]);
2069 - }
2070 - return text;
2071 - };
2072 -
2073 -
2074 - // Array of setup functions
2075 - var mwSetupFunctions = [];
2076 -
2077 - /**
2078 - * Add a function to be run during setup ( prior to mw.ready) this is useful
2079 - * for building out interfaces that should be ready before mw.ready is
2080 - * called.
2081 - *
2082 - * @param {callback}
2083 - * Function Callback function must accept a ready function
2084 - * callback to be called once setup is done
2085 - */
2086 - mw.addSetupHook = function( callback ) {
2087 - mwSetupFunctions.push ( callback ) ;
2088 - };
2089 -
2090 - /**
2091 - * One time "setup" for mwEmbed run onDomReady ( so calls to setConfg apply
2092 - * to setup )
2093 - */
2094 - // Flag to ensure setup is only run once:
2095 - var mwSetupFlag = false;
2096 - mw.setupMwEmbed = function ( ) {
2097 - // Only run the setup once:
2098 - if( mwSetupFlag ) {
2099 - return ;
2100 - }
2101 - mwSetupFlag = true;
2102 -
2103 - mw.log( 'mw:setupMwEmbed SRC:: ' + mw.getMwEmbedSrc() );
2104 -
2105 - // Check core mwEmbed loader.js file ( to get configuration and paths )
2106 - mw.checkCoreLoaderFile( function(){
2107 - // Make sure we have jQuery
2108 - mw.load( 'window.jQuery', function() {
2109 -
2110 - // Add jQuery to $j var.
2111 - if ( ! window[ '$j' ] ) {
2112 - window[ '$j' ] = jQuery.noConflict();
2113 - }
2114 -
2115 - // Set up mvEmbed utility jQuery bindings
2116 - mw.dojQueryBindings();
2117 -
2118 - // Setup user config:
2119 - mw.setupUserConfig( function(){
2120 - // Get module loader.js, and language files
2121 - // ( will hit callback directly if set via resource loader )
2122 - mw.checkModuleLoaderFiles( function() {
2123 -
2124 - // Set the User language
2125 - if( typeof wgUserLanguage != 'undefined' && mw.isValidLang( wgUserLanguage) ) {
2126 - mw.setConfig( 'userLanguage', wgUserLanguage );
2127 - }else{
2128 - // Grab it from the included url
2129 - var langKey = mw.parseUri( mw.getMwEmbedSrc() ).queryKey['uselang'];
2130 - if ( langKey && mw.isValidLang( langKey ) ) {
2131 - mw.setConfig( 'userLanguage', langKey);
2132 - }
2133 - }
2134 -
2135 - // Update the image path
2136 - mw.setConfig( 'imagesPath', mw.getMwEmbedPath() + 'skins/common/images/' );
2137 -
2138 - // Set up AJAX to not send dynamic URLs for loading
2139 - // scripts
2140 - $j.ajaxSetup( {
2141 - cache: true
2142 - } );
2143 -
2144 - // Update the magic keywords
2145 - mw.Language.magicSetup();
2146 -
2147 -
2148 - // Special Hack for conditional jquery ui inclusion (
2149 - // once
2150 - // Usability extension
2151 - // registers the jquery.ui skin in mw.style
2152 - if( mw.hasJQueryUiCss() ){
2153 - mw.style[ 'ui_' + mw.getConfig( 'jQueryUISkin' ) ] = true;
2154 - }
2155 -
2156 -
2157 - // Make sure style sheets are loaded:
2158 - mw.load( ['mw.style.mwCommon'] , function(){
2159 - // Run all the setup function hooks
2160 - // NOTE: setup functions are added via addSetupHook
2161 - // calls
2162 - // and must include a callback.
2163 - //
2164 - // Once complete we can run .ready() queued
2165 - // functions
2166 - function runSetupFunctions() {
2167 - if( mwSetupFunctions.length ) {
2168 - mwSetupFunctions.shift()( function() {
2169 - runSetupFunctions();
2170 - } );
2171 - }else{
2172 - mw.runReadyFunctions();
2173 - }
2174 - }
2175 - runSetupFunctions();
2176 - } );
2177 -
2178 - } );
2179 - });
2180 - });
2181 - });
2182 - };
2183 -
2184 - /**
2185 - * Checks for jquery ui css by name jquery-ui-1.7.2.css NOTE: this is a hack
2186 - * for usability jquery-ui in the future usability should register a
2187 - * resource in mw.skin
2188 - *
2189 - * @return true if found, return false if not found
2190 - */
2191 - mw.hasJQueryUiCss = function(){
2192 - var hasUiCss = false;
2193 - var cssStyleSheetNames = ['jquery-ui-1.7.2.css', 'jquery-ui.css'];
2194 - // Load the jQuery ui skin if usability skin not set
2195 - $j( 'link' ).each( function( na, linkNode ){
2196 - $j.each( cssStyleSheetNames, function(inx, sheetName ){
2197 - if( $j( linkNode ).attr( 'href' ).indexOf( sheetName ) != -1 ){
2198 - hasUiCss = true;
2199 - return true;
2200 - }
2201 - });
2202 - } );
2203 - // Check all the "style" nodes for @import for sheet name
2204 - // xxx Note: we could do this a bit cleaner with regEx
2205 - $j( 'style' ).each( function( na, styleNode ){
2206 - $j.each( cssStyleSheetNames, function(inx, sheetName ){
2207 - if( $j( styleNode ).text().indexOf( '@import' ) != -1
2208 - &&
2209 - $j( styleNode ).text().indexOf( sheetName ) != -1 )
2210 - {
2211 - hasUiCss=true;
2212 - return true;
2213 - }
2214 - });
2215 - });
2216 - return hasUiCss;
2217 - };
2218 -
2219 - /**
2220 - * Loads the core mwEmbed "loader.js" file config
2221 - *
2222 - * NOTE: if using the ScriptLoader all the loaders and localization
2223 - * converters are included automatically
2224 - *
2225 - * @param {Function}
2226 - * callback Function called once core loader file is loaded
2227 - */
2228 - mw.checkCoreLoaderFile = function( callback ) {
2229 - // Check if we are using scriptloader ( handles loader include
2230 - // automatically )
2231 - if( mw.getResourceLoaderPath() ) {
2232 - callback();
2233 - return ;
2234 - }
2235 -
2236 - // Check if we are using a static package ( mwEmbed path includes
2237 - // -static )
2238 - if( mw.isStaticPackge() ){
2239 - callback();
2240 - return ;
2241 - }
2242 -
2243 - // Add the Core loader to the request
2244 - // The follow code is ONLY RUN in debug / raw file mode
2245 - mw.load( 'loader.js', callback );
2246 - };
2247 -
2248 - /**
2249 - * Checks if the javascript is a static package ( not using resource loader )
2250 - *
2251 - * @return {boolean} true the included script is static false the included
2252 - * script
2253 - */
2254 - mw.isStaticPackge = function(){
2255 - var src = mw.getMwEmbedSrc();
2256 - if( src.indexOf('-static') !== -1 ){
2257 - return true;
2258 - }
2259 - return false;
2260 - };
2261 -
2262 - /**
2263 - * Check for resource loader module loaders, and localization files
2264 - *
2265 - * NOTE: if using the ScriptLoader all the loaders and localization
2266 - * converters are included automatically.
2267 - */
2268 - mw.checkModuleLoaderFiles = function( callback ) {
2269 - mw.log( 'doLoaderCheck::' );
2270 -
2271 - // Check if we are using scriptloader ( handles loader include
2272 - // automatically )
2273 - // Or if mwEmbed is a static package ( all resources are already loaded
2274 - // )
2275 - if( mw.getResourceLoaderPath() || mw.isStaticPackge() ) {
2276 - callback();
2277 - return ;
2278 - }
2279 -
2280 - // Load the configured modules / components
2281 - // The follow code is ONLY RUN in debug / raw file mode
2282 - var loaderRequest = [];
2283 -
2284 - // Load enabled components
2285 - var enabledComponents = mw.getConfig( 'coreComponents' );
2286 - function loadEnabledComponents( enabledComponents ){
2287 - if( ! enabledComponents.length ){
2288 - // If no more components load modules::
2289 -
2290 - // Add the enabledModules loaders:
2291 - var enabledModules = mw.getConfig( 'enabledModules' );
2292 - loadEnabledModules( enabledModules );
2293 - return ;
2294 - }
2295 - var componentName = enabledComponents.shift();
2296 - componentName = componentName.replace(/"/g,'');
2297 - mw.load( componentName, function(){
2298 - loadEnabledComponents( enabledComponents );
2299 - } );
2300 - }
2301 - loadEnabledComponents( enabledComponents );
2302 -
2303 -
2304 - // Set the loader context and get each loader individually
2305 - function loadEnabledModules( enabledModules ){
2306 - if( ! enabledModules.length ){
2307 - // If no more modules left load the LanguageFile
2308 - addLanguageFile();
2309 - return ;
2310 - }
2311 - var moduleName = enabledModules.shift();
2312 - moduleName = moduleName.replace(/"/g,'');
2313 - mw.setConfig( 'loaderContext', 'modules/' + moduleName + '/' );
2314 - mw.load( 'modules/' + moduleName + '/loader.js', function(){
2315 - loadEnabledModules( enabledModules );
2316 - } );
2317 - }
2318 -
2319 - function addLanguageFile(){
2320 - // Add the language file
2321 - var langLoaderRequest = [];
2322 -
2323 - if( mw.getConfig( 'userLanguage' ) ) {
2324 - var langCode = mw.getConfig( 'userLanguage' );
2325 -
2326 - // Load the language resource if not default 'en'
2327 - var transformKey = mw.getLangTransformKey( langCode );
2328 - if( transformKey != 'en' ){
2329 - // Upper case the first letter:
2330 - langCode = langCode.substr(0,1).toUpperCase() + langCode.substr( 1, langCode.length );
2331 - langLoaderRequest.push( 'languages/classes/Language' +
2332 - langCode + '.js' );
2333 - }
2334 -
2335 - }
2336 - if ( ! langLoaderRequest.length ) {
2337 - addLocalSettings();
2338 - return ;
2339 - }
2340 -
2341 - // Load the language if set
2342 - mw.load( langLoaderRequest, function(){
2343 - mw.log( 'Done moduleLoaderCheck request' );
2344 - addLocalSettings();
2345 - } );
2346 - }
2347 - function addLocalSettings(){
2348 - var continueCallback = function(){
2349 - // Set the mwModuleLoaderCheckFlag flag to true
2350 - mwModuleLoaderCheckFlag = true;
2351 - callback();
2352 - };
2353 - if( mw.getConfig( 'LoadLocalSettings') != true ){
2354 - continueCallback();
2355 - return;
2356 - }
2357 - mw.log("Load loacal settings");
2358 - mw.load( 'localSettings.js', function(){
2359 - continueCallback();
2360 - });
2361 - }
2362 -
2363 - };
2364 -
2365 - /**
2366 - * Checks if a css style rule exists
2367 - *
2368 - * On a page with lots of rules it can take some time so avoid calling this
2369 - * function where possible and cache its result
2370 - *
2371 - * NOTE: this only works for style sheets on the same domain :(
2372 - *
2373 - * @param {String}
2374 - * styleRule Style rule name to check
2375 - * @return {Boolean} true if the rule exists false if the rule does not
2376 - * exist
2377 - */
2378 - mw.styleRuleExists = function ( styleRule ) {
2379 - // Set up the skin paths configuration
2380 - for( var i=0 ; i < document.styleSheets.length ; i++ ) {
2381 - var rules = null;
2382 - try{
2383 - if ( document.styleSheets[i].cssRules )
2384 - rules = document.styleSheets[i].cssRules;
2385 - else if (document.styleSheets[0].rules)
2386 - rules = document.styleSheets[i].rules;
2387 - for(var j=0 ; j < rules.length ; j++ ) {
2388 - var rule = rules[j].selectorText;
2389 - if( rule && rule.indexOf( styleRule ) != -1 ) {
2390 - return true;
2391 - }
2392 - }
2393 - }catch ( e ) {
2394 - mw.log( 'Error: cant check rule on cross domain style sheet:' + document.styleSheets[i].href );
2395 - }
2396 - }
2397 - return false;
2398 - };
2399 -
2400 - // Flag to register the domReady has been called
2401 - var mwDomReadyFlag = false;
2402 -
2403 - // Flag to register if the domreadyHooks have been called
2404 - var mwModuleLoaderCheckFlag = false;
2405 -
2406 - /**
2407 - * This will get called when the DOM is ready Will check configuration and
2408 - * issue a mw.setupMwEmbed call if needed
2409 - */
2410 - mw.domReady = function ( ) {
2411 - if( mwDomReadyFlag ) {
2412 - return ;
2413 - }
2414 - mw.log( 'run:domReady:: ' + document.getElementsByTagName('video').length );
2415 - // Set the onDomReady Flag
2416 - mwDomReadyFlag = true;
2417 -
2418 - // Give us a chance to get to the bottom of the script.
2419 - // When loading mwEmbed asynchronously the dom ready gets called
2420 - // directly and in some browsers beets the $j = jQuery.noConflict();
2421 - // call
2422 - // and causes symbol undefined errors.
2423 - setTimeout(function(){
2424 - mw.setupMwEmbed();
2425 - },1);
2426 - };
2427 -
2428 - /**
2429 - * A version comparison utility function Handles version of types
2430 - * {Major}.{MinorN}.{Patch}
2431 - *
2432 - * Note this just handles version numbers not patch letters.
2433 - *
2434 - * @param {String}
2435 - * minVersion Minnium version needed
2436 - * @param {String}
2437 - * clientVersion Client version to be checked
2438 - *
2439 - * @return true if the version is at least of minVersion false if the
2440 - * version is less than minVersion
2441 - */
2442 - mw.versionIsAtLeast = function( minVersion, clientVersion ) {
2443 - var minVersionParts = minVersion.split('.');
2444 - var clientVersionParts = clientVersion.split('.');
2445 - for( var i =0; i < minVersionParts.length; i++ ) {
2446 - if( parseInt( clientVersionParts[i] ) > parseInt( minVersionParts[i] ) ) {
2447 - return true;
2448 - }
2449 - if( parseInt( clientVersionParts[i] ) < parseInt( minVersionParts[i] ) ) {
2450 - return false;
2451 - }
2452 - }
2453 - // Same version:
2454 - return true;
2455 - };
2456 -
2457 - /**
2458 - * Utility jQuery bindings Setup after jQuery is available ).
2459 - */
2460 - mw.dojQueryBindings = function() {
2461 - mw.log( 'mw.dojQueryBindings' );
2462 - ( function( $ ) {
2463 -
2464 - /**
2465 - * Runs all the triggers on all the named bindings of an object with
2466 - * a single callback
2467 - *
2468 - * NOTE THIS REQUIRES JQUERY 1.4.2 and above
2469 - *
2470 - * Normal jQuery tirgger calls will run the callback directly
2471 - * multiple times for every binded function.
2472 - *
2473 - * With triggerQueueCallback() callback is not called until all the
2474 - * binded events have been run.
2475 - *
2476 - * @param {string}
2477 - * triggerName Name of trigger to be run
2478 - * @param {object=}
2479 - * arguments Optional arguments object to be passed to
2480 - * the callback
2481 - * @param {function}
2482 - * callback Function called once all triggers have been
2483 - * run
2484 - *
2485 - */
2486 - $.fn.triggerQueueCallback = function( triggerName, triggerParam, callback ){
2487 - var targetObject = this;
2488 - // Support optional triggerParam data
2489 - if( !callback && typeof triggerParam == 'function' ){
2490 - callback = triggerParam;
2491 - triggerParam = null;
2492 - }
2493 - // Support namespaced event segmentation ( jQuery
2494 - var triggerBaseName = triggerName.split(".")[0];
2495 - var triggerNamespace = triggerName.split(".")[1];
2496 - // Get the callback set
2497 - var callbackSet = [];
2498 - if( ! triggerNamespace ){
2499 - callbackSet = $j( targetObject ).data( 'events' )[ triggerBaseName ];
2500 - } else{
2501 - $j.each( $j( targetObject ).data( 'events' )[ triggerBaseName ], function( inx, bindObject ){
2502 - if( bindObject.namespace == triggerNamespace ){
2503 - callbackSet.push( bindObject );
2504 - }
2505 - });
2506 - }
2507 -
2508 - if( !callbackSet || callbackSet.length === 0 ){
2509 - mw.log( '"mwEmbed::jQuery.triggerQueueCallback: No events run the callback directly: ' + triggerName );
2510 - // No events run the callback directly
2511 - callback();
2512 - return ;
2513 - }
2514 -
2515 - // Set the callbackCount
2516 - var callbackCount = ( callbackSet.length )? callbackSet.length : 1;
2517 - // mw.log("mwEmbed::jQuery.triggerQueueCallback: " + triggerName
2518 - // + ' number of queued functions:' + callbackCount );
2519 - var callInx = 0;
2520 - var doCallbackCheck = function() {
2521 - // mw.log( 'callback for: ' + mw.getCallStack()[0] +
2522 - // callInx);
2523 - callInx++;
2524 - if( callInx == callbackCount ){
2525 - callback();
2526 - }
2527 - };
2528 - if( triggerParam ){
2529 - $( this ).trigger( triggerName, [ triggerParam, doCallbackCheck ]);
2530 - } else {
2531 - $( this ).trigger( triggerName, [ doCallbackCheck ] );
2532 - }
2533 - };
2534 -
2535 - /**
2536 - * Set a given selector html to the loading spinner:
2537 - */
2538 - $.fn.loadingSpinner = function( ) {
2539 - if ( this ) {
2540 - $( this ).html(
2541 - $( '<div />' )
2542 - .addClass( "loadingSpinner" )
2543 - );
2544 - }
2545 - return this;
2546 - };
2547 -
2548 - /**
2549 - * Add an absolute overlay spinner useful for cases where the
2550 - * element does not display child elements, ( images, video )
2551 - */
2552 - $.fn.getAbsoluteOverlaySpinner = function(){
2553 - var pos = $j( this ).offset();
2554 - var posLeft = ( $j( this ).width() ) ?
2555 - parseInt( pos.left + ( .5 * $j( this ).width() ) -16 ) :
2556 - pos.left + 30;
2557 -
2558 - var posTop = ( $j( this ).height() ) ?
2559 - parseInt( pos.top + ( .5 * $j( this ).height() ) -16 ) :
2560 - pos.top + 30;
2561 -
2562 - var $spinner = $j('<div />')
2563 - .loadingSpinner()
2564 - .css({
2565 - 'width' : 32,
2566 - 'height' : 32,
2567 - 'position': 'absolute',
2568 - 'top' : posTop + 'px',
2569 - 'left' : posLeft + 'px'
2570 - });
2571 - $j('body').append( $spinner );
2572 - return $spinner;
2573 - };
2574 -
2575 - /**
2576 - * dragDrop file loader
2577 - */
2578 - $.fn.dragFileUpload = function ( conf ) {
2579 - if ( this.selector ) {
2580 - var _this = this;
2581 - // load the dragger and "setup"
2582 - mw.load( ['$j.fn.dragDropFile'], function() {
2583 - $j( _this.selector ).dragDropFile();
2584 - } );
2585 - }
2586 - };
2587 -
2588 - /**
2589 - * Shortcut to a themed button Should be depreciated for $.button
2590 - * bellow
2591 - */
2592 - $.btnHtml = function( msg, styleClass, iconId, opt ) {
2593 - if ( !opt )
2594 - opt = { };
2595 - var href = ( opt.href ) ? opt.href : '#';
2596 - var target_attr = ( opt.target ) ? ' target="' + opt.target + '" ' : '';
2597 - var style_attr = ( opt.style ) ? ' style="' + opt.style + '" ' : '';
2598 - return '<a href="' + href + '" ' + target_attr + style_attr +
2599 - ' class="ui-state-default ui-corner-all ui-icon_link ' +
2600 - styleClass + '"><span class="ui-icon ui-icon-' + iconId + '" ></span>' +
2601 - '<span class="btnText">' + msg + '</span></a>';
2602 - };
2603 -
2604 - // Shortcut to jQuery button ( should replace all btnHtml with
2605 - // button )
2606 - var mw_default_button_options = {
2607 - // The class name for the button link
2608 - 'class' : '',
2609 -
2610 - // The style properties for the button link
2611 - 'style' : { },
2612 -
2613 - // The text of the button link
2614 - 'text' : '',
2615 -
2616 - // The icon id that precedes the button link:
2617 - 'icon' : 'carat-1-n'
2618 - };
2619 -
2620 - $.button = function( options ) {
2621 - var options = $j.extend( {}, mw_default_button_options, options);
2622 -
2623 - // Button:
2624 - var $button = $j('<a />')
2625 - .attr('href', '#')
2626 - .addClass( 'ui-state-default ui-corner-all ui-icon_link' );
2627 - // Add css if set:
2628 - if( options.css ) {
2629 - $button.css( options.css );
2630 - }
2631 -
2632 - if( options['class'] ) {
2633 - $button.addClass( options['class'] );
2634 - }
2635 -
2636 - // return the button:
2637 - $button.append(
2638 - $j('<span />').addClass( 'ui-icon ui-icon-' + options.icon ),
2639 - $j('<span />').addClass( 'btnText' )
2640 - )
2641 - .buttonHover(); // add buttonHover binding;
2642 -
2643 - if( options.text ){
2644 - $button.find('.btnText').text( options.text );
2645 - } else {
2646 - $button.css('padding', '1em');
2647 - }
2648 - return $button;
2649 - };
2650 -
2651 - // Shortcut to bind hover state
2652 - $.fn.buttonHover = function() {
2653 - $j( this ).hover(
2654 - function() {
2655 - $j( this ).addClass( 'ui-state-hover' );
2656 - },
2657 - function() {
2658 - $j( this ).removeClass( 'ui-state-hover' );
2659 - }
2660 - );
2661 - return this;
2662 - };
2663 -
2664 - /**
2665 - * Resize a dialog to fit the window
2666 - *
2667 - * @param {Object}
2668 - * options horizontal and vertical space ( default 50 )
2669 - */
2670 - $.fn.dialogFitWindow = function( options ) {
2671 - var opt_default = { 'hspace':50, 'vspace':50 };
2672 - if ( !options )
2673 - var options = { };
2674 - options = $j.extend( opt_default, options );
2675 - $j( this.selector ).dialog( 'option', 'width', $j( window ).width() - options.hspace );
2676 - $j( this.selector ).dialog( 'option', 'height', $j( window ).height() - options.vspace );
2677 - $j( this.selector ).dialog( 'option', 'position', 'center' );
2678 - // update the child position: (some of this should be pushed
2679 - // up-stream via dialog config options
2680 - $j( this.selector + '~ .ui-dialog-buttonpane' ).css( {
2681 - 'position':'absolute',
2682 - 'left':'0px',
2683 - 'right':'0px',
2684 - 'bottom':'0px'
2685 - } );
2686 - };
2687 -
2688 - } )( jQuery );
2689 - };
2690 -
2691 -} )( window.mw );
2692 -
2693 -
2694 -/**
2695 - * Set DOM-ready call We copy jQuery( document ).ready here since sometimes
2696 - * mwEmbed.js is included without jQuery and we need our own "ready" system so
2697 - * that mwEmbed interfaces can support async built out and the include of
2698 - * jQuery.
2699 - */
2700 -// Check if already ready:
2701 -if ( document.readyState === "complete" ) {
2702 - mw.domReady();
2703 -}
2704 -
2705 -// Cleanup functions for the document ready method
2706 -if ( document.addEventListener ) {
2707 - DOMContentLoaded = function() {
2708 - document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
2709 - mw.domReady();
2710 - };
2711 -
2712 -} else if ( document.attachEvent ) {
2713 - DOMContentLoaded = function() {
2714 - // Make sure body exists, at least, in case IE gets a little overzealous
2715 - // (ticket #5443).
2716 - if ( document.readyState === "complete" ) {
2717 - document.detachEvent( "onreadystatechange", DOMContentLoaded );
2718 - mw.domReady();
2719 - }
2720 - };
2721 -}
2722 -// Mozilla, Opera and webkit nightlies currently support this event
2723 -if ( document.addEventListener ) {
2724 - // Use the handy event callback
2725 - document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
2726 -
2727 - // A fallback to window.onload, that will always work
2728 - window.addEventListener( "load", mw.domReady, false );
2729 -
2730 -// If IE event model is used
2731 -} else if ( document.attachEvent ) {
2732 - // ensure firing before onload,
2733 - // maybe late but safe also for iframes
2734 - document.attachEvent("onreadystatechange", DOMContentLoaded);
2735 -
2736 - // A fallback to window.onload, that will always work
2737 - window.attachEvent( "onload", mw.domReady );
2738 -
2739 - // If IE and not a frame
2740 - // continually check to see if the document is ready
2741 - var toplevel = false;
2742 -
2743 - try {
2744 - toplevel = window.frameElement == null;
2745 - } catch(e) {}
2746 -
2747 - if ( document.documentElement.doScroll && toplevel ) {
2748 - doScrollCheck();
2749 - }
2750 -}
2751 -// The DOM ready check for Internet Explorer
2752 -function doScrollCheck() {
2753 - try {
2754 - // If IE is used, use the trick by Diego Perini
2755 - // http://javascript.nwbox.com/IEContentLoaded/
2756 - document.documentElement.doScroll("left");
2757 - } catch( error ) {
2758 - setTimeout( doScrollCheck, 1 );
2759 - return;
2760 - }
2761 - mw.domReady();
2762 -}
2763 -
2764 -// If using the resource loader and jQuery has not been set give a warning to
2765 -// the user:
2766 -// (this is needed because packaged loader.js files could refrence jQuery )
2767 -if( mw.getResourceLoaderPath() && !window.jQuery ) {
2768 - mw.log( 'Error: jQuery is required for mwEmbed, please update your resource loader request' );
2769 -}
2770 -
2771 -if( mw.isStaticPackge() && !window.jQuery ){
2772 - alert( 'Error: jQuery is required for mwEmbed ');
2773 -}
2774 -
2775 -/**
2776 - * Hack to keep jQuery in $ when its already there, but also use noConflict to
2777 - * get $j = jQuery
2778 - *
2779 - * This way sites that use $ for jQuery continue to work after including mwEmbed
2780 - * javascript.
2781 - *
2782 - * Also if jQuery is included prior to mwEmbed we ensure $j is set
2783 - */
2784 -
2785 -if( window.jQuery ){
2786 - if( ! mw.versionIsAtLeast( '1.4.2', jQuery.fn.jquery ) ){
2787 - if( window.console && window.console.log ) {
2788 - console.log( 'Error mwEmbed requires jQuery 1.4 or above' );
2789 - }
2790 - }
2791 - var dollarFlag = false;
2792 - if( $ && $.fn && $.fn.jquery ) {
2793 - // NOTE we could check the version of
2794 - // jQuery and do a removal call if too old
2795 - dollarFlag = true;
2796 - }
2797 - window[ '$j' ] = jQuery.noConflict();
2798 - if( dollarFlag ) {
2799 - window[ '$' ] = jQuery.noConflict();
2800 - }
2801 -}
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/PlayerThemer/loader.js
@@ -9,7 +9,7 @@
1010 });
1111
1212 // Add the mw.PlayerThemer to the embedPlayer loader request if we have special playerThemer class
13 - $j( mw ).bind( 'LoaderEmbedPlayerUpdateRequest', function( event, playerElement, classRequest ) {
 13+ $j( mw ).bind( 'EmbedPlayerUpdateDependencies', function( event, playerElement, classRequest ) {
1414 if( $j( playerElement ).hasClass('PlayerThemer') ){
1515 // Set the player useNativeControls attribute
1616 $j( playerElement ).attr('usenativecontrols', true);
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/SmilPlayer/loader.js
@@ -29,7 +29,7 @@
3030 } );
3131
3232 // Add the mw.SmilPlayer to the embedPlayer loader:
33 - $j( mw ).bind( 'LoaderEmbedPlayerUpdateRequest', function( event, playerElement, resourceRequest ) {
 33+ $j( mw ).bind( 'EmbedPlayerUpdateDependencies', function( event, playerElement, resourceRequest ) {
3434 var smilPlayerLibrarySet = [
3535 "mw.SmilHooks",
3636 "mw.Smil",
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/SwarmTransport/loader.js
@@ -36,7 +36,7 @@
3737 });
3838
3939 // Add the mw.SwarmTransport to the embedPlayer loader:
40 - $j( mw ).bind( 'LoaderEmbedPlayerUpdateRequest', function( event, playerElement, classRequest ) {
 40+ $j( mw ).bind( 'EmbedPlayerUpdateDependencies', function( event, playerElement, classRequest ) {
4141 // If the swarm transport is enabled add mw.SwarmTransport to the request.
4242 if( mw.getConfig( 'SwarmTransport.Enable' ) ) {
4343
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/TimedText/loader.js
@@ -58,7 +58,7 @@
5959
6060 // Update the player loader request with timedText library if the embedPlayer
6161 // includes timedText tracks.
62 - $j( mw ).bind( 'LoaderEmbedPlayerUpdateRequest', function( event, playerElement, classRequest ) {
 62+ $j( mw ).bind( 'EmbedPlayerUpdateDependencies', function( event, playerElement, classRequest ) {
6363 if( mw.isTimedTextSupported( playerElement ) ) {
6464 classRequest = $j.merge( classRequest, mwTimedTextRequestSet );
6565 }
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/AddMedia/mw.RemoteSearchDriver.js
@@ -2302,7 +2302,7 @@
23032303 );
23042304 mw.log( 'append html: ' + embedHtml );
23052305 $j( '#clip_edit_disp' ).html( embedHtml );
2306 - var cat = $j.fn.embedPlayer;
 2306+
23072307 // Make sure we have the 'EmbedPlayer' module:
23082308 mw.load( 'EmbedPlayer', function() {
23092309 // Strange concurrency issue with callbacks
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/EmbedPlayer/loader.js
@@ -1,159 +0,0 @@
2 -/**
3 -* EmbedPlayer loader
4 -*/
5 -/**
6 -* Default player module configuration
7 -*/
8 -( function( mw, $ ) {
9 - /**
10 - * Check the current DOM for any tags in "EmbedPlayer.RewriteTags"
11 - */
12 - mw.documentHasPlayerTags = function() {
13 - var rewriteTags = mw.getConfig( 'EmbedPlayer.RewriteTags' );
14 - if( $( rewriteTags ).length != 0 ) {
15 - return true;
16 - }
17 - return false;
18 - };
19 -
20 - /**
21 - * Add a DOM ready check for player tags
22 - *
23 - * We use mw.addSetupHook instead of mw.ready so that
24 - * mwEmbed player is setup before any other mw.ready calls
25 - */
26 - $( mw ).bind( 'SetupInterface', function( event, callback ){
27 -
28 - mw.log( 'Loader::EmbedPlayer:rewritePagePlayerTags:' + mw.documentHasPlayerTags() );
29 -
30 - // Allow modules to do tag rewrites as well:
31 - var doModuleTagRewrites = function(){
32 - $(mw).triggerQueueCallback( 'LoadeRewritePlayerTags', callback );
33 - }
34 -
35 - if( mw.documentHasPlayerTags() ) {
36 - var rewriteElementCount = 0;
37 -
38 - // Set each player to loading ( as early on as possible )
39 - $( mw.getConfig( 'EmbedPlayer.RewriteTags' ) ).each( function( index, element ){
40 -
41 - // Assign an the element an ID ( if its missing one )
42 - if ( $( element ).attr( "id" ) == '' ) {
43 - $( element ).attr( "id", 'v' + ( rewriteElementCount++ ) );
44 - }
45 - // Add an absolute positioned loader
46 - $( element )
47 - .getAbsoluteOverlaySpinner()
48 - .attr('id', 'loadingSpinner_' + $( element ).attr('id') )
49 - .addClass( 'playerLoadingSpinner' );
50 -
51 - });
52 - // Load the embedPlayer module ( then run queued hooks )
53 - mw.load( 'EmbedPlayer', function ( ) {
54 - // Rewrite the EmbedPlayer.RewriteTags with the
55 - $( mw.getConfig( 'EmbedPlayer.RewriteTags' ) ).embedPlayer( doModuleTagRewrites );
56 - })
57 - } else {
58 - doModuleTagRewrites();
59 - }
60 - });
61 -
62 - /**
63 - * Add the module loader function:
64 - */
65 - mw.addModuleLoader( 'EmbedPlayer', function() {
66 - var _this = this;
67 - // Hide videonojs class
68 - $( '.videonojs' ).hide();
69 -
70 - // Set up the embed video player class request: (include the skin js as well)
71 - var dependencyRequest = [
72 - [
73 - 'mw.EmbedPlayer'
74 - ],
75 - [
76 - 'mw.PlayerControlBuilder',
77 - '$.fn.hoverIntent',
78 - 'mw.style.EmbedPlayer',
79 - '$.cookie',
80 - // Add JSON lib if browsers does not define "JSON" natively
81 - 'JSON',
82 - '$.ui',
83 - '$.widget'
84 - ],
85 - [
86 - '$.ui.mouse',
87 - '$.fn.menu',
88 - 'mw.style.jquerymenu',
89 - '$.ui.slider'
90 - ]
91 - ];
92 -
93 - // Pass every tag being rewritten through the update request function
94 - $( mw.getConfig( 'EmbedPlayer.RewriteTags' ) ).each( function(inx, playerElement) {
95 - mw.embedPlayerUpdateLibraryRequest( playerElement, dependencyRequest[ 1 ] )
96 - } );
97 -
98 - // Add PNG fix code needed:
99 - if ( $.browser.msie && $.browser.version < 7 ) {
100 - dependencyRequest[0].push( '$.fn.pngFix' );
101 - }
102 -
103 - // Do short detection, to avoid extra player library request in ~most~ cases.
104 - //( If browser is firefox include native, if browser is IE include java )
105 - if( $.browser.msie ) {
106 - dependencyRequest[0].push( 'mw.EmbedPlayerJava' );
107 - }
108 -
109 - // Safari gets slower load since we have to detect ogg support
110 - if( !!document.createElement('video').canPlayType && !$.browser.safari ) {
111 - dependencyRequest[0].push( 'mw.EmbedPlayerNative' )
112 - }
113 - // Check if the iFrame player api is enabled and we have a parent iframe url:
114 - if ( mw.getConfig('EmbedPlayer.EnableIframeApi')
115 - &&
116 - mw.getConfig( 'EmbedPlayer.IframeParentUrl' )
117 - ){
118 - dependencyRequest[0].push('mw.EmbedPlayerNative');
119 - dependencyRequest[0].push('$.postMessage');
120 - dependencyRequest[0].push('mw.IFramePlayerApiServer');
121 - }
122 -
123 - // Return the set of libs to be loaded
124 - return dependencyRequest;
125 - } );
126 -
127 - /**
128 - * Takes a embed player element and updates a request object with any
129 - * dependent libraries per that tags attributes.
130 - *
131 - * For example a player skin class name could result in adding some
132 - * css and javascirpt to the player library request.
133 - *
134 - * @param {Object} playerElement The tag to check for library dependent request classes.
135 - * @param {Array} dependencyRequest The library request array
136 - */
137 - mw.embedPlayerUpdateLibraryRequest = function(playerElement, dependencyRequest ){
138 - var skinName = $( playerElement ).attr( 'class' );
139 - // Set playerClassName to default if unset or not a valid skin
140 - if( ! skinName || $.inArray( skinName.toLowerCase(), mw.validSkins ) == -1 ){
141 - skinName = mw.getConfig( 'EmbedPlayer.SkinName' );
142 - }
143 - skinName = skinName.toLowerCase();
144 - // Add the skin to the request
145 - var skinCaseName = skinName.charAt(0).toUpperCase() + skinName.substr(1);
146 - // The skin js:
147 - if( $.inArray( 'mw.PlayerSkin' + skinCaseName, dependencyRequest ) == -1 ){
148 - dependencyRequest.push( 'mw.PlayerSkin' + skinCaseName );
149 - }
150 - // The skin css
151 - if( $.inArray( 'mw.style.PlayerSkin' + skinCaseName, dependencyRequest ) == -1 ){
152 - dependencyRequest.push( 'mw.style.PlayerSkin' + skinCaseName );
153 - }
154 -
155 - // Allow extension to extend the request.
156 - $( mw ).trigger( 'LoaderEmbedPlayerUpdateRequest',
157 - [ playerElement, dependencyRequest ] );
158 - }
159 -
160 -} )( mediaWiki, jQuery );
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/EmbedPlayer/EmbedPlayer.php
@@ -1,12 +1,23 @@
22 <?php
33
4 - // Register all the EmbedPlayer modules in the $wgResourceModules global array
5 - return array(
6 - 'resources' => array(
 4+ // Register all the EmbedPlayer modules
 5+ return array(
76 "mw.EmbedPlayer" => array(
8 - 'scripts' => array( "mw.EmbedPlayer.js", "skins/mw.PlayerControlBuilder.js" ),
 7+ 'scripts' => array(
 8+ "mw.EmbedPlayer.js",
 9+ "skins/mw.PlayerControlBuilder.js",
 10+ ),
 11+ 'dependencies' => array(
 12+ // jQuery dependencies:
 13+ 'jquery.hoverIntent',
 14+ 'jquery.cookie',
 15+ 'jquery.ui.mouse',
 16+ '$.fn.menu',
 17+ 'mw.style.jquerymenu',
 18+ '$.ui.slider'
 19+ ),
920 'styles' => "skins/mw.style.EmbedPlayer.css",
10 - 'messageFile' => 'EmbedPlayer.i18n.php'
 21+ 'messageFile' => 'EmbedPlayer.i18n.php',
1122 ),
1223
1324 "mw.EmbedPlayerKplayer" => array( 'scripts'=> "mw.EmbedPlayerKplayer.js" ),
@@ -24,264 +35,6 @@
2536
2637 "mw.PlayerSkinMvpcf" => array( 'scripts'=> "skins/mvpcf/mw.PlayerSkinMvpcf.js",
2738 'styles'=> "skins/mvpcf/mw.style.PlayerSkinMvpcf.css"),
28 - ),
29 - // Set any default configuration
30 - 'config' => array(
31 - // If the player controls should be overlaid on top of the video ( if supported by playback method)
32 - // can be set to false per embed player via overlayControls attribute
33 - 'EmbedPlayer.OverlayControls' => true,
34 -
35 - // If the iPad should use html controls ( can't use fullscreen or control volume,
36 - // but lets you support overlays ie html controls ads etc. )
37 - 'EmbedPlayer.EnableIpadHTMLControls'=> false,
38 -
39 - 'EmbedPlayer.LibraryPage'=> 'http://www.kaltura.org/project/HTML5_Video_Media_JavaScript_Library',
40 -
41 - // A default apiProvider ( ie where to lookup subtitles, video properties etc )
42 - // NOTE: Each player instance can also specify a specific provider
43 - "EmbedPlayer.ApiProvider" => "local",
44 -
45 - // What tags will be re-written to video player by default
46 - // Set to empty string or null to avoid automatic video tag rewrites to embedPlayer
47 - "EmbedPlayer.RewriteTags" => "video,audio,playlist",
48 -
49 - // Default video size ( if no size provided )
50 - "EmbedPlayer.DefaultSize" => "400x300",
51 -
52 - // If the video player should attribute kaltura
53 - "EmbedPlayer.KalturaAttribution" => true,
54 -
55 - // The attribution button
56 - 'EmbedPlayer.AttributionButton' => array(
57 - 'title' => 'Kaltura html5 video library',
58 - 'href' => 'http://www.kaltura.org/project/HTML5_Video_Media_JavaScript_Library',
59 - // Style icon to be applied
60 - 'class' => 'kaltura-icon',
61 - // An icon image url ( should be a 12x12 image or data url )
62 - 'iconurl' => false
63 - ),
64 -
65 - // If the player should wait for metadata like video size and duration, before trying to draw
66 - // the player interface.
67 - 'EmbedPlayer.WaitForMeta' => true,
68 -
69 - // Set the browser player warning flag displays warning for non optimal playback
70 - "EmbedPlayer.ShowNativeWarning" => true,
71 -
72 - // If fullscreen is global enabled.
73 - "EmbedPlayer.EnableFullscreen" => true,
74 -
75 - // If mwEmbed should use the Native player controls
76 - // this will prevent video tag rewriting and skinning
77 - // useful for devices such as iPad / iPod that
78 - // don't fully support DOM overlays or don't expose full-screen
79 - // functionality to javascript
80 - "EmbedPlayer.NativeControls" => false,
81 -
82 - // If mwEmbed should use native controls on mobile safari
83 - "EmbedPlayer.NativeControlsMobileSafari" => true,
84 -
85 -
86 - // The z-index given to the player interface during full screen ( high z-index )
87 - "EmbedPlayer.fullScreenZIndex" => 999998,
88 -
89 - // The default share embed mode ( can be "object" or "videojs" )
90 - //
91 - // "iframe" will provide a <iframe tag pointing to mwEmbedFrame.php
92 - // Object embedding should be much more compatible with sites that
93 - // let users embed flash applets
94 - // "videojs" will include the source javascript and video tag to
95 - // rewrite the player on the remote page DOM
96 - // Video tag embedding is much more mash-up friendly but exposes
97 - // the remote site to the mwEmbed javascript and can be a xss issue.
98 - "EmbedPlayer.ShareEmbedMode" => 'iframe',
99 -
100 - // Default player skin name
101 - "EmbedPlayer.SkinName" => "mvpcf",
102 -
103 - // Number of milliseconds between interface updates
104 - 'EmbedPlayer.MonitorRate' => 250,
105 -
106 - // If the embedPlayer should accept arguments passed in from iframe postMessages calls
107 - 'EmbedPlayer.EnalbeIFramePlayerServer' => false,
108 -
109 - // If embedPlayer should support server side temporal urls for seeking options are
110 - // flash|always|none default is support for flash only.
111 - 'EmbedPlayer.EnableURLTimeEncoding' => 'flash',
112 -
113 - // The domains which can read and send events to the video player
114 - 'EmbedPLayer.IFramePlayer.DomainWhiteList' => '*',
115 -
116 - // If the iframe should send and receive javascript events across domains via postMessage
117 - 'EmbedPlayer.EnableIframeApi' => true,
118 -
119 - /**
120 - * The base source attribute checks also see:
121 - * http://dev.w3.org/html5/spec/Overview.html#the-source-element
122 - */
123 - 'EmbedPlayer.SourceAttributes' => array(
124 - // source id
125 - 'id',
126 -
127 - // media url
128 - 'src',
129 -
130 - // Title string for the source asset
131 - 'title',
132 -
133 - // boolean if we support temporal url requests on the source media
134 - 'URLTimeEncoding',
135 -
136 - // Media has a startOffset ( used for plugins that
137 - // display ogg page time rather than presentation time
138 - 'startOffset',
139 -
140 - // A hint to the duration of the media file so that duration
141 - // can be displayed in the player without loading the media file
142 - 'durationHint',
143 -
144 - // Media start time
145 - 'start',
146 -
147 - // Media end time
148 - 'end',
149 -
150 - // If the source is the default source
151 - 'default',
152 -
153 - // Title of the source
154 - 'title',
155 -
156 - // titleKey ( used for api lookups TODO move into mediaWiki specific support
157 - 'titleKey'
158 - ),
159 - /**
160 - * Merge in the default video attributes supported by embedPlayer:
161 - */
162 - 'EmbedPlayer.Attributes' => array(
163 - /*
164 - * Base html element attributes:
165 - */
166 -
167 - // id: Auto-populated if unset
168 - "id" => null,
169 -
170 - // Width: alternate to "style" to set player width
171 - "width" => null,
172 -
173 - // Height: alternative to "style" to set player height
174 - "height" => null,
175 -
176 - /*
177 - * Base html5 video element attributes / states also see:
178 - * http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html
179 - */
180 -
181 - // Media src URI, can be relative or absolute URI
182 - "src" => null,
183 -
184 - // Poster attribute for displaying a place holder image before loading
185 - // or playing the video
186 - "poster" => null,
187 -
188 - // Autoplay if the media should start playing
189 - "autoplay" => false,
190 -
191 - // Loop attribute if the media should repeat on complete
192 - "loop" => false,
193 -
194 - // If the player controls should be displayed
195 - "controls" => true,
196 -
197 - // Video starts "paused"
198 - "paused" => true,
199 -
200 - // ReadyState an attribute informs clients of video loading state:
201 - // see: http://www.whatwg.org/specs/web-apps/current-work/#readystate
202 - "readyState" => 0,
203 -
204 - // Loading state of the video element
205 - "networkState" => 0,
206 -
207 - // Current playback position
208 - "currentTime" => 0,
209 -
210 - // Previous player set time
211 - // Lets javascript use $j('#videoId').get(0).currentTime = newTime;
212 - "previousTime" => 0,
213 -
214 - // Previous player set volume
215 - // Lets javascript use $j('#videoId').get(0).volume = newVolume;
216 - "previousVolume" => 1,
217 -
218 - // Initial player volume:
219 - "volume" => 0.75,
220 -
221 - // Caches the volume before a mute toggle
222 - "preMuteVolume" => 0.75,
223 -
224 - // Media duration: Value is populated via
225 - // custom durationHint attribute or via the media file once its played
226 - "duration" => null,
227 -
228 - // Mute state
229 - "muted" => false,
230 -
231 - /**
232 - * Custom attributes for embedPlayer player: (not part of the html5
233 - * video spec)
234 - */
235 -
236 - // Default video aspect ratio
237 - 'videoAspect' => '4:3',
238 -
239 - // Start time of the clip
240 - "start" => 0,
241 -
242 - // End time of the clip
243 - "end" => null,
244 -
245 - // A apiTitleKey for looking up subtitles, credits and related videos
246 - // TODO move to data-mwTitleKey and into mediaWikiSupport module
247 - "apiTitleKey" => null,
248 -
249 - // The apiProvider where to lookup the title key
250 - // TODO move to data-mwApiProvider and into mediaWikiSupport module
251 - "apiProvider" => null,
252 -
253 - // If the player controls should be overlaid
254 - // ( Global default via config EmbedPlayer.OverlayControls in module
255 - // loader.js)
256 - "overlaycontrols" => true,
257 -
258 - // Attribute to use 'native' controls
259 - "usenativecontrols" => false,
260 -
261 - // If the player should include an attribution button:
262 - 'attributionbutton' => true,
263 -
264 - // ROE url ( for xml based metadata )
265 - // also see: http://wiki.xiph.org/ROE
266 - "roe" => null,
267 -
268 - // If serving an ogg_chop segment use this to offset the presentation
269 - // time
270 - // ( for some plugins that use ogg page time rather than presentation
271 - // time )
272 - "startOffset" => 0,
273 -
274 - // Source page for media asset ( used for linkbacks in remote embedding
275 - // )
276 - "linkback" => null,
277 -
278 - // If the download link should be shown
279 - "download_link" => true,
280 -
281 - // Content type of the media
282 - "type" => null
283 - ),
284 - ),
28539 );
28640
287 -
28841 ?>
\ No newline at end of file
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/EmbedPlayer/EmbedPlayer.config.php
@@ -0,0 +1,101 @@
 2+<?php
 3+ /**
 4+ * Do not edit this file instead use LocalSettings.php and
 5+ * $wgMwEmbedModuleConfig[ {ModuleName} ][ {configuration name} ] = value; format
 6+ */
 7+
 8+ return array(
 9+ // If the player controls should be overlaid on top of the video ( if supported by playback method)
 10+ // can be set to false per embed player via overlayControls attribute
 11+ 'EmbedPlayer.OverlayControls' => true,
 12+
 13+ // The preferred media codec preference
 14+ // Note user selected format order
 15+ 'EmbedPlayer.CodecPreference' => array( 'webm', 'h264', 'ogg' ),
 16+
 17+ // If the iPad should use html controls ( can't use fullscreen or control volume,
 18+ // but lets you support overlays ie html controls ads etc. )
 19+ 'EmbedPlayer.EnableIpadHTMLControls'=> false,
 20+
 21+ 'EmbedPlayer.LibraryPage'=> 'http://www.kaltura.org/project/HTML5_Video_Media_JavaScript_Library',
 22+
 23+ // A default apiProvider ( ie where to lookup subtitles, video properties etc )
 24+ // NOTE: Each player instance can also specify a specific provider
 25+ "EmbedPlayer.ApiProvider" => "local",
 26+
 27+ // What tags will be re-written to video player by default
 28+ // Set to empty string or null to avoid automatic video tag rewrites to embedPlayer
 29+ "EmbedPlayer.RewriteTags" => "video,audio,playlist",
 30+
 31+ // Default video size ( if no size provided )
 32+ "EmbedPlayer.DefaultSize" => "400x300",
 33+
 34+ // If the video player should attribute kaltura
 35+ "EmbedPlayer.KalturaAttribution" => true,
 36+
 37+ // The attribution button
 38+ 'EmbedPlayer.AttributionButton' => array(
 39+ 'title' => 'Kaltura html5 video library',
 40+ 'href' => 'http://www.kaltura.org/project/HTML5_Video_Media_JavaScript_Library',
 41+ // Style icon to be applied
 42+ 'class' => 'kaltura-icon',
 43+ // An icon image url ( should be a 12x12 image or data url )
 44+ 'iconurl' => false
 45+ ),
 46+
 47+ // If the player should wait for metadata like video size and duration, before trying to draw
 48+ // the player interface.
 49+ 'EmbedPlayer.WaitForMeta' => true,
 50+
 51+ // Set the browser player warning flag displays warning for non optimal playback
 52+ "EmbedPlayer.ShowNativeWarning" => true,
 53+
 54+ // If fullscreen is global enabled.
 55+ "EmbedPlayer.EnableFullscreen" => true,
 56+
 57+ // If mwEmbed should use the Native player controls
 58+ // this will prevent video tag rewriting and skinning
 59+ // useful for devices such as iPad / iPod that
 60+ // don't fully support DOM overlays or don't expose full-screen
 61+ // functionality to javascript
 62+ "EmbedPlayer.NativeControls" => false,
 63+
 64+ // If mwEmbed should use native controls on mobile safari
 65+ "EmbedPlayer.NativeControlsMobileSafari" => true,
 66+
 67+
 68+ // The z-index given to the player interface during full screen ( high z-index )
 69+ "EmbedPlayer.fullScreenZIndex" => 999998,
 70+
 71+ // The default share embed mode ( can be "iframe" or "xssVideo" )
 72+ //
 73+ // "iframe" will provide a <iframe tag pointing to mwEmbedFrame.php
 74+ // Object embedding should be much more compatible with sites that
 75+ // let users embed flash applets
 76+ // "xssVideo" will include the source javascript and video tag to
 77+ // rewrite the player on the remote page DOM
 78+ // Video tag embedding is much more mash-up friendly but exposes
 79+ // the remote site to the mwEmbed javascript and can be a xss issue.
 80+ "EmbedPlayer.ShareEmbedMode" => 'iframe',
 81+
 82+ // Default player skin name
 83+ "EmbedPlayer.DefaultSkin" => "mvpcf",
 84+
 85+ // Number of milliseconds between interface updates
 86+ 'EmbedPlayer.MonitorRate' => 250,
 87+
 88+ // If the embedPlayer should accept arguments passed in from iframe postMessages calls
 89+ 'EmbedPlayer.EnalbeIFramePlayerServer' => false,
 90+
 91+ // If embedPlayer should support server side temporal urls for seeking options are
 92+ // flash|always|none default is support for flash only.
 93+ 'EmbedPlayer.EnableURLTimeEncoding' => 'flash',
 94+
 95+ // The domains which can read and send events to the video player
 96+ 'EmbedPLayer.IFramePlayer.DomainWhiteList' => '*',
 97+
 98+ // If the iframe should send and receive javascript events across domains via postMessage
 99+ 'EmbedPlayer.EnableIframeApi' => true,
 100+
 101+ );
 102+?>
\ No newline at end of file
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/EmbedPlayer/mw.EmbedPlayer.js
@@ -7,12 +7,7 @@
88 * mw.PlayerControlBuilder Handles skinning of the player controls
99 */
1010
11 -/**
12 - * Add the messages text:
13 - */
1411
15 -mw.includeAllModuleMessages();
16 -
1712 /**
1813 * The base source attribute checks also see:
1914 * http://dev.w3.org/html5/spec/Overview.html#the-source-element
@@ -52,172 +47,18 @@
5348 ] );
5449
5550 /**
56 - * Adds jQuery binding for embedPlayer
57 - */
58 -( function( $ ) {
59 -
60 - /*
61 - * embeds all players that match the rewrite player tags config Passes off
62 - * request to the embedPlayer selector:
63 - *
64 - * @param {Object} attributes Attributes to apply to embed players @param
65 - * {Function} callback Function to call once embedding is done
66 - */
67 - $.embedPlayers = function( attributes, callback) {
68 - $j( mw.getConfig( 'EmbedPlayer.RewriteTags' ) ).embedPlayer( attributes, callback );
69 - };
70 -
71 - /**
72 - * Selector based embedPlayer jQuery binding
73 - *
74 - * Rewrites all tags via a given selector
75 - *
76 - * @param {object=} attributes
77 - * Optional embedPlayer attributes for the given video
78 - * interface. Attributes Object can include any key value pair
79 - * that would otherwise be an attribute in the html element.
80 - *
81 - * also see: mw.getConfig( 'EmbedPlayer.Attributes' )
82 - *
83 - * @param {Function=}
84 - * callback Optional Function to be called once video interfaces
85 - * are ready
86 - *
87 - */
88 - $.fn.embedPlayer = function( attributes, callback ) {
89 - mw.log( 'EmbedPlayer:: fn.embedPlayer' );
90 - if( this.selector ){
91 - var playerSelect = this.selector;
92 - } else {
93 - var playerSelect = this;
94 - }
95 -
96 - // Define attributes if unset
97 - if( !attributes ) {
98 - attributes = {};
99 - }
100 -
101 - // Handle optional include of attributes argument:
102 - if( typeof attributes == 'function' ){
103 - callback = attributes;
104 - attributes = {};
105 - }
106 -
107 - $j( playerSelect ).each( function( index, playerElement) {
108 - // make sure the playerElement has an id:
109 - if( !$j( playerElement ).attr('id') ){
110 - $j( playerElement ).attr( "id", 'mwe_v' + ( index ) );
111 - }
112 -
113 - // If we are dynamically embedding on a "div" check if we can
114 - // add a poster image behind the loader:
115 - if( playerElement.nodeName.toLowerCase() == 'div'
116 - && ( attributes.poster || $j(playerElement).attr( 'poster' ) ) ){
117 - var posterSrc = ( attributes.poster ) ? attributes.poster : $j(playerElement).attr( 'poster' );
118 -
119 - // Set image size:
120 - var width = $j( playerElement ).width();
121 - var height = $j( playerElement ).height();
122 - if( !width ){
123 - var width = ( attributes.width )? attributes.width : '100%';
124 - }
125 - if( !height ){
126 - var height = ( attributes.height )? attributes.height : '100%';
127 - }
128 -
129 - mw.log('EmbedPlayer:: set loading background: ' + posterSrc);
130 - $j( playerElement ).append(
131 - $j( '<img />' )
132 - .attr( 'src', posterSrc)
133 - .css({
134 - 'position' : 'absolute',
135 - 'width' : width,
136 - 'height' : height
137 - })
138 - );
139 - }
140 - });
141 -
142 - // If we have not detected browser plugin embed types do that now
143 - if( ! mw.EmbedTypes.players ){
144 - mw.EmbedTypes.init();
145 - }
146 -
147 - // Create the Global Embed Player Manager ( if not already created )
148 - if( ! mw.playerManager ) {
149 - mw.log( "EmbedPlayer::Create the player manager:" );
150 - mw.playerManager = new EmbedPlayerManager();
151 - // Run the global hooks that mw.playerManager is ready
152 - mw.log( 'EmbedPlayer::trigger: EmbedPlayerManagerReady');
153 - $j( mw ).trigger( 'EmbedPlayerManagerReady' );
154 - }
155 - // Make sure we have user preference setup ( for setting preferences on
156 - // video selection )
157 - mw.setupUserConfig( function() {
158 -
159 - var addedToPlayerManager = false;
160 - mw.log("EmbedPlayer:: do: " + $j( playerSelect ).length + ' players ');
161 -
162 - // Add each selected element to the player manager:
163 - $j( playerSelect ).each( function( index, playerElement) {
164 - // Make sure the video tag was not generated by our library:
165 - if( $j( playerElement ).hasClass( 'nativeEmbedPlayerPid' ) ){
166 - $j('#loadingSpinner_' + $j( playerElement ).attr('id') ).hide();
167 - mw.log( 'EmbedPlayer::$j.embedPlayer skip embedPlayer gennerated video: ' + playerElement );
168 - } else {
169 - addedToPlayerManager = true;
170 - // Add the player
171 - mw.playerManager.addPlayerElement( playerElement, attributes);
172 - }
173 - } );
174 - if( addedToPlayerManager ){
175 - if( callback ){
176 - $j( mw ).bind( "playersReadyEvent", callback );
177 - }
178 - } else {
179 - // Run the callback directly if no players were added to the
180 - if( callback ){
181 - callback();
182 - }
183 - }
184 -
185 - });
186 - };
187 -
188 -} )( jQuery );
189 -
190 -/**
191 - * EmbedPlayerManager
 51+ * Selector based embedPlayer processing
 52+ *
 53+ * @param {Function=}
 54+ * callback Optional Function to be called once video interfaces
 55+ * are ready
19256 *
193 - * Manages calls to embed video interfaces
19457 */
195 -var EmbedPlayerManager = function( ) {
196 - // Create a Player Manage
197 - return this.init( );
198 -};
199 -EmbedPlayerManager.prototype = {
200 -
201 - // Functions to run after the video interface is ready
202 - callbackFunctions : null,
203 -
204 - playerElementQueue: [],
205 -
 58+mw.processEmbedPlayers = function( playerSelect, callback ) {
 59+ mw.log( 'EmbedPlayer:: processEmbedPlayers' );
 60+
 61+
20662 /**
207 - * Constructor initializes callbackFunctions and playerList
208 - */
209 - init: function( ) {
210 - this.callbackFunctions = [];
211 - this.playerList = [];
212 - },
213 -
214 - /**
215 - * Get the list of players
216 - */
217 - getPlayerList: function( ) {
218 - return this.playerList;
219 - },
220 -
221 - /**
22263 * Adds a player element for the embedPlayer to rewrite
22364 *
22465 * uses embedPlayer interface on audio / video elements uses mvPlayList
@@ -238,102 +79,79 @@
23980 * [Optional] attributes Extra attributes to apply to the player
24081 * interface
24182 */
242 - addPlayerElement: function( playerElement, attributes ) {
 83+ var addPlayerElement = function( playerElement ) {
24384 var _this = this;
244 - if ( !playerElement.id || playerElement.id == '' ) {
245 - // give the playerElement an id:
246 - playerElement.id = 'vid' + ( this.playerList.length + 1 );
247 - }
24885 mw.log('EmbedPlayerManager: addElement:: ' + playerElement.id );
24986
250 - // Add the element id to playerList
251 - this.playerList.push( playerElement.id );
 87+ var waitForMeta = true;
25288
253 - // Check for player attributes such as skins or plugins attributes
254 - // that add to the request set
255 - var playerDependencyRequest = [];
256 -
257 - // Merge in any custom attributes
258 - $j.extend( playerElement, attributes );
259 -
260 - // Update the list of dependent libraries for the player
261 - // ( allows modules to add to the player dependency list )
262 - mw.embedPlayerUpdateLibraryRequest( playerElement, playerDependencyRequest );
 89+ // Be sure to "stop" the target ( Firefox 3x keeps playing
 90+ // the video even though its been removed from the DOM )
 91+ if( playerElement.pause ){
 92+ playerElement.pause();
 93+ }
26394
264 - // Load any skins we need then swap in the interface
265 - mw.load( playerDependencyRequest, function() {
266 -
267 - var waitForMeta = true;
 95+ // Allow modules to override the wait for metadata flag:
 96+ $j( mw ).trigger( 'checkPlayerWaitForMetaData', playerElement );
26897
269 - // Be sure to "stop" the target ( Firefox 3x keeps playing
270 - // the video even though its been removed from the DOM )
271 - if( playerElement.pause ){
272 - playerElement.pause();
273 - }
274 -
275 - // Allow modules to override the wait for metadata flag:
276 - $j( mw ).trigger( 'checkPlayerWaitForMetaData', playerElement );
 98+ // Update the waitForMeta object if set to boolean false:
 99+ waitForMeta = ( playerElement.waitForMeta === false )? false : true;
277100
278 - // Update the waitForMeta object if set to boolean false:
279 - waitForMeta = ( playerElement.waitForMeta === false )? false : true;
280101
 102+ // Confirm we want to wait for meta data ( if not already set to false by module )
 103+ if( waitForMeta ){
 104+ waitForMeta = waitForMetaCheck( playerElement );
 105+ }
281106
282 - // Confirm we want to wait for meta data ( if not already set to false by module )
283 - if( waitForMeta ){
284 - waitForMeta = _this.waitForMetaCheck( playerElement );
 107+ var ranPlayerSwapFlag = false;
 108+
 109+ // Local callback to runPlayer swap once playerElement has metadata
 110+ function runPlayerSwap() {
 111+ // Don't run player swap twice
 112+ if( ranPlayerSwapFlag ){
 113+ return ;
285114 }
 115+ ranPlayerSwapFlag = true;
 116+ mw.log("EmbedPlayer::runPlayerSwap::" + $j( playerElement ).attr('id') );
286117
287 - var ranPlayerSwapFlag = false;
 118+ var playerInterface = new mw.EmbedPlayer( playerElement , attributes);
 119+ var swapPlayer = swapEmbedPlayerElement( playerElement, playerInterface );
 120+
288121
289 - // Local callback to runPlayer swap once playerElement has metadata
290 - function runPlayerSwap() {
291 - // Don't run player swap twice
292 - if( ranPlayerSwapFlag ){
293 - return ;
294 - }
295 - ranPlayerSwapFlag = true;
296 - mw.log("EmbedPlayer::runPlayerSwap::" + $j( playerElement ).attr('id') );
 122+ // Trigger the newEmbedPlayerEvent for embedPlayer interface
 123+ mw.log("EmbedPlayer::addPlayerElement :trigger " + playerInterface.id );
 124+ $j( mw ).trigger ( 'newEmbedPlayerEvent', $j( '#' + playerInterface.id ).get(0) );
297125
298 - var playerInterface = new mw.EmbedPlayer( playerElement , attributes);
299 - var swapPlayer = _this.swapEmbedPlayerElement( playerElement, playerInterface );
300 -
 126+ // Issue the checkPlayerSources call to the new player
 127+ // interface: make sure to use the element that is in the DOM:
 128+ $j( '#' + playerInterface.id ).get(0).checkPlayerSources();
 129+ }
301130
302 - // Trigger the newEmbedPlayerEvent for embedPlayer interface
303 - mw.log("EmbedPlayer::addPlayerElement :trigger " + playerInterface.id );
304 - $j( mw ).trigger ( 'newEmbedPlayerEvent', $j( '#' + playerInterface.id ).get(0) );
 131+ if( waitForMeta && mw.getConfig('EmbedPlayer.WaitForMeta' ) ) {
 132+ mw.log('EmbedPlayer::WaitForMeta ( video missing height (' +
 133+ $j( playerElement ).attr('height') + '), width (' +
 134+ $j( playerElement ).attr('width') + ') or duration: ' +
 135+ $j( playerElement ).attr('duration')
 136+ );
 137+ $j( playerElement ).bind("loadedmetadata", runPlayerSwap );
305138
306 - // Issue the checkPlayerSources call to the new player
307 - // interface: make sure to use the element that is in the DOM:
308 - $j( '#' + playerInterface.id ).get(0).checkPlayerSources();
309 - }
 139+ // Time-out of 5 seconds ( maybe still playable but no timely
 140+ // metadata )
 141+ setTimeout( runPlayerSwap, 5000 );
 142+ return ;
 143+ } else {
 144+ runPlayerSwap();
 145+ return ;
 146+ }
 147+ };
310148
311 - if( waitForMeta && mw.getConfig('EmbedPlayer.WaitForMeta' ) ) {
312 - mw.log('EmbedPlayer::WaitForMeta ( video missing height (' +
313 - $j( playerElement ).attr('height') + '), width (' +
314 - $j( playerElement ).attr('width') + ') or duration: ' +
315 - $j( playerElement ).attr('duration')
316 - );
317 - $j( playerElement ).bind("loadedmetadata", runPlayerSwap );
318 -
319 - // Time-out of 5 seconds ( maybe still playable but no timely
320 - // metadata )
321 - setTimeout( runPlayerSwap, 5000 );
322 - return ;
323 - } else {
324 - runPlayerSwap();
325 - return ;
326 - }
327 - });
328 - },
329 -
330149 /**
331 - * Check for bogus resolutions of the media asset that has not loaded.
 150+ * Check if we should wait for metadata.
332151 *
333 - * @return true if the resolution is "likely" to be updated by waiting for
334 - * metadata false if the resolution has been set via an attribute or
335 - * is already loaded
 152+ * @return true if the size is "likely" to be updated by waiting for metadata
 153+ * false if the size has been set via an attribute or is already loaded
336154 */
337 - waitForMetaCheck: function( playerElement ){
 155+ var waitForMetaCheck = function( playerElement ){
338156 var waitForMeta = false;
339157
340158 // Don't wait for metadata for non html5 media elements
@@ -344,9 +162,9 @@
345163 return false;
346164 }
347165 // If we don't have a native player don't wait for metadata
348 - if( !mw.EmbedTypes.players.isSupportedPlayer( 'oggNative') &&
349 - !mw.EmbedTypes.players.isSupportedPlayer( 'webmNative') &&
350 - !mw.EmbedTypes.players.isSupportedPlayer( 'h264Native' ) )
 166+ if( !mw.EmbedTypes.getMediaPlayers().isSupportedPlayer( 'oggNative') &&
 167+ !mw.EmbedTypes.getMediaPlayers().isSupportedPlayer( 'webmNative') &&
 168+ !mw.EmbedTypes.getMediaPlayers().isSupportedPlayer( 'h264Native' ) )
351169 {
352170 return false;
353171 }
@@ -355,9 +173,9 @@
356174 var width = $j( playerElement ).css( 'width' );
357175 var height = $j( playerElement ).css( 'height' );
358176
359 - // Css video defaults
 177+ // Css video defaults ( firefox )
360178 if( $j( playerElement ).css( 'width' ) == '300px' &&
361 - $j( playerElement ).css( 'height' ) == '150px'
 179+ $j( playerElement ).css( 'height' ) == '150px'
362180 ){
363181 waitForMeta = true;
364182 } else {
@@ -372,7 +190,7 @@
373191 }
374192 }
375193
376 - // Firefox ~ sometimes ~ gives -1 for unloaded media
 194+ // Firefox ~ sometimes~ gives -1 for unloaded media
377195 if ( $j(playerElement).attr( 'width' ) == -1 || $j(playerElement).attr( 'height' ) == -1 ) {
378196 waitForMeta = true;
379197 }
@@ -409,15 +227,14 @@
410228 /**
411229 * swapEmbedPlayerElement
412230 *
413 - * Takes a video element as input and swaps it out with an embed player
414 - * interface
 231+ * Takes a video element as input and swaps it out with an embed player interface
415232 *
416233 * @param {Element}
417234 * targetElement Element to be swapped
418235 * @param {Object}
419236 * playerInterface Interface to swap into the target element
420237 */
421 - swapEmbedPlayerElement: function( targetElement, playerInterface ) {
 238+ var swapEmbedPlayerElement = function( targetElement, playerInterface ) {
422239 mw.log( 'EmbedPlayer::swapEmbedPlayerElement: ' + targetElement.id );
423240 // Create a new element to swap the player interface into
424241 var swapPlayerElement = document.createElement('div');
@@ -460,46 +277,88 @@
461278 $spinner.attr('id', 'loadingSpinner_' + playerInterface.id );
462279 }
463280 return swapPlayerElement;
464 - },
 281+ };
465282
 283+
 284+
 285+
 286+
 287+ // Add a loader for <div> embed player rewrites:
 288+ $j( playerSelect ).each( function( index, playerElement) {
 289+
 290+ // Make sure the playerElement has an id:
 291+ if( !$j( playerElement ).attr('id') ){
 292+ $j( playerElement ).attr( "id", 'mwe_v' + ( index ) );
 293+ }
466294
467 - /**
468 - * Player ready will run the global callbacks once players are "ready"
469 - *
470 - * This enables mw.ready event to expose video tag elements as if the
471 - * videotag was supported natively.
472 - *
473 - * @param {Object}
474 - * player The EmbedPlayer object
475 - */
476 - playerReady: function( player ) {
477 - var _this = this;
478 - mw.log( 'EmbedPlayer::ReadyToPlay callback player:' + player.id );
479 - player.readyToPlay = true;
 295+ // If we are dynamically embedding on a "div" check if we can
 296+ // add a poster image behind the loader:
 297+ if( playerElement.nodeName.toLowerCase() == 'div'
 298+ && ( attributes.poster || $j(playerElement).attr( 'poster' ) ) ){
 299+ var posterSrc = ( attributes.poster ) ? attributes.poster : $j(playerElement).attr( 'poster' );
480300
481 - // Remove the player loader spinner:
482 - $j('#loadingSpinner_' + player.id ).remove();
483 -
484 - // Run the player ready trigger
485 - $j( player ).trigger( 'playerReady' );
486 -
487 - var is_ready = true;
488 - for ( var i = 0; i < this.playerList.length; i++ ) {
489 - var currentPlayer = $j( '#' + this.playerList[i] ).get( 0 );
490 - if ( player ) {
491 - // Check if the current video is ready ( or has an error out )
492 - is_ready = ( player.readyToPlay || player.loadError ) ? is_ready : false;
 301+ // Set image size:
 302+ var width = $j( playerElement ).width();
 303+ var height = $j( playerElement ).height();
 304+ if( !width ){
 305+ var width = ( attributes.width )? attributes.width : '100%';
493306 }
 307+ if( !height ){
 308+ var height = ( attributes.height )? attributes.height : '100%';
 309+ }
 310+
 311+ mw.log('EmbedPlayer:: set loading background: ' + posterSrc);
 312+ $j( playerElement ).append(
 313+ $j( '<img />' )
 314+ .attr( 'src', posterSrc)
 315+ .css({
 316+ 'position' : 'absolute',
 317+ 'width' : width,
 318+ 'height' : height
 319+ })
 320+ );
494321 }
495 - if ( is_ready ) {
496 - // Be sure to remove any player loader spinners
497 - $j('.loadingSpinner').remove();
 322+ });
498323
499 - mw.log( "EmbedPlayer::All on-page players ready run playerManager callbacks" );
 324+ // Create the Global Embed Player Manager ( if not already created )
 325+ if( ! mw.playerManager ) {
 326+ mw.log( "EmbedPlayer::Create the player manager:" );
 327+ mw.playerManager = new EmbedPlayerManager();
 328+ // Run the global hooks that mw.playerManager is ready
 329+ mw.log( 'EmbedPlayer::trigger: EmbedPlayerManagerReady');
 330+ $j( mw ).trigger( 'EmbedPlayerManagerReady' );
 331+ }
 332+
 333+ // Make sure we have user preference setup for setting preferences on video selection
 334+ mw.setupUserConfig( function() {
500335
501 - $j(mw).trigger( 'playersReadyEvent' );
 336+ var addedToPlayerManager = false;
 337+ mw.log("EmbedPlayer:: do: " + $j( playerSelect ).length + ' players ');
 338+
 339+ // Add each selected element to the player manager:
 340+ $j( playerSelect ).each( function( index, playerElement) {
 341+ // Make sure the video tag was not generated by our library:
 342+ if( $j( playerElement ).hasClass( 'nativeEmbedPlayerPid' ) ){
 343+ $j('#loadingSpinner_' + $j( playerElement ).attr('id') ).hide();
 344+ mw.log( 'EmbedPlayer::$j.embedPlayer skip embedPlayer gennerated video: ' + playerElement );
 345+ } else {
 346+ addedToPlayerManager = true;
 347+ // Add the player
 348+ mw.playerManager.addPlayerElement( playerElement );
 349+ }
 350+ } );
 351+ if( addedToPlayerManager ){
 352+ if( callback ){
 353+ $j( mw ).bind( "playersReadyEvent", callback );
 354+ }
 355+ } else {
 356+ // Run the callback directly if no players were added to the
 357+ if( callback ){
 358+ callback();
 359+ }
502360 }
503 - }
 361+
 362+ });
504363 };
505364
506365 /**
@@ -787,45 +646,45 @@
788647 // http://www.jibbering.com/2002/4/httprequest.html
789648 var urlParts = mw.parseUri( uri );
790649 // Get the extension from the url or from the relative name:
791 - var ext = ( urlParts.file )? urlParts.file.substr( -4 ) : uri.substr( -4 );
792 - switch( ext.toLowerCase() ) {
 650+ var ext = ( urlParts.file )? /[^.]+$/.exec( urlParts.file ) : /[^.]+$/.exec( uri );
 651+ switch( ext.toString().toLowerCase() ) {
793652 case 'smil':
794 - case '.sml':
 653+ case 'sml':
795654 return 'application/smil';
796655 break;
797 - case '.m4v':
798 - case '.mp4':
 656+ case 'm4v':
 657+ case 'mp4':
799658 return 'video/h264';
800659 break;
801660 case 'webm':
802661 return 'video/webm';
803662 break;
804 - case '.srt':
 663+ case 'srt':
805664 return 'text/x-srt';
806665 break;
807 - case '.flv':
 666+ case 'flv':
808667 return 'video/x-flv';
809668 break;
810 - case '.ogg':
811 - case '.ogv':
 669+ case 'ogg':
 670+ case 'ogv':
812671 return 'video/ogg';
813672 break;
814 - case '.oga':
 673+ case 'oga':
815674 return 'audio/ogg';
816675 break;
817 - case '.anx':
 676+ case 'anx':
818677 return 'video/ogg';
819678 break;
820 - case '.xml':
 679+ case 'xml':
821680 return 'text/xml';
822681 break;
823 - case '.avi':
 682+ case 'avi':
824683 return 'video/x-msvideo';
825684 break;
826 - case '.mpg':
 685+ case 'mpg':
827686 return 'video/mpeg';
828687 break;
829 - case '.mpeg':
 688+ case 'mpeg':
830689 return 'video/mpeg';
831690 break;
832691 }
@@ -859,6 +718,9 @@
860719 // Selected mediaSource element.
861720 selectedSource: null,
862721
 722+ // Media element thumbnail
 723+ thumbnail: null,
 724+
863725 // Media element linkback
864726 linkback: null,
865727
@@ -973,7 +835,7 @@
974836 if ( i == index ) {
975837 this.selectedSource = playableSources[i];
976838 // Update the user selected format:
977 - mw.EmbedTypes.players.setFormatPreference( playableSources[i].mimeType );
 839+ mw.EmbedTypes.getMediaPlayers().setFormatPreference( playableSources[i].mimeType );
978840 break;
979841 }
980842 }
@@ -985,6 +847,7 @@
986848 */
987849 autoSelectSource: function() {
988850 mw.log( 'EmbedPlayer::mediaElement::autoSelectSource' );
 851+ var _this = this;
989852 // Select the default source
990853 var playableSources = this.getPlayableSources();
991854 var flash_flag = ogg_flag = false;
@@ -993,13 +856,16 @@
994857 if( playableSources.length == 0 ){
995858 return false;
996859 }
 860+ var setSelectedSource = function( source ){
 861+ _this.selectedSource = source;
 862+ };
997863
998864 // Set via user-preference
999865 for ( var source = 0; source < playableSources.length; source++ ) {
1000866 var mimeType = playableSources[source].mimeType;
1001 - if ( mw.EmbedTypes.players.preference[ 'format_preference' ] == mimeType ) {
1002 - mw.log( 'Set via preference: ' + playableSources[source].mimeType );
1003 - this.selectedSource = playableSources[source];
 867+ if ( mw.EmbedTypes.getMediaPlayers().preference[ 'format_preference' ] == mimeType ) {
 868+ mw.log( 'EmbedPlayer::autoSelectSource: Set via preference: ' + playableSources[source].mimeType );
 869+ setSelectedSource( playableSources[source] );
1004870 return true;
1005871 }
1006872 }
@@ -1007,8 +873,8 @@
1008874 // Set via marked default:
1009875 for ( var source = 0; source < playableSources.length; source++ ) {
1010876 if ( playableSources[ source ].markedDefault ) {
1011 - mw.log( 'Set via marked default: ' + playableSources[source].markedDefault );
1012 - this.selectedSource = playableSources[source];
 877+ mw.log( 'EmbedPlayer::autoSelectSource: Set via marked default: ' + playableSources[source].markedDefault );
 878+ setSelectedSource( playableSources[source] );
1013879 return true;
1014880 }
1015881 }
@@ -1016,10 +882,10 @@
1017883 // Prefer native playback
1018884 for ( var source = 0; source < playableSources.length; source++ ) {
1019885 var mimeType = playableSources[source].mimeType;
1020 - var player = mw.EmbedTypes.players.defaultPlayer( mimeType );
 886+ var player = mw.EmbedTypes.getMediaPlayers().defaultPlayer( mimeType );
1021887 if ( player && player.library == 'Native' ) {
1022 - mw.log('EmbedPlayer::Set native playback');
1023 - this.selectedSource = playableSources[ source ];
 888+ mw.log('EmbedPlayer::autoSelectSource: Set via native playback');
 889+ setSelectedSource( playableSources[ source ] );
1024890 return true;
1025891 }
1026892 }
@@ -1027,7 +893,7 @@
1028894 // Set h264 via native or flash fallback
1029895 for ( var source = 0; source < playableSources.length; source++ ) {
1030896 var mimeType = playableSources[source].mimeType;
1031 - var player = mw.EmbedTypes.players.defaultPlayer( mimeType );
 897+ var player = mw.EmbedTypes.getMediaPlayers().defaultPlayer( mimeType );
1032898 if ( mimeType == 'video/h264'
1033899 && player
1034900 && (
@@ -1036,16 +902,16 @@
1037903 player.library == 'Kplayer'
1038904 )
1039905 ) {
1040 - mw.log('Set h264 via native or flash fallback');
1041 - this.selectedSource = playableSources[ source ];
 906+ mw.log('EmbedPlayer::autoSelectSource: Set h264 via native or flash fallback');
 907+ setSelectedSource( playableSources[ source ] );
1042908 return true;
1043909 }
1044910 };
1045911
1046912 // Else just select first source
1047913 if ( !this.selectedSource ) {
1048 - mw.log( 'set via first source:' + playableSources[0] );
1049 - this.selectedSource = playableSources[0];
 914+ mw.log( 'EmbedPlayer::autoSelectSource: Set via first source:' + playableSources[0] );
 915+ setSelectedSource( playableSources[0] );
1050916 return true;
1051917 }
1052918 // No Source found so no source selected
@@ -1067,9 +933,9 @@
1068934 },
1069935
1070936 /**
1071 - * Returns the poster URL for the media element.
 937+ * Returns the thumbnail URL for the media element.
1072938 *
1073 - * @returns {String} poster URL
 939+ * @returns {String} thumbnail URL
1074940 */
1075941 getPosterSrc: function( ) {
1076942 return this.poster;
@@ -1097,7 +963,7 @@
1098964 * Checks if media is a playable type
1099965 */
1100966 isPlayableType: function( mimeType ) {
1101 - if ( mw.EmbedTypes.players.defaultPlayer( mimeType ) ) {
 967+ if ( mw.EmbedTypes.getMediaPlayers().defaultPlayer( mimeType ) ) {
1102968 return true;
1103969 } else {
1104970 return false;
@@ -1252,7 +1118,10 @@
12531119 // Buffer flags
12541120 'bufferStartFlag' : false,
12551121 'bufferEndFlag' : false,
1256 -
 1122+
 1123+ // For supporting media fragments stores the play end time
 1124+ 'pauseTime' : null,
 1125+
12571126 // On done playing
12581127 'donePlayingCount' : 0
12591128 ,
@@ -1275,6 +1144,7 @@
12761145 */
12771146 init: function( element, customAttributes ) {
12781147 var _this = this;
 1148+ mw.log('EmbedPlayer: initEmbedPlayer: ' + $j(element).width() );
12791149 // Set customAttributes if unset:
12801150 if ( !customAttributes ) {
12811151 customAttributes = { };
@@ -1312,6 +1182,9 @@
13131183 }
13141184
13151185 // Set the poster:
 1186+ if ( $j( element ).attr( 'thumbnail' ) ) {
 1187+ _this.poster = $j( element ).attr( 'thumbnail' );
 1188+ }
13161189 if ( $j( element ).attr( 'poster' ) ) {
13171190 _this.poster = $j( element ).attr( 'poster' );
13181191 }
@@ -1435,7 +1308,15 @@
14361309 loadPlayerSize: function( element ) {
14371310 this.height = $j(element).css( 'height' );
14381311 this.width = $j(element).css( 'width' );
1439 -
 1312+ // Special check for chrome 100% with re-mapping to 32px
 1313+ // ( hopefully no one embeds video at 32x32 )
 1314+ if( this.height == '32px' || this.height =='32px' ){
 1315+ var defaultSize = mw.getConfig( 'EmbedPlayer.DefaultSize' ).split( 'x' );
 1316+ this.width = '100%';
 1317+ this.height = '100%';
 1318+ }
 1319+ mw.log('EmbedPlayer::loadPlayerSize: css size:' + this.width + ' h: ' + this.height);
 1320+
14401321 // Set to parent size ( resize events will cause player size updates)
14411322 if( this.height.indexOf('100%') != -1 || this.width.indexOf('100%') != -1 ){
14421323 $relativeParent = $j(element).parents().filter(function() {
@@ -1691,7 +1572,7 @@
16921573 if ( !this.mediaElement.selectedSource ) {
16931574 mw.log( 'setupSourcePlayer:: no sources, type:' + this.type );
16941575 } else {
1695 - this.selectedPlayer = mw.EmbedTypes.players.defaultPlayer( this.mediaElement.selectedSource.mimeType );
 1576+ this.selectedPlayer = mw.EmbedTypes.getMediaPlayers().defaultPlayer( this.mediaElement.selectedSource.mimeType );
16961577 }
16971578
16981579 if ( this.selectedPlayer ) {
@@ -1923,9 +1804,8 @@
19241805 // actions )
19251806 mw.log("EmbedPlayer::onClipDone:Trigger ended");
19261807
1927 - this.tempDisableEvents();
19281808 // TOOD we should improve the end event flow
1929 - $j( this ).trigger( 'ended' );
 1809+ $j( this ).trigger( 'ended' );
19301810
19311811 if( this.onDoneInterfaceFlag ){
19321812
@@ -1965,7 +1845,7 @@
19661846 // Close Menu Overlay:
19671847 this.controlBuilder.closeMenuOverlay();
19681848
1969 - // update the Poster html:
 1849+ // update the thumbnail html:
19701850 this.updatePosterHTML();
19711851
19721852 this.paused = true;
@@ -1973,7 +1853,7 @@
19741854 // Make sure the controlBuilder bindings are up-to-date
19751855 this.controlBuilder.addControlBindings();
19761856
1977 - // Once the Poster is shown run the mediaReady trigger (if not using
 1857+ // Once the thumbnail is shown run the mediaReady trigger (if not using
19781858 // native controls)
19791859 if( !this.useNativePlayerControls() ){
19801860 mw.log("mediaLoaded");
@@ -2044,17 +1924,51 @@
20451925 this.$interface.hide();
20461926 }
20471927
 1928+ // Update temporal url if present
 1929+ this.updateTemporalUrl();
 1930+
 1931+
20481932 if ( this.autoplay ) {
20491933 mw.log( 'EmbedPlayer::showPlayer::activating autoplay' );
20501934 // Issue a non-blocking play request
20511935 setTimeout(function(){
20521936 _this.play();
2053 - },1)
 1937+ },1);
20541938 }
20551939
20561940 },
2057 -
20581941 /**
 1942+ * Media framgments handler based on:
 1943+ * http://www.w3.org/2008/WebVideo/Fragments/WD-media-fragments-spec/#fragment-dimensions
 1944+ *
 1945+ * We support seconds and npt ( normal play time )
 1946+ *
 1947+ * Updates the player per fragment url info if present
 1948+ *
 1949+ */
 1950+ updateTemporalUrl: function(){
 1951+ var sourceHash = /[^\#]+$/.exec( this.getSrc() ).toString();
 1952+ if( sourceHash.indexOf('t=') === 0 ){
 1953+ // parse the times
 1954+ var times = sourceHash.substr(2).split(',');
 1955+ if( times[0] ){
 1956+ // update the current time
 1957+ this.currentTime = mw.npt2seconds( times[0].toString() );
 1958+ }
 1959+ if( times[1] ){
 1960+ this.pauseTime = mw.npt2seconds( times[1].toString() );
 1961+ // ignore invalid ranges:
 1962+ if( this.pauseTime < this.currentTime ){
 1963+ this.pauseTime = null;
 1964+ }
 1965+ }
 1966+ // Update the play head
 1967+ this.updatePlayHead( this.currentTime / this.duration );
 1968+ // Update status:
 1969+ this.controlBuilder.setStatus( mw.seconds2npt( this.currentTime ) );
 1970+ }
 1971+ },
 1972+ /**
20591973 * Get missing plugin html (check for user included code)
20601974 *
20611975 * @param {String}
@@ -2438,7 +2352,7 @@
24392353 case 'iframe':
24402354 return this.getShareIframeObject();
24412355 break;
2442 - case 'videojs':
 2356+ case 'xssVideo':
24432357 return this.getShareEmbedVideoJs();
24442358 break;
24452359 }
@@ -2600,7 +2514,7 @@
26012515 play: function() {
26022516 var _this = this;
26032517 mw.log( "EmbedPlayer:: play: " + this._propagateEvents );
2604 - if( ! this._propagateEvents){
 2518+ if( ! this._propagateEvents ){
26052519 return ;
26062520 }
26072521 // Hide any overlay:
@@ -2614,21 +2528,17 @@
26152529 } else {
26162530 this.posterDisplayed = false;
26172531 // Hide any button if present:
2618 - this.$interface.find( '.play-btn-large' ).remove();
 2532+ this.$interface.find( '.play-btn-large' ).remove();
26192533 this.doEmbedHTML();
26202534 }
26212535 }
2622 -
26232536
26242537 if( this.paused === true ){
26252538 this.paused = false;
26262539 // Check if we should Trigger the play event
2627 - if( this.bubbleEventCheck() ) {
2628 - mw.log("EmbedPlayer:: trigger play even::" + !this.paused);
2629 - if( this._propagateEvents ){
2630 - $j( this ).trigger( 'play' );
2631 - _this.tempDisableEvents();
2632 - }
 2540+ mw.log("EmbedPlayer:: trigger play even::" + !this.paused);
 2541+ if( ! this.doMethodsAutoTrigger() ) {
 2542+ $j( this ).trigger( 'play' );
26332543 }
26342544 }
26352545
@@ -2654,18 +2564,6 @@
26552565 this.monitor();
26562566 },
26572567 /**
2658 - * Returns true if the event should be triggered or false if not
2659 - *
2660 - * @@FIXME:: firefox nightlies now Do NOT bubble events. Once release tag
2661 - * every version after that
2662 - */
2663 - bubbleEventCheck: function(){
2664 - if( $j.browser.webkit ){
2665 - return true;
2666 - }
2667 - return false;
2668 - },
2669 - /**
26702568 * Base embed pause Updates the play/pause button state.
26712569 *
26722570 * There is no general way to pause the video must be overwritten by embed
@@ -2677,14 +2575,9 @@
26782576 // controls:
26792577 if( this.paused === false ){
26802578 this.paused = true;
2681 - mw.log( "EmbedPlayer:: pause: " + this._propagateEvents );
2682 -
2683 - if( this.bubbleEventCheck() ){
2684 - mw.log('EmbedPlayer:trigger pause:' + this.paused);
2685 - if( this._propagateEvents ){
2686 - $j( this ).trigger( 'pause' );
2687 - _this.tempDisableEvents();
2688 - }
 2579+ mw.log('EmbedPlayer:trigger pause:' + this.paused);
 2580+ if( ! this.doMethodsAutoTrigger() ){
 2581+ $j( this ).trigger( 'pause' );
26892582 }
26902583 }
26912584
@@ -2694,23 +2587,20 @@
26952588 .addClass( 'ui-icon-play' );
26962589
26972590 this.$interface.find('.play-btn' )
2698 - .unbind()
 2591+ .unbind('click')
26992592 .buttonHover()
27002593 .click( function() {
27012594 _this.play();
27022595 } )
27032596 .attr( 'title', gM( 'mwe-embedplayer-play_clip' ) );
27042597 },
2705 -
2706 - /**
2707 - * Disable event _propagateEvents for 10ms ( helps avoid event stacking )
2708 - */
2709 - tempDisableEvents: function(){
2710 - var _this = this;
2711 - this._propagateEvents = false;
2712 - setTimeout( function(){
2713 - _this._propagateEvents = true;
2714 - }, 10);
 2598+ // special per browser check for autoTrigger events
 2599+ // ideally jQuery would not have this inconsistency.
 2600+ doMethodsAutoTrigger: function(){
 2601+ if( $j.browser.mozilla && ! mw.versionIsAtLeast('2.0', $j.browser.version ) ){
 2602+ return true;
 2603+ }
 2604+ return false;
27152605 },
27162606
27172607 /**
@@ -2866,7 +2756,7 @@
28672757 /**
28682758 * Passes a fullscreen request to the controlBuilder interface
28692759 */
2870 - fullscreen: function() {
 2760+ fullscreen: function() {
28712761 this.controlBuilder.toggleFullscreen();
28722762 },
28732763
@@ -2965,6 +2855,11 @@
29662856 // Update the previousTime ( so we can know if the user-javascript
29672857 // changed currentTime )
29682858 _this.previousTime = _this.currentTime;
 2859+
 2860+ if( _this.pauseTime && _this.currentTime > _this.pauseTime ){
 2861+ _this.pause();
 2862+ _this.pauseTime = null;
 2863+ }
29692864
29702865
29712866 // Check if volume was set outside of embed player function
@@ -3122,68 +3017,8 @@
31233018 $j( this ).trigger('updatePlayHeadPercent', perc);
31243019 },
31253020
3126 - /**
3127 - * Highlight a section of video on the playhead
3128 - *
3129 - * @param {Object}
3130 - * options Provides "start" time & "end" time to highlight
3131 - */
3132 - highlightPlaySection:function( options ) {
3133 - mw.log( 'highlightPlaySection' );
3134 - var eid = ( this.pc ) ? this.pc.pp.id:this.id;
3135 - var dur = this.getDuration();
3136 - // set the left percet and update the slider:
3137 - rel_start_sec = mw.npt2seconds( options['start'] );
3138 - // remove the startOffset if relevent:
3139 - if ( this.startOffset )
3140 - rel_start_sec = rel_start_sec - this.startOffset
31413021
3142 - var slider_perc = 0;
3143 - if ( rel_start_sec <= 0 ) {
3144 - left_perc = 0;
3145 - options['start'] = mw.seconds2npt( this.startOffset );
3146 - rel_start_sec = 0;
3147 - this.updatePlayHead( 0 );
3148 - } else {
3149 - left_perc = parseInt( ( rel_start_sec / dur ) * 100 ) ;
3150 - slider_perc = ( left_perc / 100 );
3151 - }
3152 -
3153 - mw.log( "slider perc:" + slider_perc );
3154 - if ( ! this.isPlaying() ) {
3155 - this.updatePlayHead( slider_perc );
3156 - }
3157 -
3158 - width_perc = parseInt( ( ( mw.npt2seconds( options['end'] ) - mw.npt2seconds( options['start'] ) ) / dur ) * 100 ) ;
3159 - if ( ( width_perc + left_perc ) > 100 ) {
3160 - width_perc = 100 - left_perc;
3161 - }
3162 - // mw.log('should hl: '+rel_start_sec+ '/' + dur + ' re:' +
3163 - // rel_end_sec+' lp:' + left_perc + ' width: ' + width_perc);
3164 - $j( '#mv_seeker_' + eid + ' .mv_highlight' ).css( {
3165 - 'left' : left_perc + '%',
3166 - 'width' : width_perc + '%'
3167 - } ).show();
3168 -
3169 - this.jump_time = options['start'];
3170 - this.serverSeekTime = mw.npt2seconds( options['start'] );
3171 - // trim output to
3172 - this.controlBuilder.setStatus( gM( 'mwe-embedplayer-seek_to', mw.seconds2npt( this.serverSeekTime ) ) );
3173 - mw.log( 'DO update: ' + this.jump_time );
3174 - this.updateThumbTime( rel_start_sec );
3175 - },
3176 -
31773022 /**
3178 - * Hides the playhead highlight
3179 - */
3180 - hideHighlight: function() {
3181 - var eid = ( this.pc ) ? this.pc.pp.id:this.id;
3182 - $j( '#mv_seeker_' + eid + ' .mv_highlight' ).hide();
3183 - this.controlBuilder.setStatus( this.getTimeRange() );
3184 - },
3185 -
3186 -
3187 - /**
31883023 * Helper Functions for selected source
31893024 */
31903025
@@ -3543,8 +3378,8 @@
35443379 */
35453380 mw.EmbedTypes = {
35463381
3547 - // List of players supported
3548 - players: null,
 3382+ // MediaPlayers object ( supports methods for quering set of browser players )
 3383+ mediaPlayers: null,
35493384
35503385 // Detect flag for completion
35513386 detect_done:false,
@@ -3559,6 +3394,16 @@
35603395 this.detect();
35613396 this.detect_done = true;
35623397 },
 3398+
 3399+ getMediaPlayers: function(){
 3400+ if( this.mediaPlayers ){
 3401+ return this.mediaPlayers;
 3402+ }
 3403+ this.mediaPlayers = new mediaPlayers();
 3404+ // detect available players
 3405+ this.detectPlayers();
 3406+ return this.mediaPlayers;
 3407+ },
35633408
35643409 /**
35653410 * If the browsers supports a given mimetype
@@ -3578,13 +3423,11 @@
35793424 /**
35803425 * Detects what plug-ins the client supports
35813426 */
3582 - detect: function() {
3583 - mw.log( "embedPlayer: running detect" );
3584 - this.players = new mediaPlayers();
 3427+ detectPlayers: function() {
 3428+ mw.log( "embedPlayer: running detect" );
35853429 // every browser supports html rendering:
3586 - this.players.addPlayer( htmlPlayer );
3587 - // In Mozilla, navigator.javaEnabled() only tells us about preferences,
3588 - // we need to
 3430+ this.mediaPlayers.addPlayer( htmlPlayer );
 3431+ // In Mozilla, navigator.javaEnabled() only tells us about preferences, we need to
35893432 // search navigator.mimeTypes to see if it's installed
35903433 try{
35913434 var javaEnabled = navigator.javaEnabled();
@@ -3595,34 +3438,33 @@
35963439 var uniqueMimesOnly = $j.browser.opera || $j.browser.safari;
35973440
35983441 // Opera will switch off javaEnabled in preferences if java can't be
3599 - // found.
3600 - // And it doesn't register an application/x-java-applet mime type like
 3442+ // found. And it doesn't register an application/x-java-applet mime type like
36013443 // Mozilla does.
36023444 if ( javaEnabled && ( navigator.appName == 'Opera' ) ) {
3603 - this.players.addPlayer( cortadoPlayer );
 3445+ this.mediaPlayers.addPlayer( cortadoPlayer );
36043446 }
36053447
36063448 // ActiveX plugins
36073449 if ( $j.browser.msie ) {
36083450 // check for flash
36093451 if ( this.testActiveX( 'ShockwaveFlash.ShockwaveFlash' ) ) {
3610 - this.players.addPlayer( kplayer );
3611 - // this.players.addPlayer( flowPlayer );
 3452+ this.mediaPlayers.addPlayer( kplayer );
 3453+ // this.mediaPlayers.addPlayer( flowPlayer );
36123454 }
36133455 // VLC
36143456 if ( this.testActiveX( 'VideoLAN.VLCPlugin.2' ) ) {
3615 - this.players.addPlayer( vlcPlayer );
 3457+ this.mediaPlayers.addPlayer( vlcPlayer );
36163458 }
36173459
36183460 // Java ActiveX
36193461 if ( this.testActiveX( 'JavaWebStart.isInstalled' ) ) {
3620 - this.players.addPlayer( cortadoPlayer );
 3462+ this.mediaPlayers.addPlayer( cortadoPlayer );
36213463 }
36223464
36233465 // quicktime (currently off)
36243466 // if ( this.testActiveX(
36253467 // 'QuickTimeCheckObject.QuickTimeCheck.1' ) )
3626 - // this.players.addPlayer(quicktimeActiveXPlayer);
 3468+ // this.mediaPlayers.addPlayer(quicktimeActiveXPlayer);
36273469 }
36283470 // <video> element
36293471 if ( typeof HTMLVideoElement == 'object' // Firefox, Safari
@@ -3634,26 +3476,26 @@
36353477 if( dummyvid.canPlayType ) {
36363478 // Add the webm player
36373479 if( dummyvid.canPlayType('video/webm; codecs="vp8, vorbis"') ){
3638 - this.players.addPlayer( webmNativePlayer );
 3480+ this.mediaPlayers.addPlayer( webmNativePlayer );
36393481 }
36403482
36413483 // Test for h264:
36423484 if ( dummyvid.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"' ) ) {
3643 - this.players.addPlayer( h264NativePlayer );
 3485+ this.mediaPlayers.addPlayer( h264NativePlayer );
36443486 }
36453487 // For now if Android assume we support h264Native (FIXME
36463488 // test on real devices )
36473489 if ( mw.isAndroid2() ){
3648 - this.players.addPlayer( h264NativePlayer );
 3490+ this.mediaPlayers.addPlayer( h264NativePlayer );
36493491 }
36503492
36513493 // Test for ogg
36523494 if ( dummyvid.canPlayType( 'video/ogg; codecs="theora,vorbis"' ) ) {
3653 - this.players.addPlayer( oggNativePlayer );
 3495+ this.mediaPlayers.addPlayer( oggNativePlayer );
36543496 // older versions of safari do not support canPlayType,
36553497 // but xiph qt registers mimetype via quicktime plugin
36563498 } else if ( this.supportedMimeType( 'video/ogg' ) ) {
3657 - this.players.addPlayer( oggNativePlayer );
 3499+ this.mediaPlayers.addPlayer( oggNativePlayer );
36583500 }
36593501 }
36603502 } catch ( e ) {
@@ -3676,43 +3518,43 @@
36773519 pluginName = '';
36783520 }
36793521 if ( pluginName.toLowerCase() == 'vlc multimedia plugin' || pluginName.toLowerCase() == 'vlc multimedia plug-in' ) {
3680 - this.players.addPlayer( vlcPlayer );
 3522+ this.mediaPlayers.addPlayer( vlcPlayer );
36813523 continue;
36823524 }
36833525
36843526 if ( type == 'application/x-java-applet' ) {
3685 - this.players.addPlayer( cortadoPlayer );
 3527+ this.mediaPlayers.addPlayer( cortadoPlayer );
36863528 continue;
36873529 }
36883530
36893531 if ( (type == 'video/mpeg' || type == 'video/x-msvideo') &&
36903532 pluginName.toLowerCase() == 'vlc multimedia plugin' ) {
3691 - this.players.addPlayer( vlcMozillaPlayer );
 3533+ this.mediaPlayers.addPlayer( vlcMozillaPlayer );
36923534 }
36933535
36943536 if ( type == 'application/ogg' ) {
36953537 if ( pluginName.toLowerCase() == 'vlc multimedia plugin' ) {
3696 - this.players.addPlayer( vlcMozillaPlayer );
 3538+ this.mediaPlayers.addPlayer( vlcMozillaPlayer );
36973539 // else if ( pluginName.indexOf( 'QuickTime' ) > -1 )
3698 - // this.players.addPlayer(quicktimeMozillaPlayer);
 3540+ // this.mediaPlayers.addPlayer(quicktimeMozillaPlayer);
36993541 } else {
3700 - this.players.addPlayer( oggPluginPlayer );
 3542+ this.mediaPlayers.addPlayer( oggPluginPlayer );
37013543 }
37023544 continue;
37033545 } else if ( uniqueMimesOnly ) {
37043546 if ( type == 'application/x-vlc-player' ) {
3705 - this.players.addPlayer( vlcMozillaPlayer );
 3547+ this.mediaPlayers.addPlayer( vlcMozillaPlayer );
37063548 continue;
37073549 } else if ( type == 'video/quicktime' ) {
3708 - // this.players.addPlayer(quicktimeMozillaPlayer);
 3550+ // this.mediaPlayers.addPlayer(quicktimeMozillaPlayer);
37093551 continue;
37103552 }
37113553 }
37123554
37133555 if ( type == 'application/x-shockwave-flash' ) {
37143556
3715 - this.players.addPlayer( kplayer );
3716 - // this.players.addPlayer( flowPlayer );
 3557+ this.mediaPlayers.addPlayer( kplayer );
 3558+ // this.mediaPlayers.addPlayer( flowPlayer );
37173559
37183560 // check version to add omtk:
37193561 if( navigator.plugins["Shockwave Flash"] ){
@@ -3729,7 +3571,7 @@
37303572
37313573 // Allow extensions to detect and add their own "players"
37323574 mw.log("trigger::embedPlayerUpdateMediaPlayersEvent");
3733 - $j( mw ).trigger( 'embedPlayerUpdateMediaPlayersEvent' , this.players );
 3575+ $j( mw ).trigger( 'embedPlayerUpdateMediaPlayersEvent' , this.mediaPlayers );
37343576
37353577 },
37363578
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/EmbedPlayer/mw.IFramePlayerApiClient.js
@@ -24,8 +24,11 @@
2525 // Set the iframe server
2626 var srcParts = mw.parseUri( mw.absoluteUrl( $j(this.iframe).attr('src') ) );
2727 this.iframeServer = srcParts.protocol + '://' + srcParts.authority;
 28+
2829 this.addPlayerSendApi();
2930 this.addPlayerReciveApi();
 31+
 32+ this.addIframeFullscreenBinding();
3033 },
3134 'addPlayerSendApi': function(){
3235 var _this = this;
@@ -46,31 +49,65 @@
4750 var _this = this;
4851 $j.receiveMessage( function( event ){
4952 _this.hanldeReciveMsg( event )
50 - });
 53+ }, this.iframeServer);
5154 },
 55+ 'addIframeFullscreenBinding': function(){
 56+ var _this = this;
 57+ parentsAbsoluteList = [];
 58+ var fullscreenMode = false;
 59+ var orgSize = {
 60+ 'width' : $j( _this.iframe ).width(),
 61+ 'height' : $j( _this.iframe ).height(),
 62+ 'position' : null
 63+ }
 64+
 65+ var doFullscreen = function(){
 66+ // Make the iframe fullscreen
 67+ $j( _this.iframe ).css({
 68+ 'z-index': mw.getConfig( 'EmbedPlayer.fullScreenZIndex' ) + 1,
 69+ 'position': 'absolute',
 70+ 'top' : 0,
 71+ 'left' : 0,
 72+ 'width' : $j(window).width(),
 73+ 'height' : $j(window).height()
 74+ })
 75+
 76+ // Remove absolute css of the interface parents
 77+ $j( _this.iframe ).parents().each( function() {
 78+ //mw.log(' parent : ' + $j( this ).attr('id' ) + ' class: ' + $j( this ).attr('class') + ' pos: ' + $j( this ).css( 'position' ) );
 79+ if( $j( this ).css( 'position' ) == 'absolute' ) {
 80+ parentsAbsoluteList.push( $j( this ) );
 81+ $j( this ).css( 'position', null );
 82+ }
 83+ } );
 84+ }
 85+ var restoreWindowMode = function(){
 86+ $j( _this.iframe ).css( orgSize );
 87+ // restore any parent absolute pos:
 88+ $j(parentsAbsoluteList).each( function() {
 89+ $j( this ).css( 'position', 'absolute' );
 90+ } );
 91+ };
 92+
 93+ $j( this.playerProxy ).bind( 'onOpenFullScreen', doFullscreen);
 94+ $j( this.playerProxy ).bind( 'onCloseFullScreen', restoreWindowMode);
 95+
 96+ },
5297 /**
5398 * Handle received events
5499 */
55100 'hanldeReciveMsg': function( event ){
56 - var _this = this;
57 - // Confirm the event is coming for the target host:
58 - if( event.origin != this.iframeServer){
59 - mw.log("Skip msg from host does not match iFrame player: " + event.origin +
60 - ' != iframe Server: ' + this.iframeServer )
61 - return ;
62 - };
 101+ var _this = this;
 102+
63103 // Decode the message
64104 var msgObject = JSON.parse( event.data );
65 - //mw.log("IframePlayerApiClient:: hanldeReciveMsg: " + msgObject.triggerName );
66 -
67 -
68105 var playerAttributes = mw.getConfig( 'EmbedPlayer.Attributes' );
69 -
 106+
70107 // Before we update local attributes check that the object has not been updated by user js
71108 for( var attrName in playerAttributes ){
72109 if( attrName != 'id' ){
73110 if( _this._prevPlayerProxy[ attrName ] != _this.playerProxy[ attrName ] ){
74 - mw.log( "IFramePlayerApiClient:: User js update:" + attrName + ' set to: ' + this.playerProxy[ attrName ] + ' != old: ' + _this._prevPlayerProxy[ attrName ] );
 111+ //mw.log( "IFramePlayerApiClient:: User js update:" + attrName + ' set to: ' + this.playerProxy[ attrName ] + ' != old: ' + _this._prevPlayerProxy[ attrName ] );
75112 // Send the updated attribute back to the iframe:
76113 _this.postMessage({
77114 'attrName' : attrName,
@@ -99,7 +136,9 @@
100137 }
101138 },
102139 'postMessage': function( msgObject ){
103 - //mw.log( "IFramePlayerApiClient:: postMessage(): " + JSON.stringify( msgObj ) );
 140+ /*mw.log( "IFramePlayerApiClient:: postMessage(): " + JSON.stringify( msgObject ) +
 141+ ' iframe: ' + this.iframe + ' cw:' + this.iframe.contentWindow +
 142+ ' src: ' + mw.absoluteUrl( $j( this.iframe ).attr('src') ) );*/
104143 $j.postMessage(
105144 JSON.stringify( msgObject ),
106145 mw.absoluteUrl( $j( this.iframe ).attr('src') ),
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/EmbedPlayer/EmbedPlayer.loader.js
@@ -0,0 +1,115 @@
 2+/**
 3+* EmbedPlayer loader
 4+*/
 5+( function( mw, $ ) {
 6+ /**
 7+ * Add a DOM ready check for player tags
 8+ *
 9+ * We use SetupInterface so other functions that depend on the interface can
 10+ * wait for the IntefacesReady event
 11+ */
 12+ $( mw ).bind( 'SetupInterface', function( event, callback ){
 13+
 14+ // Allow modules to do tag rewrites as well:
 15+ var doModuleTagRewrites = function(){
 16+ $(mw).triggerQueueCallback( 'LoadeRewritePlayerTags', callback );
 17+ }
 18+ // Check if we have tags to rewrite:
 19+ if( $( mw.getConfig( 'EmbedPlayer.RewriteTags' ) ).length ) {
 20+ var rewriteElementCount = 0;
 21+
 22+ // Rewrite the embedPlayer EmbedPlayer.RewriteTags :
 23+ $( mw.getConfig( 'EmbedPlayer.RewriteTags' ) )
 24+ .embedPlayer( doModuleTagRewrites );
 25+ } else {
 26+ doModuleTagRewrites();
 27+ }
 28+ });
 29+
 30+ /**
 31+ * Add the mwEmbed jQuery loader wrapper
 32+ */
 33+ $.fn.embedPlayer = function( readyCallback ){
 34+ var _this = this;
 35+
 36+ if( this.selector ){
 37+ var playerSelect = this.selector;
 38+ } else {
 39+ var playerSelect = this;
 40+ }
 41+
 42+ // Hide videonojs class
 43+ $( '.videonojs' ).hide();
 44+
 45+ if()
 46+
 47+ // Set up the embed video player class request: (include the skin js as well)
 48+ var dependencySet = [
 49+ 'mw.EmbedPlayer'
 50+ ];
 51+
 52+ // Add PNG fix code needed:
 53+ if ( $.browser.msie && $.browser.version < 7 ) {
 54+ dependencySet.push( 'jquery.pngFix' );
 55+ }
 56+
 57+ // Guess at playback system for 90+% of users the browser indicates playback mode:
 58+ // NOTE: this does not affect a given playback library being loaded on-demand later.
 59+ if( ( $.browser.msie && $.browser.version < 9 ) || $.browser.safari ) {
 60+ dependencySet.push( 'mw.EmbedPlayerJava' );
 61+ }
 62+ // If video tag is supported add native lib:
 63+ if( document.createElement('video').canPlayType && !$.browser.safari) {
 64+ dependencySet.push( 'mw.EmbedPlayerNative' )
 65+ }
 66+
 67+
 68+ // Check if the iFrame player api is enabled and we have a parent iframe url:
 69+ // TODO we might want to move the iframe api to a separate module
 70+ if ( mw.getConfig('EmbedPlayer.EnableIframeApi')
 71+ &&
 72+ mw.getConfig( 'EmbedPlayer.IframeParentUrl' )
 73+ ){
 74+ dependencySet.push('mw.EmbedPlayerNative');
 75+ dependencySet.push('$.postMessage');
 76+ dependencySet.push('mw.IFramePlayerApiServer');
 77+ }
 78+
 79+ // Allow modules to update the set of dependencies:
 80+ var rewriteElementCount = 0;
 81+ $.each( playerSelect, function(inx, playerElement){
 82+
 83+ // Assign an the element an ID ( if its missing one )
 84+ if ( $( playerElement ).attr( "id" ) == '' ) {
 85+ $( playerElement ).attr( "id", 'v' + ( rewriteElementCount++ ) );
 86+ }
 87+
 88+ // Add an overlay loader
 89+ $( playerElement )
 90+ .getAbsoluteOverlaySpinner()
 91+ .attr('id', 'loadingSpinner_' + $( element ).attr('id') )
 92+ .addClass( 'playerLoadingSpinner' );
 93+
 94+ // Add core "skin/interface" loader
 95+ var skinString = $( playerElement ).attr( 'class' );
 96+ if( ! skinString || $.inArray( skinName.toLowerCase(), mw.validSkins ) == -1 ){
 97+ skinName = mw.getConfig( 'EmbedPlayer.DefaultSkin' );
 98+ }
 99+ skinName = skinName.toLowerCase();
 100+
 101+ // Add the skin to the request
 102+ var skinCaseName = skinName.charAt(0).toUpperCase() + skinName.substr(1);
 103+ dependencySet.push( 'mw.PlayerSkin' + skinCaseName );
 104+
 105+ // Allow other modules update the dependencies
 106+ $j( mw ).trigger( 'EmbedPlayerUpdateDependencies',
 107+ [ playerElement, dependencySet ] );
 108+ });
 109+
 110+ // Do the request and process the playerElements with updated dependency set
 111+ mediaWiki.loader.using( dependencySet, function(){
 112+ // EmbedPlayer should be ready:
 113+ });
 114+ };
 115+
 116+} )( mediaWiki, jQuery );
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/EmbedPlayer/mw.EmbedPlayerNative.js
@@ -199,7 +199,7 @@
200200 _this['on' + eventName ].apply( _this, argArray);
201201 } else {
202202 // No local handler directly propagate the event to the abstract object:
203 - $j( _this ).trigger( eventName, argArray )
 203+ $j( _this ).trigger( eventName, argArray );
204204 }
205205 }
206206 })
@@ -469,7 +469,6 @@
470470 * calls parent_play to update the interface
471471 */
472472 play: function( ) {
473 -
474473 this.getPlayerElement();
475474 this.parent_play(); // update interface
476475 if ( this.playerElement && this.playerElement.play ) {
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/EmbedPlayer/mw.EmbedPlayerKplayer.js
@@ -150,8 +150,8 @@
151151
152152 // Create an anonymous function with local player scope
153153 var createGlobalCB = function(cName, embedPlayer) {
154 - window[cName] = function(data) {
155 - if (embedPlayer._propagateEvents) {
 154+ window[ cName ] = function(data) {
 155+ if ( embedPlayer._propagateEvents ) {
156156 embedPlayer[methodName](data);
157157 }
158158 };
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/EmbedPlayer/mw.IFramePlayerApiServer.js
@@ -36,7 +36,9 @@
3737 // Exported bindings / events. ( all the native html5 events are added in 'init' )
3838 'exportedBindings': [
3939 'playerReady',
40 - 'monitorEvent'
 40+ 'monitorEvent',
 41+ 'onOpenFullScreen',
 42+ 'onCloseFullScreen'
4143 ],
4244
4345 'init': function( embedPlayer ){
@@ -54,34 +56,37 @@
5557 // Allow modules to extend the list of iframeExported bindings
5658 $j( mw ).trigger( 'AddIframePlayerBindings', [ this.exportedBindings ]);
5759
58 - this._addIframeListener();
59 - this._addIframeSender();
 60+ this.addIframeListener();
 61+ this.addIframeSender();
6062 $j( mw ).trigger( 'newIframePlayerServerSide', [embedPlayer]);
6163 },
6264
6365 /**
6466 * Listens to requested methods and triggers their action
6567 */
66 - '_addIframeListener': function(){
 68+ 'addIframeListener': function(){
6769 var _this = this;
6870 mw.log('IFramePlayerApiServer::_addIframeListener');
6971 $j.receiveMessage( function( event ) {
7072 _this.hanldeMsg( event );
71 - }, this.parentUrl );
 73+ }, this.getParentUrl() );
7274 },
73 -
 75+ getParentUrl: function(){
 76+ var purl = mw.getConfig( 'EmbedPlayer.IframeParentUrl' );
 77+ if(!purl){
 78+ mw.log("Error: iFramePlayerApiServer:: could not parse parent url. \n" +
 79+ "Player events will be dissabled");
 80+ }
 81+ return purl;
 82+ },
7483 /**
7584 * Add iframe sender bindings:
7685 */
77 - '_addIframeSender': function(){
 86+ 'addIframeSender': function(){
7887 var _this = this;
7988 // Get the parent page URL as it was passed in, for browsers that don't support
8089 // window.postMessage (this URL could be hard-coded).
81 - this.parentUrl = mw.getConfig( 'EmbedPlayer.IframeParentUrl' );
82 - if(!this.parentUrl){
83 - mw.log("Error: iFramePlayerApiServer:: could not parse parent url. \n" +
84 - "Player events will be dissabled");
85 - }
 90+
8691 // Set the initial attributes once player is "ready"
8792 $j( this.embedPlayer ).bind( 'playerReady', function(){
8893 _this.sendPlayerAttributes();
@@ -130,17 +135,17 @@
131136 } )
132137 },
133138
134 - 'postMessage': function( msgObj ){
 139+ 'postMessage': function( msgObject ){
135140 try {
136 - var messageString = JSON.stringify( msgObj );
 141+ var messageString = JSON.stringify( msgObject );
137142 } catch ( e ){
138 - mw.log("Error: could not JSON object: " + msgObj + ' ' + e);
 143+ mw.log("Error: could not JSON object: " + msgObject + ' ' + e);
139144 return ;
140 - }
 145+ }
141146 // By default postMessage sends the message to the parent frame:
142147 $j.postMessage(
143148 messageString,
144 - this.parentUrl,
 149+ this.getParentUrl(),
145150 window.parent
146151 );
147152 },
@@ -151,7 +156,7 @@
152157 * @param {string} event
153158 */
154159 'hanldeMsg': function( event ){
155 - //mw.log( 'IFramePlayerApiServer:: hanldeMsg ');
 160+ mw.log( 'IFramePlayerApiServer:: hanldeMsg: ' + event.data );
156161 // Check if the server should even be enabled
157162 if( !mw.getConfig( 'EmbedPlayer.EnableIframeApi' )){
158163 mw.log( 'Error: Loading iFrame playerApi but config EmbedPlayer.EnableIframeApi is false');
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/Sequencer/loader.js
@@ -126,7 +126,7 @@
127127 });
128128
129129 // If doing player overlays include remote for player hooks
130 - $j( mw ).bind( 'LoaderEmbedPlayerUpdateRequest', function( event, playerElement, classRequest ) {
 130+ $j( mw ).bind( 'EmbedPlayerUpdateDependencies', function( event, playerElement, classRequest ) {
131131 if( mw.getConfig( 'Sequencer.KalturaPlayerEditOverlay' )){
132132 if( $j.inArray( 'mw.MediaWikiRemoteSequencer', classRequest ) == -1 ) {
133133 classRequest.push('mw.MediaWikiRemoteSequencer');
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/MwEmbedSupport/jquery/README
@@ -0,0 +1 @@
 2+jQuery plugin resources specific to mwEmbed, can gradually be moved into mediaWiki/resources/jquery
\ No newline at end of file
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/MwEmbedSupport/jquery/jquery.triggerQueueCallback.js
@@ -0,0 +1,72 @@
 2+/**
 3+ * Runs all the triggers on all the named bindings of an object with
 4+ * a single callback
 5+ *
 6+ * NOTE THIS REQUIRES JQUERY 1.4.2 and above
 7+ *
 8+ * Normal jQuery tirgger calls will run the callback directly
 9+ * multiple times for every binded function.
 10+ *
 11+ * With triggerQueueCallback() callback is not called until all the
 12+ * binded events have been run.
 13+ *
 14+ * @param {string}
 15+ * triggerName Name of trigger to be run
 16+ * @param {object=}
 17+ * arguments Optional arguments object to be passed to
 18+ * the callback
 19+ * @param {function}
 20+ * callback Function called once all triggers have been
 21+ * run
 22+ *
 23+ */
 24+( function( $ ) {
 25+ $.fn.triggerQueueCallback = function( triggerName, triggerParam, callback ){
 26+ var targetObject = this;
 27+ // Support optional triggerParam data
 28+ if( !callback && typeof triggerParam == 'function' ){
 29+ callback = triggerParam;
 30+ triggerParam = null;
 31+ }
 32+ // Support namespaced event segmentation ( jQuery
 33+ var triggerBaseName = triggerName.split(".")[0];
 34+ var triggerNamespace = triggerName.split(".")[1];
 35+ // Get the callback set
 36+ var callbackSet = [];
 37+ if( ! triggerNamespace ){
 38+ callbackSet = $j( targetObject ).data( 'events' )[ triggerBaseName ];
 39+ } else{
 40+ $j.each( $j( targetObject ).data( 'events' )[ triggerBaseName ], function( inx, bindObject ){
 41+ if( bindObject.namespace == triggerNamespace ){
 42+ callbackSet.push( bindObject );
 43+ }
 44+ });
 45+ }
 46+
 47+ if( !callbackSet || callbackSet.length === 0 ){
 48+ mw.log( '"mwEmbed::jQuery.triggerQueueCallback: No events run the callback directly: ' + triggerName );
 49+ // No events run the callback directly
 50+ callback();
 51+ return ;
 52+ }
 53+
 54+ // Set the callbackCount
 55+ var callbackCount = ( callbackSet.length )? callbackSet.length : 1;
 56+ // mw.log("mwEmbed::jQuery.triggerQueueCallback: " + triggerName
 57+ // + ' number of queued functions:' + callbackCount );
 58+ var callInx = 0;
 59+ var doCallbackCheck = function() {
 60+ // mw.log( 'callback for: ' + mw.getCallStack()[0] +
 61+ // callInx);
 62+ callInx++;
 63+ if( callInx == callbackCount ){
 64+ callback();
 65+ }
 66+ };
 67+ if( triggerParam ){
 68+ $( this ).trigger( triggerName, [ triggerParam, doCallbackCheck ]);
 69+ } else {
 70+ $( this ).trigger( triggerName, [ doCallbackCheck ] );
 71+ }
 72+ };
 73+} )( window.mw );
\ No newline at end of file
Property changes on: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/MwEmbedSupport/jquery/jquery.triggerQueueCallback.js
___________________________________________________________________
Added: svn:mime-type
174 + text/plain
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/MwEmbedSupport/MwEmbedSupport.i18n.php
@@ -0,0 +1,737 @@
 2+<?php
 3+/**
 4+ * Localization file for mwEmbedSupport
 5+ */
 6+
 7+$messages = array();
 8+
 9+$messages['en'] = array(
 10+ 'mwe-loading_txt' => 'Loading ...',
 11+ 'mwe-size-gigabytes' => '$1 GB',
 12+ 'mwe-size-megabytes' => '$1 MB',
 13+ 'mwe-size-kilobytes' => '$1 K',
 14+ 'mwe-size-bytes' => '$1 B',
 15+ 'mwe-error_load_lib' => 'Error: JavaScript $1 was not retrievable or does not define $2',
 16+ 'mwe-apiproxy-setup' => 'Setting up API proxy',
 17+ 'mwe-load-drag-item' => 'Loading dragged item',
 18+ 'mwe-ok' => 'OK',
 19+ 'mwe-cancel' => 'Cancel',
 20+ 'mwe-enable-gadget' => 'Enable multimedia beta (mwEmbed) for all pages',
 21+ 'mwe-enable-gadget-done' => 'Multimedia beta gadget has been enabled',
 22+ 'mwe-must-login-gadget' => 'To enable gadget you must <a target="_new" href="$1">login</a>',
 23+ 'mwe-test-plural' => 'I ran {{PLURAL:$1|$1 test|$1 tests}}',
 24+);
 25+
 26+/** Message documentation (Message documentation)
 27+ * @author EugeneZelenko
 28+ * @author Fryed-peach
 29+ * @author Nike
 30+ */
 31+$messages['qqq'] = array(
 32+ 'mwe-loading_txt' => '{{Identical|Loading}}',
 33+ 'mwe-size-gigabytes' => 'Size (of a file, typically) in gibibytes (1 gibibyte = 1024×1024×1024 bytes).',
 34+ 'mwe-error_load_lib' => 'Parameters:
 35+* $1 Corresponds to the JavaScript file that was not retrievable or does not define its class name.
 36+* $2 Is the class name that was associated with the JavaScript file that was not found or could not be retrieved.',
 37+ 'mwe-ok' => '{{Identical|OK}}',
 38+ 'mwe-cancel' => '{{Identical|Cancel}}',
 39+);
 40+
 41+/** Afrikaans (Afrikaans)
 42+ * @author Naudefj
 43+ */
 44+$messages['af'] = array(
 45+ 'mwe-loading_txt' => 'laai ...',
 46+ 'mwe-error_load_lib' => 'Fout: JavaScript $1 kon nie gevind word of definieer nie $2 nie',
 47+ 'mwe-ok' => 'OK',
 48+ 'mwe-cancel' => 'Kanselleer',
 49+);
 50+
 51+/** Gheg Albanian (Gegë)
 52+ * @author Mdupont
 53+ */
 54+$messages['aln'] = array(
 55+ 'mwe-loading_txt' => 'Loading ...',
 56+ 'mwe-error_load_lib' => 'Gabim: $1 JavaScript nuk ishte shikohen ose nuk define $2',
 57+ 'mwe-apiproxy-setup' => 'Ngritja proxy API',
 58+ 'mwe-load-drag-item' => 'Loading zvarritur artikull',
 59+ 'mwe-ok' => 'Në rregull',
 60+ 'mwe-cancel' => 'Anuloj',
 61+ 'mwe-enable-gadget' => 'Aktivizo multimedial beta (mwEmbed) për të gjitha faqet',
 62+ 'mwe-enable-gadget-done' => 'Multimedia beta vegël ka qenë i aktivizuar',
 63+);
 64+
 65+/** Aragonese (Aragonés)
 66+ * @author Juanpabl
 67+ */
 68+$messages['an'] = array(
 69+ 'mwe-cancel' => 'Cancelar',
 70+);
 71+
 72+/** Arabic (العربية)
 73+ * @author OsamaK
 74+ */
 75+$messages['ar'] = array(
 76+ 'mwe-loading_txt' => 'يحمل...',
 77+ 'mwe-cancel' => 'ألغِ',
 78+);
 79+
 80+/** Belarusian (Taraškievica orthography) (Беларуская (тарашкевіца))
 81+ * @author EugeneZelenko
 82+ * @author Jim-by
 83+ */
 84+$messages['be-tarask'] = array(
 85+ 'mwe-loading_txt' => 'загрузка …',
 86+ 'mwe-error_load_lib' => 'Памылка: JavaScript $1 не даступны альбо не вызначае $2',
 87+ 'mwe-apiproxy-setup' => 'Устаноўка API-проксі',
 88+ 'mwe-load-drag-item' => 'Загрузка перанесенага элемэнту',
 89+ 'mwe-ok' => 'Добра',
 90+ 'mwe-cancel' => 'Адмяніць',
 91+ 'mwe-enable-gadget' => 'Уключыць бэта-мультымэдыя (mwEmbed) для ўсіх старонак',
 92+ 'mwe-enable-gadget-done' => 'Дапаўненьне бэта-мультымэтыя ўключанае',
 93+ 'mwe-must-login-gadget' => 'Для ўключэньня дапаўненьня Вам неабходна <a target="_new" href="$1">ўвайсьці ў сыстэму</a>',
 94+ 'mwe-test-plural' => 'Я прайшоў $1 {{PLURAL:$1|тэст|тэсты|тэстаў}}',
 95+);
 96+
 97+/** Breton (Brezhoneg)
 98+ * @author Fohanno
 99+ * @author Fulup
 100+ * @author Y-M D
 101+ */
 102+$messages['br'] = array(
 103+ 'mwe-loading_txt' => 'o kargañ...',
 104+ 'mwe-error_load_lib' => "Fazi : n'eo ket bet kavet JavaScript $1 pe n'eo ket termenet gant $2",
 105+ 'mwe-apiproxy-setup' => 'Kefluniadur ar proksi API',
 106+ 'mwe-load-drag-item' => 'O kargañ an elfenn digargañ',
 107+ 'mwe-ok' => 'Mat eo',
 108+ 'mwe-cancel' => 'Nullañ',
 109+ 'mwe-enable-gadget' => 'Gweredekaat liesvedia beta (mwEmbed) war an holl bajennoù',
 110+ 'mwe-enable-gadget-done' => 'Gweredekaet eo bet ar gadjet liesvedia beta',
 111+ 'mwe-must-login-gadget' => 'Evit gweredekaat ar gadjet e rankit <a target="_new" href="$1">kevreañ</a>',
 112+ 'mwe-test-plural' => 'Sevenet em eus $1 amprouadenn{{PLURAL:$1||}}',
 113+);
 114+
 115+/** Bosnian (Bosanski)
 116+ * @author CERminator
 117+ */
 118+$messages['bs'] = array(
 119+ 'mwe-loading_txt' => 'učitavam ...',
 120+ 'mwe-apiproxy-setup' => 'Postavljanje API proksija',
 121+ 'mwe-ok' => 'U redu',
 122+ 'mwe-cancel' => 'Odustani',
 123+);
 124+
 125+/** Czech (Česky)
 126+ * @author Mormegil
 127+ */
 128+$messages['cs'] = array(
 129+ 'mwe-loading_txt' => 'Načítá se …',
 130+ 'mwe-cancel' => 'Storno',
 131+);
 132+
 133+/** Welsh (Cymraeg) */
 134+$messages['cy'] = array(
 135+ 'mwe-loading_txt' => "wrthi'n llwytho ...",
 136+);
 137+
 138+/** German (Deutsch)
 139+ * @author Kghbln
 140+ * @author Metalhead64
 141+ */
 142+$messages['de'] = array(
 143+ 'mwe-loading_txt' => 'lade …',
 144+ 'mwe-error_load_lib' => 'Fehler: JavaScript $1 war nicht abrufbar oder lässt $2 nicht zu',
 145+ 'mwe-apiproxy-setup' => 'API-Proxy-Konfiguration',
 146+ 'mwe-load-drag-item' => 'Lade eingebettetes Element',
 147+ 'mwe-ok' => 'OK',
 148+ 'mwe-cancel' => 'Abbrechen',
 149+ 'mwe-enable-gadget' => 'Aktiviere die Beta-Version des Multimedia-Helferleins (mwEmbed) für alle Seiten',
 150+ 'mwe-enable-gadget-done' => 'Beta-Version des Multimedia-Helferleins wurde aktiviert',
 151+ 'mwe-must-login-gadget' => 'Um das Helferlein aktivieren zu können, musst du dich <a target="_new" href="$1">anmelden</a>',
 152+ 'mwe-test-plural' => '{{PLURAL:$1|$1 Test|$1 Tests}} durchlaufen',
 153+);
 154+
 155+/** Zazaki (Zazaki)
 156+ * @author Aspar
 157+ */
 158+$messages['diq'] = array(
 159+ 'mwe-loading_txt' => 'bar beno...',
 160+ 'mwe-error_load_lib' => 'xeta: $1 JavaScript re nêresiyeno ya zi pê $2yi şınasnaye niyo.',
 161+ 'mwe-apiproxy-setup' => 'proxyê APIyi eyar beno',
 162+ 'mwe-load-drag-item' => 'unsur bar beno',
 163+ 'mwe-ok' => 'temam',
 164+ 'mwe-cancel' => 'iptal',
 165+);
 166+
 167+/** Lower Sorbian (Dolnoserbski)
 168+ * @author Michawiki
 169+ */
 170+$messages['dsb'] = array(
 171+ 'mwe-loading_txt' => 'zacytujo se ...',
 172+ 'mwe-error_load_lib' => 'Zmólka: JavaScript $1 njejo wótwołujobny był abo njedefiněrujo $2',
 173+ 'mwe-apiproxy-setup' => 'Proksy API zarědowaś',
 174+ 'mwe-load-drag-item' => 'Wlecony zapisk se zacytujo',
 175+ 'mwe-ok' => 'W pórědku',
 176+ 'mwe-cancel' => 'Pśetergnuś',
 177+ 'mwe-enable-gadget' => 'Multimedia beta (mwEmbed) za wšykne boki zmóžniś',
 178+ 'mwe-enable-gadget-done' => 'Pśisłušk Multimedia beta jo se zmóžnił',
 179+ 'mwe-must-login-gadget' => 'Aby pśisłušk zmóžnił, musyš se <a target="_new" href="$1">pśizjawiś</a>',
 180+ 'mwe-test-plural' => 'Som {{PLURAL:$1|$1 test|$1 testa|$1 testy|$1 testow}} pśewjadł',
 181+);
 182+
 183+/** Greek (Ελληνικά)
 184+ * @author Crazymadlover
 185+ */
 186+$messages['el'] = array(
 187+ 'mwe-loading_txt' => 'φόρτωση ...',
 188+ 'mwe-cancel' => 'Ακύρωση',
 189+);
 190+
 191+/** Esperanto (Esperanto)
 192+ * @author Yekrats
 193+ */
 194+$messages['eo'] = array(
 195+ 'mwe-loading_txt' => 'ŝarĝante ...',
 196+ 'mwe-cancel' => 'Nuligi',
 197+);
 198+
 199+/** Spanish (Español)
 200+ * @author Translationista
 201+ */
 202+$messages['es'] = array(
 203+ 'mwe-loading_txt' => 'cargando ...',
 204+ 'mwe-error_load_lib' => 'Error: JavaScript $1 no ha podido ser recuperado o no define $2',
 205+ 'mwe-apiproxy-setup' => 'Configurando proxi de la API',
 206+ 'mwe-load-drag-item' => 'Cargando el objeto arrastrado',
 207+ 'mwe-ok' => 'OK',
 208+ 'mwe-cancel' => 'Cancelar',
 209+ 'mwe-enable-gadget' => 'Habilitar multimedia beta (mwEmbed) en todas las páginas',
 210+ 'mwe-enable-gadget-done' => 'Se ha habilitado el gadget multimedia beta',
 211+ 'mwe-must-login-gadget' => 'Para habilitar el gadget debes <a target="_new" href="$1">ingresar</a>',
 212+ 'mwe-test-plural' => 'Realicé {{PLURAL:$1|$1 prueba|$1 pruebas}}',
 213+);
 214+
 215+/** Basque (Euskara)
 216+ * @author An13sa
 217+ */
 218+$messages['eu'] = array(
 219+ 'mwe-loading_txt' => 'Kargatzen ...',
 220+ 'mwe-ok' => 'Ados',
 221+ 'mwe-cancel' => 'Ezeztatu',
 222+);
 223+
 224+/** Finnish (Suomi)
 225+ * @author Crt
 226+ * @author Str4nd
 227+ */
 228+$messages['fi'] = array(
 229+ 'mwe-loading_txt' => 'Ladataan...',
 230+ 'mwe-error_load_lib' => 'Virhe: JavaScript $1 ei ollut haettavissa tai se ei määrittele luokkaa $2',
 231+ 'mwe-apiproxy-setup' => 'Pystytetään API-välityspalvelinta',
 232+ 'mwe-ok' => 'OK',
 233+ 'mwe-cancel' => 'Peruuta',
 234+ 'mwe-must-login-gadget' => 'Sinun tulee <a target="_new" href="$1">kirjautua sisään</a>, jotta voisit käyttää pienoisohjelmaa',
 235+ 'mwe-test-plural' => 'Ajoin {{PLURAL:$1|$1 testin|$1 testiä}}',
 236+);
 237+
 238+/** French (Français)
 239+ * @author IAlex
 240+ * @author Jean-Frédéric
 241+ * @author PieRRoMaN
 242+ */
 243+$messages['fr'] = array(
 244+ 'mwe-loading_txt' => 'chargement ...',
 245+ 'mwe-error_load_lib' => "Erreur : JavaScript $1 n'a pas pu être trouvé ou ne définit pas $2",
 246+ 'mwe-apiproxy-setup' => 'Configuration du proxy API',
 247+ 'mwe-load-drag-item' => 'Chargement de l’élément dépose',
 248+ 'mwe-ok' => 'OK',
 249+ 'mwe-cancel' => 'Annuler',
 250+ 'mwe-enable-gadget' => 'Activer beta multimédia (mwEmbed) sur toutes les pages',
 251+ 'mwe-enable-gadget-done' => 'Le gadget multimédia beta a été activé',
 252+ 'mwe-must-login-gadget' => 'Afin d\'activer le gadget vous devez vous <a target="_new" href="$1">connecter</a>',
 253+ 'mwe-test-plural' => "J'ai exécuté {{PLURAL:$1|$1 test|$1 tests}}",
 254+);
 255+
 256+/** Galician (Galego)
 257+ * @author Toliño
 258+ */
 259+$messages['gl'] = array(
 260+ 'mwe-loading_txt' => 'cargando...',
 261+ 'mwe-error_load_lib' => 'Erro: o JavaScript $1 non se puido atopar ou non definía $2',
 262+ 'mwe-apiproxy-setup' => 'Configurando o proxy API',
 263+ 'mwe-load-drag-item' => 'Cargando o elemento arrastrado',
 264+ 'mwe-ok' => 'De acordo',
 265+ 'mwe-cancel' => 'Cancelar',
 266+ 'mwe-enable-gadget' => 'Activar a beta multimedia (mwEmbed) en todas as páxinas',
 267+ 'mwe-enable-gadget-done' => 'Activouse o trebello beta multimedia',
 268+ 'mwe-must-login-gadget' => 'Para activar o trebello ten que <a target="_new" href="$1">acceder ao sistema</a>',
 269+ 'mwe-test-plural' => '{{PLURAL:$1|Fíxose unha proba|Fixéronse $1 probas}}',
 270+);
 271+
 272+/** Swiss German (Alemannisch)
 273+ * @author Als-Holder
 274+ */
 275+$messages['gsw'] = array(
 276+ 'mwe-loading_txt' => 'Am Lade ...',
 277+ 'mwe-error_load_lib' => 'Fähler: s JavaScript $1 het nit chenne glade wäre oder s losst $2 nit zue',
 278+ 'mwe-apiproxy-setup' => 'API-Proxy-Konfiguration',
 279+ 'mwe-load-drag-item' => 'Am Lade vu mitgschleipfte Poschte',
 280+ 'mwe-ok' => 'OK',
 281+ 'mwe-cancel' => 'Abbräche',
 282+ 'mwe-enable-gadget' => 'D Beta-Version vum Multimedia-Heälferli (mwEmbed) fir alli Syte aktiviere',
 283+ 'mwe-enable-gadget-done' => 'Beta-Version vum Multimedia-Hälferli isch aktiviert wore',
 284+ 'mwe-must-login-gadget' => 'Go s Hälferli aktiviere chenne, muesch di <a target="_new" href="$1">aamälde</a>',
 285+ 'mwe-test-plural' => '{{PLURAL:$1|$1 Tescht|$1 Tescht}} uusgfiert',
 286+);
 287+
 288+/** Hausa (هَوُسَ) */
 289+$messages['ha'] = array(
 290+ 'mwe-cancel' => 'Soke',
 291+);
 292+
 293+/** Hebrew (עברית)
 294+ * @author Rotemliss
 295+ */
 296+$messages['he'] = array(
 297+ 'mwe-loading_txt' => 'בטעינה ...',
 298+ 'mwe-error_load_lib' => 'שגיאה: לא ניתן היה לטעון את ספריית ה־JavaScript בשם $1 או שהיא אינה מגדירה את $2',
 299+);
 300+
 301+/** Upper Sorbian (Hornjoserbsce)
 302+ * @author Michawiki
 303+ */
 304+$messages['hsb'] = array(
 305+ 'mwe-loading_txt' => 'začituje so ...',
 306+ 'mwe-size-gigabytes' => '$1 GB',
 307+ 'mwe-size-megabytes' => '$1 MB',
 308+ 'mwe-size-kilobytes' => '$1 KB',
 309+ 'mwe-size-bytes' => '$1 B',
 310+ 'mwe-error_load_lib' => 'Zmylk: JavaScript $1 njeda so wotwołać abo njedefinuje $2',
 311+ 'mwe-apiproxy-setup' => 'Proksy API zarjadować',
 312+ 'mwe-load-drag-item' => 'Wlečeny zapisk so začituje',
 313+ 'mwe-ok' => 'W porjadku',
 314+ 'mwe-cancel' => 'Přetorhnyć',
 315+ 'mwe-enable-gadget' => 'Multimedia beta (mwEmbed) za wšě strony zmóžnić',
 316+ 'mwe-enable-gadget-done' => 'Přisłušk za Multimedia beta je so zmóžnił',
 317+ 'mwe-must-login-gadget' => 'Zo by přisłušk zmóžnił, dyrbiš so <a target="_new" href="$1">přizjewić</a>',
 318+ 'mwe-test-plural' => 'Sym {{PLURAL:$1|$1 test|$1 testaj|testy|testow}} přewjedł',
 319+);
 320+
 321+/** Hungarian (Magyar)
 322+ * @author Dani
 323+ * @author Glanthor Reviol
 324+ */
 325+$messages['hu'] = array(
 326+ 'mwe-loading_txt' => 'betöltés…',
 327+ 'mwe-error_load_lib' => 'Hiba: a(z) $1 JavaScript-fájl nem elérhető, vagy nem definiálja a(z) $2 osztályt.',
 328+ 'mwe-apiproxy-setup' => 'API proxy beállítása',
 329+ 'mwe-load-drag-item' => 'Vonszolt elem betöltése',
 330+ 'mwe-ok' => 'OK',
 331+ 'mwe-cancel' => 'Mégse',
 332+ 'mwe-enable-gadget' => 'A multimédia béta (mwEmbed) engedélyezése az összes lapon',
 333+ 'mwe-enable-gadget-done' => 'A multimédia béta segédeszköz engedélyezve',
 334+ 'mwe-must-login-gadget' => 'Hogy engedélyezni tudd a segédeszközt, <a target="_new" href="$1">be kell jelentkezned</a>',
 335+ 'mwe-test-plural' => '$1 tesztet futtattam',
 336+);
 337+
 338+/** Interlingua (Interlingua)
 339+ * @author McDutchie
 340+ */
 341+$messages['ia'] = array(
 342+ 'mwe-loading_txt' => 'cargamento ...',
 343+ 'mwe-error_load_lib' => 'Error: JavaScript $1 non esseva recuperabile o non defini $2',
 344+ 'mwe-apiproxy-setup' => 'Configuration del proxy pro le API',
 345+ 'mwe-load-drag-item' => 'Cargamento del file trahite',
 346+ 'mwe-ok' => 'OK',
 347+ 'mwe-cancel' => 'Cancella',
 348+ 'mwe-enable-gadget' => 'Activar beta multimedia (mwEmbed) pro tote le paginas',
 349+ 'mwe-enable-gadget-done' => 'Le gadget beta multimedia ha essite activate',
 350+ 'mwe-must-login-gadget' => 'Pro activar le gadget tu debe <a target="_new" href="$1">aperir un session</a>',
 351+ 'mwe-test-plural' => 'Io ha executate {{PLURAL:$1|$1 test|$1 tests}}',
 352+);
 353+
 354+/** Indonesian (Bahasa Indonesia)
 355+ * @author Farras
 356+ * @author Irwangatot
 357+ * @author IvanLanin
 358+ */
 359+$messages['id'] = array(
 360+ 'mwe-loading_txt' => 'memuat...',
 361+ 'mwe-error_load_lib' => 'Kesalahan: JavaScript $1 tidak dapat diambil atau tidak mendefinisikan $2',
 362+ 'mwe-apiproxy-setup' => 'Menyiapkan proksi API',
 363+ 'mwe-load-drag-item' => 'Memuat butir terseret',
 364+ 'mwe-ok' => 'Oke',
 365+ 'mwe-cancel' => 'Batalkan',
 366+ 'mwe-enable-gadget' => 'Aktifkan beta multimedia (mwEmbed) untuk semua halaman',
 367+ 'mwe-enable-gadget-done' => 'Gadget beta multimedia telah diaktifkan',
 368+ 'mwe-must-login-gadget' => 'Untuk mengaktifkan gadget Anda harus <a target="_new" href="$1">masuk log</a>',
 369+ 'mwe-test-plural' => 'Saya menjalankan {{PLURAL:$1|$1 tes|$1 tes}}',
 370+);
 371+
 372+/** Igbo (Igbo) */
 373+$messages['ig'] = array(
 374+ 'mwe-ok' => 'Ngwanu',
 375+ 'mwe-cancel' => 'Emekwàlà',
 376+);
 377+
 378+/** Italian (Italiano)
 379+ * @author Gianfranco
 380+ */
 381+$messages['it'] = array(
 382+ 'mwe-cancel' => 'Annulla',
 383+);
 384+
 385+/** Japanese (日本語)
 386+ * @author Fryed-peach
 387+ * @author 青子守歌
 388+ */
 389+$messages['ja'] = array(
 390+ 'mwe-loading_txt' => '読み込み中 …',
 391+ 'mwe-error_load_lib' => 'エラー:JavaScript $1 は参照不能か、$2 を定義していません。',
 392+ 'mwe-apiproxy-setup' => 'API プロキシーをセットアップ中',
 393+ 'mwe-load-drag-item' => 'ドラッグされた項目を読み込み中',
 394+ 'mwe-ok' => 'OK',
 395+ 'mwe-cancel' => '中止',
 396+ 'mwe-enable-gadget' => 'マルチメディアベータ(mwEmbed)を全ページで有効化',
 397+ 'mwe-enable-gadget-done' => 'マルチメディアベータのガジェットが有効です',
 398+ 'mwe-must-login-gadget' => 'ガジェットを有効にするには<a target="_new" href="$1">ログイン</a>が必要です',
 399+ 'mwe-test-plural' => '{{PLURAL:$1|$1のテスト}}を実行する',
 400+);
 401+
 402+/** Korean (한국어)
 403+ * @author Kwj2772
 404+ */
 405+$messages['ko'] = array(
 406+ 'mwe-loading_txt' => '불러오는 중...',
 407+ 'mwe-cancel' => '취소',
 408+);
 409+
 410+/** Colognian (Ripoarisch)
 411+ * @author Purodha
 412+ */
 413+$messages['ksh'] = array(
 414+ 'mwe-loading_txt' => 'aam Laade …',
 415+ 'mwe-size-gigabytes' => '$1&nbsp;GB',
 416+ 'mwe-size-megabytes' => '$1&nbsp;MB',
 417+ 'mwe-size-kilobytes' => '$1&nbsp;KB',
 418+ 'mwe-size-bytes' => '$1&nbsp;Bytes',
 419+ 'mwe-error_load_lib' => 'Fähler: Dat JavaSkrep „<code lang="en">$1</code>“ wohr nit ze laade udder et leiht „<code lang="en">$2</code>“ nit faß.',
 420+ 'mwe-cancel' => 'Affbräsche',
 421+);
 422+
 423+/** Luxembourgish (Lëtzebuergesch)
 424+ * @author Robby
 425+ */
 426+$messages['lb'] = array(
 427+ 'mwe-loading_txt' => 'lueden ...',
 428+ 'mwe-error_load_lib' => 'Feeler: JavaScript $1 konnt net ofgeruf ginn oder definéiert $2 net',
 429+ 'mwe-apiproxy-setup' => 'API-Proxy astellen',
 430+ 'mwe-load-drag-item' => 'Den agebonnen Objet gëtt gelueden',
 431+ 'mwe-ok' => 'OK',
 432+ 'mwe-cancel' => 'Ofbriechen',
 433+ 'mwe-enable-gadget' => 'Multimedia-Beta-Gadget (mwEmbed) fir all Säiten aktivéieren',
 434+ 'mwe-enable-gadget-done' => 'De Multimedia-Beta-Gadget gouf aktivéiert',
 435+ 'mwe-must-login-gadget' => 'Fir de Gadget aktivéieren ze kënne musst Dir Iech <a target="_new" href="$1">aloggen</a>',
 436+ 'mwe-test-plural' => 'Ech hunn {{PLURAL:$1|$1 Test|$1 Tester}} gemaach',
 437+);
 438+
 439+/** Macedonian (Македонски)
 440+ * @author Bjankuloski06
 441+ */
 442+$messages['mk'] = array(
 443+ 'mwe-loading_txt' => 'Вчитувам...',
 444+ 'mwe-error_load_lib' => 'Грешка: JavaScript $1 не е достапен или не определува $2',
 445+ 'mwe-apiproxy-setup' => 'Поставувам API застапник (proxy)',
 446+ 'mwe-load-drag-item' => 'Го вчитувам повлечениот елемент',
 447+ 'mwe-ok' => 'ОК',
 448+ 'mwe-cancel' => 'Откажи',
 449+ 'mwe-enable-gadget' => 'Овозможи бета-мултимедија (mwEmbed) за сите страници',
 450+ 'mwe-enable-gadget-done' => 'Овозможена е алатката за бета-мултимедија',
 451+ 'mwe-must-login-gadget' => 'За да ја овозможите алатката морате да се <a target="_new" href="$1">најавите</a>',
 452+ 'mwe-test-plural' => 'Направив {{PLURAL:$1|$1 проверка|$1 проверки}}',
 453+);
 454+
 455+/** Malayalam (മലയാളം)
 456+ * @author Praveenp
 457+ */
 458+$messages['ml'] = array(
 459+ 'mwe-loading_txt' => 'ശേഖരിക്കുന്നു ...',
 460+ 'mwe-error_load_lib' => 'പിശക്: ജാവാസ്ക്രിപ്റ്റ് $1 ശേഖരിക്കാൻ കഴിഞ്ഞില്ല അല്ലെങ്കിൽ $2 നിർവ്വചിച്ചിട്ടില്ല',
 461+ 'mwe-apiproxy-setup' => 'എ.പി.ഐ. പ്രോക്സി സജ്ജീകരിക്കുക',
 462+ 'mwe-load-drag-item' => 'വലിച്ചിട്ടത് ശേഖരിക്കുന്നു',
 463+ 'mwe-ok' => 'ശരി',
 464+ 'mwe-cancel' => 'റദ്ദാക്കുക',
 465+);
 466+
 467+/** Erzya (Эрзянь)
 468+ * @author Botuzhaleny-sodamo
 469+ */
 470+$messages['myv'] = array(
 471+ 'mwe-loading_txt' => 'Йовкстамозо моли…',
 472+);
 473+
 474+/** Dutch (Nederlands)
 475+ * @author Siebrand
 476+ */
 477+$messages['nl'] = array(
 478+ 'mwe-loading_txt' => 'bezig met laden ...',
 479+ 'mwe-error_load_lib' => 'Fout: JavaScript $1 kon niet opgehaald worden of definieert $2 niet',
 480+ 'mwe-apiproxy-setup' => 'Bezig met het opzetten van een API-proxy',
 481+ 'mwe-load-drag-item' => 'Bezig met het laden van het gesleepte bestand',
 482+ 'mwe-ok' => 'OK',
 483+ 'mwe-cancel' => 'Annuleren',
 484+ 'mwe-enable-gadget' => "Multimedia beta (mwEmbed) voor alle pagina's inschakelen",
 485+ 'mwe-enable-gadget-done' => 'Multimedia beta is ingeschakeld',
 486+ 'mwe-must-login-gadget' => 'Om de uitbreiding in te schakelen, moet u <a target="_new" href="$1">aanmelden</a>',
 487+ 'mwe-test-plural' => '{{PLURAL:$1|$1 test|$1 tests}} uitgevoerd',
 488+);
 489+
 490+/** Norwegian (bokmål)‬ (‪Norsk (bokmål)‬)
 491+ * @author Nghtwlkr
 492+ */
 493+$messages['no'] = array(
 494+ 'mwe-loading_txt' => 'Laster ...',
 495+ 'mwe-error_load_lib' => 'Feil: JavaScript $1 kunne ikke gjenhentes eller definerer ikke $2',
 496+ 'mwe-apiproxy-setup' => 'Setter opp API-mellomtjener',
 497+ 'mwe-load-drag-item' => 'Laster dratt element',
 498+ 'mwe-ok' => 'OK',
 499+ 'mwe-cancel' => 'Avbryt',
 500+ 'mwe-enable-gadget' => 'Aktiver multimedia-beta (mwEmbed) for alle sider',
 501+ 'mwe-enable-gadget-done' => 'Skjermelement for multimedia-beta har blitt aktivert',
 502+ 'mwe-must-login-gadget' => 'For å aktivere skjermelement må du <a target="_new" href="$1">logge inn</a>',
 503+ 'mwe-test-plural' => 'Jeg kjørte {{PLURAL:$1|én test|$1 tester}}',
 504+);
 505+
 506+/** Occitan (Occitan)
 507+ * @author Cedric31
 508+ */
 509+$messages['oc'] = array(
 510+ 'mwe-loading_txt' => 'cargament ...',
 511+ 'mwe-error_load_lib' => 'Error : JavaScript $1 a pas pogut èsser trobat o definís pas $2',
 512+ 'mwe-apiproxy-setup' => 'Configuracion del proxy API',
 513+ 'mwe-load-drag-item' => 'Cargament de l’element depausat',
 514+ 'mwe-ok' => 'OK',
 515+ 'mwe-cancel' => 'Anullar',
 516+);
 517+
 518+/** Deitsch (Deitsch)
 519+ * @author Xqt
 520+ */
 521+$messages['pdc'] = array(
 522+ 'mwe-ok' => 'OK',
 523+);
 524+
 525+/** Polish (Polski)
 526+ * @author Sp5uhe
 527+ */
 528+$messages['pl'] = array(
 529+ 'mwe-loading_txt' => 'ładowanie ...',
 530+ 'mwe-error_load_lib' => 'Błąd – W plik JavaScript $1 brak jest możliwości pobrania oraz definicji $2',
 531+ 'mwe-apiproxy-setup' => 'Konfiguracja proxy dla API',
 532+ 'mwe-load-drag-item' => 'Ładowanie przeciągniętego elementu',
 533+ 'mwe-ok' => 'OK',
 534+ 'mwe-cancel' => 'Anuluj',
 535+ 'mwe-enable-gadget' => 'Włącz wersję testową multimediów (wmEmbed) na wszystkich stronach',
 536+ 'mwe-enable-gadget-done' => 'Testowy gadżet multimediów został włączony',
 537+ 'mwe-must-login-gadget' => 'Gadżet można włączyć dopiero po <a target="_new" href="$1">zalogowaniu się</a>',
 538+ 'mwe-test-plural' => 'Wykonałem $1 {{PLURAL:$1|test|testy|testów}}',
 539+);
 540+
 541+/** Piedmontese (Piemontèis)
 542+ * @author Borichèt
 543+ * @author Dragonòt
 544+ */
 545+$messages['pms'] = array(
 546+ 'mwe-loading_txt' => 'A caria ...',
 547+ 'mwe-error_load_lib' => 'Eror: JavaScript $1 as peul pa trovesse o a definiss pa $2',
 548+ 'mwe-apiproxy-setup' => 'Amposté ël proxy API',
 549+ 'mwe-load-drag-item' => "carié l'element tirà",
 550+ 'mwe-ok' => 'Va bin',
 551+ 'mwe-cancel' => 'Scancela',
 552+ 'mwe-enable-gadget' => 'Abìlita la beta multimedia (mwEmbed) për tute le pàgine',
 553+ 'mwe-enable-gadget-done' => "L'acessòri beta multimedia a l'é stàit abilità",
 554+ 'mwe-must-login-gadget' => 'Për abilité l\'acessòri a dev <a target="_new" href="$1">intré ant ël sistema</a>',
 555+ 'mwe-test-plural' => "I l'heu fàit {{PLURAL:$1|$1 test|$1 test}}",
 556+);
 557+
 558+/** Pashto (پښتو)
 559+ * @author Ahmed-Najib-Biabani-Ibrahimkhel
 560+ */
 561+$messages['ps'] = array(
 562+ 'mwe-ok' => 'ښه',
 563+ 'mwe-cancel' => 'ناګارل',
 564+);
 565+
 566+/** Portuguese (Português)
 567+ * @author Hamilton Abreu
 568+ * @author Malafaya
 569+ */
 570+$messages['pt'] = array(
 571+ 'mwe-loading_txt' => 'A carregar ...',
 572+ 'mwe-error_load_lib' => 'Erro: O JavaScript $1 não pode ser importado ou não define $2',
 573+ 'mwe-apiproxy-setup' => "A preparar o ''proxy'' da API",
 574+ 'mwe-load-drag-item' => 'A carregar o objecto arrastado',
 575+ 'mwe-ok' => 'OK',
 576+ 'mwe-cancel' => 'Cancelar',
 577+ 'mwe-enable-gadget' => 'Activar multimédia beta (mwEmbed) para todas as páginas',
 578+ 'mwe-enable-gadget-done' => 'Gadget de multimédia beta foi activado',
 579+ 'mwe-must-login-gadget' => 'Para activar o gadget tem de estar <a target="_new" href="$1">autenticado</a>',
 580+ 'mwe-test-plural' => 'Fiz $1 {{PLURAL:$1|teste|testes}}',
 581+);
 582+
 583+/** Brazilian Portuguese (Português do Brasil)
 584+ * @author Giro720
 585+ * @author Luckas Blade
 586+ */
 587+$messages['pt-br'] = array(
 588+ 'mwe-loading_txt' => 'Carregando ...',
 589+ 'mwe-error_load_lib' => 'Erro: O JavaScript $1 não pode ser importado ou não define $2',
 590+ 'mwe-apiproxy-setup' => 'Configurando proxy da API',
 591+ 'mwe-load-drag-item' => 'Carregando o objeto arrastado',
 592+ 'mwe-ok' => 'OK',
 593+ 'mwe-cancel' => 'Cancelar',
 594+ 'mwe-enable-gadget' => 'Ativar multimídia beta beta (mwEmbed) para todas as páginas',
 595+ 'mwe-enable-gadget-done' => 'Gadget de multimídia beta foi ativado',
 596+ 'mwe-must-login-gadget' => 'Para ativar o gadget você deve estar <a target="_new" href="$1">autenticado</a>',
 597+ 'mwe-test-plural' => 'Eu fiz $1 {{PLURAL:$1|teste|testes}}',
 598+);
 599+
 600+/** Russian (Русский)
 601+ * @author Александр Сигачёв
 602+ */
 603+$messages['ru'] = array(
 604+ 'mwe-loading_txt' => 'загрузка …',
 605+ 'mwe-error_load_lib' => 'Ошибка. JavaScript $1 не доступен или не определяет $2',
 606+ 'mwe-apiproxy-setup' => 'Настройка API-прокси',
 607+ 'mwe-load-drag-item' => 'Загрузка перетащенного элемента',
 608+ 'mwe-ok' => 'OK',
 609+ 'mwe-cancel' => 'Отмена',
 610+ 'mwe-enable-gadget' => 'Включить бета-мультимедиа (mwEmbed) для всех страниц',
 611+ 'mwe-enable-gadget-done' => 'Включён гаджет бета-мультимедиа',
 612+ 'mwe-must-login-gadget' => 'Для включения гаджета вам следует <a target="_new" href="$1">представиться</a>.',
 613+ 'mwe-test-plural' => 'Я прошёл {{PLURAL:$1|$1 проверку|$1 проверки|$1 проверок}}',
 614+);
 615+
 616+/** Rusyn (Русиньскый)
 617+ * @author Gazeb
 618+ */
 619+$messages['rue'] = array(
 620+ 'mwe-ok' => 'ОК',
 621+ 'mwe-cancel' => 'Сторно',
 622+);
 623+
 624+/** Slovak (Slovenčina)
 625+ * @author Helix84
 626+ */
 627+$messages['sk'] = array(
 628+ 'mwe-loading_txt' => 'načítava sa ...',
 629+ 'mwe-error_load_lib' => 'Error: JavaScript $1 nebolo možné získať alebo neobsahuje definíciu $2',
 630+);
 631+
 632+/** Serbian Cyrillic ekavian (Српски (ћирилица))
 633+ * @author Михајло Анђелковић
 634+ */
 635+$messages['sr-ec'] = array(
 636+ 'mwe-loading_txt' => 'Учитавање ...',
 637+ 'mwe-ok' => 'ОК',
 638+ 'mwe-cancel' => 'Поништи',
 639+ 'mwe-test-plural' => 'Покренуо/ла сам {{PLURAL:$1|$1 тест|$1 тестова}}',
 640+);
 641+
 642+/** Serbian Latin ekavian (Srpski (latinica)) */
 643+$messages['sr-el'] = array(
 644+ 'mwe-loading_txt' => 'Učitavanje ...',
 645+ 'mwe-ok' => 'OK',
 646+ 'mwe-cancel' => 'Poništi',
 647+ 'mwe-test-plural' => 'Pokrenuo/la sam {{PLURAL:$1|$1 test|$1 testova}}',
 648+);
 649+
 650+/** Swedish (Svenska)
 651+ * @author Dafer45
 652+ * @author GameOn
 653+ */
 654+$messages['sv'] = array(
 655+ 'mwe-loading_txt' => 'Laddar…',
 656+ 'mwe-ok' => 'OK',
 657+ 'mwe-cancel' => 'Avbryt',
 658+);
 659+
 660+/** Telugu (తెలుగు)
 661+ * @author Veeven
 662+ */
 663+$messages['te'] = array(
 664+ 'mwe-ok' => 'సరే',
 665+ 'mwe-cancel' => 'రద్దుచేయి',
 666+);
 667+
 668+/** Tagalog (Tagalog)
 669+ * @author AnakngAraw
 670+ */
 671+$messages['tl'] = array(
 672+ 'mwe-loading_txt' => 'Ikinakarga...',
 673+ 'mwe-error_load_lib' => 'Kamalian: hindi makukuha ang JavaScript na $1 o hindi nagbigay kahulugan sa $2',
 674+ 'mwe-apiproxy-setup' => 'Nagtatalaga ng pamalit na API',
 675+ 'mwe-load-drag-item' => 'Ikinakarga ang hinilang bagay',
 676+ 'mwe-ok' => 'Okey',
 677+ 'mwe-cancel' => 'Huwag ituloy',
 678+ 'mwe-enable-gadget' => 'Paganahin ang betang multimidya (mwEmbed) para sa lahat ng mga pahina',
 679+ 'mwe-enable-gadget-done' => 'Pinagana ang gadyet na pangbetang multimidya',
 680+ 'mwe-must-login-gadget' => 'Upang mapagana ang gadyet dapat kang <a target="_new" href="$1">lumagda</a>',
 681+ 'mwe-test-plural' => 'Nagpatakbo ako ng {{PLURAL:$1|$1 pagsusulit|$1 mga pagsusulit}}',
 682+);
 683+
 684+/** Turkish (Türkçe)
 685+ * @author Joseph
 686+ */
 687+$messages['tr'] = array(
 688+ 'mwe-loading_txt' => 'yükleniyor ...',
 689+ 'mwe-error_load_lib' => 'Hata: $1 JavaScripti erişilebilir değil ya da $2 tanımlı değil',
 690+ 'mwe-apiproxy-setup' => 'API vekili ayarlanıyor',
 691+ 'mwe-load-drag-item' => 'Sürüklenen öğe yükleniyor',
 692+ 'mwe-ok' => 'Tamam',
 693+ 'mwe-cancel' => 'İptal',
 694+);
 695+
 696+/** Urdu (اردو) */
 697+$messages['ur'] = array(
 698+ 'mwe-cancel' => 'منسوخ',
 699+);
 700+
 701+/** Vèneto (Vèneto)
 702+ * @author Candalua
 703+ */
 704+$messages['vec'] = array(
 705+ 'mwe-loading_txt' => "so' drio cargar ...",
 706+ 'mwe-ok' => 'Va ben',
 707+ 'mwe-cancel' => 'Anula',
 708+);
 709+
 710+/** Vietnamese (Tiếng Việt)
 711+ * @author Minh Nguyen
 712+ * @author Vinhtantran
 713+ */
 714+$messages['vi'] = array(
 715+ 'mwe-loading_txt' => 'đang tải …',
 716+ 'mwe-size-kilobytes' => '$1 kB',
 717+ 'mwe-error_load_lib' => 'Lỗi: JavaScript $1 không truy xuất được hoặc không định nghĩa $2',
 718+ 'mwe-apiproxy-setup' => 'Đang thiết lập proxy API',
 719+ 'mwe-load-drag-item' => 'Đang tải các mục đã kéo',
 720+ 'mwe-ok' => 'OK',
 721+ 'mwe-cancel' => 'Hủy bỏ',
 722+ 'mwe-enable-gadget' => 'Kích hoạt đa phương tiện bản beta (mwEmbed) cho mọi trang',
 723+ 'mwe-enable-gadget-done' => 'Công cụ đa năng đa phương tiện bản beta đã được kích hoạt',
 724+ 'mwe-must-login-gadget' => 'Để kích hoạt công cụ đa năng bạn phải <a target="_new" href="$1">đăng nhập</a>',
 725+ 'mwe-test-plural' => 'Tôi đã chạy {{PLURAL:$1|$1 mẫu thử|$1 mẫu thử}}',
 726+);
 727+
 728+/** Wu (吴语) */
 729+$messages['wuu'] = array(
 730+ 'mwe-cancel' => '取消',
 731+);
 732+
 733+/** Simplified Chinese (‪中文(简体)‬) */
 734+$messages['zh-hans'] = array(
 735+ 'mwe-loading_txt' => '载入中……',
 736+ 'mwe-ok' => '确定',
 737+ 'mwe-cancel' => '取消',
 738+);
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/MwEmbedSupport/jquery.menu/jquery.menu.css
@@ -0,0 +1,119 @@
 2+/* Styles for jQuery menu widget
 3+Author: Maggie Wachs, maggie@filamentgroup.com
 4+Date: September 2008
 5+*/
 6+
 7+
 8+/* REQUIRED STYLES - the menus will only render correctly with these rules */
 9+
 10+.fg-menu-container { position: absolute; top:0; left:-999px; padding: .4em; overflow: hidden; }
 11+.fg-menu-container.fg-menu-flyout { overflow: visible; }
 12+
 13+.fg-menu, .fg-menu ul { list-style:none none; padding: 0; margin:0; }
 14+
 15+.fg-menu { position:relative; }
 16+.fg-menu-flyout .fg-menu { position:static; }
 17+
 18+.fg-menu ul { position:absolute; top:0; }
 19+.fg-menu ul ul { top:-1px; }
 20+
 21+.fg-menu-container.fg-menu-ipod .fg-menu-content,
 22+.fg-menu-container.fg-menu-ipod .fg-menu-content ul { background: none !important; }
 23+
 24+.fg-menu.fg-menu-scroll,
 25+.fg-menu ul.fg-menu-scroll { overflow: scroll; overflow-x: hidden; }
 26+
 27+.fg-menu li { clear:both; float:left; width:100%; margin: 0; padding:0; border: 0; }
 28+.fg-menu li li { font-size:1em; } /* inner li font size must be reset so that they don't blow up */
 29+
 30+.fg-menu-flyout ul ul { padding: .4em; }
 31+.fg-menu-flyout li { position:relative; }
 32+
 33+.fg-menu-scroll { overflow: scroll; overflow-x: hidden; }
 34+
 35+.fg-menu-breadcrumb { margin: 0; padding: 0; }
 36+
 37+.fg-menu-footer { margin-top: .4em;
 38+padding: .4em;
 39+position:absolute;
 40+bottom:2px;
 41+width: 170px;
 42+}
 43+.fg-menu-header { margin-bottom: .4em; padding: .4em; }
 44+
 45+.fg-menu-breadcrumb li { float: left; list-style: none; margin: 0; padding: 0 .2em; font-size: .9em; opacity: .7; }
 46+.fg-menu-breadcrumb li.fg-menu-prev-list,
 47+.fg-menu-breadcrumb li.fg-menu-current-crumb { clear: left; float: none; opacity: 1; }
 48+.fg-menu-breadcrumb li.fg-menu-current-crumb { padding-top: .2em; }
 49+
 50+.fg-menu-breadcrumb a,
 51+.fg-menu-breadcrumb span { float: left; }
 52+
 53+.fg-menu-footer a:link,
 54+.fg-menu-footer a:visited { float:left; width:100%; text-decoration: none; }
 55+.fg-menu-footer a:hover,
 56+.fg-menu-footer a:active { }
 57+
 58+.fg-menu-footer a span { float:left; cursor: pointer; }
 59+
 60+.fg-menu-breadcrumb .fg-menu-prev-list a:link,
 61+.fg-menu-breadcrumb .fg-menu-prev-list a:visited,
 62+.fg-menu-breadcrumb .fg-menu-prev-list a:hover,
 63+.fg-menu-breadcrumb .fg-menu-prev-list a:active { background-image: none; text-decoration:none; }
 64+
 65+.fg-menu-breadcrumb .fg-menu-prev-list a { float: left; padding-right: .4em; }
 66+.fg-menu-breadcrumb .fg-menu-prev-list a .ui-icon { float: left; }
 67+
 68+.fg-menu-breadcrumb .fg-menu-current-crumb a:link,
 69+.fg-menu-breadcrumb .fg-menu-current-crumb a:visited,
 70+.fg-menu-breadcrumb .fg-menu-current-crumb a:hover,
 71+.fg-menu-breadcrumb .fg-menu-current-crumb a:active { display:block; background-image:none; font-size:1.3em; text-decoration:none; }
 72+
 73+
 74+
 75+/* REQUIRED LINK STYLES: links are "display:block" by default; if the menu options are split into
 76+ selectable node links and 'next' links, the script floats the node links left and floats the 'next' links to the right */
 77+
 78+.fg-menu a:link,
 79+.fg-menu a:visited,
 80+.fg-menu a:hover,
 81+.fg-menu a:active { float:left; width:92%; padding:.3em 3%; text-decoration:none; outline: 0 !important; }
 82+
 83+.fg-menu a { border: 1px dashed transparent; }
 84+
 85+.fg-menu a.ui-state-default:link,
 86+.fg-menu a.ui-state-default:visited,
 87+.fg-menu a.ui-state-default:hover,
 88+.fg-menu a.ui-state-default:active,
 89+.fg-menu a.ui-state-hover:link,
 90+.fg-menu a.ui-state-hover:visited,
 91+.fg-menu a.ui-state-hover:hover,
 92+.fg-menu a.ui-state-hover:active,
 93+.fg-menu a.ui-state-active:link,
 94+.fg-menu a.ui-state-active:visited,
 95+.fg-menu a.ui-state-active:hover,
 96+.fg-menu a.ui-state-active:active { border-style: solid; font-weight: normal; }
 97+
 98+.fg-menu a span { display:block; cursor:pointer; }
 99+
 100+
 101+ /* SUGGESTED STYLES - for use with jQuery UI Themeroller CSS */
 102+
 103+.fg-menu-indicator span { float:left; }
 104+.fg-menu-indicator span.ui-icon { float:right; }
 105+
 106+.fg-menu-content.ui-widget-content,
 107+.fg-menu-content ul.ui-widget-content { border:0; }
 108+
 109+
 110+/* ICONS AND DIVIDERS */
 111+
 112+.fg-menu.fg-menu-has-icons a:link,
 113+.fg-menu.fg-menu-has-icons a:visited,
 114+.fg-menu.fg-menu-has-icons a:hover,
 115+.fg-menu.fg-menu-has-icons a:active { padding-left:20px; }
 116+
 117+.fg-menu .horizontal-divider hr, .fg-menu .horizontal-divider span { padding:0; margin:5px .6em; }
 118+.fg-menu .horizontal-divider hr { border:0; height:1px; }
 119+.fg-menu .horizontal-divider span { font-size:.9em; text-transform: uppercase; padding-left:.2em; }
 120+
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/MwEmbedSupport/jquery.menu/jquery.menu.js
@@ -0,0 +1,813 @@
 2+/*--------------------------------------------------------------------
 3+Scripts for creating and manipulating custom menus based on standard <ul> markup
 4+Version: 3.0, 03.31.2009
 5+
 6+By: Maggie Costello Wachs (maggie@filamentgroup.com) and Scott Jehl (scott@filamentgroup.com)
 7+ http://www.filamentgroup.com
 8+ * reference articles: http://www.filamentgroup.com/lab/jquery_ipod_style_drilldown_menu/
 9+
 10+* modified by Michael Dale, ( michael.dale@kaltura.com )
 11+
 12+Copyright (c) 2009 Filament Group
 13+Dual licensed under the MIT (filamentgroup.com/examples/mit-license.txt) and GPL (filamentgroup.com/examples/gpl-license.txt) licenses.
 14+
 15+NOTE: mwEmbed will switch to jquery ui menu once that is released
 16+NOTE: This menu contains several customizations for use in mwEmbed modules::
 17+
 18+* added getLineItem helper function
 19+* added special class "divider" that is non selectable menu item horizontal hr
 20+--------------------------------------------------------------------*/
 21+
 22+
 23+var allUIMenus = [];
 24+
 25+(function($) {
 26+
 27+
 28+/**
 29+* Utility line item ( li ) from text string function
 30+*
 31+* @param {String} string Text to display for the menu item
 32+* @param {String} icon jQuery UI icon key displayed to the left of the menu item
 33+* @param {Function} callback Function called once the line item is selected
 34+*/
 35+$.getLineItem = function( string, icon , callback) {
 36+ var $li = $j( '<li>' ).append(
 37+ $j('<a>')
 38+ .attr('href', '#')
 39+ .click( callback )
 40+ );
 41+ if( icon ) {
 42+ $li.find( 'a' ).append(
 43+ $j('<span style="float:left;"></span>')
 44+ .addClass( 'ui-icon ui-icon-' + icon )
 45+ );
 46+ }
 47+ $li.find( 'a' ).append( $j('<span>').text( string ) );
 48+ //mw.log(' li html: ' + $j('<div>').append( $li ).html() );
 49+ return $li;
 50+};
 51+
 52+$.fn.menu = function( options ) {
 53+ var caller = this;
 54+ var options = options;
 55+ if( ! caller.m ) {
 56+ caller.m = new Menu(caller, options);
 57+ allUIMenus.push( caller.m );
 58+
 59+
 60+ //Set up bindings:
 61+ $(this)
 62+ .mousedown(function() {
 63+ if (!caller.m.menuOpen) { caller.m.showLoading(); };
 64+ })
 65+ .click(function() {
 66+ if (caller.m.menuOpen == false) {
 67+ caller.m.showMenu();
 68+ }else {
 69+ caller.m.kill();
 70+ };
 71+ return false;
 72+ });
 73+ }
 74+
 75+ //Check for autoShow menu option
 76+ if( options.autoShow ) {
 77+ // ( handle async build out)
 78+ setTimeout(function() {
 79+ caller.m.showLoading();
 80+ caller.m.showMenu();
 81+ }, 0 );
 82+ }
 83+
 84+ //Else process the request:
 85+ if( options == 'show' ){
 86+ caller.m.showMenu();
 87+ }
 88+
 89+ return this;
 90+};
 91+
 92+function Menu(caller, options) {
 93+ var menu = this;
 94+ var caller = $(caller);
 95+
 96+ mw.log( 'jQuery.Menu:: target container: ' + options.targetMenuContainer );
 97+
 98+ var callerClassList = 'fg-menu-container ui-widget ui-widget-content ui-corner-all';
 99+ if( options.targetMenuContainer ) {
 100+ var container = $( options.targetMenuContainer )
 101+ .addClass( callerClassList )
 102+ .html( options.content )
 103+ }else{
 104+ var container = $('<div>').addClass( callerClassList ).html( options.content );
 105+ }
 106+
 107+
 108+ this.menuOpen = false;
 109+ this.menuExists = false;
 110+
 111+ var options = jQuery.extend( {
 112+ content: null,
 113+ autoShow: false,
 114+ width: 180, // width of menu container, must be set or passed in to calculate widths of child menus
 115+ maxHeight: 180, // max height of menu (if a drilldown: height does not include breadcrumb)
 116+ targetMenuContainer: null,
 117+ zindex: 2,
 118+ positionOpts: {
 119+ posX: 'left',
 120+ posY: 'bottom',
 121+ offsetX: 0,
 122+ offsetY: 0,
 123+ directionH: 'right',
 124+ directionV: 'down',
 125+ detectH: true, // do horizontal collision detection
 126+ detectV: true, // do vertical collision detection
 127+ linkToFront: false
 128+ },
 129+ showSpeed: 200, // show/hide speed in milliseconds
 130+ createMenuCallback: null,
 131+ callerOnState: 'ui-state-active', // class to change the appearance of the link/button when the menu is showing
 132+ loadingState: 'ui-state-loading', // class added to the link/button while the menu is created
 133+ linkHover: 'ui-state-hover', // class for menu option hover state
 134+ linkHoverSecondary: 'li-hover', // alternate class, may be used for multi-level menus
 135+ // ----- multi-level menu defaults -----
 136+ crossSpeed: 200, // cross-fade speed for multi-level menus
 137+ crumbDefaultText: 'Choose an option:',
 138+ backLink: true, // in the ipod-style menu: instead of breadcrumbs, show only a 'back' link
 139+ backLinkText: 'Back',
 140+ flyOut: false, // multi-level menus are ipod-style by default; this parameter overrides to make a flyout instead
 141+ flyOutOnState: 'ui-state-default',
 142+ // class to style the link (specifically, a span within the link) used in the multi-level menu to show the next level
 143+ nextMenuLink: 'ui-icon-triangle-1-e',
 144+ topLinkText: 'All',
 145+ nextCrumbLink: 'ui-icon-carat-1-e'
 146+ }, options);
 147+
 148+
 149+ // Apply some custom css to container
 150+ container.css( {
 151+ 'left' : '0px',
 152+ 'z-index': options.zindex
 153+ } );
 154+
 155+ var killAllMenus = function() {
 156+ $.each(allUIMenus, function(i) {
 157+ if (allUIMenus[i].menuOpen) { allUIMenus[i].kill(); };
 158+ });
 159+ };
 160+
 161+ this.kill = function() {
 162+ caller
 163+ .removeClass(options.loadingState)
 164+ .removeClass('fg-menu-open')
 165+ .removeClass(options.callerOnState);
 166+ container.find('li').removeClass(options.linkHoverSecondary).find('a').removeClass(options.linkHover);
 167+ if (options.flyOutOnState) { container.find('li a').removeClass(options.flyOutOnState); };
 168+ if (options.callerOnState) { caller.removeClass(options.callerOnState); };
 169+ if (container.is('.fg-menu-ipod')) { menu.resetDrilldownMenu(); };
 170+ if (container.is('.fg-menu-flyout')) { menu.resetFlyoutMenu(); };
 171+ if( ! options.keepPosition ){
 172+ container.parent().hide();
 173+ } else {
 174+ container.hide();
 175+ }
 176+ menu.menuOpen = false;
 177+ $(document).unbind('click', killAllMenus);
 178+ $(document).unbind('keydown');
 179+ };
 180+
 181+ this.showLoading = function() {
 182+ caller.addClass(options.loadingState);
 183+ };
 184+
 185+ this.showMenu = function() {
 186+ mw.log('$j.menu:: show menu' );
 187+ killAllMenus();
 188+ mw.log('jquery.menu:: killAllMenus' );
 189+ if ( ! menu.menuExists) {
 190+ menu.create()
 191+ };
 192+ mw.log('jquery.menu:: menu.create' );
 193+ caller
 194+ .addClass('fg-menu-open')
 195+ .addClass(options.callerOnState);
 196+ container.parent().show().click(function() {
 197+ menu.kill();
 198+ return false;
 199+ });
 200+ mw.log('jquery.menu:: menu. binding container' );
 201+
 202+ container.hide().slideDown(options.showSpeed).find('.fg-menu:eq(0)');
 203+ menu.menuOpen = true;
 204+ caller.removeClass(options.loadingState);
 205+ $(document).click(killAllMenus);
 206+
 207+ // assign key events
 208+ $(document).keydown(function(event) {
 209+ var e;
 210+ if (event.which !="") { e = event.which; }
 211+ else if (event.charCode != "") { e = event.charCode; }
 212+ else if (event.keyCode != "") { e = event.keyCode; }
 213+
 214+ var menuType = ($(event.target).parents('div').is('.fg-menu-flyout')) ? 'flyout' : 'ipod' ;
 215+
 216+ switch(e) {
 217+ case 37: // left arrow
 218+ if (menuType == 'flyout') {
 219+ $(event.target).trigger('mouseout');
 220+ if ($('.'+options.flyOutOnState).size() > 0) { $('.'+options.flyOutOnState).trigger('mouseover'); };
 221+ };
 222+
 223+ if (menuType == 'ipod') {
 224+ $(event.target).trigger('mouseout');
 225+ if ($('.fg-menu-footer').find('a').size() > 0) { $('.fg-menu-footer').find('a').trigger('click'); };
 226+ if ($('.fg-menu-header').find('a').size() > 0) { $('.fg-menu-current-crumb').prev().find('a').trigger('click'); };
 227+ if ($('.fg-menu-current').prev().is('.fg-menu-indicator')) {
 228+ $('.fg-menu-current').prev().trigger('mouseover');
 229+ };
 230+ };
 231+ return false;
 232+ break;
 233+
 234+ case 38: // up arrow
 235+ if ($(event.target).is('.' + options.linkHover)) {
 236+ var prevLink = $(event.target).parent().prev().find('a:eq(0)');
 237+ if (prevLink.size() > 0) {
 238+ $(event.target).trigger('mouseout');
 239+ prevLink.trigger('mouseover');
 240+ };
 241+ }
 242+ else { container.find('a:eq(0)').trigger('mouseover'); }
 243+ return false;
 244+ break;
 245+
 246+ case 39: // right arrow
 247+ if ($(event.target).is('.fg-menu-indicator')) {
 248+ if (menuType == 'flyout') {
 249+ $(event.target).next().find('a:eq(0)').trigger('mouseover');
 250+ }
 251+ else if (menuType == 'ipod') {
 252+ $(event.target).trigger('click');
 253+ setTimeout(function() {
 254+ $(event.target).next().find('a:eq(0)').trigger('mouseover');
 255+ }, options.crossSpeed);
 256+ };
 257+ };
 258+ return false;
 259+ break;
 260+
 261+ case 40: // down arrow
 262+ if ($(event.target).is('.' + options.linkHover)) {
 263+ var nextLink = $(event.target).parent().next().find('a:eq(0)');
 264+ if (nextLink.size() > 0) {
 265+ $(event.target).trigger('mouseout');
 266+ nextLink.trigger('mouseover');
 267+ };
 268+ }
 269+ else { container.find('a:eq(0)').trigger('mouseover'); }
 270+ return false;
 271+ break;
 272+
 273+ case 27: // escape
 274+ killAllMenus();
 275+ break;
 276+
 277+ case 13: // enter
 278+ if ($(event.target).is('.fg-menu-indicator') && menuType == 'ipod') {
 279+ $(event.target).trigger('click');
 280+ setTimeout(function() {
 281+ $(event.target).next().find('a:eq(0)').trigger('mouseover');
 282+ }, options.crossSpeed);
 283+ };
 284+ break;
 285+ };
 286+ });
 287+ };
 288+
 289+ this.create = function() {
 290+ mw.log( "jquery.menu.create ");
 291+
 292+ container.css({
 293+ 'width' : options.width
 294+ })
 295+ .find( 'ul:first' )
 296+ .not( '.fg-menu-breadcrumb' )
 297+ .addClass('fg-menu');
 298+
 299+ if(!options.keepPosition){
 300+ container.appendTo('body')
 301+ }
 302+
 303+
 304+ container.find('ul, li a').addClass('ui-corner-all');
 305+
 306+ // aria roles & attributes
 307+ container.find( 'ul' ).attr('role', 'menu').eq(0).attr('aria-activedescendant','active-menuitem').attr('aria-labelledby', caller.attr('id'));
 308+ container.find( 'li' ).attr('role', 'menuitem');
 309+ container.find( 'li:has(ul)' ).attr('aria-haspopup', 'true').find('ul').attr('aria-expanded', 'false');
 310+ container.find( 'a' ).attr('tabindex', '-1');
 311+
 312+ // when there are multiple levels of hierarchy, create flyout or drilldown menu
 313+ if ( container.find( 'ul' ).size() > 1 ) {
 314+ if ( options.flyOut ) {
 315+ mw.log(" call menu.flyout ");
 316+ menu.flyout(container, options);
 317+ } else {
 318+ mw.log(" call menu.drilldown ");
 319+ menu.drilldown(container, options);
 320+ }
 321+ } else {
 322+ container.find( 'a' ).click( function() {
 323+ menu.chooseItem( this );
 324+ return false;
 325+ } );
 326+ };
 327+
 328+ if (options.linkHover) {
 329+ var allLinks = container.find('.fg-menu li a');
 330+ allLinks.hover(
 331+ function() {
 332+ var menuitem = $(this);
 333+ var menuli = menuitem.parent();
 334+ if( !menuli.hasClass('divider') && !menuli.hasClass('disabled') ){
 335+ $('.'+options.linkHover).removeClass(options.linkHover).blur().parent().removeAttr('id');
 336+ $(this).addClass(options.linkHover).focus().parent().addClass('active-menuitem');
 337+ }
 338+ },
 339+ function() {
 340+ if( typeof menuitem != 'undefined' && !menuitem.hasClass('divider') && !menuitem.hasClass('disabled') ){
 341+ $(this).removeClass(options.linkHover).blur().parent().removeClass('active-menuitem');
 342+ }
 343+ }
 344+ );
 345+ };
 346+
 347+ if (options.linkHoverSecondary) {
 348+ container.find('.fg-menu li').hover(
 349+ function() {
 350+ $(this).siblings('li').removeClass(options.linkHoverSecondary);
 351+ if (options.flyOutOnState) { $(this).siblings('li').find('a').removeClass(options.flyOutOnState); }
 352+ $(this).addClass(options.linkHoverSecondary);
 353+ },
 354+ function() { $(this).removeClass(options.linkHoverSecondary); }
 355+ );
 356+ };
 357+ if( !options.keepPosition ){
 358+ menu.setPosition(container, caller, options);
 359+ }
 360+ menu.menuExists = true;
 361+
 362+ if( typeof options.createMenuCallback == 'function' ){
 363+ options.createMenuCallback();
 364+ }
 365+ };
 366+
 367+ this.chooseItem = function(item) {
 368+ menu.kill();
 369+ if( options.selectItemCallback )
 370+ options.selectItemCallback( item );
 371+ };
 372+};
 373+
 374+Menu.prototype.flyout = function(container, options) {
 375+ var menu = this;
 376+
 377+ this.resetFlyoutMenu = function() {
 378+ var allLists = container.find('ul ul');
 379+ allLists.removeClass('ui-widget-content').hide();
 380+ };
 381+
 382+ container.addClass('fg-menu-flyout').find('li:has(ul)').each(function() {
 383+ var linkWidth = container.width();
 384+ var showTimer, hideTimer;
 385+ var allSubLists = $(this).find('ul');
 386+
 387+ allSubLists.css({ left: linkWidth, width: linkWidth }).hide();
 388+
 389+ $(this).find('a:eq(0)').addClass('fg-menu-indicator').html(
 390+ '<span>' + $(this).find('a:eq(0)').html() +
 391+ '</span><span class="ui-icon '+options.nextMenuLink+'"></span>')
 392+ .hover(
 393+ function() {
 394+ clearTimeout(hideTimer);
 395+ var subList = $(this).next();
 396+ if (!fitVertical(subList, $(this).offset().top)) { subList.css({ top: 'auto', bottom: 0 }); };
 397+ if (!fitHorizontal(subList, $(this).offset().left + 100)) { subList.css({ left: 'auto', right: linkWidth, 'z-index': 1005 }); };
 398+ showTimer = setTimeout(function() {
 399+ subList.addClass('ui-widget-content').show(options.showSpeed).attr('aria-expanded', 'true');
 400+ }, 300);
 401+ },
 402+ function() {
 403+ clearTimeout(showTimer);
 404+ var subList = $(this).next();
 405+ hideTimer = setTimeout(function() {
 406+ subList.removeClass('ui-widget-content').hide(options.showSpeed).attr('aria-expanded', 'false');
 407+ }, 400);
 408+ }
 409+ );
 410+
 411+ $(this).find('ul a').hover(
 412+ function() {
 413+ clearTimeout(hideTimer);
 414+ if ($(this).parents('ul').prev().is('a.fg-menu-indicator')) {
 415+ $(this).parents('ul').prev().addClass(options.flyOutOnState);
 416+ }
 417+ },
 418+ function() {
 419+ hideTimer = setTimeout(function() {
 420+ allSubLists.hide(options.showSpeed);
 421+ container.find(options.flyOutOnState).removeClass(options.flyOutOnState);
 422+ }, 500);
 423+ }
 424+ );
 425+ });
 426+
 427+ container.find('a').click(function() {
 428+ menu.chooseItem(this);
 429+ return false;
 430+ });
 431+};
 432+
 433+
 434+Menu.prototype.drilldown = function(container, options) {
 435+ var menu = this;
 436+ var topList = container.find('.fg-menu');
 437+ var breadcrumb = $('<ul class="fg-menu-breadcrumb ui-widget-header ui-corner-all ui-helper-clearfix"></ul>');
 438+ var crumbDefaultHeader = $('<li class="fg-menu-breadcrumb-text">'+options.crumbDefaultText+'</li>');
 439+ var firstCrumbText = (options.backLink) ? options.backLinkText : options.topLinkText;
 440+ var firstCrumbClass = (options.backLink) ? 'fg-menu-prev-list' : 'fg-menu-all-lists';
 441+ var firstCrumbLinkClass = (options.backLink) ? 'ui-state-default ui-corner-all' : '';
 442+ var firstCrumbIcon = (options.backLink) ? '<span class="ui-icon ui-icon-triangle-1-w"></span>' : '';
 443+ var firstCrumb = $('<li class="'+firstCrumbClass+'"><a href="#" class="'+firstCrumbLinkClass+'">'+firstCrumbIcon+firstCrumbText+'</a></li>');
 444+
 445+ container.addClass('fg-menu-ipod');
 446+
 447+ if (options.backLink) { breadcrumb.addClass('fg-menu-footer').appendTo(container).hide(); }
 448+ else { breadcrumb.addClass('fg-menu-header').prependTo(container); };
 449+ breadcrumb.append(crumbDefaultHeader);
 450+
 451+ var checkMenuHeight = function(el) {
 452+ if (el.height() > options.maxHeight) { el.addClass('fg-menu-scroll') };
 453+ el.css({
 454+ height: options.maxHeight-30
 455+ });
 456+ };
 457+
 458+ var resetChildMenu = function(el) { el.removeClass('fg-menu-scroll').removeClass('fg-menu-current').height('auto'); };
 459+
 460+ this.resetDrilldownMenu = function() {
 461+ $('.fg-menu-current').removeClass('fg-menu-current');
 462+ topList.animate({ left: 0 }, options.crossSpeed, function() {
 463+ $(this).find('ul').each(function() {
 464+ $(this).hide();
 465+ resetChildMenu($(this));
 466+ });
 467+ topList.addClass('fg-menu-current');
 468+ });
 469+ $('.fg-menu-all-lists').find('span').remove();
 470+ breadcrumb.empty().append(crumbDefaultHeader);
 471+ $('.fg-menu-footer').empty().hide();
 472+ checkMenuHeight(topList);
 473+ };
 474+
 475+ topList
 476+ .addClass('fg-menu-content fg-menu-current ui-widget-content ui-helper-clearfix')
 477+ .css({ width: container.width() })
 478+ .find('ul')
 479+ .css({ width: container.width(), left: container.width() })
 480+ .addClass('ui-widget-content')
 481+ .hide();
 482+ checkMenuHeight(topList);
 483+
 484+ topList.find('a').each(function() {
 485+ // if the link opens a child menu:
 486+ if ($(this).next().is('ul')) {
 487+ $(this)
 488+ .addClass('fg-menu-indicator')
 489+ .each(function() { $(this).html('<span>' + $(this).html() + '</span><span class="ui-icon '+options.nextMenuLink+'"></span>'); })
 490+ .click(function() { // ----- show the next menu
 491+ var nextList = $(this).next();
 492+ var parentUl = $(this).parents('ul:eq(0)');
 493+ var parentLeft = (parentUl.is('.fg-menu-content')) ? 0 : parseFloat(topList.css('left'));
 494+ var nextLeftVal = Math.round(parentLeft - parseFloat(container.width()));
 495+ var footer = $('.fg-menu-footer');
 496+
 497+ // show next menu
 498+ resetChildMenu(parentUl);
 499+ checkMenuHeight(nextList);
 500+ topList.animate({ left: nextLeftVal }, options.crossSpeed);
 501+ nextList.show().addClass('fg-menu-current').attr('aria-expanded', 'true');
 502+
 503+ var setPrevMenu = function(backlink) {
 504+ var b = backlink;
 505+ var c = $('.fg-menu-current');
 506+ var prevList = c.parents('ul:eq(0)');
 507+ c.hide().attr('aria-expanded', 'false');
 508+ resetChildMenu(c);
 509+ checkMenuHeight(prevList);
 510+ prevList.addClass('fg-menu-current').attr('aria-expanded', 'true');
 511+ if (prevList.hasClass('fg-menu-content')) { b.remove(); footer.hide(); };
 512+ };
 513+
 514+ // initialize "back" link
 515+ if (options.backLink) {
 516+ if (footer.find('a').size() == 0) {
 517+ footer.show();
 518+ $('<a href="#"><span class="ui-icon ui-icon-triangle-1-w"></span> <span>Back</span></a>')
 519+ .appendTo(footer)
 520+ .click(function() { // ----- show the previous menu
 521+ var b = $(this);
 522+ var prevLeftVal = parseFloat(topList.css('left')) + container.width();
 523+ topList.animate({ left: prevLeftVal }, options.crossSpeed, function() {
 524+ setPrevMenu(b);
 525+ });
 526+ return false;
 527+ });
 528+ }
 529+ }
 530+ // or initialize top breadcrumb
 531+ else {
 532+ if (breadcrumb.find('li').size() == 1) {
 533+ breadcrumb.empty().append(firstCrumb);
 534+ firstCrumb.find('a').click(function() {
 535+ menu.resetDrilldownMenu();
 536+ return false;
 537+ });
 538+ }
 539+ $('.fg-menu-current-crumb').removeClass('fg-menu-current-crumb');
 540+ var crumbText = $(this).find('span:eq(0)').text();
 541+ var newCrumb = $('<li class="fg-menu-current-crumb"><a href="javascript://" class="fg-menu-crumb">'+crumbText+'</a></li>');
 542+ newCrumb
 543+ .appendTo(breadcrumb)
 544+ .find('a').click(function() {
 545+ if ($(this).parent().is('.fg-menu-current-crumb')) {
 546+ menu.chooseItem(this);
 547+ }
 548+ else {
 549+ var newLeftVal = - ($('.fg-menu-current').parents('ul').size() - 1) * 180;
 550+ topList.animate({ left: newLeftVal }, options.crossSpeed, function() {
 551+ setPrevMenu();
 552+ });
 553+
 554+ // make this the current crumb, delete all breadcrumbs after this one, and navigate to the relevant menu
 555+ $(this).parent().addClass('fg-menu-current-crumb').find('span').remove();
 556+ $(this).parent().nextAll().remove();
 557+ };
 558+ return false;
 559+ });
 560+ newCrumb.prev().append(' <span class="ui-icon '+options.nextCrumbLink+'"></span>');
 561+ };
 562+ return false;
 563+ });
 564+ }
 565+ // if the link is a leaf node (doesn't open a child menu)
 566+ else {
 567+ $(this).click(function() {
 568+ menu.chooseItem(this);
 569+ return false;
 570+ });
 571+ };
 572+ });
 573+};
 574+
 575+
 576+/* Menu.prototype.setPosition parameters (defaults noted with *):
 577+ referrer = the link (or other element) used to show the overlaid object
 578+ settings = can override the defaults:
 579+ - posX/Y: where the top left corner of the object should be positioned in relation to its referrer.
 580+ X: left*, center, right
 581+ Y: top, center, bottom*
 582+ - offsetX/Y: the number of pixels to be offset from the x or y position. Can be a positive or negative number.
 583+ - directionH/V: where the entire menu should appear in relation to its referrer.
 584+ Horizontal: left*, right
 585+ Vertical: up, down*
 586+ - detectH/V: detect the viewport horizontally / vertically
 587+ - linkToFront: copy the menu link and place it on top of the menu (visual effect to make it look like it overlaps the object) */
 588+
 589+Menu.prototype.setPosition = function(widget, caller, options) {
 590+ mw.log( 'setPosition' );
 591+
 592+ var el = widget;
 593+ var referrer = caller;
 594+ var dims = {
 595+ refX: referrer.offset().left,
 596+ refY: referrer.offset().top,
 597+ refW: referrer.getTotalWidth(),
 598+ refH: referrer.getTotalHeight()
 599+ };
 600+ var options = options;
 601+ var xVal, yVal;
 602+
 603+ var helper = $( '<div class="menuPositionHelper">' );
 604+ helper.css( 'z-index', options.zindex );
 605+
 606+ mw.log("set z-index");
 607+
 608+ // Hard code width height of button if unset ( crazy IE )
 609+ if( isNaN( dims.refW ) || isNaN( dims.refH ) ) {
 610+ dims.refH = 16;
 611+ dims.refW = 23;
 612+ }
 613+ helper.css({
 614+ 'position': 'absolute',
 615+ 'left': dims.refX,
 616+ 'top': dims.refY,
 617+ 'width': dims.refW,
 618+ 'height': dims.refH
 619+ });
 620+
 621+ mw.log("set helper.css ");
 622+
 623+ el.wrap( helper );
 624+
 625+ mw.log("wrap helper");
 626+
 627+ xVal = yVal = 0;
 628+ // get X pos
 629+ switch( options.positionOpts.posX ) {
 630+ case 'left': xVal = 0;
 631+ break;
 632+ case 'center': xVal = dims.refW / 2;
 633+ break;
 634+ case 'right': xVal = dims.refW;
 635+ break;
 636+ };
 637+
 638+ // get Y pos
 639+ switch( options.positionOpts.posY ) {
 640+ case 'top' : yVal = 0;
 641+ break;
 642+ case 'center' : yVal = dims.refH / 2;
 643+ break;
 644+ case 'bottom' : yVal = dims.refH;
 645+ break;
 646+ };
 647+
 648+ // add the offsets (zero by default)
 649+ xVal += ( options.positionOpts.offsetX )? options.positionOpts.offsetX : 0;
 650+ yVal += ( options.positionOpts.offsetY )? options.positionOpts.offsetY : 0;
 651+
 652+ mw.log(" about to position: " + yVal );
 653+ // position the object vertically
 654+ if (options.positionOpts.directionV == 'up') {
 655+ el.css( {
 656+ 'top': 'auto',
 657+ 'bottom': yVal
 658+ } );
 659+ if (options.positionOpts.detectV && !fitVertical(el)) {
 660+ el.css({
 661+ 'bottom' : 'auto',
 662+ 'top' : yVal
 663+ });
 664+ }
 665+ } else {
 666+ el.css({
 667+ 'bottom' : 'auto',
 668+ 'top' : yVal
 669+ });
 670+ if (options.positionOpts.detectV && !fitVertical(el)) {
 671+ el.css({
 672+ 'top' : 'auto',
 673+ 'bottom' : yVal
 674+ });
 675+ }
 676+ };
 677+
 678+ mw.log(" done with add the offsets && position the object vertically");
 679+
 680+ // and horizontally
 681+ if (options.positionOpts.directionH == 'left') {
 682+ el.css({ left: 'auto', right: xVal });
 683+ if (options.positionOpts.detectH && !fitHorizontal(el)) {
 684+ el.css({ right: 'auto', left: xVal });
 685+ }
 686+ }
 687+ else {
 688+ el.css({ right: 'auto', left: xVal });
 689+ if (options.positionOpts.detectH && !fitHorizontal(el)) {
 690+ el.css({ left: 'auto', right: xVal });
 691+ }
 692+ };
 693+
 694+ mw.log(" done with position the object horizontally");
 695+
 696+ // if specified, clone the referring element and position it so that it appears on top of the menu
 697+ if (options.positionOpts.linkToFront) {
 698+ referrer.clone().addClass('linkClone').css({
 699+ position: 'absolute',
 700+ top: 0,
 701+ right: 'auto',
 702+ bottom: 'auto',
 703+ left: 0,
 704+ width: referrer.width(),
 705+ height: referrer.height()
 706+ }).insertAfter(el);
 707+ };
 708+ mw.log('done with all');
 709+};
 710+
 711+
 712+/* Utilities to sort and find viewport dimensions */
 713+
 714+function sortBigToSmall(a, b) { return b - a; };
 715+
 716+jQuery.fn.getTotalWidth = function() {
 717+ return $(this).width() + parseInt($(this).css('paddingRight')) + parseInt($(this).css('paddingLeft')) + parseInt($(this).css('borderRightWidth')) + parseInt($(this).css('borderLeftWidth'));
 718+};
 719+
 720+jQuery.fn.getTotalHeight = function() {
 721+ return $(this).height() + parseInt($(this).css('paddingTop')) + parseInt($(this).css('paddingBottom')) + parseInt($(this).css('borderTopWidth')) + parseInt($(this).css('borderBottomWidth'));
 722+};
 723+
 724+function getScrollTop() {
 725+ return self.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
 726+};
 727+
 728+function getScrollLeft() {
 729+ return self.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft;
 730+};
 731+
 732+function getWindowHeight() {
 733+ var de = document.documentElement;
 734+ return self.innerHeight || (de && de.clientHeight) || document.body.clientHeight;
 735+};
 736+
 737+function getWindowWidth() {
 738+ var de = document.documentElement;
 739+ return self.innerWidth || (de && de.clientWidth) || document.body.clientWidth;
 740+};
 741+
 742+/* Utilities to test whether an element will fit in the viewport
 743+ Parameters:
 744+ el = element to position, required
 745+ leftOffset / topOffset = optional parameter if the offset cannot be calculated (i.e., if the object is in the DOM but is set to display: 'none') */
 746+
 747+function fitHorizontal(el, leftOffset) {
 748+ var leftVal = parseInt(leftOffset) || $(el).offset().left;
 749+ return (leftVal + $(el).width() <= getWindowWidth() + getScrollLeft() && leftVal - getScrollLeft() >= 0);
 750+};
 751+
 752+function fitVertical(el, topOffset) {
 753+ var topVal = parseInt(topOffset) || $(el).offset().top;
 754+ return (topVal + $(el).height() <= getWindowHeight() + getScrollTop() && topVal - getScrollTop() >= 0);
 755+};
 756+
 757+/*--------------------------------------------------------------------
 758+ * javascript method: "pxToEm"
 759+ * by:
 760+ Scott Jehl (scott@filamentgroup.com)
 761+ Maggie Wachs (maggie@filamentgroup.com)
 762+ http://www.filamentgroup.com
 763+ *
 764+ * Copyright (c) 2008 Filament Group
 765+ * Dual licensed under the MIT (filamentgroup.com/examples/mit-license.txt) and GPL (filamentgroup.com/examples/gpl-license.txt) licenses.
 766+ *
 767+ * Description: Extends the native Number and String objects with pxToEm method. pxToEm converts a pixel value to ems depending on inherited font size.
 768+ * Article: http://www.filamentgroup.com/lab/retaining_scalable_interfaces_with_pixel_to_em_conversion/
 769+ * Demo: http://www.filamentgroup.com/examples/pxToEm/
 770+ *
 771+ * Options:
 772+ scope: string or jQuery selector for font-size scoping
 773+ reverse: Boolean, true reverses the conversion to em-px
 774+ * Dependencies: jQuery library
 775+ * Usage Example: myPixelValue.pxToEm(); or myPixelValue.pxToEm({'scope':'#navigation', reverse: true});
 776+ *
 777+ * Version: 2.0, 08.01.2008
 778+ * Changelog:
 779+ * 08.02.2007 initial Version 1.0
 780+ * 08.01.2008 - fixed font-size calculation for IE
 781+--------------------------------------------------------------------*/
 782+
 783+Number.prototype.pxToEm = String.prototype.pxToEm = function(settings) {
 784+ //set defaults
 785+ settings = jQuery.extend({
 786+ scope: 'body',
 787+ reverse: false
 788+ }, settings);
 789+
 790+ var pxVal = (this == '') ? 0 : parseFloat(this);
 791+ var scopeVal;
 792+ var getWindowWidth = function() {
 793+ var de = document.documentElement;
 794+ return self.innerWidth || (de && de.clientWidth) || document.body.clientWidth;
 795+ };
 796+
 797+ /* When a percentage-based font-size is set on the body, IE returns that percent of the window width as the font-size.
 798+ For example, if the body font-size is 62.5% and the window width is 1000px, IE will return 625px as the font-size.
 799+ When this happens, we calculate the correct body font-size (%) and multiply it by 16 (the standard browser font size)
 800+ to get an accurate em value. */
 801+
 802+ if (settings.scope == 'body' && $.browser.msie && (parseFloat($('body').css('font-size')) / getWindowWidth()).toFixed(1) > 0.0) {
 803+ var calcFontSize = function() {
 804+ return (parseFloat($('body').css('font-size'))/getWindowWidth()).toFixed(3) * 16;
 805+ };
 806+ scopeVal = calcFontSize();
 807+ }
 808+ else { scopeVal = parseFloat(jQuery(settings.scope).css("font-size")); };
 809+
 810+ var result = (settings.reverse == true) ? (pxVal * scopeVal).toFixed(2) + 'px' : (pxVal / scopeVal).toFixed(2) + 'em';
 811+ return result;
 812+};
 813+
 814+} )( jQuery );
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/MwEmbedSupport/mwEmbed.core.js
@@ -0,0 +1,433 @@
 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+( function( mw, $ ) {
 23+
 24+ /**
 25+ * Set the mwEmbedVersion
 26+ */
 27+ window.MW_EMBED_VERSION = '1.1g';
 28+
 29+ // Globals to pre-set ready functions in dynamic loading of mwEmbed
 30+ if( typeof window.preMwEmbedReady == 'undefined'){
 31+ window.preMwEmbedReady = [];
 32+ }
 33+ // Globals to pre-set config values in dynamic loading of mwEmbed
 34+ if( typeof window.preMwEmbedConfig == 'undefined') {
 35+ window.preMwEmbedConfig = [];
 36+ }
 37+
 38+ /**
 39+ * Enables pages to target a "interfaces ready" state.
 40+ *
 41+ * TODO make it work!
 42+ *
 43+ * This is different from jQuery(document).ready() ( jQuery ready is not
 44+ * friendly with dynamic includes and not friendly with core interface
 45+ * asynchronous build out. )
 46+ *
 47+ * @param {Function}
 48+ * callback Function to run once DOM and jQuery are ready
 49+ */
 50+ var mwOnLoadFunctions = []; // Setup the local mwOnLoadFunctions array:
 51+ var mwReadyFlag = false; // mw Ready flag ( set once mwEmbed is ready )
 52+ mw.ready = function( callback ) {
 53+ if( mwReadyFlag === false ) {
 54+ // Add the callbcak to the onLoad function stack
 55+ mwOnLoadFunctions.push ( callback );
 56+ } else {
 57+ // If mwReadyFlag is already "true" issue the callback directly:
 58+ callback();
 59+ }
 60+ };
 61+
 62+ // add a domReady setup infterface trigger
 63+ SetupInterface
 64+ /**
 65+ * Runs all the queued functions called by mwEmbedSetup
 66+ */
 67+ mw.runReadyFunctions = function ( ) {
 68+ mw.log('mw.runReadyFunctions: ' + mwOnLoadFunctions.length );
 69+ // Run any pre-setup ready functions
 70+ while( preMwEmbedReady.length ){
 71+ preMwEmbedReady.shift()();
 72+ }
 73+ // Run all the queued functions:
 74+ while( mwOnLoadFunctions.length ) {
 75+ mwOnLoadFunctions.shift()();
 76+ }
 77+ // Sets mwReadyFlag to true so that future mw.ready run the
 78+ // callback directly
 79+ mwReadyFlag = true;
 80+
 81+ };
 82+
 83+ /**
 84+ * Aliased functions
 85+ *
 86+ * Wrap mediaWiki functionality while we port over the libraries
 87+ */
 88+ mw.setConfig = function( name, value ){
 89+ mediaWiki.config.set( name, value );
 90+ };
 91+ mw.getConfig = function( name, value ){
 92+ mediaWiki.config.get( name, value );
 93+ };
 94+ mw.setDefaultConfig = function( name, value ){
 95+ if( ! mediaWiki.config.get( name ) ){
 96+ mediaWiki.config.set( name, value );
 97+ }
 98+ };
 99+ mw.load = function( resources, callback ){
 100+ mediaWiki.using( resources, callback, function(){
 101+ // failed to load
 102+ });
 103+ };
 104+
 105+ /**
 106+ * Merge in a configuration value:
 107+ */
 108+ mw.mergeConfig = function( name, value ){
 109+ if( typeof name == 'object' ) {
 110+ $j.each( name, function( inx, val) {
 111+ mw.mergeConfig( inx, val );
 112+ });
 113+ return ;
 114+ }
 115+ // Check if we should "merge" the config
 116+ if( typeof value == 'object' && typeof mw.getConfig( name ) == 'object' ) {
 117+ if ( value.constructor.toString().indexOf("Array") != -1 &&
 118+ mw.getConfig( name ).constructor.toString().indexOf("Array") != -1
 119+ ){
 120+ // merge in the array
 121+ mw.setConfig( name, $j.merge( mw.getConfig( name ), value ) );
 122+ } else {
 123+ mw.setConfig( name, value );
 124+ }
 125+ return ;
 126+ }
 127+ // else do a normal setConfig
 128+ mw.setConfig( name, value );
 129+ };
 130+
 131+ /**
 132+ * Utility Functions
 133+ *
 134+ * TOOD some of these utility functions are used in the upload Wizard, break them out into
 135+ * associated files.
 136+ */
 137+
 138+ /**
 139+ * Given a float number of seconds, returns npt format response. ( ignore
 140+ * days for now )
 141+ *
 142+ * @param {Float}
 143+ * sec Seconds
 144+ * @param {Boolean}
 145+ * show_ms If milliseconds should be displayed.
 146+ * @return {Float} String npt format
 147+ */
 148+ mw.seconds2npt = function( sec, show_ms ) {
 149+ if ( isNaN( sec ) ) {
 150+ mw.log("Warning: trying to get npt time on NaN:" + sec);
 151+ return '0:00:00';
 152+ }
 153+
 154+ var tm = mw.seconds2Measurements( sec )
 155+
 156+ // Round the number of seconds to the required number of significant
 157+ // digits
 158+ if ( show_ms ) {
 159+ tm.seconds = Math.round( tm.seconds * 1000 ) / 1000;
 160+ } else {
 161+ tm.seconds = Math.round( tm.seconds );
 162+ }
 163+ if ( tm.seconds < 10 ){
 164+ tm.seconds = '0' + tm.seconds;
 165+ }
 166+ if( tm.hours == 0 ){
 167+ hoursStr = ''
 168+ } else {
 169+ if ( tm.minutes < 10 )
 170+ tm.minutes = '0' + tm.minutes;
 171+
 172+ hoursStr = tm.hours + ":";
 173+ }
 174+ return hoursStr + tm.minutes + ":" + tm.seconds;
 175+ }
 176+
 177+ /**
 178+ * Given seconds return array with 'days', 'hours', 'min', 'seconds'
 179+ *
 180+ * @param {float}
 181+ * sec Seconds to be converted into time measurements
 182+ */
 183+ mw.seconds2Measurements = function ( sec ){
 184+ var tm = {};
 185+ tm.days = Math.floor( sec / ( 3600 * 24 ) )
 186+ tm.hours = Math.floor( sec / 3600 );
 187+ tm.minutes = Math.floor( ( sec / 60 ) % 60 );
 188+ tm.seconds = sec % 60;
 189+ return tm;
 190+ }
 191+
 192+ /**
 193+ * Take hh:mm:ss,ms or hh:mm:ss.ms input, return the number of seconds
 194+ *
 195+ * @param {String}
 196+ * npt_str NPT time string
 197+ * @return {Float} Number of seconds
 198+ */
 199+ mw.npt2seconds = function ( npt_str ) {
 200+ if ( !npt_str ) {
 201+ // mw.log('npt2seconds:not valid ntp:'+ntp);
 202+ return 0;
 203+ }
 204+ // Strip {npt:}01:02:20 or 32{s} from time if present
 205+ npt_str = npt_str.replace( /npt:|s/g, '' );
 206+
 207+ var hour = 0;
 208+ var min = 0;
 209+ var sec = 0;
 210+
 211+ times = npt_str.split( ':' );
 212+ if ( times.length == 3 ) {
 213+ sec = times[2];
 214+ min = times[1];
 215+ hour = times[0];
 216+ } else if ( times.length == 2 ) {
 217+ sec = times[1];
 218+ min = times[0];
 219+ } else {
 220+ sec = times[0];
 221+ }
 222+ // Sometimes a comma is used instead of period for ms
 223+ sec = sec.replace( /,\s?/, '.' );
 224+ // Return seconds float
 225+ return parseInt( hour * 3600 ) + parseInt( min * 60 ) + parseFloat( sec );
 226+ }
 227+
 228+ /**
 229+ * addLoaderDialog small helper for displaying a loading dialog
 230+ *
 231+ * @param {String}
 232+ * dialogHtml text Html of the loader msg
 233+ */
 234+ mw.addLoaderDialog = function( dialogHtml ) {
 235+ $dialog = mw.addDialog( {
 236+ 'title' : dialogHtml,
 237+ 'content' : dialogHtml + '<br>' +
 238+ $j('<div />')
 239+ .loadingSpinner()
 240+ .html()
 241+ });
 242+ return $dialog;
 243+ }
 244+
 245+
 246+
 247+ /**
 248+ * Add a (temporary) dialog window:
 249+ *
 250+ * @param {Object} with following keys:
 251+ * title: {String} Title string for the dialog
 252+ * content: {String} to be inserted in msg box
 253+ * buttons: {Object} A button object for the dialog Can be a string
 254+ * for the close button
 255+ * any jquery.ui.dialog option
 256+ */
 257+ mw.addDialog = function ( options ) {
 258+ // Remove any other dialog
 259+ $j( '#mwTempLoaderDialog' ).remove();
 260+
 261+ if( !options){
 262+ options = {};
 263+ }
 264+
 265+ // Extend the default options with provided options
 266+ var options = $j.extend({
 267+ 'bgiframe': true,
 268+ 'draggable': true,
 269+ 'resizable': false,
 270+ 'modal': true
 271+ }, options );
 272+
 273+ if( ! options.title || ! options.content ){
 274+ mw.log("Error: mwEmbed addDialog missing required options ( title, content ) ")
 275+ return ;
 276+ }
 277+
 278+ // Append the dialog div on top:
 279+ $j( 'body' ).append(
 280+ $j('<div />')
 281+ .attr( {
 282+ 'id' : "mwTempLoaderDialog",
 283+ 'title' : options.title
 284+ })
 285+ .css({
 286+ 'display': 'none'
 287+ })
 288+ .append( options.content )
 289+ );
 290+
 291+ // Build the uiRequest
 292+ var uiRequest = [ '$j.ui.dialog' ];
 293+ if( options.draggable ){
 294+ uiRequest.push( '$j.ui.draggable' )
 295+ }
 296+ if( options.resizable ){
 297+ uiRequest.push( '$j.ui.resizable' );
 298+ }
 299+
 300+ // Special button string
 301+ if ( typeof options.buttons == 'string' ) {
 302+ var buttonMsg = options.buttons;
 303+ buttons = { };
 304+ options.buttons[ buttonMsg ] = function() {
 305+ $j( this ).dialog( 'close' );
 306+ }
 307+ }
 308+
 309+ // Load the dialog resources
 310+ mw.load([
 311+ [
 312+ '$j.ui'
 313+ ],
 314+ uiRequest
 315+ ], function() {
 316+ $j( '#mwTempLoaderDialog' ).dialog( options );
 317+ } );
 318+ return $j( '#mwTempLoaderDialog' );
 319+ }
 320+
 321+ /**
 322+ * Close the loader dialog created with addLoaderDialog
 323+ */
 324+ mw.closeLoaderDialog = function() {
 325+ $j( '#mwTempLoaderDialog' ).dialog( 'destroy' ).remove();
 326+ };
 327+
 328+ // MOVE TO jquery.client
 329+ // move to jquery.client
 330+ mw.isIphone = function(){
 331+ return ( navigator.userAgent.indexOf('iPhone') != -1 && ! mw.isIpad() );
 332+ };
 333+ // Uses hack described at:
 334+ // http://www.bdoran.co.uk/2010/07/19/detecting-the-iphone4-and-resolution-with-javascript-or-php/
 335+ mw.isIphone4 = function(){
 336+ return ( mw.isIphone() && ( window.devicePixelRatio && window.devicePixelRatio >= 2 ) );
 337+ };
 338+ mw.isIpod = function(){
 339+ return ( navigator.userAgent.indexOf('iPod') != -1 );
 340+ };
 341+ mw.isIpad = function(){
 342+ return ( navigator.userAgent.indexOf('iPad') != -1 );
 343+ };
 344+ // Android 2 has some restrictions vs other mobile platforms
 345+ mw.isAndroid2 = function(){
 346+ return ( navigator.userAgent.indexOf( 'Android 2.') != -1 );
 347+ };
 348+
 349+ /**
 350+ * Fallforward system by default prefers flash.
 351+ *
 352+ * This is separate from the EmbedPlayer library detection to provide
 353+ * package loading control NOTE: should be phased out in favor of browser
 354+ * feature detection where possible
 355+ *
 356+ */
 357+ mw.isHTML5FallForwardNative = function(){
 358+ if( mw.isMobileHTML5() ){
 359+ return true;
 360+ }
 361+ // Check for url flag to force html5:
 362+ if( document.URL.indexOf('forceMobileHTML5') != -1 ){
 363+ return true;
 364+ }
 365+ // Fall forward native:
 366+ // if the browser supports flash ( don't use html5 )
 367+ if( mw.supportsFlash() ){
 368+ return false;
 369+ }
 370+ // No flash return true if the browser supports html5 video tag with
 371+ // basic support for canPlayType:
 372+ if( mw.supportsHTML5() ){
 373+ return true;
 374+ }
 375+
 376+ return false;
 377+ }
 378+
 379+ mw.isMobileHTML5 = function(){
 380+ // Check for a mobile html5 user agent:
 381+ if ( mw.isIphone() ||
 382+ mw.isIpod() ||
 383+ mw.isIpad() ||
 384+ mw.isAndroid2()
 385+ ){
 386+ return true;
 387+ }
 388+ return false;
 389+ };
 390+ mw.supportsHTML5 = function(){
 391+ // Blackberry is evil in its response to canPlayType calls.
 392+ if( navigator.userAgent.indexOf('BlackBerry') != -1 ){
 393+ return false ;
 394+ }
 395+ var dummyvid = document.createElement( "video" );
 396+ if( dummyvid.canPlayType ) {
 397+ return true;
 398+ }
 399+ return false;
 400+ }
 401+
 402+ mw.supportsFlash = function(){
 403+ // Check if the client does not have flash and has the video tag
 404+ if ( navigator.mimeTypes && navigator.mimeTypes.length > 0 ) {
 405+ for ( var i = 0; i < navigator.mimeTypes.length; i++ ) {
 406+ var type = navigator.mimeTypes[i].type;
 407+ var semicolonPos = type.indexOf( ';' );
 408+ if ( semicolonPos > -1 ) {
 409+ type = type.substr( 0, semicolonPos );
 410+ }
 411+ if (type == 'application/x-shockwave-flash' ) {
 412+ // flash is installed
 413+ return true;
 414+ }
 415+ }
 416+ }
 417+
 418+ // for IE:
 419+ var hasObj = true;
 420+ if( typeof ActiveXObject != 'undefined' ){
 421+ try {
 422+ var obj = new ActiveXObject( 'ShockwaveFlash.ShockwaveFlash' );
 423+ } catch ( e ) {
 424+ hasObj = false;
 425+ }
 426+ if( hasObj ){
 427+ return true;
 428+ }
 429+ }
 430+ return false;
 431+ };
 432+
 433+
 434+} )( mediaWiki, jQuery );
\ No newline at end of file
Property changes on: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/MwEmbedSupport/mwEmbed.core.js
___________________________________________________________________
Added: svn:mime-type
1435 + text/plain
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/MwEmbedSupport/MwEmbedSupport.php
@@ -0,0 +1,8 @@
 2+<?php
 3+
 4+return array(
 5+
 6+)
 7+
 8+?>
 9+
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/MwEmbedSupport/mwEmbed.old.js
@@ -0,0 +1,2698 @@
 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 mwEmbed Dual licensed under the MIT or GPL Version 2 licenses.
 8+ *
 9+ * @copyright (C) 2010 Kaltura
 10+ * @author Michael Dale ( michael.dale at kaltura.com )
 11+ *
 12+ * @url http://www.kaltura.org/project/HTML5_Video_Media_JavaScript_Library
 13+ *
 14+ * Libraries used include code license in headers
 15+ */
 16+
 17+/**
 18+ * Setup the "mw" global:
 19+ */
 20+if ( typeof window.mw == 'undefined' ) {
 21+ window.mw = { };
 22+}
 23+/**
 24+ * Set the mwEmbedVersion
 25+ */
 26+var MW_EMBED_VERSION = '1.1h';
 27+
 28+// Globals to pre-set ready functions in dynamic loading of mwEmbed
 29+if( typeof preMwEmbedReady == 'undefined'){
 30+ var preMwEmbedReady = [];
 31+}
 32+// Globals to pre-set config values in dynamic loading of mwEmbed
 33+if( typeof preMwEmbedConfig == 'undefined') {
 34+ var preMwEmbedConfig = [];
 35+}
 36+
 37+/**
 38+ * The global mw object:
 39+ */
 40+( function( mw ) {
 41+ // The version of mwEmbed
 42+ mw.version = MW_EMBED_VERSION;
 43+
 44+ // List valid skins here:
 45+ mw.validSkins = [ 'mvpcf', 'kskin' ];
 46+
 47+ // Storage variable for loaded style sheet keys
 48+ if( ! mw.style ){
 49+ mw.style = { };
 50+ }
 51+
 52+ /**
 53+ * Configuration System:
 54+ */
 55+
 56+ // Local scope configuration var:
 57+ if( !mwConfig ){
 58+ var mwConfig = { };
 59+ }
 60+
 61+ if( !mwNonDefaultConfigList ){
 62+ var mwNonDefaultConfigList = [];
 63+ }
 64+
 65+ // mw scope mwUserConfig var. Stores user configuration
 66+ var mwUserConfig = { };
 67+
 68+ /**
 69+ * Setter for configuration values
 70+ *
 71+ * @param [Mixed]
 72+ * name Name of configuration value {Object} Will iderate through
 73+ * each key and call setConfig {String} Will set configuration by
 74+ * string name to value
 75+ * @param {String}
 76+ * value Value of configuration name {Object} value Set of values
 77+ * to be merged
 78+ */
 79+ mw.setConfig = function ( name, value ) {
 80+ if( typeof name == 'object' ) {
 81+ for( var i in name ) {
 82+ mw.setConfig( i, name[ i ] );
 83+ }
 84+ return ;
 85+ }
 86+ mwConfig[ name ] = value;
 87+ mwNonDefaultConfigList.push( name );
 88+ };
 89+
 90+ // Apply any pre-setup config:
 91+ mw.setConfig( preMwEmbedConfig );
 92+
 93+ /**
 94+ * Merge in a configuration value:
 95+ */
 96+ mw.mergeConfig = function( name, value ){
 97+ if( typeof name == 'object' ) {
 98+ $j.each( name, function( inx, val) {
 99+ mw.setConfig( inx, val );
 100+ });
 101+ return ;
 102+ }
 103+ // Check if we should "merge" the config
 104+ if( typeof value == 'object' && typeof mwConfig[ name ] == 'object' ) {
 105+ if ( value.constructor.toString().indexOf("Array") != -1 &&
 106+ mwConfig[ name ].constructor.toString().indexOf("Array") != -1 ){
 107+ // merge in the array
 108+ mwConfig[ name ] = $j.merge( mwConfig[ name ], value );
 109+ } else {
 110+ for( var i in value ){
 111+ mwConfig[ name ][ i ] = value[ i ];
 112+ }
 113+ }
 114+ return ;
 115+ }
 116+ // else do a normal setConfig
 117+ mwConfig[ name ] = value;
 118+ mwNonDefaultConfigList.push( name );
 119+ };
 120+
 121+ /**
 122+ * Set a default config value Will only update configuration if no value is
 123+ * present
 124+ *
 125+ * @param [Mixed]
 126+ * value Set configuration name to value {Object} Will idorate
 127+ * through each key and call setDefaultConfig {String} Will set
 128+ * configuration by string name to value
 129+ */
 130+ mw.setDefaultConfig = function( name, value ) {
 131+ if( typeof name == 'object' ) {
 132+ for( var i in name ) {
 133+ mw.setDefaultConfig( i, name[ i ] );
 134+ }
 135+ return ;
 136+ }
 137+ if( typeof mwConfig[ name ] == 'undefined' ) {
 138+ mwConfig[ name ] = value;
 139+ return ;
 140+ }
 141+ };
 142+
 143+ /**
 144+ * Getter for configuration values
 145+ *
 146+ * @param {String}
 147+ * name of configuration value to get
 148+ * @return {Mixed} value of configuration key returns "false" if key not
 149+ * found
 150+ */
 151+ mw.getConfig = function ( name ) {
 152+ if( mwConfig[ name ] )
 153+ return mwConfig[ name ];
 154+ return false;
 155+ };
 156+ /**
 157+ * Get all the non-default configuration ( useful for passing state to
 158+ * iframes in limited hash url length of a few K )
 159+ */
 160+ mw.getNonDefaultConfigObject = function(){
 161+ var nonDefaultConfig = {};
 162+ for( var i =0 ; i < mwNonDefaultConfigList.length; i ++){
 163+ var configKey = mwNonDefaultConfigList[i];
 164+ nonDefaultConfig[ configKey ] = mw.getConfig( configKey );
 165+ }
 166+ return nonDefaultConfig;
 167+ }
 168+
 169+ /**
 170+ * Loads the mwUserConfig from a cookie.
 171+ *
 172+ * Modules that want to use "User Config" should call this setup function in
 173+ * their moduleLoader code.
 174+ *
 175+ * For performance interfaces using "user config" should load '$j.cookie' &
 176+ * 'JSON' in their module loader
 177+ *
 178+ * By abstracting user preference we could eventually integrate a persistent
 179+ * per-account preference system on the server.
 180+ *
 181+ * @parma {Function} callback Function to be called once userPrefrences are
 182+ * loaded
 183+ */
 184+ var setupUserConfigFlag = false;
 185+ mw.setupUserConfig = function( callback ) {
 186+ if( setupUserConfigFlag ) {
 187+ if( callback ) {
 188+ callback();
 189+ }
 190+ return ;
 191+ }
 192+ // Do Setup user config:
 193+ mw.load( [ '$j.cookie', 'JSON' ], function() {
 194+ if( $j.cookie( 'mwUserConfig' ) ) {
 195+ mwUserConfig = JSON.parse( $j.cookie( 'mwUserConfig' ) );
 196+ }
 197+ setupUserConfigFlag = true;
 198+ if( callback ) {
 199+ callback();
 200+ }
 201+ });
 202+ };
 203+
 204+ /**
 205+ * Save a user configuration var to a cookie & local global variable Loads
 206+ * the cookie plugin if not already loaded
 207+ *
 208+ * @param {String}
 209+ * name Name of user configuration value
 210+ * @param {String}
 211+ * value Value of configuration name
 212+ */
 213+ mw.setUserConfig = function ( name, value, cookieOptions ) {
 214+ if( ! setupUserConfigFlag ) {
 215+ mw.log( "Error: userConfig not setup" );
 216+ return false;
 217+ }
 218+ // Update local value
 219+ mwUserConfig[ name ] = value;
 220+
 221+ // Update the cookie ( '$j.cookie' & 'JSON' should already be loaded )
 222+ $j.cookie( 'mwUserConfig', JSON.stringify( mwUserConfig ) );
 223+ };
 224+
 225+ /**
 226+ * Save a user configuration var to a cookie & local global variable
 227+ *
 228+ * @param {String}
 229+ * name Name of user configuration value
 230+ * @return value of the configuration name false if the configuration name
 231+ * could not be found
 232+ */
 233+ mw.getUserConfig = function ( name ) {
 234+ if( mwUserConfig[ name ] )
 235+ return mwUserConfig[ name ];
 236+ return false;
 237+ };
 238+
 239+ /**
 240+ * Add a hook system for a target object / interface
 241+ *
 242+ * depricated you should instead use jQuery's bind and trigger
 243+ *
 244+ * @param {Object}
 245+ * targetObj Interface Object to add hook system to.
 246+ */
 247+ mw.addHookSystem = function( targetObj ) {
 248+
 249+ // Setup the target object hook holder:
 250+ targetObj[ 'hooks' ] = { };
 251+
 252+ /**
 253+ * Adds a hook to the target object
 254+ *
 255+ * Should be called by clients to setup named hooks
 256+ *
 257+ * @param {String}
 258+ * hookName Name of hook to be added
 259+ * @param {Function}
 260+ * hookFunction Function to be called at hook time
 261+ */
 262+ targetObj.addHook = function( hookName, hookFunction ) {
 263+ if( ! this.hooks[ hookName ] ) {
 264+ this.hooks[ hookName ] = [ ];
 265+ }
 266+ this.hooks[ hookName ].push( hookFunction );
 267+ };
 268+
 269+ /**
 270+ * Runs all the hooks by a given name with reference to the host object
 271+ *
 272+ * Should be called by the host object at named execution points
 273+ *
 274+ * @param {String}
 275+ * hookName Name of hook to be called
 276+ * @return Value of hook result true interface should continue function
 277+ * execution false interface should stop or return from method
 278+ */
 279+ targetObj.runHook = function( hookName, options ) {
 280+ if( this.hooks[ hookName ] ) {
 281+ for( var i =0; i < this.hooks[ hookName ].length; i ++ ) {
 282+ if( typeof( this.hooks[ hookName ][ i ] ) == 'function' ) {
 283+ this.hooks[ hookName ][ i ]( options );
 284+ }
 285+ }
 286+ }
 287+ };
 288+ };
 289+
 290+ // Add hooks system to the core "mw" object
 291+ mw.addHookSystem( mw );
 292+
 293+ // Stores callbacks for resource loader loading
 294+ var mwLoadDoneCB = { };
 295+
 296+
 297+ /**
 298+ * Top level loader prototype:
 299+ */
 300+ mw.loader = {
 301+ /**
 302+ * Javascript Module Loader functions
 303+ *
 304+ * @key Name of Module
 305+ * @value function code to load module
 306+ */
 307+ moduleLoaders : [],
 308+
 309+ /**
 310+ * Module resource list queue.
 311+ *
 312+ * @key Name of Module
 313+ * @value .resourceList list of resources to be loaded .functionQueue
 314+ * list of functions to be run once module is ready
 315+ */
 316+ moduleLoadQueue: { },
 317+
 318+ /**
 319+ * Javascript Class Paths
 320+ *
 321+ * @key Name of resource
 322+ * @value Class file path
 323+ */
 324+ resourcePaths : { },
 325+
 326+ /**
 327+ * Stores resources that have been requested ( to avoid re-requesting
 328+ * the same resources ) in concurrent requests )
 329+ */
 330+ requestedResourceQueue: { },
 331+
 332+ /**
 333+ * javascript Resource Paths
 334+ *
 335+ * @key Name of resource
 336+ * @value Name of depenent style sheet
 337+ */
 338+ resourceStyleDependency: { },
 339+
 340+ /**
 341+ * Core load function:
 342+ *
 343+ * @param {Mixed}
 344+ * loadRequest:
 345+ *
 346+ * {String} Name of a module to be loaded Modules are added via
 347+ * addModuleLoader and can define custom code needed to check config and
 348+ * return a list of resources to be loaded
 349+ *
 350+ * {String} Name of a resource to loaded. Resources are added via
 351+ * addResourcePaths function Using defined resource names avoids loading
 352+ * the same resource twice by first checking if the named resource is
 353+ * defined in the global javascript scope variable
 354+ *
 355+ * {String} Absolute or relative to url path The same file won't be
 356+ * loaded twice
 357+ *
 358+ * {Array} can be an array of any combination of the above strings. Will
 359+ * be loaded in-order or in a single resource loader request if
 360+ * scriptLoader is available.
 361+ *
 362+ * {Array} {Array} Can be a set of Arrays for loading. Some browsers
 363+ * execute included scripts out of order. This lets you chain sets of
 364+ * request for those browsers. If using the server side resource loader
 365+ * order is preserved in output and a single request will be used.
 366+ *
 367+ * @param {Function}
 368+ * callback Function called once loading is complete
 369+ *
 370+ */
 371+ load: function( loadRequest, instanceCallback ) {
 372+ // mw.log("mw.load:: " + loadRequest );
 373+ var _this = this;
 374+
 375+ // Throw out any loadRequests that are not strings
 376+ loadRequest = this.cleanLoadRequest( loadRequest );
 377+
 378+ // Ensure the callback is only called once per load instance
 379+ var callback = function(){
 380+ // mw.log( 'instanceCallback::running callback: ' +
 381+ // instanceCallback );
 382+ if( instanceCallback ){
 383+ // We pass the loadRequest back to the callback for easy
 384+ // debugging of concurrency issues.
 385+ // ( normally its not used )
 386+ instanceCallback( loadRequest );
 387+ instanceCallback = null;
 388+ }
 389+ };
 390+
 391+ // Check for empty loadRequest ( directly return the callback )
 392+ if( mw.isEmpty( loadRequest ) ) {
 393+ mw.log( 'Empty load request: ( ' + loadRequest + ' ) ' );
 394+ callback( loadRequest );
 395+ return ;
 396+ }
 397+
 398+
 399+ // Check if its a multi-part request:
 400+ if( typeof loadRequest == 'object' ) {
 401+ if( loadRequest.length > 1 ) {
 402+ this.loadMany ( loadRequest, callback );
 403+ return ;
 404+ }else{
 405+ // If an array of length 1 set as first element
 406+ loadRequest = loadRequest[0];
 407+ }
 408+ }
 409+
 410+ // Check for the module name loader function
 411+ if( this.moduleLoaders[ loadRequest ] ) {
 412+ var resourceSet = this.getModuleResourceSet( loadRequest );
 413+ if( !resourceSet ){
 414+ mw.log( "mw.load:: Error with module loader: " + loadRequest + ' ( no resource set defined )' );
 415+ return ;
 416+ }
 417+
 418+ // xxx should use refactor "ready" stuff into a "domReady" class
 419+ // So we would not have local scope globals like this:
 420+ // if ( mwReadyFlag ) {
 421+ // Load the module directly if load request is after
 422+ // mw.ready has run
 423+ this.load( resourceSet, callback );
 424+ // } else {
 425+ // this.addToModuleLoaderQueue(
 426+ // loadRequest,
 427+ // resourceSet,
 428+ // callback
 429+ // );
 430+ // }
 431+ return ;
 432+ }
 433+
 434+ // Check for javascript resource
 435+ if( this.getResourcePath( loadRequest ) ) {
 436+ this.loadResource( loadRequest, callback );
 437+ return ;
 438+ }
 439+
 440+ // Try loading as a "file" or via ScriptLoader
 441+ if( loadRequest ) {
 442+ // Check if this resource was already requested
 443+ if( typeof this.requestedResourceQueue[ loadRequest ] == 'object' ){
 444+ this.requestedResourceQueue[ loadRequest ].push( callback );
 445+ return ;
 446+ } else {
 447+ this.requestedResourceQueue[ loadRequest ] = [];
 448+ }
 449+
 450+ if( loadRequest.indexOf( '.js' ) == -1 && !mw.getResourceLoaderPath() ) {
 451+ mw.log( 'Error: are you sure ' + loadRequest + ' is a file ( is it missing a resource path? ) ' );
 452+ }
 453+ mw.getScript( loadRequest, function(){
 454+ // Check if we have requestedResources queue items:
 455+ while( _this.requestedResourceQueue[ loadRequest ].length ){
 456+ _this.requestedResourceQueue[ loadRequest ].shift()( loadRequest );
 457+ }
 458+ callback( loadRequest );
 459+ // empty the load request queue:
 460+ _this.requestedResourceQueue[ loadRequest ] = [];
 461+ });
 462+ return ;
 463+ }
 464+
 465+ // Possible error?
 466+ mw.log( "Error could not handle load request: " + loadRequest );
 467+ },
 468+
 469+ getModuleResourceSet: function( moduleName ){
 470+ // Check if the module loader is a function ~run that function~
 471+ if( typeof ( this.moduleLoaders[ moduleName ] ) == 'function' ) {
 472+ // Add the result of the module loader function
 473+ return this.moduleLoaders[ moduleName ]();
 474+ } else if( typeof ( this.moduleLoaders[ moduleName ] ) == 'object' ){
 475+ // set resourceSet directly
 476+ return this.moduleLoaders[ moduleName ];
 477+ }
 478+ return false;
 479+ },
 480+
 481+ /**
 482+ * Clean the loadRequest ( throw out any non-string items )
 483+ */
 484+ cleanLoadRequest: function( loadRequest ){
 485+ var cleanRequest = [];
 486+ if( ! loadRequest ){
 487+ return [];
 488+ }
 489+ if( typeof loadRequest == 'string' )
 490+ return loadRequest;
 491+ for( var i =0;i < loadRequest.length; i++ ){
 492+ if( typeof loadRequest[i] == 'object' ) {
 493+ cleanRequest[i] = this.cleanLoadRequest( loadRequest[i] );
 494+ } else if( typeof loadRequest[i] == 'string' ){
 495+ cleanRequest[i] = $j.trim( loadRequest[i] );
 496+ } else{
 497+ // bad request type skip
 498+ }
 499+ }
 500+ return cleanRequest;
 501+ },
 502+
 503+ /**
 504+ * Load a set of scripts. Will issue many load requests or package the
 505+ * request for the resource loader
 506+ *
 507+ * @param {Object}
 508+ * loadSet Set of scripts to be loaded
 509+ * @param {Function}
 510+ * callback Function to call once all scripts are loaded.
 511+ */
 512+ loadMany: function( loadSet, callback ) {
 513+ var _this = this;
 514+ // Setup up the local "loadStates"
 515+ var loadStates = { };
 516+
 517+ // Check if we can load via the "resource loader" ( mwEmbed was
 518+ // included via scriptLoader )
 519+ if( mw.getResourceLoaderPath() ) {
 520+ // Get the grouped loadStates variable
 521+ loadStates = this.getGroupLoadState( loadSet );
 522+ if( mw.isEmpty( loadStates ) ) {
 523+ // mw.log( 'loadMany:all resources already loaded');
 524+ callback();
 525+ return ;
 526+ }
 527+ }else{
 528+ // Check if its a dependency set ( nested objects )
 529+ if( typeof loadSet [ 0 ] == 'object' ) {
 530+ _this.dependencyChainCallFlag[ loadSet ] = false;
 531+ // Load sets of resources ( to preserver order for some
 532+ // browsers )
 533+ _this.loadDependencyChain( loadSet, callback );
 534+ return ;
 535+ }
 536+
 537+ // Set the initial load state for every item in the loadSet
 538+ for( var i = 0; i < loadSet.length ; i++ ) {
 539+ var loadName = loadSet[ i ];
 540+ loadStates[ loadName ] = 0;
 541+ }
 542+ }
 543+
 544+ // We are infact loading many:
 545+ // mw.log("mw.load: LoadMany:: " + loadSet );
 546+
 547+ // Issue the load request check check loadStates to see if we are
 548+ // "done"
 549+ for( var loadName in loadStates ) {
 550+ // mw.log("loadMany: load: " + loadName );
 551+ this.load( loadName, function ( loadName ) {
 552+ loadStates[ loadName ] = 1;
 553+
 554+ /*
 555+ * for( var i in loadStates ) { mw.log( loadName + '
 556+ * finished of: ' + i + ' : ' + loadStates[i] ); }
 557+ */
 558+
 559+ // Check if all load request states are set 1
 560+ var loadDone = true;
 561+ for( var j in loadStates ) {
 562+ if( loadStates[ j ] === 0 )
 563+ loadDone = false;
 564+ }
 565+ // Run the parent scope callback for "loadMany"
 566+ if( loadDone ) {
 567+ callback( loadName );
 568+ }
 569+ } );
 570+ }
 571+ },
 572+
 573+ /**
 574+ * Get grouped load state for script loader
 575+ *
 576+ * Groups the scriptRequest where possible: Modules include "loader
 577+ * code" so they are separated into pre-condition code to be run for
 578+ * subsequent requests
 579+ *
 580+ * @param {Object}
 581+ * loadSet Loadset to return grouped
 582+ * @return {Object} grouped loadSet
 583+ */
 584+ getGroupLoadState: function( loadSet ) {
 585+ var groupedLoadSet = [];
 586+ var loadStates = { };
 587+ // Merge load set into new groupedLoadSet
 588+ if( typeof loadSet[0] == 'object' ) {
 589+ for( var i = 0; i < loadSet.length ; i++ ) {
 590+ for( var j = 0; j < loadSet[i].length ; j++ ) {
 591+ // Make sure we have not already included it:
 592+ groupedLoadSet.push( loadSet[i][j] );
 593+ }
 594+ }
 595+ } else {
 596+ // Use the loadSet directly:
 597+ groupedLoadSet = loadSet;
 598+ }
 599+
 600+ // Setup grouped loadStates Set:
 601+ var groupClassKey = '';
 602+ var coma = '';
 603+ var uniqueResourceName = {};
 604+ for( var i=0; i < groupedLoadSet.length; i++ ) {
 605+ var loadName = groupedLoadSet[ i ];
 606+ if( this.getResourcePath( loadName ) ) {
 607+ // Check if not already in request queue and not defined in
 608+ // global namespace
 609+ if( !mw.isset( loadName ) && ! uniqueResourceName[ loadName] ){
 610+ groupClassKey += coma + loadName;
 611+ coma = ',';
 612+
 613+ // Check for style sheet dependencies
 614+ if( this.resourceStyleDependency[ loadName ] ){
 615+ groupClassKey += coma + this.resourceStyleDependency[ loadName ];
 616+ }
 617+ }
 618+ } else if ( this.moduleLoaders[ loadName ] ) {
 619+
 620+ // Module loaders break up grouped script requests ( add the
 621+ // current groupClassKey )
 622+ if( groupClassKey != '' ) {
 623+ loadStates[ groupClassKey ] = 0;
 624+ groupClassKey = coma = '';
 625+ }
 626+ if( ! uniqueResourceName[ loadName] ){
 627+ // Add the module to the loadSate
 628+ loadStates[ loadName ] = 0;
 629+ }
 630+ }
 631+ uniqueResourceName[ loadName] = true;
 632+ }
 633+
 634+ // Add groupClassKey if set:
 635+ if( groupClassKey != '' ) {
 636+ loadStates [ groupClassKey ] = 0;
 637+ }
 638+
 639+ return loadStates;
 640+ },
 641+
 642+ // Array to register that a callback has been called
 643+ dependencyChainCallFlag: { },
 644+
 645+ /**
 646+ * Load a sets of scripts satisfy dependency order for browsers that
 647+ * execute dynamically included scripts out of order
 648+ *
 649+ * @param {Object}
 650+ * loadChain A set of javascript arrays to be loaded. Sets
 651+ * are requested in array order.
 652+ */
 653+ loadDependencyChain: function( loadChain, callback ) {
 654+ var _this = this;
 655+ // Load with dependency checks
 656+ var callSet = loadChain.shift();
 657+ this.load( callSet, function( cbname ) {
 658+ if ( loadChain.length != 0 ) {
 659+ _this.loadDependencyChain( loadChain, callback );
 660+ } else {
 661+ // NOTE: IE gets called twice so we have check the
 662+ // dependencyChainCallFlag before calling the callback
 663+ if( _this.dependencyChainCallFlag[ callSet ] == callback ) {
 664+ mw.log("... already called this callback for " + callSet );
 665+ return ;
 666+ }
 667+ _this.dependencyChainCallFlag[ callSet ] = callback;
 668+ callback( );
 669+ }
 670+ } );
 671+ },
 672+
 673+ /**
 674+ * Add to the module loader queue
 675+ */
 676+ addToModuleLoaderQueue: function( moduleName, resourceSet, callback ) {
 677+ mw.log(" addToModuleLoaderQueue:: " + moduleName + ' resourceSet: ' + resourceSet );
 678+ if( this.moduleLoadQueue[ moduleName ] ){
 679+ // If the module is already in the queue just add its callback:
 680+ this.moduleLoadQueue[ moduleName ].functionQueue.push( callback );
 681+ } else {
 682+ // create the moduleLoadQueue item
 683+ this.moduleLoadQueue[ moduleName ] = {
 684+ 'resourceSet' : resourceSet,
 685+ 'functionQueue' : [ callback ],
 686+ 'loaded' : false
 687+ };
 688+ }
 689+ },
 690+
 691+ /**
 692+ * Loops over all modules in queue, builds request sets based on config
 693+ * request type
 694+ */
 695+ runModuleLoadQueue: function(){
 696+ var _this = this;
 697+ mw.log( "mw.runModuleLoadQueue:: " );
 698+ var runModuleFunctionQueue = function(){
 699+ // Run all the callbacks
 700+ for( var moduleName in _this.moduleLoadQueue ){
 701+ while( _this.moduleLoadQueue[moduleName].functionQueue.length ) {
 702+ _this.moduleLoadQueue[moduleName].functionQueue.shift()();
 703+ }
 704+ }
 705+ };
 706+
 707+ // Check for single request or javascript debug based loading:
 708+ if( !mw.getResourceLoaderPath() || mw.getConfig( 'loader.groupStrategy' ) == 'single' ){
 709+ // if not using the resource load just do a normal array merge
 710+ // ( for browsers like IE that don't follow first append first
 711+ // execute rule )
 712+ var fullResourceList = [];
 713+ for( var moduleName in this.moduleLoadQueue ) {
 714+ var resourceSet = this.moduleLoadQueue[ moduleName ].resourceSet;
 715+ // Lets try a global merge
 716+ fullResourceList = $j.merge( fullResourceList, resourceSet );
 717+ }
 718+ mw.load( fullResourceList, function(){
 719+ runModuleFunctionQueue();
 720+ });
 721+ return ;
 722+ }
 723+
 724+ // Else do per module group loading
 725+ if( mw.getConfig( 'loader.groupStrategy' ) == 'module' ) {
 726+ var fullResourceList = [];
 727+ var sharedResourceList = [];
 728+
 729+ for( var moduleName in this.moduleLoadQueue ) {
 730+ // Build a shared dependencies list and load that separately
 731+ // "first"
 732+ // ( in IE we have to wait until its "ready" since it does
 733+ // not follow dom order )
 734+ var moduleResourceList = this.getFlatModuleResourceList( moduleName );
 735+ // Build the sharedResourceList
 736+ for( var i=0; i < moduleResourceList.length; i++ ){
 737+ var moduleResource = moduleResourceList[i];
 738+ // Check if already in the full resource list if so add
 739+ // to shared.
 740+ if( fullResourceList[ moduleResource ] ){
 741+ if( $j.inArray( moduleResource, sharedResourceList ) == -1 ){
 742+ sharedResourceList.push( moduleResource );
 743+ }
 744+ }
 745+ // Add to the fullResourceList
 746+ fullResourceList[ moduleResource ] = true;
 747+ }
 748+ }
 749+
 750+ // Local module request set ( stores the actual request we will
 751+ // make after grouping shared resources
 752+ var moduleRequestSet = {};
 753+
 754+ // Only add non-shared to respective modules load requests
 755+ for( var moduleName in this.moduleLoadQueue ) {
 756+ moduleRequestSet[ moduleName ] = [];
 757+ var moduleResourceList = this.getFlatModuleResourceList( moduleName );
 758+ for( var i =0; i < moduleResourceList.length; i++ ){
 759+ var moduleResource = moduleResourceList[i];
 760+ if( $j.inArray( moduleResource, sharedResourceList ) == -1 ){
 761+ moduleRequestSet[ moduleName ].push( moduleResource );
 762+ }
 763+ }
 764+ }
 765+ var sharedResourceLoadDone = false;
 766+ // Check if modules are done
 767+ var checkModulesDone = function(){
 768+ if( !sharedResourceLoadDone ){
 769+ return false;
 770+ }
 771+ for( var moduleName in _this.moduleLoadQueue ) {
 772+ if( ! _this.moduleLoadQueue[ moduleName ].loaded ){
 773+ return false;
 774+ }
 775+ }
 776+ runModuleFunctionQueue();
 777+ };
 778+ // Local instance of load requests to retain resourceSet
 779+ // context:
 780+ var localLoadCallInstance = function( moduleName, resourceSet ){
 781+ mw.load( resourceSet, function(){
 782+ _this.moduleLoadQueue[ moduleName ].loaded = true;
 783+ checkModulesDone();
 784+ });
 785+ };
 786+
 787+ // Load the shared resources
 788+ mw.load( sharedResourceList, function(){
 789+ // mw.log("Shared Resources loaded");
 790+ // xxx check if we are in "IE" and dependencies need to be
 791+ // loaded "first"
 792+ sharedResourceLoadDone = true;
 793+ checkModulesDone();
 794+ });
 795+ // Load all module Request Set
 796+ for( var moduleName in moduleRequestSet ){
 797+ localLoadCallInstance( moduleName, moduleRequestSet[ moduleName ] );
 798+ }
 799+ }
 800+ // xxx Here we could also do some "intelligent" grouping
 801+ },
 802+
 803+ getFlatModuleResourceList: function( moduleName ){
 804+ var moduleList = [];
 805+ for( var j in this.moduleLoadQueue[moduleName].resourceSet ){
 806+ // Check if we have a multi-set array:
 807+ if( typeof this.moduleLoadQueue[moduleName].resourceSet[j] == 'object' ){
 808+ moduleList = $j.merge( moduleList, this.moduleLoadQueue[moduleName].resourceSet[j] );
 809+ } else {
 810+ moduleList = $j.merge( moduleList, [ this.moduleLoadQueue[moduleName].resourceSet[j] ] );
 811+ }
 812+ }
 813+ return moduleList;
 814+ },
 815+
 816+ /**
 817+ * Loads javascript or css associated with a resourceName
 818+ *
 819+ * @param {String}
 820+ * resourceName Name of resource to load
 821+ * @param {Function}
 822+ * callback Function to run once resource is loaded
 823+ */
 824+ loadResource: function( resourceName , callback) {
 825+ // mw.log("LoadResource:" + resourceName );
 826+ var _this = this;
 827+
 828+ // Check for css dependency on resource name
 829+ if( this.resourceStyleDependency[ resourceName ] ) {
 830+ if( ! mw.isset( this.resourceStyleDependency[ resourceName ] )){
 831+ mw.log("loadResource:: dependent css resource: " + this.resourceStyleDependency[ resourceName ] );
 832+ _this.loadResource( this.resourceStyleDependency[ resourceName ] , function() {
 833+ // Continue the original loadResource request.
 834+ _this.loadResource( resourceName, callback );
 835+ });
 836+ return ;
 837+ }
 838+ }
 839+
 840+ // Make sure the resource is not already defined:
 841+ if ( mw.isset( resourceName ) ) {
 842+ // mw.log( 'Class ( ' + resourceName + ' ) already defined ' );
 843+ callback( resourceName );
 844+ return ;
 845+ }
 846+
 847+ // Setup the Script Request var:
 848+ var scriptRequest = null;
 849+
 850+
 851+ // If the scriptloader is enabled use the resourceName as the
 852+ // scriptRequest:
 853+ if( mw.getResourceLoaderPath() ) {
 854+ scriptRequest = resourceName;
 855+ }else{
 856+ // Get the resource url:
 857+ var baseClassPath = this.getResourcePath( resourceName );
 858+ // Add the mwEmbed path if not a root path or a full url
 859+ if( baseClassPath.indexOf( '/' ) !== 0 &&
 860+ baseClassPath.indexOf( '://' ) === -1 ) {
 861+ scriptRequest = mw.getMwEmbedPath() + baseClassPath;
 862+ }else{
 863+ scriptRequest = baseClassPath;
 864+ }
 865+ if( ! scriptRequest ) {
 866+ mw.log( "Error Could not get url for resource " + resourceName );
 867+ return false;
 868+ }
 869+ }
 870+ // Include resource defined check for older browsers
 871+ var resourceDone = false;
 872+
 873+ // Set the loadDone callback per the provided resourceName
 874+ mw.setLoadDoneCB( resourceName, callback );
 875+ // Issue the request to load the resource (include resource name in
 876+ // result callback:
 877+ mw.getScript( scriptRequest, function( scriptRequest ) {
 878+ // If its a "style sheet" manually set its resource to true
 879+ var ext = scriptRequest.substr( scriptRequest.split('?')[0].lastIndexOf( '.' ), 4 ).toLowerCase();
 880+ if( ext == '.css' && resourceName.substr(0,8) == 'mw.style' ){
 881+ mw.style[ resourceName.substr( 9 ) ] = true;
 882+ }
 883+
 884+ // Send warning if resourceName is not defined
 885+ if(! mw.isset( resourceName )
 886+ && mwLoadDoneCB[ resourceName ] != 'done' ) {
 887+ // mw.log( 'Possible Error: ' + resourceName +' not set in
 888+ // time, or not defined in:' + "\n"
 889+ // + _this.getResourcePath( resourceName ) );
 890+ }
 891+
 892+ // If ( debug mode ) and the script include is missing resource
 893+ // messages
 894+ // do a separate request to retrieve the msgs
 895+ if( mw.currentClassMissingMessages ) {
 896+ mw.log( " resourceName " + resourceName + " is missing messages" );
 897+ // Reset the currentClassMissingMessages flag
 898+ mw.currentClassMissingMessages = false;
 899+
 900+ // Load msgs for this resource:
 901+ mw.loadResourceMessages( resourceName, function() {
 902+ // Run the onDone callback
 903+ mw.loadDone( resourceName );
 904+ } );
 905+ } else {
 906+ // If not using the resource loader make sure the
 907+ // resourceName is available before firing the loadDone
 908+ if( !mw.getResourceLoaderPath() ) {
 909+ mw.waitForObject( resourceName, function( resourceName ) {
 910+ // Once object is ready run loadDone
 911+ mw.loadDone( resourceName );
 912+ } );
 913+ } else {
 914+ // loadDone should be appended to the bottom of the
 915+ // resource loader response
 916+ // mw.loadDone( resourceName );
 917+ }
 918+ }
 919+ } );
 920+ },
 921+
 922+ /**
 923+ * Adds a module to the mwLoader object
 924+ *
 925+ * @param {String}
 926+ * name Name of module
 927+ * @param {Function}
 928+ * moduleLoader Function that loads dependencies for a module
 929+ */
 930+ addModuleLoader: function( name, moduleLoader ) {
 931+ this.moduleLoaders [ name ] = moduleLoader;
 932+ },
 933+
 934+ /**
 935+ * Adds resource file path key value pairs
 936+ *
 937+ * @param {Object}
 938+ * resourceSet JSON formated list of resource name file path
 939+ * pairs.
 940+ *
 941+ * resourceSet must be strict JSON to allow the php scriptLoader to
 942+ * parse the file paths.
 943+ */
 944+ addResourcePaths: function( resourceSet ) {
 945+ var prefix = ( mw.getConfig( 'loaderContext' ) )?
 946+ mw.getConfig( 'loaderContext' ): '';
 947+
 948+ for( var i in resourceSet ) {
 949+ this.resourcePaths[ i ] = prefix + resourceSet[ i ];
 950+ }
 951+ },
 952+
 953+ /*
 954+ * Adds a named style sheet dependency to a named resource
 955+ *
 956+ * @parma {Object} resourceSet JSON formated list of resource names and
 957+ * associated style sheet names
 958+ */
 959+ addStyleResourceDependency: function( resourceSet ){
 960+ for( var i in resourceSet ){
 961+ this.resourceStyleDependency[ i ] = resourceSet[i];
 962+ }
 963+ },
 964+
 965+ /**
 966+ * Get a resource path from a resourceName if no resource found return
 967+ * false
 968+ */
 969+ getResourcePath: function( resourceName ) {
 970+ if( this.resourcePaths[ resourceName ] )
 971+ return this.resourcePaths[ resourceName ];
 972+ return false;
 973+ }
 974+ };
 975+
 976+ /**
 977+ * Load done callback for script loader
 978+ *
 979+ * @param {String}
 980+ * requestName Name of the load request
 981+ */
 982+ mw.loadDone = function( requestName ) {
 983+ if( !mwLoadDoneCB[ requestName ] ) {
 984+ return true;
 985+ }
 986+ while( mwLoadDoneCB[ requestName ].length ) {
 987+ // check if mwLoadDoneCB is already "done"
 988+ // the function list is not an object
 989+ if( typeof mwLoadDoneCB[ requestName ] != 'object' )
 990+ {
 991+ break;
 992+ }
 993+ var func = mwLoadDoneCB[ requestName ].pop();
 994+ if( typeof func == 'function' ) {
 995+ // mw.log( "LoadDone: " + requestName + ' run callback::' +
 996+ // func);
 997+ func( requestName );
 998+ }else{
 999+ mw.log('mwLoadDoneCB: Error non callback function on stack');
 1000+ }
 1001+ }
 1002+ // Set the load request name to done
 1003+ mwLoadDoneCB[ requestName ] = 'done';
 1004+ };
 1005+
 1006+ /**
 1007+ * Set a load done callback
 1008+ *
 1009+ * @param {String}
 1010+ * requestName Name of resource or request set
 1011+ * @param {Function}
 1012+ * callback Function called once requestName is ready
 1013+ */
 1014+ mw.setLoadDoneCB = function( requestName, callback ) {
 1015+ // If the requestName is already done loading just callback
 1016+ if( mwLoadDoneCB[ requestName ] == 'done' ) {
 1017+ callback( requestName );
 1018+ }
 1019+ // Setup the function queue if unset
 1020+ if( typeof mwLoadDoneCB[ requestName ] != 'object' ) {
 1021+ mwLoadDoneCB[ requestName ] = [];
 1022+ }
 1023+ mwLoadDoneCB[ requestName ].push( callback );
 1024+ };
 1025+
 1026+ /**
 1027+ * Shortcut entry points / convenience functions: Lets you write mw.load()
 1028+ * instead of mw.loader.load() only these entry points should be used.
 1029+ *
 1030+ * future closure optimizations could minify internal function names
 1031+ */
 1032+
 1033+ /**
 1034+ * Load Object entry point: Loads a requested set of javascript
 1035+ */
 1036+ mw.load = function( loadRequest, callback ) {
 1037+ return mw.loader.load( loadRequest, callback );
 1038+ };
 1039+
 1040+ /**
 1041+ * Add module entry point: Adds a module to the mwLoader object
 1042+ */
 1043+ mw.addModuleLoader = function ( name, loaderFunction ) {
 1044+ return mw.loader.addModuleLoader( name, loaderFunction );
 1045+ };
 1046+
 1047+ /**
 1048+ * Add Class File Paths entry point:
 1049+ */
 1050+ mw.addResourcePaths = function ( resourceSet ) {
 1051+ return mw.loader.addResourcePaths( resourceSet );
 1052+ };
 1053+
 1054+ mw.addStyleResourceDependency = function ( resourceSet ) {
 1055+ return mw.loader.addStyleResourceDependency( resourceSet );
 1056+ };
 1057+
 1058+ /**
 1059+ * Get Class File Path entry point:
 1060+ */
 1061+ mw.getResourcePath = function( resourceName ) {
 1062+ return mw.loader.getResourcePath( resourceName );
 1063+ };
 1064+
 1065+
 1066+ /**
 1067+ * Utility Functions
 1068+ */
 1069+
 1070+ /**
 1071+ * addLoaderDialog small helper for displaying a loading dialog
 1072+ *
 1073+ * @param {String}
 1074+ * dialogHtml text Html of the loader msg
 1075+ */
 1076+ mw.addLoaderDialog = function( dialogHtml ) {
 1077+ if( typeof dialogHtml == 'undefined'){
 1078+ dialogHtml ='';
 1079+ }
 1080+ var $dialog = mw.addDialog( {
 1081+ 'title' : dialogHtml,
 1082+ 'content' : dialogHtml + '<br>' +
 1083+ $j('<div />')
 1084+ .loadingSpinner()
 1085+ .html()
 1086+ });
 1087+ return $dialog;
 1088+ };
 1089+
 1090+ /**
 1091+ * Close the loader dialog created with addLoaderDialog
 1092+ */
 1093+ mw.closeLoaderDialog = function() {
 1094+ // Make sure the dialog resource is present
 1095+ if( !mw.isset( '$j.ui.dialog' ) ) {
 1096+ return false;
 1097+ }
 1098+ // Close with timeout since jquery ui binds with timeout:
 1099+ // ui dialog line 530
 1100+ setTimeout( function(){
 1101+ $j( '#mwTempLoaderDialog' )
 1102+ .dialog( 'destroy' );
 1103+ } , 10);
 1104+ };
 1105+
 1106+ /**
 1107+ * Add a (temporary) dialog window:
 1108+ *
 1109+ * @param {Object}
 1110+ * with following keys: title: {String} Title string for the
 1111+ * dialog content: {String} to be inserted in msg box buttons:
 1112+ * {Object} A button object for the dialog Can be a string for
 1113+ * the close button any jquery.ui.dialog option
 1114+ */
 1115+ mw.addDialog = function ( options ) {
 1116+ // Remove any other dialog
 1117+ $j( '#mwTempLoaderDialog' ).remove();
 1118+
 1119+ if( !options){
 1120+ options = {};
 1121+ }
 1122+
 1123+ // Extend the default options with provided options
 1124+ var options = $j.extend({
 1125+ 'bgiframe': true,
 1126+ 'draggable': true,
 1127+ 'resizable': false,
 1128+ 'modal': true,
 1129+ 'position' : ['center', 'center']
 1130+ }, options );
 1131+
 1132+ if( ! options.title || ! options.content ){
 1133+ mw.log("Error: mwEmbed addDialog missing required options ( title, content ) ");
 1134+ return ;
 1135+ }
 1136+
 1137+ // Append the dialog div on top:
 1138+ $j( 'body' ).append(
 1139+ $j('<div />')
 1140+ .attr( {
 1141+ 'id' : "mwTempLoaderDialog",
 1142+ 'title' : options.title
 1143+ })
 1144+ .hide()
 1145+ .append( options.content )
 1146+ );
 1147+
 1148+ // Build the uiRequest
 1149+ var uiRequest = [ '$j.ui.dialog' ];
 1150+ if( options.draggable ){
 1151+ uiRequest.push( '$j.ui.mouse' );
 1152+ uiRequest.push( '$j.ui.draggable' );
 1153+ }
 1154+ if( options.resizable ){
 1155+ uiRequest.push( '$j.ui.resizable' );
 1156+ }
 1157+
 1158+ // Special button string
 1159+ if ( typeof options.buttons == 'string' ) {
 1160+ var buttonMsg = options.buttons;
 1161+ buttons = { };
 1162+ options.buttons[ buttonMsg ] = function() {
 1163+ $j( this ).dialog( 'close' );
 1164+ };
 1165+ }
 1166+
 1167+ // Load the dialog resources
 1168+ mw.load([
 1169+ [
 1170+ '$j.ui',
 1171+ '$j.widget',
 1172+ '$j.ui.mouse',
 1173+ '$j.ui.position'
 1174+ ],
 1175+ uiRequest
 1176+ ], function() {
 1177+ var $dialog = $j( '#mwTempLoaderDialog' ).show().dialog( options );
 1178+ } );
 1179+ return $j( '#mwTempLoaderDialog' );
 1180+ };
 1181+
 1182+ /**
 1183+ * Similar to php isset function checks if the variable exists. Does a safe
 1184+ * check of a descendant method or variable
 1185+ *
 1186+ * @param {String}
 1187+ * objectPath
 1188+ * @return {Boolean} true if objectPath exists false if objectPath is
 1189+ * undefined
 1190+ */
 1191+ mw.isset = function( objectPath ) {
 1192+ if ( !objectPath || typeof objectPath != 'string') {
 1193+ return false;
 1194+ }
 1195+ var pathSet = objectPath.split( '.' );
 1196+ var cur_path = '';
 1197+
 1198+ for ( var p = 0; p < pathSet.length; p++ ) {
 1199+ cur_path = ( cur_path == '' ) ? cur_path + pathSet[p] : cur_path + '.' + pathSet[p];
 1200+ eval( 'var ptest = typeof ( ' + cur_path + ' ); ' );
 1201+ if ( ptest == 'undefined' ) {
 1202+ return false;
 1203+ }
 1204+ }
 1205+ return true;
 1206+ };
 1207+
 1208+ /**
 1209+ * Wait for a object to be defined and the call the callback
 1210+ *
 1211+ * @param {Object}
 1212+ * objectName Name of object to be defined
 1213+ * @param {Function}
 1214+ * callback Function to call once object is defined
 1215+ * @param {Null}
 1216+ * callNumber Used internally to keep track of number of times
 1217+ * waitForObject has been called
 1218+ */
 1219+ var waitTime = 1200; // About 30 seconds
 1220+ mw.waitForObject = function( objectName, callback, _callNumber) {
 1221+ // mw.log( 'waitForObject: ' + objectName + ' cn: ' + _callNumber);
 1222+
 1223+ // Increment callNumber:
 1224+ if( !_callNumber ) {
 1225+ _callNumber = 1;
 1226+ } else {
 1227+ _callNumber++;
 1228+ }
 1229+
 1230+ if( _callNumber > waitTime ) {
 1231+ mw.log( "Error: waiting for object: " + objectName + ' timeout ' );
 1232+ callback( false );
 1233+ return ;
 1234+ }
 1235+
 1236+ // If the object is defined ( or we are done loading from a callback )
 1237+ if ( mw.isset( objectName ) || mwLoadDoneCB[ objectName ] == 'done' ) {
 1238+ callback( objectName );
 1239+ }else{
 1240+ setTimeout( function( ) {
 1241+ mw.waitForObject( objectName, callback, _callNumber);
 1242+ }, 25);
 1243+ }
 1244+ };
 1245+
 1246+ /**
 1247+ * Check if an object is empty or if its an empty string.
 1248+ *
 1249+ * @param {Object}
 1250+ * object Object to be checked
 1251+ */
 1252+ mw.isEmpty = function( object ) {
 1253+ if( typeof object == 'string' ) {
 1254+ if( object == '' ) return true;
 1255+ // Non empty string:
 1256+ return false;
 1257+ }
 1258+
 1259+ // If an array check length:
 1260+ if( Object.prototype.toString.call( object ) === "[object Array]"
 1261+ && object.length == 0 ) {
 1262+ return true;
 1263+ }
 1264+
 1265+ // Else check as an object:
 1266+ for( var i in object ) { return false; }
 1267+
 1268+ // Else object is empty:
 1269+ return true;
 1270+ };
 1271+
 1272+ /**
 1273+ * Log a string msg to the console
 1274+ *
 1275+ * all mw.log statements will be removed on minification so lots of mw.log
 1276+ * calls will not impact performance in non debug mode
 1277+ *
 1278+ * @param {String}
 1279+ * string String to output to console
 1280+ */
 1281+ mw.log = function( string ) {
 1282+ // Add any prepend debug strings if necessary
 1283+ if ( mw.getConfig( 'Mw.LogPrepend' ) ){
 1284+ string = mw.getConfig( 'Mw.LogPrepend' ) + string;
 1285+ }
 1286+ // To debug stack size ( useful for iPad / safari that have a 100 call
 1287+ // stack limit
 1288+ // string = mw.getCallStack().length -1 + ' : ' + string;
 1289+
 1290+ if ( window.console ) {
 1291+ window.console.log( string );
 1292+ } else {
 1293+ /**
 1294+ * Old IE and non-Firebug debug: ( commented out for now )
 1295+ */
 1296+
 1297+ /*
 1298+ * var log_elm = document.getElementById('mv_js_log'); if(!log_elm) {
 1299+ * document.getElementsByTagName("body")[0].innerHTML += '<div ' +
 1300+ * 'style="position:absolute;z-index:500;bottom:0px;left:0px;right:0px;height:200px;">' + '<textarea
 1301+ * id="mv_js_log" cols="120" rows="12"></textarea>' + '</div>'; }
 1302+ * var log_elm = document.getElementById('mv_js_log'); if(log_elm) {
 1303+ * log_elm.value+=string+"\n"; // scroll to bottom:
 1304+ * log_elm.scrollTop = log_elm.scrollHeight; }
 1305+ */
 1306+ }
 1307+ };
 1308+ mw.getCallStack = function(){
 1309+ var stringifyArguments = function(args) {
 1310+ for (var i = 0; i < args.length; ++i) {
 1311+ var arg = args[i];
 1312+ if (arg === undefined) {
 1313+ args[i] = 'undefined';
 1314+ } else if (arg === null) {
 1315+ args[i] = 'null';
 1316+ } else if (arg.constructor) {
 1317+ if (arg.constructor === Array) {
 1318+ if (arg.length < 3) {
 1319+ args[i] = '[' + stringifyArguments(arg) + ']';
 1320+ } else {
 1321+ args[i] = '[' + stringifyArguments(Array.prototype.slice.call(arg, 0, 1)) + '...' + stringifyArguments(Array.prototype.slice.call(arg, -1)) + ']';
 1322+ }
 1323+ } else if (arg.constructor === Object) {
 1324+ args[i] = '#object';
 1325+ } else if (arg.constructor === Function) {
 1326+ args[i] = '#function';
 1327+ } else if (arg.constructor === String) {
 1328+ args[i] = '"' + arg + '"';
 1329+ }
 1330+ }
 1331+ }
 1332+ return args.join(',');
 1333+ };
 1334+ var getStack = function(curr){
 1335+ var ANON = '{anonymous}', fnRE = /function\s*([\w\-$]+)?\s*\(/i,
 1336+ stack = [], fn, args, maxStackSize = 100;
 1337+
 1338+ while (curr && stack.length < maxStackSize) {
 1339+ fn = fnRE.test(curr.toString()) ? RegExp.$1 || ANON : ANON;
 1340+ args = Array.prototype.slice.call(curr['arguments']);
 1341+ stack[stack.length] = fn + '(' + stringifyArguments(args) + ')';
 1342+ curr = curr.caller;
 1343+ }
 1344+ return stack;
 1345+ }
 1346+ // Add stack size ( iPad has 100 stack size limit )
 1347+ var stack = getStack( arguments.callee );
 1348+ return stack;
 1349+ }
 1350+
 1351+ // Setup the local mwOnLoadFunctions array:
 1352+ var mwOnLoadFunctions = [];
 1353+
 1354+ // mw Ready flag ( set once mwEmbed is ready )
 1355+ var mwReadyFlag = false;
 1356+
 1357+ /**
 1358+ * Enables load hooks to run once mwEmbeed is "ready" Will ensure jQuery is
 1359+ * available, is in the $j namespace and mw interfaces and configuration has
 1360+ * been loaded and applied
 1361+ *
 1362+ * This is different from jQuery(document).ready() ( jQuery ready is not
 1363+ * friendly with dynamic includes and not friendly with core interface
 1364+ * asynchronous build out. )
 1365+ *
 1366+ * @param {Function}
 1367+ * callback Function to run once DOM and jQuery are ready
 1368+ */
 1369+ mw.ready = function( callback ) {
 1370+ if( mwReadyFlag === false ) {
 1371+ // Add the callbcak to the onLoad function stack
 1372+ mwOnLoadFunctions.push ( callback );
 1373+ } else {
 1374+ // If mwReadyFlag is already "true" issue the callback directly:
 1375+ callback();
 1376+ }
 1377+ };
 1378+
 1379+ /**
 1380+ * Runs all the queued functions called by mwEmbedSetup
 1381+ */
 1382+ mw.runReadyFunctions = function ( ) {
 1383+ mw.log('mw.runReadyFunctions: ' + mwOnLoadFunctions.length );
 1384+ // Run any pre-setup ready functions
 1385+ while( preMwEmbedReady.length ){
 1386+ preMwEmbedReady.shift()();
 1387+ }
 1388+ // Run all the queued functions:
 1389+ while( mwOnLoadFunctions.length ) {
 1390+ mwOnLoadFunctions.shift()();
 1391+ }
 1392+ // Sets mwReadyFlag to true so that future mw.ready run the
 1393+ // callback directly
 1394+ mwReadyFlag = true;
 1395+
 1396+ // Once we have run all the queued functions
 1397+ setTimeout(function(){
 1398+ mw.loader.runModuleLoadQueue();
 1399+ },1);
 1400+ };
 1401+
 1402+
 1403+ /**
 1404+ * Wrapper for jQuery getScript, Uses the scriptLoader if enabled
 1405+ *
 1406+ *
 1407+ * @param {String}
 1408+ * scriptRequest The requested path or resourceNames for the
 1409+ * scriptLoader
 1410+ * @param {Function}
 1411+ * callback Function to call once script is loaded
 1412+ */
 1413+ mw.getScript = function( scriptRequest, callback ) {
 1414+ // mw.log( "mw.getScript::" + scriptRequest );
 1415+ // Setup the local scope callback instace
 1416+ var myCallback = function(){
 1417+ if( callback ) {
 1418+ callback( scriptRequest );
 1419+ }
 1420+ };
 1421+ // Set the base url based scriptLoader availability & type of
 1422+ // scriptRequest
 1423+ // ( presently script loader only handles "classes" not relative urls:
 1424+ var scriptLoaderPath = mw.getResourceLoaderPath();
 1425+
 1426+ // Check if its a resource name, ( ie does not start with "/" and does
 1427+ // not include ://
 1428+ var isResourceName = ( scriptRequest.indexOf('://') == -1 && scriptRequest.indexOf('/') !== 0 )? true : false;
 1429+
 1430+ var ext = scriptRequest.substr( scriptRequest.lastIndexOf( '.' ), 4 ).toLowerCase();
 1431+ var isCssFile = ( ext == '.css') ? true : false ;
 1432+
 1433+ if( scriptLoaderPath && isResourceName ) {
 1434+ url = scriptLoaderPath + '?class=' + scriptRequest ;
 1435+ } else {
 1436+ // Add the mwEmbed path if a relative path request
 1437+ url = ( isResourceName ) ? mw.getMwEmbedPath() : '';
 1438+ url+= scriptRequest;
 1439+ }
 1440+
 1441+ // Add on the request parameters to the url:
 1442+ url += ( url.indexOf( '?' ) == -1 )? '?' : '&';
 1443+ url += mw.getUrlParam();
 1444+
 1445+ // Only log sciprts ( Css is logged via "add css" )
 1446+ if( !isCssFile ){
 1447+ mw.log( 'mw.getScript: ' + url );
 1448+ }
 1449+
 1450+ // If jQuery is available and debug is off load the script via jQuery
 1451+ // ( will use XHR if on same domain )
 1452+ if( mw.isset( 'window.jQuery' )
 1453+ && mw.getConfig( 'debug' ) === false
 1454+ && typeof $j != 'undefined'
 1455+ && mw.parseUri( url ).protocal != 'file'
 1456+ && !isCssFile )
 1457+ {
 1458+ $j.getScript( url, myCallback);
 1459+ return ;
 1460+ }
 1461+
 1462+ /**
 1463+ * No jQuery OR In debug mode OR Is css file :: inject the script
 1464+ * instead of doing an XHR eval
 1465+ */
 1466+
 1467+ // load style sheet directly if requested loading css
 1468+ if( isCssFile ){
 1469+ mw.getStyleSheet( url, myCallback);
 1470+ return ;
 1471+ }
 1472+
 1473+ // Load and bind manually: ( copied from jQuery ajax function )
 1474+ var head = document.getElementsByTagName("head")[ 0 ];
 1475+ var script = document.createElement("script");
 1476+ script.setAttribute( 'src', url );
 1477+
 1478+ // Attach handlers ( if using script loader it issues onDone callback as
 1479+ // well )
 1480+ script.onload = script.onreadystatechange = function() {
 1481+ if (!this.readyState || this.readyState == "loaded" || this.readyState == "complete") {
 1482+ myCallback();
 1483+ }
 1484+ };
 1485+ // mw.log(" append script: " + script.src );
 1486+ // Append the script to the DOM:
 1487+ head.appendChild( script );
 1488+ };
 1489+
 1490+ /**
 1491+ * Add a style sheet string to the document head
 1492+ *
 1493+ * @param {String}
 1494+ * cssResourceName Name of style sheet that has been defined
 1495+ * @param {String}
 1496+ * cssString Css Payload to be added to head of document
 1497+ */
 1498+ mw.addStyleString = function( cssResourceName, cssString ) {
 1499+ if( mw.style[ cssResourceName ] ) {
 1500+ mw.log(" Style: ( " + cssResourceName + ' ) already set' );
 1501+ return true;
 1502+ }
 1503+ // Set the style to true ( to not request it again )
 1504+ mw.style[ cssResourceName ] = true;
 1505+ // Add the spinner directly ( without jQuery in case we have to
 1506+ // dynamically load jQuery )
 1507+ mw.log( 'Adding style:' + cssResourceName + " to dom " );
 1508+ var styleNode = document.createElement('style');
 1509+ styleNode.type = "text/css";
 1510+ // Use cssText or createTextNode depending on browser:
 1511+ if( ( window.attachEvent && !window.opera ) ) {
 1512+ styleNode.styleSheet.cssText = cssString;
 1513+ } else {
 1514+ var styleText = document.createTextNode( cssString );
 1515+ styleNode.appendChild( styleText );
 1516+ }
 1517+ var head = document.getElementsByTagName("head")[0];
 1518+ head.appendChild( styleNode );
 1519+ };
 1520+
 1521+ /**
 1522+ * Get a style sheet and append the style sheet to the DOM
 1523+ *
 1524+ * @param {Mixed}
 1525+ * {String} url Url of the style sheet to be loaded {Function}
 1526+ * callback Function called once sheet is ready
 1527+ */
 1528+ mw.getStyleSheet = function( url , callback) {
 1529+ // Add URL params ( if not already included )
 1530+ if ( url.indexOf( '?' ) == -1 ) {
 1531+ url += '?' + mw.getUrlParam();
 1532+ }
 1533+
 1534+ // Check if style sheet is already included:
 1535+ var foundSheet = false;
 1536+ $j( 'link' ).each( function() {
 1537+ var currentSheet = $j( this) .attr( 'href' );
 1538+ var sheetParts = currentSheet.split('?');
 1539+ var urlParts = url.split('?');
 1540+ // if the base url's match check the parameters:
 1541+ if( sheetParts[0] == urlParts[0] && sheetParts[1]) {
 1542+ // Check if url params match ( sort to do string compare )
 1543+ if( sheetParts[1].split( '&' ).sort().join('') ==
 1544+ urlParts[1].split('&').sort().join('') ) {
 1545+ foundSheet = true;
 1546+ }
 1547+ }
 1548+ } );
 1549+ if( foundSheet ) {
 1550+ mw.log( 'skiped sheet: ' + url);
 1551+ if( callback) {
 1552+ callback();
 1553+ }
 1554+ return ;
 1555+ }
 1556+
 1557+ mw.log( ' add css: ' + url );
 1558+ $j( 'head' ).append(
 1559+ $j('<link />').attr( {
 1560+ 'rel' : 'stylesheet',
 1561+ 'type' : 'text/css',
 1562+ 'href' : url
 1563+ } )
 1564+ );
 1565+ // No easy way to check css "onLoad" attribute
 1566+ // In production sheets are loaded via resource loader and fire the
 1567+ // onDone function call.
 1568+ if( callback ) {
 1569+ callback();
 1570+ }
 1571+ };
 1572+
 1573+ mw.getRelativeMwEmbedPath = function(){
 1574+ return mw.getMwEmbedPath(true);
 1575+ };
 1576+ /**
 1577+ * Get the path to the mwEmbed folder
 1578+ */
 1579+ mw.getMwEmbedPath = function( relativePath ) {
 1580+ // Get mwEmbed src:
 1581+ var src = mw.getMwEmbedSrc();
 1582+ var mwpath = null;
 1583+
 1584+ // Check for direct include of the mwEmbed.js
 1585+ if ( src.indexOf( 'mwEmbed.js' ) !== -1 ) {
 1586+ alert( 'Direct Refrece to mwEmbed is no longer suported, please update to ResourceLoader.php?class=window.jQuery,mwEmbed& instead');
 1587+ mwpath = src.substr( 0, src.indexOf( 'mwEmbed.js' ) );
 1588+ }
 1589+
 1590+ // Check for scriptLoader include of mwEmbed:
 1591+ if ( src.indexOf( 'mwResourceLoader.php' ) !== -1 ) {
 1592+ // Script loader is in the root of MediaWiki, Include the default
 1593+ // mwEmbed extension path:
 1594+ mwpath = src.substr( 0, src.indexOf( 'mwResourceLoader.php' ) ) + mw.getConfig( 'mediaWikiEmbedPath' );
 1595+ }
 1596+
 1597+ // resource loader has ResourceLoader name when local:
 1598+ if( src.indexOf( 'ResourceLoader.php' ) !== -1 ) {
 1599+ mwpath = src.substr( 0, src.indexOf( 'ResourceLoader.php' ) );
 1600+ }
 1601+
 1602+ // For static packages mwEmbed packages start with: "mwEmbed-"
 1603+ if( src.indexOf( 'mwEmbed-' ) !== -1 && src.indexOf( '-static' ) !== -1 ) {
 1604+ mwpath = src.substr( 0, src.indexOf( 'mwEmbed-' ) );
 1605+ }
 1606+
 1607+ // Error out if we could not get the path:
 1608+ if( mwpath === null ) {
 1609+ mw.log( "Error could not get mwEmbed path " );
 1610+ return ;
 1611+ }
 1612+
 1613+ // Update the cached var with the absolute path:
 1614+ if( !relativePath ){
 1615+ mwpath = mw.absoluteUrl( mwpath ) ;
 1616+ }
 1617+ return mwpath;
 1618+ };
 1619+
 1620+ /**
 1621+ * Get Script loader path
 1622+ *
 1623+ * @returns {String}|{Boolean} Url of the scriptLodaer false if the
 1624+ * scriptLoader is not used
 1625+ */
 1626+ mw.getResourceLoaderPath = function( ) {
 1627+ var src = mw.getMwEmbedSrc();
 1628+ if ( src.indexOf( 'mwResourceLoader.php' ) !== -1 ||
 1629+ src.indexOf( 'ResourceLoader.php' ) !== -1 )
 1630+ {
 1631+ // Return just the script part of the url
 1632+ return src.split('?')[0];
 1633+ }
 1634+ return false;
 1635+ };
 1636+ /**
 1637+ * Given a float number of seconds, returns npt format response. ( ignore
 1638+ * days for now )
 1639+ *
 1640+ * @param {Float}
 1641+ * sec Seconds
 1642+ * @param {Boolean}
 1643+ * verbose If hours and milliseconds should padded be displayed.
 1644+ * @return {Float} String npt format
 1645+ */
 1646+ mw.seconds2npt = function( sec, verbose ) {
 1647+ if ( isNaN( sec ) ) {
 1648+ mw.log("Warning: trying to get npt time on NaN:" + sec);
 1649+ return '0:00:00';
 1650+ }
 1651+
 1652+ var tm = mw.seconds2Measurements( sec );
 1653+
 1654+ // Round the number of seconds to the required number of significant
 1655+ // digits
 1656+ if ( verbose ) {
 1657+ tm.seconds = Math.round( tm.seconds * 1000 ) / 1000;
 1658+ } else {
 1659+ tm.seconds = Math.round( tm.seconds );
 1660+ }
 1661+ if ( tm.seconds < 10 ){
 1662+ tm.seconds = '0' + tm.seconds;
 1663+ }
 1664+ if( tm.hours == 0 && !verbose ){
 1665+ hoursStr = '';
 1666+ } else {
 1667+ if ( tm.minutes < 10 && verbose) {
 1668+ tm.minutes = '0' + tm.minutes;
 1669+ }
 1670+
 1671+ if( tm.hours < 10 && verbose){
 1672+ tm.hours = '0' + tm.hours;
 1673+ }
 1674+
 1675+ hoursStr = tm.hours + ':';
 1676+ }
 1677+ return hoursStr + tm.minutes + ":" + tm.seconds;
 1678+ };
 1679+ /**
 1680+ * Given seconds return array with 'days', 'hours', 'min', 'seconds'
 1681+ *
 1682+ * @param {float}
 1683+ * sec Seconds to be converted into time measurements
 1684+ */
 1685+ mw.seconds2Measurements = function ( sec ){
 1686+ var tm = {};
 1687+ tm.days = Math.floor( sec / ( 3600 * 24 ) );
 1688+ tm.hours = Math.floor( sec / 3600 );
 1689+ tm.minutes = Math.floor( ( sec / 60 ) % 60 );
 1690+ tm.seconds = sec % 60;
 1691+ return tm;
 1692+ };
 1693+
 1694+ /**
 1695+ * Given a float number of seconds, returns npt format response. ( ignore
 1696+ * days for now )
 1697+ *
 1698+ * @param {Float}
 1699+ * sec Seconds
 1700+ * @param {Boolean}
 1701+ * verbose If hours and milliseconds should padded be displayed.
 1702+ * @return {Float} String npt format
 1703+ */
 1704+ mw.npt2seconds = function ( npt_str ) {
 1705+ if ( !npt_str ) {
 1706+ // mw.log('npt2seconds:not valid ntp:'+ntp);
 1707+ return false;
 1708+ }
 1709+ // Strip {npt:}01:02:20 or 32{s} from time if present
 1710+ npt_str = npt_str.replace( /npt:|s/g, '' );
 1711+
 1712+ var hour = 0;
 1713+ var min = 0;
 1714+ var sec = 0;
 1715+
 1716+ times = npt_str.split( ':' );
 1717+ if ( times.length == 3 ) {
 1718+ sec = times[2];
 1719+ min = times[1];
 1720+ hour = times[0];
 1721+ } else if ( times.length == 2 ) {
 1722+ sec = times[1];
 1723+ min = times[0];
 1724+ } else {
 1725+ sec = times[0];
 1726+ }
 1727+ // Sometimes a comma is used instead of period for ms
 1728+ sec = sec.replace( /,\s?/, '.' );
 1729+ // Return seconds float
 1730+ return parseInt( hour * 3600 ) + parseInt( min * 60 ) + parseFloat( sec );
 1731+ };
 1732+
 1733+ // Local mwEmbedSrc variable ( for cache of mw.getMwEmbedSrc )
 1734+ var mwEmbedSrc = null;
 1735+
 1736+ /**
 1737+ * Gets the mwEmbed script src attribute
 1738+ */
 1739+ mw.getMwEmbedSrc = function() {
 1740+ if ( mwEmbedSrc ) {
 1741+ return mwEmbedSrc;
 1742+ }
 1743+
 1744+ // Get all the javascript includes:
 1745+ var js_elements = document.getElementsByTagName( "script" );
 1746+ for ( var i = 0; i < js_elements.length; i++ ) {
 1747+ // Check for mwEmbed.js and/or script loader
 1748+ var src = js_elements[i].getAttribute( "src" );
 1749+ if ( src ) {
 1750+ if ( // Check for mwEmbed.js ( debug mode )
 1751+ ( src.indexOf( 'mwEmbed.js' ) !== -1 && src.indexOf( 'MediaWiki:Gadget') == -1 )
 1752+ || // Check for resource loader
 1753+ (
 1754+ ( src.indexOf( 'mwResourceLoader.php' ) !== -1 || src.indexOf( 'ResourceLoader.php' ) !== -1 )
 1755+ &&
 1756+ src.indexOf( 'mwEmbed' ) !== -1
 1757+ )
 1758+ || // Check for static mwEmbed package
 1759+ ( src.indexOf( 'mwEmbed' ) !== -1 && src.indexOf( 'static' ) !== -1 )
 1760+ ) {
 1761+ mwEmbedSrc = src;
 1762+ return mwEmbedSrc;
 1763+ }
 1764+ }
 1765+ }
 1766+ mw.log( 'Error: getMwEmbedSrc failed to get script path' );
 1767+ return false;
 1768+ };
 1769+
 1770+ // Local mwUrlParam variable ( for cache of mw.getUrlParam )
 1771+ var mwUrlParam = null;
 1772+
 1773+ /**
 1774+ * Get URL Parameters per parameters in the host script include
 1775+ */
 1776+ mw.getUrlParam = function() {
 1777+ if ( mwUrlParam ) {
 1778+ return mwUrlParam;
 1779+ }
 1780+
 1781+ var mwEmbedSrc = mw.getMwEmbedSrc();
 1782+ var req_param = '';
 1783+
 1784+ // If we already have a URI, add it to the param request:
 1785+ var urid = mw.parseUri( mwEmbedSrc ).queryKey['urid'];
 1786+
 1787+ // If we're in debug mode, get a fresh unique request key and pass on
 1788+ // "debug" param
 1789+ if ( mw.parseUri( mwEmbedSrc ).queryKey['debug'] == 'true' ) {
 1790+ mw.setConfig( 'debug', true );
 1791+ var d = new Date();
 1792+ req_param += 'urid=' + d.getTime() + '&debug=true';
 1793+
 1794+ } else if ( urid ) {
 1795+ // Just pass on the existing urid:
 1796+ req_param += 'urid=' + urid;
 1797+ } else {
 1798+ // Otherwise, Use the mwEmbed version
 1799+ req_param += 'urid=' + mw.version;
 1800+ }
 1801+
 1802+ // Add the language param if present:
 1803+ var langKey = mw.parseUri( mwEmbedSrc ).queryKey['uselang'];
 1804+ if ( langKey )
 1805+ req_param += '&uselang=' + langKey;
 1806+
 1807+ // Update the local cache and return the value
 1808+ mwUrlParam = req_param;
 1809+ return mwUrlParam;
 1810+ };
 1811+
 1812+ /**
 1813+ * Replace url parameters via newParams key value pairs
 1814+ *
 1815+ * @param {String}
 1816+ * url Source url to be updated
 1817+ * @param {Object}
 1818+ * newParams key, value paris to swap in
 1819+ * @return {String} the updated url
 1820+ */
 1821+ mw.replaceUrlParams = function( url, newParams ) {
 1822+ var parsedUrl = mw.parseUri( url );
 1823+
 1824+ if ( parsedUrl.protocol != '' ) {
 1825+ var new_url = parsedUrl.protocol + '://' + parsedUrl.authority + parsedUrl.path + '?';
 1826+ } else {
 1827+ var new_url = parsedUrl.path + '?';
 1828+ }
 1829+
 1830+ // Merge new params:
 1831+ for( var key in newParams ) {
 1832+ parsedUrl.queryKey[ key ] = newParams[ key ];
 1833+ }
 1834+
 1835+ // Output to new_url
 1836+ var amp = '';
 1837+ for ( var key in parsedUrl.queryKey ) {
 1838+ var val = parsedUrl.queryKey[ key ];
 1839+ new_url += amp + key + '=' + val;
 1840+ amp = '&';
 1841+ }
 1842+ return new_url;
 1843+ };
 1844+
 1845+ /**
 1846+ * parseUri 1.2.2 (c) Steven Levithan <stevenlevithan.com> MIT License
 1847+ */
 1848+ mw.parseUri = function (str) {
 1849+ var o = mw.parseUri.options,
 1850+ m = o.parser[o.strictMode ? "strict" : "loose"].exec(str),
 1851+ uri = {},
 1852+ i = 14;
 1853+
 1854+ while (i--) uri[o.key[i]] = m[i] || "";
 1855+
 1856+ uri[o.q.name] = {};
 1857+ uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) {
 1858+ if ($1) uri[o.q.name][$1] = $2;
 1859+ });
 1860+
 1861+ return uri;
 1862+ };
 1863+
 1864+ /**
 1865+ * Parse URI function
 1866+ *
 1867+ * For documentation on its usage see:
 1868+ * http://stevenlevithan.com/demo/parseuri/js/
 1869+ */
 1870+ mw.parseUri.options = {
 1871+ strictMode: false,
 1872+ key: ["source", "protocol", "authority", "userInfo", "user", "password", "host",
 1873+ "port", "relative", "path", "directory", "file", "query", "anchor"],
 1874+ q: {
 1875+ name: "queryKey",
 1876+ parser: /(?:^|&)([^&=]*)=?([^&]*)/g
 1877+ },
 1878+ parser: {
 1879+ strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
 1880+ loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
 1881+ }
 1882+ };
 1883+
 1884+ /**
 1885+ * getAbsoluteUrl takes a src and returns the absolute location given the
 1886+ * document.URL or a contextUrl param
 1887+ *
 1888+ * @param {String}
 1889+ * src path or url
 1890+ * @param {String}
 1891+ * contextUrl The domain / context for creating an absolute url
 1892+ * from a relative path
 1893+ * @return {String} absolute url
 1894+ */
 1895+mw.absoluteUrl = function( src, contextUrl ) {
 1896+
 1897+ var parsedSrc = mw.parseUri( src );
 1898+
 1899+ // Source is already absolute return:
 1900+ if( parsedSrc.protocol != '') {
 1901+ return src;
 1902+ }
 1903+
 1904+ // Get parent Url location the context URL
 1905+ if( !contextUrl ) {
 1906+ contextUrl = document.URL;
 1907+ }
 1908+ var parsedUrl = mw.parseUri( contextUrl );
 1909+
 1910+ // Check for IE local file that does not flip the slashes
 1911+ if( parsedUrl.directory == '' && parsedUrl.protocol == 'file' ){
 1912+ // pop off the file
 1913+ var fileUrl = contextUrl.split( '\\');
 1914+ fileUrl.pop();
 1915+ return fileUrl.join('\\') + '\\' + src;
 1916+ }
 1917+
 1918+ // Check for leading slash:
 1919+ if( src.indexOf( '/' ) === 0 ) {
 1920+ return parsedUrl.protocol + '://' + parsedUrl.authority + src;
 1921+ }else{
 1922+ return parsedUrl.protocol + '://' + parsedUrl.authority + parsedUrl.directory + src;
 1923+ }
 1924+ };
 1925+ /**
 1926+ * Check if a given source string is likely a url
 1927+ *
 1928+ * @return {boolean} true if a url false if a string
 1929+ */
 1930+ mw.isUrl = function( src ){
 1931+ var parsedSrc = mw.parseUri( src );
 1932+ // if the url is just a string source and host will match
 1933+ return ( parsedSrc.host != parsedSrc.source );
 1934+ };
 1935+
 1936+ /**
 1937+ * Escape quotes in a text string
 1938+ *
 1939+ * @param {String}
 1940+ * text String to be escaped
 1941+ * @return {string} escaped text string
 1942+ */
 1943+ mw.escapeQuotes = function( text ) {
 1944+ var re = new RegExp("'","g");
 1945+ text = text.replace(re,"\\'");
 1946+ re = new RegExp("\\n","g");
 1947+ text = text.replace(re,"\\n");
 1948+ return mw.escapeQuotesHTML(text);
 1949+ };
 1950+
 1951+ /**
 1952+ * Escape an HTML text string
 1953+ *
 1954+ * @param {String}
 1955+ * text String to be escaped
 1956+ * @return {string} escaped text html string
 1957+ */
 1958+ mw.escapeQuotesHTML = function( text ) {
 1959+ var replaceMap = {
 1960+ "&" : "&amp;",
 1961+ '"' : "&quot;",
 1962+ '<' : "&lt;",
 1963+ '>' : "&gt;"
 1964+ };
 1965+ for( var i in replaceMap ){
 1966+ text = text.split(i).join( replaceMap[i]);
 1967+ }
 1968+ return text;
 1969+ };
 1970+
 1971+
 1972+ // Array of setup functions
 1973+ var mwSetupFunctions = [];
 1974+
 1975+ /**
 1976+ * Add a function to be run during setup ( prior to mw.ready) this is useful
 1977+ * for building out interfaces that should be ready before mw.ready is
 1978+ * called.
 1979+ *
 1980+ * @param {callback}
 1981+ * Function Callback function must accept a ready function
 1982+ * callback to be called once setup is done
 1983+ */
 1984+ mw.addSetupHook = function( callback ) {
 1985+ mwSetupFunctions.push ( callback ) ;
 1986+ };
 1987+
 1988+ /**
 1989+ * One time "setup" for mwEmbed run onDomReady ( so calls to setConfg apply
 1990+ * to setup )
 1991+ */
 1992+ // Flag to ensure setup is only run once:
 1993+ var mwSetupFlag = false;
 1994+ mw.setupMwEmbed = function ( ) {
 1995+ // Only run the setup once:
 1996+ if( mwSetupFlag ) {
 1997+ return ;
 1998+ }
 1999+ mwSetupFlag = true;
 2000+
 2001+ mw.log( 'mw:setupMwEmbed SRC:: ' + mw.getMwEmbedSrc() );
 2002+
 2003+ // Check core mwEmbed loader.js file ( to get configuration and paths )
 2004+ mw.checkCoreLoaderFile( function(){
 2005+ // Make sure we have jQuery
 2006+ mw.load( 'window.jQuery', function() {
 2007+
 2008+ // Add jQuery to $j var.
 2009+ if ( ! window[ '$j' ] ) {
 2010+ window[ '$j' ] = jQuery.noConflict();
 2011+ }
 2012+
 2013+ // Set up mvEmbed utility jQuery bindings
 2014+ mw.dojQueryBindings();
 2015+
 2016+ // Setup user config:
 2017+ mw.setupUserConfig( function(){
 2018+ // Get module loader.js, and language files
 2019+ // ( will hit callback directly if set via resource loader )
 2020+ mw.checkModuleLoaderFiles( function() {
 2021+
 2022+ // Set the User language
 2023+ if( typeof wgUserLanguage != 'undefined' && mw.isValidLang( wgUserLanguage) ) {
 2024+ mw.setConfig( 'userLanguage', wgUserLanguage );
 2025+ }else{
 2026+ // Grab it from the included url
 2027+ var langKey = mw.parseUri( mw.getMwEmbedSrc() ).queryKey['uselang'];
 2028+ if ( langKey && mw.isValidLang( langKey ) ) {
 2029+ mw.setConfig( 'userLanguage', langKey);
 2030+ }
 2031+ }
 2032+
 2033+ // Update the image path
 2034+ mw.setConfig( 'imagesPath', mw.getMwEmbedPath() + 'skins/common/images/' );
 2035+
 2036+ // Set up AJAX to not send dynamic URLs for loading
 2037+ // scripts
 2038+ $j.ajaxSetup( {
 2039+ cache: true
 2040+ } );
 2041+
 2042+ // Update the magic keywords
 2043+ mw.Language.magicSetup();
 2044+
 2045+
 2046+ // Special Hack for conditional jquery ui inclusion (
 2047+ // once
 2048+ // Usability extension
 2049+ // registers the jquery.ui skin in mw.style
 2050+ if( mw.hasJQueryUiCss() ){
 2051+ mw.style[ 'ui_' + mw.getConfig( 'jQueryUISkin' ) ] = true;
 2052+ }
 2053+
 2054+
 2055+ // Make sure style sheets are loaded:
 2056+ mw.load( ['mw.style.mwCommon'] , function(){
 2057+ // Run all the setup function hooks
 2058+ // NOTE: setup functions are added via addSetupHook
 2059+ // calls
 2060+ // and must include a callback.
 2061+ //
 2062+ // Once complete we can run .ready() queued
 2063+ // functions
 2064+ function runSetupFunctions() {
 2065+ if( mwSetupFunctions.length ) {
 2066+ mwSetupFunctions.shift()( function() {
 2067+ runSetupFunctions();
 2068+ } );
 2069+ }else{
 2070+ mw.runReadyFunctions();
 2071+ }
 2072+ }
 2073+ runSetupFunctions();
 2074+ } );
 2075+
 2076+ } );
 2077+ });
 2078+ });
 2079+ });
 2080+ };
 2081+
 2082+ /**
 2083+ * Checks for jquery ui css by name jquery-ui-1.7.2.css NOTE: this is a hack
 2084+ * for usability jquery-ui in the future usability should register a
 2085+ * resource in mw.skin
 2086+ *
 2087+ * @return true if found, return false if not found
 2088+ */
 2089+ mw.hasJQueryUiCss = function(){
 2090+ var hasUiCss = false;
 2091+ var cssStyleSheetNames = ['jquery-ui-1.7.2.css', 'jquery-ui.css'];
 2092+ // Load the jQuery ui skin if usability skin not set
 2093+ $j( 'link' ).each( function( na, linkNode ){
 2094+ $j.each( cssStyleSheetNames, function(inx, sheetName ){
 2095+ if( $j( linkNode ).attr( 'href' ).indexOf( sheetName ) != -1 ){
 2096+ hasUiCss = true;
 2097+ return true;
 2098+ }
 2099+ });
 2100+ } );
 2101+ // Check all the "style" nodes for @import for sheet name
 2102+ // xxx Note: we could do this a bit cleaner with regEx
 2103+ $j( 'style' ).each( function( na, styleNode ){
 2104+ $j.each( cssStyleSheetNames, function(inx, sheetName ){
 2105+ if( $j( styleNode ).text().indexOf( '@import' ) != -1
 2106+ &&
 2107+ $j( styleNode ).text().indexOf( sheetName ) != -1 )
 2108+ {
 2109+ hasUiCss=true;
 2110+ return true;
 2111+ }
 2112+ });
 2113+ });
 2114+ return hasUiCss;
 2115+ };
 2116+
 2117+ /**
 2118+ * Loads the core mwEmbed "loader.js" file config
 2119+ *
 2120+ * NOTE: if using the ScriptLoader all the loaders and localization
 2121+ * converters are included automatically
 2122+ *
 2123+ * @param {Function}
 2124+ * callback Function called once core loader file is loaded
 2125+ */
 2126+ mw.checkCoreLoaderFile = function( callback ) {
 2127+ // Check if we are using scriptloader ( handles loader include
 2128+ // automatically )
 2129+ if( mw.getResourceLoaderPath() ) {
 2130+ callback();
 2131+ return ;
 2132+ }
 2133+
 2134+ // Check if we are using a static package ( mwEmbed path includes
 2135+ // -static )
 2136+ if( mw.isStaticPackge() ){
 2137+ callback();
 2138+ return ;
 2139+ }
 2140+
 2141+ // Add the Core loader to the request
 2142+ // The follow code is ONLY RUN in debug / raw file mode
 2143+ mw.load( 'loader.js', callback );
 2144+ };
 2145+
 2146+ /**
 2147+ * Checks if the javascript is a static package ( not using resource loader )
 2148+ *
 2149+ * @return {boolean} true the included script is static false the included
 2150+ * script
 2151+ */
 2152+ mw.isStaticPackge = function(){
 2153+ var src = mw.getMwEmbedSrc();
 2154+ if( src.indexOf('-static') !== -1 ){
 2155+ return true;
 2156+ }
 2157+ return false;
 2158+ };
 2159+
 2160+ /**
 2161+ * Check for resource loader module loaders, and localization files
 2162+ *
 2163+ * NOTE: if using the ScriptLoader all the loaders and localization
 2164+ * converters are included automatically.
 2165+ */
 2166+ mw.checkModuleLoaderFiles = function( callback ) {
 2167+ mw.log( 'doLoaderCheck::' );
 2168+
 2169+ // Check if we are using scriptloader ( handles loader include
 2170+ // automatically )
 2171+ // Or if mwEmbed is a static package ( all resources are already loaded
 2172+ // )
 2173+ if( mw.getResourceLoaderPath() || mw.isStaticPackge() ) {
 2174+ callback();
 2175+ return ;
 2176+ }
 2177+
 2178+ // Load the configured modules / components
 2179+ // The follow code is ONLY RUN in debug / raw file mode
 2180+ var loaderRequest = [];
 2181+
 2182+ // Load enabled components
 2183+ var enabledComponents = mw.getConfig( 'coreComponents' );
 2184+ function loadEnabledComponents( enabledComponents ){
 2185+ if( ! enabledComponents.length ){
 2186+ // If no more components load modules::
 2187+
 2188+ // Add the enabledModules loaders:
 2189+ var enabledModules = mw.getConfig( 'enabledModules' );
 2190+ loadEnabledModules( enabledModules );
 2191+ return ;
 2192+ }
 2193+ var componentName = enabledComponents.shift();
 2194+ componentName = componentName.replace(/"/g,'');
 2195+ mw.load( componentName, function(){
 2196+ loadEnabledComponents( enabledComponents );
 2197+ } );
 2198+ }
 2199+ loadEnabledComponents( enabledComponents );
 2200+
 2201+
 2202+ // Set the loader context and get each loader individually
 2203+ function loadEnabledModules( enabledModules ){
 2204+ if( ! enabledModules.length ){
 2205+ // If no more modules left load the LanguageFile
 2206+ addLanguageFile();
 2207+ return ;
 2208+ }
 2209+ var moduleName = enabledModules.shift();
 2210+ moduleName = moduleName.replace(/"/g,'');
 2211+ mw.setConfig( 'loaderContext', 'modules/' + moduleName + '/' );
 2212+ mw.load( 'modules/' + moduleName + '/loader.js', function(){
 2213+ loadEnabledModules( enabledModules );
 2214+ } );
 2215+ }
 2216+
 2217+ function addLanguageFile(){
 2218+ // Add the language file
 2219+ var langLoaderRequest = [];
 2220+
 2221+ if( mw.getConfig( 'userLanguage' ) ) {
 2222+ var langCode = mw.getConfig( 'userLanguage' );
 2223+
 2224+ // Load the language resource if not default 'en'
 2225+ var transformKey = mw.getLangTransformKey( langCode );
 2226+ if( transformKey != 'en' ){
 2227+ // Upper case the first letter:
 2228+ langCode = langCode.substr(0,1).toUpperCase() + langCode.substr( 1, langCode.length );
 2229+ langLoaderRequest.push( 'languages/classes/Language' +
 2230+ langCode + '.js' );
 2231+ }
 2232+
 2233+ }
 2234+ if ( ! langLoaderRequest.length ) {
 2235+ addLocalSettings();
 2236+ return ;
 2237+ }
 2238+
 2239+ // Load the language if set
 2240+ mw.load( langLoaderRequest, function(){
 2241+ mw.log( 'Done moduleLoaderCheck request' );
 2242+ addLocalSettings();
 2243+ } );
 2244+ }
 2245+ function addLocalSettings(){
 2246+ var continueCallback = function(){
 2247+ // Set the mwModuleLoaderCheckFlag flag to true
 2248+ mwModuleLoaderCheckFlag = true;
 2249+ callback();
 2250+ };
 2251+ if( mw.getConfig( 'LoadLocalSettings') != true ){
 2252+ continueCallback();
 2253+ return;
 2254+ }
 2255+ mw.log("Load loacal settings");
 2256+ mw.load( 'localSettings.js', function(){
 2257+ continueCallback();
 2258+ });
 2259+ }
 2260+
 2261+ };
 2262+
 2263+ /**
 2264+ * Checks if a css style rule exists
 2265+ *
 2266+ * On a page with lots of rules it can take some time so avoid calling this
 2267+ * function where possible and cache its result
 2268+ *
 2269+ * NOTE: this only works for style sheets on the same domain :(
 2270+ *
 2271+ * @param {String}
 2272+ * styleRule Style rule name to check
 2273+ * @return {Boolean} true if the rule exists false if the rule does not
 2274+ * exist
 2275+ */
 2276+ mw.styleRuleExists = function ( styleRule ) {
 2277+ // Set up the skin paths configuration
 2278+ for( var i=0 ; i < document.styleSheets.length ; i++ ) {
 2279+ var rules = null;
 2280+ try{
 2281+ if ( document.styleSheets[i].cssRules )
 2282+ rules = document.styleSheets[i].cssRules;
 2283+ else if (document.styleSheets[0].rules)
 2284+ rules = document.styleSheets[i].rules;
 2285+ for(var j=0 ; j < rules.length ; j++ ) {
 2286+ var rule = rules[j].selectorText;
 2287+ if( rule && rule.indexOf( styleRule ) != -1 ) {
 2288+ return true;
 2289+ }
 2290+ }
 2291+ }catch ( e ) {
 2292+ mw.log( 'Error: cant check rule on cross domain style sheet:' + document.styleSheets[i].href );
 2293+ }
 2294+ }
 2295+ return false;
 2296+ };
 2297+
 2298+ // Flag to register the domReady has been called
 2299+ var mwDomReadyFlag = false;
 2300+
 2301+ // Flag to register if the domreadyHooks have been called
 2302+ var mwModuleLoaderCheckFlag = false;
 2303+
 2304+ /**
 2305+ * This will get called when the DOM is ready Will check configuration and
 2306+ * issue a mw.setupMwEmbed call if needed
 2307+ */
 2308+ mw.domReady = function ( ) {
 2309+ if( mwDomReadyFlag ) {
 2310+ return ;
 2311+ }
 2312+ mw.log( 'run:domReady:: ' + document.getElementsByTagName('video').length );
 2313+ // Set the onDomReady Flag
 2314+ mwDomReadyFlag = true;
 2315+
 2316+ // Give us a chance to get to the bottom of the script.
 2317+ // When loading mwEmbed asynchronously the dom ready gets called
 2318+ // directly and in some browsers beets the $j = jQuery.noConflict();
 2319+ // call
 2320+ // and causes symbol undefined errors.
 2321+ setTimeout(function(){
 2322+ mw.setupMwEmbed();
 2323+ },1);
 2324+ };
 2325+
 2326+ /**
 2327+ * A version comparison utility function Handles version of types
 2328+ * {Major}.{MinorN}.{Patch}
 2329+ *
 2330+ * Note this just handles version numbers not patch letters.
 2331+ *
 2332+ * @param {String}
 2333+ * minVersion Minnium version needed
 2334+ * @param {String}
 2335+ * clientVersion Client version to be checked
 2336+ *
 2337+ * @return true if the version is at least of minVersion false if the
 2338+ * version is less than minVersion
 2339+ */
 2340+ mw.versionIsAtLeast = function( minVersion, clientVersion ) {
 2341+ var minVersionParts = minVersion.split('.');
 2342+ var clientVersionParts = clientVersion.split('.');
 2343+ for( var i =0; i < minVersionParts.length; i++ ) {
 2344+ if( parseInt( clientVersionParts[i] ) > parseInt( minVersionParts[i] ) ) {
 2345+ return true;
 2346+ }
 2347+ if( parseInt( clientVersionParts[i] ) < parseInt( minVersionParts[i] ) ) {
 2348+ return false;
 2349+ }
 2350+ }
 2351+ // Same version:
 2352+ return true;
 2353+ };
 2354+
 2355+ /**
 2356+ * Utility jQuery bindings Setup after jQuery is available ).
 2357+ */
 2358+ mw.dojQueryBindings = function() {
 2359+ mw.log( 'mw.dojQueryBindings' );
 2360+ ( function( $ ) {
 2361+
 2362+ /**
 2363+ * Runs all the triggers on all the named bindings of an object with
 2364+ * a single callback
 2365+ *
 2366+ * NOTE THIS REQUIRES JQUERY 1.4.2 and above
 2367+ *
 2368+ * Normal jQuery tirgger calls will run the callback directly
 2369+ * multiple times for every binded function.
 2370+ *
 2371+ * With triggerQueueCallback() callback is not called until all the
 2372+ * binded events have been run.
 2373+ *
 2374+ * @param {string}
 2375+ * triggerName Name of trigger to be run
 2376+ * @param {object=}
 2377+ * arguments Optional arguments object to be passed to
 2378+ * the callback
 2379+ * @param {function}
 2380+ * callback Function called once all triggers have been
 2381+ * run
 2382+ *
 2383+ */
 2384+ $.fn.triggerQueueCallback = function( triggerName, triggerParam, callback ){
 2385+ var targetObject = this;
 2386+ // Support optional triggerParam data
 2387+ if( !callback && typeof triggerParam == 'function' ){
 2388+ callback = triggerParam;
 2389+ triggerParam = null;
 2390+ }
 2391+ // Support namespaced event segmentation ( jQuery
 2392+ var triggerBaseName = triggerName.split(".")[0];
 2393+ var triggerNamespace = triggerName.split(".")[1];
 2394+ // Get the callback set
 2395+ var callbackSet = [];
 2396+ if( ! triggerNamespace ){
 2397+ callbackSet = $j( targetObject ).data( 'events' )[ triggerBaseName ];
 2398+ } else{
 2399+ $j.each( $j( targetObject ).data( 'events' )[ triggerBaseName ], function( inx, bindObject ){
 2400+ if( bindObject.namespace == triggerNamespace ){
 2401+ callbackSet.push( bindObject );
 2402+ }
 2403+ });
 2404+ }
 2405+
 2406+ if( !callbackSet || callbackSet.length === 0 ){
 2407+ mw.log( '"mwEmbed::jQuery.triggerQueueCallback: No events run the callback directly: ' + triggerName );
 2408+ // No events run the callback directly
 2409+ callback();
 2410+ return ;
 2411+ }
 2412+
 2413+ // Set the callbackCount
 2414+ var callbackCount = ( callbackSet.length )? callbackSet.length : 1;
 2415+ // mw.log("mwEmbed::jQuery.triggerQueueCallback: " + triggerName
 2416+ // + ' number of queued functions:' + callbackCount );
 2417+ var callInx = 0;
 2418+ var doCallbackCheck = function() {
 2419+ // mw.log( 'callback for: ' + mw.getCallStack()[0] +
 2420+ // callInx);
 2421+ callInx++;
 2422+ if( callInx == callbackCount ){
 2423+ callback();
 2424+ }
 2425+ };
 2426+ if( triggerParam ){
 2427+ $( this ).trigger( triggerName, [ triggerParam, doCallbackCheck ]);
 2428+ } else {
 2429+ $( this ).trigger( triggerName, [ doCallbackCheck ] );
 2430+ }
 2431+ };
 2432+
 2433+ /**
 2434+ * Set a given selector html to the loading spinner:
 2435+ */
 2436+ $.fn.loadingSpinner = function( ) {
 2437+ if ( this ) {
 2438+ $( this ).html(
 2439+ $( '<div />' )
 2440+ .addClass( "loadingSpinner" )
 2441+ );
 2442+ }
 2443+ return this;
 2444+ };
 2445+
 2446+ /**
 2447+ * Add an absolute overlay spinner useful for cases where the
 2448+ * element does not display child elements, ( images, video )
 2449+ */
 2450+ $.fn.getAbsoluteOverlaySpinner = function(){
 2451+ var pos = $j( this ).offset();
 2452+ var posLeft = ( $j( this ).width() ) ?
 2453+ parseInt( pos.left + ( .5 * $j( this ).width() ) -16 ) :
 2454+ pos.left + 30;
 2455+
 2456+ var posTop = ( $j( this ).height() ) ?
 2457+ parseInt( pos.top + ( .5 * $j( this ).height() ) -16 ) :
 2458+ pos.top + 30;
 2459+
 2460+ var $spinner = $j('<div />')
 2461+ .loadingSpinner()
 2462+ .css({
 2463+ 'width' : 32,
 2464+ 'height' : 32,
 2465+ 'position': 'absolute',
 2466+ 'top' : posTop + 'px',
 2467+ 'left' : posLeft + 'px'
 2468+ });
 2469+ $j('body').append( $spinner );
 2470+ return $spinner;
 2471+ };
 2472+
 2473+ /**
 2474+ * dragDrop file loader
 2475+ */
 2476+ $.fn.dragFileUpload = function ( conf ) {
 2477+ if ( this.selector ) {
 2478+ var _this = this;
 2479+ // load the dragger and "setup"
 2480+ mw.load( ['$j.fn.dragDropFile'], function() {
 2481+ $j( _this.selector ).dragDropFile();
 2482+ } );
 2483+ }
 2484+ };
 2485+
 2486+ /**
 2487+ * Shortcut to a themed button Should be depreciated for $.button
 2488+ * bellow
 2489+ */
 2490+ $.btnHtml = function( msg, styleClass, iconId, opt ) {
 2491+ if ( !opt )
 2492+ opt = { };
 2493+ var href = ( opt.href ) ? opt.href : '#';
 2494+ var target_attr = ( opt.target ) ? ' target="' + opt.target + '" ' : '';
 2495+ var style_attr = ( opt.style ) ? ' style="' + opt.style + '" ' : '';
 2496+ return '<a href="' + href + '" ' + target_attr + style_attr +
 2497+ ' class="ui-state-default ui-corner-all ui-icon_link ' +
 2498+ styleClass + '"><span class="ui-icon ui-icon-' + iconId + '" ></span>' +
 2499+ '<span class="btnText">' + msg + '</span></a>';
 2500+ };
 2501+
 2502+ // Shortcut to jQuery button ( should replace all btnHtml with
 2503+ // button )
 2504+ var mw_default_button_options = {
 2505+ // The class name for the button link
 2506+ 'class' : '',
 2507+
 2508+ // The style properties for the button link
 2509+ 'style' : { },
 2510+
 2511+ // The text of the button link
 2512+ 'text' : '',
 2513+
 2514+ // The icon id that precedes the button link:
 2515+ 'icon' : 'carat-1-n'
 2516+ };
 2517+
 2518+ $.button = function( options ) {
 2519+ var options = $j.extend( {}, mw_default_button_options, options);
 2520+
 2521+ // Button:
 2522+ var $button = $j('<a />')
 2523+ .attr('href', '#')
 2524+ .addClass( 'ui-state-default ui-corner-all ui-icon_link' );
 2525+ // Add css if set:
 2526+ if( options.css ) {
 2527+ $button.css( options.css );
 2528+ }
 2529+
 2530+ if( options['class'] ) {
 2531+ $button.addClass( options['class'] );
 2532+ }
 2533+
 2534+ // return the button:
 2535+ $button.append(
 2536+ $j('<span />').addClass( 'ui-icon ui-icon-' + options.icon ),
 2537+ $j('<span />').addClass( 'btnText' )
 2538+ )
 2539+ .buttonHover(); // add buttonHover binding;
 2540+
 2541+ if( options.text ){
 2542+ $button.find('.btnText').text( options.text );
 2543+ } else {
 2544+ $button.css('padding', '1em');
 2545+ }
 2546+ return $button;
 2547+ };
 2548+
 2549+ // Shortcut to bind hover state
 2550+ $.fn.buttonHover = function() {
 2551+ $j( this ).hover(
 2552+ function() {
 2553+ $j( this ).addClass( 'ui-state-hover' );
 2554+ },
 2555+ function() {
 2556+ $j( this ).removeClass( 'ui-state-hover' );
 2557+ }
 2558+ );
 2559+ return this;
 2560+ };
 2561+
 2562+ /**
 2563+ * Resize a dialog to fit the window
 2564+ *
 2565+ * @param {Object}
 2566+ * options horizontal and vertical space ( default 50 )
 2567+ */
 2568+ $.fn.dialogFitWindow = function( options ) {
 2569+ var opt_default = { 'hspace':50, 'vspace':50 };
 2570+ if ( !options )
 2571+ var options = { };
 2572+ options = $j.extend( opt_default, options );
 2573+ $j( this.selector ).dialog( 'option', 'width', $j( window ).width() - options.hspace );
 2574+ $j( this.selector ).dialog( 'option', 'height', $j( window ).height() - options.vspace );
 2575+ $j( this.selector ).dialog( 'option', 'position', 'center' );
 2576+ // update the child position: (some of this should be pushed
 2577+ // up-stream via dialog config options
 2578+ $j( this.selector + '~ .ui-dialog-buttonpane' ).css( {
 2579+ 'position':'absolute',
 2580+ 'left':'0px',
 2581+ 'right':'0px',
 2582+ 'bottom':'0px'
 2583+ } );
 2584+ };
 2585+
 2586+ } )( jQuery );
 2587+ };
 2588+
 2589+} )( window.mw );
 2590+
 2591+
 2592+/**
 2593+ * Set DOM-ready call We copy jQuery( document ).ready here since sometimes
 2594+ * mwEmbed.js is included without jQuery and we need our own "ready" system so
 2595+ * that mwEmbed interfaces can support async built out and the include of
 2596+ * jQuery.
 2597+ */
 2598+// Check if already ready:
 2599+if ( document.readyState === "complete" ) {
 2600+ mw.domReady();
 2601+}
 2602+
 2603+// Cleanup functions for the document ready method
 2604+if ( document.addEventListener ) {
 2605+ DOMContentLoaded = function() {
 2606+ document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
 2607+ mw.domReady();
 2608+ };
 2609+
 2610+} else if ( document.attachEvent ) {
 2611+ DOMContentLoaded = function() {
 2612+ // Make sure body exists, at least, in case IE gets a little overzealous
 2613+ // (ticket #5443).
 2614+ if ( document.readyState === "complete" ) {
 2615+ document.detachEvent( "onreadystatechange", DOMContentLoaded );
 2616+ mw.domReady();
 2617+ }
 2618+ };
 2619+}
 2620+// Mozilla, Opera and webkit nightlies currently support this event
 2621+if ( document.addEventListener ) {
 2622+ // Use the handy event callback
 2623+ document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
 2624+
 2625+ // A fallback to window.onload, that will always work
 2626+ window.addEventListener( "load", mw.domReady, false );
 2627+
 2628+// If IE event model is used
 2629+} else if ( document.attachEvent ) {
 2630+ // ensure firing before onload,
 2631+ // maybe late but safe also for iframes
 2632+ document.attachEvent("onreadystatechange", DOMContentLoaded);
 2633+
 2634+ // A fallback to window.onload, that will always work
 2635+ window.attachEvent( "onload", mw.domReady );
 2636+
 2637+ // If IE and not a frame
 2638+ // continually check to see if the document is ready
 2639+ var toplevel = false;
 2640+
 2641+ try {
 2642+ toplevel = window.frameElement == null;
 2643+ } catch(e) {}
 2644+
 2645+ if ( document.documentElement.doScroll && toplevel ) {
 2646+ doScrollCheck();
 2647+ }
 2648+}
 2649+// The DOM ready check for Internet Explorer
 2650+function doScrollCheck() {
 2651+ try {
 2652+ // If IE is used, use the trick by Diego Perini
 2653+ // http://javascript.nwbox.com/IEContentLoaded/
 2654+ document.documentElement.doScroll("left");
 2655+ } catch( error ) {
 2656+ setTimeout( doScrollCheck, 1 );
 2657+ return;
 2658+ }
 2659+ mw.domReady();
 2660+}
 2661+
 2662+// If using the resource loader and jQuery has not been set give a warning to
 2663+// the user:
 2664+// (this is needed because packaged loader.js files could refrence jQuery )
 2665+if( mw.getResourceLoaderPath() && !window.jQuery ) {
 2666+ mw.log( 'Error: jQuery is required for mwEmbed, please update your resource loader request' );
 2667+}
 2668+
 2669+if( mw.isStaticPackge() && !window.jQuery ){
 2670+ alert( 'Error: jQuery is required for mwEmbed ');
 2671+}
 2672+
 2673+/**
 2674+ * Hack to keep jQuery in $ when its already there, but also use noConflict to
 2675+ * get $j = jQuery
 2676+ *
 2677+ * This way sites that use $ for jQuery continue to work after including mwEmbed
 2678+ * javascript.
 2679+ *
 2680+ * Also if jQuery is included prior to mwEmbed we ensure $j is set
 2681+ */
 2682+
 2683+if( window.jQuery ){
 2684+ if( ! mw.versionIsAtLeast( '1.4.2', jQuery.fn.jquery ) ){
 2685+ if( window.console && window.console.log ) {
 2686+ console.log( 'Error mwEmbed requires jQuery 1.4 or above' );
 2687+ }
 2688+ }
 2689+ var dollarFlag = false;
 2690+ if( $ && $.fn && $.fn.jquery ) {
 2691+ // NOTE we could check the version of
 2692+ // jQuery and do a removal call if too old
 2693+ dollarFlag = true;
 2694+ }
 2695+ window[ '$j' ] = jQuery.noConflict();
 2696+ if( dollarFlag ) {
 2697+ window[ '$' ] = jQuery.noConflict();
 2698+ }
 2699+}
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/modules/MwEmbedSupport/README
@@ -0,0 +1,3 @@
 2+This is the mwEmbed Support module it supplies common functionality that other mwEmbed modules depend on.
 3+
 4+Modules can express the dependency as 'mwembed.support'
\ No newline at end of file
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/resources/README
@@ -0,0 +1,4 @@
 2+This is almost a direct copy of MediaWiki/resources
 3+
 4+Some mediaWiki specific code is removed and we rename the resource define file ( to not assume it
 5+stays in sync with mediaWiki )
\ No newline at end of file

Status & tagging log