r69090 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r69089‎ | r69090 | r69091 >
Date:11:34, 6 July 2010
Author:dale
Status:deferred (Comments)
Tags:
Comment:
* start of rewrite of sequenceEditor for new smilPlayer module.
* basic timeline, clip selection, and player integration.
* add-media-wizard and clip-edit functionality needs remains to be restored.
Modified paths:
  • /branches/MwEmbedStandAlone/loader.js (modified) (history)
  • /branches/MwEmbedStandAlone/modules/EmbedPlayer/mw.EmbedPlayer.js (modified) (history)
  • /branches/MwEmbedStandAlone/modules/EmbedPlayer/skins/mw.PlayerControlBuilder.js (modified) (history)
  • /branches/MwEmbedStandAlone/modules/SequenceEdit (added) (history)
  • /branches/MwEmbedStandAlone/modules/SequenceEdit/SequenceEdit.i18n.php (added) (history)
  • /branches/MwEmbedStandAlone/modules/SequenceEdit/css (added) (history)
  • /branches/MwEmbedStandAlone/modules/SequenceEdit/css/mw.style.SequenceEdit.css (added) (history)
  • /branches/MwEmbedStandAlone/modules/SequenceEdit/loader.js (added) (history)
  • /branches/MwEmbedStandAlone/modules/SequenceEdit/mw.FirefoggRender.js (added) (history)
  • /branches/MwEmbedStandAlone/modules/SequenceEdit/mw.SequenceEdit.js (added) (history)
  • /branches/MwEmbedStandAlone/modules/SequenceEdit/mw.SequenceEditKeyBindings.js (added) (history)
  • /branches/MwEmbedStandAlone/modules/SequenceEdit/mw.SequenceEditPlayer.js (added) (history)
  • /branches/MwEmbedStandAlone/modules/SequenceEdit/mw.SequenceEditTimeline.js (added) (history)
  • /branches/MwEmbedStandAlone/modules/SequenceEdit/tests (added) (history)
  • /branches/MwEmbedStandAlone/modules/SequenceEdit/tests/SampleEditorSequenceSmil.xml (added) (history)
  • /branches/MwEmbedStandAlone/modules/SequenceEdit/tests/Sequence_Editor.html (added) (history)
  • /branches/MwEmbedStandAlone/modules/SequenceEdit/tests/VideoRender.html (added) (history)
  • /branches/MwEmbedStandAlone/modules/SequenceEdit/tests/VideoRender.xml (added) (history)
  • /branches/MwEmbedStandAlone/modules/SequenceEdit/ui.layout (added) (history)
  • /branches/MwEmbedStandAlone/modules/SequenceEdit/ui.layout/ui.layout-1.2.0.js (added) (history)
  • /branches/MwEmbedStandAlone/modules/Sequencer (deleted) (history)
  • /branches/MwEmbedStandAlone/modules/SmilPlayer/loader.js (modified) (history)
  • /branches/MwEmbedStandAlone/modules/SmilPlayer/mw.EmbedPlayerSmil.js (modified) (history)
  • /branches/MwEmbedStandAlone/modules/SmilPlayer/mw.Smil.js (modified) (history)
  • /branches/MwEmbedStandAlone/modules/SmilPlayer/mw.SmilBody.js (modified) (history)
  • /branches/MwEmbedStandAlone/modules/SmilPlayer/mw.SmilBuffer.js (modified) (history)
  • /branches/MwEmbedStandAlone/modules/SmilPlayer/mw.SmilHooks.js (modified) (history)
  • /branches/MwEmbedStandAlone/modules/SmilPlayer/tests/VideoClipBegin.html (modified) (history)
  • /branches/MwEmbedStandAlone/modules/SmilPlayer/tests/VideoClipBeginSmil.xml (modified) (history)
  • /branches/MwEmbedStandAlone/modules/SmilPlayer/tests/VideoCrossFade.html (modified) (history)
  • /branches/MwEmbedStandAlone/mwEmbed.js (modified) (history)

Diff [purge]

Index: branches/MwEmbedStandAlone/loader.js
@@ -46,15 +46,15 @@
4747 * is transcluded into base mwEmbed class include.
4848 */
4949 var mwEnabledModuleList = [
50 - 'AddMedia',
51 - 'ClipEdit',
5250 'EmbedPlayer',
53 - 'ApiProxy',
54 - 'Sequencer',
5551 'TimedText',
5652 'SmilPlayer',
5753 'MediaRss',
58 - 'SwarmTransport'
 54+ 'SwarmTransport',
 55+ 'AddMedia',
 56+ 'ClipEdit',
 57+ 'SequenceEdit',
 58+ 'ApiProxy'
5959 ];
6060
6161 /**
Index: branches/MwEmbedStandAlone/mwEmbed.js
@@ -16,18 +16,18 @@
1717 */
1818
1919 /**
20 -* Setup the "mw" global:
21 -*/
 20+ * Setup the "mw" global:
 21+ */
2222 if ( typeof window.mw == 'undefined' ) {
2323 window.mw = { };
2424 }
2525
2626 /**
27 -* Set the mwEmbedVersion
28 -*/
 27+ * Set the mwEmbedVersion
 28+ */
2929 var MW_EMBED_VERSION = '1.1g';
3030
31 -// Globals to pre-set ready functions in dynamic loading of mwEmbed
 31+// Globals to pre-set ready functions in dynamic loading of mwEmbed
3232 if( typeof preMwEmbedReady == 'undefined'){
3333 var preMwEmbedReady = [];
3434 }
@@ -37,8 +37,8 @@
3838 }
3939
4040 /**
41 -* The global mw object:
42 -*/
 41+ * The global mw object:
 42+ */
4343 ( function( mw ) {
4444 // The version of mwEmbed
4545 mw.version = MW_EMBED_VERSION
@@ -46,31 +46,32 @@
4747 // List valid skins here:
4848 mw.validSkins = [ 'mvpcf', 'kskin' ];
4949
50 - // Storage variable for loaded style sheet keys
 50+ // Storage variable for loaded style sheet keys
5151 mw.style = { };
5252
5353 /**
54 - * Configuration System:
55 - */
 54+ * Configuration System:
 55+ */
5656
5757 // Local scope configuration var:
5858 if( !mwConfig ){
5959 var mwConfig = { };
6060 }
6161
62 - // Local scope mwUserConfig var. Stores user configuration
 62+ // Local scope mwUserConfig var. Stores user configuration
6363 var mwUserConfig = { };
6464
6565 /**
66 - * Setter for configuration values
67 - *
68 - * @param [Mixed] name Name of configuration value
69 - * {Object} Will iderate through each key and call setConfig
70 - * {String} Will set configuration by string name to value
71 - * @param
72 - * {String} value Value of configuration name
73 - * {Object} value Set of values to be merged
74 - */
 66+ * Setter for configuration values
 67+ *
 68+ * @param [Mixed]
 69+ * name Name of configuration value {Object} Will iderate through
 70+ * each key and call setConfig {String} Will set configuration by
 71+ * string name to value
 72+ * @param {String}
 73+ * value Value of configuration name {Object} value Set of values
 74+ * to be merged
 75+ */
7576 mw.setConfig = function ( name, value ) {
7677 if( typeof name == 'object' ) {
7778 for( var i in name ) {
@@ -89,12 +90,14 @@
9091 }
9192
9293 /**
93 - * Set a default config value
94 - * Will only update configuration if no value is present
95 - * @param [Mixed] value Set configuration name to value
96 - * {Object} Will iderate through each key and call setDefaultConfig
97 - * {String} Will set configuration by string name to value
98 - */
 94+ * Set a default config value Will only update configuration if no value is
 95+ * present
 96+ *
 97+ * @param [Mixed]
 98+ * value Set configuration name to value {Object} Will iderate
 99+ * through each key and call setDefaultConfig {String} Will set
 100+ * configuration by string name to value
 101+ */
99102 mw.setDefaultConfig = function( name, value ) {
100103 if( typeof name == 'object' ) {
101104 for( var i in name ) {
@@ -102,19 +105,21 @@
103106 }
104107 return ;
105108 }
106 - // Only update the controls if undefined ( ie don't override false properties )
 109+ // Only update the controls if undefined ( ie don't override false
 110+ // properties )
107111 if( typeof mwConfig[ name ] == 'undefined') {
108112 mwConfig[ name ] = value;
109113 }
110114 }
111115
112116 /**
113 - * Getter for configuration values
114 - *
115 - * @param {String} name of configuration value to get
116 - * @return {Mixed} value of configuration key
117 - * returns "false" if key not found
118 - */
 117+ * Getter for configuration values
 118+ *
 119+ * @param {String}
 120+ * name of configuration value to get
 121+ * @return {Mixed} value of configuration key returns "false" if key not
 122+ * found
 123+ */
119124 mw.getConfig = function ( name ) {
120125 if( mwConfig[ name ] )
121126 return mwConfig[ name ];
@@ -122,19 +127,20 @@
123128 }
124129
125130 /**
126 - * Loads the mwUserConfig from a cookie.
127 - *
128 - * Modules that want to use "User Config" should call
129 - * this setup function in their moduleLoader code.
130 - *
131 - * For performance interfaces using "user config"
132 - * should load '$j.cookie' & 'JSON' in their module loader
133 - *
134 - * By abstracting user preference we could eventually integrate
135 - * a persistent per-account preference system on the server.
136 - *
137 - * @parma {Function} callback Function to be called once userPrefrences are loaded
138 - */
 131+ * Loads the mwUserConfig from a cookie.
 132+ *
 133+ * Modules that want to use "User Config" should call this setup function in
 134+ * their moduleLoader code.
 135+ *
 136+ * For performance interfaces using "user config" should load '$j.cookie' &
 137+ * 'JSON' in their module loader
 138+ *
 139+ * By abstracting user preference we could eventually integrate a persistent
 140+ * per-account preference system on the server.
 141+ *
 142+ * @parma {Function} callback Function to be called once userPrefrences are
 143+ * loaded
 144+ */
139145 var setupUserConfigFlag = false;
140146 mw.setupUserConfig = function( callback ) {
141147 if( setupUserConfigFlag ) {
@@ -143,7 +149,7 @@
144150 }
145151 return ;
146152 }
147 - // Do Setup user config:
 153+ // Do Setup user config:
148154 mw.load( [ '$j.cookie', 'JSON' ], function() {
149155 if( $j.cookie( 'mwUserConfig' ) ) {
150156 mwUserConfig = JSON.parse( $j.cookie( 'mwUserConfig' ) );
@@ -156,12 +162,14 @@
157163 }
158164
159165 /**
160 - * Save a user configuration var to a cookie & local global variable
161 - * Loads the cookie plugin if not already loaded
162 - *
163 - * @param {String} name Name of user configuration value
164 - * @param {String} value Value of configuration name
165 - */
 166+ * Save a user configuration var to a cookie & local global variable Loads
 167+ * the cookie plugin if not already loaded
 168+ *
 169+ * @param {String}
 170+ * name Name of user configuration value
 171+ * @param {String}
 172+ * value Value of configuration name
 173+ */
166174 mw.setUserConfig = function ( name, value, cookieOptions ) {
167175 if( ! setupUserConfigFlag ) {
168176 mw.log( "Error: userConfig not setup" );
@@ -170,18 +178,18 @@
171179 // Update local value
172180 mwUserConfig[ name ] = value;
173181
174 - // Update the cookie ( '$j.cookie' & 'JSON' should already be loaded )
 182+ // Update the cookie ( '$j.cookie' & 'JSON' should already be loaded )
175183 $j.cookie( 'mwUserConfig', JSON.stringify( mwUserConfig ) );
176184 }
177185
178186 /**
179 - * Save a user configuration var to a cookie & local global variable
180 - *
181 - * @param {String} name Name of user configuration value
182 - * @return
183 - * value of the configuration name
184 - * false if the configuration name could not be found
185 - */
 187+ * Save a user configuration var to a cookie & local global variable
 188+ *
 189+ * @param {String}
 190+ * name Name of user configuration value
 191+ * @return value of the configuration name false if the configuration name
 192+ * could not be found
 193+ */
186194 mw.getUserConfig = function ( name ) {
187195 if( mwUserConfig[ name ] )
188196 return mwUserConfig[ name ];
@@ -189,25 +197,28 @@
190198 }
191199
192200 /**
193 - * Add a hook system for a target object / interface
194 - *
195 - * depricated you should instead use jQuery's bind and trigger
196 - *
197 - * @param {Object} targetObj Interface Object to add hook system to.
198 - */
 201+ * Add a hook system for a target object / interface
 202+ *
 203+ * depricated you should instead use jQuery's bind and trigger
 204+ *
 205+ * @param {Object}
 206+ * targetObj Interface Object to add hook system to.
 207+ */
199208 mw.addHookSystem = function( targetObj ) {
200209
201210 // Setup the target object hook holder:
202211 targetObj[ 'hooks' ] = { };
203212
204213 /**
205 - * Adds a hook to the target object
206 - *
207 - * Should be called by clients to setup named hooks
208 - *
209 - * @param {String} hookName Name of hook to be added
210 - * @param {Function} hookFunction Function to be called at hook time
211 - */
 214+ * Adds a hook to the target object
 215+ *
 216+ * Should be called by clients to setup named hooks
 217+ *
 218+ * @param {String}
 219+ * hookName Name of hook to be added
 220+ * @param {Function}
 221+ * hookFunction Function to be called at hook time
 222+ */
212223 targetObj.addHook = function( hookName, hookFunction ) {
213224 if( ! this.hooks[ hookName ] ) {
214225 this.hooks[ hookName ] = [ ];
@@ -216,15 +227,15 @@
217228 }
218229
219230 /**
220 - * Runs all the hooks by a given name with reference to the host object
221 - *
222 - * Should be called by the host object at named execution points
223 - *
224 - * @param {String} hookName Name of hook to be called
225 - * @return Value of hook result
226 - * true interface should continue function execution
227 - * false interface should stop or return from method
228 - */
 231+ * Runs all the hooks by a given name with reference to the host object
 232+ *
 233+ * Should be called by the host object at named execution points
 234+ *
 235+ * @param {String}
 236+ * hookName Name of hook to be called
 237+ * @return Value of hook result true interface should continue function
 238+ * execution false interface should stop or return from method
 239+ */
229240 targetObj.runHook = function( hookName, options ) {
230241 if( this.hooks[ hookName ] ) {
231242 for( var i =0; i < this.hooks[ hookName ].length; i ++ ) {
@@ -244,89 +255,93 @@
245256
246257
247258 /**
248 - * Top level loader prototype:
249 - */
 259+ * Top level loader prototype:
 260+ */
250261 mw.loader = {
251262 /**
252 - * Javascript Module Loader functions
253 - * @key Name of Module
254 - * @value function code to load module
255 - */
 263+ * Javascript Module Loader functions
 264+ *
 265+ * @key Name of Module
 266+ * @value function code to load module
 267+ */
256268 moduleLoaders : [],
257269
258270 /**
259 - * Module resource list queue.
260 - * @key Name of Module
261 - * @value
262 - * .resourceList list of resources to be loaded
263 - * .functionQueue list of functions to be run once module is ready
264 - */
 271+ * Module resource list queue.
 272+ *
 273+ * @key Name of Module
 274+ * @value .resourceList list of resources to be loaded .functionQueue
 275+ * list of functions to be run once module is ready
 276+ */
265277 moduleLoadQueue: { },
266278
267279 /**
268 - * Javascript Class Paths
269 - * @key Name of resource
270 - * @value Class file path
271 - */
 280+ * Javascript Class Paths
 281+ *
 282+ * @key Name of resource
 283+ * @value Class file path
 284+ */
272285 resourcePaths : { },
273286
274287 /**
275 - * javascript Resource Paths
276 - * @key Name of resource
277 - * @value Name of depenent style sheet
278 - */
 288+ * javascript Resource Paths
 289+ *
 290+ * @key Name of resource
 291+ * @value Name of depenent style sheet
 292+ */
279293 resourceStyleDependency: { },
280294
281295 /**
282 - * Core load function:
283 - *
284 - * @param {Mixed} loadRequest:
285 - *
286 - * {String} Name of a module to be loaded
287 - * Modules are added via addModuleLoader and can define custom
288 - * code needed to check config and return a list of resources
289 - * to be loaded
290 - *
291 - * {String} Name of a resource to loaded.
292 - * Resources are added via addResourcePaths function
293 - * Using defined resource names avoids loading the same resource
294 - * twice by first checking if the named resource is defined in
295 - * the global javascript scope variable
296 - *
297 - * {String} Absolute or relative to url path
298 - * The same file won't be loaded twice
299 - *
300 - * {Array} can be an array of any combination of the above strings.
301 - * Will be loaded in-order or in a single resource loader request
302 - * if scriptLoader is available.
303 - *
304 - * {Array} {Array} Can be a set of Arrays for loading.
305 - * Some browsers execute included scripts out of order.
306 - * This lets you chain sets of request for those browsers.
307 - * If using the server side resource loader order is preserved
308 - * in output and a single request will be used.
309 - *
310 - * @param {Function} callback Function called once loading is complete
311 - *
312 - */
 296+ * Core load function:
 297+ *
 298+ * @param {Mixed}
 299+ * loadRequest:
 300+ *
 301+ * {String} Name of a module to be loaded Modules are added via
 302+ * addModuleLoader and can define custom code needed to check config and
 303+ * return a list of resources to be loaded
 304+ *
 305+ * {String} Name of a resource to loaded. Resources are added via
 306+ * addResourcePaths function Using defined resource names avoids loading
 307+ * the same resource twice by first checking if the named resource is
 308+ * defined in the global javascript scope variable
 309+ *
 310+ * {String} Absolute or relative to url path The same file won't be
 311+ * loaded twice
 312+ *
 313+ * {Array} can be an array of any combination of the above strings. Will
 314+ * be loaded in-order or in a single resource loader request if
 315+ * scriptLoader is available.
 316+ *
 317+ * {Array} {Array} Can be a set of Arrays for loading. Some browsers
 318+ * execute included scripts out of order. This lets you chain sets of
 319+ * request for those browsers. If using the server side resource loader
 320+ * order is preserved in output and a single request will be used.
 321+ *
 322+ * @param {Function}
 323+ * callback Function called once loading is complete
 324+ *
 325+ */
313326 load: function( loadRequest, instanceCallback ) {
314 - //mw.log("mw.load:: " + loadRequest );
 327+ // mw.log("mw.load:: " + loadRequest );
315328
316329 // Throw out any loadRequests that are not strings
317330 loadRequest = this.cleanLoadRequest( loadRequest );
318331
319 - // Ensure the callback is only called once per load instance
 332+ // Ensure the callback is only called once per load instance
320333 var callback = function(){
321 - //mw.log( 'instanceCallback::running callback: ' + instanceCallback );
 334+ // mw.log( 'instanceCallback::running callback: ' +
 335+ // instanceCallback );
322336 if( instanceCallback ){
323 - // We pass the loadRequest back to the callback for easy debugging of concurrency issues.
324 - // ( normally its not used )
 337+ // We pass the loadRequest back to the callback for easy
 338+ // debugging of concurrency issues.
 339+ // ( normally its not used )
325340 instanceCallback( loadRequest );
326341 instanceCallback = null;
327342 }
328343 }
329344
330 - // Check for empty loadRequest ( directly return the callback )
 345+ // Check for empty loadRequest ( directly return the callback )
331346 if( mw.isEmpty( loadRequest ) ) {
332347 mw.log( 'Empty load request: ( ' + loadRequest + ' ) ' );
333348 callback( loadRequest );
@@ -334,18 +349,18 @@
335350 }
336351
337352
338 - // Check if its a multi-part request:
 353+ // Check if its a multi-part request:
339354 if( typeof loadRequest == 'object' ) {
340355 if( loadRequest.length > 1 ) {
341356 this.loadMany ( loadRequest, callback );
342357 return ;
343358 }else{
344 - // If an array of length 1 set as first element
 359+ // If an array of length 1 set as first element
345360 loadRequest = loadRequest[0];
346361 }
347362 }
348363
349 - // Check for the module name loader function
 364+ // Check for the module name loader function
350365 if( this.moduleLoaders[ loadRequest ] ) {
351366 var resourceSet = this.getModuleResourceSet( loadRequest );
352367 if( !resourceSet ){
@@ -354,9 +369,10 @@
355370 }
356371
357372 // xxx should use refactor "ready" stuff into a "domReady" class
358 - // So we would not have local scope globals like this:
 373+ // So we would not have local scope globals like this:
359374 if ( mwReadyFlag ) {
360 - // Load the module directly if load request is after mw.ready has run
 375+ // Load the module directly if load request is after
 376+ // mw.ready has run
361377 this.load( resourceSet, callback );
362378 } else {
363379 this.addToModuleLoaderQueue(
@@ -368,7 +384,7 @@
369385 return ;
370386 }
371387
372 - // Check for javascript resource
 388+ // Check for javascript resource
373389 if( this.getResourcePath( loadRequest ) ) {
374390 this.loadResource( loadRequest, callback );
375391 return ;
@@ -383,7 +399,7 @@
384400 return ;
385401 }
386402
387 - // Possible error?
 403+ // Possible error?
388404 mw.log( "Error could not handle load request: " + loadRequest );
389405 },
390406
@@ -393,14 +409,14 @@
394410 // Add the result of the module loader function
395411 return this.moduleLoaders[ moduleName ]();
396412 } else if( typeof ( this.moduleLoaders[ moduleName ] ) == 'object' ){
397 - // set resourceSet directly
 413+ // set resourceSet directly
398414 return this.moduleLoaders[ moduleName ];
399415 }
400416 return false;
401417 },
402418
403419 /**
404 - * Clean the loadRequest ( throw out any non-string items )
 420+ * Clean the loadRequest ( throw out any non-string items )
405421 */
406422 cleanLoadRequest: function( loadRequest ){
407423 var cleanRequest = [];
@@ -418,31 +434,35 @@
419435 return cleanRequest;
420436 },
421437 /**
422 - * Load a set of scripts.
423 - * Will issue many load requests or package the request for the resource loader
424 - *
425 - * @param {Object} loadSet Set of scripts to be loaded
426 - * @param {Function} callback Function to call once all scripts are loaded.
427 - */
 438+ * Load a set of scripts. Will issue many load requests or package the
 439+ * request for the resource loader
 440+ *
 441+ * @param {Object}
 442+ * loadSet Set of scripts to be loaded
 443+ * @param {Function}
 444+ * callback Function to call once all scripts are loaded.
 445+ */
428446 loadMany: function( loadSet, callback ) {
429447 var _this = this;
430 - // Setup up the local "loadStates"
 448+ // Setup up the local "loadStates"
431449 var loadStates = { };
432450
433 - // Check if we can load via the "resource loader" ( mwEmbed was included via scriptLoader )
 451+ // Check if we can load via the "resource loader" ( mwEmbed was
 452+ // included via scriptLoader )
434453 if( mw.getResourceLoaderPath() ) {
435 - // Get the grouped loadStates variable
 454+ // Get the grouped loadStates variable
436455 loadStates = this.getGroupLoadState( loadSet );
437456 if( mw.isEmpty( loadStates ) ) {
438 - //mw.log( 'loadMany:all resources already loaded');
 457+ // mw.log( 'loadMany:all resources already loaded');
439458 callback();
440459 return ;
441460 }
442461 }else{
443 - // Check if its a dependency set ( nested objects )
 462+ // Check if its a dependency set ( nested objects )
444463 if( typeof loadSet [ 0 ] == 'object' ) {
445464 _this.dependencyChainCallFlag[ loadSet ] = false;
446 - //Load sets of resources ( to preserver order for some browsers )
 465+ // Load sets of resources ( to preserver order for some
 466+ // browsers )
447467 _this.loadDependencyChain( loadSet, callback );
448468 return ;
449469 }
@@ -457,25 +477,25 @@
458478 // We are infact loading many:
459479 mw.log("mw.load: LoadMany:: " + loadSet );
460480
461 - // Issue the load request check check loadStates to see if we are "done"
 481+ // Issue the load request check check loadStates to see if we are
 482+ // "done"
462483 for( var loadName in loadStates ) {
463 - //mw.log("loadMany: load: " + loadName );
 484+ // mw.log("loadMany: load: " + loadName );
464485 this.load( loadName, function ( loadName ) {
465486 loadStates[ loadName ] = 1;
466487
467488 /*
468 - for( var i in loadStates ) {
469 - mw.log( loadName + ' finished of: ' + i + ' : ' + loadStates[i] );
470 - }
471 - */
 489+ * for( var i in loadStates ) { mw.log( loadName + '
 490+ * finished of: ' + i + ' : ' + loadStates[i] ); }
 491+ */
472492
473 - //Check if all load request states are set 1
 493+ // Check if all load request states are set 1
474494 var loadDone = true;
475495 for( var j in loadStates ) {
476496 if( loadStates[ j ] === 0 )
477497 loadDone = false;
478498 }
479 - // Run the parent scope callback for "loadMany"
 499+ // Run the parent scope callback for "loadMany"
480500 if( loadDone ) {
481501 callback( loadName );
482502 }
@@ -484,16 +504,16 @@
485505 },
486506
487507 /**
488 - * Get grouped load state for script loader
489 - *
490 - * Groups the scriptRequest where possible:
491 - * Modules include "loader code" so they are separated
492 - * into pre-condition code to be run for subsequent requests
493 - *
494 - * @param {Object} loadSet Loadset to return grouped
495 - * @return {Object}
496 - * grouped loadSet
497 - */
 508+ * Get grouped load state for script loader
 509+ *
 510+ * Groups the scriptRequest where possible: Modules include "loader
 511+ * code" so they are separated into pre-condition code to be run for
 512+ * subsequent requests
 513+ *
 514+ * @param {Object}
 515+ * loadSet Loadset to return grouped
 516+ * @return {Object} grouped loadSet
 517+ */
498518 getGroupLoadState: function( loadSet ) {
499519 var groupedLoadSet = [];
500520 var loadStates = { };
@@ -501,12 +521,12 @@
502522 if( typeof loadSet[0] == 'object' ) {
503523 for( var i = 0; i < loadSet.length ; i++ ) {
504524 for( var j = 0; j < loadSet[i].length ; j++ ) {
505 - // Make sure we have not already included it:
 525+ // Make sure we have not already included it:
506526 groupedLoadSet.push( loadSet[i][j] );
507527 }
508528 }
509529 } else {
510 - // Use the loadSet directly:
 530+ // Use the loadSet directly:
511531 groupedLoadSet = loadSet;
512532 }
513533
@@ -518,7 +538,7 @@
519539
520540
521541 if( this.getResourcePath( loadName ) ) {
522 - // Only add to group request if not already set:
 542+ // Only add to group request if not already set:
523543 if ( !mw.isset( loadName ) ) {
524544 groupClassKey += coma + loadName
525545 coma = ',';
@@ -530,7 +550,8 @@
531551 }
532552 } else if ( this.moduleLoaders[ loadName ] ) {
533553
534 - // Module loaders break up grouped script requests ( add the current groupClassKey )
 554+ // Module loaders break up grouped script requests ( add the
 555+ // current groupClassKey )
535556 if( groupClassKey != '' ) {
536557 loadStates[ groupClassKey ] = 0;
537558 groupClassKey = coma = '';
@@ -540,7 +561,7 @@
541562 }
542563 }
543564
544 - // Add groupClassKey if set:
 565+ // Add groupClassKey if set:
545566 if( groupClassKey != '' ) {
546567 loadStates [ groupClassKey ] = 0;
547568 }
@@ -548,16 +569,17 @@
549570 return loadStates;
550571 },
551572
552 - // Array to register that a callback has been called
 573+ // Array to register that a callback has been called
553574 dependencyChainCallFlag: { },
554575
555576 /**
556 - * Load a sets of scripts satisfy dependency order for browsers that execute
557 - * dynamically included scripts out of order
558 - *
559 - * @param {Object} loadChain A set of javascript arrays to be loaded.
560 - * Sets are requested in array order.
561 - */
 577+ * Load a sets of scripts satisfy dependency order for browsers that
 578+ * execute dynamically included scripts out of order
 579+ *
 580+ * @param {Object}
 581+ * loadChain A set of javascript arrays to be loaded. Sets
 582+ * are requested in array order.
 583+ */
562584 loadDependencyChain: function( loadChain, callback ) {
563585 var _this = this;
564586 // Load with dependency checks
@@ -566,8 +588,8 @@
567589 if ( loadChain.length != 0 ) {
568590 _this.loadDependencyChain( loadChain, callback );
569591 } else {
570 - // NOTE: IE gets called twice so we have check the
571 - // dependencyChainCallFlag before calling the callback
 592+ // NOTE: IE gets called twice so we have check the
 593+ // dependencyChainCallFlag before calling the callback
572594 if( _this.dependencyChainCallFlag[ callSet ] == callback ) {
573595 mw.log("... already called this callback for " + callSet );
574596 return ;
@@ -579,12 +601,12 @@
580602 },
581603
582604 /**
583 - * Add to the module loader queue
584 - */
 605+ * Add to the module loader queue
 606+ */
585607 addToModuleLoaderQueue: function( moduleName, resourceSet, callback ) {
586608 mw.log(" addToModuleLoaderQueue:: " + moduleName + ' resourceSet: ' + resourceSet );
587609 if( this.moduleLoadQueue[ moduleName ] ){
588 - // If the module is already in the queue just add its callback:
 610+ // If the module is already in the queue just add its callback:
589611 this.moduleLoadQueue[ moduleName ].functionQueue.push( callback );
590612 } else {
591613 // create the moduleLoadQueue item
@@ -597,13 +619,14 @@
598620 },
599621
600622 /**
601 - * Loops over all modules in queue, builds request sets based on config request type
602 - */
 623+ * Loops over all modules in queue, builds request sets based on config
 624+ * request type
 625+ */
603626 runModuleLoadQueue: function(){
604627 var _this = this;
605628 mw.log( "mw.runModuleLoadQueue:: " );
606629 var runModuleFunctionQueue = function(){
607 - // Run all the callbacks
 630+ // Run all the callbacks
608631 for( var moduleName in _this.moduleLoadQueue ){
609632 while( _this.moduleLoadQueue[moduleName].functionQueue.length ) {
610633 _this.moduleLoadQueue[moduleName].functionQueue.shift()();
@@ -611,10 +634,11 @@
612635 }
613636 }
614637
615 - // Check for single request or javascript debug based loading:
 638+ // Check for single request or javascript debug based loading:
616639 if( !mw.getResourceLoaderPath() || mw.getConfig( 'loader.groupStrategy' ) == 'single' ){
617 - // if not using the resource load just do a normal array merge
618 - // ( for browsers like IE that don't follow first append first execute rule )
 640+ // if not using the resource load just do a normal array merge
 641+ // ( for browsers like IE that don't follow first append first
 642+ // execute rule )
619643 var fullResourceList = [];
620644 for( var moduleName in this.moduleLoadQueue ) {
621645 var resourceSet = this.moduleLoadQueue[ moduleName ].resourceSet;
@@ -633,13 +657,16 @@
634658 var sharedResourceList = [];
635659
636660 for( var moduleName in this.moduleLoadQueue ) {
637 - // Build a shared dependencies list and load that separately "first"
638 - // ( in IE we have to wait until its "ready" since it does not follow dom order )
 661+ // Build a shared dependencies list and load that separately
 662+ // "first"
 663+ // ( in IE we have to wait until its "ready" since it does
 664+ // not follow dom order )
639665 var moduleResourceList = this.getFlatModuleResourceList( moduleName );
640 - // Build the sharedResourceList
 666+ // Build the sharedResourceList
641667 for( var i=0; i < moduleResourceList.length; i++ ){
642668 var moduleResource = moduleResourceList[i];
643 - // Check if already in the full resource list if so add to shared.
 669+ // Check if already in the full resource list if so add
 670+ // to shared.
644671 if( fullResourceList[ moduleResource ] ){
645672 if( $j.inArray( moduleResource, sharedResourceList ) == -1 ){
646673 sharedResourceList.push( moduleResource );
@@ -650,7 +677,8 @@
651678 }
652679 }
653680
654 - // Local module request set ( stores the actual request we will make after grouping shared resources
 681+ // Local module request set ( stores the actual request we will
 682+ // make after grouping shared resources
655683 var moduleRequestSet = {};
656684
657685 // Only add non-shared to respective modules load requests
@@ -677,7 +705,8 @@
678706 }
679707 runModuleFunctionQueue();
680708 }
681 - // Local instance of load requests to retain resourceSet context:
 709+ // Local instance of load requests to retain resourceSet
 710+ // context:
682711 var localLoadCallInstance = function( moduleName, resourceSet ){
683712 mw.load( resourceSet, function(){
684713 _this.moduleLoadQueue[ moduleName ].loaded = true;
@@ -685,25 +714,26 @@
686715 });
687716 }
688717
689 - // Load the shared resources
 718+ // Load the shared resources
690719 mw.load( sharedResourceList, function(){
691 - //mw.log("Shared Resources loaded");
692 - // xxx check if we are in "IE" and dependencies need to be loaded "first"
 720+ // mw.log("Shared Resources loaded");
 721+ // xxx check if we are in "IE" and dependencies need to be
 722+ // loaded "first"
693723 sharedResourceLoadDone = true;
694724 checkModulesDone();
695725 });
696 - // Load all module Request Set
 726+ // Load all module Request Set
697727 for( var moduleName in moduleRequestSet ){
698728 localLoadCallInstance( moduleName, moduleRequestSet[ moduleName ] );
699729 }
700730 }
701 - // xxx Here we could also do some "intelligent" grouping
 731+ // xxx Here we could also do some "intelligent" grouping
702732 },
703733
704734 getFlatModuleResourceList: function( moduleName ){
705735 var moduleList = [];
706736 for( var j in this.moduleLoadQueue[moduleName].resourceSet ){
707 - // Check if we have a multi-set array:
 737+ // Check if we have a multi-set array:
708738 if( typeof this.moduleLoadQueue[moduleName].resourceSet[j] == 'object' ){
709739 moduleList = $j.merge( moduleList, this.moduleLoadQueue[moduleName].resourceSet[j] );
710740 } else {
@@ -713,21 +743,23 @@
714744 return moduleList;
715745 },
716746 /**
717 - * Loads javascript or css associated with a resourceName
718 - *
719 - * @param {String} resourceName Name of resource to load
720 - * @param {Function} callback Function to run once resource is loaded
721 - */
 747+ * Loads javascript or css associated with a resourceName
 748+ *
 749+ * @param {String}
 750+ * resourceName Name of resource to load
 751+ * @param {Function}
 752+ * callback Function to run once resource is loaded
 753+ */
722754 loadResource: function( resourceName , callback) {
723 - //mw.log("LoadResource:" + resourceName );
 755+ // mw.log("LoadResource:" + resourceName );
724756 var _this = this;
725757
726 - // Check for css dependency on resource name
 758+ // Check for css dependency on resource name
727759 if( this.resourceStyleDependency[ resourceName ] ) {
728760 if( ! mw.isset( this.resourceStyleDependency[ resourceName ] )){
729761 mw.log("loadResource:: dependent css resource: " + this.resourceStyleDependency[ resourceName ] );
730762 _this.loadResource( this.resourceStyleDependency[ resourceName ] , function() {
731 - // Continue the original loadResource request.
 763+ // Continue the original loadResource request.
732764 _this.loadResource( resourceName, callback );
733765 });
734766 return ;
@@ -736,16 +768,17 @@
737769
738770 // Make sure the resource is not already defined:
739771 if ( mw.isset( resourceName ) ) {
740 - //mw.log( 'Class ( ' + resourceName + ' ) already defined ' );
 772+ // mw.log( 'Class ( ' + resourceName + ' ) already defined ' );
741773 callback( resourceName );
742774 return ;
743775 }
744776
745 - // Setup the Script Request var:
 777+ // Setup the Script Request var:
746778 var scriptRequest = null;
747779
748780
749 - // If the scriptloader is enabled use the resourceName as the scriptRequest:
 781+ // If the scriptloader is enabled use the resourceName as the
 782+ // scriptRequest:
750783 if( mw.getResourceLoaderPath() ) {
751784 scriptRequest = resourceName;
752785 }else{
@@ -766,9 +799,10 @@
767800 // Include resource defined check for older browsers
768801 var resourceDone = false;
769802
770 - // Set the loadDone callback per the provided resourceName
 803+ // Set the loadDone callback per the provided resourceName
771804 mw.setLoadDoneCB( resourceName, callback );
772 - // Issue the request to load the resource (include resource name in result callback:
 805+ // Issue the request to load the resource (include resource name in
 806+ // result callback:
773807 mw.getScript( scriptRequest, function( scriptRequest ) {
774808 // If its a "style sheet" manually set its resource to true
775809 var ext = scriptRequest.substr( scriptRequest.split('?')[0].lastIndexOf( '.' ), 4 ).toLowerCase();
@@ -783,53 +817,58 @@
784818 + _this.getResourcePath( resourceName ) );
785819 }
786820
787 - // If ( debug mode ) and the script include is missing resource messages
788 - // do a separate request to retrieve the msgs
 821+ // If ( debug mode ) and the script include is missing resource
 822+ // messages
 823+ // do a separate request to retrieve the msgs
789824 if( mw.currentClassMissingMessages ) {
790825 mw.log( " resourceName " + resourceName + " is missing messages" );
791826 // Reset the currentClassMissingMessages flag
792827 mw.currentClassMissingMessages = false;
793828
794 - // Load msgs for this resource:
 829+ // Load msgs for this resource:
795830 mw.loadResourceMessages( resourceName, function() {
796 - // Run the onDone callback
 831+ // Run the onDone callback
797832 mw.loadDone( resourceName );
798833 } );
799834 } else {
800 - // If not using the resource loader make sure the resourceName is available before firing the loadDone
 835+ // If not using the resource loader make sure the
 836+ // resourceName is available before firing the loadDone
801837 if( !mw.getResourceLoaderPath() ) {
802838 mw.waitForObject( resourceName, function( resourceName ) {
803 - // Once object is ready run loadDone
 839+ // Once object is ready run loadDone
804840 mw.loadDone( resourceName );
805841 } );
806842 } else {
807 - // loadDone should be appended to the bottom of the resource loader response
808 - //mw.loadDone( resourceName );
 843+ // loadDone should be appended to the bottom of the
 844+ // resource loader response
 845+ // mw.loadDone( resourceName );
809846 }
810847 }
811848 } );
812849 },
813850
814851 /**
815 - * Adds a module to the mwLoader object
816 - *
817 - * @param {String} name Name of module
818 - * @param {Function} moduleLoader Function that
819 - * loads dependencies for a module
820 - */
 852+ * Adds a module to the mwLoader object
 853+ *
 854+ * @param {String}
 855+ * name Name of module
 856+ * @param {Function}
 857+ * moduleLoader Function that loads dependencies for a module
 858+ */
821859 addModuleLoader: function( name, moduleLoader ) {
822860 this.moduleLoaders [ name ] = moduleLoader;
823861 },
824862
825863 /**
826 - * Adds resource file path key value pairs
827 - *
828 - * @param {Object} resourceSet JSON formated list of
829 - * resource name file path pairs.
830 - *
831 - * resourceSet must be strict JSON to allow the
832 - * php scriptLoader to parse the file paths.
833 - */
 864+ * Adds resource file path key value pairs
 865+ *
 866+ * @param {Object}
 867+ * resourceSet JSON formated list of resource name file path
 868+ * pairs.
 869+ *
 870+ * resourceSet must be strict JSON to allow the php scriptLoader to
 871+ * parse the file paths.
 872+ */
834873 addResourcePaths: function( resourceSet ) {
835874 var prefix = ( mw.getConfig( 'loaderContext' ) )?
836875 mw.getConfig( 'loaderContext' ): '';
@@ -840,11 +879,11 @@
841880 },
842881
843882 /*
844 - * Adds a named style sheet dependency to a named resource
845 - *
846 - * @parma {Object} resourceSet JSON formated list of resource names
847 - * and associated style sheet names
848 - */
 883+ * Adds a named style sheet dependency to a named resource
 884+ *
 885+ * @parma {Object} resourceSet JSON formated list of resource names and
 886+ * associated style sheet names
 887+ */
849888 addStyleResourceDependency: function( resourceSet ){
850889 for( var i in resourceSet ){
851890 this.resourceStyleDependency[ i ] = resourceSet[i];
@@ -852,9 +891,9 @@
853892 },
854893
855894 /**
856 - * Get a resource path from a resourceName
857 - * if no resource found return false
858 - */
 895+ * Get a resource path from a resourceName if no resource found return
 896+ * false
 897+ */
859898 getResourcePath: function( resourceName ) {
860899 if( this.resourcePaths[ resourceName ] )
861900 return this.resourcePaths[ resourceName ]
@@ -863,15 +902,17 @@
864903 }
865904
866905 /**
867 - * Load done callback for script loader
868 - * @param {String} requestName Name of the load request
869 - */
 906+ * Load done callback for script loader
 907+ *
 908+ * @param {String}
 909+ * requestName Name of the load request
 910+ */
870911 mw.loadDone = function( requestName ) {
871912 if( !mwLoadDoneCB[ requestName ] ) {
872913 return true;
873914 }
874915 while( mwLoadDoneCB[ requestName ].length ) {
875 - // check if mwLoadDoneCB is already "done"
 916+ // check if mwLoadDoneCB is already "done"
876917 // the function list is not an object
877918 if( typeof mwLoadDoneCB[ requestName ] != 'object' )
878919 {
@@ -879,7 +920,8 @@
880921 }
881922 var func = mwLoadDoneCB[ requestName ].pop();
882923 if( typeof func == 'function' ) {
883 - //mw.log( "LoadDone: " + requestName + ' run callback::' + func);
 924+ // mw.log( "LoadDone: " + requestName + ' run callback::' +
 925+ // func);
884926 func( requestName );
885927 }else{
886928 mw.log('mwLoadDoneCB: Error non callback function on stack');
@@ -890,10 +932,13 @@
891933 };
892934
893935 /**
894 - * Set a load done callback
895 - * @param {String} requestName Name of resource or request set
896 - * @param {Function} callback Function called once requestName is ready
897 - */
 936+ * Set a load done callback
 937+ *
 938+ * @param {String}
 939+ * requestName Name of resource or request set
 940+ * @param {Function}
 941+ * callback Function called once requestName is ready
 942+ */
898943 mw.setLoadDoneCB = function( requestName, callback ) {
899944 // If the requestName is already done loading just callback
900945 if( mwLoadDoneCB[ requestName ] == 'done' ) {
@@ -907,31 +952,29 @@
908953 };
909954
910955 /**
911 - * Shortcut entry points / convenience functions:
912 - * Lets you write mw.load() instead of mw.loader.load()
913 - * only these entry points should be used.
914 - *
915 - * future closure optimizations could minify internal
916 - * function names
917 - */
 956+ * Shortcut entry points / convenience functions: Lets you write mw.load()
 957+ * instead of mw.loader.load() only these entry points should be used.
 958+ *
 959+ * future closure optimizations could minify internal function names
 960+ */
918961
919962 /**
920 - * Load Object entry point: Loads a requested set of javascript
921 - */
 963+ * Load Object entry point: Loads a requested set of javascript
 964+ */
922965 mw.load = function( loadRequest, callback ) {
923966 return mw.loader.load( loadRequest, callback );
924967 }
925968
926969 /**
927 - * Add module entry point: Adds a module to the mwLoader object
928 - */
 970+ * Add module entry point: Adds a module to the mwLoader object
 971+ */
929972 mw.addModuleLoader = function ( name, loaderFunction ) {
930973 return mw.loader.addModuleLoader( name, loaderFunction );
931974 }
932975
933976 /**
934 - * Add Class File Paths entry point:
935 - */
 977+ * Add Class File Paths entry point:
 978+ */
936979 mw.addResourcePaths = function ( resourceSet ) {
937980 return mw.loader.addResourcePaths( resourceSet );
938981 }
@@ -941,23 +984,23 @@
942985 }
943986
944987 /**
945 - * Get Class File Path entry point:
946 - */
 988+ * Get Class File Path entry point:
 989+ */
947990 mw.getResourcePath = function( resourceName ) {
948991 return mw.loader.getResourcePath( resourceName );
949992 }
950993
951994
952995 /**
953 - * Utility Functions
954 - */
 996+ * Utility Functions
 997+ */
955998
956999 /**
957 - * addLoaderDialog
958 - * small helper for displaying a loading dialog
959 - *
960 - * @param {String} dialogHtml text Html of the loader msg
961 - */
 1000+ * addLoaderDialog small helper for displaying a loading dialog
 1001+ *
 1002+ * @param {String}
 1003+ * dialogHtml text Html of the loader msg
 1004+ */
9621005 mw.addLoaderDialog = function( dialogHtml ) {
9631006 $dialog = mw.addDialog( dialogHtml, dialogHtml + '<br>' +
9641007 $j('<div />')
@@ -986,16 +1029,20 @@
9871030 }
9881031
9891032 /**
990 - * Add a (temporary) dialog window:
991 - * @param {String} title Title string for the dialog
992 - * @param {String} dialogHtml String to be inserted in msg box
993 - * @param {Mixed} buttonOption A button object for the dialog
994 - * Can be a string for the close buton
995 - */
 1033+ * Add a (temporary) dialog window:
 1034+ *
 1035+ * @param {String}
 1036+ * title Title string for the dialog
 1037+ * @param {String}
 1038+ * dialogHtml String to be inserted in msg box
 1039+ * @param {Mixed}
 1040+ * buttonOption A button object for the dialog Can be a string
 1041+ * for the close buton
 1042+ */
9961043 mw.addDialog = function ( title, dialogHtml, buttons ) {
9971044 $j( '#mwTempLoaderDialog' ).remove();
9981045
999 - // Append the style free loader ontop:
 1046+ // Append the style free loader ontop:
10001047 $j( 'body' ).append(
10011048 $j('<div />')
10021049 .attr( {
@@ -1049,14 +1096,14 @@
10501097
10511098
10521099 /**
1053 - * Similar to php isset function checks if the variable exists.
1054 - * Does a safe check of a descendant method or variable
1055 - *
1056 - * @param {String} objectPath
1057 - * @return {Boolean}
1058 - * true if objectPath exists
1059 - * false if objectPath is undefined
1060 - */
 1100+ * Similar to php isset function checks if the variable exists. Does a safe
 1101+ * check of a descendant method or variable
 1102+ *
 1103+ * @param {String}
 1104+ * objectPath
 1105+ * @return {Boolean} true if objectPath exists false if objectPath is
 1106+ * undefined
 1107+ */
10611108 mw.isset = function( objectPath ) {
10621109 if ( !objectPath ) {
10631110 return false;
@@ -1075,18 +1122,21 @@
10761123 }
10771124
10781125 /**
1079 - * Wait for a object to be defined and the call the callback
1080 - *
1081 - * @param {Object} objectName Name of object to be defined
1082 - * @param {Function} callback Function to call once object is defined
1083 - * @param {Null} callNumber Used internally to keep track of
1084 - * number of times waitForObject has been called
1085 - */
1086 - var waitTime = 1200; // About 30 seconds
 1126+ * Wait for a object to be defined and the call the callback
 1127+ *
 1128+ * @param {Object}
 1129+ * objectName Name of object to be defined
 1130+ * @param {Function}
 1131+ * callback Function to call once object is defined
 1132+ * @param {Null}
 1133+ * callNumber Used internally to keep track of number of times
 1134+ * waitForObject has been called
 1135+ */
 1136+ var waitTime = 1200; // About 30 seconds
10871137 mw.waitForObject = function( objectName, callback, _callNumber) {
1088 - //mw.log( 'waitForObject: ' + objectName + ' cn: ' + _callNumber);
 1138+ // mw.log( 'waitForObject: ' + objectName + ' cn: ' + _callNumber);
10891139
1090 - // Increment callNumber:
 1140+ // Increment callNumber:
10911141 if( !_callNumber ) {
10921142 _callNumber = 1;
10931143 } else {
@@ -1110,14 +1160,15 @@
11111161 }
11121162
11131163 /**
1114 - * Check if an object is empty or if its an empty string.
1115 - *
1116 - * @param {Object} object Object to be checked
1117 - */
 1164+ * Check if an object is empty or if its an empty string.
 1165+ *
 1166+ * @param {Object}
 1167+ * object Object to be checked
 1168+ */
11181169 mw.isEmpty = function( object ) {
11191170 if( typeof object == 'string' ) {
11201171 if( object == '' ) return true;
1121 - // Non empty string:
 1172+ // Non empty string:
11221173 return false;
11231174 }
11241175
@@ -1127,7 +1178,7 @@
11281179 return true;
11291180 }
11301181
1131 - // Else check as an object:
 1182+ // Else check as an object:
11321183 for( var i in object ) { return false; }
11331184
11341185 // Else object is empty:
@@ -1135,16 +1186,17 @@
11361187 }
11371188
11381189 /**
1139 - * Log a string msg to the console
1140 - *
1141 - * all mw.log statements will be removed on minification so
1142 - * lots of mw.log calls will not impact performance in non debug mode
1143 - *
1144 - * @param {String} string String to output to console
1145 - */
 1190+ * Log a string msg to the console
 1191+ *
 1192+ * all mw.log statements will be removed on minification so lots of mw.log
 1193+ * calls will not impact performance in non debug mode
 1194+ *
 1195+ * @param {String}
 1196+ * string String to output to console
 1197+ */
11461198 mw.log = function( string ) {
11471199
1148 - // Add any prepend debug strings if necessary
 1200+ // Add any prepend debug strings if necessary
11491201 if ( mw.getConfig( 'pre-append-log' ) ){
11501202 string = mw.getConfig( 'pre-append-log' ) + string;
11511203 }
@@ -1153,40 +1205,39 @@
11541206 window.console.log( string );
11551207 } else {
11561208 /**
1157 - * Old IE and non-Firebug debug: ( commented out for now )
 1209+ * Old IE and non-Firebug debug: ( commented out for now )
11581210 */
1159 - /*var log_elm = document.getElementById('mv_js_log');
1160 - if(!log_elm) {
1161 - document.getElementsByTagName("body")[0].innerHTML = document.getElementsByTagName("body")[0].innerHTML +
1162 - '<div style="position:absolute;z-index:500;bottom:0px;left:0px;right:0px;height:200px;">'+
1163 - '<textarea id="mv_js_log" cols="120" rows="12"></textarea>'+
1164 - '</div>';
1165 -
1166 - var log_elm = document.getElementById('mv_js_log');
1167 - }
1168 - if(log_elm) {
1169 - log_elm.value+=string+"\n";
1170 - }*/
 1211+ /*
 1212+ * var log_elm = document.getElementById('mv_js_log'); if(!log_elm) {
 1213+ * document.getElementsByTagName("body")[0].innerHTML =
 1214+ * document.getElementsByTagName("body")[0].innerHTML + '<div
 1215+ * style="position:absolute;z-index:500;bottom:0px;left:0px;right:0px;height:200px;">'+ '<textarea
 1216+ * id="mv_js_log" cols="120" rows="12"></textarea>'+ '</div>';
 1217+ *
 1218+ * var log_elm = document.getElementById('mv_js_log'); } if(log_elm) {
 1219+ * log_elm.value+=string+"\n"; }
 1220+ */
11711221 }
11721222 }
11731223
1174 - //Setup the local mwOnLoadFunctions array:
 1224+ // Setup the local mwOnLoadFunctions array:
11751225 var mwOnLoadFunctions = [];
11761226
1177 - //mw Ready flag ( set once mwEmbed is ready )
 1227+ // mw Ready flag ( set once mwEmbed is ready )
11781228 var mwReadyFlag = false;
11791229
11801230 /**
1181 - * Enables load hooks to run once mwEmbeed is "ready"
1182 - * Will ensure jQuery is available, is in the $j namespace
1183 - * and mw interfaces and configuration has been loaded and applied
1184 - *
1185 - * This is different from jQuery(document).ready()
1186 - * ( jQuery ready is not friendly with dynamic includes
1187 - * and not friendly with core interface asynchronous build out. )
1188 - *
1189 - * @param {Function} callback Function to run once DOM and jQuery are ready
1190 - */
 1231+ * Enables load hooks to run once mwEmbeed is "ready" Will ensure jQuery is
 1232+ * available, is in the $j namespace and mw interfaces and configuration has
 1233+ * been loaded and applied
 1234+ *
 1235+ * This is different from jQuery(document).ready() ( jQuery ready is not
 1236+ * friendly with dynamic includes and not friendly with core interface
 1237+ * asynchronous build out. )
 1238+ *
 1239+ * @param {Function}
 1240+ * callback Function to run once DOM and jQuery are ready
 1241+ */
11911242 mw.ready = function( callback ) {
11921243 if( mwReadyFlag === false ) {
11931244 // Add the callbcak to the onLoad function stack
@@ -1198,51 +1249,54 @@
11991250 }
12001251
12011252 /**
1202 - * Runs all the queued functions
1203 - * called by mwEmbedSetup
1204 - */
 1253+ * Runs all the queued functions called by mwEmbedSetup
 1254+ */
12051255 mw.runReadyFunctions = function ( ) {
12061256 mw.log('mw.runReadyFunctions: ' + mwOnLoadFunctions.length );
1207 - // Run any pre-setup ready functions
 1257+ // Run any pre-setup ready functions
12081258 while( preMwEmbedReady.length ){
12091259 preMwEmbedReady.shift()();
12101260 }
1211 - // Run all the queued functions:
 1261+ // Run all the queued functions:
12121262 while( mwOnLoadFunctions.length ) {
12131263 mwOnLoadFunctions.shift()();
1214 - }
1215 -
1216 - // Once we have run all the queued functions
1217 - mw.loader.runModuleLoadQueue();
 1264+ }
12181265
12191266 // Sets mwReadyFlag to true so that future mw.ready run the
12201267 // callback directly
12211268 mwReadyFlag = true;
12221269
 1270+ // Once we have run all the queued functions
 1271+ mw.loader.runModuleLoadQueue();
 1272+
12231273 }
12241274
12251275
12261276 /**
1227 - * Wrapper for jQuery getScript,
1228 - * Uses the scriptLoader if enabled
1229 - *
1230 - *
1231 - * @param {String} scriptRequest The requested path or resourceNames for the scriptLoader
1232 - * @param {Function} callback Function to call once script is loaded
1233 - */
 1277+ * Wrapper for jQuery getScript, Uses the scriptLoader if enabled
 1278+ *
 1279+ *
 1280+ * @param {String}
 1281+ * scriptRequest The requested path or resourceNames for the
 1282+ * scriptLoader
 1283+ * @param {Function}
 1284+ * callback Function to call once script is loaded
 1285+ */
12341286 mw.getScript = function( scriptRequest, callback ) {
1235 - //mw.log( "mw.getScript::" + scriptRequest );
1236 - // Setup the local scope callback instace
 1287+ // mw.log( "mw.getScript::" + scriptRequest );
 1288+ // Setup the local scope callback instace
12371289 var myCallback = function(){
12381290 if( callback ) {
12391291 callback( scriptRequest );
12401292 }
12411293 }
1242 - // Set the base url based scriptLoader availability & type of scriptRequest
1243 - // ( presently script loader only handles "classes" not relative urls:
 1294+ // Set the base url based scriptLoader availability & type of
 1295+ // scriptRequest
 1296+ // ( presently script loader only handles "classes" not relative urls:
12441297 var scriptLoaderPath = mw.getResourceLoaderPath();
12451298
1246 - // Check if its a resource name, ( ie does not start with "/" and does not include ://
 1299+ // Check if its a resource name, ( ie does not start with "/" and does
 1300+ // not include ://
12471301 var isResourceName = ( scriptRequest.indexOf('://') == -1 && scriptRequest.indexOf('/') !== 0 )? true : false;
12481302
12491303 var ext = scriptRequest.substr( scriptRequest.lastIndexOf( '.' ), 4 ).toLowerCase();
@@ -1265,8 +1319,8 @@
12661320 mw.log( 'mw.getScript: ' + url );
12671321 }
12681322
1269 - // If jQuery is available and debug is off load the scirpt via jQuery
1270 - //( will use XHR if on same domain )
 1323+ // If jQuery is available and debug is off load the scirpt via jQuery
 1324+ // ( will use XHR if on same domain )
12711325 if( mw.isset( 'window.jQuery' )
12721326 && mw.getConfig( 'debug' ) === false
12731327 && typeof $j != 'undefined'
@@ -1277,14 +1331,9 @@
12781332 }
12791333
12801334 /**
1281 - * No jQuery
1282 - * OR
1283 - * In debug mode
1284 - * OR
1285 - * Is css file
1286 - *
1287 - * :: inject the script instead of doing an XHR eval
1288 - */
 1335+ * No jQuery OR In debug mode OR Is css file
 1336+ * :: inject the script instead of doing an XHR eval
 1337+ */
12891338
12901339 // load style sheet directly if requested loading css
12911340 if( isCssFile ){
@@ -1292,28 +1341,31 @@
12931342 return ;
12941343 }
12951344
1296 - // Load and bind manually: ( copied from jQuery ajax function )
 1345+ // Load and bind manually: ( copied from jQuery ajax function )
12971346 var head = document.getElementsByTagName("head")[ 0 ];
12981347 var script = document.createElement("script");
12991348 script.setAttribute( 'src', url );
13001349
1301 - // Attach handlers ( if using script loader it issues onDone callback as well )
 1350+ // Attach handlers ( if using script loader it issues onDone callback as
 1351+ // well )
13021352 script.onload = script.onreadystatechange = function() {
13031353 if (!this.readyState || this.readyState == "loaded" || this.readyState == "complete") {
13041354 myCallback();
13051355 }
13061356 };
1307 - //mw.log(" append script: " + script.src );
 1357+ // mw.log(" append script: " + script.src );
13081358 // Append the script to the DOM:
13091359 head.appendChild( script );
13101360 };
13111361
13121362 /**
1313 - * Add a style sheet string to the document head
1314 - *
1315 - * @param {String} cssResourceName Name of style sheet that has been defined
1316 - * @param {String} cssString Css Payload to be added to head of document
1317 - */
 1363+ * Add a style sheet string to the document head
 1364+ *
 1365+ * @param {String}
 1366+ * cssResourceName Name of style sheet that has been defined
 1367+ * @param {String}
 1368+ * cssString Css Payload to be added to head of document
 1369+ */
13181370 mw.addStyleString = function( cssResourceName, cssString ) {
13191371 if( mw.style[ cssResourceName ] ) {
13201372 mw.log(" Style: ( " + cssResourceName + ' ) already set' );
@@ -1321,11 +1373,12 @@
13221374 }
13231375 // Set the style to true ( to not request it again )
13241376 mw.style[ cssResourceName ] = true;
1325 - // Add the spinner directly ( without jQuery in case we have to dynamically load jQuery )
 1377+ // Add the spinner directly ( without jQuery in case we have to
 1378+ // dynamically load jQuery )
13261379 mw.log( 'Adding style:' + cssResourceName + " to dom " );
13271380 var styleNode = document.createElement('style');
13281381 styleNode.type = "text/css";
1329 - // Use cssText or createTextNode depending on browser:
 1382+ // Use cssText or createTextNode depending on browser:
13301383 if( ( window.attachEvent && !window.opera ) ) {
13311384 styleNode.styleSheet.cssText = cssString;
13321385 } else {
@@ -1337,12 +1390,12 @@
13381391 };
13391392
13401393 /**
1341 - * Get a style sheet and append the style sheet to the DOM
1342 - *
1343 - * @param {Mixed}
1344 - * {String} url Url of the style sheet to be loaded
1345 - * {Function} callback Function called once sheet is ready
1346 - */
 1394+ * Get a style sheet and append the style sheet to the DOM
 1395+ *
 1396+ * @param {Mixed}
 1397+ * {String} url Url of the style sheet to be loaded {Function}
 1398+ * callback Function called once sheet is ready
 1399+ */
13471400 mw.getStyleSheet = function( url , callback) {
13481401 // Add URL params ( if not already included )
13491402 if ( url.indexOf( '?' ) == -1 ) {
@@ -1355,9 +1408,9 @@
13561409 var currentSheet = $j( this) .attr( 'href' );
13571410 var sheetParts = currentSheet.split('?');
13581411 var urlParts = url.split('?');
1359 - //if the base url's match check the parameters:
 1412+ // if the base url's match check the parameters:
13601413 if( sheetParts[0] == urlParts[0] && sheetParts[1]) {
1361 - //Check if url params match ( sort to do string compare )
 1414+ // Check if url params match ( sort to do string compare )
13621415 if( sheetParts[1].split( '&' ).sort().join('') ==
13631416 urlParts[1].split('&').sort().join('') ) {
13641417 foundSheet = true;
@@ -1380,8 +1433,9 @@
13811434 'href' : url
13821435 } )
13831436 );
1384 - // No easy way to check css "onLoad" attribute
1385 - // In production sheets are loaded via resource loader and fire the onDone function call.
 1437+ // No easy way to check css "onLoad" attribute
 1438+ // In production sheets are loaded via resource loader and fire the
 1439+ // onDone function call.
13861440 if( callback ) {
13871441 callback();
13881442 }
@@ -1392,8 +1446,8 @@
13931447 var mwEmbedPath = null;
13941448
13951449 /**
1396 - * Get the path to the mwEmbed folder
1397 - */
 1450+ * Get the path to the mwEmbed folder
 1451+ */
13981452 mw.getMwEmbedPath = function() {
13991453 if ( mwEmbedPath ) {
14001454 return mwEmbedPath;
@@ -1408,9 +1462,10 @@
14091463 mwpath = src.substr( 0, src.indexOf( 'mwEmbed.js' ) );
14101464 }
14111465
1412 - // Check for scriptLoader include of mwEmbed:
 1466+ // Check for scriptLoader include of mwEmbed:
14131467 if ( src.indexOf( 'mwResourceLoader.php' ) !== -1 ) {
1414 - // Script loader is in the root of MediaWiki, Include the default mwEmbed extension path:
 1468+ // Script loader is in the root of MediaWiki, Include the default
 1469+ // mwEmbed extension path:
14151470 mwpath = src.substr( 0, src.indexOf( 'mwResourceLoader.php' ) ) + mw.getConfig( 'mediaWikiEmbedPath' );
14161471 }
14171472
@@ -1430,18 +1485,17 @@
14311486 return ;
14321487 }
14331488
1434 - // Update the cached var with the absolute path:
 1489+ // Update the cached var with the absolute path:
14351490 mwEmbedPath = mw.absoluteUrl( mwpath ) ;
14361491 return mwEmbedPath;
14371492 }
14381493
14391494 /**
1440 - * Get Script loader path
1441 - *
1442 - * @returns {String}|{Boolean}
1443 - * Url of the scriptLodaer
1444 - * false if the scriptLoader is not used
1445 - */
 1495+ * Get Script loader path
 1496+ *
 1497+ * @returns {String}|{Boolean} Url of the scriptLodaer false if the
 1498+ * scriptLoader is not used
 1499+ */
14461500 mw.getResourceLoaderPath = function( ) {
14471501 var src = mw.getMwEmbedSrc();
14481502 if ( src.indexOf( 'mwResourceLoader.php' ) !== -1 ||
@@ -1454,12 +1508,14 @@
14551509 }
14561510
14571511 /**
1458 - * Given a float number of seconds, returns npt format response.
1459 - * ( ignore days for now )
1460 - *
1461 - * @param {Float} sec Seconds
1462 - * @param {Boolean} show_ms If milliseconds should be displayed.
1463 - * @return {Float} String npt format
 1512+ * Given a float number of seconds, returns npt format response. ( ignore
 1513+ * days for now )
 1514+ *
 1515+ * @param {Float}
 1516+ * sec Seconds
 1517+ * @param {Boolean}
 1518+ * show_ms If milliseconds should be displayed.
 1519+ * @return {Float} String npt format
14641520 */
14651521 mw.seconds2npt = function( sec, show_ms ) {
14661522 if ( isNaN( sec ) ) {
@@ -1469,7 +1525,8 @@
14701526
14711527 var tm = mw.seconds2Measurements( sec )
14721528
1473 - // Round the number of seconds to the required number of significant digits
 1529+ // Round the number of seconds to the required number of significant
 1530+ // digits
14741531 if ( show_ms ) {
14751532 tm.seconds = Math.round( tm.seconds * 1000 ) / 1000;
14761533 } else {
@@ -1484,8 +1541,10 @@
14851542 }
14861543
14871544 /**
1488 - * Given seconds return array with 'days', 'hours', 'min', 'seconds'
1489 - * @param {float} sec Seconds to be converted into time measurements
 1545+ * Given seconds return array with 'days', 'hours', 'min', 'seconds'
 1546+ *
 1547+ * @param {float}
 1548+ * sec Seconds to be converted into time measurements
14901549 */
14911550 mw.seconds2Measurements = function ( sec ){
14921551 var tm = {};
@@ -1497,17 +1556,18 @@
14981557 }
14991558
15001559 /**
1501 - * Take hh:mm:ss,ms or hh:mm:ss.ms input, return the number of seconds
1502 - *
1503 - * @param {String} npt_str NPT time string
1504 - * @return {Float} Number of seconds
1505 - */
 1560+ * Take hh:mm:ss,ms or hh:mm:ss.ms input, return the number of seconds
 1561+ *
 1562+ * @param {String}
 1563+ * npt_str NPT time string
 1564+ * @return {Float} Number of seconds
 1565+ */
15061566 mw.npt2seconds = function ( npt_str ) {
15071567 if ( !npt_str ) {
15081568 // mw.log('npt2seconds:not valid ntp:'+ntp);
15091569 return false;
15101570 }
1511 - // Strip {npt:}01:02:20 or 32{s} from time if present
 1571+ // Strip {npt:}01:02:20 or 32{s} from time if present
15121572 npt_str = npt_str.replace( /npt:|s/g, '' );
15131573
15141574 var hour = 0;
@@ -1535,8 +1595,8 @@
15361596 var mwEmbedSrc = null;
15371597
15381598 /**
1539 - * Gets the mwEmbed script src attribute
1540 - */
 1599+ * Gets the mwEmbed script src attribute
 1600+ */
15411601 mw.getMwEmbedSrc = function() {
15421602 if ( mwEmbedSrc ) {
15431603 return mwEmbedSrc;
@@ -1548,9 +1608,9 @@
15491609 // Check for mwEmbed.js and/or script loader
15501610 var src = js_elements[i].getAttribute( "src" );
15511611 if ( src ) {
1552 - if ( // Check for mwEmbed.js ( debug mode )
 1612+ if ( // Check for mwEmbed.js ( debug mode )
15531613 ( src.indexOf( 'mwEmbed.js' ) !== -1 && src.indexOf( 'MediaWiki:Gadget') == -1 )
1554 - || // Check for resource loader
 1614+ || // Check for resource loader
15551615 (
15561616 ( src.indexOf( 'mwResourceLoader.php' ) !== -1 || src.indexOf( 'ResourceLoader.php' ) !== -1 )
15571617 &&
@@ -1572,8 +1632,8 @@
15731633 var mwUrlParam = null;
15741634
15751635 /**
1576 - * Get URL Parameters per parameters in the host script include
1577 - */
 1636+ * Get URL Parameters per parameters in the host script include
 1637+ */
15781638 mw.getUrlParam = function() {
15791639 if ( mwUrlParam ) {
15801640 return mwUrlParam;
@@ -1585,14 +1645,15 @@
15861646 // If we already have a URI, add it to the param request:
15871647 var urid = mw.parseUri( mwEmbedSrc ).queryKey['urid']
15881648
1589 - // If we're in debug mode, get a fresh unique request key and pass on "debug" param
 1649+ // If we're in debug mode, get a fresh unique request key and pass on
 1650+ // "debug" param
15901651 if ( mw.parseUri( mwEmbedSrc ).queryKey['debug'] == 'true' ) {
15911652 mw.setConfig( 'debug', true );
15921653 var d = new Date();
15931654 req_param += 'urid=' + d.getTime() + '&debug=true';
15941655
15951656 } else if ( urid ) {
1596 - // Just pass on the existing urid:
 1657+ // Just pass on the existing urid:
15971658 req_param += 'urid=' + urid;
15981659 } else {
15991660 // Otherwise, Use the mwEmbed version
@@ -1604,19 +1665,20 @@
16051666 if ( langKey )
16061667 req_param += '&uselang=' + langKey;
16071668
1608 - // Update the local cache and return the value
 1669+ // Update the local cache and return the value
16091670 mwUrlParam = req_param;
16101671 return mwUrlParam;
16111672 }
16121673
1613 - /**
1614 - * Replace url parameters via newParams key value pairs
1615 - *
1616 - * @param {String} url Source url to be updated
1617 - * @param {Object} newParams key, value paris to swap in
1618 - * @return {String}
1619 - * the updated url
1620 - */
 1674+ /**
 1675+ * Replace url parameters via newParams key value pairs
 1676+ *
 1677+ * @param {String}
 1678+ * url Source url to be updated
 1679+ * @param {Object}
 1680+ * newParams key, value paris to swap in
 1681+ * @return {String} the updated url
 1682+ */
16211683 mw.replaceUrlParams = function( url, newParams ) {
16221684 var parsedUrl = mw.parseUri( url );
16231685
@@ -1626,7 +1688,7 @@
16271689 var new_url = parsedUrl.path + '?';
16281690 }
16291691
1630 - // Merge new params:
 1692+ // Merge new params:
16311693 for( var key in newParams ) {
16321694 parsedUrl.queryKey[ key ] = newParams[ key ];
16331695 }
@@ -1642,10 +1704,8 @@
16431705 }
16441706
16451707 /**
1646 - * parseUri 1.2.2
1647 - * (c) Steven Levithan <stevenlevithan.com>
1648 - * MIT License
1649 - */
 1708+ * parseUri 1.2.2 (c) Steven Levithan <stevenlevithan.com> MIT License
 1709+ */
16501710 mw.parseUri = function (str) {
16511711 var o = mw.parseUri.options,
16521712 m = o.parser[o.strictMode ? "strict" : "loose"].exec(str),
@@ -1663,11 +1723,11 @@
16641724 };
16651725
16661726 /**
1667 - * Parse URI function
1668 - *
1669 - * For documentation on its usage see:
1670 - * http://stevenlevithan.com/demo/parseuri/js/
1671 - */
 1727+ * Parse URI function
 1728+ *
 1729+ * For documentation on its usage see:
 1730+ * http://stevenlevithan.com/demo/parseuri/js/
 1731+ */
16721732 mw.parseUri.options = {
16731733 strictMode: false,
16741734 key: ["source", "protocol", "authority", "userInfo", "user", "password", "host",
@@ -1683,11 +1743,13 @@
16841744 };
16851745
16861746 /**
1687 - * getAbsoluteUrl takes a src and returns the absolute location given the document.URL
1688 - *
1689 - * @param {String} src path or url
1690 - * @return {String} absolute url
1691 - */
 1747+ * getAbsoluteUrl takes a src and returns the absolute location given the
 1748+ * document.URL
 1749+ *
 1750+ * @param {String}
 1751+ * src path or url
 1752+ * @return {String} absolute url
 1753+ */
16921754 mw.absoluteUrl = function( src, contextUrl ) {
16931755 var parsedSrc = mw.parseUri( src );
16941756 // Source is already absolute return:
@@ -1695,14 +1757,14 @@
16961758 return src;
16971759 }
16981760
1699 - // Get parent Url location the context URL
 1761+ // Get parent Url location the context URL
17001762 if( contextUrl) {
17011763 var parsedUrl = mw.parseUri( contextUrl );
17021764 } else {
17031765 var parsedUrl = mw.parseUri( document.URL );
17041766 }
17051767
1706 - // Check for leading slash:
 1768+ // Check for leading slash:
17071769 if( src.indexOf( '/' ) === 0 ) {
17081770 return parsedUrl.protocol + '://' + parsedUrl.authority + src;
17091771 }else{
@@ -1712,9 +1774,10 @@
17131775
17141776 /**
17151777 * Escape quotes in a text string
1716 - * @param {String} text String to be escaped
1717 - * @return {string}
1718 - * escaped text string
 1778+ *
 1779+ * @param {String}
 1780+ * text String to be escaped
 1781+ * @return {string} escaped text string
17191782 */
17201783 mw.escapeQuotes = function( text ) {
17211784 var re = new RegExp("'","g");
@@ -1726,9 +1789,10 @@
17271790
17281791 /**
17291792 * Escape an HTML text string
1730 - * @param {String} text String to be escaped
1731 - * @return {string}
1732 - * escaped text html string
 1793+ *
 1794+ * @param {String}
 1795+ * text String to be escaped
 1796+ * @return {string} escaped text html string
17331797 */
17341798 mw.escapeQuotesHTML = function( text ) {
17351799 var re = new RegExp('&',"g");
@@ -1747,32 +1811,32 @@
17481812 var mwSetupFunctions = [];
17491813
17501814 /**
1751 - * Add a function to be run during setup ( prior to mw.ready)
1752 - * this is useful for building out interfaces that
1753 - * should be ready before mw.ready is called.
1754 - *
1755 - * @param {callback} Function Callback function must
1756 - * accept a ready function callback to be called once
1757 - * setup is done
1758 - */
 1815+ * Add a function to be run during setup ( prior to mw.ready) this is useful
 1816+ * for building out interfaces that should be ready before mw.ready is
 1817+ * called.
 1818+ *
 1819+ * @param {callback}
 1820+ * Function Callback function must accept a ready function
 1821+ * callback to be called once setup is done
 1822+ */
17591823 mw.addSetupHook = function( callback ) {
17601824 mwSetupFunctions.push ( callback ) ;
17611825 };
17621826
17631827 /**
1764 - * One time "setup" for mwEmbed
1765 - * run onDomReady ( so calls to setConfg apply to setup )
1766 - */
 1828+ * One time "setup" for mwEmbed run onDomReady ( so calls to setConfg apply
 1829+ * to setup )
 1830+ */
17671831 // Flag to ensure setup is only run once:
17681832 var mwSetupFlag = false;
17691833 mw.setupMwEmbed = function ( ) {
1770 - // Only run the setup once:
 1834+ // Only run the setup once:
17711835 if( mwSetupFlag ) {
17721836 return ;
17731837 }
17741838 mwSetupFlag = true;
17751839
1776 - // Apply any pre-setup config:
 1840+ // Apply any pre-setup config:
17771841 mw.setConfig( preMwEmbedConfig );
17781842
17791843
@@ -1780,16 +1844,16 @@
17811845
17821846 // Check core mwEmbed loader.js file ( to get configuration and paths )
17831847 mw.checkCoreLoaderFile( function(){
1784 - // Make sure we have jQuery
 1848+ // Make sure we have jQuery
17851849 mw.load( 'window.jQuery', function() {
17861850
1787 - // Add jQuery to $j var.
 1851+ // Add jQuery to $j var.
17881852 if ( ! window[ '$j' ] ) {
17891853 window[ '$j' ] = jQuery.noConflict();
17901854 }
17911855
1792 - // Get module loader.js, and language files
1793 - // ( will hit callback directly if set via resource loader )
 1856+ // Get module loader.js, and language files
 1857+ // ( will hit callback directly if set via resource loader )
17941858 mw.checkModuleLoaderFiles( function() {
17951859
17961860 // Set the User language
@@ -1803,7 +1867,7 @@
18041868 }
18051869 }
18061870
1807 - // Update the image path
 1871+ // Update the image path
18081872 mw.setConfig( 'imagesPath', mw.getMwEmbedPath() + 'skins/common/images/' );
18091873
18101874 // Set up AJAX to not send dynamic URLs for loading scripts
@@ -1811,27 +1875,30 @@
18121876 cache: true
18131877 } );
18141878
1815 - // Update the magic keywords
 1879+ // Update the magic keywords
18161880 mw.Language.magicSetup();
18171881
18181882 // Set up mvEmbed utility jQuery bindings
18191883 mw.dojQueryBindings();
18201884
18211885
1822 - // Special Hack for conditional jquery ui inclusion ( once Usability extension
1823 - // registers the jquery.ui skin in mw.style this won't be needed )
 1886+ // Special Hack for conditional jquery ui inclusion ( once
 1887+ // Usability extension
 1888+ // registers the jquery.ui skin in mw.style this won't be
 1889+ // needed )
18241890 if( mw.hasJQueryUiCss() ){
18251891 mw.style[ 'ui_' + mw.getConfig( 'jQueryUISkin' ) ] = true;
18261892 }
18271893
18281894
1829 - // Make sure style sheets are loaded:
 1895+ // Make sure style sheets are loaded:
18301896 mw.load( ['mw.style.mwCommon'] , function(){
1831 - // Run all the setup function hooks
1832 - // NOTE: setup functions are added via addSetupHook calls
 1897+ // Run all the setup function hooks
 1898+ // NOTE: setup functions are added via addSetupHook
 1899+ // calls
18331900 // and must include a callback.
18341901 //
1835 - // Once complete we can run .ready() queued functions
 1902+ // Once complete we can run .ready() queued functions
18361903 function runSetupFunctions() {
18371904 if( mwSetupFunctions.length ) {
18381905 mwSetupFunctions.shift()( function() {
@@ -1850,12 +1917,12 @@
18511918 };
18521919
18531920 /**
1854 - * Checks for jquery ui css by name jquery-ui-1.7.2.css
1855 - * NOTE: this is a hack for usability jquery-ui
1856 - * in the future usability should register a resource in mw.skin
1857 - *
1858 - * @return true if found, return false if not found
1859 - */
 1921+ * Checks for jquery ui css by name jquery-ui-1.7.2.css NOTE: this is a hack
 1922+ * for usability jquery-ui in the future usability should register a
 1923+ * resource in mw.skin
 1924+ *
 1925+ * @return true if found, return false if not found
 1926+ */
18601927 mw.hasJQueryUiCss = function(){
18611928 var hasUiCss = false;
18621929 // Load the jQuery ui skin if usability skin not set
@@ -1868,38 +1935,41 @@
18691936 return hasUiCss;
18701937 }
18711938
1872 - /**
 1939+ /**
18731940 * Loads the core mwEmbed "loader.js" file config
1874 - *
1875 - * NOTE: if using the ScriptLoader all the loaders and localization converters
1876 - * are included automatically
1877 - *
1878 - * @param {Function} callback Function called once core loader file is loaded
 1941+ *
 1942+ * NOTE: if using the ScriptLoader all the loaders and localization
 1943+ * converters are included automatically
 1944+ *
 1945+ * @param {Function}
 1946+ * callback Function called once core loader file is loaded
18791947 */
18801948 mw.checkCoreLoaderFile = function( callback ) {
1881 - // Check if we are using scriptloader ( handles loader include automatically )
 1949+ // Check if we are using scriptloader ( handles loader include
 1950+ // automatically )
18821951 if( mw.getResourceLoaderPath() ) {
18831952 callback();
18841953 return ;
18851954 }
18861955
1887 - // Check if we are using a static package ( mwEmbed path includes -static )
 1956+ // Check if we are using a static package ( mwEmbed path includes
 1957+ // -static )
18881958 if( mw.isStaticPackge() ){
18891959 callback();
18901960 return ;
18911961 }
18921962
18931963 // Add the Core loader to the request
1894 - // The follow code is ONLY RUN in debug / raw file mode
 1964+ // The follow code is ONLY RUN in debug / raw file mode
18951965 mw.load( 'loader.js', callback );
18961966 }
18971967
18981968 /**
1899 - * Checks if the javascript is a static package ( not using resource loader )
1900 - * @return {boolean}
1901 - * true the included script is static
1902 - * false the included script
1903 - */
 1969+ * Checks if the javascript is a static package ( not using resource loader )
 1970+ *
 1971+ * @return {boolean} true the included script is static false the included
 1972+ * script
 1973+ */
19041974 mw.isStaticPackge = function(){
19051975 var src = mw.getMwEmbedSrc();
19061976 if( src.indexOf('-static') !== -1 ){
@@ -1909,26 +1979,28 @@
19101980 }
19111981
19121982 /**
1913 - * Check for resource loader module loaders, and localization files
1914 - *
1915 - * NOTE: if using the ScriptLoader all the loaders and localization converters
1916 - * are included automatically.
1917 - */
 1983+ * Check for resource loader module loaders, and localization files
 1984+ *
 1985+ * NOTE: if using the ScriptLoader all the loaders and localization
 1986+ * converters are included automatically.
 1987+ */
19181988 mw.checkModuleLoaderFiles = function( callback ) {
19191989 mw.log( 'doLoaderCheck::' );
19201990
1921 - // Check if we are using scriptloader ( handles loader include automatically )
1922 - // Or if mwEmbed is a static package ( all resources are already loaded )
 1991+ // Check if we are using scriptloader ( handles loader include
 1992+ // automatically )
 1993+ // Or if mwEmbed is a static package ( all resources are already loaded
 1994+ // )
19231995 if( mw.getResourceLoaderPath() || mw.isStaticPackge() ) {
19241996 callback();
19251997 return ;
19261998 }
19271999
19282000 // Load the configured modules / components
1929 - // The follow code is ONLY RUN in debug / raw file mode
 2001+ // The follow code is ONLY RUN in debug / raw file mode
19302002 var loaderRequest = [];
19312003
1932 - //Load enabled components
 2004+ // Load enabled components
19332005 var enabledComponents = mw.getConfig( 'coreComponents' );
19342006 function loadEnabledComponents( enabledComponents ){
19352007 if( ! enabledComponents.length ){
@@ -1947,7 +2019,7 @@
19482020 loadEnabledComponents( enabledComponents );
19492021
19502022
1951 - // Set the loader context and get each loader individually
 2023+ // Set the loader context and get each loader individually
19522024 function loadEnabledModules( enabledModules ){
19532025 if( ! enabledModules.length ){
19542026 // If no more modules left load the LanguageFile
@@ -1968,7 +2040,7 @@
19692041 if( mw.getConfig( 'userLanguage' ) ) {
19702042 var langCode = mw.getConfig( 'userLanguage' );
19712043
1972 - // Load the language resource if not default 'en'
 2044+ // Load the language resource if not default 'en'
19732045 var transformKey = mw.getLangTransformKey( langCode );
19742046 if( transformKey != 'en' ){
19752047 // Upper case the first letter:
@@ -1995,21 +2067,20 @@
19962068 }
19972069
19982070 /**
1999 - * Checks if a css style rule exists
2000 - *
2001 - * On a page with lots of rules it can take some time
2002 - * so avoid calling this function where possible and
2003 - * cache its result
2004 - *
2005 - * NOTE: this only works for style sheets on the same domain :(
2006 - *
2007 - * @param {String} styleRule Style rule name to check
2008 - * @return {Boolean}
2009 - * true if the rule exists
2010 - * false if the rule does not exist
2011 - */
 2071+ * Checks if a css style rule exists
 2072+ *
 2073+ * On a page with lots of rules it can take some time so avoid calling this
 2074+ * function where possible and cache its result
 2075+ *
 2076+ * NOTE: this only works for style sheets on the same domain :(
 2077+ *
 2078+ * @param {String}
 2079+ * styleRule Style rule name to check
 2080+ * @return {Boolean} true if the rule exists false if the rule does not
 2081+ * exist
 2082+ */
20122083 mw.styleRuleExists = function ( styleRule ) {
2013 - // Set up the skin paths configuration
 2084+ // Set up the skin paths configuration
20142085 for( var i=0 ; i < document.styleSheets.length ; i++ ) {
20152086 var rules = null;
20162087 try{
@@ -2037,9 +2108,9 @@
20382109 var mwModuleLoaderCheckFlag = false;
20392110
20402111 /**
2041 - * This will get called when the DOM is ready
2042 - * Will check configuration and issue a mw.setupMwEmbed call if needed
2043 - */
 2112+ * This will get called when the DOM is ready Will check configuration and
 2113+ * issue a mw.setupMwEmbed call if needed
 2114+ */
20442115 mw.domReady = function ( ) {
20452116 if( mwDomReadyFlag ) {
20462117 return ;
@@ -2048,28 +2119,30 @@
20492120 // Set the onDomReady Flag
20502121 mwDomReadyFlag = true;
20512122
2052 - // Give us a chance to get to the bottom of the script.
2053 - // When loading mwEmbed asynchronously the dom ready gets called
2054 - // directly and in some browsers beets the $j = jQuery.noConflict(); call
2055 - // and causes symbol undefined errors.
 2123+ // Give us a chance to get to the bottom of the script.
 2124+ // When loading mwEmbed asynchronously the dom ready gets called
 2125+ // directly and in some browsers beets the $j = jQuery.noConflict();
 2126+ // call
 2127+ // and causes symbol undefined errors.
20562128 setTimeout(function(){
20572129 mw.setupMwEmbed();
20582130 },1);
20592131 }
20602132
20612133 /**
2062 - * A version comparison utility function
2063 - * Handles version of types {Major}.{MinorN}.{Patch}
2064 - *
2065 - * Note this just handles version numbers not patch letters.
2066 - *
2067 - * @param {String} minVersion Minnium version needed
2068 - * @param {String} clientVersion Client version to be checked
2069 -
2070 - * @return
2071 - * true if the version is at least of minVersion
2072 - * false if the version is less than minVersion
2073 - */
 2134+ * A version comparison utility function Handles version of types
 2135+ * {Major}.{MinorN}.{Patch}
 2136+ *
 2137+ * Note this just handles version numbers not patch letters.
 2138+ *
 2139+ * @param {String}
 2140+ * minVersion Minnium version needed
 2141+ * @param {String}
 2142+ * clientVersion Client version to be checked
 2143+ *
 2144+ * @return true if the version is at least of minVersion false if the
 2145+ * version is less than minVersion
 2146+ */
20742147 mw.versionIsAtLeast = function( minVersion, clientVersion ) {
20752148 var minVersionParts = minVersion.split('.')
20762149 var clientVersionParts = clientVersion.split('.');
@@ -2088,20 +2161,23 @@
20892162 /**
20902163 * Runs all the triggers on a given object with a single "callback"
20912164 *
2092 - * Normal tirgger calls will run the callback directly multiple times
2093 - * for every binded function.
 2165+ * Normal tirgger calls will run the callback directly multiple times for
 2166+ * every binded function.
20942167 *
2095 - * With runTriggersCallback() callback is not called until all the
2096 - * binded events have been run.
 2168+ * With runTriggersCallback() callback is not called until all the binded
 2169+ * events have been run.
20972170 *
2098 - * @param {object} targetObject Target object to run triggers on
2099 - * @param {string} triggerName Name of trigger to be run
2100 - * @param {function} callback Function called once all triggers have been run
 2171+ * @param {object}
 2172+ * targetObject Target object to run triggers on
 2173+ * @param {string}
 2174+ * triggerName Name of trigger to be run
 2175+ * @param {function}
 2176+ * callback Function called once all triggers have been run
21012177 *
21022178 */
21032179 mw.runTriggersCallback = function( targetObject, triggerName, callback ){
21042180 mw.log( ' runTriggersCallback:: ' + triggerName );
2105 - // If events are not present directly run callback
 2181+ // If events are not present directly run callback
21062182 if( ! $j( targetObject ).data( 'events' ) ||
21072183 ! $j( targetObject ).data( 'events' )[ triggerName ] ) {
21082184 mw.log( ' trigger name not found: ' + triggerName );
@@ -2129,16 +2205,15 @@
21302206 } );
21312207 }
21322208 /**
2133 - * Utility jQuery bindings
2134 - * Setup after jQuery is available ).
 2209+ * Utility jQuery bindings Setup after jQuery is available ).
21352210 */
21362211 mw.dojQueryBindings = function() {
21372212 mw.log( 'mw.dojQueryBindings' );
21382213 ( function( $ ) {
21392214
21402215 /**
2141 - * Set a given selector html to the loading spinner:
2142 - */
 2216+ * Set a given selector html to the loading spinner:
 2217+ */
21432218 $.fn.loadingSpinner = function( ) {
21442219 if ( this ) {
21452220 $j( this ).html(
@@ -2146,38 +2221,28 @@
21472222 .addClass( "loadingSpinner" )
21482223 );
21492224 }
2150 - /*
2151 - //var csstransforms = false;
2152 - if ( Modernizr.csstransforms ) {
2153 - var barNumber = 7;
2154 - var barContent = '';
2155 - var barSpacingDegrees = 360 / barNumber;
2156 - var barOpacityDelta = 1 / (barNumber);
2157 - for (i = 1; i < barNumber+1; i++) {
2158 - barContent += '<div class="bar' + i + '" style="-moz-transform:rotate(' + (i-1) * barSpacingDegrees + 'deg) translate(0, -40px);-webkit-transform:rotate(' + (i-1) * barSpacingDegrees + 'deg) translate(0, -40px);opacity:' + (i) * barOpacityDelta + '; background:#000"/>';
2159 - }
2160 - $j( this ).html(
2161 - $j( '<div />' )
2162 - .addClass( "cssLoadingSpinner" )
2163 - .html( barContent )
2164 - );
2165 - var rotations = 0;
2166 - setInterval( function ( ) {
2167 - $j('.cssLoadingSpinner')
2168 - .css('-moz-transform','rotate('+rotations+'deg)')
2169 - .css('-webkit-transform','rotate('+rotations+'deg)');
2170 - if( rotations == 360 ) {
2171 - rotations = 0;
2172 - }
2173 - rotations += 5;
2174 - }, 25);
2175 - }
2176 - */
 2225+ /*
 2226+ * //var csstransforms = false; if ( Modernizr.csstransforms ) {
 2227+ * var barNumber = 7; var barContent = ''; var barSpacingDegrees =
 2228+ * 360 / barNumber; var barOpacityDelta = 1 / (barNumber); for
 2229+ * (i = 1; i < barNumber+1; i++) { barContent += '<div
 2230+ * class="bar' + i + '" style="-moz-transform:rotate(' + (i-1) *
 2231+ * barSpacingDegrees + 'deg) translate(0,
 2232+ * -40px);-webkit-transform:rotate(' + (i-1) * barSpacingDegrees +
 2233+ * 'deg) translate(0, -40px);opacity:' + (i) * barOpacityDelta + ';
 2234+ * background:#000"/>'; } $j( this ).html( $j( '<div />' )
 2235+ * .addClass( "cssLoadingSpinner" ) .html( barContent ) ); var
 2236+ * rotations = 0; setInterval( function ( ) {
 2237+ * $j('.cssLoadingSpinner')
 2238+ * .css('-moz-transform','rotate('+rotations+'deg)')
 2239+ * .css('-webkit-transform','rotate('+rotations+'deg)'); if(
 2240+ * rotations == 360 ) { rotations = 0; } rotations += 5; }, 25); }
 2241+ */
21772242 return this;
21782243 }
21792244 /**
2180 - * Add an absolute overlay spinner useful for cases where the element
2181 - * does not display child elements, ( images, video )
 2245+ * Add an absolute overlay spinner useful for cases where the
 2246+ * element does not display child elements, ( images, video )
21822247 */
21832248 $.fn.getAbsoluteOverlaySpinner = function(){
21842249 var pos = $j( this ).offset();
@@ -2203,8 +2268,8 @@
22042269 }
22052270
22062271 /**
2207 - * dragDrop file loader
2208 - */
 2272+ * dragDrop file loader
 2273+ */
22092274 $.fn.dragFileUpload = function ( conf ) {
22102275 if ( this.selector ) {
22112276 var _this = this;
@@ -2216,8 +2281,8 @@
22172282 }
22182283
22192284 /**
2220 - * Shortcut to a themed button
2221 - * Should be depreciated for $.button bellow
 2285+ * Shortcut to a themed button Should be depreciated for $.button
 2286+ * bellow
22222287 */
22232288 $.btnHtml = function( msg, styleClass, iconId, opt ) {
22242289 if ( !opt )
@@ -2231,7 +2296,8 @@
22322297 '<span class="btnText">' + msg + '</span></a>';
22332298 };
22342299
2235 - // Shortcut to jQuery button ( should replace all btnHtml with button )
 2300+ // Shortcut to jQuery button ( should replace all btnHtml with
 2301+ // button )
22362302 var mw_default_button_options = {
22372303 // The class name for the button link
22382304 'class' : '',
@@ -2249,11 +2315,11 @@
22502316 $.button = function( options ) {
22512317 var options = $j.extend( mw_default_button_options, options);
22522318
2253 - // Button:
 2319+ // Button:
22542320 var $btn = $j('<a />')
22552321 .attr('href', '#')
22562322 .addClass( 'ui-state-default ui-corner-all ui-icon_link' );
2257 - // Add css if set:
 2323+ // Add css if set:
22582324 if( options.css ) {
22592325 $btn.css( options.css )
22602326 }
@@ -2284,9 +2350,11 @@
22852351 };
22862352
22872353 /**
2288 - * Resize a dialog to fit the window
2289 - * @param {Object} options horizontal and vertical space ( default 50 )
2290 - */
 2354+ * Resize a dialog to fit the window
 2355+ *
 2356+ * @param {Object}
 2357+ * options horizontal and vertical space ( default 50 )
 2358+ */
22912359 $.fn.dialogFitWindow = function( options ) {
22922360 var opt_default = { 'hspace':50, 'vspace':50 };
22932361 if ( !options )
@@ -2295,7 +2363,8 @@
22962364 $j( this.selector ).dialog( 'option', 'width', $j( window ).width() - options.hspace );
22972365 $j( this.selector ).dialog( 'option', 'height', $j( window ).height() - options.vspace );
22982366 $j( this.selector ).dialog( 'option', 'position', 'center' );
2299 - // update the child position: (some of this should be pushed up-stream via dialog config options
 2367+ // update the child position: (some of this should be pushed
 2368+ // up-stream via dialog config options
23002369 $j( this.selector + '~ .ui-dialog-buttonpane' ).css( {
23012370 'position':'absolute',
23022371 'left':'0px',
@@ -2311,13 +2380,11 @@
23122381
23132382
23142383 /**
2315 -* Set DOM-ready call
2316 -* We copy jQuery( document ).ready here since sometimes
2317 -* mwEmbed.js is included without jQuery
2318 -* and we need our own "ready" system so that
2319 -* mwEmbed interfaces can support async built out
2320 -* and the inclution of jQuery.
2321 -*/
 2384+ * Set DOM-ready call We copy jQuery( document ).ready here since sometimes
 2385+ * mwEmbed.js is included without jQuery and we need our own "ready" system so
 2386+ * that mwEmbed interfaces can support async built out and the inclution of
 2387+ * jQuery.
 2388+ */
23222389 var mwDomIsReady = false;
23232390 function runMwDomReady(){
23242391 mwDomIsReady = true;
@@ -2325,7 +2392,7 @@
23262393 mw.domReady()
23272394 }
23282395 }
2329 -// Check if already ready:
 2396+// Check if already ready:
23302397 if ( document.readyState === "complete" ) {
23312398 runMwDomReady();
23322399 }
@@ -2339,7 +2406,8 @@
23402407
23412408 } else if ( document.attachEvent ) {
23422409 DOMContentLoaded = function() {
2343 - // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
 2410+ // Make sure body exists, at least, in case IE gets a little overzealous
 2411+ // (ticket #5443).
23442412 if ( document.readyState === "complete" ) {
23452413 document.detachEvent( "onreadystatechange", DOMContentLoaded );
23462414 runMwDomReady();
@@ -2395,8 +2463,9 @@
23962464 }
23972465
23982466
2399 -// If using the resource loader and jQuery has not been set give a warning to the user:
2400 -// (this is needed because packaged loader.js files could refrence jQuery )
 2467+// If using the resource loader and jQuery has not been set give a warning to
 2468+// the user:
 2469+// (this is needed because packaged loader.js files could refrence jQuery )
24012470 if( mw.getResourceLoaderPath() && !window.jQuery ) {
24022471 mw.log( 'Error: jQuery is required for mwEmbed, please update your resource loader request' );
24032472 }
@@ -2406,14 +2475,13 @@
24072476 }
24082477
24092478 /**
2410 - * Hack to keep jQuery in $ when its
2411 - * already there, but also use noConflict to get $j = jQuery
 2479+ * Hack to keep jQuery in $ when its already there, but also use noConflict to
 2480+ * get $j = jQuery
24122481 *
2413 - * This way sites that use $ for jQuery continue to work after
2414 - * including mwEmbed javascript.
 2482+ * This way sites that use $ for jQuery continue to work after including mwEmbed
 2483+ * javascript.
24152484 *
2416 - * Also if jQuery is included prior to mwEmbed we ensure
2417 - * $j is set
 2485+ * Also if jQuery is included prior to mwEmbed we ensure $j is set
24182486 */
24192487
24202488 if( window.jQuery ){
Index: branches/MwEmbedStandAlone/modules/SmilPlayer/mw.SmilBody.js
@@ -49,12 +49,8 @@
5050 var _this = this;
5151 if( !$node.attr('id')
5252 && !$node.attr( 'xml:id' )
53 - && (
54 - _this.getNodeSmilType( $node ) == 'ref'
55 - || _this.getNodeSmilType( $node ) == 'smilText'
56 - )
5753 ){
58 - $node.attr('id', _this.smil.embedPlayer.id + '_ref_' + _this.idIndex );
 54+ $node.attr('id', _this.getNodeSmilType( $node ) + '_' + _this.idIndex );
5955 mw.log('SmilBody:: gave: ' + $node.get(0).nodeName + ' id: ' + $node.attr('id') );
6056 _this.idIndex++;
6157 }
@@ -248,16 +244,28 @@
249245 },
250246
251247 /**
252 - * getElementsForTimeRecurse
253 - * @param {Object} $node Node to recursively search for elements in the given time range
254 - */
 248+ * get the sequence elements from a given par node if no node is provied assume root
 249+ * @param {element=} $parNode Optional parNode to list all sequence timelines
 250+ */
 251+ getSeqElements: function( $node ){
 252+ if( ! $node ){
 253+ $node = this.$dom;
 254+ }
 255+ return $node.find('seq');
 256+ },
255257
 258+
256259 /**
257260 * Recurse over all body elements, issues a callback on all ref and smilText nodes
258261 * adds startOffset info for easy timeline checks.
 262+ * @param {Object} $node Node Starting point
259263 */
260264 getRefElementsRecurse: function( $node, startOffset, callback ){
261265 var _this = this;
 266+
 267+ // Make sure $node is wrapped in jQuery object
 268+ $node = $j( $node );
 269+
262270 // Setup local pointers:
263271 var nodeType = this.getNodeSmilType( $node );
264272
@@ -301,8 +309,8 @@
302310 * Returns the smil body duration
303311 * ( wraps getDurationRecurse to get top level node duration )
304312 */
305 - getDuration: function(){
306 - this.duration = this.getNodeDuration( this.$dom );
 313+ getDuration: function( forceRefresh ){
 314+ this.duration = this.getNodeDuration( this.$dom , forceRefresh);
307315 mw.log("smilBody:: getDuration: " + this.duration );
308316 return this.duration;
309317 },
@@ -318,6 +326,11 @@
319327 ) {
320328 return $node.data('computedDuration');
321329 }
 330+ if( forceRefresh ){
 331+ //clear out implictDuration
 332+ $node.data( 'implictDuration', false );
 333+ $node.data( 'computedDuration', false );
 334+ }
322335
323336 var _this = this;
324337 var duration = 0;
Index: branches/MwEmbedStandAlone/modules/SmilPlayer/loader.js
@@ -1,4 +1,4 @@
2 -/*
 2+/**
33 * Loader for smilPlayer
44 */
55 // Wrap in mw to not pollute global namespace
@@ -47,7 +47,7 @@
4848 /**
4949 * Check if a video tag element has a smil source
5050 */
51 - mw.CheckElementForSMIL = function( element ){
 51+ mw.CheckElementForSMIL = function( element ){
5252 if( $j( element ) .attr('type' ) == 'application/smil' ||
5353 ( $j( element ).attr('src' ) &&
5454 $j( element ).attr('src' ).substr( -4) == 'smil' ) )
Index: branches/MwEmbedStandAlone/modules/SmilPlayer/mw.Smil.js
@@ -1,378 +1,394 @@
22 /**
3 - * The Smil object
4 - *
 3+ * The Smil object
 4+ *
55 * @copyright kaltura
6 - * @author: Michael Dale mdale@wikimedia.org
 6+ * @author: Michael Dale mdale@wikimedia.org
77 * @license GPL2
88 *
99 * Sequence player wraps smil into the video tag
1010 *
11 - * Provides an html5 video tag like api to a smil document.
12 - *
13 - * Supports frame by frame rendering of "smil"
14 - * Supports "drop frame" realtime playback of "smil"
 11+ * Provides an html5 video tag like api to a smil document.
1512 *
16 - * Extends the "embedPlayer" and represents the playlist as a single video stream
 13+ * Supports frame by frame rendering of "smil" Supports "drop frame" realtime
 14+ * playback of "smil"
1715 *
 16+ * Extends the "embedPlayer" and represents the playlist as a single video
 17+ * stream
 18+ *
1819 */
19 -
 20+
2021 /* Add the hooks needed for playback */
21 -mw.Smil = function( options ){
22 - return this.init( options );
 22+mw.Smil = function(options) {
 23+ return this.init(options);
2324 }
2425 mw.Smil.prototype = {
25 -
26 - // Store the mw.SmilLayout object
 26+
 27+ // Store the mw.SmilLayout object
2728 layout : null,
28 -
 29+
2930 // Stores the mw.SmilBody object
3031 body : null,
31 -
 32+
3233 // Stores the mw.SmilBuffer object
33 - buffer: null,
34 -
35 - // Stores the mw.SmilAnimate object
36 - animate: null,
37 -
 34+ buffer : null,
 35+
 36+ // Stores the mw.SmilAnimate object
 37+ animate : null,
 38+
3839 // Stores the mw.SmilTransisions object
39 - transitions: null,
40 -
41 - // Stores the smil document for this object ( for relative image paths )
42 - smilUrl: null,
43 -
44 - // The abstract embed player parent
45 - embedPlayer: null,
46 -
47 - /**
48 - * Constructor
49 - * @param {Object} embedPlayer Reference to the embedPlayer driving the smil object
50 - */
51 - init: function( embedPlayer ) {
52 - mw.log(" Smil:: init with player: " + embedPlayer.id );
 40+ transitions : null,
 41+
 42+ // Stores the smil document for this object ( for relative image paths )
 43+ smilUrl : null,
 44+
 45+ // The abstract embed player parent
 46+ embedPlayer : null,
 47+
 48+ /**
 49+ * Constructor
 50+ *
 51+ * @param {Object}
 52+ * embedPlayer Reference to the embedPlayer driving the smil
 53+ * object
 54+ */
 55+ init : function(embedPlayer) {
 56+ mw.log(" Smil:: init with player: " + embedPlayer.id);
5357 this.embedPlayer = embedPlayer;
5458 },
55 -
56 - /**
57 - * Load smil into this object from a url
58 - * @parm {string} url Source url of smil XML
59 - * @param {function} callback Function to call once smil is loaded and ready
60 - */
61 - loadFromUrl: function( url , callback ) {
 59+
 60+ /**
 61+ * Load smil into this object from a url
 62+ *
 63+ * @parm {string} url Source url of smil XML
 64+ * @param {function}
 65+ * callback Function to call once smil is loaded and ready
 66+ */
 67+ loadFromUrl : function(url, callback) {
6268 var _this = this;
63 - this.smilUrl = url;
64 - mw.log( 'Smil::loadFromUrl : ' + url );
65 -
66 - // Try for direct load ( api cross domain loading is handled outside of SmilInterface
67 - $j.get( url, function( data ) {
68 - _this.loadFromString( data );
 69+ this.smilUrl = url;
 70+ mw.log('Smil::loadFromUrl : ' + url);
 71+
 72+ // Try for direct load ( api cross domain loading is handled outside of
 73+ // SmilInterface
 74+ $j.get(url, function(data) {
 75+ _this.loadFromString(data);
6976 // XXX check success or failure
70 - callback();
71 - });
 77+ callback();
 78+ });
7279 },
73 -
 80+
7481 /**
75 - * Set smil from xml string
76 - * @param {string} SmilXmlString Xml string of smil to be processed
77 - */
78 - loadFromString: function ( smilXmlString ){
 82+ * Set smil from xml string
 83+ *
 84+ * @param {string}
 85+ * SmilXmlString Xml string of smil to be processed
 86+ */
 87+ loadFromString : function(smilXmlString) {
7988 // Load the parsed string into the local "dom"
80 - this.$dom = $j( smilXmlString );
81 -
82 - mw.log( "Smil::loadFromString: loaded smil dom: " + this.$dom );
83 -
 89+ this.$dom = $j(smilXmlString);
 90+
 91+ mw.log("Smil::loadFromString: loaded smil dom: " + this.$dom);
 92+
8493 // Clear out the layout
8594 this.layout = null;
86 -
87 - // Clear out the body
 95+
 96+ // Clear out the body
8897 this.body = null;
89 -
 98+
9099 // Clear out the top level duration
91100 this.duration = null;
92 -
 101+
93102 // Clear out the "buffer" object
94103 this.buffer = null;
95104 },
96 -
 105+
97106 /**
98 - * Internal function to get the jQuery smil dom
99 - */
100 - getDom: function() {
101 - if( this.$dom ) {
 107+ * Internal function to get the jQuery smil dom
 108+ */
 109+ getDom : function() {
 110+ if (this.$dom) {
102111 return this.$dom;
103112 }
104 - mw.log( "Error SMIL Dom not available" ) ;
105 - return ;
 113+ mw.log("Error SMIL Dom not available");
 114+ return;
106115 },
107 -
 116+
108117 /**
109118 * Render a specific time
110119 */
111 - renderTime: function( time, callback ) {
112 - // Setup the layout if not already setup:
113 - this.getLayout().setupLayout( this.embedPlayer.getRenderTarget() );
114 -
 120+ renderTime : function(time, callback) {
 121+ // Setup the layout if not already setup:
 122+ this.getLayout().setupLayout(this.embedPlayer.getRenderTarget());
 123+
115124 // Update the render target with bodyElements for the requested time
116 - this.getBody().renderTime( time );
117 -
 125+ this.getBody().renderTime(time);
 126+
118127 // Wait until buffer is ready and run the callback
119 - this.getBuffer().addAssetsReadyCallback( callback );
 128+ this.getBuffer().addAssetsReadyCallback(callback);
120129 },
121 -
122 -
 130+
123131 /**
124 - * We use animateTime instead of a tight framerate loop
125 - * so that we can optimize with css transformations
126 - *
127 - */
128 - animateTime: function( time, timeDelta ){
129 - //mw.log("Smil::animateTime: " + time + ' delta: ' + timeDelta );
130 - this.getBody().renderTime( time, timeDelta );
 132+ * We use animateTime instead of a tight framerate loop so that we can
 133+ * optimize with css transformations
 134+ *
 135+ */
 136+ animateTime : function(time, timeDelta) {
 137+ // mw.log("Smil::animateTime: " + time + ' delta: ' + timeDelta );
 138+ this.getBody().renderTime(time, timeDelta);
131139 },
132 -
 140+
133141 /**
134142 * Pause all animations and playback
135143 */
136 - pause: function( currentTime ){
137 - this.getBody().pause( currentTime );
 144+ pause : function(currentTime) {
 145+ this.getBody().pause(currentTime);
138146 },
139 -
 147+
140148 /**
141 - * Checks if the playback is in sync with the current time
142 - * @return {boolean}
143 - * true if playback is insync,
144 - * false if not in sync with all animation elements ( video tag for now )
 149+ * Checks if the playback is in sync with the current time
 150+ *
 151+ * @return {boolean} true if playback is insync, false if not in sync with
 152+ * all animation elements ( video tag for now )
145153 */
146 - getPlaybackSyncDelta: function( currentTime ){
147 - return this.getAnimate().getPlaybackSyncDelta( currentTime );
 154+ getPlaybackSyncDelta : function(currentTime) {
 155+ return this.getAnimate().getPlaybackSyncDelta(currentTime);
148156 },
149 -
150 - getBufferedPercent: function(){
 157+
 158+ getBufferedPercent : function() {
151159 // Get the clip buffered percent
152160 return this.getBuffer().getBufferedPercent();
153161 },
154 -
 162+
155163 /**
156 - * Get the set of audio ranges for flattening.
 164+ * Get the set of audio ranges for flattening.
157165 */
158 - getAudioTimeSet: function(){
 166+ getAudioTimeSet : function() {
159167 return this.getBody().getFlatAudioTimeLine();
160168 },
161 -
 169+
162170 /**
163 - * Pass on the request to start buffering the entire sequence of clips
 171+ * Pass on the request to start buffering the entire sequence of clips
164172 */
165 - startBuffer: function(){
 173+ startBuffer : function() {
166174 this.getBuffer().startBuffer();
167175 },
168 -
 176+
169177 /**
170 - * Get the smil buffer object
171 - */
172 - getBuffer: function(){
173 - if( ! this.buffer ) {
174 - this.buffer = new mw.SmilBuffer( this ) ;
 178+ * Get the smil buffer object
 179+ */
 180+ getBuffer : function() {
 181+ if (!this.buffer) {
 182+ this.buffer = new mw.SmilBuffer(this);
175183 }
176 - return this.buffer;
 184+ return this.buffer;
177185 },
178 -
 186+
179187 /**
180 - * Get the animate object
181 - */
182 - getAnimate: function(){
183 - if( ! this.animate ){
184 - this.animate = new mw.SmilAnimate( this );
 188+ * Get the animate object
 189+ */
 190+ getAnimate : function() {
 191+ if (!this.animate) {
 192+ this.animate = new mw.SmilAnimate(this);
185193 }
186194 return this.animate;
187195 },
188 -
 196+
189197 /**
190 - * Get the smil layout object, with reference to the body
 198+ * Get the smil layout object, with reference to the body
191199 */
192 - getLayout: function() {
193 - if( !this.layout ) {
194 - this.layout = new mw.SmilLayout( this );
 200+ getLayout : function() {
 201+ if (!this.layout) {
 202+ this.layout = new mw.SmilLayout(this);
195203 }
196204 return this.layout;
197205 },
198 -
 206+
199207 /**
200208 * Get the smil body object
201209 */
202 - getBody: function(){
203 - if( !this.body ){
204 - this.body = new mw.SmilBody( this );
 210+ getBody : function() {
 211+ if (!this.body) {
 212+ this.body = new mw.SmilBody(this);
205213 }
206214 return this.body;
207215 },
208216 /**
209217 * Get the transitions object
210218 */
211 - getTransitions: function(){
212 - if( !this.transitions ){
213 - this.transitions = new mw.SmilTransitions( this );
 219+ getTransitions : function() {
 220+ if (!this.transitions) {
 221+ this.transitions = new mw.SmilTransitions(this);
214222 }
215223 return this.transitions;
216224 },
217 -
218 - /**
219 - * Function called continuously to keep sync smil "in sync"
220 - * Checks buffer states...
 225+
 226+ /**
 227+ * Function called continuously to keep sync smil "in sync" Checks buffer
 228+ * states...
221229 */
222 - syncWithTime: function( time ){
 230+ syncWithTime : function(time) {
223231 /* .. not yet implementd ... */
224 - mw.log( 'smil sync: ' + time);
 232+ mw.log('smil sync: ' + time);
225233 },
226 -
227 -
 234+
228235 /**
229236 * Get the duration form the smil body
230237 */
231 - getDuration: function(){
 238+ getDuration : function( forceRefresh ) {
232239 // return 0 while we don't have the $dom loaded
233 - if( !this.$dom ){
 240+ if (!this.$dom) {
234241 return 0;
235242 }
236 -
237 - if( !this.duration ){
238 - this.duration = this.getBody().getDuration();
 243+
 244+ if (!this.duration || forceRefresh ) {
 245+ this.duration = this.getBody().getDuration( forceRefresh );
239246 }
240 - return this.duration;
 247+ return this.duration;
241248 },
 249+ removeById: function ( smilElementId ) {
 250+ var $smilElement = this.$dom.find( '#' + smilElementId );
 251+
 252+ // Remove from layout
 253+ this.getLayout().getRootLayout().find( '#' + this.getAssetId( $smilElement ) )
 254+ .remove();
242255
 256+ // remove from dom
 257+ $smilElement.remove();
 258+
 259+ // xxx todo invalidate dom duration cache
 260+ },
243261 /**
244262 * Some Smil Utility functions
245 - */
246 -
 263+ */
 264+
247265 /**
248 - * maps a smil element id to a html 'safer' id
249 - * as a decedent subname of the embedPlayer parent
250 - *
251 - * @param {Object} smilElement Element to get id for
252 - */
253 - getAssetId: function( smilElement ){
254 - if(! $j( smilElement ).attr('id') ) {
255 - mw.log("Error: getAssetId smilElement missing id " ) ;
256 - return false;
 266+ * maps a smil element id to a html 'safer' id as a decedent subname of the
 267+ * embedPlayer parent
 268+ *
 269+ * @param {Object}
 270+ * smilElement Element to get id for
 271+ */
 272+ getAssetId : function(smilElement) {
 273+ if (!$j(smilElement).attr('id')) {
 274+ mw.log("Error: getAssetId smilElement missing id ");
 275+ return false;
257276 }
258 - if( ! this.embedPlayer || ! this.embedPlayer.id ) {
 277+ if (!this.embedPlayer || !this.embedPlayer.id) {
259278 mw.log("Error: getAssetId missing parent embedPlayer");
260279 return false;
261280 }
262 - return this.embedPlayer.id + '_' + $j( smilElement ).attr('id');
 281+ return this.embedPlayer.id + '_' + $j(smilElement).attr('id');
263282 },
264 -
 283+
265284 /**
266 - * Get an absolute path to asset based on the smil URL
267 - * @param {string} assetPath Path to asset to be transformed into url
268 - */
269 - getAssetUrl: function( assetPath ){
270 - // Context url is the smil document url:
271 - var contextUrl = mw.absoluteUrl( this.smilUrl );
272 - return mw.absoluteUrl( assetPath, contextUrl );
 285+ * Get an absolute path to asset based on the smil URL
 286+ *
 287+ * @param {string}
 288+ * assetPath Path to asset to be transformed into url
 289+ */
 290+ getAssetUrl : function(assetPath) {
 291+ // Context url is the smil document url:
 292+ var contextUrl = mw.absoluteUrl(this.smilUrl);
 293+ return mw.absoluteUrl(assetPath, contextUrl);
273294 },
274 -
 295+
275296 /**
276297 * Get the smil resource type based on nodeName and type attribute
277298 */
278 - getRefType: function( smilElement ) {
279 - if( $j( smilElement ).length == 0 ){
 299+ getRefType : function(smilElement) {
 300+ if ($j(smilElement).length == 0) {
280301 mw.log('Error: Smil::getRefType on empty smilElement');
281302 return;
282303 }
283304 // Get the smil type
284 - var smilType = $j( smilElement ).get(0).nodeName.toLowerCase();
285 -
286 - if( this.getBody().smilBlockTypeMap[ smilType ] != 'ref' ){
287 - mw.log("Error: trying to get ref type of node that is not a ref" + smilType);
288 - return null;
 305+ var smilType = $j(smilElement).get(0).nodeName.toLowerCase();
 306+
 307+ if (this.getBody().smilBlockTypeMap[smilType] != 'ref') {
 308+ mw.log("Error: trying to get ref type of node that is not a ref"
 309+ + smilType);
 310+ return null;
289311 }
290 -
 312+
291313 // If the smilType is ref, check for a content type
292 - if( smilType == 'ref' ){
293 - switch( $j( smilElement ).attr( 'type' ) ) {
294 - case 'text/html':
295 - smilType = 'cdata_html';
 314+ if (smilType == 'ref') {
 315+ switch ($j(smilElement).attr('type')) {
 316+ case 'text/html':
 317+ smilType = 'cdata_html';
296318 break;
297 - case 'video/ogg':
298 - case 'video/h.264':
299 - case 'video/webm':
300 - smilType = 'video';
 319+ case 'video/ogg':
 320+ case 'video/h.264':
 321+ case 'video/webm':
 322+ smilType = 'video';
301323 break;
302 - case 'audio/ogg':
303 - smilType = 'audio';
 324+ case 'audio/ogg':
 325+ smilType = 'audio';
304326 break;
305327 }
306328 }
307329 return smilType;
308330 },
309 -
310 - /**
 331+
 332+ /**
311333 * Parse smil time function
312334 * http://www.w3.org/TR/SMIL3/smil-timing.html#Timing-ClockValueSyntax
313335 *
314 - * Smil time has the following structure:
315 - *
316 - * Clock-value ::= ( Full-clock-value | Partial-clock-value | Timecount-value )
317 - * Full-clock-value ::= Hours ":" Minutes ":" Seconds ("." Fraction)?
318 - * Partial-clock-value ::= Minutes ":" Seconds ("." Fraction)?
319 - * Timecount-value ::= Timecount ("." Fraction)? (Metric)?
320 - * Metric ::= "h" | "min" | "s" | "ms"
321 - * Hours ::= DIGIT+ // any positive number
322 - * Minutes ::= 2DIGIT // range from 00 to 59
323 - * Seconds ::= 2DIGIT // range from 00 to 59
324 - * Fraction ::= DIGIT+
325 - * Timecount ::= DIGIT+
326 - * 2DIGIT ::= DIGIT DIGIT
327 - * DIGIT ::= [0-9]
 336+ * Smil time has the following structure:
328337 *
329 - * @param {mixed} timeValue time value of smil structure
330 - * @return {float} Seconds from time value, if timeValue is empty or null return 0
 338+ * Clock-value ::= ( Full-clock-value | Partial-clock-value |
 339+ * Timecount-value ) Full-clock-value ::= Hours ":" Minutes ":" Seconds ("."
 340+ * Fraction)? Partial-clock-value ::= Minutes ":" Seconds ("." Fraction)?
 341+ * Timecount-value ::= Timecount ("." Fraction)? (Metric)? Metric ::= "h" |
 342+ * "min" | "s" | "ms" Hours ::= DIGIT+ // any positive number Minutes ::=
 343+ * 2DIGIT // range from 00 to 59 Seconds ::= 2DIGIT // range from 00 to 59
 344+ * Fraction ::= DIGIT+ Timecount ::= DIGIT+ 2DIGIT ::= DIGIT DIGIT DIGIT ::=
 345+ * [0-9]
 346+ *
 347+ * @param {mixed}
 348+ * timeValue time value of smil structure
 349+ * @return {float} Seconds from time value, if timeValue is empty or null
 350+ * return 0
331351 */
332 - parseTime : function( timeValue ){
333 - if( !timeValue )
 352+ parseTime : function(timeValue) {
 353+ if (!timeValue)
334354 return 0;
335 -
336 - // If timeValue is already a clean number of seconds, return seconds:
337 - if( ! isNaN( timeValue ) ){
338 - return parseFloat( timeValue );
339 - }
340 - // Trim whitespace if empty return zero
341 - timeValue = $j.trim( timeValue );
342 - if( timeValue == '' ){
343 - return 0;
344 - }
345 -
346 - // First check for hh:mm:ss time:
347 - if ( timeValue.split( ':' ).length == 3 || timeValue.split( ':' ).length == 2 ) {
348 - return mw.npt2seconds( timeValue );
349 - }
350 -
351 - var timeFactor = null
352 - // Check for metric hours
353 - if( timeValue.substr( -1 ) == 'h' ){
354 - timeFactor = 3600 ;
355 - }
356 - // Min metric
357 - if( timeValue.substr( -3 ) == 'min' ){
358 - timeFactor = 60;
359 - }
360 - // Seconds
361 - if( timeValue.substr( -1 ) == 's'){
362 - timeFactor = 1;
363 - }
364 - // Millaseconds
365 - if( timeValue.substr( -2 ) == 'ms'){
366 - timeFactor = .001;
367 - }
368 -
369 - if( timeFactor){
370 - return parseFloat( parseFloat( timeValue ) * timeFactor );
371 - }
372 - mw.log("Error could not parse time: " + timeValue);
 355+
 356+ // If timeValue is already a clean number of seconds, return seconds:
 357+ if (!isNaN(timeValue)) {
 358+ return parseFloat(timeValue);
 359+ }
 360+ // Trim whitespace if empty return zero
 361+ timeValue = $j.trim(timeValue);
 362+ if (timeValue == '') {
373363 return 0;
374364 }
375 -}
376365
 366+ // First check for hh:mm:ss time:
 367+ if (timeValue.split(':').length == 3 || timeValue.split(':').length == 2) {
 368+ return mw.npt2seconds(timeValue);
 369+ }
377370
 371+ var timeFactor = null
 372+ // Check for metric hours
 373+ if (timeValue.substr(-1) == 'h') {
 374+ timeFactor = 3600;
 375+ }
 376+ // Min metric
 377+ if (timeValue.substr(-3) == 'min') {
 378+ timeFactor = 60;
 379+ }
 380+ // Seconds
 381+ if (timeValue.substr(-1) == 's') {
 382+ timeFactor = 1;
 383+ }
 384+ // Millaseconds
 385+ if (timeValue.substr(-2) == 'ms') {
 386+ timeFactor = .001;
 387+ }
378388
379 -
\ No newline at end of file
 389+ if (timeFactor) {
 390+ return parseFloat(parseFloat(timeValue) * timeFactor);
 391+ }
 392+ mw.log("Error could not parse time: " + timeValue);
 393+ return 0;
 394+}
 395+}
Index: branches/MwEmbedStandAlone/modules/SmilPlayer/tests/VideoCrossFade.html
@@ -26,7 +26,7 @@
2727 'statusTarget': '#targetFoggStatus'
2828 });
2929 if( foggRender.doRender() ){
30 - $j('#renderToFile').text('Stop Render').click(function(){
 30+ $j('#renderToFile').text('Stop Render').unbind().click(function(){
3131 foggRender.stopRender();
3232 });
3333 }
Index: branches/MwEmbedStandAlone/modules/SmilPlayer/tests/VideoClipBegin.html
@@ -26,7 +26,7 @@
2727 'statusTarget': '#targetFoggStatus'
2828 });
2929 if( foggRender.doRender() ){
30 - $j('#renderToFile').text('Stop Render').click(function(){
 30+ $j('#renderToFile').text('Stop Render').unbind().click(function(){
3131 foggRender.stopRender();
3232 });
3333 }
@@ -42,17 +42,21 @@
4343 <tr>
4444 <td>
4545
46 -<video id="videoClipBegin" type="application/smil" src="VideoClipBeginSmil.xml" width="400" height="300"></video>
 46+<video id="videoClipBegin" width="400" height="300">
 47+ <source type="application/smil" src="VideoClipBeginSmil.xml" />
 48+</video>
4749 <p></p>seek to <input id="seekInputTime" size="4" value = "6"></input><span id="seekInProgress" style="display: none"> Seeking<blink>...</blink></span>
4850 <br/>
4951 <a id="startBuffer" href="#">Start buffering</a> <br>
5052 <a id="renderToFile" href="#">Render to file</a> <span id="targetFoggStatus"></span>
5153 </td>
5254 <td valign="top">
53 -Sample playlist code:
 55+Sample Smil Embed code:
5456 <div style="clear:both"></div>
5557 <textarea style="width:500px;">
56 -<video id="videoClipBegin" type="application/smil" src="VideoClipBeginSmil.xml" width="400" height="300"></video>
 58+<video id="videoClipBegin" width="400" height="300">
 59+ <source type="application/smil" src="VideoClipBeginSmil.xml" />
 60+</video>
5761 </textarea>
5862 <div style="clear:both"></div>
5963
Index: branches/MwEmbedStandAlone/modules/SmilPlayer/tests/VideoClipBeginSmil.xml
@@ -40,7 +40,7 @@
4141
4242 <video src="http://upload.wikimedia.org/wikipedia/commons/8/8b/Yochai_Benkler_-_On_Autonomy%2C_Control_and_Cultural_Experience.ogg"
4343 transIn="fromBlack"
44 - dur="10"
 44+ dur="0:3:43"
4545 clipBegin = "0:3:43"
4646 />
4747
Index: branches/MwEmbedStandAlone/modules/SmilPlayer/mw.SmilHooks.js
@@ -1,19 +1,25 @@
22
33 // Define the SmilHooks object
4 -mw.SmilHooks = {};
 4+mw.SmilHooks = {
 5+ addSmilPlayer: function(){
 6+ // Check if the smil player has already been added:
 7+ if( mw.EmbedTypes.players.defaultPlayers[ 'application/smil' ] )
 8+ return ;
 9+
 10+ // Add the swarmTransport playerType
 11+ mw.EmbedTypes.players.defaultPlayers[ 'application/smil' ] = [ 'Smil' ];
 12+
 13+ // Build the swarm Transport "player"
 14+ var smilMediaPlayer = new mediaPlayer( 'smilPlayer', [ 'application/smil' ], 'Smil' );
 15+
 16+ // Add the swarmTransport "player"
 17+ mw.EmbedTypes.players.addPlayer( smilMediaPlayer );
 18+ }
 19+};
520
621 // Add the smil player to available player types:
722 $j( mw ).bind( 'EmbedPlayerManagerReady', function( event ) {
8 -
9 - // Add the swarmTransport playerType
10 - mw.EmbedTypes.players.defaultPlayers[ 'application/smil' ] = [ 'Smil' ];
11 -
12 - // Build the swarm Transport "player"
13 - var smilMediaPlayer = new mediaPlayer( 'smilPlayer', [ 'application/smil' ], 'Smil' );
14 -
15 - // Add the swarmTransport "player"
16 - mw.EmbedTypes.players.addPlayer( smilMediaPlayer );
17 -
 23+ mw.SmilHooks.addSmilPlayer();
1824 } );
1925
2026 // Tell embedPlayer not to wait for height / width metadata in cases of smil documents
@@ -28,18 +34,27 @@
2935 $j( mw ).bind( 'newEmbedPlayerEvent', function( event, swapedPlayerId ) {
3036 // Setup local reference to embedPlayer interface
3137 var embedPlayer = $j( '#' + swapedPlayerId ).get(0);
 38+ // Add the smil player ( in case we were dynamically loaded and EmbedPlayerManagerReady has already been called )
 39+ mw.SmilHooks.addSmilPlayer();
3240
3341 // Setup the "embedCode" binding to swap in an updated url
3442 $j( embedPlayer ).bind( 'checkPlayerSourcesEvent', function( event, callback ) {
35 - mw.log( " smil enter checkPlayerSources" );
36 - // Get the first smil source:
37 - mw.log( "Source is: " + embedPlayer.mediaElement.getSources( 'application/smil' )[0].getSrc() );
38 - embedPlayer.smil = new mw.Smil( embedPlayer );
39 -
40 - // Load the smil url as part of "source check"
41 - embedPlayer.smil.loadFromUrl( embedPlayer.mediaElement.getSources( 'application/smil' )[0].getSrc(), function(){
42 - callback();
43 - });
 43+ mw.log( "SmilHooks::checkPlayerSources" );
 44+ // Make sure there is a smil source:
 45+ if( embedPlayer.mediaElement.getSources( 'application/smil' ).length ){
 46+ // Get the first smil source:
 47+ mw.log( "Source is: " + embedPlayer.mediaElement.getSources( 'application/smil' )[0].getSrc() );
 48+
 49+ // Add the smil engine to the embed player:
 50+ embedPlayer.smil = new mw.Smil( embedPlayer );
 51+
 52+ // Load the smil url as part of "source check"
 53+ embedPlayer.smil.loadFromUrl( embedPlayer.mediaElement.getSources( 'application/smil' )[0].getSrc(), function(){
 54+ callback();
 55+ });
 56+ } else {
 57+ callback();
 58+ }
4459 } );
4560 });
4661
Index: branches/MwEmbedStandAlone/modules/SmilPlayer/mw.EmbedPlayerSmil.js
@@ -68,11 +68,8 @@
6969 setCurrentTime: function( time, callback ) {
7070 //mw.log('EmbedPlayerSmil::setCurrentTime: ' + time );
7171 // Set "loading" spinner here)
72 - $j( this ).append(
73 - $j( '<div />')
74 - .attr('id', 'loadingSpinner_' + this.id )
75 - .loadingSpinner()
76 - );
 72+ $j( this ).getAbsoluteOverlaySpinner()
 73+ .attr('id', 'loadingSpinner_' + this.id )
7774 // Start seek
7875 this.controlBuilder.onSeek();
7976 this.smilPlayTime = time;
Index: branches/MwEmbedStandAlone/modules/SmilPlayer/mw.SmilBuffer.js
@@ -131,7 +131,7 @@
132132 }
133133 // get the percentage buffered, translated into buffer time and call continueBufferLoad with a timeout
134134 var timeBuffered = _this.getBufferedPercent() * _this.smil.getDuration();
135 - mw.log( 'ContinueBufferLoad::Timed buffered: ' + timeBuffered );
 135+ //mw.log( 'ContinueBufferLoad::Timed buffered: ' + timeBuffered );
136136 _this.continueBufferLoad( timeBuffered );
137137 }, this.smil.embedPlayer.monitorRate * 2 );
138138
@@ -156,7 +156,6 @@
157157 // but in theory we could set something up with large images
158158 switch( this.smil.getRefType( smilElement ) ){
159159 case 'video':
160 - // xxx "seek" to support offsets
161160 var vid = $j( '#' + this.smil.getAssetId( smilElement ) ).get(0);
162161
163162 // The load request does not work very well instead .play() then .pause() and seek when on display
@@ -167,6 +166,9 @@
168167 // Issue the load / play request
169168 vid.play();
170169 vid.volume = 0;
 170+
 171+ // XXX seek to clipBegin if provided ( we don't need to load before that point )
 172+
171173 } else {
172174 // else we have some percentage loaded pause playback
173175 //( should continue to load the asset )
@@ -285,6 +287,27 @@
286288 },
287289
288290 /**
 291+ * Clip ready for grabbing a frame such as a canvas thumb
 292+ */
 293+ canGrabRelativeTime: function( smilElement, relativeTime, callback ){
 294+ var absoluteTime = relativeTime;
 295+ if( $j( smilElement ).attr('clipBegin') ){
 296+ absoluteTime += this.smil.parseTime( $j( smilElement ).attr('clipBegin') );
 297+ }
 298+ switch( this.smil.getRefType( smilElement ) ){
 299+ case 'video':
 300+ this.videoBufferSeek( smilElement, absoluteTime, callback )
 301+ break;
 302+ case 'image':
 303+ this.loadImageCallback( smilElement, callback );
 304+ break;
 305+ default:
 306+ // Assume other formats are directly displayed
 307+ break;
 308+ }
 309+ },
 310+
 311+ /**
289312 * Check if we can play a given time
290313 * @return {boolean} True if the time can be played, false if we need to buffer
291314 */
@@ -331,25 +354,6 @@
332355 },
333356
334357 /**
335 - * Manage seek listeners
336 - */
337 - runSeekCallback: function(assetId, time, callback){
338 - var _this = this;
339 -
340 - // Get the video target:
341 - var vid = $j ( '#' + assetId).get(0);
342 -
343 - if( this.videoListeners[ assetId ] ){
344 - this.videoListeners[ assetId ] = true;
345 - vid.addEventListener( 'seeked', function(){
346 -
347 - });
348 - }
349 -
350 - this.videoListeners[ assetId ] = callback;
351 - },
352 -
353 - /**
354358 * Abstract the seeked Listener so we don't have stacking bindings
355359 */
356360 registerVideoSeekListener: function( assetId ){
@@ -363,10 +367,23 @@
364368 }, false);
365369 },
366370
 371+ loadImageCallback: function ( smilElement, callback ){
 372+ var assetId = this.smil.getAssetId( smilElement );
 373+ // Make sure the image is in the dom ( load it )
 374+ this.loadElement( smilElement );
 375+ // add the jQuery "loaded" callback
 376+ $j( '#' + assetId).loaded( callback );
 377+ },
 378+
367379 videoBufferSeek: function ( smilElement, seekTime, callback ){
368380 var _this = this;
369 - // Get the video target:
 381+
 382+ // Get the asset target:
370383 var assetId = this.smil.getAssetId( smilElement );
 384+
 385+ // make sure the target video is in the dom:
 386+ this.loadElement( smilElement );
 387+
371388 var $vid = $j ( '#' + assetId);
372389 var vid = $vid.get(0);
373390 // Add the asset to the loading set
Index: branches/MwEmbedStandAlone/modules/EmbedPlayer/mw.EmbedPlayer.js
@@ -165,7 +165,7 @@
166166
167167 // If the player controls should be overlaid
168168 //( Global default via config EmbedPlayer.OverlayControls in module loader.js)
169 - "EmbedPlayer.OverlayControls" : true,
 169+ "overlayControls" : true,
170170
171171 // ROE url ( for xml based metadata )
172172 // also see: http://wiki.xiph.org/ROE
@@ -421,7 +421,7 @@
422422 if( ranPlayerSwapFlag ){
423423 return ;
424424 }
425 - mw.log("runPlayerSwap::" + $j( playerElement ).attr('id') );
 425+ mw.log("mwEmbedPlayer::runPlayerSwap::" + $j( playerElement ).attr('id') );
426426 ranPlayerSwapFlag = true;
427427 var playerInterface = new mw.EmbedPlayer( playerElement , attributes);
428428
@@ -429,7 +429,7 @@
430430
431431
432432 // Pass the id to any hook that needs to interface prior to checkPlayerSources
433 - mw.log("addElement :: trigger :: newEmbedPlayerEvent");
 433+ mw.log("mwEmbedPlayer::addElement :trigger :: newEmbedPlayerEvent");
434434 $j( mw ).trigger ( 'newEmbedPlayerEvent', playerInterface.id );
435435
436436 // Issue the checkPlayerSources call to the new player interface:
@@ -438,7 +438,7 @@
439439 }
440440
441441 if( waitForMeta ) {
442 - mw.log('DO WaitForMeta ( video missing height (' + $j( playerElement ).attr('height') + '), width (' + $j( playerElement ).attr('width') + ') or duration' );
 442+ mw.log('mwEmbedPlayer::WaitForMeta ( video missing height (' + $j( playerElement ).attr('height') + '), width (' + $j( playerElement ).attr('width') + ') or duration' );
443443 playerElement.removeEventListener( "loadedmetadata", runPlayerSwap, true );
444444 playerElement.addEventListener( "loadedmetadata", runPlayerSwap, true );
445445
@@ -1465,55 +1465,68 @@
14661466 */
14671467 setPlayerSize: function( element ) {
14681468
1469 - this['height'] = parseInt( $j(element).css( 'height' ) );
1470 - this['width'] = parseInt( $j(element).css( 'width' ) );
 1469+ this.height = parseInt( $j(element).css( 'height' ) );
 1470+ this.width = parseInt( $j(element).css( 'width' ) );
14711471
1472 - if( !this['height'] && !this['width'] ) {
1473 - this['height'] = parseInt( $j(element).attr( 'height' ) );
1474 - this['width'] = parseInt( $j(element).attr( 'width' ) );
 1472+ if( !this.height && !this.width ) {
 1473+ this.height = parseInt( $j(element).attr( 'height' ) );
 1474+ this.width = parseInt( $j(element).attr( 'width' ) );
14751475 }
14761476
14771477 // Special case for audio
14781478 // Firefox sets audio height to "0px" while webkit uses 32px .. force zero:
1479 - if( element.tagName.toLowerCase() == 'audio' && this['height'] == '32') {
1480 - this['height'] = 0;
 1479+ if( element.tagName.toLowerCase() == 'audio' && this.height == '32' ) {
 1480+ this.height = 0;
14811481 }
14821482
14831483 // Use default aspect ration to get height or width ( if rewriting a non-audio player )
1484 - if( element.tagName.toLowerCase() != 'audio' ) {
1485 - if( this['height'] && !this['width'] && this.videoAspect ) {
1486 - var aspect = this.videoAspect.split( ':' );
1487 - this['width'] = parseInt( this.height * ( aspect[0] / aspect[1] ) );
 1484+ if( element.tagName.toLowerCase() != 'audio' && this.videoAspect ) {
 1485+ var aspect = this.videoAspect.split( ':' );
 1486+ if( this.height && !this.width ) {
 1487+ this.width = parseInt( this.height * ( aspect[0] / aspect[1] ) );
 1488+ }
 1489+ if( this.width && !this.height ) {
 1490+ var apectRatio = ( aspect[1] / aspect[0] );
 1491+ this.height = parseInt( this.width * ( aspect[1] / aspect[0] ) );
14881492 }
1489 -
1490 - if( this['width'] && !this['height'] && this.videoAspect ) {
1491 - var aspect = this.videoAspect.split( ':' );
1492 - this['height'] = parseInt( this.width * ( aspect[1] / aspect[0] ) );
1493 - }
14941493 }
14951494
14961495 // On load sometimes attr is temporally -1 as we don't have video metadata yet.
14971496 // or in IE we get NaN for width height
14981497 //
14991498 // NOTE: browsers that do support height width should set "waitForMeta" flag in addElement
1500 - if( ( isNaN( this['height'] ) && isNaN( this['width'] ) ) ||
1501 - ( this['height'] == -1 || this['width'] == -1 ) ||
 1499+ if( ( isNaN( this.height ) && isNaN( this.width ) ) ||
 1500+ ( this.height == -1 || this.width == -1 ) ||
15021501 // Check for firefox defaults
15031502 // Note: ideally firefox would not do random guesses at css values
15041503 ( (this.height == 150 || this.height == 64 ) && this.width == 300 )
15051504 ) {
15061505 var defaultSize = mw.getConfig( 'EmbedPlayer.DefaultSize' ).split( 'x' );
1507 - this['width'] = defaultSize[0];
 1506+ this.width = defaultSize[0];
15081507
15091508 // Special height default for audio tag ( if not set )
15101509 if( element.tagName.toLowerCase() == 'audio' ) {
1511 - this['height'] = 0;
 1510+ this.height = 0;
15121511 }else{
1513 - this['height'] = defaultSize[1];
 1512+ this.height = defaultSize[1];
15141513 }
15151514 }
15161515
15171516 },
 1517+ /**
 1518+ * Resize the player to a new size
 1519+ */
 1520+ resizePlayer: function( size , animate){
 1521+ this.width = size.width;
 1522+ this.hegith = size.height;
 1523+ if( animate ){
 1524+ $j(this).animate(size);
 1525+ this.$interface.animate( size );
 1526+ }else{
 1527+ $j(this).css(size);
 1528+ this.$interface.css( size );
 1529+ }
 1530+ },
15181531
15191532 /**
15201533 * Get the player pixel width not including controls
@@ -1812,7 +1825,7 @@
18131826 *
18141827 * @return start_npt and end_npt time if present
18151828 */
1816 - getTimeRange: function() {
 1829+ getTimeRange: function() {
18171830 var end_time = (this.controlBuilder.longTimeDisp)? '/' + mw.seconds2npt( this.getDuration() ) : '';
18181831 var default_time_range = '0:00:00' + end_time;
18191832 if ( !this.mediaElement )
@@ -2720,6 +2733,7 @@
27212734 if ( this.thumbnail_disp ) {
27222735 // already in stooped state
27232736 mw.log( 'already in stopped state' );
 2737+ this.controlBuilder.setStatus( this.getTimeRange() );
27242738 } else {
27252739 // rewrite the html to thumbnail disp
27262740 this.showThumbnail();
Index: branches/MwEmbedStandAlone/modules/EmbedPlayer/skins/mw.PlayerControlBuilder.js
@@ -634,15 +634,17 @@
635635 if( ! this.embedPlayer.supports['overlays'] ){
636636 return false;
637637 }
638 - // If the config is false
639 - if( mw.getConfig( 'EmbedPlayer.OverlayControls' ) == false){
640 - return false;
641 - }
642638
643639 // If disabled via the player
644640 if( this.embedPlayer.overlayControls === false ){
645641 return false;
646642 }
 643+
 644+ // If the config is false
 645+ if( mw.getConfig( 'EmbedPlayer.OverlayControls' ) == false){
 646+ return false;
 647+ }
 648+
647649 // don't hide controls when content "height" is 0 ( audio tags )
648650 if( this.embedPlayer.getPlayerHeight() == 0 ){
649651 return false;
Index: branches/MwEmbedStandAlone/modules/SequenceEdit/loader.js
@@ -0,0 +1,69 @@
 2+/**
 3+* SequenceEdit loader
 4+*/
 5+
 6+// Wrap in mw to not pollute global namespace
 7+( function( mw ) {
 8+ mw.addResourcePaths( {
 9+
 10+ "mw.SequenceEdit" : "mw.SequenceEdit.js",
 11+ "mw.style.SequenceEdit" : "mw.style.SequenceEdit.css",
 12+ "mw.SequenceEditPlayer" : "mw.SequenceEditPlayer.js",
 13+ "mw.SequenceEditTimeline" : "mw.SequenceEditTimeline.js",
 14+ "mw.SequenceEditKeyBindings" : "mw.SequenceEditKeyBindings.js",
 15+
 16+ "mw.FirefoggRender" : "mw.FirefoggRender.js",
 17+ "$j.fn.layout" : "ui.layout/ui.layout-1.2.0.js",
 18+
 19+ "RemoteMwSequencer" : "remotes/RemoteMwSequencer.js",
 20+
 21+ "mw.style.SequenceEdit" : "css/mw.style.SequenceEdit.css",
 22+
 23+ "playlistEmbed" : "playlistEmbed.js"
 24+ } );
 25+
 26+ /**
 27+ * The FirefoggRender sub module
 28+ */
 29+ mw.addModuleLoader( 'FirefoggRender',
 30+ [
 31+ 'mw.Firefogg',
 32+ 'mw.FirefoggRender',
 33+ 'mw.UploadInterface'
 34+ ]
 35+ );
 36+
 37+ // SequenceEditor module loader
 38+ mw.addModuleLoader( 'SequenceEdit', function( ) {
 39+ // Make sure we have the required mwEmbed libs:
 40+ return [
 41+ [ // Load the EmbedPlayer Module ( includes lots of dependent classes )
 42+ 'EmbedPlayer'
 43+ ],
 44+ [
 45+ '$j.contextMenu',
 46+ 'mw.SequenceEdit',
 47+ 'mw.SequenceEditPlayer',
 48+ 'mw.SequenceEditTimeline',
 49+ 'mw.SequenceEditKeyBindings',
 50+
 51+ 'mw.style.SequenceEdit'
 52+ ],
 53+ [
 54+ '$j.fn.layout',
 55+ // UI components used in the sequencer interface:
 56+ '$j.ui.accordion',
 57+ '$j.ui.dialog',
 58+ '$j.ui.droppable',
 59+ '$j.ui.draggable',
 60+ '$j.ui.progressbar',
 61+ '$j.ui.sortable',
 62+ '$j.ui.resizable',
 63+ '$j.ui.slider',
 64+ '$j.ui.tabs'
 65+ ]
 66+ ];
 67+ });
 68+
 69+} )( window.mw );
 70+
\ No newline at end of file
Index: branches/MwEmbedStandAlone/modules/SequenceEdit/SequenceEdit.i18n.php
@@ -0,0 +1,1219 @@
 2+<?php
 3+/*
 4+ * Internationalisation for SequenceEdit
 5+ *
 6+ * @file
 7+ * @ingroup Extensions
 8+ */
 9+
 10+$messages = array();
 11+$messages['en'] = array(
 12+ 'mwe-sequenceedit-loading_timeline' => 'Loading timeline ...',
 13+ 'mwe-sequenceedit-loading_player' => 'Loading player...',
 14+ 'mwe-sequenceedit-loading_edit' => 'Loading edit...',
 15+ 'mwe-sequenceedit-no-sequence-start-new' => 'Empty sequence, [$1 browser for assets] to create a new sequence',
 16+ 'mwe-sequenceedit-video-track' => 'Video track',
 17+ 'mwe-sequenceedit-audio-track' => 'Audio track',
 18+
 19+ 'mwe-sequenceedit-transition_in' => 'Transition in',
 20+ 'mwe-sequenceedit-transition_out' => 'Transition out',
 21+ 'mwe-sequenceedit-effects' => 'Effects stack',
 22+ 'mwe-sequenceedit-remove_transition' => 'Remove transition',
 23+ 'mwe-sequenceedit-edit_transin' => 'Edit transition into clip',
 24+ 'mwe-sequenceedit-edit_transout' => 'Edit transition out of clip',
 25+ 'mwe-sequenceedit-add-transition' => 'Add a transition',
 26+ 'mwe-sequenceedit-menu_clipedit' => 'Edit media',
 27+ 'mwe-sequenceedit-menu_transition' => 'Transitions and effects',
 28+ 'mwe-sequenceedit-menu_cliplib' => 'Add media',
 29+ 'mwe-sequenceedit-menu_resource_overview' => 'Resource overview',
 30+ 'mwe-sequenceedit-menu_options' => 'Options',
 31+ 'mwe-sequenceedit-loading_user_rights' => 'Loading user rights ...',
 32+ 'mwe-sequenceedit-no_edit_permissions' => 'You do not have permissions to save changes to this sequence',
 33+ 'mwe-sequenceedit-edit_clip' => 'Edit clip',
 34+ 'mwe-sequenceedit-edit_save' => 'Save sequence changes',
 35+ 'mwe-sequenceedit-saving_wait' => 'Save in progress (please wait)',
 36+ 'mwe-sequenceedit-save_done' => 'Save complete',
 37+ 'mwe-sequenceedit-edit_cancel' => 'Cancel sequence edit',
 38+ 'mwe-sequenceedit-edit_cancel_confirm' => 'Are you sure you want to cancel your edit? Changes will be lost.',
 39+ 'mwe-sequenceedit-zoom_in' => 'Zoom in',
 40+ 'mwe-sequenceedit-zoom_out' => 'Zoom out',
 41+ 'mwe-sequenceedit-cut_clip' => 'Cut clips',
 42+ 'mwe-sequenceedit-expand_track' => 'Expand track',
 43+ 'mwe-sequenceedit-collapse_track' => 'Collapse track',
 44+ 'mwe-sequenceedit-play_from_position' => 'Play from playline position',
 45+ 'mwe-sequenceedit-pixle2sec' => 'pixels to seconds',
 46+ 'mwe-sequenceedit-rmclip' => 'Remove clip',
 47+ 'mwe-sequenceedit-clip_in' => 'clip in',
 48+ 'mwe-sequenceedit-clip_out' => 'clip out',
 49+ 'mwe-sequenceedit-no_selected_resource' => '<h3>No resource selected</h3> Select a clip to enable editing.',
 50+ 'mwe-sequenceedit-error_edit_multiple' => '<h3>Multiple resources selected</h3> Select a single clip to edit it.',
 51+ 'mwe-sequenceedit-editor_options' => 'Editor options',
 52+ 'mwe-sequenceedit-editor_mode' => 'Editor mode',
 53+ 'mwe-sequenceedit-simple_editor_desc' => 'simple editor (iMovie style)',
 54+ 'mwe-sequenceedit-advanced_editor_desc' => 'advanced editor (Final Cut style)',
 55+ 'mwe-sequenceedit-other_options' => 'Other options',
 56+ 'mwe-sequenceedit-contextmenu_opt' => 'Enable context menus',
 57+ 'mwe-sequenceedit-sequencer_credit_line' => 'Developed by [$1 Kaltura, Inc] in partnership with the [$1 Wikimedia Foundation]',
 58+ 'mwe-sequenceedit-sequence-create-one' => 'Nostart a sequence',
 59+);
 60+$messages['af'] = array(
 61+ 'mwe-sequenceedit-menu_options' => 'Opsies',
 62+ 'mwe-sequenceedit-other_options' => 'Ander opsies',
 63+);
 64+$messages['ar'] = array(
 65+ 'mwe-sequenceedit-remove_transition' => 'أزل الترجمة',
 66+ 'mwe-sequenceedit-edit_transin' => 'عدّل الترجمة في المقطع',
 67+ 'mwe-sequenceedit-edit_transout' => 'عدّل الترجمة خارج المقطع',
 68+ 'mwe-sequenceedit-menu_clipedit' => 'حرّر الوسيط',
 69+ 'mwe-sequenceedit-menu_transition' => 'ترجمات ومؤثرات',
 70+ 'mwe-sequenceedit-menu_cliplib' => 'أضف وسيطًا',
 71+ 'mwe-sequenceedit-menu_options' => 'خيارات',
 72+ 'mwe-sequenceedit-loading_timeline' => 'يحمل الشريط الزمني...',
 73+ 'mwe-sequenceedit-loading_user_rights' => 'يحمل صلاحيات المستخدم...',
 74+ 'mwe-sequenceedit-edit_clip' => 'حرّر المقطع',
 75+ 'mwe-sequenceedit-saving_wait' => 'الحفظ قيد التنفيذ (من فضلك انتظر)',
 76+ 'mwe-sequenceedit-save_done' => 'اكتمل الحفظ',
 77+ 'mwe-sequenceedit-edit_cancel_confirm' => 'أمتأكد من أنك تريد إلغاء تعديلك؟ سوف تضيع التعديلات.',
 78+ 'mwe-sequenceedit-zoom_in' => 'قرّب',
 79+ 'mwe-sequenceedit-zoom_out' => 'بعّد',
 80+ 'mwe-sequenceedit-expand_track' => 'وسّع المقطوعة',
 81+ 'mwe-sequenceedit-collapse_track' => 'اطوِ المقطوعة',
 82+ 'mwe-sequenceedit-rmclip' => 'أزل المقطع',
 83+ 'mwe-sequenceedit-editor_options' => 'خيارات المحرر',
 84+ 'mwe-sequenceedit-editor_mode' => 'وضع المحرّر',
 85+ 'mwe-sequenceedit-simple_editor_desc' => 'مُحرّر بسيط (على نمط iMovie)',
 86+ 'mwe-sequenceedit-other_options' => 'خيارات أخرى',
 87+);
 88+$messages['be-tarask'] = array(
 89+ 'mwe-sequenceedit-transition_in' => 'Пераход у',
 90+ 'mwe-sequenceedit-transition_out' => 'Пераход з',
 91+ 'mwe-sequenceedit-effects' => 'Набор эфэктаў',
 92+ 'mwe-sequenceedit-remove_transition' => 'Выдаліць пераход',
 93+ 'mwe-sequenceedit-edit_transin' => 'Рэдагаваць пераход у частку файла',
 94+ 'mwe-sequenceedit-edit_transout' => 'Рэдагаваць пераход з часткі файла',
 95+ 'mwe-sequenceedit-add-transition' => 'Дадаць пераход',
 96+ 'mwe-sequenceedit-menu_clipedit' => 'Рэдагаваць мэдыя',
 97+ 'mwe-sequenceedit-menu_transition' => 'Пераходы і эфэкты',
 98+ 'mwe-sequenceedit-menu_cliplib' => 'Дадаць мэдыя',
 99+ 'mwe-sequenceedit-menu_resource_overview' => 'Агляд рэсурсаў',
 100+ 'mwe-sequenceedit-menu_options' => 'Устаноўкі',
 101+ 'mwe-sequenceedit-loading_timeline' => 'Загрузка шкалы часу ...',
 102+ 'mwe-sequenceedit-loading_user_rights' => 'Загрузка правоў удзельніка ...',
 103+ 'mwe-sequenceedit-no_edit_permissions' => 'Вы ня маеце правоў для захаваньня зьменаў у гэтай пасьлядоўнасьці',
 104+ 'mwe-sequenceedit-edit_clip' => 'Рэдагаваць частку файла',
 105+ 'mwe-sequenceedit-edit_save' => 'Захаваць зьмены пасьлядоўнасьці',
 106+ 'mwe-sequenceedit-saving_wait' => 'Захаваньне зьдзяйсьняецца (калі ласка, пачакайце)',
 107+ 'mwe-sequenceedit-save_done' => 'Захаваньне скончанае',
 108+ 'mwe-sequenceedit-edit_cancel' => 'Адмяніць рэдагаваньне пасьлядоўнасьці',
 109+ 'mwe-sequenceedit-edit_cancel_confirm' => 'Вы ўпэўнены, што жадаеце адмяніць Вашае рэдагаваньне? Зьмены будуць страчаныя.',
 110+ 'mwe-sequenceedit-zoom_in' => 'Павялічыць',
 111+ 'mwe-sequenceedit-zoom_out' => 'Паменшыць',
 112+ 'mwe-sequenceedit-cut_clip' => 'Кадраваньне кліпаў',
 113+ 'mwe-sequenceedit-expand_track' => 'Павялічыць сьцежку',
 114+ 'mwe-sequenceedit-collapse_track' => 'Паменшыць сьцежку',
 115+ 'mwe-sequenceedit-play_from_position' => 'Прайграваць з цяперашняй пазыцыі',
 116+ 'mwe-sequenceedit-pixle2sec' => 'піксэлі ў сэкундах',
 117+ 'mwe-sequenceedit-rmclip' => 'Выдаліць частку файла',
 118+ 'mwe-sequenceedit-clip_in' => 'дадаць кліп',
 119+ 'mwe-sequenceedit-clip_out' => 'выдаліць кліп',
 120+ 'mwe-sequenceedit-no_selected_resource' => '<h3>Рэсурс не выбраны</h3> Выберыце частку файла для уключэньня рэдагаваньня.',
 121+ 'mwe-sequenceedit-error_edit_multiple' => '<h3>Выбраныя некалькі рэсурсаў</h3> Выберыце адну частку файла для яе рэдагаваньня.',
 122+ 'mwe-sequenceedit-editor_options' => 'Устаноўкі рэдактара',
 123+ 'mwe-sequenceedit-editor_mode' => 'Рэжым рэдактара',
 124+ 'mwe-sequenceedit-simple_editor_desc' => 'просты рэдактар (стыль iMovie)',
 125+ 'mwe-sequenceedit-advanced_editor_desc' => 'палепшаны рэдактар (стыль Final Cut)',
 126+ 'mwe-sequenceedit-other_options' => 'Іншыя ўстаноўкі',
 127+ 'mwe-sequenceedit-contextmenu_opt' => 'Дазволіць кантэкстныя мэню',
 128+ 'mwe-sequenceedit-sequencer_credit_line' => 'Распрацавана <a href="http://kaltura.com">Kaltura, Inc.</a> у садружнасьці з <a href="http://wikimediafoundation.org/wiki/Home">фундацыяй «Вікімэдыя»</a> (<a href="#">падрабязнасьці </a>).',
 129+);
 130+$messages['br'] = array(
 131+ 'mwe-sequenceedit-menu_clipedit' => 'Aozañ ar media',
 132+ 'mwe-sequenceedit-menu_cliplib' => 'Ouzhpennañ ur media',
 133+ 'mwe-sequenceedit-menu_options' => 'Dibarzhioù',
 134+ 'mwe-sequenceedit-edit_clip' => 'Aozañ ar c\'hlip',
 135+ 'mwe-sequenceedit-save_done' => 'Echu eo an enrollañ',
 136+ 'mwe-sequenceedit-zoom_in' => 'Zoumiñ',
 137+ 'mwe-sequenceedit-zoom_out' => 'Dizoumiñ',
 138+ 'mwe-sequenceedit-rmclip' => 'Dilemel ar c\'hlip',
 139+ 'mwe-sequenceedit-editor_options' => 'Dibarzhioù an aozer',
 140+ 'mwe-sequenceedit-simple_editor_desc' => 'aozer eeun (stil iMovie)',
 141+ 'mwe-sequenceedit-other_options' => 'Dibarzhioù all',
 142+);
 143+$messages['bs'] = array(
 144+ 'mwe-sequenceedit-remove_transition' => 'Ukloni prelazak',
 145+ 'mwe-sequenceedit-add-transition' => 'Dodaj prijelaz',
 146+ 'mwe-sequenceedit-menu_clipedit' => 'Uredi mediju',
 147+ 'mwe-sequenceedit-menu_transition' => 'Prijelazi i efekti',
 148+ 'mwe-sequenceedit-menu_cliplib' => 'Dodaj mediju',
 149+ 'mwe-sequenceedit-menu_resource_overview' => 'Pregled resursa',
 150+ 'mwe-sequenceedit-menu_options' => 'Opcije',
 151+ 'mwe-sequenceedit-loading_timeline' => 'Učitavanje vremenske linije ...',
 152+ 'mwe-sequenceedit-loading_user_rights' => 'Učitavanje korisničkih prava ...',
 153+ 'mwe-sequenceedit-no_edit_permissions' => 'Nemate dopuštenja da spremite izmjene ove sekvence',
 154+ 'mwe-sequenceedit-edit_clip' => 'Uredi isječak',
 155+ 'mwe-sequenceedit-edit_save' => 'Spremi izmjene sekvence',
 156+ 'mwe-sequenceedit-saving_wait' => 'Spremanje u toku (molimo pričekajte)',
 157+ 'mwe-sequenceedit-save_done' => 'Spremanje završeno',
 158+ 'mwe-sequenceedit-edit_cancel' => 'Odustani od uređivanja sekvence',
 159+ 'mwe-sequenceedit-edit_cancel_confirm' => 'Da li ste sigurni da želite odustati od Vašeg uređivanja? Izmjene će biti izgubljene.',
 160+ 'mwe-sequenceedit-zoom_in' => 'Približi',
 161+ 'mwe-sequenceedit-zoom_out' => 'Udalji',
 162+ 'mwe-sequenceedit-cut_clip' => 'Rezanje isječaka',
 163+ 'mwe-sequenceedit-expand_track' => 'Proširi traku',
 164+ 'mwe-sequenceedit-collapse_track' => 'Smanji traku',
 165+ 'mwe-sequenceedit-pixle2sec' => 'pikseli u sekunde',
 166+ 'mwe-sequenceedit-rmclip' => 'Ukloni isječak',
 167+ 'mwe-sequenceedit-editor_options' => 'Opcije uređivača',
 168+ 'mwe-sequenceedit-editor_mode' => 'Način uređivanja',
 169+ 'mwe-sequenceedit-simple_editor_desc' => 'jednostavni uređivač (iMovie stil)',
 170+ 'mwe-sequenceedit-advanced_editor_desc' => 'napredni uređivač (Final Cut stil)',
 171+ 'mwe-sequenceedit-other_options' => 'Ostale opcije',
 172+ 'mwe-sequenceedit-contextmenu_opt' => 'Omogući kontekstne menije',
 173+);
 174+$messages['de'] = array(
 175+ 'mwe-sequenceedit-transition_in' => 'Übergang ein',
 176+ 'mwe-sequenceedit-transition_out' => 'Übergang aus',
 177+ 'mwe-sequenceedit-remove_transition' => 'Übergang entfernen',
 178+ 'mwe-sequenceedit-menu_transition' => 'Übergänge und Effekte',
 179+ 'mwe-sequenceedit-menu_resource_overview' => 'Quellübersicht',
 180+ 'mwe-sequenceedit-menu_options' => 'Optionen',
 181+ 'mwe-sequenceedit-loading_timeline' => 'Lade Zeitleiste …',
 182+ 'mwe-sequenceedit-loading_user_rights' => 'Lade Benutzerrechte …',
 183+ 'mwe-sequenceedit-no_edit_permissions' => 'Du hast keine Berechtigungen, Änderungen zu dieser Sequenz zu speichern',
 184+ 'mwe-sequenceedit-edit_clip' => 'Clip bearbeiten',
 185+ 'mwe-sequenceedit-edit_save' => 'Sequenzänderungen speichern',
 186+ 'mwe-sequenceedit-saving_wait' => 'Speichere (bitte warten)',
 187+ 'mwe-sequenceedit-save_done' => 'Speicherung fertig',
 188+ 'mwe-sequenceedit-edit_cancel' => 'Sequenzbearbeitung abbrechen',
 189+ 'mwe-sequenceedit-edit_cancel_confirm' => 'Bist du sicher, dass du deine Bearbeitung abbrechen willst? Änderungen gehen verloren.',
 190+ 'mwe-sequenceedit-zoom_in' => 'Vergrößern',
 191+ 'mwe-sequenceedit-zoom_out' => 'Verkleinern',
 192+ 'mwe-sequenceedit-cut_clip' => 'Clips schneiden',
 193+ 'mwe-sequenceedit-expand_track' => 'Spur ausklappen',
 194+ 'mwe-sequenceedit-collapse_track' => 'Spur einklappen',
 195+ 'mwe-sequenceedit-play_from_position' => 'Abspielen ab Playline-Position',
 196+ 'mwe-sequenceedit-rmclip' => 'Clip entfernen',
 197+ 'mwe-sequenceedit-clip_in' => 'Clip hinzufügen',
 198+ 'mwe-sequenceedit-clip_out' => 'Clip entfernen',
 199+ 'mwe-sequenceedit-no_selected_resource' => '<h3>Keine Quelle ausgewählt</h3> Wähle einen Clip aus, um das Bearbeiten zu aktivieren.',
 200+ 'mwe-sequenceedit-error_edit_multiple' => '<h3>Mehrere Quellen ausgewählt</h3> Wähle nur einen Clip aus, um ihn zu bearbeiten.',
 201+ 'mwe-sequenceedit-editor_options' => 'Editoroptionen',
 202+ 'mwe-sequenceedit-editor_mode' => 'Editormodus',
 203+ 'mwe-sequenceedit-simple_editor_desc' => 'einfacher Editor (iMovie-Stil)',
 204+ 'mwe-sequenceedit-advanced_editor_desc' => 'erweiterter Editor (Final-Cut-Stil)',
 205+ 'mwe-sequenceedit-other_options' => 'Andere Optionen',
 206+ 'mwe-sequenceedit-contextmenu_opt' => 'Kontextmenüs aktivieren',
 207+ 'mwe-sequenceedit-sequencer_credit_line' => 'Entwickelt von <a href="http://kaltura.com">Kaltura, Inc.</a> in Zusammenarbeit mit der <a href="http://wikimediafoundation.org/wiki/Home">Wikimedia Foundation</a> (<a href="#">mehr Informationen</a>).',
 208+);
 209+$messages['diq'] = array(
 210+ 'mwe-sequenceedit-transition_in' => 'dekewtış',
 211+ 'mwe-sequenceedit-transition_out' => 'teber kewtış',
 212+ 'mwe-sequenceedit-effects' => 'loda (kopê) efekti',
 213+ 'mwe-sequenceedit-remove_transition' => 'raviyertış wedar/werad',
 214+ 'mwe-sequenceedit-edit_transin' => 'şiyayişê klibi bıvurn',
 215+ 'mwe-sequenceedit-edit_transout' => 'klip ra şliyayiş bıvurn',
 216+ 'mwe-sequenceedit-add-transition' => 'Yew çarnayiş de bike',
 217+ 'mwe-sequenceedit-menu_clipedit' => 'medya bıvurn',
 218+ 'mwe-sequenceedit-menu_transition' => 'efekt u raviyertışi',
 219+ 'mwe-sequenceedit-menu_cliplib' => 'medya têarê ker',
 220+ 'mwe-sequenceedit-menu_resource_overview' => 'Resource overview',
 221+ 'mwe-sequenceedit-menu_options' => 'tercihi',
 222+ 'mwe-sequenceedit-loading_timeline' => 'Loading timeline ...',
 223+ 'mwe-sequenceedit-loading_user_rights' => 'heqê karberi bar bêni',
 224+ 'mwe-sequenceedit-no_edit_permissions' => 'şıma nêşkeni vuriyayişan no rêzkerdışi re qeyd bıkeri',
 225+ 'mwe-sequenceedit-edit_clip' => 'klib bıvurn',
 226+ 'mwe-sequenceedit-edit_save' => 'vuriyayişanê rêzkerdışan qeyd bıker',
 227+ 'mwe-sequenceedit-saving_wait' => 'qeyd kerdış dewam keno ( kerem kerê vınderê)',
 228+ 'mwe-sequenceedit-save_done' => 'qeyd kerdış temam bı',
 229+ 'mwe-sequenceedit-edit_cancel' => 'vuriyayişê rêzbiyayişi iptal bıker',
 230+ 'mwe-sequenceedit-edit_cancel_confirm' => 'şıma raşta wazeni vurnayişanê xo iptal ker? vuriyayişi vindibeni',
 231+ 'mwe-sequenceedit-zoom_in' => 'biyar nızdi (zoom ker)',
 232+ 'mwe-sequenceedit-zoom_out' => 'dûr ker (zoom meker)',
 233+ 'mwe-sequenceedit-cut_clip' => 'kliban bıqesn',
 234+ 'mwe-sequenceedit-expand_track' => 'reç hêra ker',
 235+ 'mwe-sequenceedit-collapse_track' => 'reç teng ker',
 236+ 'mwe-sequenceedit-play_from_position' => 'bı serê xetê kaydayiş ra bıd\' kaydayış',
 237+ 'mwe-sequenceedit-pixle2sec' => 'piksel re saniye',
 238+ 'mwe-sequenceedit-rmclip' => 'klib wedar/werad',
 239+ 'mwe-sequenceedit-clip_in' => 'zerre re klib',
 240+ 'mwe-sequenceedit-clip_out' => 'teber re klib',
 241+ 'mwe-sequenceedit-no_selected_resource' => '<h3>çı çıme nêvıciya</h3> qey aktifkerdışê vurnayişi yew klib bıvıcinê.',
 242+ 'mwe-sequenceedit-error_edit_multiple' => '<h3>yew ra zêd çıme vıciya</h3> qey vurnayişi yew klib bıvıcinê.',
 243+ 'mwe-sequenceedit-editor_options' => 'tercihê editori',
 244+ 'mwe-sequenceedit-editor_mode' => 'modê editori',
 245+ 'mwe-sequenceedit-simple_editor_desc' => 'editoro basit (bı stilê imovie\'yi)',
 246+ 'mwe-sequenceedit-advanced_editor_desc' => 'editoro dewlemend (bı stilê final cut\'i)',
 247+ 'mwe-sequenceedit-other_options' => 'tercihê bini',
 248+ 'mwe-sequenceedit-contextmenu_opt' => 'menuyê muhtewayan aktif bıker',
 249+ 'mwe-sequenceedit-sequencer_credit_line' => 'hetê <a href="http://kaltura.com">Kaltura, Inc.</a>yi ra pê ortaxiyê <a href="http://wikimediafoundation.org/wiki/Home">Wikimedia Foundation</a> (<a href="#">qey malumato zêd</a>)yi dewlemend biyo.',
 250+);
 251+$messages['dsb'] = array(
 252+ 'mwe-sequenceedit-transition_in' => 'Zablendowanje',
 253+ 'mwe-sequenceedit-transition_out' => 'Wublendowanje',
 254+ 'mwe-sequenceedit-effects' => 'Skład efektow',
 255+ 'mwe-sequenceedit-remove_transition' => 'Pśechad wótpóraś',
 256+ 'mwe-sequenceedit-edit_transin' => 'Zablendowanje do klipa wobźěłaś',
 257+ 'mwe-sequenceedit-edit_transout' => 'Wublendowanje z klipa wobźěłaś',
 258+ 'mwe-sequenceedit-add-transition' => 'Pśechad pśidaś',
 259+ 'mwe-sequenceedit-menu_clipedit' => 'Medije wobźěłaś',
 260+ 'mwe-sequenceedit-menu_transition' => 'Pśechady a efekty',
 261+ 'mwe-sequenceedit-menu_cliplib' => 'Medije pśidaś',
 262+ 'mwe-sequenceedit-menu_resource_overview' => 'Pśeglěd resursow',
 263+ 'mwe-sequenceedit-menu_options' => 'Opcije',
 264+ 'mwe-sequenceedit-loading_timeline' => 'Casowu ceru zacytaś ...',
 265+ 'mwe-sequenceedit-loading_user_rights' => 'Wužywarske pšawa se zacytuju ...',
 266+ 'mwe-sequenceedit-no_edit_permissions' => 'Njamaš pšawa, aby změny na toś tej sekwency składował.',
 267+ 'mwe-sequenceedit-edit_clip' => 'Klip wobźěłaś',
 268+ 'mwe-sequenceedit-edit_save' => 'Sekwencowe změny składowaś',
 269+ 'mwe-sequenceedit-saving_wait' => 'Składujo se rowno (pšosym cakaj)',
 270+ 'mwe-sequenceedit-save_done' => 'Składowanje dokóńcone',
 271+ 'mwe-sequenceedit-edit_cancel' => 'Wobźěłanje sekwence pśetergnuś',
 272+ 'mwe-sequenceedit-edit_cancel_confirm' => 'Coš napšawdu swójo wobźěłanje pśetergnuś? Změny se zgubiju.',
 273+ 'mwe-sequenceedit-zoom_in' => 'Pówětšyś',
 274+ 'mwe-sequenceedit-zoom_out' => 'Pómjeńšyś',
 275+ 'mwe-sequenceedit-cut_clip' => 'Klipy stśigaś',
 276+ 'mwe-sequenceedit-expand_track' => 'Ceru wuklapnuś',
 277+ 'mwe-sequenceedit-collapse_track' => 'Ceru złožyś',
 278+ 'mwe-sequenceedit-play_from_position' => 'Wót pozicije wótegraś',
 279+ 'mwe-sequenceedit-pixle2sec' => 'piksele do sekundow',
 280+ 'mwe-sequenceedit-rmclip' => 'Klip wótpóraś',
 281+ 'mwe-sequenceedit-clip_in' => 'Klip pśidaś',
 282+ 'mwe-sequenceedit-clip_out' => 'Klip wótpóraś',
 283+ 'mwe-sequenceedit-no_selected_resource' => '<h3>Žedna resursa wubrana</h3> Wubjeŕ klip, aby zmóžnił wobźěłowanje.',
 284+ 'mwe-sequenceedit-error_edit_multiple' => '<h3>Někotare resurse wubrane</h3> Wubjeŕ jadnotliwy klip, aby jen wobźěłał.',
 285+ 'mwe-sequenceedit-editor_options' => 'Editorowe opcije',
 286+ 'mwe-sequenceedit-editor_mode' => 'Editorowy modus',
 287+ 'mwe-sequenceedit-simple_editor_desc' => 'jadnory editor (stil iMovie)',
 288+ 'mwe-sequenceedit-advanced_editor_desc' => 'rozšyrjony editor (stil Final Cut)',
 289+ 'mwe-sequenceedit-other_options' => 'Druge opcije',
 290+ 'mwe-sequenceedit-contextmenu_opt' => 'Kontekstowe menije zmóžniś',
 291+ 'mwe-sequenceedit-sequencer_credit_line' => 'Wuwity wót <a href="http://kaltura.com">Kaltura, Inc.</a> gromaźe ze załožbu <a href="http://wikimediafoundation.org/wiki/Home">Wikimedia Foundation</a> (<a href="#">dalšne informacije</a>).',
 292+);
 293+$messages['el'] = array(
 294+ 'mwe-sequenceedit-transition_in' => 'Ταχύτητα μέσα',
 295+ 'mwe-sequenceedit-transition_out' => 'Ταχύτητα έξω',
 296+ 'mwe-sequenceedit-remove_transition' => 'Αφαίρεση ταχύτητας',
 297+ 'mwe-sequenceedit-menu_clipedit' => 'Επεξεργασία μέσου',
 298+ 'mwe-sequenceedit-menu_cliplib' => 'Προσθήκη μέσου',
 299+ 'mwe-sequenceedit-menu_resource_overview' => 'Επισκόπηση πηγής',
 300+ 'mwe-sequenceedit-menu_options' => 'Επιλογές',
 301+ 'mwe-sequenceedit-loading_timeline' => 'Φορτώνει η χρονολογία ...',
 302+ 'mwe-sequenceedit-loading_user_rights' => 'Φορτώνουν τα δικαιώματα χρήστη ...',
 303+ 'mwe-sequenceedit-edit_clip' => 'Επεξεργασία κλιπ',
 304+ 'mwe-sequenceedit-edit_save' => 'Αποθήκευση αλλαγών ακολουθίας',
 305+ 'mwe-sequenceedit-saving_wait' => 'Αποθήκευση σε εξέλιξη (παρακαλώ περιμένετε)',
 306+ 'mwe-sequenceedit-save_done' => 'Η αποθήκευση ολοκληρώθηκε',
 307+ 'mwe-sequenceedit-edit_cancel' => 'Ακύρωση επεξεργασίας ακολουθίας',
 308+ 'mwe-sequenceedit-zoom_in' => 'Μεγέθυνση',
 309+ 'mwe-sequenceedit-zoom_out' => 'Σμίκρυνση',
 310+ 'mwe-sequenceedit-pixle2sec' => 'πίξελ ανά δευτερόλεπτα',
 311+ 'mwe-sequenceedit-rmclip' => 'Αφαίρεση κλιπ',
 312+ 'mwe-sequenceedit-editor_options' => 'Επιλογές επεξεργαστή',
 313+ 'mwe-sequenceedit-editor_mode' => 'Λειτουργία επεξεργαστή',
 314+ 'mwe-sequenceedit-simple_editor_desc' => 'απλός επεξεργαστής (iMovie στυλ)',
 315+ 'mwe-sequenceedit-advanced_editor_desc' => 'προχωρημένος επεξεργαστής (Final Cut στυλ)',
 316+ 'mwe-sequenceedit-other_options' => 'Άλλες επιλογές',
 317+);
 318+$messages['eo'] = array(
 319+ 'mwe-sequenceedit-menu_options' => 'Agordoj',
 320+ 'mwe-sequenceedit-zoom_in' => 'Zomi',
 321+ 'mwe-sequenceedit-zoom_out' => 'Malzomi',
 322+ 'mwe-sequenceedit-editor_options' => 'Opcioj por redaktilo',
 323+ 'mwe-sequenceedit-editor_mode' => 'Redakta reĝimo',
 324+ 'mwe-sequenceedit-other_options' => 'Aliaj agordoj',
 325+);
 326+$messages['es'] = array(
 327+ 'mwe-sequenceedit-transition_in' => 'Transición de entrada',
 328+ 'mwe-sequenceedit-transition_out' => 'Transición de salida',
 329+ 'mwe-sequenceedit-effects' => 'Pila de efectos',
 330+ 'mwe-sequenceedit-remove_transition' => 'Remover transición',
 331+ 'mwe-sequenceedit-edit_transin' => 'Editar la transición en el clip',
 332+ 'mwe-sequenceedit-edit_transout' => 'Editar la transición fuera del clip',
 333+ 'mwe-sequenceedit-add-transition' => 'Añadir una transición',
 334+ 'mwe-sequenceedit-menu_clipedit' => 'Editar medios',
 335+ 'mwe-sequenceedit-menu_transition' => 'Transiciones y efectos',
 336+ 'mwe-sequenceedit-menu_cliplib' => 'Agregar medios',
 337+ 'mwe-sequenceedit-menu_options' => 'Opciones',
 338+ 'mwe-sequenceedit-loading_timeline' => 'Cargando línea temporal...',
 339+ 'mwe-sequenceedit-loading_user_rights' => 'Cargando derechos de usuario...',
 340+ 'mwe-sequenceedit-no_edit_permissions' => 'No tienes permisos para grabar cambios a esta secuencia',
 341+ 'mwe-sequenceedit-edit_clip' => 'Editar clip',
 342+ 'mwe-sequenceedit-edit_save' => 'Grabar cambios de secuencia',
 343+ 'mwe-sequenceedit-saving_wait' => 'Grabado en proceso (por favor espere)',
 344+ 'mwe-sequenceedit-save_done' => 'Grabar completo',
 345+ 'mwe-sequenceedit-edit_cancel' => 'Cancelar edición de secuencia',
 346+ 'mwe-sequenceedit-edit_cancel_confirm' => 'Estás seguro que deseas cancelar tu edición? Los cambios se perderán.',
 347+ 'mwe-sequenceedit-zoom_in' => 'Agrandar',
 348+ 'mwe-sequenceedit-zoom_out' => 'Achicar',
 349+ 'mwe-sequenceedit-cut_clip' => 'Cortar clips',
 350+ 'mwe-sequenceedit-expand_track' => 'Expandir la pista',
 351+ 'mwe-sequenceedit-collapse_track' => 'Contraer la pista',
 352+ 'mwe-sequenceedit-pixle2sec' => 'píxeles a segundos',
 353+ 'mwe-sequenceedit-rmclip' => 'Remover clip',
 354+ 'mwe-sequenceedit-editor_options' => 'Opciones de editor',
 355+ 'mwe-sequenceedit-editor_mode' => 'Modo editor',
 356+ 'mwe-sequenceedit-simple_editor_desc' => 'editor simple(estilo iMovie)',
 357+ 'mwe-sequenceedit-advanced_editor_desc' => 'editor avanzado (estilo Final Cut)',
 358+ 'mwe-sequenceedit-other_options' => 'Otras opciones',
 359+ 'mwe-sequenceedit-contextmenu_opt' => 'Habilitar menúes contextuales',
 360+ 'mwe-sequenceedit-sequencer_credit_line' => 'Desarrollado por <a href="http://kaltura.com">Kaltura, Inc.</a> en asociación con <a href="http://wikimediafoundation.org/wiki/Home">Fundación Wikimedia</a> (<a href="#">más información</a>).',
 361+);
 362+$messages['fi'] = array(
 363+ 'mwe-sequenceedit-menu_options' => 'Asetukset',
 364+ 'mwe-sequenceedit-simple_editor_desc' => 'yksinkertainen editori (iMovie-tyyli)',
 365+ 'mwe-sequenceedit-other_options' => 'Muut valinnat',
 366+ 'mwe-sequenceedit-sequencer_credit_line' => 'Kehittänyt <a href="http://kaltura.com">Kaltura, Inc.</a> yhteistyössä <a href="http://wikimediafoundation.org/wiki/Home">Wikimedia Foundationin</a> kanssa (<a href="#">lisätietoja</a>).',
 367+);
 368+$messages['fr'] = array(
 369+ 'mwe-sequenceedit-transition_in' => 'Transition entrante',
 370+ 'mwe-sequenceedit-transition_out' => 'Transition sortante',
 371+ 'mwe-sequenceedit-effects' => 'Pile d\'effets',
 372+ 'mwe-sequenceedit-remove_transition' => 'Supprimer la transition',
 373+ 'mwe-sequenceedit-edit_transin' => 'Modifier la transition vers le clip',
 374+ 'mwe-sequenceedit-edit_transout' => 'Modifier la transition hors du clip',
 375+ 'mwe-sequenceedit-add-transition' => 'Ajouter une traduction',
 376+ 'mwe-sequenceedit-menu_clipedit' => 'Modifier le media',
 377+ 'mwe-sequenceedit-menu_transition' => 'Transitions et effets',
 378+ 'mwe-sequenceedit-menu_cliplib' => 'Ajouter un media',
 379+ 'mwe-sequenceedit-menu_resource_overview' => 'Vue d\'ensemble de la ressource',
 380+ 'mwe-sequenceedit-menu_options' => 'Options',
 381+ 'mwe-sequenceedit-loading_timeline' => 'Chargement de la chronologie ...',
 382+ 'mwe-sequenceedit-loading_user_rights' => 'Chargement des droits d\'utilisateur ...',
 383+ 'mwe-sequenceedit-no_edit_permissions' => 'Vous n\'avez pas l\'autorisation de sauvegarder les changements apportés à cette séquence',
 384+ 'mwe-sequenceedit-edit_clip' => 'Modifier le clip',
 385+ 'mwe-sequenceedit-edit_save' => 'Sauvegarder les modifications de la séquence',
 386+ 'mwe-sequenceedit-saving_wait' => 'Sauvegarde en cours (veuillez patienter)',
 387+ 'mwe-sequenceedit-save_done' => 'Sauvegarde terminée',
 388+ 'mwe-sequenceedit-edit_cancel' => 'Annuler la modification de la séquence',
 389+ 'mwe-sequenceedit-edit_cancel_confirm' => 'Êtes-vous sûr de vouloir annuler votre modification ? Les changements seront perdus.',
 390+ 'mwe-sequenceedit-zoom_in' => 'Zoom avant',
 391+ 'mwe-sequenceedit-zoom_out' => 'Zoom arrière',
 392+ 'mwe-sequenceedit-cut_clip' => 'Couper les clips',
 393+ 'mwe-sequenceedit-expand_track' => 'Étendre la piste',
 394+ 'mwe-sequenceedit-collapse_track' => 'Réduire la piste',
 395+ 'mwe-sequenceedit-play_from_position' => 'Lire à partir de la position de lecture',
 396+ 'mwe-sequenceedit-pixle2sec' => 'pixels vers secondes',
 397+ 'mwe-sequenceedit-rmclip' => 'Supprimer le clip',
 398+ 'mwe-sequenceedit-clip_in' => 'attacher',
 399+ 'mwe-sequenceedit-clip_out' => 'détacher',
 400+ 'mwe-sequenceedit-no_selected_resource' => '<h3>Aucune ressource sélectionnée</h3> Sélectionnez un clip pour activer l\'édition',
 401+ 'mwe-sequenceedit-error_edit_multiple' => '<h3>Plusieurs ressources sélectionnées</h3> Sélectionnez un seul clip pour le modifier',
 402+ 'mwe-sequenceedit-editor_options' => 'Options de l\'éditeur',
 403+ 'mwe-sequenceedit-editor_mode' => 'Mode de l\'éditeur',
 404+ 'mwe-sequenceedit-simple_editor_desc' => 'éditeur simple (style iMovie)',
 405+ 'mwe-sequenceedit-advanced_editor_desc' => 'éditeur avancé (style Final Cut)',
 406+ 'mwe-sequenceedit-other_options' => 'Autres options',
 407+ 'mwe-sequenceedit-contextmenu_opt' => 'Activer les menus contextuels',
 408+ 'mwe-sequenceedit-sequencer_credit_line' => 'Développé par <a href="http://kaltura.com">Kaltura, Inc.</a> en partenariat avec la <a href="http://wikimediafoundation.org/wiki/Home">Wikimedia Foundation</a> (<a href="#">plus d\'information</a>).',
 409+);
 410+$messages['gl'] = array(
 411+ 'mwe-sequenceedit-transition_in' => 'Transición de entrada',
 412+ 'mwe-sequenceedit-transition_out' => 'Transición de saída',
 413+ 'mwe-sequenceedit-effects' => 'Pila de efectos',
 414+ 'mwe-sequenceedit-remove_transition' => 'Eliminar a transición',
 415+ 'mwe-sequenceedit-edit_transin' => 'Editar a transición no vídeo',
 416+ 'mwe-sequenceedit-edit_transout' => 'Editar a transición fóra do vídeo',
 417+ 'mwe-sequenceedit-add-transition' => 'Engadir unha transición',
 418+ 'mwe-sequenceedit-menu_clipedit' => 'Editar o soporte',
 419+ 'mwe-sequenceedit-menu_transition' => 'Transicións e efectos',
 420+ 'mwe-sequenceedit-menu_cliplib' => 'Engadir un soporte',
 421+ 'mwe-sequenceedit-menu_resource_overview' => 'Vista xeral dos recursos',
 422+ 'mwe-sequenceedit-menu_options' => 'Opcións',
 423+ 'mwe-sequenceedit-loading_timeline' => 'Cargando a liña do tempo...',
 424+ 'mwe-sequenceedit-loading_user_rights' => 'Cargando os dereitos de usuario...',
 425+ 'mwe-sequenceedit-no_edit_permissions' => 'Non ten os permisos necesarios para gardar os cambios feitos nesta secuencia',
 426+ 'mwe-sequenceedit-edit_clip' => 'Editar o vídeo',
 427+ 'mwe-sequenceedit-edit_save' => 'Gardar os cambios feitos na secuencia',
 428+ 'mwe-sequenceedit-saving_wait' => 'Gardando (por favor, espere)',
 429+ 'mwe-sequenceedit-save_done' => 'Gardado',
 430+ 'mwe-sequenceedit-edit_cancel' => 'Cancelar a edición da secuencia',
 431+ 'mwe-sequenceedit-edit_cancel_confirm' => 'Está seguro de querer cancelar a súa edición? Perderanse todos os cambios feitos.',
 432+ 'mwe-sequenceedit-zoom_in' => 'Ampliar',
 433+ 'mwe-sequenceedit-zoom_out' => 'Reducir',
 434+ 'mwe-sequenceedit-cut_clip' => 'Cortar os vídeos',
 435+ 'mwe-sequenceedit-expand_track' => 'Expandir a pista',
 436+ 'mwe-sequenceedit-collapse_track' => 'Contraer a pista',
 437+ 'mwe-sequenceedit-play_from_position' => 'Reproducir desde a posición de lectura',
 438+ 'mwe-sequenceedit-pixle2sec' => 'píxeles a segundos',
 439+ 'mwe-sequenceedit-rmclip' => 'Eliminar o vídeo',
 440+ 'mwe-sequenceedit-clip_in' => 'achegar',
 441+ 'mwe-sequenceedit-clip_out' => 'separar',
 442+ 'mwe-sequenceedit-no_selected_resource' => '<h3>Non se seleccionou ningún recurso</h3> Seleccione un vídeo para permitir a edición.',
 443+ 'mwe-sequenceedit-error_edit_multiple' => '<h3>Seleccionáronse varios recursos</h3> Seleccione soamente un vídeo para editalo.',
 444+ 'mwe-sequenceedit-editor_options' => 'Opcións do editor',
 445+ 'mwe-sequenceedit-editor_mode' => 'Modo do editor',
 446+ 'mwe-sequenceedit-simple_editor_desc' => 'editor simple (estilo iMovie)',
 447+ 'mwe-sequenceedit-advanced_editor_desc' => 'editor avanzado (estilo Final Cut)',
 448+ 'mwe-sequenceedit-other_options' => 'Outras opcións',
 449+ 'mwe-sequenceedit-contextmenu_opt' => 'Activar os menús contextuais',
 450+ 'mwe-sequenceedit-sequencer_credit_line' => 'Desenvolvido por <a href="http://kaltura.com">Kaltura, Inc.</a> en colaboración coa <a href="http://wikimediafoundation.org/wiki/Portada_galega">Fundación Wikimedia</a> (<a href="#">máis información</a>).',
 451+);
 452+$messages['gsw'] = array(
 453+ 'mwe-sequenceedit-transition_in' => 'Ibergang aa',
 454+ 'mwe-sequenceedit-transition_out' => 'Ibergang ab',
 455+ 'mwe-sequenceedit-effects' => 'Effäkt-Stacks',
 456+ 'mwe-sequenceedit-remove_transition' => 'Ibergang useneh',
 457+ 'mwe-sequenceedit-edit_transin' => 'Ibergang im Clip bearbeite',
 458+ 'mwe-sequenceedit-edit_transout' => 'Ibergang usserhalb vum Clip bearbeite',
 459+ 'mwe-sequenceedit-add-transition' => 'Ibergang zuefiege',
 460+ 'mwe-sequenceedit-menu_clipedit' => 'Medie bearbeite',
 461+ 'mwe-sequenceedit-menu_transition' => 'Ibergäng un Effäkt',
 462+ 'mwe-sequenceedit-menu_cliplib' => 'Medie zuefiege',
 463+ 'mwe-sequenceedit-menu_resource_overview' => 'Quälleibersicht',
 464+ 'mwe-sequenceedit-menu_options' => 'Optione',
 465+ 'mwe-sequenceedit-loading_timeline' => 'Am Lade vun ere Zytzylete ...',
 466+ 'mwe-sequenceedit-loading_user_rights' => 'Am Lade vu Benutzerrächt ...',
 467+ 'mwe-sequenceedit-no_edit_permissions' => 'Du derfsch Änderige in däm Abschnitt nit spychere',
 468+ 'mwe-sequenceedit-edit_clip' => 'Clip bearbeite',
 469+ 'mwe-sequenceedit-edit_save' => 'Änderige am Abschnitt spychere',
 470+ 'mwe-sequenceedit-saving_wait' => 'Grad am Spychere (bitte wart no)',
 471+ 'mwe-sequenceedit-save_done' => 'Spychere fertig',
 472+ 'mwe-sequenceedit-edit_cancel' => 'Bearbeitig vu däm Abschnitt abbräche',
 473+ 'mwe-sequenceedit-edit_cancel_confirm' => 'Bisch sicher, ass Du Dyni bearbeitig witt abbräche? Alli Änderige gehn derno verlore.',
 474+ 'mwe-sequenceedit-zoom_in' => 'Vergreßere',
 475+ 'mwe-sequenceedit-zoom_out' => 'Verchleinere',
 476+ 'mwe-sequenceedit-cut_clip' => 'Clips uusschnitte',
 477+ 'mwe-sequenceedit-expand_track' => 'Spur uusklappe',
 478+ 'mwe-sequenceedit-collapse_track' => 'Spur yyklappe',
 479+ 'mwe-sequenceedit-play_from_position' => 'Abspile ab dr Playline-Position',
 480+ 'mwe-sequenceedit-pixle2sec' => 'Pixel je Sekund',
 481+ 'mwe-sequenceedit-rmclip' => 'Clip uuseneh',
 482+ 'mwe-sequenceedit-clip_in' => 'Clip zuefiege',
 483+ 'mwe-sequenceedit-clip_out' => 'Clip uuseneh',
 484+ 'mwe-sequenceedit-no_selected_resource' => '<h3>Kei Quälle uusgwehlt</h3> Wehl e Clip uus go s Bearbeite meglig mache.',
 485+ 'mwe-sequenceedit-error_edit_multiple' => '<h3>Meh wie ei Quälle uusgwehlt</h3> Wehl ei einzige Clip zuem Bearbeite uus.',
 486+ 'mwe-sequenceedit-editor_options' => 'Yystellige zum Bearbeite',
 487+ 'mwe-sequenceedit-editor_mode' => 'Bearbeitigsmodus',
 488+ 'mwe-sequenceedit-simple_editor_desc' => 'Eifachi Bearbeitig (iMovie-Stil)',
 489+ 'mwe-sequenceedit-advanced_editor_desc' => 'Fortgschritteni Bearbeitig (Final Cut-Stil)',
 490+ 'mwe-sequenceedit-other_options' => 'Anderi Optione',
 491+ 'mwe-sequenceedit-contextmenu_opt' => 'Kontext-Menüs zueloo',
 492+ 'mwe-sequenceedit-sequencer_credit_line' => 'Entwicklet dur <a href="http://kaltura.com">Kaltura, Inc.</a> zämme mit dr <a href="http://wikimediafoundation.org/wiki/Home">Wikimedia Foundation</a> (<a href="#">meh Informatione</a>).',
 493+);
 494+$messages['he'] = array(
 495+ 'mwe-sequenceedit-transition_in' => 'מעברון כניסה',
 496+ 'mwe-sequenceedit-transition_out' => 'מעברון יציאה',
 497+ 'mwe-sequenceedit-effects' => 'מכלול האפקטים',
 498+ 'mwe-sequenceedit-remove_transition' => 'הסרת המעברון',
 499+ 'mwe-sequenceedit-edit_transin' => 'עריכת המעברון אל תוך הסרטון',
 500+ 'mwe-sequenceedit-edit_transout' => 'עריכת המעברון אל מחוץ לסרטון',
 501+ 'mwe-sequenceedit-menu_clipedit' => 'עריכת המדיה',
 502+ 'mwe-sequenceedit-menu_transition' => 'מעברונים ואפקטים',
 503+ 'mwe-sequenceedit-menu_cliplib' => 'הוספת מדיה',
 504+ 'mwe-sequenceedit-menu_resource_overview' => 'סקירת המשאבים',
 505+ 'mwe-sequenceedit-menu_options' => 'אפשרויות',
 506+ 'mwe-sequenceedit-loading_timeline' => 'מתבצעת טעינת ציר הזמן ...',
 507+ 'mwe-sequenceedit-loading_user_rights' => 'מתבצעת טעינת הרשאות המשתמש ...',
 508+ 'mwe-sequenceedit-no_edit_permissions' => 'אין לכם הרשאות לשמור את השינויים לרצף זה',
 509+ 'mwe-sequenceedit-edit_clip' => 'עריכת הסרטון',
 510+ 'mwe-sequenceedit-edit_save' => 'שמירת השינויים ברצף',
 511+ 'mwe-sequenceedit-saving_wait' => 'השמירה מתבצעת (נא להמתין)',
 512+ 'mwe-sequenceedit-save_done' => 'השמירה הושלמה',
 513+ 'mwe-sequenceedit-edit_cancel' => 'ביטול עריכת הרצף',
 514+ 'mwe-sequenceedit-edit_cancel_confirm' => 'האם אתם בטוחים שברצונם לבטל את עריכתכם? השינויים יאבדו.',
 515+ 'mwe-sequenceedit-zoom_in' => 'התקרבות',
 516+ 'mwe-sequenceedit-zoom_out' => 'התרחקות',
 517+ 'mwe-sequenceedit-cut_clip' => 'גזירת סרטונים',
 518+ 'mwe-sequenceedit-expand_track' => 'הרחבת הרצועה',
 519+ 'mwe-sequenceedit-collapse_track' => 'צמצום הרצועה',
 520+ 'mwe-sequenceedit-play_from_position' => 'נגינה מהמיקום בשורת הנגינה',
 521+ 'mwe-sequenceedit-pixle2sec' => 'פיקסלים לשניות',
 522+ 'mwe-sequenceedit-rmclip' => 'הסרת סרטון',
 523+ 'mwe-sequenceedit-no_selected_resource' => '<h3>לא נבחר משאב</h3> יש לבחור סרטון כדי לאפשר עריכה.',
 524+ 'mwe-sequenceedit-error_edit_multiple' => '<h3>נבחרו מספר מקורות</h3> יש לבחור בקטע בודד כדי לערוך אותו.',
 525+ 'mwe-sequenceedit-editor_options' => 'אפשרויות העורך',
 526+ 'mwe-sequenceedit-editor_mode' => 'מצב עורך',
 527+ 'mwe-sequenceedit-simple_editor_desc' => 'עורך פשוט (בסגנון iMovie)',
 528+ 'mwe-sequenceedit-advanced_editor_desc' => 'עורך מתקדם (בסגנון Final Cut)',
 529+ 'mwe-sequenceedit-other_options' => 'אפשרויות אחרות',
 530+ 'mwe-sequenceedit-contextmenu_opt' => 'הפעלת תפריטי ההקשר',
 531+ 'mwe-sequenceedit-sequencer_credit_line' => 'פותח על ידי <a href="http://kaltura.com">Kaltura בע"מ</a> בשיתוף עם <a href="http://wikimediafoundation.org/wiki/Home">קרן ויקימדיה</a> (<a href="#">למידע נוסף</a>).',
 532+);
 533+$messages['hsb'] = array(
 534+ 'mwe-sequenceedit-transition_in' => 'Zablendować',
 535+ 'mwe-sequenceedit-transition_out' => 'Wublendować',
 536+ 'mwe-sequenceedit-effects' => 'Stapl efektow',
 537+ 'mwe-sequenceedit-remove_transition' => 'Přechad wotstronić',
 538+ 'mwe-sequenceedit-edit_transin' => 'Přechod do klipa wobdźěłać',
 539+ 'mwe-sequenceedit-edit_transout' => 'Přechod z klipa wobdźěłać',
 540+ 'mwe-sequenceedit-add-transition' => 'Přechad přidać',
 541+ 'mwe-sequenceedit-menu_clipedit' => 'Medije wobdźěłać',
 542+ 'mwe-sequenceedit-menu_transition' => 'Přechady a efekty',
 543+ 'mwe-sequenceedit-menu_cliplib' => 'Medije přidać',
 544+ 'mwe-sequenceedit-menu_resource_overview' => 'Resursowy přehlad',
 545+ 'mwe-sequenceedit-menu_options' => 'Opcije',
 546+ 'mwe-sequenceedit-loading_timeline' => 'Časowa lajsta ...',
 547+ 'mwe-sequenceedit-loading_user_rights' => 'Wužiwarske prawa so začituja ...',
 548+ 'mwe-sequenceedit-no_edit_permissions' => 'Nimaš prawa, zo by změny na tutej sekwency składował',
 549+ 'mwe-sequenceedit-edit_clip' => 'Klip wobdźěłać',
 550+ 'mwe-sequenceedit-edit_save' => 'Změny sekwency składować',
 551+ 'mwe-sequenceedit-saving_wait' => 'Składuje so runje (prošu čakać)',
 552+ 'mwe-sequenceedit-save_done' => 'Składowanje zakónčene',
 553+ 'mwe-sequenceedit-edit_cancel' => 'Wobdźěłowanje sekwency přetorhnyć',
 554+ 'mwe-sequenceedit-edit_cancel_confirm' => 'Chceš woprawdźe swoje wobdźěłanje zaćisnyć? Změny so zhubja.',
 555+ 'mwe-sequenceedit-zoom_in' => 'Powjetšić',
 556+ 'mwe-sequenceedit-zoom_out' => 'Pomjeńšić',
 557+ 'mwe-sequenceedit-cut_clip' => 'Klipy třihać',
 558+ 'mwe-sequenceedit-expand_track' => 'Ćěr rozfałdować',
 559+ 'mwe-sequenceedit-collapse_track' => 'Ćěr fałdować',
 560+ 'mwe-sequenceedit-play_from_position' => 'Wot aktuelneje pozicije wohtrać',
 561+ 'mwe-sequenceedit-pixle2sec' => 'piksele do sekundow',
 562+ 'mwe-sequenceedit-rmclip' => 'Klip wotstronić',
 563+ 'mwe-sequenceedit-clip_in' => 'klip přidać',
 564+ 'mwe-sequenceedit-clip_out' => 'klip wotstronić',
 565+ 'mwe-sequenceedit-no_selected_resource' => '<h3>Žana resursa wubrana</h3> Wubjer klip, zo by wobdźěłowanje zmóžnił.',
 566+ 'mwe-sequenceedit-error_edit_multiple' => '<h3>Wjacore resursy wubrane</h3> Wubjer jednotliwy klip za wobdźěłanje.',
 567+ 'mwe-sequenceedit-editor_options' => 'Editorowe opcije',
 568+ 'mwe-sequenceedit-editor_mode' => 'Editorowy modus',
 569+ 'mwe-sequenceedit-simple_editor_desc' => 'jednory editor (stil iMovie)',
 570+ 'mwe-sequenceedit-advanced_editor_desc' => 'rozšěrjeny editor (stil Final Cut)',
 571+ 'mwe-sequenceedit-other_options' => 'Druhe opcije',
 572+ 'mwe-sequenceedit-contextmenu_opt' => 'Kontekstowe menije zmóžnić',
 573+ 'mwe-sequenceedit-sequencer_credit_line' => 'Wuwity wot <a href="http://kaltura.com">Kaltura, Inc.</a> w partnerstwje ze załožbu <a href="http://wikimediafoundation.org/wiki/Home">Wikimedia Foundation</a> (<a href="#">dalše informacije</a>).',
 574+);
 575+$messages['hu'] = array(
 576+ 'mwe-sequenceedit-transition_in' => 'Áttűnés kezdete',
 577+ 'mwe-sequenceedit-transition_out' => 'Áttűnés vége',
 578+ 'mwe-sequenceedit-effects' => 'Effektverem',
 579+ 'mwe-sequenceedit-remove_transition' => 'Áttűnés eltávolítása',
 580+ 'mwe-sequenceedit-edit_transin' => 'Kezdő átmenet szerkesztése',
 581+ 'mwe-sequenceedit-edit_transout' => 'Klip végi átmenet szerkesztése',
 582+ 'mwe-sequenceedit-add-transition' => 'Átmenet hozzáadása',
 583+ 'mwe-sequenceedit-menu_clipedit' => 'Média szerkesztése',
 584+ 'mwe-sequenceedit-menu_transition' => 'Áttűnések és effektek',
 585+ 'mwe-sequenceedit-menu_cliplib' => 'Média hozzáadása',
 586+ 'mwe-sequenceedit-menu_resource_overview' => 'Erőforrás áttekintés',
 587+ 'mwe-sequenceedit-menu_options' => 'Beállítások',
 588+ 'mwe-sequenceedit-loading_timeline' => 'Idővonal betöltése…',
 589+ 'mwe-sequenceedit-loading_user_rights' => 'Felhasználói jogosultságok betöltése…',
 590+ 'mwe-sequenceedit-no_edit_permissions' => 'Nincs jogosultságod a változtatások elmentéséhez a jelenetbe',
 591+ 'mwe-sequenceedit-edit_clip' => 'Klip szerkesztése',
 592+ 'mwe-sequenceedit-edit_save' => 'Jelenet változásainak mentése',
 593+ 'mwe-sequenceedit-saving_wait' => 'Mentés folyamatban (kérlek várj)',
 594+ 'mwe-sequenceedit-save_done' => 'Mentés kész',
 595+ 'mwe-sequenceedit-edit_cancel' => 'Jelenet szerkesztésének eldobása',
 596+ 'mwe-sequenceedit-edit_cancel_confirm' => 'Biztos vagy benne, hogy megszakítod a szerkesztést? A változtatások elvesznek.',
 597+ 'mwe-sequenceedit-zoom_in' => 'Nagyítás',
 598+ 'mwe-sequenceedit-zoom_out' => 'Kicsinyítés',
 599+ 'mwe-sequenceedit-cut_clip' => 'Klipek vágása',
 600+ 'mwe-sequenceedit-expand_track' => 'Sáv kibontása',
 601+ 'mwe-sequenceedit-collapse_track' => 'Sáv összecsukása',
 602+ 'mwe-sequenceedit-play_from_position' => 'Lejátszás a lejátszó pozíciójától',
 603+ 'mwe-sequenceedit-pixle2sec' => 'képpontokat másodpercekké',
 604+ 'mwe-sequenceedit-rmclip' => 'Klip eltávolítása',
 605+ 'mwe-sequenceedit-clip_in' => 'klip eleji',
 606+ 'mwe-sequenceedit-clip_out' => 'klip végi',
 607+ 'mwe-sequenceedit-no_selected_resource' => '<h3>Nincs kiválasztott erőforrás</h3> Válassz egy klipet a szerkesztéshez.',
 608+ 'mwe-sequenceedit-error_edit_multiple' => '<h3>Több erőforrás kiválasztva</h3> Egy klipet válassz a szerkesztéséhez.',
 609+ 'mwe-sequenceedit-editor_options' => 'Szerkesztő beállításai',
 610+ 'mwe-sequenceedit-editor_mode' => 'Szerkesztői mód',
 611+ 'mwe-sequenceedit-simple_editor_desc' => 'egyszerű szerkesztő (iMovie stílusban)',
 612+ 'mwe-sequenceedit-advanced_editor_desc' => 'haladó szerkesztő (Final Cut stílusban)',
 613+ 'mwe-sequenceedit-other_options' => 'Egyéb beállítások',
 614+ 'mwe-sequenceedit-contextmenu_opt' => 'Helyi menük engedélyezése',
 615+ 'mwe-sequenceedit-sequencer_credit_line' => 'Fejlesztette a <a href="http://kaltura.com">Kaltura, Inc.</a> együttműködésben a <a href="http://wikimediafoundation.org/wiki/Home">Wikimédia Alapítvánnyal</a> (<a href="#">további információk</a>)',
 616+);
 617+$messages['ia'] = array(
 618+ 'mwe-sequenceedit-transition_in' => 'Transition entrante',
 619+ 'mwe-sequenceedit-transition_out' => 'Transition sortiente',
 620+ 'mwe-sequenceedit-effects' => 'Pila de effectos',
 621+ 'mwe-sequenceedit-remove_transition' => 'Remover transition',
 622+ 'mwe-sequenceedit-edit_transin' => 'Inserer transition in clip',
 623+ 'mwe-sequenceedit-edit_transout' => 'Remover transition del clip',
 624+ 'mwe-sequenceedit-add-transition' => 'Adder un transition',
 625+ 'mwe-sequenceedit-menu_clipedit' => 'Modificar multimedia',
 626+ 'mwe-sequenceedit-menu_transition' => 'Transitiones e effectos',
 627+ 'mwe-sequenceedit-menu_cliplib' => 'Adder multimedia',
 628+ 'mwe-sequenceedit-menu_resource_overview' => 'Summario de ressources',
 629+ 'mwe-sequenceedit-menu_options' => 'Optiones',
 630+ 'mwe-sequenceedit-loading_timeline' => 'Carga chronologia ...',
 631+ 'mwe-sequenceedit-loading_user_rights' => 'Carga derectos de usator ...',
 632+ 'mwe-sequenceedit-no_edit_permissions' => 'Tu non ha le permission de immagazinar modificationes a iste sequentia',
 633+ 'mwe-sequenceedit-edit_clip' => 'Modificar clip',
 634+ 'mwe-sequenceedit-edit_save' => 'Immagazinar modificationes del sequentia',
 635+ 'mwe-sequenceedit-saving_wait' => 'Immagazinage in curso (per favor attende)',
 636+ 'mwe-sequenceedit-save_done' => 'Immagazinage complete',
 637+ 'mwe-sequenceedit-edit_cancel' => 'Cancellar modification del sequentia',
 638+ 'mwe-sequenceedit-edit_cancel_confirm' => 'Es tu secur de voler cancellar tu modification? Le cambiamentos essera perdite.',
 639+ 'mwe-sequenceedit-zoom_in' => 'Zoom avante',
 640+ 'mwe-sequenceedit-zoom_out' => 'Zoom retro',
 641+ 'mwe-sequenceedit-cut_clip' => 'Trenchar clips',
 642+ 'mwe-sequenceedit-expand_track' => 'Expander tracia',
 643+ 'mwe-sequenceedit-collapse_track' => 'Contraher tracia',
 644+ 'mwe-sequenceedit-play_from_position' => 'Reproducer a partir del position de lectura',
 645+ 'mwe-sequenceedit-pixle2sec' => 'pixeles a secundas',
 646+ 'mwe-sequenceedit-rmclip' => 'Remover clip',
 647+ 'mwe-sequenceedit-clip_in' => 'attachar',
 648+ 'mwe-sequenceedit-clip_out' => 'distachar',
 649+ 'mwe-sequenceedit-no_selected_resource' => '<h3>Nulle ressource seligite</h3> Selige un clip pro activar le modification.',
 650+ 'mwe-sequenceedit-error_edit_multiple' => '<h3>Plure ressources seligite</h3> Selige un sol clip pro modificar lo.',
 651+ 'mwe-sequenceedit-editor_options' => 'Optiones de editor',
 652+ 'mwe-sequenceedit-editor_mode' => 'Modo de editor',
 653+ 'mwe-sequenceedit-simple_editor_desc' => 'editor simple (stilo iMovie)',
 654+ 'mwe-sequenceedit-advanced_editor_desc' => 'editor avantiate (stilo Final Cut)',
 655+ 'mwe-sequenceedit-other_options' => 'Altere optiones',
 656+ 'mwe-sequenceedit-contextmenu_opt' => 'Activar menus contextual',
 657+ 'mwe-sequenceedit-sequencer_credit_line' => 'Disveloppate per <a href="http://kaltura.com">Kaltura, Inc.</a> in association con le <a href="http://wikimediafoundation.org/wiki/Home">Fundation Wikimedia</a> (<a href="#">plus information</a>).',
 658+);
 659+$messages['id'] = array(
 660+ 'mwe-sequenceedit-transition_in' => 'Transisi masuk',
 661+ 'mwe-sequenceedit-transition_out' => 'Transisi keluar',
 662+ 'mwe-sequenceedit-effects' => 'Tumpuk efek',
 663+ 'mwe-sequenceedit-remove_transition' => 'Singkirkan transisi',
 664+ 'mwe-sequenceedit-edit_transin' => 'Sunting transisi masuk klip',
 665+ 'mwe-sequenceedit-edit_transout' => 'Sunting transisi keluar klip',
 666+ 'mwe-sequenceedit-add-transition' => 'Tambahkan transisi',
 667+ 'mwe-sequenceedit-menu_clipedit' => 'Sunting media',
 668+ 'mwe-sequenceedit-menu_transition' => 'Transisi dan efek',
 669+ 'mwe-sequenceedit-menu_cliplib' => 'Tambah media',
 670+ 'mwe-sequenceedit-menu_resource_overview' => 'Tinjauan sumber daya',
 671+ 'mwe-sequenceedit-menu_options' => 'Pilihan',
 672+ 'mwe-sequenceedit-loading_timeline' => 'Memuat garis waktu ...',
 673+ 'mwe-sequenceedit-loading_user_rights' => 'Memuat hak pengguna ...',
 674+ 'mwe-sequenceedit-no_edit_permissions' => 'Anda tidak memiliki hak untuk menyimpan perubahan pada bagian ini',
 675+ 'mwe-sequenceedit-edit_clip' => 'Sunting klip',
 676+ 'mwe-sequenceedit-edit_save' => 'Simpan perubahan urutan',
 677+ 'mwe-sequenceedit-saving_wait' => 'Penyimpanan dalam proses (mohoon tunggu)',
 678+ 'mwe-sequenceedit-save_done' => 'Menyimpanan lengkap',
 679+ 'mwe-sequenceedit-edit_cancel' => 'Batalkan suntingan urutan',
 680+ 'mwe-sequenceedit-edit_cancel_confirm' => 'Apakan anda yakin akan membatalkan suntingan anda? Perubahan akan hilang.',
 681+ 'mwe-sequenceedit-zoom_in' => 'Zum masuk',
 682+ 'mwe-sequenceedit-zoom_out' => 'Zum keluar',
 683+ 'mwe-sequenceedit-cut_clip' => 'Potong klip',
 684+ 'mwe-sequenceedit-expand_track' => 'Kembangkan trek',
 685+ 'mwe-sequenceedit-collapse_track' => 'Ciutkan trek',
 686+ 'mwe-sequenceedit-play_from_position' => 'Putar dari posisi playline',
 687+ 'mwe-sequenceedit-pixle2sec' => 'piksel ke detik',
 688+ 'mwe-sequenceedit-rmclip' => 'Hapus klip',
 689+ 'mwe-sequenceedit-clip_in' => 'klip masuk',
 690+ 'mwe-sequenceedit-clip_out' => 'klip keluar',
 691+ 'mwe-sequenceedit-no_selected_resource' => '<h3>Tidak ada sumber dipilih</h3> Pilih klip untuk mengaktifkan suntingan.',
 692+ 'mwe-sequenceedit-error_edit_multiple' => '<h3>Beberapa sumber telah dipilih</h3> Pilih satu klip untuk disunting.',
 693+ 'mwe-sequenceedit-editor_options' => 'Pilihan penyunting',
 694+ 'mwe-sequenceedit-editor_mode' => 'Modus sunting',
 695+ 'mwe-sequenceedit-simple_editor_desc' => 'suntingan sederhana (gaya iMovie)',
 696+ 'mwe-sequenceedit-advanced_editor_desc' => 'suntingan lanjutan (gaya potongan akhir)',
 697+ 'mwe-sequenceedit-other_options' => 'Pilihan lain',
 698+ 'mwe-sequenceedit-contextmenu_opt' => 'Aktifkan menu konteks',
 699+ 'mwe-sequenceedit-sequencer_credit_line' => 'Dikembangkan oleh <a href="http://kaltura.com">Kaltura, Inc</a> bekerja sama dengan <a href="http://wikimediafoundation.org/wiki/Home">Wikimedia Foundation</a> (<a href="#">informasi lebih lanjut</a>).',
 700+);
 701+$messages['it'] = array(
 702+ 'mwe-sequenceedit-menu_options' => 'Opzioni',
 703+ 'mwe-sequenceedit-other_options' => 'Altre opzioni',
 704+ 'mwe-sequenceedit-contextmenu_opt' => 'Attiva i menu contestuali',
 705+);
 706+$messages['ja'] = array(
 707+ 'mwe-sequenceedit-transition_in' => 'トランジション・イン',
 708+ 'mwe-sequenceedit-transition_out' => 'トランジション・アウト',
 709+ 'mwe-sequenceedit-effects' => 'エフェクト棚',
 710+ 'mwe-sequenceedit-remove_transition' => 'トランジションを除去',
 711+ 'mwe-sequenceedit-edit_transin' => 'クリップのトランジション・インを編集',
 712+ 'mwe-sequenceedit-edit_transout' => 'クリップのトランジション・アウトを編集',
 713+ 'mwe-sequenceedit-add-transition' => 'トランジションを追加',
 714+ 'mwe-sequenceedit-menu_clipedit' => 'メディアを編集',
 715+ 'mwe-sequenceedit-menu_transition' => 'トランジションとエフェクト',
 716+ 'mwe-sequenceedit-menu_cliplib' => 'メディアを追加',
 717+ 'mwe-sequenceedit-menu_resource_overview' => 'リソース概観',
 718+ 'mwe-sequenceedit-menu_options' => 'オプション',
 719+ 'mwe-sequenceedit-loading_timeline' => 'タイムラインを読み込み中 …',
 720+ 'mwe-sequenceedit-loading_user_rights' => '利用者権限を読み込み中 …',
 721+ 'mwe-sequenceedit-no_edit_permissions' => 'あなたはこのシーケンスに変更を加える許可がありません',
 722+ 'mwe-sequenceedit-edit_clip' => 'クリップを編集',
 723+ 'mwe-sequenceedit-edit_save' => 'シーケンスの変更を保存',
 724+ 'mwe-sequenceedit-saving_wait' => '保存処理中 (お待ちください)',
 725+ 'mwe-sequenceedit-save_done' => '保存完了',
 726+ 'mwe-sequenceedit-edit_cancel' => 'シーケンスの編集を中止',
 727+ 'mwe-sequenceedit-edit_cancel_confirm' => '本当に編集を中止しますか?変更は失われます。',
 728+ 'mwe-sequenceedit-zoom_in' => '拡大',
 729+ 'mwe-sequenceedit-zoom_out' => '縮小',
 730+ 'mwe-sequenceedit-cut_clip' => 'クリップを切り抜く',
 731+ 'mwe-sequenceedit-expand_track' => 'トラックを展開',
 732+ 'mwe-sequenceedit-collapse_track' => 'トラックを折り畳む',
 733+ 'mwe-sequenceedit-play_from_position' => '再生開始位置から再生',
 734+ 'mwe-sequenceedit-pixle2sec' => 'ピクセルから秒へ',
 735+ 'mwe-sequenceedit-rmclip' => 'クリップを削除',
 736+ 'mwe-sequenceedit-clip_in' => '添付する',
 737+ 'mwe-sequenceedit-clip_out' => '除去する',
 738+ 'mwe-sequenceedit-no_selected_resource' => '<h3>素材が選択されていません</h3>編集を行うにはクリップを選択してください。',
 739+ 'mwe-sequenceedit-error_edit_multiple' => '<h3>複数の素材が選択されています</h3> 編集するにはクリップを1つだけ選択してください。',
 740+ 'mwe-sequenceedit-editor_options' => '編集オプション',
 741+ 'mwe-sequenceedit-editor_mode' => '編集モード',
 742+ 'mwe-sequenceedit-simple_editor_desc' => '単純なエディター (iMovie 風)',
 743+ 'mwe-sequenceedit-advanced_editor_desc' => '高度なエディター (Final Cut 風)',
 744+ 'mwe-sequenceedit-other_options' => '他のオプション',
 745+ 'mwe-sequenceedit-contextmenu_opt' => 'コンテキストメニューを有効化',
 746+ 'mwe-sequenceedit-sequencer_credit_line' => '本機能は<a href="http://kaltura.com">Kaltura, Inc.</a> が <a href="http://wikimediafoundation.org/wiki/Home">ウィキメディア財団</a>の協力のもと開発しました (<a href="#">詳細情報</a>)。',
 747+);
 748+$messages['ko'] = array(
 749+ 'mwe-sequenceedit-menu_options' => '설정',
 750+ 'mwe-sequenceedit-zoom_in' => '확대',
 751+ 'mwe-sequenceedit-zoom_out' => '축소',
 752+ 'mwe-sequenceedit-editor_options' => '에디터 설정',
 753+ 'mwe-sequenceedit-other_options' => '다른 설정',
 754+);
 755+$messages['ksh'] = array(
 756+ 'mwe-sequenceedit-transition_in' => 'Övverjang en',
 757+ 'mwe-sequenceedit-transition_out' => 'Övverjang uß',
 758+ 'mwe-sequenceedit-effects' => 'Dä Pöngel met dä Effäkte',
 759+ 'mwe-sequenceedit-remove_transition' => 'Dä Övverjang fott nämme',
 760+ 'mwe-sequenceedit-edit_transin' => 'Donn dä Övverjang en dä Ußschnett eren bränge',
 761+ 'mwe-sequenceedit-edit_transout' => 'Donn dä Övverjang uß däm Ußschned eruß bränge',
 762+ 'mwe-sequenceedit-add-transition' => 'Donn ene Övverjang dobei',
 763+ 'mwe-sequenceedit-menu_clipedit' => 'Meedije Ändere',
 764+ 'mwe-sequenceedit-menu_transition' => 'Övverjäng un besönder Effäkte',
 765+ 'mwe-sequenceedit-menu_cliplib' => 'Alle Meedije',
 766+ 'mwe-sequenceedit-menu_resource_overview' => 'Övverseesch',
 767+ 'mwe-sequenceedit-menu_options' => 'Ußwahle',
 768+ 'mwe-sequenceedit-loading_timeline' => 'En Zick-Reih aam Laade&nbsp;…',
 769+ 'mwe-sequenceedit-loading_user_rights' => 'Metmaacher-Rääschte aam Laade&nbsp;…',
 770+ 'mwe-sequenceedit-no_edit_permissions' => 'Do häs nit dat Rääsch, Änderunge aan heh dä Afshpellleß afzeshpeishere',
 771+ 'mwe-sequenceedit-edit_clip' => 'Ußschnett ändere',
 772+ 'mwe-sequenceedit-edit_save' => 'Änderunge aan dä Afshpellleß afshpeishere',
 773+ 'mwe-sequenceedit-saving_wait' => 'Et Afsheijshere es noch em Jang, donn noch jät waade.',
 774+ 'mwe-sequenceedit-save_done' => 'Fäädesch afjeshpeishert',
 775+ 'mwe-sequenceedit-edit_cancel' => 'Et Ändere vun dä Afshpellleß afbreshe',
 776+ 'mwe-sequenceedit-edit_cancel_confirm' => 'Bes De sescher, dat De et Ändere afbräsche wells? All Ding Werrek beß jäz jeiht verschött!',
 777+ 'mwe-sequenceedit-zoom_in' => 'Eraan zoome',
 778+ 'mwe-sequenceedit-zoom_out' => 'Fott zoome',
 779+ 'mwe-sequenceedit-cut_clip' => 'Ußschnedde ußschnigge',
 780+ 'mwe-sequenceedit-expand_track' => 'Shpoor opklappe',
 781+ 'mwe-sequenceedit-collapse_track' => 'Shpoor ennklappe',
 782+ 'mwe-sequenceedit-play_from_position' => 'Vun dä Linnesch aan afschpelle',
 783+ 'mwe-sequenceedit-pixle2sec' => 'Pixele pro Sekund',
 784+ 'mwe-sequenceedit-rmclip' => 'Ußschnett fott schmiiße',
 785+ 'mwe-sequenceedit-clip_in' => 'Ußschnett en',
 786+ 'mwe-sequenceedit-clip_out' => 'Ußschnett uß',
 787+ 'mwe-sequenceedit-no_selected_resource' => '<h3>Nix ußjesöhk</h3>Söhk ene Ußschnett uß, öm et Ändere müjjelesch ze maache.',
 788+ 'mwe-sequenceedit-error_edit_multiple' => '<h3>Mieh wie ein Denge ußjesöhk</h3>Söhk ene einzel Ußschnett uß, öm et Ändere müjjelesch ze maache.',
 789+ 'mwe-sequenceedit-editor_options' => 'Enshtällunge för et Ändere',
 790+ 'mwe-sequenceedit-editor_mode' => 'Aat vum Beärbeide',
 791+ 'mwe-sequenceedit-simple_editor_desc' => 'Eijfach Beärbeide (em Shtil vun <i lang="en">iMovie</i>)',
 792+ 'mwe-sequenceedit-advanced_editor_desc' => 'Beärbeide met alle Schikaane (em Shtil vun <i lang="en">Final Cut</i>)',
 793+ 'mwe-sequenceedit-other_options' => 'Ander Müjjeleshkeite',
 794+ 'mwe-sequenceedit-contextmenu_opt' => 'Donn de Kontex-Menühß zohlohße',
 795+ 'mwe-sequenceedit-sequencer_credit_line' => 'Äntweckelt vun dä Ferma <i lang="en"><a href="http://kaltura.com">Kaltura, Inc.</a></i> em Zosammewerke met dä <a href="http://wikimediafoundation.org/wiki/Home">Wikimedia Shtefftung</a> (<a href="#">mieh Enfommazjohne</a>).',
 796+);
 797+$messages['lb'] = array(
 798+ 'mwe-sequenceedit-transition_in' => 'Iwwergang fir eran',
 799+ 'mwe-sequenceedit-transition_out' => 'Iwwergang fir eraus',
 800+ 'mwe-sequenceedit-remove_transition' => 'Iwwergang ewechhuelen',
 801+ 'mwe-sequenceedit-add-transition' => 'En Iwwergang derbäisetzen',
 802+ 'mwe-sequenceedit-menu_transition' => 'Iwwergäng an Effekter',
 803+ 'mwe-sequenceedit-menu_cliplib' => 'E Medium derbäi setzen',
 804+ 'mwe-sequenceedit-menu_resource_overview' => 'Iwwersiicht iwwer d\'Ressourcen',
 805+ 'mwe-sequenceedit-menu_options' => 'Optiounen',
 806+ 'mwe-sequenceedit-loading_timeline' => 'Zäitläischt lueden ...',
 807+ 'mwe-sequenceedit-loading_user_rights' => 'Benotzerrechter lueden ...',
 808+ 'mwe-sequenceedit-no_edit_permissions' => 'Dir hutt net d\'Rechter fir Ännerungen un dëser Sequenz',
 809+ 'mwe-sequenceedit-edit_clip' => 'Clip änneren',
 810+ 'mwe-sequenceedit-edit_save' => 'D\'Ännerunge vun der Sequenz späicheren',
 811+ 'mwe-sequenceedit-saving_wait' => 'Späicheren amgaang (waard w.e.g.)',
 812+ 'mwe-sequenceedit-save_done' => 'Späicheren ofgeschloss',
 813+ 'mwe-sequenceedit-edit_cancel' => 'Ännerung vun der Sequenz ofbriechen',
 814+ 'mwe-sequenceedit-edit_cancel_confirm' => 'Sidd Dir sécher datt dir Är Ännerung ofbrieche wëllt? D\'Ännerunge gi verluer.',
 815+ 'mwe-sequenceedit-zoom_in' => 'Era zoomen',
 816+ 'mwe-sequenceedit-cut_clip' => 'Clippe schneiden',
 817+ 'mwe-sequenceedit-pixle2sec' => 'Pixelen op Sekonnen',
 818+ 'mwe-sequenceedit-rmclip' => 'Clip ewechhuelen',
 819+ 'mwe-sequenceedit-clip_in' => 'Clip derbäisetzen',
 820+ 'mwe-sequenceedit-clip_out' => 'Clip ewechhuelen',
 821+ 'mwe-sequenceedit-other_options' => 'Aner Optiounen',
 822+ 'mwe-sequenceedit-contextmenu_opt' => 'Kontextmenüen aktivéieren',
 823+ 'mwe-sequenceedit-sequencer_credit_line' => 'Entwéckelt vu <a href="http://kaltura.com">Kaltura, Inc.</a> an zesummenaarbecht mat der <a href="http://wikimediafoundation.org/wiki/Home">Wikimedia Foundation</a> (<a href="#">méi Informatiounen</a>).',
 824+);
 825+$messages['ml'] = array(
 826+ 'mwe-sequenceedit-menu_clipedit' => 'മീഡിയ തിരുത്തുക',
 827+ 'mwe-sequenceedit-menu_cliplib' => 'മീഡിയ കൂട്ടിച്ചേർക്കുക',
 828+ 'mwe-sequenceedit-menu_resource_overview' => 'സ്രോതസ്സ് അവലോകനം',
 829+ 'mwe-sequenceedit-menu_options' => 'ഐച്ഛികങ്ങൾ',
 830+ 'mwe-sequenceedit-loading_timeline' => 'സമയരേഖ ശേഖരിക്കുന്നു ...',
 831+ 'mwe-sequenceedit-loading_user_rights' => 'ഉപയോക്തൃ അവകാശങ്ങൾ ശേഖരിക്കുന്നു ...',
 832+ 'mwe-sequenceedit-no_edit_permissions' => 'ഈ അനുവർത്തനത്തിൽ മാറ്റങ്ങൾ സേവ് ചെയ്യാനുള്ള അനുമതി താങ്കൾക്കില്ല',
 833+ 'mwe-sequenceedit-edit_clip' => 'ചലച്ചിത്രശകലം തിരുത്തുക',
 834+ 'mwe-sequenceedit-edit_save' => 'അനുവർത്തനത്തിലെ മാറ്റങ്ങൾ സേവ് ചെയ്യുക',
 835+ 'mwe-sequenceedit-saving_wait' => 'സേവ് ചെയ്യൽ പുരോഗമിക്കുന്നു (ദയവായി കാത്തിരിക്കുക)',
 836+ 'mwe-sequenceedit-save_done' => 'പൂർണ്ണമായത് സേവ് ചെയ്യുക',
 837+ 'mwe-sequenceedit-edit_cancel' => 'അനുവർത്തനത്തിലെ തിരുത്തൽ റദ്ദാക്കുക',
 838+ 'mwe-sequenceedit-edit_cancel_confirm' => 'താങ്കളുടെ തിരുത്തൽ റദ്ദാക്കണം എന്നതിൽ താങ്കൾ ഉറച്ചു നിൽക്കുന്നുവോ? മാറ്റങ്ങൾ നഷ്ടമാവുന്നതാണ്.',
 839+ 'mwe-sequenceedit-zoom_in' => 'വലുതാക്കുക',
 840+ 'mwe-sequenceedit-zoom_out' => 'ചെറുതാക്കുക',
 841+ 'mwe-sequenceedit-cut_clip' => 'ചലച്ചിത്രശകലം മുറിയ്ക്കുക',
 842+ 'mwe-sequenceedit-rmclip' => 'ചലച്ചിത്രശകലം നീക്കംചെയ്യുക',
 843+ 'mwe-sequenceedit-clip_in' => 'ചലച്ചിത്രശകലം ഉൾപ്പെടുത്തുക',
 844+ 'mwe-sequenceedit-clip_out' => 'ചലച്ചിത്രശകലം പുറംതള്ളുക',
 845+ 'mwe-sequenceedit-no_selected_resource' => '<h3>ഒരു സ്രോതസ്സും തിരഞ്ഞെടുത്തിട്ടില്ല</h3> മാറ്റംവരുത്തുവാൻ ഒരു ചലച്ചിത്രശകലം തിരഞ്ഞെടുക്കുക.',
 846+ 'mwe-sequenceedit-error_edit_multiple' => '<h3>നിരവധി സ്രോതസ്സുകൾ തിരഞ്ഞെടുത്തിരിക്കുന്നു</h3> മാറ്റംവരുത്തുവാനായി ഒരു ചലച്ചിത്രശകലം തിരഞ്ഞെടുക്കുക.',
 847+ 'mwe-sequenceedit-editor_options' => 'തിരുത്തലുപകരണ ഐച്ഛികങ്ങൾ',
 848+ 'mwe-sequenceedit-editor_mode' => 'തിരുത്തലുപകരണ സമ്പ്രദായം',
 849+ 'mwe-sequenceedit-simple_editor_desc' => 'ലളിതമായ തിരുത്തലുപകരണം (iMovie രീതി)',
 850+ 'mwe-sequenceedit-advanced_editor_desc' => 'വിപുലമായ തിരുത്തലുപകരണം (ഫൈനൽ കട്ട് രീതി)',
 851+ 'mwe-sequenceedit-other_options' => 'മറ്റ് ഐച്ഛികങ്ങൾ',
 852+ 'mwe-sequenceedit-sequencer_credit_line' => '<a href="http://kaltura.com">Kaltura, Inc.</a>, <a href="http://wikimediafoundation.org/wiki/Home">വിക്കിമീഡിയ ഫൗണ്ടേഷന്റെ</a> പങ്കാളിത്തത്തോടു കൂടി വികസിപ്പിച്ചെടുത്തത് (<a href="#">കൂടുതൽ വിവരങ്ങൾ</a>).',
 853+);
 854+$messages['nl'] = array(
 855+ 'mwe-sequenceedit-transition_in' => 'Overgangen',
 856+ 'mwe-sequenceedit-transition_out' => 'Overgang einde',
 857+ 'mwe-sequenceedit-effects' => 'Effecten',
 858+ 'mwe-sequenceedit-remove_transition' => 'Overgang verwijderen',
 859+ 'mwe-sequenceedit-edit_transin' => 'Overgang in clip bewerken',
 860+ 'mwe-sequenceedit-edit_transout' => 'Overgang uit clip verwijderen',
 861+ 'mwe-sequenceedit-add-transition' => 'Overgang toevoegen',
 862+ 'mwe-sequenceedit-menu_clipedit' => 'Media bewerken',
 863+ 'mwe-sequenceedit-menu_transition' => 'Overgangseffecten',
 864+ 'mwe-sequenceedit-menu_cliplib' => 'Media toevoegen',
 865+ 'mwe-sequenceedit-menu_resource_overview' => 'Bronnenoverzicht',
 866+ 'mwe-sequenceedit-menu_options' => 'Instellingen',
 867+ 'mwe-sequenceedit-loading_timeline' => 'Bezig met het laden van de tijdlijn ...',
 868+ 'mwe-sequenceedit-loading_user_rights' => 'Bezig met laden van gebruikersrechten ...',
 869+ 'mwe-sequenceedit-no_edit_permissions' => 'U hebt geen rechten om wijzigingen aan deze reeks op te slaan',
 870+ 'mwe-sequenceedit-edit_clip' => 'Clip bewerken',
 871+ 'mwe-sequenceedit-edit_save' => 'Wijzigingen aan de reeks opslaan',
 872+ 'mwe-sequenceedit-saving_wait' => 'Bezig met opslaan. Even geduld, alstublieft.',
 873+ 'mwe-sequenceedit-save_done' => 'Opslaan voltooid.',
 874+ 'mwe-sequenceedit-edit_cancel' => 'Bewerken van de reeks annuleren',
 875+ 'mwe-sequenceedit-edit_cancel_confirm' => 'Weet u zeker dat u uw bewerking wilt afbreken? Alle wijzigingen worden ongedaan gemaakt.',
 876+ 'mwe-sequenceedit-zoom_in' => 'Vergroten',
 877+ 'mwe-sequenceedit-zoom_out' => 'Verkleinen',
 878+ 'mwe-sequenceedit-cut_clip' => 'Clips uitsnijden',
 879+ 'mwe-sequenceedit-expand_track' => 'Spoor uitklappen',
 880+ 'mwe-sequenceedit-collapse_track' => 'Spoor inklappen',
 881+ 'mwe-sequenceedit-play_from_position' => 'Afspelen vanaf positie',
 882+ 'mwe-sequenceedit-pixle2sec' => 'pixels naar seconden',
 883+ 'mwe-sequenceedit-rmclip' => 'Clip verwijderen',
 884+ 'mwe-sequenceedit-clip_in' => 'clip toevoegen',
 885+ 'mwe-sequenceedit-clip_out' => 'clip verwijderen',
 886+ 'mwe-sequenceedit-no_selected_resource' => '<h3>Er is geen bestand geselecteerd</h3>
 887+Selecteer een te bewerken clip.',
 888+ 'mwe-sequenceedit-error_edit_multiple' => '<h3>Er zijn meerdere bestanden geselecteerd</h3>
 889+Selecteer één te bewerken clip.',
 890+ 'mwe-sequenceedit-editor_options' => 'Editorinstellingen',
 891+ 'mwe-sequenceedit-editor_mode' => 'Bewerkingsmodus',
 892+ 'mwe-sequenceedit-simple_editor_desc' => 'eenvoudige editor (iMovie-stijl)',
 893+ 'mwe-sequenceedit-advanced_editor_desc' => 'uitgebreide editor (Final Cut-stijl)',
 894+ 'mwe-sequenceedit-other_options' => 'Ander opsies',
 895+ 'mwe-sequenceedit-contextmenu_opt' => 'Contextafhankelijke menu\'s inschakelen',
 896+ 'mwe-sequenceedit-sequencer_credit_line' => 'Ontwikkeld door <a href="http://kaltura.com">Kaltura, Inc.</a> in samenwerking met de <a href="http://wikimediafoundation.org/wiki/Home">Wikimedia Foundation</a> (<a href="#">meer informatie</a>).',
 897+);
 898+$messages['oc'] = array(
 899+ 'mwe-sequenceedit-transition_in' => 'Transicion entranta',
 900+ 'mwe-sequenceedit-transition_out' => 'Transicion sortenta',
 901+ 'mwe-sequenceedit-effects' => 'Pila d\'efièches',
 902+ 'mwe-sequenceedit-remove_transition' => 'Suprimir la transicion',
 903+ 'mwe-sequenceedit-edit_transin' => 'Modificar la transicion cap al clip',
 904+ 'mwe-sequenceedit-edit_transout' => 'Modificar la transicion en defòta del clip',
 905+ 'mwe-sequenceedit-menu_clipedit' => 'Modificar lo mèdia',
 906+ 'mwe-sequenceedit-menu_transition' => 'Transicions e efièches',
 907+ 'mwe-sequenceedit-menu_cliplib' => 'Apondre un mèdia',
 908+ 'mwe-sequenceedit-menu_resource_overview' => 'Vista d\'ensemble de la ressorsa',
 909+ 'mwe-sequenceedit-menu_options' => 'Opcions',
 910+ 'mwe-sequenceedit-loading_timeline' => 'Cargament de la cronologia ...',
 911+ 'mwe-sequenceedit-loading_user_rights' => 'Cargament dels dreches d\'utilizaire ...',
 912+ 'mwe-sequenceedit-no_edit_permissions' => 'Avètz pas l\'autorizacion de salvar los cambiaments aportats a aquesta sequéncia',
 913+ 'mwe-sequenceedit-edit_clip' => 'Modificar lo clip',
 914+ 'mwe-sequenceedit-edit_save' => 'Salvar las modificacions de la sequéncia',
 915+ 'mwe-sequenceedit-saving_wait' => 'Salvament en cors (pacientatz)',
 916+ 'mwe-sequenceedit-save_done' => 'Salvament acabat',
 917+ 'mwe-sequenceedit-edit_cancel' => 'Anullar la modificacion de la sequéncia',
 918+ 'mwe-sequenceedit-edit_cancel_confirm' => 'Sètz segur que volètz anullar vòstra modificacion ? Los cambiaments seràn perduts.',
 919+ 'mwe-sequenceedit-zoom_in' => 'Agrandir',
 920+ 'mwe-sequenceedit-zoom_out' => 'Reduire',
 921+ 'mwe-sequenceedit-cut_clip' => 'Copar los clips',
 922+ 'mwe-sequenceedit-expand_track' => 'Espandir la pista',
 923+ 'mwe-sequenceedit-collapse_track' => 'Reduire la pista',
 924+ 'mwe-sequenceedit-play_from_position' => 'Legir a partir de la posicion de lectura',
 925+ 'mwe-sequenceedit-pixle2sec' => 'pixèls cap a segondas',
 926+ 'mwe-sequenceedit-rmclip' => 'Suprimir lo clip',
 927+ 'mwe-sequenceedit-clip_in' => 'estacar',
 928+ 'mwe-sequenceedit-clip_out' => 'destacar',
 929+ 'mwe-sequenceedit-no_selected_resource' => '<h3>Cap de ressorsa pas seleccionada</h3> Seleccionatz un clip per activar l\'edicion',
 930+ 'mwe-sequenceedit-error_edit_multiple' => '<h3>Mantuna ressorsa seleccionada</h3> Seleccionatz un sol clip per lo modificar',
 931+ 'mwe-sequenceedit-editor_options' => 'Opcions de l\'editor',
 932+ 'mwe-sequenceedit-editor_mode' => 'Mòde de l\'editor',
 933+ 'mwe-sequenceedit-simple_editor_desc' => 'editor simple (estil iMovie)',
 934+ 'mwe-sequenceedit-advanced_editor_desc' => 'editor avançat (estil Final Cut)',
 935+ 'mwe-sequenceedit-other_options' => 'Autras opcions',
 936+ 'mwe-sequenceedit-contextmenu_opt' => 'Activar los menuts contextuals',
 937+ 'mwe-sequenceedit-sequencer_credit_line' => 'Desvolopat per <a href="http://kaltura.com">Kaltura, Inc.</a> en partenariat amb la <a href="http://wikimediafoundation.org/wiki/Home">Wikimedia Foundation</a> (<a href="#">mai d\'entresenhas</a>).',
 938+);
 939+$messages['pl'] = array(
 940+ 'mwe-sequenceedit-transition_in' => 'Wejście',
 941+ 'mwe-sequenceedit-transition_out' => 'Wyjście',
 942+ 'mwe-sequenceedit-effects' => 'Stos efektów',
 943+ 'mwe-sequenceedit-remove_transition' => 'Usuń przejście',
 944+ 'mwe-sequenceedit-edit_transin' => 'Edytuj przejście do klipu',
 945+ 'mwe-sequenceedit-edit_transout' => 'Edytuj przejście zakończenia klipu',
 946+ 'mwe-sequenceedit-menu_clipedit' => 'Edytuj multimeda',
 947+ 'mwe-sequenceedit-menu_transition' => 'Przejścia i efekty',
 948+ 'mwe-sequenceedit-menu_cliplib' => 'Dodaj media',
 949+ 'mwe-sequenceedit-menu_resource_overview' => 'Przegląd zasobów',
 950+ 'mwe-sequenceedit-menu_options' => 'Opcje',
 951+ 'mwe-sequenceedit-loading_timeline' => 'Ładowanie osi czasu ...',
 952+ 'mwe-sequenceedit-loading_user_rights' => 'Ładowanie praw użytkowników ...',
 953+ 'mwe-sequenceedit-no_edit_permissions' => 'Nie masz uprawnień, aby zapisać zmiany w tej kolejności',
 954+ 'mwe-sequenceedit-edit_clip' => 'Edytuj klip',
 955+ 'mwe-sequenceedit-edit_save' => 'Zapisz sekwencję zmian',
 956+ 'mwe-sequenceedit-saving_wait' => 'Zapisywanie trwa (proszę czekać)',
 957+ 'mwe-sequenceedit-save_done' => 'Zapisano',
 958+ 'mwe-sequenceedit-edit_cancel' => 'Anuluj sekwencję zmian',
 959+ 'mwe-sequenceedit-edit_cancel_confirm' => 'Czy na pewno chcesz anulować edycję? Zmiany zostaną utracone.',
 960+ 'mwe-sequenceedit-zoom_in' => 'Powiększ',
 961+ 'mwe-sequenceedit-zoom_out' => 'Pomniejsz',
 962+ 'mwe-sequenceedit-cut_clip' => 'Przytnij klipy',
 963+ 'mwe-sequenceedit-rmclip' => 'Usuń klip',
 964+ 'mwe-sequenceedit-clip_in' => 'początek klipu',
 965+ 'mwe-sequenceedit-clip_out' => 'koniec klipu',
 966+ 'mwe-sequenceedit-no_selected_resource' => '<h3>Nie wybrano zasobu</h3> Wybierz klip, jeśli chcesz edytować.',
 967+ 'mwe-sequenceedit-error_edit_multiple' => '<h3>Wybrano wiele zasobów</h3> Wybierz jeden klip, jeśli chcesz edytować.',
 968+ 'mwe-sequenceedit-editor_options' => 'Opcje edytora',
 969+ 'mwe-sequenceedit-editor_mode' => 'Tryb pracy edytora',
 970+ 'mwe-sequenceedit-simple_editor_desc' => 'prosty edytor tekstu (w stylu iMovie)',
 971+ 'mwe-sequenceedit-advanced_editor_desc' => 'zaawansowany edytor (w stylu Final Cut)',
 972+ 'mwe-sequenceedit-other_options' => 'Inne opcje',
 973+ 'mwe-sequenceedit-contextmenu_opt' => 'Włącz menu kontekstowe',
 974+ 'mwe-sequenceedit-sequencer_credit_line' => 'Wykonane przez <a href="http://kaltura.com">Kaltura, Inc,</a> we współpracy z <a href="http://wikimediafoundation.org/wiki/Home">Fundacją Wikimedia</a> (<a href="#">więcej informacji</a>).',
 975+);
 976+$messages['pt'] = array(
 977+ 'mwe-sequenceedit-transition_in' => 'Entrada da transição',
 978+ 'mwe-sequenceedit-transition_out' => 'Saída da transição',
 979+ 'mwe-sequenceedit-effects' => 'Pilha de efeitos',
 980+ 'mwe-sequenceedit-remove_transition' => 'Remover transição',
 981+ 'mwe-sequenceedit-edit_transin' => 'Inserir transição no clipe',
 982+ 'mwe-sequenceedit-edit_transout' => 'Remover transição do clipe',
 983+ 'mwe-sequenceedit-add-transition' => 'Adicionar uma transição',
 984+ 'mwe-sequenceedit-menu_clipedit' => 'Editar multimédia',
 985+ 'mwe-sequenceedit-menu_transition' => 'Transições e efeitos',
 986+ 'mwe-sequenceedit-menu_cliplib' => 'Adicionar multimédia',
 987+ 'mwe-sequenceedit-menu_resource_overview' => 'Visão geral dos recursos',
 988+ 'mwe-sequenceedit-menu_options' => 'Opções',
 989+ 'mwe-sequenceedit-loading_timeline' => 'A carregar linha do tempo ...',
 990+ 'mwe-sequenceedit-loading_user_rights' => 'A carregar os direitos do utilizador ...',
 991+ 'mwe-sequenceedit-no_edit_permissions' => 'Não tem permissões para gravar alterações a esta sequência',
 992+ 'mwe-sequenceedit-edit_clip' => 'Editar clipe',
 993+ 'mwe-sequenceedit-edit_save' => 'Gravar mudanças na sequência',
 994+ 'mwe-sequenceedit-saving_wait' => 'Gravação em progresso (por favor, aguarde)',
 995+ 'mwe-sequenceedit-save_done' => 'Gravação completa',
 996+ 'mwe-sequenceedit-edit_cancel' => 'Cancelar edição da sequência',
 997+ 'mwe-sequenceedit-edit_cancel_confirm' => 'Tem a certeza de que quer cancelar a edição? As alterações serão perdidas.',
 998+ 'mwe-sequenceedit-zoom_in' => 'Aproximar',
 999+ 'mwe-sequenceedit-zoom_out' => 'Afastar',
 1000+ 'mwe-sequenceedit-cut_clip' => 'Cortar clipes',
 1001+ 'mwe-sequenceedit-expand_track' => 'Expandir faixa',
 1002+ 'mwe-sequenceedit-collapse_track' => 'Colapsar faixa',
 1003+ 'mwe-sequenceedit-play_from_position' => 'Começar a partir da posicão na linha',
 1004+ 'mwe-sequenceedit-pixle2sec' => 'pixels para segundos',
 1005+ 'mwe-sequenceedit-rmclip' => 'Remover clipe',
 1006+ 'mwe-sequenceedit-clip_in' => 'entrada do clipe',
 1007+ 'mwe-sequenceedit-clip_out' => 'saída do clipe',
 1008+ 'mwe-sequenceedit-no_selected_resource' => '<h3>Nenhum recurso seleccionado</h3> Seleccione um clip para possibilitar edição.',
 1009+ 'mwe-sequenceedit-error_edit_multiple' => '<h3>Vários recursos seleccionados</h3> Seleccione um único clipe para editá-lo.',
 1010+ 'mwe-sequenceedit-editor_options' => 'Opções do editor',
 1011+ 'mwe-sequenceedit-editor_mode' => 'Modo editor',
 1012+ 'mwe-sequenceedit-simple_editor_desc' => 'editor simples (estilo iMovie)',
 1013+ 'mwe-sequenceedit-advanced_editor_desc' => 'editor avançado (estilo Final Cut)',
 1014+ 'mwe-sequenceedit-other_options' => 'Outras opções',
 1015+ 'mwe-sequenceedit-contextmenu_opt' => 'Possibilitar menus de contexto',
 1016+ 'mwe-sequenceedit-sequencer_credit_line' => 'Desenvolvido por <a href="http://kaltura.com">Kaltura, Inc.</a> em parceria com a <a href="http://wikimediafoundation.org/wiki/Home">Wikimedia Foundation</a> (<a href="#">mais informações</a>).',
 1017+);
 1018+$messages['pt-br'] = array(
 1019+ 'mwe-sequenceedit-menu_options' => 'Opções',
 1020+ 'mwe-sequenceedit-loading_user_rights' => 'A carregar direitos de usuário ...',
 1021+ 'mwe-sequenceedit-other_options' => 'Outras opções',
 1022+ 'mwe-sequenceedit-contextmenu_opt' => 'Habilitar menus de contexto',
 1023+);
 1024+$messages['ru'] = array(
 1025+ 'mwe-sequenceedit-transition_in' => 'Переход в',
 1026+ 'mwe-sequenceedit-transition_out' => 'Переход из',
 1027+ 'mwe-sequenceedit-effects' => 'Набор эффектов',
 1028+ 'mwe-sequenceedit-remove_transition' => 'Удалить переход',
 1029+ 'mwe-sequenceedit-edit_transin' => 'Изменить переход в клипе',
 1030+ 'mwe-sequenceedit-edit_transout' => 'Изменить переход-выход в клипе',
 1031+ 'mwe-sequenceedit-add-transition' => 'Добавить переход',
 1032+ 'mwe-sequenceedit-menu_clipedit' => 'Изменить медиа',
 1033+ 'mwe-sequenceedit-menu_transition' => 'Переходы и эффекты',
 1034+ 'mwe-sequenceedit-menu_cliplib' => 'Добавить медиа',
 1035+ 'mwe-sequenceedit-menu_resource_overview' => 'Обзор ресурсов',
 1036+ 'mwe-sequenceedit-menu_options' => 'Настройки',
 1037+ 'mwe-sequenceedit-loading_timeline' => 'Загружается хронология …',
 1038+ 'mwe-sequenceedit-loading_user_rights' => 'Загружаются права участников …',
 1039+ 'mwe-sequenceedit-no_edit_permissions' => 'У вас нет разрешения сохранять изменения последовательности',
 1040+ 'mwe-sequenceedit-edit_clip' => 'Редактировать клип',
 1041+ 'mwe-sequenceedit-edit_save' => 'Сохранить изменения последовательности',
 1042+ 'mwe-sequenceedit-saving_wait' => 'Идёт сохранение (пожалуйста, подождите)',
 1043+ 'mwe-sequenceedit-save_done' => 'Сохранение завершено',
 1044+ 'mwe-sequenceedit-edit_cancel' => 'Отменить правку последовательности',
 1045+ 'mwe-sequenceedit-edit_cancel_confirm' => 'Вы уверены, что хотите отменить Вашу правку? Изменения будут потеряны.',
 1046+ 'mwe-sequenceedit-zoom_in' => 'Увеличить',
 1047+ 'mwe-sequenceedit-zoom_out' => 'Уменьшить',
 1048+ 'mwe-sequenceedit-cut_clip' => 'Кадрирование клипов',
 1049+ 'mwe-sequenceedit-expand_track' => 'Развернуть трек',
 1050+ 'mwe-sequenceedit-collapse_track' => 'Свернуть трек',
 1051+ 'mwe-sequenceedit-play_from_position' => 'Проигрывать с позиции линии воспроизведения',
 1052+ 'mwe-sequenceedit-pixle2sec' => 'пикселов в секунду',
 1053+ 'mwe-sequenceedit-rmclip' => 'Удалить клип',
 1054+ 'mwe-sequenceedit-clip_in' => 'добавить клип',
 1055+ 'mwe-sequenceedit-clip_out' => 'убрать клип',
 1056+ 'mwe-sequenceedit-no_selected_resource' => '<h3>Не выбран ресурс</h3>Выберите клип для редактирования.',
 1057+ 'mwe-sequenceedit-error_edit_multiple' => '<h3>Выбрано несколько ресурсов</h3> Выберите один клип для редактирования.',
 1058+ 'mwe-sequenceedit-editor_options' => 'Настройки редактора',
 1059+ 'mwe-sequenceedit-editor_mode' => 'Режим редактора',
 1060+ 'mwe-sequenceedit-simple_editor_desc' => 'простой редактор (стиль iMovie)',
 1061+ 'mwe-sequenceedit-advanced_editor_desc' => 'улучшенный редактор (стиль Final Cut)',
 1062+ 'mwe-sequenceedit-other_options' => 'Другие настройки',
 1063+ 'mwe-sequenceedit-contextmenu_opt' => 'Включить контекстные меню',
 1064+ 'mwe-sequenceedit-sequencer_credit_line' => 'Разработано <a href="http://kaltura.com">Kaltura, Inc</a> в сотрудничестве с <a href="http://wikimediafoundation.org/wiki/Home">Фондом Викимедиа</a> (<a href="#">подробнее</a>).',
 1065+);
 1066+$messages['sah'] = array(
 1067+ 'mwe-sequenceedit-menu_options' => 'Туруоруулар',
 1068+ 'mwe-sequenceedit-edit_clip' => 'Клибы уларытыы',
 1069+ 'mwe-sequenceedit-zoom_in' => 'Улаатыннар',
 1070+ 'mwe-sequenceedit-zoom_out' => 'Кыччат',
 1071+);
 1072+$messages['sk'] = array(
 1073+ 'mwe-sequenceedit-transition_in' => 'Prechod do',
 1074+ 'mwe-sequenceedit-transition_out' => 'Prechod z',
 1075+ 'mwe-sequenceedit-effects' => 'Zásobník efektov',
 1076+ 'mwe-sequenceedit-remove_transition' => 'Odstrániť prechod',
 1077+ 'mwe-sequenceedit-edit_transin' => 'Upraviť prechod do klipu',
 1078+ 'mwe-sequenceedit-edit_transout' => 'Upraviť prechod z klipu',
 1079+ 'mwe-sequenceedit-menu_clipedit' => 'Upraviť multimédiá',
 1080+ 'mwe-sequenceedit-menu_transition' => 'Prechody a efekty',
 1081+ 'mwe-sequenceedit-menu_cliplib' => 'Pridať multimédiá',
 1082+ 'mwe-sequenceedit-menu_resource_overview' => 'Prehľad zdroja',
 1083+ 'mwe-sequenceedit-menu_options' => 'Možnosti',
 1084+ 'mwe-sequenceedit-loading_timeline' => 'Načítava sa časová os ...',
 1085+ 'mwe-sequenceedit-loading_user_rights' => 'Načítavajú sa oprávnenia používateľov ...',
 1086+ 'mwe-sequenceedit-no_edit_permissions' => 'Nemáte oprávnenie ukladať zmenu tejto sekvencie',
 1087+ 'mwe-sequenceedit-edit_clip' => 'Upraviť klip',
 1088+ 'mwe-sequenceedit-edit_save' => 'Uložiť zmeny sekvencie',
 1089+ 'mwe-sequenceedit-saving_wait' => 'Prebieha ukladanie (prosím, čakajte)',
 1090+ 'mwe-sequenceedit-save_done' => 'Ukladanie dokončené',
 1091+ 'mwe-sequenceedit-edit_cancel' => 'Zrušiť úpravu sekvencie',
 1092+ 'mwe-sequenceedit-edit_cancel_confirm' => 'Ste si istý, že chcete zrušiť svoje úpravy? Zmeny sa stratia.',
 1093+ 'mwe-sequenceedit-zoom_in' => 'Priblížiť',
 1094+ 'mwe-sequenceedit-zoom_out' => 'Oddialiť',
 1095+ 'mwe-sequenceedit-cut_clip' => 'Strih klipov',
 1096+ 'mwe-sequenceedit-expand_track' => 'Rozšíriť stopu',
 1097+ 'mwe-sequenceedit-collapse_track' => 'Zmrštiť stopu',
 1098+ 'mwe-sequenceedit-play_from_position' => 'Prehrať od značky',
 1099+ 'mwe-sequenceedit-pixle2sec' => 'pixle na sekundy',
 1100+ 'mwe-sequenceedit-rmclip' => 'Odstrániť klip',
 1101+ 'mwe-sequenceedit-no_selected_resource' => '<h3>Nebol vybraný žiadny zdroj</h3> Úpravu začnete vybraním klipu.',
 1102+ 'mwe-sequenceedit-error_edit_multiple' => '<h3>Boli vybrané viaceré zdroje</h3> Úpravu začnete vybraním jediného klipu.',
 1103+ 'mwe-sequenceedit-editor_options' => 'Možnosti editora',
 1104+ 'mwe-sequenceedit-editor_mode' => 'Režim editora',
 1105+ 'mwe-sequenceedit-simple_editor_desc' => 'jednoduchý editor (v štýle iMovie)',
 1106+ 'mwe-sequenceedit-advanced_editor_desc' => 'pokročilý editor (v štýle Final Cut)',
 1107+ 'mwe-sequenceedit-other_options' => 'Ďalšie možnosti',
 1108+ 'mwe-sequenceedit-contextmenu_opt' => 'Zapnúť kontextové menu',
 1109+ 'mwe-sequenceedit-sequencer_credit_line' => 'Vyvinula <a href="http://kaltura.com">Kaltura, Inc.</a> v spolupráci s <a href="http://wikimediafoundation.org/wiki/Home">Wikimedia Foundation</a> (<a href="#">ďalšie informácie</a>).',
 1110+);
 1111+$messages['sv'] = array(
 1112+ 'mwe-sequenceedit-menu_clipedit' => 'Redigera media',
 1113+ 'mwe-sequenceedit-menu_cliplib' => 'Lägg till media',
 1114+ 'mwe-sequenceedit-menu_options' => 'Alternativ',
 1115+ 'mwe-sequenceedit-loading_timeline' => 'Laddar tidslinje...',
 1116+ 'mwe-sequenceedit-loading_user_rights' => 'Laddar användarrättigheter...',
 1117+ 'mwe-sequenceedit-zoom_in' => 'Zooma in',
 1118+ 'mwe-sequenceedit-zoom_out' => 'Zooma ut',
 1119+ 'mwe-sequenceedit-pixle2sec' => 'Pixlar till sekunder',
 1120+ 'mwe-sequenceedit-other_options' => 'Andra alternativ',
 1121+);
 1122+$messages['te'] = array(
 1123+ 'mwe-sequenceedit-menu_options' => 'ఎంపికలు',
 1124+ 'mwe-sequenceedit-saving_wait' => 'భద్రపరడం జరుగుతూంది (దయచేసి వేచివుండండి)',
 1125+ 'mwe-sequenceedit-save_done' => 'భద్రపరచడం పూర్తయ్యింది',
 1126+ 'mwe-sequenceedit-edit_cancel_confirm' => 'మీరు నిజంగానే మీ మార్పుని రద్దుచేయాలనుకుంటున్నారా? మార్పులు పోతాయి.',
 1127+ 'mwe-sequenceedit-editor_options' => 'కూర్పరి ఎంపికలు',
 1128+ 'mwe-sequenceedit-other_options' => 'ఇతర ఎంపికలు',
 1129+);
 1130+$messages['tr'] = array(
 1131+ 'mwe-sequenceedit-transition_in' => 'İçe geçiş',
 1132+ 'mwe-sequenceedit-transition_out' => 'Dışa geçiş',
 1133+ 'mwe-sequenceedit-effects' => 'Efekt yığını',
 1134+ 'mwe-sequenceedit-remove_transition' => 'Geçişi kaldır',
 1135+ 'mwe-sequenceedit-edit_transin' => 'Klibe geçişi değiştir',
 1136+ 'mwe-sequenceedit-edit_transout' => 'Klipten geçişi değiştir',
 1137+ 'mwe-sequenceedit-add-transition' => 'Geçiş ekle',
 1138+ 'mwe-sequenceedit-menu_clipedit' => 'Ortamı değiştir',
 1139+ 'mwe-sequenceedit-menu_transition' => 'Geçişler ve efektler',
 1140+ 'mwe-sequenceedit-menu_cliplib' => 'Ortam ekle',
 1141+ 'mwe-sequenceedit-menu_resource_overview' => 'Kaynak genel bakışı',
 1142+ 'mwe-sequenceedit-menu_options' => 'Seçenekler',
 1143+ 'mwe-sequenceedit-loading_timeline' => 'Zaman çizelgesi yükleniyor ...',
 1144+ 'mwe-sequenceedit-loading_user_rights' => 'Kullanıcı hakları yükleniyor ...',
 1145+ 'mwe-sequenceedit-no_edit_permissions' => 'Bu dizilişe değişiklikleri kaydetme izniniz yok',
 1146+ 'mwe-sequenceedit-edit_clip' => 'Klibi değiştir',
 1147+ 'mwe-sequenceedit-edit_save' => 'Diziliş değişikliklerini kaydet',
 1148+ 'mwe-sequenceedit-saving_wait' => 'Kaydetme sürüyor (lütfen bekleyin)',
 1149+ 'mwe-sequenceedit-save_done' => 'Kaydetme tamamlandı',
 1150+ 'mwe-sequenceedit-edit_cancel' => 'Diziliş değişikliğini iptal et',
 1151+ 'mwe-sequenceedit-edit_cancel_confirm' => 'Değişikliğinizi iptal etmek istediğinize emin misiniz? Değişiklikler kaybolacaktır.',
 1152+ 'mwe-sequenceedit-zoom_in' => 'Yakınlaştır',
 1153+ 'mwe-sequenceedit-zoom_out' => 'Uzaklaştır',
 1154+ 'mwe-sequenceedit-cut_clip' => 'Klipleri kes',
 1155+ 'mwe-sequenceedit-expand_track' => 'İzi genişlet',
 1156+ 'mwe-sequenceedit-collapse_track' => 'İzi daralt',
 1157+ 'mwe-sequenceedit-play_from_position' => 'Oynatma çizgisi konumundan oynat',
 1158+ 'mwe-sequenceedit-pixle2sec' => 'piksele saniye',
 1159+ 'mwe-sequenceedit-rmclip' => 'Klibi kaldır',
 1160+ 'mwe-sequenceedit-clip_in' => 'içe klip',
 1161+ 'mwe-sequenceedit-clip_out' => 'dışa klip',
 1162+ 'mwe-sequenceedit-no_selected_resource' => '<h3>Hiç kaynak seçilmedi</h3> Değiştirmeyi etkinleştirmek için bir klip seçin.',
 1163+ 'mwe-sequenceedit-error_edit_multiple' => '<h3>Birden fazla kaynak seçildi</h3> Değiştirmek için tek klip seçin.',
 1164+ 'mwe-sequenceedit-editor_options' => 'Düzenleyici seçenekleri',
 1165+ 'mwe-sequenceedit-editor_mode' => 'Düzenleyici kipi',
 1166+ 'mwe-sequenceedit-simple_editor_desc' => 'basit düzenleyici (iMovie tarzı)',
 1167+ 'mwe-sequenceedit-advanced_editor_desc' => 'gelişmiş düzenleyici (Final Cut tarzı)',
 1168+ 'mwe-sequenceedit-other_options' => 'Diğer seçenekler',
 1169+ 'mwe-sequenceedit-contextmenu_opt' => 'İçerik menülerini etkinleştir',
 1170+ 'mwe-sequenceedit-sequencer_credit_line' => '<a href="http://kaltura.com">Kaltura, Inc.</a> tarafından, <a href="http://wikimediafoundation.org/wiki/Home">Wikimedia Foundation</a> (<a href="#">daha fazla bilgi</a>) ortaklığında geliştirilmiştir.',
 1171+);
 1172+$messages['vec'] = array(
 1173+ 'mwe-sequenceedit-menu_options' => 'Opzioni',
 1174+ 'mwe-sequenceedit-saving_wait' => 'So\' drio salvar (speta n\'atimo, par piaser)',
 1175+ 'mwe-sequenceedit-save_done' => 'Salvatajo conpleto',
 1176+ 'mwe-sequenceedit-zoom_in' => 'Strenzi zoom',
 1177+ 'mwe-sequenceedit-zoom_out' => 'Slarga zoom',
 1178+);
 1179+$messages['vep'] = array(
 1180+ 'mwe-sequenceedit-menu_cliplib' => 'Ližata medijad',
 1181+ 'mwe-sequenceedit-rmclip' => 'Heitta klip poiš',
 1182+);
 1183+$messages['vi'] = array(
 1184+ 'mwe-sequenceedit-transition_in' => 'Chuyển tiếp vào',
 1185+ 'mwe-sequenceedit-transition_out' => 'Chuyển tiếp ra',
 1186+ 'mwe-sequenceedit-effects' => 'Đống hiệu ứng',
 1187+ 'mwe-sequenceedit-remove_transition' => 'Xóa chuyển tiếp',
 1188+ 'mwe-sequenceedit-edit_transin' => 'Sửa chuyển tiếp vào clip',
 1189+ 'mwe-sequenceedit-edit_transout' => 'Sửa chuyển tiếp ra khỏi clip',
 1190+ 'mwe-sequenceedit-menu_clipedit' => 'Sửa tập tin nghe nhìn',
 1191+ 'mwe-sequenceedit-menu_transition' => 'Điểm chuyển và hiệu ứng',
 1192+ 'mwe-sequenceedit-menu_cliplib' => 'Thêm phương tiện',
 1193+ 'mwe-sequenceedit-menu_resource_overview' => 'Tổng quát tài nguyên',
 1194+ 'mwe-sequenceedit-menu_options' => 'Tùy chọn',
 1195+ 'mwe-sequenceedit-loading_timeline' => 'Đang tải dòng thời gian ...',
 1196+ 'mwe-sequenceedit-loading_user_rights' => 'Đang tải quyền thành viên ...',
 1197+ 'mwe-sequenceedit-no_edit_permissions' => 'Bạn không quyền lưu thay đổi vào cảnh này',
 1198+ 'mwe-sequenceedit-edit_clip' => 'Sửa clip',
 1199+ 'mwe-sequenceedit-edit_save' => 'Lưu thay đổi trong cảnh',
 1200+ 'mwe-sequenceedit-saving_wait' => 'Đang lưu (xin chờ)',
 1201+ 'mwe-sequenceedit-save_done' => 'Đã lưu',
 1202+ 'mwe-sequenceedit-edit_cancel' => 'Hủy sửa cảnh',
 1203+ 'mwe-sequenceedit-edit_cancel_confirm' => 'Bạn có chắc là mình muốn hủy sửa đổi không? Các thay đổi sẽ bị mất.',
 1204+ 'mwe-sequenceedit-zoom_in' => 'Phóng to',
 1205+ 'mwe-sequenceedit-zoom_out' => 'Thu nhỏ',
 1206+ 'mwe-sequenceedit-cut_clip' => 'Cắt clip',
 1207+ 'mwe-sequenceedit-expand_track' => 'Bung track',
 1208+ 'mwe-sequenceedit-collapse_track' => 'Thu nhỏ track',
 1209+ 'mwe-sequenceedit-play_from_position' => 'Chơi từ vị trí playline',
 1210+ 'mwe-sequenceedit-pixle2sec' => 'pixel sang giây',
 1211+ 'mwe-sequenceedit-rmclip' => 'Xóa clip',
 1212+ 'mwe-sequenceedit-no_selected_resource' => '<h3>Chưa chọn tài nguyên</h3> Hãy chọn clip để sửa đổi.',
 1213+ 'mwe-sequenceedit-error_edit_multiple' => '<h3>Đã chọn hơn một tài nguyên</h3> Hãy chỉ chọn một clip để sửa đổi nó.',
 1214+ 'mwe-sequenceedit-editor_options' => 'Tùy chọn sửa đổi',
 1215+ 'mwe-sequenceedit-editor_mode' => 'Chế độ sửa đổi',
 1216+ 'mwe-sequenceedit-simple_editor_desc' => 'bộ sửa đổi đơn giản (kiểu iMovie)',
 1217+ 'mwe-sequenceedit-advanced_editor_desc' => 'bộ sửa đổi nâng cấp (kiểu Final Cut)',
 1218+ 'mwe-sequenceedit-other_options' => 'Tùy chọn khác',
 1219+ 'mwe-sequenceedit-sequencer_credit_line' => 'Do <a href="http://kaltura.com">Kaltura, Inc.</a> phát triển với sự hỗ trợ của <a href="http://wikimediafoundation.org/wiki/Trang_chủ?uselang=vi">Quỹ Wikimedia</a> (<a href="#">chi tiết</a>).',
 1220+);
Index: branches/MwEmbedStandAlone/modules/SequenceEdit/mw.SequenceEditKeyBindings.js
@@ -0,0 +1,91 @@
 2+/**
 3+* Stores the key bindings
 4+*/
 5+
 6+mw.SequenceEditKeyBindings = function( sequenceEdit ) {
 7+ return this.init( sequenceEdit );
 8+};
 9+mw.SequenceEditKeyBindings.prototype = {
 10+ // set of key flags:
 11+ shiftDown: false,
 12+ ctrlDown: false,
 13+
 14+ init: function( sequenceEdit ){
 15+ this.sequenceEdit = sequenceEdit;
 16+ this.setupKeyBindigs()
 17+ },
 18+
 19+ bindEvent: function( eventType, callback){
 20+ if( typeof eventType == 'object' ){
 21+ for( var i in eventType ){
 22+ this.bindEvent( i, eventType[i] );
 23+ }
 24+ }
 25+ switch( eventType ){
 26+ case 'copy':
 27+ this.copyEvent = callback;
 28+ break;
 29+ case 'cut':
 30+ this.cutEvent = callback;
 31+ break;
 32+ case 'paste' :
 33+ this.pasteEvent = callback;
 34+ break;
 35+ case 'escape' :
 36+ this.escapeEvent = callback;
 37+ break;
 38+ case 'delete':
 39+ this.deleteEvent = callback;
 40+ break;
 41+ }
 42+ return this;
 43+ },
 44+ onInputFocus: function( ){
 45+ _this.inputFocus = true;
 46+ },
 47+ onInputBlur: function(){
 48+ _this.inputFocus = false;
 49+ },
 50+ setupKeyBindigs: function(){
 51+ var _this = this;
 52+ // Set up key bindings
 53+ $j( window ).keydown( function( e ) {
 54+ mw.log( 'SequenceEditKeyBindings::pushed down on:' + e.which );
 55+ if ( e.which == 16 )
 56+ _this.shiftDown = true;
 57+
 58+ if ( e.which == 17 )
 59+ _this.ctrlDown = true;
 60+
 61+ if ( ( e.which == 67 && _this.ctrlDown ) && !_this.inputFocus )
 62+ _this.copyEvent();
 63+
 64+ if ( ( e.which == 88 && _this.ctrlDown ) && !_this.inputFocus )
 65+ _this.cutEvent();
 66+
 67+ // Paste cips on v + ctrl while not focused on a text area:
 68+ if ( ( e.which == 86 && _this.ctrlDown ) && !_this.inputFocus )
 69+ _this.pasteEvent();
 70+
 71+ } );
 72+ $j( window ).keyup( function( e ) {
 73+ mw.log( 'SequenceEditKeyBindings::key up on ' + e.which );
 74+ // User let go of "shift" turn off multi-select
 75+ if ( e.which == 16 )
 76+ _this.shiftDown = false;
 77+
 78+ if ( e.which == 17 )
 79+ _this.ctrlDown = false;
 80+
 81+ // Escape key ( deselect )
 82+ if ( e.which == 27 )
 83+ _this.escapeEvent();
 84+
 85+
 86+ // Backspace or Delete key while not focused on a text area:
 87+ if ( ( e.which == 8 || e.which == 46 ) && !_this.inputFocus )
 88+ _this.deleteEvent();
 89+ } );
 90+ }
 91+
 92+}
\ No newline at end of file
Index: branches/MwEmbedStandAlone/modules/SequenceEdit/mw.SequenceEditTimeline.js
@@ -0,0 +1,347 @@
 2+
 3+//Wrap in mw closure to avoid global leakage
 4+( function( mw ) {
 5+
 6+mw.SequenceEditTimeline = function( sequenceEdit ) {
 7+ return this.init( sequenceEdit );
 8+};
 9+
 10+// Set up the mvSequencer object
 11+mw.SequenceEditTimeline.prototype = {
 12+ // Lazy init $timelineTracksContainer
 13+ $timelineTracksContainer : null,
 14+
 15+ // store a pointer to the track layout
 16+ trackLayout: null,
 17+
 18+ //Default height width of timeline clip:
 19+ timelineThumbSize: {
 20+ 'height': 90,
 21+ 'width' : 120
 22+ },
 23+
 24+ init: function( sequenceEdit ){
 25+ this.sequenceEdit = sequenceEdit;
 26+ },
 27+
 28+ getTimelineContainer: function(){
 29+ return this.sequenceEdit.getContainer().find('.mwseq-timeline');
 30+ },
 31+
 32+ getTracksContainer: function(){
 33+ if( ! this.$timelineTracksContainer ){
 34+ // getTimelineContainer
 35+ this.getTimelineContainer().append(
 36+ $j('<div />')
 37+ .addClass('timelineTrackContainer')
 38+ .append(
 39+ $j('<div />')
 40+ .addClass( 'ui-layout-west trackNamesContainer'),
 41+
 42+ $j('<div />')
 43+ .addClass( 'ui-layout-center trackClipsContainer')
 44+ )
 45+ )
 46+ // Apply layout control to track name / trackClips division
 47+ this.$timelineTracksContainer = this.getTimelineContainer().find( '.timelineTrackContainer');
 48+ this.trackLayout = this.$timelineTracksContainer
 49+ .layout( {
 50+ 'applyDefaultStyles': true,
 51+ 'west__size' : 150,
 52+ 'west__minSize' : 100,
 53+ 'west__maxSize' : 300
 54+ } );
 55+ }
 56+ return this.$timelineTracksContainer;
 57+ },
 58+ resizeTimeline: function(){
 59+ if( this.trackLayout ){
 60+ this.trackLayout.resizeAll();
 61+ }
 62+ },
 63+ //draw the timeline
 64+ drawTimeline: function(){
 65+ // Empty the timeline container
 66+ this.getTimelineContainer().empty();
 67+
 68+ // Get the top level sequence tracks
 69+ var seqTracks = this.sequenceEdit.getSmil().getBody().getSeqElements();
 70+ var trackType = 'video';
 71+ // for now just two tracks first is video second is audio
 72+ for( var trackIndex=0; trackIndex < seqTracks.length; trackIndex++){
 73+
 74+ if( trackType == 'audio' ){
 75+ mw.log("SequenceEditTimeline::Error only two tracks presently suppoted");
 76+ break;
 77+ }
 78+ // Draw the sequence track
 79+ this.drawSequenceTrack( trackIndex, seqTracks[ trackIndex ], trackType);
 80+ trackType = 'audio';
 81+ }
 82+ },
 83+
 84+ drawSequenceTrack: function( trackIndex, sequenceNode, trackType ){
 85+ mw.log(" drawSequenceTrack: Track inx: " + trackIndex + ' trackType:' + trackType );
 86+ // Check if we already have a container for this track set
 87+
 88+ // Add a sequence track Name
 89+ this.getTracksContainer().find('.trackNamesContainer').append(
 90+ this.getTrackNameInterface( trackIndex, sequenceNode, trackType )
 91+ )
 92+
 93+ // Add Sequence clips
 94+ this.getTracksContainer().find('.trackClipsContainer').append(
 95+ this.getTrackClipInterface( trackIndex ,sequenceNode , trackType )
 96+ )
 97+ // Load and display all clip thumbnails
 98+ },
 99+
 100+ /**
 101+ * Get Track Clip Interface
 102+ */
 103+ getTrackClipInterface: function( trackIndex, sequenceNode, trackType ){
 104+ var _this = this;
 105+ // setup a local pointer to the smil engine:
 106+ var smil = this.sequenceEdit.getSmil();
 107+ // Get all the refs that are children of the sequenceNode with associated offsets and durations
 108+ // for now assume all tracks start at zero:
 109+ var startOffset = 0;
 110+ var $trackClips =
 111+ $j('<div />')
 112+ .attr('id', this.sequenceEdit.getId() + '_trackClips_' + trackIndex )
 113+ .addClass('trackClips ui-corner-all');
 114+
 115+ smil.getBody().getRefElementsRecurse( sequenceNode, startOffset, function( $node ){
 116+ // Draw the node onto the timeline:
 117+
 118+ // xxx would be good to support both "storyboard" and "timeline" view modes.
 119+ // for now just "storyboard"
 120+
 121+ // add a clip float left box container
 122+ $trackClips.append(
 123+ $j('<div />')
 124+ .attr('id', _this.getTimelineClipId( $node ) )
 125+ .data('smilId', $node.attr('id'))
 126+ .addClass('timelineClip ui-corner-all')
 127+ .css( _this.timelineThumbSize )
 128+ .loadingSpinner()
 129+ .click(function(){
 130+ //Add clip to selection
 131+ _this.handleMultiSelect( this );
 132+ })
 133+ .draggable( {
 134+ axis:'x',
 135+ containment:'#' + _this.sequenceEdit.getId() + '_trackClips_' + trackIndex,
 136+ opacity:50,
 137+ //handle: ":not(.clip_control)",
 138+ scroll:true,
 139+ drag:function( e, ui ) {
 140+ // debugger;
 141+ //insert_key = _this.clipDragUpdate( ui, this );
 142+ },
 143+ start:function( e, ui ) {
 144+ mw.log( 'start drag:' + this.id );
 145+ // make sure we are ontop
 146+ $j( this ).css( { top:'0px', zindex:10 } );
 147+ },
 148+ stop:function( e, ui ) {
 149+ mw.log("stop drag");
 150+ $j( this ).css( { top:'0px', zindex:0 } );
 151+ // switch dom order
 152+ }
 153+ } )
 154+ )
 155+
 156+
 157+ // Check Buffer for when the first frame of the smilNode can be grabbed:
 158+ smil.getBuffer().canGrabRelativeTime( $node, 0, function(){
 159+ mw.log("getTrackClipInterface::canGrabRelativeTime for " + smil.getAssetId( $node ));
 160+ _this.drawClipThumb( $node , 0);
 161+ });
 162+ })
 163+
 164+ // Add global TrackClipInterface bindings:
 165+ var keyBindings = this.sequenceEdit.getKeyBindings();
 166+ keyBindings.bindEvent({
 167+ 'escape': function(){
 168+ _this.getTimelineContainer().find( '.selectedClip' ).removeClass( 'selectedClip' );
 169+ },
 170+ 'delete': function(){
 171+ _this.removeSelectedClips();
 172+ }
 173+ })
 174+ return $trackClips;
 175+ },
 176+
 177+ /**
 178+ * Remove selected clips and update the smil player
 179+ */
 180+ removeSelectedClips: function(){
 181+ var smil = this.sequenceEdit.getSmil();
 182+ // modify the smil.dom and rebuild
 183+ this.getTimelineContainer().find( '.selectedClip' ).each(function( inx, selectedClip ){
 184+ // Remove from smil dom:
 185+ smil.removeById( $j(selectedClip).data('smilId') );
 186+ // Remove from timeline dom:
 187+ $j( selectedClip ).remove();
 188+ })
 189+ // Invalidate embedPlayer duration
 190+ this.sequenceEdit.getEmbedPlayer().duration = null;
 191+ // Rebuild the smil duration:
 192+ smil.getDuration( true );
 193+ // Update the time display / stop playback if playing
 194+ this.sequenceEdit.getEmbedPlayer().stop();
 195+ },
 196+
 197+ /**
 198+ * Handle multiple selections based on what clips was just "cliked"
 199+ */
 200+ handleMultiSelect: function( clickClip ){
 201+ var keyBindings = this.sequenceEdit.getKeyBindings();
 202+ var $target = this.getTimelineContainer();
 203+ var smil = this.sequenceEdit.getSmil();
 204+ var embedPlayer = this.sequenceEdit.getEmbedPlayer();
 205+
 206+
 207+ // Add the selectedClip class to the clickClip
 208+ if( $j( clickClip ).hasClass( 'selectedClip') && $target.find( '.selectedClip' ).length == 1 ){
 209+ $j( clickClip ).removeClass( 'selectedClip' );
 210+ }else {
 211+ $j( clickClip ).addClass( 'selectedClip' );
 212+ }
 213+
 214+ // If not in multi select mode remove all existing selections except for clickClip
 215+ mw.log( ' HandleMultiSelect::' + keyBindings.shiftDown + ' ctrl_down:' + keyBindings.ctrlDown );
 216+
 217+ if ( ! keyBindings.shiftDown && ! keyBindings.ctrlDown ) {
 218+ $target.find( '.selectedClip' ).each( function( inx, selectedClip ) {
 219+ if( $j( clickClip ).attr('id') != $j( selectedClip ).attr('id') ){
 220+ $j( selectedClip ).removeClass('selectedClip');
 221+ }
 222+ } );
 223+ }
 224+ // Seek to the current clip time ( startOffset of current )
 225+ var seekTime = smil.$dom.find('#' + $j( clickClip ).data('smilId') ).data( 'startOffset' )
 226+ embedPlayer.setCurrentTime( seekTime, function(){
 227+ mw.log("handleMultiSelect::seek done")
 228+ });
 229+
 230+ // if shift select is down select the in-between clips
 231+ if( keyBindings.shiftDown ){
 232+ // get the min max of current selection (within the current track)
 233+ var max_order = 0;
 234+ var min_order = 999999999;
 235+ $target.find( '.timelineClip' ).each( function( inx, curClip) {
 236+ if( $j(curClip).hasClass('selectedClip') ){
 237+ // Set min max
 238+ if ( inx < min_order )
 239+ min_order = inx;
 240+ if ( inx > max_order )
 241+ max_order = inx;
 242+ }
 243+ } );
 244+ // select all non-selected between max or min
 245+ $target.find( '.timelineClip' ).each( function( inx, curClip) {
 246+ if( inx > min_order && inx < max_order ){
 247+ $j(curClip).addClass( 'selectedClip')
 248+ }
 249+ });
 250+ }
 251+ },
 252+
 253+ getTimelineClipId: function( $node ){
 254+ return this.sequenceEdit.getSmil().getAssetId( $node ) + '_timelineClip';
 255+ },
 256+
 257+ // Draw a clip thumb into the timeline clip target
 258+ drawClipThumb: function ( $node , relativeTime ){
 259+ var _this = this;
 260+ var smil = this.sequenceEdit.getSmil();
 261+ // Check the display type:
 262+ smil.getBuffer().canGrabRelativeTime( $node, relativeTime, function(){
 263+ mw.log("drawClipThumb:: canGrabRelativeTime:" + _this.getTimelineClipId( $node ));
 264+
 265+ var naturaSize = {};
 266+
 267+ var drawElement = $j( '#' + smil.getAssetId( $node ) ).get(0);
 268+
 269+ if( drawElement.nodeName.toLowerCase() == 'img' ){
 270+ naturaSize.height = drawElement.naturalHeight;
 271+ naturaSize.width = drawElement.naturalWidth;
 272+ } else if( drawElement.nodeName.toLowerCase() == 'video' ){
 273+ naturaSize.height = drawElement.videoHeight;
 274+ naturaSize.width = drawElement.videoWidth;
 275+ }
 276+
 277+ // Draw the thumb via canvas grab
 278+ // NOTE I attempted to scale down the image using canvas but failed
 279+ // xxx should revisit thumb size issue:
 280+ $j( '#' + _this.getTimelineClipId( $node ) ).html(
 281+ $j('<canvas />')
 282+ .attr({
 283+ height: naturaSize.height,
 284+ width : naturaSize.width
 285+ }).css( {
 286+ height:'100%',
 287+ widht:'100%'
 288+ })
 289+ .addClass("ui-corner-all")
 290+ )
 291+ .find( 'canvas')
 292+ .get(0)
 293+ .getContext('2d')
 294+ .drawImage( $j( '#' + smil.getAssetId( $node ) ).get(0), 0, 0)
 295+ })
 296+ },
 297+ /**
 298+ * Gets an sequence track control interface
 299+ * features to add :: expand collapse, hide, mute etc.
 300+ * for now just audio or video with icon
 301+ */
 302+ getTrackNameInterface: function( trackIndex, sequenceNode, trackType ){
 303+ var $trackNameInterface =
 304+ $j('<a />')
 305+ .attr('href','#')
 306+ .addClass( "ui-icon_link" );
 307+ if( trackType == 'video'){
 308+ $trackNameInterface.append(
 309+ $j('<span />').addClass( 'ui-icon ui-icon-video'),
 310+ $j('<span />').text( gM( 'mwe-sequenceedit-video-track' ) )
 311+ )
 312+ } else {
 313+ $trackNameInterface.append(
 314+ $j('<span />').addClass( 'ui-icon ui-icon-volume-on'),
 315+ $j('<span />').text( gM( 'mwe-sequenceedit-audio-track' ) )
 316+ )
 317+ }
 318+ // Wrap the track name in a box that matches the trackNames
 319+ return $j('<div />')
 320+ .attr('id', this.sequenceEdit.getId() + '_trackName_' + trackIndex)
 321+ .addClass('trackNames ui-corner-all')
 322+ .append(
 323+ $trackNameInterface
 324+ )
 325+ },
 326+
 327+ getSequenceTrackTitle: function( sequenceNode ){
 328+ if( $j( sequenceNode).attr('title') ){
 329+ return $j( sequenceNode).attr('title');
 330+ }
 331+ // Else return an empty string ( for now )
 332+ return ''
 333+ },
 334+
 335+ getSequenceTrackId: function( index, sequenceNode ){
 336+ if( ! $j( sequenceNode ).data('id') ){
 337+ $j( sequenceNode ).data('id', this.sequenceEdit.getId() + '_sequenceTrack_' + index );
 338+ }
 339+ return $j( sequenceNode ).data('id');
 340+ }
 341+}
 342+
 343+
 344+
 345+
 346+
 347+
 348+} )( window.mw );
\ No newline at end of file
Index: branches/MwEmbedStandAlone/modules/SequenceEdit/tests/Sequence_Editor.html
@@ -0,0 +1,41 @@
 2+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
 3+"http://www.w3.org/TR/html4/loose.dtd">
 4+<html>
 5+<head>
 6+ <title>SMIL Sequence Editor example</title>
 7+ <script type="text/javascript" src="../../../mwEmbed.js?debug=true"></script>
 8+ <script type="text/javascript">
 9+ mw.ready( function(){
 10+ mw.load( 'SequenceEdit', function(){
 11+ $j('#seqContainer').sequenceEdit({
 12+ 'smilSource' : 'SampleEditorSequenceSmil.xml',
 13+ //set the add media wizard to only include commons:
 14+ 'AddMediaConf':{
 15+ 'enabled_providers':[ 'wiki_commons', 'kaltura', 'archive_org', 'flickr', 'metavid' ],
 16+ 'import_url_mode' : 'remote_link',
 17+ 'default_query' : 'fish'
 18+ }
 19+ });
 20+ });
 21+ });
 22+ </script>
 23+<style>
 24+ body {
 25+ font: x-small sans-serif;
 26+ color: black;
 27+ margin: 0;
 28+ padding: 0;
 29+ }
 30+ img {
 31+ border:medium none;
 32+ }
 33+</style>
 34+
 35+</head>
 36+<body>
 37+ <div id="seqContainer" style="position:absolute;top:5px;bottom:10px;left:10px;right:10px;">
 38+ Loading sequence editor ...
 39+ </div>
 40+ </body>
 41+</html>
 42+
Index: branches/MwEmbedStandAlone/modules/SequenceEdit/tests/SampleEditorSequenceSmil.xml
@@ -0,0 +1,52 @@
 2+<?xml version="1.0" encoding="UTF-8"?>
 3+<smil baseProfile="Language" version="3.0" xmlns="http://www.w3.org/ns/SMIL">
 4+ <head>
 5+ <meta name="title" content="Simple Crossfading Example"/>
 6+
 7+ <transition id=""
 8+ type="fade"
 9+ subtype="fadeFromColor"
 10+ fadeColor="#000"
 11+ dur="4s"/>
 12+
 13+ </head>
 14+ <body>
 15+ <seq>
 16+
 17+ <video src="http://upload.wikimedia.org/wikipedia/commons/9/94/Folgers.ogv"
 18+ dur="5s"
 19+ clipBegin = "17s"
 20+ />
 21+
 22+ <video src="http://upload.wikimedia.org/wikipedia/commons/1/14/Independence_Day%2C_1940_Promotion.ogv"
 23+ dur="1s"
 24+ />
 25+
 26+ <video src="http://upload.wikimedia.org/wikipedia/commons/1/14/Independence_Day%2C_1940_Promotion.ogv"
 27+ transIn="fromBlack"
 28+ dur="2s"
 29+ clipBegin = "16s"
 30+ />
 31+
 32+ <video src="http://upload.wikimedia.org/wikipedia/commons/9/94/Folgers.ogv"
 33+ dur="3s"
 34+ clipBegin = "16s"
 35+ />
 36+
 37+ <video src="http://upload.wikimedia.org/wikipedia/commons/1/14/Independence_Day%2C_1940_Promotion.ogv"
 38+ dur="2"
 39+ clipBegin = "18"
 40+ />
 41+
 42+ <video src="http://upload.wikimedia.org/wikipedia/commons/8/8b/Yochai_Benkler_-_On_Autonomy%2C_Control_and_Cultural_Experience.ogg"
 43+ transIn="fromBlack"
 44+ dur="10"
 45+ clipBegin = "0:3:43"
 46+ />
 47+
 48+ </seq>
 49+
 50+ </body>
 51+</smil>
 52+
 53+
Index: branches/MwEmbedStandAlone/modules/SequenceEdit/tests/VideoRender.xml
@@ -0,0 +1,89 @@
 2+<?xml version="1.0" encoding="UTF-8"?>
 3+<smil baseProfile="Language" version="3.0" xmlns="http://www.w3.org/ns/SMIL">
 4+ <head>
 5+ <meta name="title" content="Simple Rendering Example"/>
 6+
 7+ <transition id="fromBlack"
 8+ type="fade"
 9+ subtype="fadeFromColor"
 10+ fadeColor="#000"
 11+ dur="4s"/>
 12+
 13+ <transition id="fromGreen"
 14+ type="fade"
 15+ subtype="fadeFromColor"
 16+ fadeColor="#87CF87"
 17+ dur="4s"/>
 18+
 19+ <transition id="xFade"
 20+ type="fade"
 21+ subtype="crossfade"
 22+ dur="4s"/>
 23+
 24+ <layout>
 25+ <root-layout backgroundColor="green" height="800" width="500"/>
 26+ <region backgroundColor="green" height="700" top="50" left="50" width="400" xml:id="image_region"/>
 27+ <region xml:id="Title" height="25" width="300" left="100" top="10"/>
 28+ <region xml:id="Captions" height="70" width="300" left="100" top="510"/>
 29+ <region id="audio_region" soundLevel="100%"/>
 30+ </layout>
 31+
 32+ </head>
 33+ <body>
 34+ <par>
 35+
 36+ <video src="media/raw_media/cats_of_ulthar_lovecraft_jp.ogg"
 37+ begin="1s"
 38+ dur="1000s"
 39+ />
 40+
 41+ <video src="media/raw_media/le_voyage_dans_la_lune_edit_1.ogv"
 42+ transIn="fromBlack"
 43+ type="video/ogg"
 44+ fill="transition"
 45+ dur="1000s"
 46+ />
 47+
 48+ <video src="media/raw_media/MoviePowderPresentsPlan9FromOuterSpace.ogv"
 49+ begin="15s"
 50+ transIn="xFade"
 51+
 52+ fill="transition"
 53+ dur="1000s"
 54+ durationHint="70"
 55+ type="video/ogg"
 56+ />
 57+
 58+ <img src="media/raw_media/fruitStand.jpg"
 59+ dur="25s"
 60+ fill="freeze"
 61+ fit="meet"
 62+ id="image"
 63+ panZoom="0,0,100%,100%"
 64+ region="image_region"
 65+ >
 66+
 67+ <animate attributeName="panZoom" begin="2.0"
 68+ dur="1.5s" fill="freeze" values="-1,4,99%,99%;511,509,47%,14%"/>
 69+
 70+ <animate attributeName="panZoom" begin="5.0"
 71+ dur="1.5s" fill="freeze" values="511,509,47%,14%;418,-3,34%,13%"/>
 72+
 73+ <animate attributeName="panZoom" begin="9.0"
 74+ dur="1.5s" fill="freeze" values="418,-3,34%,13%;9,1115,41%,20%"/>
 75+
 76+ <animate attributeName="panZoom" begin="13.0"
 77+ dur="1.5s" fill="freeze" values="9,1115,41%,20%;573,2073,64%,17%"/>
 78+
 79+ <animate attributeName="panZoom" begin="16.0"
 80+ dur="1.5s" fill="freeze" values="573,2073,64%,17%;1118,1365,14%,8%"/>
 81+
 82+ <animate attributeName="panZoom" begin="18.0"
 83+ dur="1.5s" fill="freeze" values="1118,1365,14%,8%;0,0,100%,100%"/>
 84+ </img>
 85+
 86+</par>
 87+</body>
 88+</smil>
 89+
 90+
Index: branches/MwEmbedStandAlone/modules/SequenceEdit/tests/VideoRender.html
@@ -0,0 +1,72 @@
 2+<!doctype html>
 3+<html>
 4+<head>
 5+ <title>Video CrossFade Example</title>
 6+ <script type="text/javascript" src="../../../mwEmbed.js?debug=true"></script>
 7+ <!-- <script type="text/javascript" src="../../ResourceLoader.php?class=window.jQuery,mwEmbed&debug=true"></script> -->
 8+ <script type="text/javascript">
 9+ mw.setConfig( 'EmbedPlayer.OverlayControls', false );
 10+ mw.ready(function(){
 11+ $j( "#seekInputTime" ).blur( function(){
 12+ var smilVid = $j('#videoCrossfade').get(0);
 13+ $j('#seekInProgress').show();
 14+ smilVid.setCurrentTime( parseFloat( $j(this).val() ), function() {
 15+ $j('#seekInProgress').hide();
 16+ });
 17+ });
 18+ $j('#startBuffer').click( function(){
 19+ $j('#videoCrossfade').get(0).load();
 20+ return false;
 21+ });
 22+ $j('#renderToFile').click(function(){
 23+ $j(this).empty().unbind().after(
 24+ $j('<span />').text( ' ' ),
 25+ $j('<span />').attr('id', 'targetFoggStatus' )
 26+ );
 27+
 28+ // xxx for local rendering 'AddMedia.firefogg' is overkill
 29+ // but will have to clean up modularity later
 30+
 31+ mw.load( ['AddMedia.firefogg','mw.FirefoggRender'],function(){
 32+ var foggRender = $j('#videoCrossfade').firefoggRender({
 33+ 'statusTarget': '#targetFoggStatus'
 34+ });
 35+ foggRender.doRender();
 36+
 37+ $j('#renderToFile').text('Stop Render').click(function(){
 38+ foggRender.stopRender();
 39+ });
 40+ })
 41+ return false;
 42+ });
 43+ });
 44+ </script>
 45+</head>
 46+<body>
 47+<h3>Sample Video CrossFade</h3>
 48+<table>
 49+<tr>
 50+<td>
 51+
 52+<video id="videoCrossfade" type="application/smil" src="VideoRender.xml" width="400" height="300"></video>
 53+<p></p>seek to <input id="seekInputTime" size="4" value = "6"></input><span id="seekInProgress" style="display: none"> Seeking<blink>...</blink></span>
 54+<br/>
 55+<a id="startBuffer" href="#">Start buffering</a> <br>
 56+<a id="renderToFile" href="#">Render to file</a>
 57+</td>
 58+<td valign="top">
 59+Sample playlist code:
 60+<div style="clear:both"></div>
 61+<textarea style="width:500px;">
 62+<video id="videoCrossfade" type="application/smil" src="VideoRender.xml" width="400" height="300"></video>
 63+</textarea>
 64+<div style="clear:both"></div>
 65+
 66+SMIL Source:
 67+<div style="clear:both"></div>
 68+<iframe style="width:500px;height:300px" src="VideoRender.xml"></iframe>
 69+</td>
 70+</tr>
 71+</table>
 72+</body>
 73+</html>
Index: branches/MwEmbedStandAlone/modules/SequenceEdit/mw.FirefoggRender.js
@@ -0,0 +1,187 @@
 2+/*
 3+* Handles driving the firefogg render system
 4+*/
 5+
 6+/*
 7+* Set the jQuery bindings:
 8+*/
 9+( function( $ ) {
 10+ $.fn.firefoggRender = function( options, callback ) {
 11+ if(!options)
 12+ options = {};
 13+ options.playerTarget = this.selector;
 14+ var myFogg = new mw.FirefoggRender( options );
 15+ return myFogg;
 16+ }
 17+} )( jQuery );
 18+
 19+
 20+mw.FirefoggRender = function( options ) {
 21+ return this.init( options );
 22+};
 23+// Set up the mvPlaylist object
 24+mw.FirefoggRender.prototype = {
 25+
 26+ // Default render options:
 27+ renderOptions: {
 28+ "videoQuality" : 8,
 29+ "framerate" : 30
 30+ },
 31+
 32+ // Render time
 33+ renderTime: null,
 34+
 35+ // The interval time ( set via requested framerate)
 36+ interval: null,
 37+
 38+ // Continue rendering
 39+ continueRendering:false,
 40+
 41+ // Start time for rendering
 42+ startTime: 0,
 43+
 44+ // Constructor
 45+ init:function( options ) {
 46+ var _this = this;
 47+
 48+ // Grab the mvFirefogg object to do basic tests
 49+ this.myFogg = new mw.Firefogg( {
 50+ 'only_fogg':true
 51+ });
 52+
 53+ // Check for firefogg:
 54+ if ( this.myFogg.getFirefogg() ) {
 55+ this.enabled = true;
 56+ } else {
 57+ this.enabled = false;
 58+ mw.log('Error firefogg not installed');
 59+ return this;
 60+ }
 61+
 62+ // Setup local fogg pointer:
 63+ this.fogg = this.myFogg.fogg;
 64+
 65+ // Setup player instance
 66+ this.playerTarget = options.playerTarget;
 67+
 68+ // Extend the render options with any provided details
 69+ if( options['renderOptions'] ){
 70+ this.renderOptions = $j.extend( this.renderOptions, options['renderOptions'] );
 71+ }
 72+
 73+ if( options ['statusTarget']){
 74+ this.statusTarget = options ['statusTarget'];
 75+ }
 76+
 77+ // If no height width provided use target DOM width/height
 78+ if( !this.renderOptions.width && !this.renderOptions.height ) {
 79+ this.renderOptions.width = $j(this.playerTarget).width();
 80+ this.renderOptions.height = $j(this.playerTarget).height();
 81+ }
 82+
 83+
 84+ },
 85+ getPlayer: function(){
 86+ return $j( this.playerTarget ).get( 0 );
 87+ },
 88+ // Start rendering
 89+ doRender: function() {
 90+ var _this = this;
 91+ // Make sure we get a target destination
 92+ if( !_this.fogg.saveVideoAs() ){
 93+ return false;
 94+ }
 95+ // Set the render time to "startTime" of the render request
 96+ this.renderTime = this.startTime;
 97+
 98+ // Get the interval from renderOptions framerate
 99+ this.interval = 1 / this.renderOptions.framerate
 100+
 101+ // Set the continue rendering flag to true:
 102+ this.continueRendering = true;
 103+
 104+ // Set a target file:
 105+ mw.log( "Firefogg Render Settings:" + JSON.stringify( _this.renderOptions ) );
 106+ this.fogg.initRender( JSON.stringify( _this.renderOptions ), 'foggRender.ogv' );
 107+
 108+ // Add audio if we had any:
 109+ var audioSet = this.getPlayer().getAudioTimeSet();
 110+ var previusAudioTime = 0;
 111+ for( var i=0; i < audioSet.length ; i++) {
 112+ var currentAudio = audioSet[i];
 113+ // Check if we need to add silence
 114+ if( currentAudio.startTime > previusAudioTime ){
 115+ mw.log("FirefoggRender::addSilence " + ( currentAudio.startTime - previusAudioTime ));
 116+ this.fogg.addSilence( currentAudio.startTime - previusAudioTime );
 117+ }
 118+ // Add the block of audio from the url
 119+ mw.log("FirefoggRender::addAudioUrl " + currentAudio.src +
 120+ ', ' + currentAudio.offset + ', ' + currentAudio.duration );
 121+ this.fogg.addAudioUrl( currentAudio.src, currentAudio.offset, currentAudio.duration );
 122+
 123+ // Update previusAudioTime
 124+ previusAudioTime = currentAudio.startTime + currentAudio.duration;
 125+ }
 126+ // Now issue the save video as call
 127+ _this.doNextFrame();
 128+ return true;
 129+ },
 130+
 131+ /**
 132+ * Do the next frame in the render target
 133+ */
 134+ doNextFrame: function() {
 135+ var _this = this;
 136+ // internal function to handle updates:
 137+ /*mw.log( "FirefoggRender::doNextFrame: on " + ( Math.round( _this.renderTime * 10 ) / 10 ) + " of " +
 138+ ( Math.round( _this.player.getDuration() * 10 ) / 10 ) );
 139+ */
 140+
 141+ _this.getPlayer().setCurrentTime( _this.renderTime, function() {
 142+
 143+ _this.fogg.addFrame( $j( _this.playerTarget ).attr( 'id' ) );
 144+ $j( _this.statusTarget ).text( "AddFrame::" + ( Math.round( _this.renderTime * 1000 ) / 1000 ) );
 145+
 146+ _this.renderTime += _this.interval;
 147+
 148+ if ( _this.renderTime >= _this.getPlayer().getDuration() || ! _this.continueRendering ) {
 149+ _this.doFinalRender();
 150+ } else {
 151+ // Don't block on render requests
 152+ setTimeout(function(){
 153+ _this.doNextFrame();
 154+ },1 )
 155+ }
 156+ } );
 157+ },
 158+
 159+ /**
 160+ * Stop the current render process on the next frame
 161+ */
 162+ stopRender: function() {
 163+ this.continueRendering = false;
 164+ },
 165+
 166+ /**
 167+ * Issue the call to firefogg to render out the ogg video
 168+ */
 169+ doFinalRender: function() {
 170+ mw.log("FirefoggRender:: doFinalRenderr" );
 171+ this.fogg.render();
 172+ this.updateStatus();
 173+ },
 174+
 175+ /**
 176+ * Update the render status
 177+ */
 178+ updateStatus: function() {
 179+ var _this = this;
 180+ var rstatus = _this.fogg.renderstatus();
 181+ $j( _this.statusTarget ).text( rstatus );
 182+ if ( rstatus != 'done' && rstatus != 'rendering failed' ) {
 183+ setTimeout( function() {
 184+ _this.updateStatus();
 185+ }, 100 );
 186+ }
 187+ }
 188+}
\ No newline at end of file
Property changes on: branches/MwEmbedStandAlone/modules/SequenceEdit/mw.FirefoggRender.js
___________________________________________________________________
Added: svn:mergeinfo
1189 Merged /branches/REL1_15/phase3/js2/mwEmbed/libSequencer/mvFirefoggRender.js:r51646
2190 Merged /branches/sqlite/js2/mwEmbed/libSequencer/mvFirefoggRender.js:r58211-58321
Added: svn:eol-style
3191 + native
Index: branches/MwEmbedStandAlone/modules/SequenceEdit/css/mw.style.SequenceEdit.css
@@ -0,0 +1,48 @@
 2+
 3+
 4+.mwe-sequence-edit .timelineTrackContainer{
 5+ position: absolute;
 6+ border: solid thin #999;
 7+ top: 4px;
 8+ left:4px;
 9+ right: 4px;
 10+ bottom: 4px;
 11+}
 12+
 13+.mwe-sequence-edit .trackNameContainer{
 14+ overflow:hidden;
 15+}
 16+.mwe-sequence-edit .trackClipsContainer{
 17+ overflow-x: scroll;
 18+}
 19+
 20+.mwe-sequence-edit .trackClips{
 21+ height: 100px;
 22+ background-color: #EEE;
 23+ border: solid thin #999;
 24+}
 25+
 26+.mwe-sequence-edit .trackNames{
 27+ height: 100px;
 28+ background-color: #EEE;
 29+ border: solid thin #999;
 30+}
 31+
 32+
 33+.mwe-sequence-edit .timelineClip{
 34+ float: left;
 35+ margin: 5px;
 36+ background-color: #FFF;
 37+ border: 2px solid #555;
 38+ overflow: hidden;
 39+}
 40+.mwe-sequence-edit .timelineClip:hover{
 41+ border: 2px solid #66F;
 42+}
 43+.mwe-sequence-edit .selectedClip{
 44+ border: 2px solid #F66;
 45+}
 46+.mwe-sequence-edit .selectedClip:hover{
 47+ border: 2px solid #F22;
 48+}
 49+
Index: branches/MwEmbedStandAlone/modules/SequenceEdit/mw.SequenceEditPlayer.js
@@ -0,0 +1,103 @@
 2+
 3+//Wrap in mw closure to avoid global leakage
 4+( function( mw ) {
 5+
 6+mw.SequenceEditPlayer = function( sequenceEdit ) {
 7+ return this.init( sequenceEdit );
 8+};
 9+
 10+// Set up the mvSequencer object
 11+mw.SequenceEditPlayer.prototype = {
 12+ // The id of the sequence player
 13+ smilPlayerId: null, // lazy init
 14+
 15+ init: function( sequenceEdit ){
 16+ this.sequenceEdit = sequenceEdit;
 17+ },
 18+ /**
 19+ * Draw a smil player to the screen.
 20+ */
 21+ drawPlayer: function( callback ){
 22+ var _this = this;
 23+ var $playerTarget = this.sequenceEdit.getContainer().find( '.mwseq-player' );
 24+ var smilSource = this.sequenceEdit.getSmilSource()
 25+ if( ! smilSource ){
 26+ $playerTarget.append(
 27+ gM( 'mwe-sequenceedit-no-sequence-start-new',
 28+ $j('<a />').click(function(){
 29+ alert( 'Browse for assets / start new sequence' );
 30+ })
 31+ )
 32+ )
 33+ return ;
 34+ }
 35+
 36+ // Else add the player
 37+ $playerTarget.html(
 38+ $j('<video />').css(
 39+ this.getPlayerSize()
 40+ ).attr({
 41+ 'id' : this.getSmilPlayerId()
 42+ }).append(
 43+ $j('<source />').attr({
 44+ 'type' : 'application/smil',
 45+ 'src' : smilSource
 46+ })
 47+ )
 48+ );
 49+ // Draw the player ( keep the playhead for now )
 50+ // xxx we will eventually replace the playhead with sequence
 51+ // based playhead interface for doing easy trims.
 52+ $j( '#' + this.getSmilPlayerId() ).embedPlayer({
 53+ 'overlayControls' : false
 54+ }, function(){
 55+ // Set the player interface to autoMargin ( need to fix css propagation in embed player)
 56+ $j( '#' + _this.getSmilPlayerId() ).parent('.interface_wrap').css('margin', 'auto');
 57+ if( callback ){
 58+ callback();
 59+ }
 60+ })
 61+
 62+ },
 63+
 64+ resizePlayer: function(){
 65+ mw.log("SequenceEditPlayer:: resizePlayer: " + $j('#' + this.getSmilPlayerId() ).length );
 66+ $j('#' + this.getSmilPlayerId() ).get(0)
 67+ .resizePlayer(
 68+ this.getPlayerSize(),
 69+ true
 70+ );
 71+ },
 72+
 73+ getPlayerSize: function(){
 74+ var size = {};
 75+ var $playerContainer = this.sequenceEdit.getContainer().find('.mwseq-player');
 76+ size.width = $playerContainer.width();
 77+ if( this.sequenceEdit.videoAspect ){
 78+ var aspect = this.sequenceEdit.videoAspect.split( ':' );
 79+ var apectRatio = ( aspect[1] / aspect[0] );
 80+ size.height = parseInt( size.width * ( aspect[1] / aspect[0] ) );
 81+ } else {
 82+ size.height = $playerContainer.width();
 83+ }
 84+ // Check if we exceeded the max height
 85+ if( size.height > $playerContainer.height() ){
 86+ size.height = $playerContainer.height();
 87+ size.width = parseInt( size.height * ( aspect[0] / aspect[1] ) );
 88+ }
 89+ return size;
 90+ },
 91+
 92+ /**
 93+ * Get a player id based on
 94+ */
 95+ getSmilPlayerId: function(){
 96+ if( !this.smilPlayerId ){
 97+ this.smilPlayerId = this.sequenceEdit.getId() + '_smilPlayer';
 98+ }
 99+ return this.smilPlayerId;
 100+ }
 101+}
 102+
 103+
 104+} )( window.mw );
\ No newline at end of file
Index: branches/MwEmbedStandAlone/modules/SequenceEdit/ui.layout/ui.layout-1.2.0.js
@@ -0,0 +1,2507 @@
 2+/*
 3+ * jquery.layout 1.2.0
 4+ *
 5+ * Copyright (c) 2008
 6+ * Fabrizio Balliano (http://www.fabrizioballiano.net)
 7+ * Kevin Dalman (http://allpro.net)
 8+ *
 9+ * Dual licensed under the GPL (http://www.gnu.org/licenses/gpl.html)
 10+ * and MIT (http://www.opensource.org/licenses/mit-license.php) licenses.
 11+ *
 12+ * $Date: 2008-12-27 02:17:22 +0100 (sab, 27 dic 2008) $
 13+ * $Rev: 203 $
 14+ *
 15+ * NOTE: For best code readability, view this with a fixed-space font and tabs equal to 4-chars
 16+ */
 17+(function($) {
 18+
 19+$.fn.layout = function (opts) {
 20+
 21+/*
 22+ * ###########################
 23+ * WIDGET CONFIG & OPTIONS
 24+ * ###########################
 25+ */
 26+
 27+ // DEFAULTS for options
 28+ var
 29+ prefix = "ui-layout-" // prefix for ALL selectors and classNames
 30+ , defaults = { // misc default values
 31+ paneClass: prefix+"pane" // ui-layout-pane
 32+ , resizerClass: prefix+"resizer" // ui-layout-resizer
 33+ , togglerClass: prefix+"toggler" // ui-layout-toggler
 34+ , togglerInnerClass: prefix+"" // ui-layout-open / ui-layout-closed
 35+ , buttonClass: prefix+"button" // ui-layout-button
 36+ , contentSelector: "."+prefix+"content"// ui-layout-content
 37+ , contentIgnoreSelector: "."+prefix+"ignore" // ui-layout-mask
 38+ }
 39+ ;
 40+
 41+ // DEFAULT PANEL OPTIONS - CHANGE IF DESIRED
 42+ var options = {
 43+ name: "" // FUTURE REFERENCE - not used right now
 44+ , scrollToBookmarkOnLoad: true // after creating a layout, scroll to bookmark in URL (.../page.htm#myBookmark)
 45+ , defaults: { // default options for 'all panes' - will be overridden by 'per-pane settings'
 46+ applyDefaultStyles: false // apply basic styles directly to resizers & buttons? If not, then stylesheet must handle it
 47+ , closable: true // pane can open & close
 48+ , resizable: true // when open, pane can be resized
 49+ , slidable: true // when closed, pane can 'slide' open over other panes - closes on mouse-out
 50+ //, paneSelector: [ ] // MUST be pane-specific!
 51+ , contentSelector: defaults.contentSelector // INNER div/element to auto-size so only it scrolls, not the entire pane!
 52+ , contentIgnoreSelector: defaults.contentIgnoreSelector // elem(s) to 'ignore' when measuring 'content'
 53+ , paneClass: defaults.paneClass // border-Pane - default: 'ui-layout-pane'
 54+ , resizerClass: defaults.resizerClass // Resizer Bar - default: 'ui-layout-resizer'
 55+ , togglerClass: defaults.togglerClass // Toggler Button - default: 'ui-layout-toggler'
 56+ , buttonClass: defaults.buttonClass // CUSTOM Buttons - default: 'ui-layout-button-toggle/-open/-close/-pin'
 57+ , resizerDragOpacity: 1 // option for ui.draggable
 58+ //, resizerCursor: "" // MUST be pane-specific - cursor when over resizer-bar
 59+ , maskIframesOnResize: true // true = all iframes OR = iframe-selector(s) - adds masking-div during resizing/dragging
 60+ //, size: 100 // inital size of pane - defaults are set 'per pane'
 61+ , minSize: 0 // when manually resizing a pane
 62+ , maxSize: 0 // ditto, 0 = no limit
 63+ , spacing_open: 6 // space between pane and adjacent panes - when pane is 'open'
 64+ , spacing_closed: 6 // ditto - when pane is 'closed'
 65+ , togglerLength_open: 50 // Length = WIDTH of toggler button on north/south edges - HEIGHT on east/west edges
 66+ , togglerLength_closed: 50 // 100% OR -1 means 'full height/width of resizer bar' - 0 means 'hidden'
 67+ , togglerAlign_open: "center" // top/left, bottom/right, center, OR...
 68+ , togglerAlign_closed: "center" // 1 => nn = offset from top/left, -1 => -nn == offset from bottom/right
 69+ , togglerTip_open: "Close" // Toggler tool-tip (title)
 70+ , togglerTip_closed: "Open" // ditto
 71+ , resizerTip: "Resize" // Resizer tool-tip (title)
 72+ , sliderTip: "Slide Open" // resizer-bar triggers 'sliding' when pane is closed
 73+ , sliderCursor: "pointer" // cursor when resizer-bar will trigger 'sliding'
 74+ , slideTrigger_open: "click" // click, dblclick, mouseover
 75+ , slideTrigger_close: "mouseout" // click, mouseout
 76+ , hideTogglerOnSlide: false // when pane is slid-open, should the toggler show?
 77+ , togglerContent_open: "" // text or HTML to put INSIDE the toggler
 78+ , togglerContent_closed: "" // ditto
 79+ , showOverflowOnHover: false // will bind allowOverflow() utility to pane.onMouseOver
 80+ , enableCursorHotkey: true // enabled 'cursor' hotkeys
 81+ //, customHotkey: "" // MUST be pane-specific - EITHER a charCode OR a character
 82+ , customHotkeyModifier: "SHIFT" // either 'SHIFT', 'CTRL' or 'CTRL+SHIFT' - NOT 'ALT'
 83+ // NOTE: fxSss_open & fxSss_close options (eg: fxName_open) are auto-generated if not passed
 84+ , fxName: "slide" // ('none' or blank), slide, drop, scale
 85+ , fxSpeed: null // slow, normal, fast, 200, nnn - if passed, will OVERRIDE fxSettings.duration
 86+ , fxSettings: {} // can be passed, eg: { easing: "easeOutBounce", duration: 1500 }
 87+ , initClosed: false // true = init pane as 'closed'
 88+ , initHidden: false // true = init pane as 'hidden' - no resizer or spacing
 89+
 90+ /* callback options do not have to be set - listed here for reference only
 91+ , onshow_start: "" // CALLBACK when pane STARTS to Show - BEFORE onopen/onhide_start
 92+ , onshow_end: "" // CALLBACK when pane ENDS being Shown - AFTER onopen/onhide_end
 93+ , onhide_start: "" // CALLBACK when pane STARTS to Close - BEFORE onclose_start
 94+ , onhide_end: "" // CALLBACK when pane ENDS being Closed - AFTER onclose_end
 95+ , onopen_start: "" // CALLBACK when pane STARTS to Open
 96+ , onopen_end: "" // CALLBACK when pane ENDS being Opened
 97+ , onclose_start: "" // CALLBACK when pane STARTS to Close
 98+ , onclose_end: "" // CALLBACK when pane ENDS being Closed
 99+ , onresize_start: "" // CALLBACK when pane STARTS to be ***MANUALLY*** Resized
 100+ , onresize_end: "" // CALLBACK when pane ENDS being Resized ***FOR ANY REASON***
 101+ */
 102+ }
 103+ , north: {
 104+ paneSelector: "."+prefix+"north" // default = .ui-layout-north
 105+ , size: "auto"
 106+ , resizerCursor: "n-resize"
 107+ }
 108+ , south: {
 109+ paneSelector: "."+prefix+"south" // default = .ui-layout-south
 110+ , size: "auto"
 111+ , resizerCursor: "s-resize"
 112+ }
 113+ , east: {
 114+ paneSelector: "."+prefix+"east" // default = .ui-layout-east
 115+ , size: 200
 116+ , resizerCursor: "e-resize"
 117+ }
 118+ , west: {
 119+ paneSelector: "."+prefix+"west" // default = .ui-layout-west
 120+ , size: 200
 121+ , resizerCursor: "w-resize"
 122+ }
 123+ , center: {
 124+ paneSelector: "."+prefix+"center" // default = .ui-layout-center
 125+ }
 126+
 127+ };
 128+
 129+
 130+ var effects = { // LIST *PREDEFINED EFFECTS* HERE, even if effect has no settings
 131+ slide: {
 132+ all: { duration: "fast" } // eg: duration: 1000, easing: "easeOutBounce"
 133+ , north: { direction: "up" }
 134+ , south: { direction: "down" }
 135+ , east: { direction: "right"}
 136+ , west: { direction: "left" }
 137+ }
 138+ , drop: {
 139+ all: { duration: "slow" } // eg: duration: 1000, easing: "easeOutQuint"
 140+ , north: { direction: "up" }
 141+ , south: { direction: "down" }
 142+ , east: { direction: "right"}
 143+ , west: { direction: "left" }
 144+ }
 145+ , scale: {
 146+ all: { duration: "fast" }
 147+ }
 148+ };
 149+
 150+
 151+ // STATIC, INTERNAL CONFIG - DO NOT CHANGE THIS!
 152+ var config = {
 153+ allPanes: "north,south,east,west,center"
 154+ , borderPanes: "north,south,east,west"
 155+ , zIndex: { // set z-index values here
 156+ resizer_normal: 1 // normal z-index for resizer-bars
 157+ , pane_normal: 2 // normal z-index for panes
 158+ , mask: 4 // overlay div used to mask pane(s) during resizing
 159+ , sliding: 100 // applied to both the pane and its resizer when a pane is 'slid open'
 160+ , resizing: 10000 // applied to the CLONED resizer-bar when being 'dragged'
 161+ , animation: 10000 // applied to the pane when being animated - not applied to the resizer
 162+ }
 163+ , resizers: {
 164+ cssReq: {
 165+ position: "absolute"
 166+ , padding: 0
 167+ , margin: 0
 168+ , fontSize: "1px"
 169+ , textAlign: "left" // to counter-act "center" alignment!
 170+ , overflow: "hidden" // keep toggler button from overflowing
 171+ , zIndex: 1
 172+ }
 173+ , cssDef: { // DEFAULT CSS - applied if: options.PANE.applyDefaultStyles=true
 174+ background: "#DDD"
 175+ , border: "none"
 176+ }
 177+ }
 178+ , togglers: {
 179+ cssReq: {
 180+ position: "absolute"
 181+ , display: "block"
 182+ , padding: 0
 183+ , margin: 0
 184+ , overflow: "hidden"
 185+ , textAlign: "center"
 186+ , fontSize: "1px"
 187+ , cursor: "pointer"
 188+ , zIndex: 1
 189+ }
 190+ , cssDef: { // DEFAULT CSS - applied if: options.PANE.applyDefaultStyles=true
 191+ background: "#AAA"
 192+ }
 193+ }
 194+ , content: {
 195+ cssReq: {
 196+ overflow: "auto"
 197+ }
 198+ , cssDef: {}
 199+ }
 200+ , defaults: { // defaults for ALL panes - overridden by 'per-pane settings' below
 201+ cssReq: {
 202+ position: "absolute"
 203+ , margin: 0
 204+ , zIndex: 2
 205+ }
 206+ , cssDef: {
 207+ padding: "10px"
 208+ , background: "#FFF"
 209+ , border: "1px solid #BBB"
 210+ , overflow: "auto"
 211+ }
 212+ }
 213+ , north: {
 214+ edge: "top"
 215+ , sizeType: "height"
 216+ , dir: "horz"
 217+ , cssReq: {
 218+ top: 0
 219+ , bottom: "auto"
 220+ , left: 0
 221+ , right: 0
 222+ , width: "auto"
 223+ // height: DYNAMIC
 224+ }
 225+ }
 226+ , south: {
 227+ edge: "bottom"
 228+ , sizeType: "height"
 229+ , dir: "horz"
 230+ , cssReq: {
 231+ top: "auto"
 232+ , bottom: 0
 233+ , left: 0
 234+ , right: 0
 235+ , width: "auto"
 236+ // height: DYNAMIC
 237+ }
 238+ }
 239+ , east: {
 240+ edge: "right"
 241+ , sizeType: "width"
 242+ , dir: "vert"
 243+ , cssReq: {
 244+ left: "auto"
 245+ , right: 0
 246+ , top: "auto" // DYNAMIC
 247+ , bottom: "auto" // DYNAMIC
 248+ , height: "auto"
 249+ // width: DYNAMIC
 250+ }
 251+ }
 252+ , west: {
 253+ edge: "left"
 254+ , sizeType: "width"
 255+ , dir: "vert"
 256+ , cssReq: {
 257+ left: 0
 258+ , right: "auto"
 259+ , top: "auto" // DYNAMIC
 260+ , bottom: "auto" // DYNAMIC
 261+ , height: "auto"
 262+ // width: DYNAMIC
 263+ }
 264+ }
 265+ , center: {
 266+ dir: "center"
 267+ , cssReq: {
 268+ left: "auto" // DYNAMIC
 269+ , right: "auto" // DYNAMIC
 270+ , top: "auto" // DYNAMIC
 271+ , bottom: "auto" // DYNAMIC
 272+ , height: "auto"
 273+ , width: "auto"
 274+ }
 275+ }
 276+ };
 277+
 278+
 279+ // DYNAMIC DATA
 280+ var state = {
 281+ // generate random 'ID#' to identify layout - used to create global namespace for timers
 282+ id: Math.floor(Math.random() * 10000)
 283+ , container: {}
 284+ , north: {}
 285+ , south: {}
 286+ , east: {}
 287+ , west: {}
 288+ , center: {}
 289+ };
 290+
 291+
 292+ var
 293+ altEdge = {
 294+ top: "bottom"
 295+ , bottom: "top"
 296+ , left: "right"
 297+ , right: "left"
 298+ }
 299+ , altSide = {
 300+ north: "south"
 301+ , south: "north"
 302+ , east: "west"
 303+ , west: "east"
 304+ }
 305+ ;
 306+
 307+
 308+/*
 309+ * ###########################
 310+ * INTERNAL HELPER FUNCTIONS
 311+ * ###########################
 312+ */
 313+
 314+ /**
 315+ * isStr
 316+ *
 317+ * Returns true if passed param is EITHER a simple string OR a 'string object' - otherwise returns false
 318+ */
 319+ var isStr = function (o) {
 320+ if (typeof o == "string")
 321+ return true;
 322+ else if (typeof o == "object") {
 323+ try {
 324+ var match = o.constructor.toString().match(/string/i);
 325+ return (match !== null);
 326+ } catch (e) {}
 327+ }
 328+ return false;
 329+ };
 330+
 331+ /**
 332+ * str
 333+ *
 334+ * Returns a simple string if the passed param is EITHER a simple string OR a 'string object',
 335+ * else returns the original object
 336+ */
 337+ var str = function (o) {
 338+ if (typeof o == "string" || isStr(o)) return $.trim(o); // trim converts 'String object' to a simple string
 339+ else return o;
 340+ };
 341+
 342+ /**
 343+ * min / max
 344+ *
 345+ * Alias for Math.min/.max to simplify coding
 346+ */
 347+ var min = function (x,y) { return Math.min(x,y); };
 348+ var max = function (x,y) { return Math.max(x,y); };
 349+
 350+ /**
 351+ * transformData
 352+ *
 353+ * Processes the options passed in and transforms them into the format used by layout()
 354+ * Missing keys are added, and converts the data if passed in 'flat-format' (no sub-keys)
 355+ * In flat-format, pane-specific-settings are prefixed like: north__optName (2-underscores)
 356+ * To update effects, options MUST use nested-keys format, with an effects key
 357+ *
 358+ * @callers initOptions()
 359+ * @params JSON d Data/options passed by user - may be a single level or nested levels
 360+ * @returns JSON Creates a data struture that perfectly matches 'options', ready to be imported
 361+ */
 362+ var transformData = function (d) {
 363+ var json = { defaults:{fxSettings:{}}, north:{fxSettings:{}}, south:{fxSettings:{}}, east:{fxSettings:{}}, west:{fxSettings:{}}, center:{fxSettings:{}} };
 364+ d = d || {};
 365+ if (d.effects || d.defaults || d.north || d.south || d.west || d.east || d.center)
 366+ json = $.extend( json, d ); // already in json format - add to base keys
 367+ else
 368+ // convert 'flat' to 'nest-keys' format - also handles 'empty' user-options
 369+ $.each( d, function (key,val) {
 370+ a = key.split("__");
 371+ json[ a[1] ? a[0] : "defaults" ][ a[1] ? a[1] : a[0] ] = val;
 372+ });
 373+ return json;
 374+ };
 375+
 376+ /**
 377+ * setFlowCallback
 378+ *
 379+ * Set an INTERNAL callback to avoid simultaneous animation
 380+ * Runs only if needed and only if all callbacks are not 'already set'!
 381+ *
 382+ * @param String action Either 'open' or 'close'
 383+ * @pane String pane A valid border-pane name, eg 'west'
 384+ * @pane Boolean param Extra param for callback (optional)
 385+ */
 386+ var setFlowCallback = function (action, pane, param) {
 387+ var
 388+ cb = action +","+ pane +","+ (param ? 1 : 0)
 389+ , cP, cbPane
 390+ ;
 391+ $.each(c.borderPanes.split(","), function (i,p) {
 392+ if (c[p].isMoving) {
 393+ bindCallback(p); // TRY to bind a callback
 394+ return false; // BREAK
 395+ }
 396+ });
 397+
 398+ function bindCallback (p, test) {
 399+ cP = c[p];
 400+ if (!cP.doCallback) {
 401+ cP.doCallback = true;
 402+ cP.callback = cb;
 403+ }
 404+ else { // try to 'chain' this callback
 405+ cpPane = cP.callback.split(",")[1]; // 2nd param is 'pane'
 406+ if (cpPane != p && cpPane != pane) // callback target NOT 'itself' and NOT 'this pane'
 407+ bindCallback (cpPane, true); // RECURSE
 408+ }
 409+ }
 410+ };
 411+
 412+ /**
 413+ * execFlowCallback
 414+ *
 415+ * RUN the INTERNAL callback for this pane - if one exists
 416+ *
 417+ * @param String action Either 'open' or 'close'
 418+ * @pane String pane A valid border-pane name, eg 'west'
 419+ * @pane Boolean param Extra param for callback (optional)
 420+ */
 421+ var execFlowCallback = function (pane) {
 422+ var cP = c[pane];
 423+
 424+ // RESET flow-control flaGs
 425+ c.isLayoutBusy = false;
 426+ delete cP.isMoving;
 427+ if (!cP.doCallback || !cP.callback) return;
 428+
 429+ cP.doCallback = false; // RESET logic flag
 430+
 431+ // EXECUTE the callback
 432+ var
 433+ cb = cP.callback.split(",")
 434+ , param = (cb[2] > 0 ? true : false)
 435+ ;
 436+ if (cb[0] == "open")
 437+ open( cb[1], param );
 438+ else if (cb[0] == "close")
 439+ close( cb[1], param );
 440+
 441+ if (!cP.doCallback) cP.callback = null; // RESET - unless callback above enabled it again!
 442+ };
 443+
 444+ /**
 445+ * execUserCallback
 446+ *
 447+ * Executes a Callback function after a trigger event, like resize, open or close
 448+ *
 449+ * @param String pane This is passed only so we can pass the 'pane object' to the callback
 450+ * @param String v_fn Accepts a function name, OR a comma-delimited array: [0]=function name, [1]=argument
 451+ */
 452+ var execUserCallback = function (pane, v_fn) {
 453+ if (!v_fn) return;
 454+ var fn;
 455+ try {
 456+ if (typeof v_fn == "function")
 457+ fn = v_fn;
 458+ else if (typeof v_fn != "string")
 459+ return;
 460+ else if (v_fn.indexOf(",") > 0) {
 461+ // function name cannot contain a comma, so must be a function name AND a 'name' parameter
 462+ var
 463+ args = v_fn.split(",")
 464+ , fn = eval(args[0])
 465+ ;
 466+ if (typeof fn=="function" && args.length > 1)
 467+ return fn(args[1]); // pass the argument parsed from 'list'
 468+ }
 469+ else // just the name of an external function?
 470+ fn = eval(v_fn);
 471+
 472+ if (typeof fn=="function")
 473+ // pass data: pane-name, pane-element, pane-state, pane-options, and layout-name
 474+ return fn( pane, $Ps[pane], $.extend({},state[pane]), $.extend({},options[pane]), options.name );
 475+ }
 476+ catch (ex) {}
 477+ };
 478+
 479+ /**
 480+ * cssNum
 481+ *
 482+ * Returns the 'current CSS value' for an element - returns 0 if property does not exist
 483+ *
 484+ * @callers Called by many methods
 485+ * @param jQuery $Elem Must pass a jQuery object - first element is processed
 486+ * @param String property The name of the CSS property, eg: top, width, etc.
 487+ * @returns Variant Usually is used to get an integer value for position (top, left) or size (height, width)
 488+ */
 489+ var cssNum = function ($E, prop) {
 490+ var
 491+ val = 0
 492+ , hidden = false
 493+ , visibility = ""
 494+ ;
 495+ if (!$.browser.msie) { // IE CAN read dimensions of 'hidden' elements - FF CANNOT
 496+ if ($.curCSS($E[0], "display", true) == "none") {
 497+ hidden = true;
 498+ visibility = $.curCSS($E[0], "visibility", true); // SAVE current setting
 499+ $E.css({ display: "block", visibility: "hidden" }); // show element 'invisibly' so we can measure it
 500+ }
 501+ }
 502+
 503+ val = parseInt($.curCSS($E[0], prop, true), 10) || 0;
 504+
 505+ if (hidden) { // WAS hidden, so put back the way it was
 506+ $E.css({ display: "none" });
 507+ if (visibility && visibility != "hidden")
 508+ $E.css({ visibility: visibility }); // reset 'visibility'
 509+ }
 510+
 511+ return val;
 512+ };
 513+
 514+ /**
 515+ * cssW / cssH / cssSize
 516+ *
 517+ * Contains logic to check boxModel & browser, and return the correct width/height for the current browser/doctype
 518+ *
 519+ * @callers initPanes(), sizeMidPanes(), initHandles(), sizeHandles()
 520+ * @param Variant elem Can accept a 'pane' (east, west, etc) OR a DOM object OR a jQuery object
 521+ * @param Integer outerWidth/outerHeight (optional) Can pass a width, allowing calculations BEFORE element is resized
 522+ * @returns Integer Returns the innerHeight of the elem by subtracting padding and borders
 523+ *
 524+ * @TODO May need to add additional logic to handle more browser/doctype variations?
 525+ */
 526+ var cssW = function (e, outerWidth) {
 527+ var $E;
 528+ if (isStr(e)) {
 529+ e = str(e);
 530+ $E = $Ps[e];
 531+ }
 532+ else
 533+ $E = $(e);
 534+
 535+ // a 'calculated' outerHeight can be passed so borders and/or padding are removed if needed
 536+ if (outerWidth <= 0)
 537+ return 0;
 538+ else if (!(outerWidth>0))
 539+ outerWidth = isStr(e) ? getPaneSize(e) : $E.outerWidth();
 540+
 541+ if (!$.boxModel)
 542+ return outerWidth;
 543+
 544+ else // strip border and padding size from outerWidth to get CSS Width
 545+ return outerWidth
 546+ - cssNum($E, "paddingLeft")
 547+ - cssNum($E, "paddingRight")
 548+ - ($.curCSS($E[0], "borderLeftStyle", true) == "none" ? 0 : cssNum($E, "borderLeftWidth"))
 549+ - ($.curCSS($E[0], "borderRightStyle", true) == "none" ? 0 : cssNum($E, "borderRightWidth"))
 550+ ;
 551+ };
 552+ var cssH = function (e, outerHeight) {
 553+ var $E;
 554+ if (isStr(e)) {
 555+ e = str(e);
 556+ $E = $Ps[e];
 557+ }
 558+ else
 559+ $E = $(e);
 560+
 561+ // a 'calculated' outerHeight can be passed so borders and/or padding are removed if needed
 562+ if (outerHeight <= 0)
 563+ return 0;
 564+ else if (!(outerHeight>0))
 565+ outerHeight = (isStr(e)) ? getPaneSize(e) : $E.outerHeight();
 566+
 567+ if (!$.boxModel)
 568+ return outerHeight;
 569+
 570+ else // strip border and padding size from outerHeight to get CSS Height
 571+ return outerHeight
 572+ - cssNum($E, "paddingTop")
 573+ - cssNum($E, "paddingBottom")
 574+ - ($.curCSS($E[0], "borderTopStyle", true) == "none" ? 0 : cssNum($E, "borderTopWidth"))
 575+ - ($.curCSS($E[0], "borderBottomStyle", true) == "none" ? 0 : cssNum($E, "borderBottomWidth"))
 576+ ;
 577+ };
 578+ var cssSize = function (pane, outerSize) {
 579+ if (c[pane].dir=="horz") // pane = north or south
 580+ return cssH(pane, outerSize);
 581+ else // pane = east or west
 582+ return cssW(pane, outerSize);
 583+ };
 584+
 585+ /**
 586+ * getPaneSize
 587+ *
 588+ * Calculates the current 'size' (width or height) of a border-pane - optionally with 'pane spacing' added
 589+ *
 590+ * @returns Integer Returns EITHER Width for east/west panes OR Height for north/south panes - adjusted for boxModel & browser
 591+ */
 592+ var getPaneSize = function (pane, inclSpace) {
 593+ var
 594+ $P = $Ps[pane]
 595+ , o = options[pane]
 596+ , s = state[pane]
 597+ , oSp = (inclSpace ? o.spacing_open : 0)
 598+ , cSp = (inclSpace ? o.spacing_closed : 0)
 599+ ;
 600+ if (!$P || s.isHidden)
 601+ return 0;
 602+ else if (s.isClosed || (s.isSliding && inclSpace))
 603+ return cSp;
 604+ else if (c[pane].dir == "horz")
 605+ return $P.outerHeight() + oSp;
 606+ else // dir == "vert"
 607+ return $P.outerWidth() + oSp;
 608+ };
 609+
 610+ var setPaneMinMaxSizes = function (pane) {
 611+ var
 612+ d = cDims
 613+ , edge = c[pane].edge
 614+ , dir = c[pane].dir
 615+ , o = options[pane]
 616+ , s = state[pane]
 617+ , $P = $Ps[pane]
 618+ , $altPane = $Ps[ altSide[pane] ]
 619+ , paneSpacing = o.spacing_open
 620+ , altPaneSpacing = options[ altSide[pane] ].spacing_open
 621+ , altPaneSize = (!$altPane ? 0 : (dir=="horz" ? $altPane.outerHeight() : $altPane.outerWidth()))
 622+ , containerSize = (dir=="horz" ? d.innerHeight : d.innerWidth)
 623+ // limitSize prevents this pane from 'overlapping' opposite pane - even if opposite pane is currently closed
 624+ , limitSize = containerSize - paneSpacing - altPaneSize - altPaneSpacing
 625+ , minSize = s.minSize || 0
 626+ , maxSize = Math.min(s.maxSize || 9999, limitSize)
 627+ , minPos, maxPos // used to set resizing limits
 628+ ;
 629+ switch (pane) {
 630+ case "north": minPos = d.offsetTop + minSize;
 631+ maxPos = d.offsetTop + maxSize;
 632+ break;
 633+ case "west": minPos = d.offsetLeft + minSize;
 634+ maxPos = d.offsetLeft + maxSize;
 635+ break;
 636+ case "south": minPos = d.offsetTop + d.innerHeight - maxSize;
 637+ maxPos = d.offsetTop + d.innerHeight - minSize;
 638+ break;
 639+ case "east": minPos = d.offsetLeft + d.innerWidth - maxSize;
 640+ maxPos = d.offsetLeft + d.innerWidth - minSize;
 641+ break;
 642+ }
 643+ // save data to pane-state
 644+ $.extend(s, { minSize: minSize, maxSize: maxSize, minPosition: minPos, maxPosition: maxPos });
 645+ };
 646+
 647+ /**
 648+ * getPaneDims
 649+ *
 650+ * Returns data for setting the size/position of center pane. Date is also used to set Height for east/west panes
 651+ *
 652+ * @returns JSON Returns a hash of all dimensions: top, bottom, left, right, (outer) width and (outer) height
 653+ */
 654+ var getPaneDims = function () {
 655+ var d = {
 656+ top: getPaneSize("north", true) // true = include 'spacing' value for p
 657+ , bottom: getPaneSize("south", true)
 658+ , left: getPaneSize("west", true)
 659+ , right: getPaneSize("east", true)
 660+ , width: 0
 661+ , height: 0
 662+ };
 663+
 664+ with (d) {
 665+ width = cDims.innerWidth - left - right;
 666+ height = cDims.innerHeight - bottom - top;
 667+ // now add the 'container border/padding' to get final positions - relative to the container
 668+ top += cDims.top;
 669+ bottom += cDims.bottom;
 670+ left += cDims.left;
 671+ right += cDims.right;
 672+ }
 673+
 674+ return d;
 675+ };
 676+
 677+
 678+ /**
 679+ * getElemDims
 680+ *
 681+ * Returns data for setting size of an element (container or a pane).
 682+ *
 683+ * @callers create(), onWindowResize() for container, plus others for pane
 684+ * @returns JSON Returns a hash of all dimensions: top, bottom, left, right, outerWidth, innerHeight, etc
 685+ */
 686+ var getElemDims = function ($E) {
 687+ var
 688+ d = {} // dimensions hash
 689+ , e, b, p // edge, border, padding
 690+ ;
 691+
 692+ $.each("Left,Right,Top,Bottom".split(","), function () {
 693+ e = str(this);
 694+ b = d["border" +e] = cssNum($E, "border"+e+"Width");
 695+ p = d["padding"+e] = cssNum($E, "padding"+e);
 696+ d["offset" +e] = b + p; // total offset of content from outer edge
 697+ // if BOX MODEL, then 'position' = PADDING (ignore borderWidth)
 698+ if ($E == $Container)
 699+ d[e.toLowerCase()] = ($.boxModel ? p : 0);
 700+ });
 701+
 702+ d.innerWidth = d.outerWidth = $E.outerWidth();
 703+ d.innerHeight = d.outerHeight = $E.outerHeight();
 704+ if ($.boxModel) {
 705+ d.innerWidth -= (d.offsetLeft + d.offsetRight);
 706+ d.innerHeight -= (d.offsetTop + d.offsetBottom);
 707+ }
 708+
 709+ return d;
 710+ };
 711+
 712+
 713+ var setTimer = function (pane, action, fn, ms) {
 714+ var
 715+ Layout = window.layout = window.layout || {}
 716+ , Timers = Layout.timers = Layout.timers || {}
 717+ , name = "layout_"+ state.id +"_"+ pane +"_"+ action // UNIQUE NAME for every layout-pane-action
 718+ ;
 719+ if (Timers[name]) return; // timer already set!
 720+ else Timers[name] = setTimeout(fn, ms);
 721+ };
 722+
 723+ var clearTimer = function (pane, action) {
 724+ var
 725+ Layout = window.layout = window.layout || {}
 726+ , Timers = Layout.timers = Layout.timers || {}
 727+ , name = "layout_"+ state.id +"_"+ pane +"_"+ action // UNIQUE NAME for every layout-pane-action
 728+ ;
 729+ if (Timers[name]) {
 730+ clearTimeout( Timers[name] );
 731+ delete Timers[name];
 732+ return true;
 733+ }
 734+ else
 735+ return false;
 736+ };
 737+
 738+
 739+/*
 740+ * ###########################
 741+ * INITIALIZATION METHODS
 742+ * ###########################
 743+ */
 744+
 745+ /**
 746+ * create
 747+ *
 748+ * Initialize the layout - called automatically whenever an instance of layout is created
 749+ *
 750+ * @callers NEVER explicity called
 751+ * @returns An object pointer to the instance created
 752+ */
 753+ var create = function () {
 754+ // initialize config/options
 755+ initOptions();
 756+
 757+ // initialize all objects
 758+ initContainer(); // set CSS as needed and init state.container dimensions
 759+ initPanes(); // size & position all panes
 760+ initHandles(); // create and position all resize bars & togglers buttons
 761+ initResizable(); // activate resizing on all panes where resizable=true
 762+ sizeContent("all"); // AFTER panes & handles have been initialized, size 'content' divs
 763+
 764+ if (options.scrollToBookmarkOnLoad)
 765+ with (self.location) if (hash) replace( hash ); // scrollTo Bookmark
 766+
 767+ // bind hotkey function - keyDown - if required
 768+ initHotkeys();
 769+
 770+ // bind resizeAll() for 'this layout instance' to window.resize event
 771+ $(window).resize(function () {
 772+ var timerID = "timerLayout_"+state.id;
 773+ if (window[timerID]) clearTimeout(window[timerID]);
 774+ window[timerID] = null;
 775+ if (true || $.browser.msie) // use a delay for IE because the resize event fires repeatly
 776+ window[timerID] = setTimeout(resizeAll, 100);
 777+ else // most other browsers have a built-in delay before firing the resize event
 778+ resizeAll(); // resize all layout elements NOW!
 779+ });
 780+ };
 781+
 782+ /**
 783+ * initContainer
 784+ *
 785+ * Validate and initialize container CSS and events
 786+ *
 787+ * @callers create()
 788+ */
 789+ var initContainer = function () {
 790+ try { // format html/body if this is a full page layout
 791+ if ($Container[0].tagName == "BODY") {
 792+ $("html").css({
 793+ height: "100%"
 794+ , overflow: "hidden"
 795+ });
 796+ $("body").css({
 797+ position: "relative"
 798+ , height: "100%"
 799+ , overflow: "hidden"
 800+ , margin: 0
 801+ , padding: 0 // TODO: test whether body-padding could be handled?
 802+ , border: "none" // a body-border creates problems because it cannot be measured!
 803+ });
 804+ }
 805+ else { // set required CSS - overflow and position
 806+ var
 807+ CSS = { overflow: "hidden" } // make sure container will not 'scroll'
 808+ , p = $Container.css("position")
 809+ , h = $Container.css("height")
 810+ ;
 811+ // if this is a NESTED layout, then outer-pane ALREADY has position and height
 812+ if (!$Container.hasClass("ui-layout-pane")) {
 813+ if (!p || "fixed,absolute,relative".indexOf(p) < 0)
 814+ CSS.position = "relative"; // container MUST have a 'position'
 815+ if (!h || h=="auto")
 816+ CSS.height = "100%"; // container MUST have a 'height'
 817+ }
 818+ $Container.css( CSS );
 819+ }
 820+ } catch (ex) {}
 821+
 822+ // get layout-container dimensions (updated when necessary)
 823+ cDims = state.container = getElemDims( $Container ); // update data-pointer too
 824+ };
 825+
 826+ /**
 827+ * initHotkeys
 828+ *
 829+ * Bind layout hotkeys - if options enabled
 830+ *
 831+ * @callers create()
 832+ */
 833+ var initHotkeys = function () {
 834+ // bind keyDown to capture hotkeys, if option enabled for ANY pane
 835+ $.each(c.borderPanes.split(","), function (i,pane) {
 836+ var o = options[pane];
 837+ if (o.enableCursorHotkey || o.customHotkey) {
 838+ $(document).keydown( keyDown ); // only need to bind this ONCE
 839+ return false; // BREAK - binding was done
 840+ }
 841+ });
 842+ };
 843+
 844+ /**
 845+ * initOptions
 846+ *
 847+ * Build final CONFIG and OPTIONS data
 848+ *
 849+ * @callers create()
 850+ */
 851+ var initOptions = function () {
 852+ // simplify logic by making sure passed 'opts' var has basic keys
 853+ opts = transformData( opts );
 854+
 855+ // update default effects, if case user passed key
 856+ if (opts.effects) {
 857+ $.extend( effects, opts.effects );
 858+ delete opts.effects;
 859+ }
 860+
 861+ // see if any 'global options' were specified
 862+ $.each("name,scrollToBookmarkOnLoad".split(","), function (idx,key) {
 863+ if (opts[key] !== undefined)
 864+ options[key] = opts[key];
 865+ else if (opts.defaults[key] !== undefined) {
 866+ options[key] = opts.defaults[key];
 867+ delete opts.defaults[key];
 868+ }
 869+ });
 870+
 871+ // remove any 'defaults' that MUST be set 'per-pane'
 872+ $.each("paneSelector,resizerCursor,customHotkey".split(","),
 873+ function (idx,key) { delete opts.defaults[key]; } // is OK if key does not exist
 874+ );
 875+
 876+ // now update options.defaults
 877+ $.extend( options.defaults, opts.defaults );
 878+ // make sure required sub-keys exist
 879+ //if (typeof options.defaults.fxSettings != "object") options.defaults.fxSettings = {};
 880+
 881+ // merge all config & options for the 'center' pane
 882+ c.center = $.extend( true, {}, c.defaults, c.center );
 883+ $.extend( options.center, opts.center );
 884+ // Most 'default options' do not apply to 'center', so add only those that DO
 885+ var o_Center = $.extend( true, {}, options.defaults, opts.defaults, options.center ); // TEMP data
 886+ $.each("paneClass,contentSelector,contentIgnoreSelector,applyDefaultStyles,showOverflowOnHover".split(","),
 887+ function (idx,key) { options.center[key] = o_Center[key]; }
 888+ );
 889+
 890+ var defs = options.defaults;
 891+
 892+ // create a COMPLETE set of options for EACH border-pane
 893+ $.each(c.borderPanes.split(","), function(i,pane) {
 894+ // apply 'pane-defaults' to CONFIG.PANE
 895+ c[pane] = $.extend( true, {}, c.defaults, c[pane] );
 896+ // apply 'pane-defaults' + user-options to OPTIONS.PANE
 897+ o = options[pane] = $.extend( true, {}, options.defaults, options[pane], opts.defaults, opts[pane] );
 898+
 899+ // make sure we have base-classes
 900+ if (!o.paneClass) o.paneClass = defaults.paneClass;
 901+ if (!o.resizerClass) o.resizerClass = defaults.resizerClass;
 902+ if (!o.togglerClass) o.togglerClass = defaults.togglerClass;
 903+
 904+ // create FINAL fx options for each pane, ie: options.PANE.fxName/fxSpeed/fxSettings[_open|_close]
 905+ $.each(["_open","_close",""], function (i,n) {
 906+ var
 907+ sName = "fxName"+n
 908+ , sSpeed = "fxSpeed"+n
 909+ , sSettings = "fxSettings"+n
 910+ ;
 911+ // recalculate fxName according to specificity rules
 912+ o[sName] =
 913+ opts[pane][sName] // opts.west.fxName_open
 914+ || opts[pane].fxName // opts.west.fxName
 915+ || opts.defaults[sName] // opts.defaults.fxName_open
 916+ || opts.defaults.fxName // opts.defaults.fxName
 917+ || o[sName] // options.west.fxName_open
 918+ || o.fxName // options.west.fxName
 919+ || defs[sName] // options.defaults.fxName_open
 920+ || defs.fxName // options.defaults.fxName
 921+ || "none"
 922+ ;
 923+ // validate fxName to be sure is a valid effect
 924+ var fxName = o[sName];
 925+ if (fxName == "none" || !$.effects || !$.effects[fxName] || (!effects[fxName] && !o[sSettings] && !o.fxSettings))
 926+ fxName = o[sName] = "none"; // effect not loaded, OR undefined FX AND fxSettings not passed
 927+ // set vars for effects subkeys to simplify logic
 928+ var
 929+ fx = effects[fxName] || {} // effects.slide
 930+ , fx_all = fx.all || {} // effects.slide.all
 931+ , fx_pane = fx[pane] || {} // effects.slide.west
 932+ ;
 933+ // RECREATE the fxSettings[_open|_close] keys using specificity rules
 934+ o[sSettings] = $.extend(
 935+ {}
 936+ , fx_all // effects.slide.all
 937+ , fx_pane // effects.slide.west
 938+ , defs.fxSettings || {} // options.defaults.fxSettings
 939+ , defs[sSettings] || {} // options.defaults.fxSettings_open
 940+ , o.fxSettings // options.west.fxSettings
 941+ , o[sSettings] // options.west.fxSettings_open
 942+ , opts.defaults.fxSettings // opts.defaults.fxSettings
 943+ , opts.defaults[sSettings] || {} // opts.defaults.fxSettings_open
 944+ , opts[pane].fxSettings // opts.west.fxSettings
 945+ , opts[pane][sSettings] || {} // opts.west.fxSettings_open
 946+ );
 947+ // recalculate fxSpeed according to specificity rules
 948+ o[sSpeed] =
 949+ opts[pane][sSpeed] // opts.west.fxSpeed_open
 950+ || opts[pane].fxSpeed // opts.west.fxSpeed (pane-default)
 951+ || opts.defaults[sSpeed] // opts.defaults.fxSpeed_open
 952+ || opts.defaults.fxSpeed // opts.defaults.fxSpeed
 953+ || o[sSpeed] // options.west.fxSpeed_open
 954+ || o[sSettings].duration // options.west.fxSettings_open.duration
 955+ || o.fxSpeed // options.west.fxSpeed
 956+ || o.fxSettings.duration // options.west.fxSettings.duration
 957+ || defs.fxSpeed // options.defaults.fxSpeed
 958+ || defs.fxSettings.duration// options.defaults.fxSettings.duration
 959+ || fx_pane.duration // effects.slide.west.duration
 960+ || fx_all.duration // effects.slide.all.duration
 961+ || "normal" // DEFAULT
 962+ ;
 963+ // DEBUG: if (pane=="east") debugData( $.extend({}, {speed: o[sSpeed], fxSettings_duration: o[sSettings].duration}, o[sSettings]), pane+"."+sName+" = "+fxName );
 964+ });
 965+ });
 966+ };
 967+
 968+ /**
 969+ * initPanes
 970+ *
 971+ * Initialize module objects, styling, size and position for all panes
 972+ *
 973+ * @callers create()
 974+ */
 975+ var initPanes = function () {
 976+ // NOTE: do north & south FIRST so we can measure their height - do center LAST
 977+ $.each(c.allPanes.split(","), function() {
 978+ var
 979+ pane = str(this)
 980+ , o = options[pane]
 981+ , s = state[pane]
 982+ , fx = s.fx
 983+ , dir = c[pane].dir
 984+ // if o.size is not > 0, then we will use MEASURE the pane and use that as it's 'size'
 985+ , size = o.size=="auto" || isNaN(o.size) ? 0 : o.size
 986+ , minSize = o.minSize || 1
 987+ , maxSize = o.maxSize || 9999
 988+ , spacing = o.spacing_open || 0
 989+ , sel = o.paneSelector
 990+ , isIE6 = ($.browser.msie && $.browser.version < 7)
 991+ , CSS = {}
 992+ , $P, $C
 993+ ;
 994+ $Cs[pane] = false; // init
 995+
 996+ if (sel.substr(0,1)==="#") // ID selector
 997+ // NOTE: elements selected 'by ID' DO NOT have to be 'children'
 998+ $P = $Ps[pane] = $Container.find(sel+":first");
 999+ else { // class or other selector
 1000+ $P = $Ps[pane] = $Container.children(sel+":first");
 1001+ // look for the pane nested inside a 'form' element
 1002+ if (!$P.length) $P = $Ps[pane] = $Container.children("form:first").children(sel+":first");
 1003+ }
 1004+
 1005+ if (!$P.length) {
 1006+ $Ps[pane] = false; // logic
 1007+ return true; // SKIP to next
 1008+ }
 1009+
 1010+ // add basic classes & attributes
 1011+ $P
 1012+ .attr("pane", pane) // add pane-identifier
 1013+ .addClass( o.paneClass +" "+ o.paneClass+"-"+pane ) // default = "ui-layout-pane ui-layout-pane-west" - may be a dupe of 'paneSelector'
 1014+ ;
 1015+
 1016+ // init pane-logic vars, etc.
 1017+ if (pane != "center") {
 1018+ s.isClosed = false; // true = pane is closed
 1019+ s.isSliding = false; // true = pane is currently open by 'sliding' over adjacent panes
 1020+ s.isResizing= false; // true = pane is in process of being resized
 1021+ s.isHidden = false; // true = pane is hidden - no spacing, resizer or toggler is visible!
 1022+ s.noRoom = false; // true = pane 'automatically' hidden due to insufficient room - will unhide automatically
 1023+ // create special keys for internal use
 1024+ c[pane].pins = []; // used to track and sync 'pin-buttons' for border-panes
 1025+ }
 1026+
 1027+ CSS = $.extend({ visibility: "visible", display: "block" }, c.defaults.cssReq, c[pane].cssReq );
 1028+ if (o.applyDefaultStyles) $.extend( CSS, c.defaults.cssDef, c[pane].cssDef ); // cosmetic defaults
 1029+ $P.css(CSS); // add base-css BEFORE 'measuring' to calc size & position
 1030+ CSS = {}; // reset var
 1031+
 1032+ // set css-position to account for container borders & padding
 1033+ switch (pane) {
 1034+ case "north": CSS.top = cDims.top;
 1035+ CSS.left = cDims.left;
 1036+ CSS.right = cDims.right;
 1037+ break;
 1038+ case "south": CSS.bottom = cDims.bottom;
 1039+ CSS.left = cDims.left;
 1040+ CSS.right = cDims.right;
 1041+ break;
 1042+ case "west": CSS.left = cDims.left; // top, bottom & height set by sizeMidPanes()
 1043+ break;
 1044+ case "east": CSS.right = cDims.right; // ditto
 1045+ break;
 1046+ case "center": // top, left, width & height set by sizeMidPanes()
 1047+ }
 1048+
 1049+ if (dir == "horz") { // north or south pane
 1050+ if (size === 0 || size == "auto") {
 1051+ $P.css({ height: "auto" });
 1052+ size = $P.outerHeight();
 1053+ }
 1054+ size = max(size, minSize);
 1055+ size = min(size, maxSize);
 1056+ size = min(size, cDims.innerHeight - spacing);
 1057+ CSS.height = max(1, cssH(pane, size));
 1058+ s.size = size; // update state
 1059+ // make sure minSize is sufficient to avoid errors
 1060+ s.maxSize = maxSize; // init value
 1061+ s.minSize = max(minSize, size - CSS.height + 1); // = pane.outerHeight when css.height = 1px
 1062+ // handle IE6
 1063+ //if (isIE6) CSS.width = cssW($P, cDims.innerWidth);
 1064+ $P.css(CSS); // apply size & position
 1065+ }
 1066+ else if (dir == "vert") { // east or west pane
 1067+ if (size === 0 || size == "auto") {
 1068+ $P.css({ width: "auto", float: "left" }); // float = FORCE pane to auto-size
 1069+ size = $P.outerWidth();
 1070+ $P.css({ float: "none" }); // RESET
 1071+ }
 1072+ size = max(size, minSize);
 1073+ size = min(size, maxSize);
 1074+ size = min(size, cDims.innerWidth - spacing);
 1075+ CSS.width = max(1, cssW(pane, size));
 1076+ s.size = size; // update state
 1077+ s.maxSize = maxSize; // init value
 1078+ // make sure minSize is sufficient to avoid errors
 1079+ s.minSize = max(minSize, size - CSS.width + 1); // = pane.outerWidth when css.width = 1px
 1080+ $P.css(CSS); // apply size - top, bottom & height set by sizeMidPanes
 1081+ sizeMidPanes(pane, null, true); // true = onInit
 1082+ }
 1083+ else if (pane == "center") {
 1084+ $P.css(CSS); // top, left, width & height set by sizeMidPanes...
 1085+ sizeMidPanes("center", null, true); // true = onInit
 1086+ }
 1087+
 1088+ // close or hide the pane if specified in settings
 1089+ if (o.initClosed && o.closable) {
 1090+ $P.hide().addClass("closed");
 1091+ s.isClosed = true;
 1092+ }
 1093+ else if (o.initHidden || o.initClosed) {
 1094+ hide(pane, true); // will be completely invisible - no resizer or spacing
 1095+ s.isHidden = true;
 1096+ }
 1097+ else
 1098+ $P.addClass("open");
 1099+
 1100+ // check option for auto-handling of pop-ups & drop-downs
 1101+ if (o.showOverflowOnHover)
 1102+ $P.hover( allowOverflow, resetOverflow );
 1103+
 1104+ /*
 1105+ * see if this pane has a 'content element' that we need to auto-size
 1106+ */
 1107+ if (o.contentSelector) {
 1108+ $C = $Cs[pane] = $P.children(o.contentSelector+":first"); // match 1-element only
 1109+ if (!$C.length) {
 1110+ $Cs[pane] = false;
 1111+ return true; // SKIP to next
 1112+ }
 1113+ $C.css( c.content.cssReq );
 1114+ if (o.applyDefaultStyles) $C.css( c.content.cssDef ); // cosmetic defaults
 1115+ // NO PANE-SCROLLING when there is a content-div
 1116+ $P.css({ overflow: "hidden" });
 1117+ }
 1118+ });
 1119+ };
 1120+
 1121+ /**
 1122+ * initHandles
 1123+ *
 1124+ * Initialize module objects, styling, size and position for all resize bars and toggler buttons
 1125+ *
 1126+ * @callers create()
 1127+ */
 1128+ var initHandles = function () {
 1129+ // create toggler DIVs for each pane, and set object pointers for them, eg: $R.north = north toggler DIV
 1130+ $.each(c.borderPanes.split(","), function() {
 1131+ var
 1132+ pane = str(this)
 1133+ , o = options[pane]
 1134+ , s = state[pane]
 1135+ , rClass = o.resizerClass
 1136+ , tClass = o.togglerClass
 1137+ , $P = $Ps[pane]
 1138+ ;
 1139+ $Rs[pane] = false; // INIT
 1140+ $Ts[pane] = false;
 1141+
 1142+ if (!$P || (!o.closable && !o.resizable)) return; // pane does not exist - skip
 1143+
 1144+ var
 1145+ edge = c[pane].edge
 1146+ , isOpen = $P.is(":visible")
 1147+ , spacing = (isOpen ? o.spacing_open : o.spacing_closed)
 1148+ , _pane = "-"+ pane // used for classNames
 1149+ , _state = (isOpen ? "-open" : "-closed") // used for classNames
 1150+ , $R, $T
 1151+ ;
 1152+ // INIT RESIZER BAR
 1153+ $R = $Rs[pane] = $("<span></span>");
 1154+
 1155+ if (isOpen && o.resizable)
 1156+ ; // this is handled by initResizable
 1157+ else if (!isOpen && o.slidable)
 1158+ $R.attr("title", o.sliderTip).css("cursor", o.sliderCursor);
 1159+
 1160+ $R
 1161+ // if paneSelector is an ID, then create a matching ID for the resizer, eg: "#paneLeft" => "paneLeft-resizer"
 1162+ .attr("id", (o.paneSelector.substr(0,1)=="#" ? o.paneSelector.substr(1) + "-resizer" : ""))
 1163+ .attr("resizer", pane) // so we can read this from the resizer
 1164+ .css(c.resizers.cssReq) // add base/required styles
 1165+ // POSITION of resizer bar - allow for container border & padding
 1166+ .css(edge, cDims[edge] + getPaneSize(pane))
 1167+ // ADD CLASSNAMES - eg: class="resizer resizer-west resizer-open"
 1168+ .addClass( rClass +" "+ rClass+_pane +" "+ rClass+_state +" "+ rClass+_pane+_state )
 1169+ .appendTo($Container) // append DIV to container
 1170+ ;
 1171+ // ADD VISUAL STYLES
 1172+ if (o.applyDefaultStyles)
 1173+ $R.css(c.resizers.cssDef);
 1174+
 1175+ if (o.closable) {
 1176+ // INIT COLLAPSER BUTTON
 1177+ $T = $Ts[pane] = $("<div></div>");
 1178+ $T
 1179+ // if paneSelector is an ID, then create a matching ID for the resizer, eg: "#paneLeft" => "paneLeft-toggler"
 1180+ .attr("id", (o.paneSelector.substr(0,1)=="#" ? o.paneSelector.substr(1) + "-toggler" : ""))
 1181+ .css(c.togglers.cssReq) // add base/required styles
 1182+ .attr("title", (isOpen ? o.togglerTip_open : o.togglerTip_closed))
 1183+ .click(function(evt){ toggle(pane); evt.stopPropagation(); })
 1184+ .mouseover(function(evt){ evt.stopPropagation(); }) // prevent resizer event
 1185+ // ADD CLASSNAMES - eg: class="toggler toggler-west toggler-west-open"
 1186+ .addClass( tClass +" "+ tClass+_pane +" "+ tClass+_state +" "+ tClass+_pane+_state )
 1187+ .appendTo($R) // append SPAN to resizer DIV
 1188+ ;
 1189+
 1190+ // ADD INNER-SPANS TO TOGGLER
 1191+ if (o.togglerContent_open) // ui-layout-open
 1192+ $("<span>"+ o.togglerContent_open +"</span>")
 1193+ .addClass("content content-open")
 1194+ .css("display", s.isClosed ? "none" : "block")
 1195+ .appendTo( $T )
 1196+ ;
 1197+ if (o.togglerContent_closed) // ui-layout-closed
 1198+ $("<span>"+ o.togglerContent_closed +"</span>")
 1199+ .addClass("content content-closed")
 1200+ .css("display", s.isClosed ? "block" : "none")
 1201+ .appendTo( $T )
 1202+ ;
 1203+
 1204+ // ADD BASIC VISUAL STYLES
 1205+ if (o.applyDefaultStyles)
 1206+ $T.css(c.togglers.cssDef);
 1207+
 1208+ if (!isOpen) bindStartSlidingEvent(pane, true); // will enable if state.PANE.isSliding = true
 1209+ }
 1210+
 1211+ });
 1212+
 1213+ // SET ALL HANDLE SIZES & LENGTHS
 1214+ sizeHandles("all", true); // true = onInit
 1215+ };
 1216+
 1217+ /**
 1218+ * initResizable
 1219+ *
 1220+ * Add resize-bars to all panes that specify it in options
 1221+ *
 1222+ * @dependancies $.fn.resizable - will abort if not found
 1223+ * @callers create()
 1224+ */
 1225+ var initResizable = function () {
 1226+ var
 1227+ draggingAvailable = (typeof $.fn.draggable == "function")
 1228+ , minPosition, maxPosition, edge // set in start()
 1229+ ;
 1230+
 1231+ $.each(c.borderPanes.split(","), function() {
 1232+ var
 1233+ pane = str(this)
 1234+ , o = options[pane]
 1235+ , s = state[pane]
 1236+ ;
 1237+ if (!draggingAvailable || !$Ps[pane] || !o.resizable) {
 1238+ o.resizable = false;
 1239+ return true; // skip to next
 1240+ }
 1241+
 1242+ var
 1243+ rClass = o.resizerClass
 1244+ // 'drag' classes are applied to the ORIGINAL resizer-bar while dragging is in process
 1245+ , dragClass = rClass+"-drag" // resizer-drag
 1246+ , dragPaneClass = rClass+"-"+pane+"-drag" // resizer-north-drag
 1247+ // 'dragging' class is applied to the CLONED resizer-bar while it is being dragged
 1248+ , draggingClass = rClass+"-dragging" // resizer-dragging
 1249+ , draggingPaneClass = rClass+"-"+pane+"-dragging" // resizer-north-dragging
 1250+ , draggingClassSet = false // logic var
 1251+ , $P = $Ps[pane]
 1252+ , $R = $Rs[pane]
 1253+ ;
 1254+
 1255+ if (!s.isClosed)
 1256+ $R
 1257+ .attr("title", o.resizerTip)
 1258+ .css("cursor", o.resizerCursor) // n-resize, s-resize, etc
 1259+ ;
 1260+
 1261+ $R.draggable({
 1262+ containment: $Container[0] // limit resizing to layout container
 1263+ , axis: (c[pane].dir=="horz" ? "y" : "x") // limit resizing to horz or vert axis
 1264+ , delay: 200
 1265+ , distance: 1
 1266+ // basic format for helper - style it using class: .ui-draggable-dragging
 1267+ , helper: "clone"
 1268+ , opacity: o.resizerDragOpacity
 1269+ //, iframeFix: o.draggableIframeFix // TODO: consider using when bug is fixed
 1270+ , zIndex: c.zIndex.resizing
 1271+
 1272+ , start: function (e, ui) {
 1273+ // onresize_start callback - will CANCEL hide if returns false
 1274+ // TODO: CONFIRM that dragging can be cancelled like this???
 1275+ if (false === execUserCallback(pane, o.onresize_start)) return false;
 1276+
 1277+ s.isResizing = true; // prevent pane from closing while resizing
 1278+ clearTimer(pane, "closeSlider"); // just in case already triggered
 1279+
 1280+ $R.addClass( dragClass +" "+ dragPaneClass ); // add drag classes
 1281+ draggingClassSet = false; // reset logic var - see drag()
 1282+
 1283+ // SET RESIZING LIMITS - used in drag()
 1284+ var resizerWidth = (pane=="east" || pane=="south" ? o.spacing_open : 0);
 1285+ setPaneMinMaxSizes(pane); // update pane-state
 1286+ s.minPosition -= resizerWidth;
 1287+ s.maxPosition -= resizerWidth;
 1288+ edge = (c[pane].dir=="horz" ? "top" : "left");
 1289+
 1290+ // MASK PANES WITH IFRAMES OR OTHER TROUBLESOME ELEMENTS
 1291+ $(o.maskIframesOnResize === true ? "iframe" : o.maskIframesOnResize).each(function() {
 1292+ $('<div class="ui-layout-mask"/>')
 1293+ .css({
 1294+ background: "#fff"
 1295+ , opacity: "0.001"
 1296+ , zIndex: 9
 1297+ , position: "absolute"
 1298+ , width: this.offsetWidth+"px"
 1299+ , height: this.offsetHeight+"px"
 1300+ })
 1301+ .css($(this).offset()) // top & left
 1302+ .appendTo(this.parentNode) // put div INSIDE pane to avoid zIndex issues
 1303+ ;
 1304+ });
 1305+ }
 1306+
 1307+ , drag: function (e, ui) {
 1308+ if (!draggingClassSet) { // can only add classes after clone has been added to the DOM
 1309+ $(".ui-draggable-dragging")
 1310+ .addClass( draggingClass +" "+ draggingPaneClass ) // add dragging classes
 1311+ .children().css("visibility","hidden") // hide toggler inside dragged resizer-bar
 1312+ ;
 1313+ draggingClassSet = true;
 1314+ // draggable bug!? RE-SET zIndex to prevent E/W resize-bar showing through N/S pane!
 1315+ if (s.isSliding) $Ps[pane].css("zIndex", c.zIndex.sliding);
 1316+ }
 1317+ // CONTAIN RESIZER-BAR TO RESIZING LIMITS
 1318+ if (ui.position[edge] < s.minPosition) ui.position[edge] = s.minPosition;
 1319+ else if (ui.position[edge] > s.maxPosition) ui.position[edge] = s.maxPosition;
 1320+ }
 1321+
 1322+ , stop: function (e, ui) {
 1323+ var
 1324+ dragPos = ui.position
 1325+ , resizerPos
 1326+ , newSize
 1327+ ;
 1328+ $R.removeClass( dragClass +" "+ dragPaneClass ); // remove drag classes
 1329+
 1330+ switch (pane) {
 1331+ case "north": resizerPos = dragPos.top; break;
 1332+ case "west": resizerPos = dragPos.left; break;
 1333+ case "south": resizerPos = cDims.outerHeight - dragPos.top - $R.outerHeight(); break;
 1334+ case "east": resizerPos = cDims.outerWidth - dragPos.left - $R.outerWidth(); break;
 1335+ }
 1336+ // remove container margin from resizer position to get the pane size
 1337+ newSize = resizerPos - cDims[ c[pane].edge ];
 1338+
 1339+ sizePane(pane, newSize);
 1340+
 1341+ // UN-MASK PANES MASKED IN drag.start
 1342+ $("div.ui-layout-mask").remove(); // Remove iframe masks
 1343+
 1344+ s.isResizing = false;
 1345+ }
 1346+
 1347+ });
 1348+ });
 1349+ };
 1350+
 1351+
 1352+
 1353+/*
 1354+ * ###########################
 1355+ * ACTION METHODS
 1356+ * ###########################
 1357+ */
 1358+
 1359+ /**
 1360+ * hide / show
 1361+ *
 1362+ * Completely 'hides' a pane, including its spacing - as if it does not exist
 1363+ * The pane is not actually 'removed' from the source, so can use 'show' to un-hide it
 1364+ *
 1365+ * @param String pane The pane being hidden, ie: north, south, east, or west
 1366+ */
 1367+ var hide = function (pane, onInit) {
 1368+ var
 1369+ o = options[pane]
 1370+ , s = state[pane]
 1371+ , $P = $Ps[pane]
 1372+ , $R = $Rs[pane]
 1373+ ;
 1374+ if (!$P || s.isHidden) return; // pane does not exist OR is already hidden
 1375+
 1376+ // onhide_start callback - will CANCEL hide if returns false
 1377+ if (false === execUserCallback(pane, o.onhide_start)) return;
 1378+
 1379+ s.isSliding = false; // just in case
 1380+
 1381+ // now hide the elements
 1382+ if ($R) $R.hide(); // hide resizer-bar
 1383+ if (onInit || s.isClosed) {
 1384+ s.isClosed = true; // to trigger open-animation on show()
 1385+ s.isHidden = true;
 1386+ $P.hide(); // no animation when loading page
 1387+ sizeMidPanes(c[pane].dir == "horz" ? "all" : "center");
 1388+ execUserCallback(pane, o.onhide_end || o.onhide);
 1389+ }
 1390+ else {
 1391+ s.isHiding = true; // used by onclose
 1392+ close(pane, false); // adjust all panes to fit
 1393+ //s.isHidden = true; - will be set by close - if not cancelled
 1394+ }
 1395+ };
 1396+
 1397+ var show = function (pane, openPane) {
 1398+ var
 1399+ o = options[pane]
 1400+ , s = state[pane]
 1401+ , $P = $Ps[pane]
 1402+ , $R = $Rs[pane]
 1403+ ;
 1404+ if (!$P || !s.isHidden) return; // pane does not exist OR is not hidden
 1405+
 1406+ // onhide_start callback - will CANCEL hide if returns false
 1407+ if (false === execUserCallback(pane, o.onshow_start)) return;
 1408+
 1409+ s.isSliding = false; // just in case
 1410+ s.isShowing = true; // used by onopen/onclose
 1411+ //s.isHidden = false; - will be set by open/close - if not cancelled
 1412+
 1413+ // now show the elements
 1414+ if ($R && o.spacing_open > 0) $R.show();
 1415+ if (openPane === false)
 1416+ close(pane, true); // true = force
 1417+ else
 1418+ open(pane); // adjust all panes to fit
 1419+ };
 1420+
 1421+
 1422+ /**
 1423+ * toggle
 1424+ *
 1425+ * Toggles a pane open/closed by calling either open or close
 1426+ *
 1427+ * @param String pane The pane being toggled, ie: north, south, east, or west
 1428+ */
 1429+ var toggle = function (pane) {
 1430+ var s = state[pane];
 1431+ if (s.isHidden)
 1432+ show(pane); // will call 'open' after unhiding it
 1433+ else if (s.isClosed)
 1434+ open(pane);
 1435+ else
 1436+ close(pane);
 1437+ };
 1438+
 1439+ /**
 1440+ * close
 1441+ *
 1442+ * Close the specified pane (animation optional), and resize all other panes as needed
 1443+ *
 1444+ * @param String pane The pane being closed, ie: north, south, east, or west
 1445+ */
 1446+ var close = function (pane, force, noAnimation) {
 1447+ var
 1448+ $P = $Ps[pane]
 1449+ , $R = $Rs[pane]
 1450+ , $T = $Ts[pane]
 1451+ , o = options[pane]
 1452+ , s = state[pane]
 1453+ , doFX = !noAnimation && !s.isClosed && (o.fxName_close != "none")
 1454+ , edge = c[pane].edge
 1455+ , rClass = o.resizerClass
 1456+ , tClass = o.togglerClass
 1457+ , _pane = "-"+ pane // used for classNames
 1458+ , _open = "-open"
 1459+ , _sliding= "-sliding"
 1460+ , _closed = "-closed"
 1461+ // transfer logic vars to temp vars
 1462+ , isShowing = s.isShowing
 1463+ , isHiding = s.isHiding
 1464+ ;
 1465+ // now clear the logic vars
 1466+ delete s.isShowing;
 1467+ delete s.isHiding;
 1468+
 1469+ if (!$P || (!o.resizable && !o.closable)) return; // invalid request
 1470+ else if (!force && s.isClosed && !isShowing) return; // already closed
 1471+
 1472+ if (c.isLayoutBusy) { // layout is 'busy' - probably with an animation
 1473+ setFlowCallback("close", pane, force); // set a callback for this action, if possible
 1474+ return; // ABORT
 1475+ }
 1476+
 1477+ // onclose_start callback - will CANCEL hide if returns false
 1478+ // SKIP if just 'showing' a hidden pane as 'closed'
 1479+ if (!isShowing && false === execUserCallback(pane, o.onclose_start)) return;
 1480+
 1481+ // SET flow-control flags
 1482+ c[pane].isMoving = true;
 1483+ c.isLayoutBusy = true;
 1484+
 1485+ s.isClosed = true;
 1486+ // update isHidden BEFORE sizing panes
 1487+ if (isHiding) s.isHidden = true;
 1488+ else if (isShowing) s.isHidden = false;
 1489+
 1490+ // sync any 'pin buttons'
 1491+ syncPinBtns(pane, false);
 1492+
 1493+ // resize panes adjacent to this one
 1494+ if (!s.isSliding) sizeMidPanes(c[pane].dir == "horz" ? "all" : "center");
 1495+
 1496+ // if this pane has a resizer bar, move it now
 1497+ if ($R) {
 1498+ $R
 1499+ .css(edge, cDims[edge]) // move the resizer bar
 1500+ .removeClass( rClass+_open +" "+ rClass+_pane+_open )
 1501+ .removeClass( rClass+_sliding +" "+ rClass+_pane+_sliding )
 1502+ .addClass( rClass+_closed +" "+ rClass+_pane+_closed )
 1503+ ;
 1504+ // DISABLE 'resizing' when closed - do this BEFORE bindStartSlidingEvent
 1505+ if (o.resizable)
 1506+ $R
 1507+ .draggable("disable")
 1508+ .css("cursor", "default")
 1509+ .attr("title","")
 1510+ ;
 1511+ // if pane has a toggler button, adjust that too
 1512+ if ($T) {
 1513+ $T
 1514+ .removeClass( tClass+_open +" "+ tClass+_pane+_open )
 1515+ .addClass( tClass+_closed +" "+ tClass+_pane+_closed )
 1516+ .attr("title", o.togglerTip_closed) // may be blank
 1517+ ;
 1518+ }
 1519+ sizeHandles(); // resize 'length' and position togglers for adjacent panes
 1520+ }
 1521+
 1522+ // ANIMATE 'CLOSE' - if no animation, then was ALREADY shown above
 1523+ if (doFX) {
 1524+ lockPaneForFX(pane, true); // need to set left/top so animation will work
 1525+ $P.hide( o.fxName_close, o.fxSettings_close, o.fxSpeed_close, function () {
 1526+ lockPaneForFX(pane, false); // undo
 1527+ if (!s.isClosed) return; // pane was opened before animation finished!
 1528+ close_2();
 1529+ });
 1530+ }
 1531+ else {
 1532+ $P.hide(); // just hide pane NOW
 1533+ close_2();
 1534+ }
 1535+
 1536+ // SUBROUTINE
 1537+ function close_2 () {
 1538+ bindStartSlidingEvent(pane, true); // will enable if state.PANE.isSliding = true
 1539+
 1540+ // onclose callback - UNLESS just 'showing' a hidden pane as 'closed'
 1541+ if (!isShowing) execUserCallback(pane, o.onclose_end || o.onclose);
 1542+ // onhide OR onshow callback
 1543+ if (isShowing) execUserCallback(pane, o.onshow_end || o.onshow);
 1544+ if (isHiding) execUserCallback(pane, o.onhide_end || o.onhide);
 1545+
 1546+ // internal flow-control callback
 1547+ execFlowCallback(pane);
 1548+ }
 1549+ };
 1550+
 1551+ /**
 1552+ * open
 1553+ *
 1554+ * Open the specified pane (animation optional), and resize all other panes as needed
 1555+ *
 1556+ * @param String pane The pane being opened, ie: north, south, east, or west
 1557+ */
 1558+ var open = function (pane, slide, noAnimation) {
 1559+ var
 1560+ $P = $Ps[pane]
 1561+ , $R = $Rs[pane]
 1562+ , $T = $Ts[pane]
 1563+ , o = options[pane]
 1564+ , s = state[pane]
 1565+ , doFX = !noAnimation && s.isClosed && (o.fxName_open != "none")
 1566+ , edge = c[pane].edge
 1567+ , rClass = o.resizerClass
 1568+ , tClass = o.togglerClass
 1569+ , _pane = "-"+ pane // used for classNames
 1570+ , _open = "-open"
 1571+ , _closed = "-closed"
 1572+ , _sliding= "-sliding"
 1573+ // transfer logic var to temp var
 1574+ , isShowing = s.isShowing
 1575+ ;
 1576+ // now clear the logic var
 1577+ delete s.isShowing;
 1578+
 1579+ if (!$P || (!o.resizable && !o.closable)) return; // invalid request
 1580+ else if (!s.isClosed && !s.isSliding) return; // already open
 1581+
 1582+ // pane can ALSO be unhidden by just calling show(), so handle this scenario
 1583+ if (s.isHidden && !isShowing) {
 1584+ show(pane, true);
 1585+ return;
 1586+ }
 1587+
 1588+ if (c.isLayoutBusy) { // layout is 'busy' - probably with an animation
 1589+ setFlowCallback("open", pane, slide); // set a callback for this action, if possible
 1590+ return; // ABORT
 1591+ }
 1592+
 1593+ // onopen_start callback - will CANCEL hide if returns false
 1594+ if (false === execUserCallback(pane, o.onopen_start)) return;
 1595+
 1596+ // SET flow-control flags
 1597+ c[pane].isMoving = true;
 1598+ c.isLayoutBusy = true;
 1599+
 1600+ // 'PIN PANE' - stop sliding
 1601+ if (s.isSliding && !slide) // !slide = 'open pane normally' - NOT sliding
 1602+ bindStopSlidingEvents(pane, false); // will set isSliding=false
 1603+
 1604+ s.isClosed = false;
 1605+ // update isHidden BEFORE sizing panes
 1606+ if (isShowing) s.isHidden = false;
 1607+
 1608+ // Container size may have changed - shrink the pane if now 'too big'
 1609+ setPaneMinMaxSizes(pane); // update pane-state
 1610+ if (s.size > s.maxSize) // pane is too big! resize it before opening
 1611+ $P.css( c[pane].sizeType, max(1, cssSize(pane, s.maxSize)) );
 1612+
 1613+ bindStartSlidingEvent(pane, false); // remove trigger event from resizer-bar
 1614+
 1615+ if (doFX) { // ANIMATE
 1616+ lockPaneForFX(pane, true); // need to set left/top so animation will work
 1617+ $P.show( o.fxName_open, o.fxSettings_open, o.fxSpeed_open, function() {
 1618+ lockPaneForFX(pane, false); // undo
 1619+ if (s.isClosed) return; // pane was closed before animation finished!
 1620+ open_2(); // continue
 1621+ });
 1622+ }
 1623+ else {// no animation
 1624+ $P.show(); // just show pane and...
 1625+ open_2(); // continue
 1626+ }
 1627+
 1628+ // SUBROUTINE
 1629+ function open_2 () {
 1630+ // NOTE: if isSliding, then other panes are NOT 'resized'
 1631+ if (!s.isSliding) // resize all panes adjacent to this one
 1632+ sizeMidPanes(c[pane].dir=="vert" ? "center" : "all");
 1633+
 1634+ // if this pane has a toggler, move it now
 1635+ if ($R) {
 1636+ $R
 1637+ .css(edge, cDims[edge] + getPaneSize(pane)) // move the toggler
 1638+ .removeClass( rClass+_closed +" "+ rClass+_pane+_closed )
 1639+ .addClass( rClass+_open +" "+ rClass+_pane+_open )
 1640+ .addClass( !s.isSliding ? "" : rClass+_sliding +" "+ rClass+_pane+_sliding )
 1641+ ;
 1642+ if (o.resizable)
 1643+ $R
 1644+ .draggable("enable")
 1645+ .css("cursor", o.resizerCursor)
 1646+ .attr("title", o.resizerTip)
 1647+ ;
 1648+ else
 1649+ $R.css("cursor", "default"); // n-resize, s-resize, etc
 1650+ // if pane also has a toggler button, adjust that too
 1651+ if ($T) {
 1652+ $T
 1653+ .removeClass( tClass+_closed +" "+ tClass+_pane+_closed )
 1654+ .addClass( tClass+_open +" "+ tClass+_pane+_open )
 1655+ .attr("title", o.togglerTip_open) // may be blank
 1656+ ;
 1657+ }
 1658+ sizeHandles("all"); // resize resizer & toggler sizes for all panes
 1659+ }
 1660+
 1661+ // resize content every time pane opens - to be sure
 1662+ sizeContent(pane);
 1663+
 1664+ // sync any 'pin buttons'
 1665+ syncPinBtns(pane, !s.isSliding);
 1666+
 1667+ // onopen callback
 1668+ execUserCallback(pane, o.onopen_end || o.onopen);
 1669+
 1670+ // onshow callback
 1671+ if (isShowing) execUserCallback(pane, o.onshow_end || o.onshow);
 1672+
 1673+ // internal flow-control callback
 1674+ execFlowCallback(pane);
 1675+ }
 1676+ };
 1677+
 1678+
 1679+ /**
 1680+ * lockPaneForFX
 1681+ *
 1682+ * Must set left/top on East/South panes so animation will work properly
 1683+ *
 1684+ * @param String pane The pane to lock, 'east' or 'south' - any other is ignored!
 1685+ * @param Boolean doLock true = set left/top, false = remove
 1686+ */
 1687+ var lockPaneForFX = function (pane, doLock) {
 1688+ var $P = $Ps[pane];
 1689+ if (doLock) {
 1690+ $P.css({ zIndex: c.zIndex.animation }); // overlay all elements during animation
 1691+ if (pane=="south")
 1692+ $P.css({ top: cDims.top + cDims.innerHeight - $P.outerHeight() });
 1693+ else if (pane=="east")
 1694+ $P.css({ left: cDims.left + cDims.innerWidth - $P.outerWidth() });
 1695+ }
 1696+ else {
 1697+ if (!state[pane].isSliding) $P.css({ zIndex: c.zIndex.pane_normal });
 1698+ if (pane=="south")
 1699+ $P.css({ top: "auto" });
 1700+ else if (pane=="east")
 1701+ $P.css({ left: "auto" });
 1702+ }
 1703+ };
 1704+
 1705+
 1706+ /**
 1707+ * bindStartSlidingEvent
 1708+ *
 1709+ * Toggle sliding functionality of a specific pane on/off by adding removing 'slide open' trigger
 1710+ *
 1711+ * @callers open(), close()
 1712+ * @param String pane The pane to enable/disable, 'north', 'south', etc.
 1713+ * @param Boolean enable Enable or Disable sliding?
 1714+ */
 1715+ var bindStartSlidingEvent = function (pane, enable) {
 1716+ var
 1717+ o = options[pane]
 1718+ , $R = $Rs[pane]
 1719+ , trigger = o.slideTrigger_open
 1720+ ;
 1721+ if (!$R || !o.slidable) return;
 1722+ // make sure we have a valid event
 1723+ if (trigger != "click" && trigger != "dblclick" && trigger != "mouseover") trigger = "click";
 1724+ $R
 1725+ // add or remove trigger event
 1726+ [enable ? "bind" : "unbind"](trigger, slideOpen)
 1727+ // set the appropriate cursor & title/tip
 1728+ .css("cursor", (enable ? o.sliderCursor: "default"))
 1729+ .attr("title", (enable ? o.sliderTip : ""))
 1730+ ;
 1731+ };
 1732+
 1733+ /**
 1734+ * bindStopSlidingEvents
 1735+ *
 1736+ * Add or remove 'mouseout' events to 'slide close' when pane is 'sliding' open or closed
 1737+ * Also increases zIndex when pane is sliding open
 1738+ * See bindStartSlidingEvent for code to control 'slide open'
 1739+ *
 1740+ * @callers slideOpen(), slideClosed()
 1741+ * @param String pane The pane to process, 'north', 'south', etc.
 1742+ * @param Boolean isOpen Is pane open or closed?
 1743+ */
 1744+ var bindStopSlidingEvents = function (pane, enable) {
 1745+ var
 1746+ o = options[pane]
 1747+ , s = state[pane]
 1748+ , trigger = o.slideTrigger_close
 1749+ , action = (enable ? "bind" : "unbind") // can't make 'unbind' work! - see disabled code below
 1750+ , $P = $Ps[pane]
 1751+ , $R = $Rs[pane]
 1752+ ;
 1753+
 1754+ s.isSliding = enable; // logic
 1755+ clearTimer(pane, "closeSlider"); // just in case
 1756+
 1757+ // raise z-index when sliding
 1758+ $P.css({ zIndex: (enable ? c.zIndex.sliding : c.zIndex.pane_normal) });
 1759+ $R.css({ zIndex: (enable ? c.zIndex.sliding : c.zIndex.resizer_normal) });
 1760+
 1761+ // make sure we have a valid event
 1762+ if (trigger != "click" && trigger != "mouseout") trigger = "mouseout";
 1763+
 1764+ // when trigger is 'mouseout', must cancel timer when mouse moves between 'pane' and 'resizer'
 1765+ if (enable) { // BIND trigger events
 1766+ $P.bind(trigger, slideClosed );
 1767+ $R.bind(trigger, slideClosed );
 1768+ if (trigger = "mouseout") {
 1769+ $P.bind("mouseover", cancelMouseOut );
 1770+ $R.bind("mouseover", cancelMouseOut );
 1771+ }
 1772+ }
 1773+ else { // UNBIND trigger events
 1774+ // TODO: why does unbind of a 'single function' not work reliably?
 1775+ //$P[action](trigger, slideClosed );
 1776+ $P.unbind(trigger);
 1777+ $R.unbind(trigger);
 1778+ if (trigger = "mouseout") {
 1779+ //$P[action]("mouseover", cancelMouseOut );
 1780+ $P.unbind("mouseover");
 1781+ $R.unbind("mouseover");
 1782+ clearTimer(pane, "closeSlider");
 1783+ }
 1784+ }
 1785+
 1786+ // SUBROUTINE for mouseout timer clearing
 1787+ function cancelMouseOut (evt) {
 1788+ clearTimer(pane, "closeSlider");
 1789+ evt.stopPropagation();
 1790+ }
 1791+ };
 1792+
 1793+ var slideOpen = function () {
 1794+ var pane = $(this).attr("resizer"); // attr added by initHandles
 1795+ if (state[pane].isClosed) { // skip if already open!
 1796+ bindStopSlidingEvents(pane, true); // pane is opening, so BIND trigger events to close it
 1797+ open(pane, true); // true = slide - ie, called from here!
 1798+ }
 1799+ };
 1800+
 1801+ var slideClosed = function () {
 1802+ var
 1803+ $E = $(this)
 1804+ , pane = $E.attr("pane") || $E.attr("resizer")
 1805+ , o = options[pane]
 1806+ , s = state[pane]
 1807+ ;
 1808+ if (s.isClosed || s.isResizing)
 1809+ return; // skip if already closed OR in process of resizing
 1810+ else if (o.slideTrigger_close == "click")
 1811+ close_NOW(); // close immediately onClick
 1812+ else // trigger = mouseout - use a delay
 1813+ setTimer(pane, "closeSlider", close_NOW, 300); // .3 sec delay
 1814+
 1815+ // SUBROUTINE for timed close
 1816+ function close_NOW () {
 1817+ bindStopSlidingEvents(pane, false); // pane is being closed, so UNBIND trigger events
 1818+ if (!s.isClosed) close(pane); // skip if already closed!
 1819+ }
 1820+ };
 1821+
 1822+
 1823+ /**
 1824+ * sizePane
 1825+ *
 1826+ * @callers initResizable.stop()
 1827+ * @param String pane The pane being resized - usually west or east, but potentially north or south
 1828+ * @param Integer newSize The new size for this pane - will be validated
 1829+ */
 1830+ var sizePane = function (pane, size) {
 1831+ // TODO: accept "auto" as size, and size-to-fit pane content
 1832+ var
 1833+ edge = c[pane].edge
 1834+ , dir = c[pane].dir
 1835+ , o = options[pane]
 1836+ , s = state[pane]
 1837+ , $P = $Ps[pane]
 1838+ , $R = $Rs[pane]
 1839+ ;
 1840+ // calculate 'current' min/max sizes
 1841+ setPaneMinMaxSizes(pane); // update pane-state
 1842+ // compare/update calculated min/max to user-options
 1843+ s.minSize = max(s.minSize, o.minSize);
 1844+ if (o.maxSize > 0) s.maxSize = min(s.maxSize, o.maxSize);
 1845+ // validate passed size
 1846+ size = max(size, s.minSize);
 1847+ size = min(size, s.maxSize);
 1848+ s.size = size; // update state
 1849+
 1850+ // move the resizer bar and resize the pane
 1851+ $R.css( edge, size + cDims[edge] );
 1852+ $P.css( c[pane].sizeType, max(1, cssSize(pane, size)) );
 1853+
 1854+ // resize all the adjacent panes, and adjust their toggler buttons
 1855+ if (!s.isSliding) sizeMidPanes(dir=="horz" ? "all" : "center");
 1856+ sizeHandles();
 1857+ sizeContent(pane);
 1858+ execUserCallback(pane, o.onresize_end || o.onresize);
 1859+ };
 1860+
 1861+ /**
 1862+ * sizeMidPanes
 1863+ *
 1864+ * @callers create(), open(), close(), onWindowResize()
 1865+ */
 1866+ var sizeMidPanes = function (panes, overrideDims, onInit) {
 1867+ if (!panes || panes == "all") panes = "east,west,center";
 1868+
 1869+ var d = getPaneDims();
 1870+ if (overrideDims) $.extend( d, overrideDims );
 1871+
 1872+ $.each(panes.split(","), function() {
 1873+ if (!$Ps[this]) return; // NO PANE - skip
 1874+ var
 1875+ pane = str(this)
 1876+ , o = options[pane]
 1877+ , s = state[pane]
 1878+ , $P = $Ps[pane]
 1879+ , $R = $Rs[pane]
 1880+ , hasRoom = true
 1881+ , CSS = {}
 1882+ ;
 1883+
 1884+ if (pane == "center") {
 1885+ d = getPaneDims(); // REFRESH Dims because may have just 'unhidden' East or West pane after a 'resize'
 1886+ CSS = $.extend( {}, d ); // COPY ALL of the paneDims
 1887+ CSS.width = max(1, cssW(pane, CSS.width));
 1888+ CSS.height = max(1, cssH(pane, CSS.height));
 1889+ hasRoom = (CSS.width > 1 && CSS.height > 1);
 1890+ /*
 1891+ * Extra CSS for IE6 or IE7 in Quirks-mode - add 'width' to NORTH/SOUTH panes
 1892+ * Normally these panes have only 'left' & 'right' positions so pane auto-sizes
 1893+ */
 1894+ if ($.browser.msie && (!$.boxModel || $.browser.version < 7)) {
 1895+ if ($Ps.north) $Ps.north.css({ width: cssW($Ps.north, cDims.innerWidth) });
 1896+ if ($Ps.south) $Ps.south.css({ width: cssW($Ps.south, cDims.innerWidth) });
 1897+ }
 1898+ }
 1899+ else { // for east and west, set only the height
 1900+ CSS.top = d.top;
 1901+ CSS.bottom = d.bottom;
 1902+ CSS.height = max(1, cssH(pane, d.height));
 1903+ hasRoom = (CSS.height > 1);
 1904+ }
 1905+
 1906+ if (hasRoom) {
 1907+ $P.css(CSS);
 1908+ if (s.noRoom) {
 1909+ s.noRoom = false;
 1910+ if (s.isHidden) return;
 1911+ else show(pane, !s.isClosed);
 1912+ /* OLD CODE - keep until sure line above works right!
 1913+ if (!s.isClosed) $P.show(); // in case was previously hidden due to NOT hasRoom
 1914+ if ($R) $R.show();
 1915+ */
 1916+ }
 1917+ if (!onInit) {
 1918+ sizeContent(pane);
 1919+ execUserCallback(pane, o.onresize_end || o.onresize);
 1920+ }
 1921+ }
 1922+ else if (!s.noRoom) { // no room for pane, so just hide it (if not already)
 1923+ s.noRoom = true; // update state
 1924+ if (s.isHidden) return;
 1925+ if (onInit) { // skip onhide callback and other logic onLoad
 1926+ $P.hide();
 1927+ if ($R) $R.hide();
 1928+ }
 1929+ else hide(pane);
 1930+ }
 1931+ });
 1932+ };
 1933+
 1934+
 1935+ var sizeContent = function (panes) {
 1936+ if (!panes || panes == "all") panes = c.allPanes;
 1937+
 1938+ $.each(panes.split(","), function() {
 1939+ if (!$Cs[this]) return; // NO CONTENT - skip
 1940+ var
 1941+ pane = str(this)
 1942+ , ignore = options[pane].contentIgnoreSelector
 1943+ , $P = $Ps[pane]
 1944+ , $C = $Cs[pane]
 1945+ , e_C = $C[0] // DOM element
 1946+ , height = cssH($P); // init to pane.innerHeight
 1947+ ;
 1948+ $P.children().each(function() {
 1949+ if (this == e_C) return; // Content elem - skip
 1950+ var $E = $(this);
 1951+ if (!ignore || !$E.is(ignore))
 1952+ height -= $E.outerHeight();
 1953+ });
 1954+ if (height > 0)
 1955+ height = cssH($C, height);
 1956+ if (height < 1)
 1957+ $C.hide(); // no room for content!
 1958+ else
 1959+ $C.css({ height: height }).show();
 1960+ });
 1961+ };
 1962+
 1963+
 1964+ /**
 1965+ * sizeHandles
 1966+ *
 1967+ * Called every time a pane is opened, closed, or resized to slide the togglers to 'center' and adjust their length if necessary
 1968+ *
 1969+ * @callers initHandles(), open(), close(), resizeAll()
 1970+ */
 1971+ var sizeHandles = function (panes, onInit) {
 1972+ if (!panes || panes == "all") panes = c.borderPanes;
 1973+
 1974+ $.each(panes.split(","), function() {
 1975+ var
 1976+ pane = str(this)
 1977+ , o = options[pane]
 1978+ , s = state[pane]
 1979+ , $P = $Ps[pane]
 1980+ , $R = $Rs[pane]
 1981+ , $T = $Ts[pane]
 1982+ ;
 1983+ if (!$P || !$R || (!o.resizable && !o.closable)) return; // skip
 1984+
 1985+ var
 1986+ dir = c[pane].dir
 1987+ , _state = (s.isClosed ? "_closed" : "_open")
 1988+ , spacing = o["spacing"+ _state]
 1989+ , togAlign = o["togglerAlign"+ _state]
 1990+ , togLen = o["togglerLength"+ _state]
 1991+ , paneLen
 1992+ , offset
 1993+ , CSS = {}
 1994+ ;
 1995+ if (spacing == 0) {
 1996+ $R.hide();
 1997+ return;
 1998+ }
 1999+ else if (!s.noRoom && !s.isHidden) // skip if resizer was hidden for any reason
 2000+ $R.show(); // in case was previously hidden
 2001+
 2002+ // Resizer Bar is ALWAYS same width/height of pane it is attached to
 2003+ if (dir == "horz") { // north/south
 2004+ paneLen = $P.outerWidth();
 2005+ $R.css({
 2006+ width: max(1, cssW($R, paneLen)) // account for borders & padding
 2007+ , height: max(1, cssH($R, spacing)) // ditto
 2008+ , left: cssNum($P, "left")
 2009+ });
 2010+ }
 2011+ else { // east/west
 2012+ paneLen = $P.outerHeight();
 2013+ $R.css({
 2014+ height: max(1, cssH($R, paneLen)) // account for borders & padding
 2015+ , width: max(1, cssW($R, spacing)) // ditto
 2016+ , top: cDims.top + getPaneSize("north", true)
 2017+ //, top: cssNum($Ps["center"], "top")
 2018+ });
 2019+
 2020+ }
 2021+
 2022+ if ($T) {
 2023+ if (togLen == 0 || (s.isSliding && o.hideTogglerOnSlide)) {
 2024+ $T.hide(); // always HIDE the toggler when 'sliding'
 2025+ return;
 2026+ }
 2027+ else
 2028+ $T.show(); // in case was previously hidden
 2029+
 2030+ if (!(togLen > 0) || togLen == "100%" || togLen > paneLen) {
 2031+ togLen = paneLen;
 2032+ offset = 0;
 2033+ }
 2034+ else { // calculate 'offset' based on options.PANE.togglerAlign_open/closed
 2035+ if (typeof togAlign == "string") {
 2036+ switch (togAlign) {
 2037+ case "top":
 2038+ case "left": offset = 0;
 2039+ break;
 2040+ case "bottom":
 2041+ case "right": offset = paneLen - togLen;
 2042+ break;
 2043+ case "middle":
 2044+ case "center":
 2045+ default: offset = Math.floor((paneLen - togLen) / 2); // 'default' catches typos
 2046+ }
 2047+ }
 2048+ else { // togAlign = number
 2049+ var x = parseInt(togAlign); //
 2050+ if (togAlign >= 0) offset = x;
 2051+ else offset = paneLen - togLen + x; // NOTE: x is negative!
 2052+ }
 2053+ }
 2054+
 2055+ var
 2056+ $TC_o = (o.togglerContent_open ? $T.children(".content-open") : false)
 2057+ , $TC_c = (o.togglerContent_closed ? $T.children(".content-closed") : false)
 2058+ , $TC = (s.isClosed ? $TC_c : $TC_o)
 2059+ ;
 2060+ if ($TC_o) $TC_o.css("display", s.isClosed ? "none" : "block");
 2061+ if ($TC_c) $TC_c.css("display", s.isClosed ? "block" : "none");
 2062+
 2063+ if (dir == "horz") { // north/south
 2064+ var width = cssW($T, togLen);
 2065+ $T.css({
 2066+ width: max(0, width) // account for borders & padding
 2067+ , height: max(1, cssH($T, spacing)) // ditto
 2068+ , left: offset // TODO: VERIFY that toggler positions correctly for ALL values
 2069+ });
 2070+ if ($TC) // CENTER the toggler content SPAN
 2071+ $TC.css("marginLeft", Math.floor((width-$TC.outerWidth())/2)); // could be negative
 2072+ }
 2073+ else { // east/west
 2074+ var height = cssH($T, togLen);
 2075+ $T.css({
 2076+ height: max(0, height) // account for borders & padding
 2077+ , width: max(1, cssW($T, spacing)) // ditto
 2078+ , top: offset // POSITION the toggler
 2079+ });
 2080+ if ($TC) // CENTER the toggler content SPAN
 2081+ $TC.css("marginTop", Math.floor((height-$TC.outerHeight())/2)); // could be negative
 2082+ }
 2083+
 2084+
 2085+ }
 2086+
 2087+ // DONE measuring and sizing this resizer/toggler, so can be 'hidden' now
 2088+ if (onInit && o.initHidden) {
 2089+ $R.hide();
 2090+ if ($T) $T.hide();
 2091+ }
 2092+ });
 2093+ };
 2094+
 2095+
 2096+ /**
 2097+ * resizeAll
 2098+ *
 2099+ * @callers window.onresize(), callbacks or custom code
 2100+ */
 2101+ var resizeAll = function () {
 2102+ var
 2103+ oldW = cDims.innerWidth
 2104+ , oldH = cDims.innerHeight
 2105+ ;
 2106+ cDims = state.container = getElemDims($Container); // UPDATE container dimensions
 2107+
 2108+ var
 2109+ checkH = (cDims.innerHeight < oldH)
 2110+ , checkW = (cDims.innerWidth < oldW)
 2111+ , s, dir
 2112+ ;
 2113+
 2114+ if (checkH || checkW)
 2115+ // NOTE special order for sizing: S-N-E-W
 2116+ $.each(["south","north","east","west"], function(i,pane) {
 2117+ s = state[pane];
 2118+ dir = c[pane].dir;
 2119+ if (!s.isClosed && ((checkH && dir=="horz") || (checkW && dir=="vert"))) {
 2120+ setPaneMinMaxSizes(pane); // update pane-state
 2121+ // shrink pane if 'too big' to fit
 2122+ if (s.size > s.maxSize)
 2123+ sizePane(pane, s.maxSize);
 2124+ }
 2125+ });
 2126+
 2127+ sizeMidPanes("all");
 2128+ sizeHandles("all"); // reposition the toggler elements
 2129+ };
 2130+
 2131+
 2132+ /**
 2133+ * keyDown
 2134+ *
 2135+ * Capture keys when enableCursorHotkey - toggle pane if hotkey pressed
 2136+ *
 2137+ * @callers document.keydown()
 2138+ */
 2139+ function keyDown (evt) {
 2140+ if (!evt) return true;
 2141+ var code = evt.keyCode;
 2142+ if (code < 33) return true; // ignore special keys: ENTER, TAB, etc
 2143+
 2144+ var
 2145+ PANE = {
 2146+ 38: "north" // Up Cursor
 2147+ , 40: "south" // Down Cursor
 2148+ , 37: "west" // Left Cursor
 2149+ , 39: "east" // Right Cursor
 2150+ }
 2151+ , isCursorKey = (code >= 37 && code <= 40)
 2152+ , ALT = evt.altKey // no worky!
 2153+ , SHIFT = evt.shiftKey
 2154+ , CTRL = evt.ctrlKey
 2155+ , pane = false
 2156+ , s, o, k, m, el
 2157+ ;
 2158+
 2159+ if (!CTRL && !SHIFT)
 2160+ return true; // no modifier key - abort
 2161+ else if (isCursorKey && options[PANE[code]].enableCursorHotkey) // valid cursor-hotkey
 2162+ pane = PANE[code];
 2163+ else // check to see if this matches a custom-hotkey
 2164+ $.each(c.borderPanes.split(","), function(i,p) { // loop each pane to check its hotkey
 2165+ o = options[p];
 2166+ k = o.customHotkey;
 2167+ m = o.customHotkeyModifier; // if missing or invalid, treated as "CTRL+SHIFT"
 2168+ if ((SHIFT && m=="SHIFT") || (CTRL && m=="CTRL") || (CTRL && SHIFT)) { // Modifier matches
 2169+ if (k && code == (isNaN(k) || k <= 9 ? k.toUpperCase().charCodeAt(0) : k)) { // Key matches
 2170+ pane = p;
 2171+ return false; // BREAK
 2172+ }
 2173+ }
 2174+ });
 2175+
 2176+ if (!pane) return true; // no hotkey - abort
 2177+
 2178+ // validate pane
 2179+ o = options[pane]; // get pane options
 2180+ s = state[pane]; // get pane options
 2181+ if (!o.enableCursorHotkey || s.isHidden || !$Ps[pane]) return true;
 2182+
 2183+ // see if user is in a 'form field' because may be 'selecting text'!
 2184+ el = evt.target || evt.srcElement;
 2185+ if (el && SHIFT && isCursorKey && (el.tagName=="TEXTAREA" || (el.tagName=="INPUT" && (code==37 || code==39))))
 2186+ return true; // allow text-selection
 2187+
 2188+ // SYNTAX NOTES
 2189+ // use "returnValue=false" to abort keystroke but NOT abort function - can run another command afterwards
 2190+ // use "return false" to abort keystroke AND abort function
 2191+ toggle(pane);
 2192+ evt.stopPropagation();
 2193+ evt.returnValue = false; // CANCEL key
 2194+ return false;
 2195+ };
 2196+
 2197+
 2198+/*
 2199+ * ###########################
 2200+ * UTILITY METHODS
 2201+ * called externally only
 2202+ * ###########################
 2203+ */
 2204+
 2205+ function allowOverflow (elem) {
 2206+ if (this && this.tagName) elem = this; // BOUND to element
 2207+ var $P;
 2208+ if (typeof elem=="string")
 2209+ $P = $Ps[elem];
 2210+ else {
 2211+ if ($(elem).attr("pane")) $P = $(elem);
 2212+ else $P = $(elem).parents("div[pane]:first");
 2213+ }
 2214+ if (!$P.length) return; // INVALID
 2215+
 2216+ var
 2217+ pane = $P.attr("pane")
 2218+ , s = state[pane]
 2219+ ;
 2220+
 2221+ // if pane is already raised, then reset it before doing it again!
 2222+ // this would happen if allowOverflow is attached to BOTH the pane and an element
 2223+ if (s.cssSaved)
 2224+ resetOverflow(pane); // reset previous CSS before continuing
 2225+
 2226+ // if pane is raised by sliding or resizing, or it's closed, then abort
 2227+ if (s.isSliding || s.isResizing || s.isClosed) {
 2228+ s.cssSaved = false;
 2229+ return;
 2230+ }
 2231+
 2232+ var
 2233+ newCSS = { zIndex: (c.zIndex.pane_normal + 1) }
 2234+ , curCSS = {}
 2235+ , of = $P.css("overflow")
 2236+ , ofX = $P.css("overflowX")
 2237+ , ofY = $P.css("overflowY")
 2238+ ;
 2239+ // determine which, if any, overflow settings need to be changed
 2240+ if (of != "visible") {
 2241+ curCSS.overflow = of;
 2242+ newCSS.overflow = "visible";
 2243+ }
 2244+ if (ofX && ofX != "visible" && ofX != "auto") {
 2245+ curCSS.overflowX = ofX;
 2246+ newCSS.overflowX = "visible";
 2247+ }
 2248+ if (ofY && ofY != "visible" && ofY != "auto") {
 2249+ curCSS.overflowY = ofX;
 2250+ newCSS.overflowY = "visible";
 2251+ }
 2252+
 2253+ // save the current overflow settings - even if blank!
 2254+ s.cssSaved = curCSS;
 2255+
 2256+ // apply new CSS to raise zIndex and, if necessary, make overflow 'visible'
 2257+ $P.css( newCSS );
 2258+
 2259+ // make sure the zIndex of all other panes is normal
 2260+ $.each(c.allPanes.split(","), function(i, p) {
 2261+ if (p != pane) resetOverflow(p);
 2262+ });
 2263+
 2264+ };
 2265+
 2266+ function resetOverflow (elem) {
 2267+ if (this && this.tagName) elem = this; // BOUND to element
 2268+ var $P;
 2269+ if (typeof elem=="string")
 2270+ $P = $Ps[elem];
 2271+ else {
 2272+ if ($(elem).hasClass("ui-layout-pane")) $P = $(elem);
 2273+ else $P = $(elem).parents("div[pane]:first");
 2274+ }
 2275+ if (!$P.length) return; // INVALID
 2276+
 2277+ var
 2278+ pane = $P.attr("pane")
 2279+ , s = state[pane]
 2280+ , CSS = s.cssSaved || {}
 2281+ ;
 2282+ // reset the zIndex
 2283+ if (!s.isSliding && !s.isResizing)
 2284+ $P.css("zIndex", c.zIndex.pane_normal);
 2285+
 2286+ // reset Overflow - if necessary
 2287+ $P.css( CSS );
 2288+
 2289+ // clear var
 2290+ s.cssSaved = false;
 2291+ };
 2292+
 2293+
 2294+ /**
 2295+ * getBtn
 2296+ *
 2297+ * Helper function to validate params received by addButton utilities
 2298+ *
 2299+ * @param String selector jQuery selector for button, eg: ".ui-layout-north .toggle-button"
 2300+ * @param String pane Name of the pane the button is for: 'north', 'south', etc.
 2301+ * @returns If both params valid, the element matching 'selector' in a jQuery wrapper - otherwise 'false'
 2302+ */
 2303+ function getBtn(selector, pane, action) {
 2304+ var
 2305+ $E = $(selector)
 2306+ , err = "Error Adding Button \n\nInvalid "
 2307+ ;
 2308+ if (!$E.length) // element not found
 2309+ alert(err+"selector: "+ selector);
 2310+ else if (c.borderPanes.indexOf(pane) == -1) // invalid 'pane' sepecified
 2311+ alert(err+"pane: "+ pane);
 2312+ else { // VALID
 2313+ var btn = options[pane].buttonClass +"-"+ action;
 2314+ $E.addClass( btn +" "+ btn +"-"+ pane );
 2315+ return $E;
 2316+ }
 2317+ return false; // INVALID
 2318+ };
 2319+
 2320+
 2321+ /**
 2322+ * addToggleBtn
 2323+ *
 2324+ * Add a custom Toggler button for a pane
 2325+ *
 2326+ * @param String selector jQuery selector for button, eg: ".ui-layout-north .toggle-button"
 2327+ * @param String pane Name of the pane the button is for: 'north', 'south', etc.
 2328+ */
 2329+ function addToggleBtn (selector, pane) {
 2330+ var $E = getBtn(selector, pane, "toggle");
 2331+ if ($E)
 2332+ $E
 2333+ .attr("title", state[pane].isClosed ? "Open" : "Close")
 2334+ .click(function (evt) {
 2335+ toggle(pane);
 2336+ evt.stopPropagation();
 2337+ })
 2338+ ;
 2339+ };
 2340+
 2341+ /**
 2342+ * addOpenBtn
 2343+ *
 2344+ * Add a custom Open button for a pane
 2345+ *
 2346+ * @param String selector jQuery selector for button, eg: ".ui-layout-north .open-button"
 2347+ * @param String pane Name of the pane the button is for: 'north', 'south', etc.
 2348+ */
 2349+ function addOpenBtn (selector, pane) {
 2350+ var $E = getBtn(selector, pane, "open");
 2351+ if ($E)
 2352+ $E
 2353+ .attr("title", "Open")
 2354+ .click(function (evt) {
 2355+ open(pane);
 2356+ evt.stopPropagation();
 2357+ })
 2358+ ;
 2359+ };
 2360+
 2361+ /**
 2362+ * addCloseBtn
 2363+ *
 2364+ * Add a custom Close button for a pane
 2365+ *
 2366+ * @param String selector jQuery selector for button, eg: ".ui-layout-north .close-button"
 2367+ * @param String pane Name of the pane the button is for: 'north', 'south', etc.
 2368+ */
 2369+ function addCloseBtn (selector, pane) {
 2370+ var $E = getBtn(selector, pane, "close");
 2371+ if ($E)
 2372+ $E
 2373+ .attr("title", "Close")
 2374+ .click(function (evt) {
 2375+ close(pane);
 2376+ evt.stopPropagation();
 2377+ })
 2378+ ;
 2379+ };
 2380+
 2381+ /**
 2382+ * addPinBtn
 2383+ *
 2384+ * Add a custom Pin button for a pane
 2385+ *
 2386+ * Four classes are added to the element, based on the paneClass for the associated pane...
 2387+ * Assuming the default paneClass and the pin is 'up', these classes are added for a west-pane pin:
 2388+ * - ui-layout-pane-pin
 2389+ * - ui-layout-pane-west-pin
 2390+ * - ui-layout-pane-pin-up
 2391+ * - ui-layout-pane-west-pin-up
 2392+ *
 2393+ * @param String selector jQuery selector for button, eg: ".ui-layout-north .ui-layout-pin"
 2394+ * @param String pane Name of the pane the pin is for: 'north', 'south', etc.
 2395+ */
 2396+ function addPinBtn (selector, pane) {
 2397+ var $E = getBtn(selector, pane, "pin");
 2398+ if ($E) {
 2399+ var s = state[pane];
 2400+ $E.click(function (evt) {
 2401+ setPinState($(this), pane, (s.isSliding || s.isClosed));
 2402+ if (s.isSliding || s.isClosed) open( pane ); // change from sliding to open
 2403+ else close( pane ); // slide-closed
 2404+ evt.stopPropagation();
 2405+ });
 2406+ // add up/down pin attributes and classes
 2407+ setPinState ($E, pane, (!s.isClosed && !s.isSliding));
 2408+ // add this pin to the pane data so we can 'sync it' automatically
 2409+ // PANE.pins key is an array so we can store multiple pins for each pane
 2410+ c[pane].pins.push( selector ); // just save the selector string
 2411+ }
 2412+ };
 2413+
 2414+ /**
 2415+ * syncPinBtns
 2416+ *
 2417+ * INTERNAL function to sync 'pin buttons' when pane is opened or closed
 2418+ * Unpinned means the pane is 'sliding' - ie, over-top of the adjacent panes
 2419+ *
 2420+ * @callers open(), close()
 2421+ * @params pane These are the params returned to callbacks by layout()
 2422+ * @params doPin True means set the pin 'down', False means 'up'
 2423+ */
 2424+ function syncPinBtns (pane, doPin) {
 2425+ $.each(c[pane].pins, function (i, selector) {
 2426+ setPinState($(selector), pane, doPin);
 2427+ });
 2428+ };
 2429+
 2430+ /**
 2431+ * setPinState
 2432+ *
 2433+ * Change the class of the pin button to make it look 'up' or 'down'
 2434+ *
 2435+ * @callers addPinBtn(), syncPinBtns()
 2436+ * @param Element $Pin The pin-span element in a jQuery wrapper
 2437+ * @param Boolean doPin True = set the pin 'down', False = set it 'up'
 2438+ * @param String pinClass The root classname for pins - will add '-up' or '-down' suffix
 2439+ */
 2440+ function setPinState ($Pin, pane, doPin) {
 2441+ var updown = $Pin.attr("pin");
 2442+ if (updown && doPin == (updown=="down")) return; // already in correct state
 2443+ var
 2444+ root = options[pane].buttonClass
 2445+ , class1 = root +"-pin"
 2446+ , class2 = class1 +"-"+ pane
 2447+ , UP1 = class1 + "-up"
 2448+ , UP2 = class2 + "-up"
 2449+ , DN1 = class1 + "-down"
 2450+ , DN2 = class2 + "-down"
 2451+ ;
 2452+ $Pin
 2453+ .attr("pin", doPin ? "down" : "up") // logic
 2454+ .attr("title", doPin ? "Un-Pin" : "Pin")
 2455+ .removeClass( doPin ? UP1 : DN1 )
 2456+ .removeClass( doPin ? UP2 : DN2 )
 2457+ .addClass( doPin ? DN1 : UP1 )
 2458+ .addClass( doPin ? DN2 : UP2 )
 2459+ ;
 2460+ };
 2461+
 2462+
 2463+/*
 2464+ * ###########################
 2465+ * CREATE/RETURN BORDER-LAYOUT
 2466+ * ###########################
 2467+ */
 2468+
 2469+ // init global vars
 2470+ var
 2471+ $Container = $(this).css({ overflow: "hidden" }) // Container elem
 2472+ , $Ps = {} // Panes x4 - set in initPanes()
 2473+ , $Cs = {} // Content x4 - set in initPanes()
 2474+ , $Rs = {} // Resizers x4 - set in initHandles()
 2475+ , $Ts = {} // Togglers x4 - set in initHandles()
 2476+ // object aliases
 2477+ , c = config // alias for config hash
 2478+ , cDims = state.container // alias for easy access to 'container dimensions'
 2479+ ;
 2480+
 2481+ // create the border layout NOW
 2482+ create();
 2483+
 2484+ // return object pointers to expose data & option Properties, and primary action Methods
 2485+ return {
 2486+ options: options // property - options hash
 2487+ , state: state // property - dimensions hash
 2488+ , panes: $Ps // property - object pointers for ALL panes: panes.north, panes.center
 2489+ , toggle: toggle // method - pass a 'pane' ("north", "west", etc)
 2490+ , open: open // method - ditto
 2491+ , close: close // method - ditto
 2492+ , hide: hide // method - ditto
 2493+ , show: show // method - ditto
 2494+ , resizeContent: sizeContent // method - ditto
 2495+ , sizePane: sizePane // method - pass a 'pane' AND a 'size' in pixels
 2496+ , resizeAll: resizeAll // method - no parameters
 2497+ , addToggleBtn: addToggleBtn // utility - pass element selector and 'pane'
 2498+ , addOpenBtn: addOpenBtn // utility - ditto
 2499+ , addCloseBtn: addCloseBtn // utility - ditto
 2500+ , addPinBtn: addPinBtn // utility - ditto
 2501+ , allowOverflow: allowOverflow // utility - pass calling element
 2502+ , resetOverflow: resetOverflow // utility - ditto
 2503+ , cssWidth: cssW
 2504+ , cssHeight: cssH
 2505+ };
 2506+
 2507+}
 2508+})( jQuery );
\ No newline at end of file
Index: branches/MwEmbedStandAlone/modules/SequenceEdit/mw.SequenceEdit.js
@@ -0,0 +1,220 @@
 2+/**
 3+ * Main Sequence Editor Driver
 4+ */
 5+
 6+mw.includeAllModuleMessages();
 7+
 8+/*
 9+* Setup the sequenceEdit jQuery binding:
 10+*/
 11+( function( $ ) {
 12+ $.fn.sequenceEdit = function( options ) {
 13+ // Debugger
 14+ if( $j( this.selector ).length == 0 ){
 15+ mw.log("SequenceEdit::Error missing target container");
 16+ return;
 17+ }
 18+ var seqContainer = $j( this.selector ).get(0);
 19+ // Check if we already have a sequencer associated with this target
 20+ if( seqContainer['sequenceEdit'] ){
 21+ // xxx todo: pass on the options / action
 22+ return ;
 23+ }
 24+ options['interfaceContainer'] = this.selector;
 25+
 26+ // Issue a request to get the CSS file (if not already included):
 27+ mw.log( 'SequenceEdit:: create new SequenceEdit' );
 28+
 29+ // Initialize the sequence object (it will take over from there)
 30+ seqContainer['sequenceEdit'] = new mw.SequenceEdit( options );
 31+
 32+ // Draw the sequencer UI
 33+ seqContainer['sequenceEdit'].drawUI();
 34+
 35+ //Return the sequence jquery object
 36+ return this;
 37+
 38+ }
 39+} )( jQuery );
 40+
 41+//Wrap in mw closure to avoid global leakage
 42+( function( mw ) {
 43+
 44+/**
 45+ * The set of valid sequenceEdit options
 46+ */
 47+var mw_sequenceedit_default_options = {
 48+ 'interfaceContainer' : null,
 49+ 'smilSource' : null,
 50+ 'videoAspect' : '4:3'
 51+}
 52+mw.SequenceEdit = function( options ) {
 53+ return this.init( options );
 54+};
 55+
 56+// Set up the mvSequencer object
 57+mw.SequenceEdit.prototype = {
 58+ // lazy init id for the sequenceEdit instance.
 59+ id: null,
 60+
 61+ init: function( options ){
 62+ if(!options)
 63+ options = {};
 64+ // Validate and set default options :
 65+ for( var optionName in mw_sequenceedit_default_options ){
 66+ if( typeof options[ optionName] != 'undefined'){
 67+ this[optionName] = options[ optionName] ;
 68+ } else {
 69+ this[optionName] = mw_sequenceedit_default_options[ optionName ]
 70+ }
 71+ }
 72+ // For style properties assgin top level mwe-sequence-edit class
 73+ this.getContainer().addClass('mwe-sequence-edit');
 74+ },
 75+
 76+ // Return the container id for the sequence
 77+ getId: function(){
 78+ if( !this.id ){
 79+ // Assign the container an id if missing one::
 80+ if( ! this.getContainer().attr('id') ){
 81+ this.getContainer().attr('id', 'sequenceEdit_' + new Date().getTime() + Math.random() );
 82+ }
 83+ this.id = this.getContainer().attr('id');
 84+ }
 85+ return this.id;
 86+ },
 87+ /**
 88+ * @return smilSource url
 89+ */
 90+ getSmilSource: function(){
 91+ return this.smilSource;
 92+ },
 93+ /**
 94+ * draw the initial sequence ui, uses ui.layout for adjustable layout
 95+ */
 96+ drawUI: function( ){
 97+ var _this = this;
 98+ mw.log("SequenceEdit:: drawUI to: " + this.interfaceContainer +
 99+ ' ' + this.getContainer().length);
 100+
 101+ // Add the ui layout
 102+ this.getContainer().html(
 103+ this.getUiLayout()
 104+ )
 105+ // Once the layout is in the dom setup resizableLayout "layout" options
 106+ this.applyLayoutBindings();
 107+
 108+ // Add the smil player
 109+ //xxx deal with the case of an empty player~~
 110+ this.getPlayer().drawPlayer( function(){
 111+ // Once the player and smil is loaded ::
 112+ // start buffering
 113+ _this.getEmbedPlayer().load();
 114+
 115+ // Add the timeline
 116+ _this.getTimeline().drawTimeline();
 117+
 118+ });
 119+
 120+ // Add deafult clip edit
 121+
 122+ },
 123+ getPlayer: function(){
 124+ if( ! this.player ){
 125+ this.player = new mw.SequenceEditPlayer( this );
 126+ }
 127+ return this.player;
 128+ },
 129+ getEmbedPlayer:function(){
 130+ return $j( '#' + this.getPlayer().getSmilPlayerId() ).get(0);
 131+ },
 132+ getSmil: function(){
 133+ if( !this.smil ){
 134+ this.smil = this.getEmbedPlayer().smil;
 135+ }
 136+ return this.smil;
 137+ },
 138+ getTimeline: function(){
 139+ if( ! this.timeline ){
 140+ this.timeline = new mw.SequenceEditTimeline( this );
 141+ }
 142+ return this.timeline;
 143+ },
 144+ getKeyBindings:function(){
 145+ if( ! this.keyBindings ){
 146+ this.keyBindings = new mw.SequenceEditKeyBindings( this );
 147+ }
 148+ return this.keyBindings;
 149+ },
 150+ // Apply the resizable layout bindings and default sizes
 151+ applyLayoutBindings: function(){
 152+ var _this = this;
 153+ this.getContainer().find('.resizableLayout').layout({
 154+ 'applyDefaultStyles': true,
 155+ /* player container */
 156+ 'east__minSize': 240,
 157+ 'east__size': 400,
 158+ 'east__onresize':function(){
 159+ _this.getPlayer().resizePlayer();
 160+ },
 161+
 162+ /* edit container */
 163+ 'center__minSize' : 300,
 164+
 165+ /* timeline container */
 166+ 'south__minSize' : 160,
 167+ 'south__size' : 240,
 168+ 'south__onresize' : function(){
 169+ _this.getTimeline().resizeTimeline();
 170+ }
 171+ });
 172+ },
 173+
 174+ /**
 175+ * Get the UI layout
 176+ */
 177+ getUiLayout: function(){
 178+ // xxx There is probably a cleaner way to generate a list of jQuery objects than $j('new').children();
 179+ return $j('<div />').append(
 180+ $j('<div />')
 181+ .addClass( "mwseq-menu" )
 182+ .css({
 183+ 'position':'absolute',
 184+ 'height': '25px',
 185+ 'width': '100%',
 186+ 'top': '0px',
 187+ 'left' : '0px'
 188+ })
 189+ .text('Menu')
 190+ ,
 191+
 192+ $j('<div />')
 193+ .addClass('resizableLayout')
 194+ .css({
 195+ 'position':'absolute',
 196+ 'top': '25px',
 197+ 'left': '0px',
 198+ 'right': '0px',
 199+ 'bottom':'0px'
 200+ })
 201+ .append(
 202+ $j('<div />')
 203+ .addClass( "ui-layout-center mwseq-edit" )
 204+ .text( gM('mwe-sequenceedit-loading_edit') ),
 205+ $j('<div />')
 206+ .addClass( "ui-layout-east mwseq-player" )
 207+ .text( gM('mwe-sequenceedit-loading_player') ),
 208+ $j('<div />')
 209+ .addClass( "ui-layout-south mwseq-timeline" )
 210+ .text( gM('mwe-sequenceedit-loading_timeline') )
 211+ )
 212+ ).children();
 213+ },
 214+
 215+ getContainer: function(){
 216+ return $j( this.interfaceContainer );
 217+ }
 218+
 219+}
 220+
 221+} )( window.mw );
\ No newline at end of file

Comments

#Comment by Heldergeovane (talk | contribs)   11:41, 18 October 2010

It seems to me that the comments for functions mw.setConfig and mw.setDefaultConfig were better formated before this update in

/branches/MwEmbedStandAlone/mwEmbed.js

Was that the intended formatting or just an accident?

#Comment by Mdale (talk | contribs)   17:31, 18 October 2010

Yes the formatting got updated by some comment re-factoring. It may be less pretty but I believe the idea was to make it work better with closure compiler conventions: http://code.google.com/closure/compiler/docs/js-for-compiler.html

#Comment by Heldergeovane (talk | contribs)   18:03, 18 October 2010

Shouldn't each parameter be in its own line after "@param"?

	/**
	 * Setter for configuration values
	 * 
	 * @param {string|Object} name Name of configuration value
	 *     {Object} Will iderate through each key and call setConfig
	 *     {string} Will set configuration by string name to value
	 * @param {String} value Value of configuration name
	 *     {Object} value Set of values to be merged
	 */
	mw.setConfig = function ( name, value ) {

It seems that the compiler doesn't uses [Mixed], because it gives the message:

JSC_INEXISTANT_PARAM: parameter Mixed does not appear in setConfig's parameter list at ...

(when testing the code here ).

#Comment by Papyromancer (talk | contribs)   19:01, 18 October 2010

I believe this is from one of my changesets on the Kaltura.org svn that Michael imported.

I am working on making the documentation Closure friendly and capable of compiling docs html pages with the JSDoc-Toolkit.

I will update the formatting on my next sprint through the documentation (the end of next week).

Status & tagging log