From: Roan Kattouw Date: Thu, 26 Nov 2009 14:24:56 +0000 (+0000) Subject: Partial revert of r59446: add js2stopgap.js back in, some extensions (at least Usabil... X-Git-Tag: 1.31.0-rc.0~38705 X-Git-Url: http://git.cyclocoop.org/data/%24oldEdit?a=commitdiff_plain;h=0cc7be4a2e97053af58d61fa84f544f67e40bd2d;p=lhc%2Fweb%2Fwiklou.git Partial revert of r59446: add js2stopgap.js back in, some extensions (at least UsabilityInitiative and LiquidThreads) depend on it. --- diff --git a/js2/README b/js2/README new file mode 100644 index 0000000000..d82b80f501 --- /dev/null +++ b/js2/README @@ -0,0 +1,4 @@ +MediaWiki Javascript phase 2 + +See Documentation on wiki: +http://www.mediawiki.org/wiki/JS2_Overview \ No newline at end of file diff --git a/js2/ajaxcategories.js b/js2/ajaxcategories.js new file mode 100644 index 0000000000..b46d8b3adf --- /dev/null +++ b/js2/ajaxcategories.js @@ -0,0 +1,326 @@ +loadGM( { + "ajax-add-category" : "[Add Category]", + "ajax-add-category-submit" : "[Add]", + "ajax-confirm-prompt" : "[Confirmation Text]", + "ajax-confirm-title" : "[Confirmation Title]", + "ajax-confirm-save" : "[Save]", + "ajax-add-category-summary" : "[Add category $1]", + "ajax-remove-category-summary" : "[Remove category $2]", + "ajax-confirm-actionsummary" : "[Summary]", + "ajax-error-title" : "Error", + "ajax-error-dismiss" : "OK", + "ajax-remove-category-error" : "[RemoveErr]" +} ); + +var ajaxCategories = { + handleAddLink : function( e ) { + e.preventDefault(); + + // Make sure the suggestion plugin is loaded. Load everything else while we're at it + mvJsLoader.doLoad( + ['$j.ui', '$j.ui.dialog', '$j.fn.suggestions'], + function() { + $j( '#mw-addcategory-prompt' ).toggle(); + + $j( '#mw-addcategory-input' ).suggestions( { + 'fetch':ajaxCategories.fetchSuggestions, + 'cancel': function() { + var req = ajaxCategories.request; + if ( req.abort ) + req.abort(); + } + } ); + + $j( '#mw-addcategory-input' ).suggestions(); + } + ); + }, + + fetchSuggestions : function( query ) { + var that = this; + var request = $j.ajax( { + url: wgScriptPath + '/api.php', + data: { + 'action': 'query', + 'list': 'allpages', + 'apnamespace': 14, + 'apprefix': $j( this ).val(), + 'format': 'json' + }, + dataType: 'json', + success: function( data ) { + // Process data.query.allpages into an array of titles + var pages = data.query.allpages; + var titleArr = []; + + $j.each( pages, function( i, page ) { + var title = page.title.split( ':', 2 )[1]; + titleArr.push( title ); + } ); + + $j( that ).suggestions( 'suggestions', titleArr ); + } + } ); + + ajaxCategories.request = request; + }, + + reloadCategoryList : function( response ) { + var holder = $j( '
' ); + + holder.load( + window.location.href + ' .catlinks', + function() { + $j( '.catlinks' ).replaceWith( holder.find( '.catlinks' ) ); + ajaxCategories.setupAJAXCategories(); + ajaxCategories.removeProgressIndicator( $j( '.catlinks' ) ); + } + ); + }, + + confirmEdit : function( page, fn, actionSummary, doneFn ) { + // Load jQuery UI + mvJsLoader.doLoad( + ['$j.ui', '$j.ui.dialog', '$j.fn.suggestions'], + function() { + // Produce a confirmation dialog + + var dialog = $j( '
' ); + + dialog.addClass( 'mw-ajax-confirm-dialog' ); + dialog.attr( 'title', gM( 'ajax-confirm-title' ) ); + + // Intro text. + var confirmIntro = $j( '

' ); + confirmIntro.text( gM( 'ajax-confirm-prompt' ) ); + dialog.append( confirmIntro ); + + // Summary of the action to be taken + var summaryHolder = $j( '

' ); + var summaryLabel = $j( '' ); + summaryLabel.text( gM( 'ajax-confirm-actionsummary' ) + " " ); + summaryHolder.text( actionSummary ); + summaryHolder.prepend( summaryLabel ); + dialog.append( summaryHolder ); + + // Reason textbox. + var reasonBox = $j( '' ); + reasonBox.addClass( 'mw-ajax-confirm-reason' ); + dialog.append( reasonBox ); + + // Submit button + var submitButton = $j( '' ); + submitButton.val( gM( 'ajax-confirm-save' ) ); + + var submitFunction = function() { + ajaxCategories.addProgressIndicator( dialog ); + ajaxCategories.doEdit( + page, + fn, + reasonBox.val(), + function() { + doneFn(); + dialog.dialog( 'close' ); + ajaxCategories.removeProgressIndicator( dialog ); + } + ); + }; + + var buttons = { }; + buttons[gM( 'ajax-confirm-save' )] = submitFunction; + var dialogOptions = { + 'AutoOpen' : true, + 'buttons' : buttons, + 'width' : 450 + }; + + $j( '#catlinks' ).prepend( dialog ); + dialog.dialog( dialogOptions ); + } + ); + }, + + doEdit : function( page, fn, summary, doneFn ) { + // Get an edit token for the page. + var getTokenVars = { + 'action':'query', + 'prop':'info|revisions', + 'intoken':'edit', + 'titles':page, + 'rvprop':'content|timestamp', + 'format':'json' + }; + + $j.get( wgScriptPath + '/api.php', getTokenVars, + function( reply ) { + var infos = reply.query.pages; + $j.each( + infos, + function( pageid, data ) { + var token = data.edittoken; + var timestamp = data.revisions[0].timestamp; + var oldText = data.revisions[0]['*']; + + var newText = fn( oldText ); + + if ( newText === false ) return; + + var postEditVars = { + 'action':'edit', + 'title':page, + 'text':newText, + 'summary':summary, + 'token':token, + 'basetimestamp':timestamp, + 'format':'json' + }; + + $j.post( wgScriptPath + '/api.php', postEditVars, doneFn, 'json' ); + } + ); + } + , 'json' ); + }, + + addProgressIndicator : function( elem ) { + var indicator = $j( '

' ); + + indicator.addClass( 'mw-ajax-loader' ); + + elem.append( indicator ); + }, + + removeProgressIndicator : function( elem ) { + elem.find( '.mw-ajax-loader' ).remove(); + }, + + handleCategoryAdd : function( e ) { + // Grab category text + var category = $j( '#mw-addcategory-input' ).val(); + var appendText = "\n[[" + wgFormattedNamespaces[14] + ":" + category + "]]\n"; + var summary = gM( 'ajax-add-category-summary', category ); + + ajaxCategories.confirmEdit( + wgPageName, + function( oldText ) { return oldText + appendText }, + summary, + ajaxCategories.reloadCategoryList + ); + }, + + handleDeleteLink : function( e ) { + e.preventDefault(); + + var category = $j( this ).parent().find( 'a' ).text(); + + // Build a regex that matches legal invocations of that category. + + // In theory I should escape the aliases, but there's no JS function for it + // Shouldn't have any real impact, can't be exploited or anything, so we'll + // leave it for now. + var categoryNSFragment = ''; + $j.each( wgNamespaceIds, function( name, id ) { + if ( id == 14 ) { + // Allow the first character to be any case + var firstChar = name.charAt( 0 ); + firstChar = '[' + firstChar.toUpperCase() + firstChar.toLowerCase() + ']'; + categoryNSFragment += '|' + firstChar + name.substr( 1 ); + } + } ); + categoryNSFragment = categoryNSFragment.substr( 1 ); // Remove leading | + + // Build the regex + var titleFragment = category; + + firstChar = category.charAt( 0 ); + firstChar = '[' + firstChar.toUpperCase() + firstChar.toLowerCase() + ']'; + titleFragment = firstChar + category.substr( 1 ); + var categoryRegex = '\\[\\[' + categoryNSFragment + ':' + titleFragment + '(\\|[^\\]]*)?\\]\\]'; + categoryRegex = new RegExp( categoryRegex, 'g' ); + + var summary = gM( 'ajax-remove-category-summary', category ); + + ajaxCategories.confirmEdit( + wgPageName, + function( oldText ) { + var newText = oldText.replace( categoryRegex, '' ); + + if ( newText == oldText ) { + var error = gM( 'ajax-remove-category-error' ); + ajaxCategories.showError( error ); + ajaxCategories.removeProgressIndicator( $j( '.mw-ajax-confirm-dialog' ) ); + $j( '.mw-ajax-confirm-dialog' ).dialog( 'close' ); + return false; + } + + return newText; + }, + summary, ajaxCategories.reloadCategoryList + ); + }, + + showError : function( str ) { + var dialog = $j( '
' ); + dialog.text( str ); + + $j( '#bodyContent' ).append( dialog ); + + var buttons = { }; + buttons[gM( 'ajax-error-dismiss' )] = function( e ) { + dialog.dialog( 'close' ); + }; + var dialogOptions = { + 'buttons' : buttons, + 'AutoOpen' : true, + 'title' : gM( 'ajax-error-title' ) + }; + + dialog.dialog( dialogOptions ); + }, + + setupAJAXCategories : function() { + // Only do it for articles. + if ( !wgIsArticle ) return; + + var clElement = $j( '.catlinks' ); + + // Unhide hidden category holders. + clElement.removeClass( 'catlinks-allhidden' ); + + var addLink = $j( '' ); + addLink.addClass( 'mw-ajax-addcategory' ); + + // Create [Add Category] link + addLink.text( gM( 'ajax-add-category' ) ); + addLink.attr( 'href', '#' ); + addLink.click( ajaxCategories.handleAddLink ); + clElement.append( addLink ); + + // Create add category prompt + var promptContainer = $j( '
' ); + var promptTextbox = $j( '' ); + var addButton = $j( '' ); + addButton.val( gM( 'ajax-add-category-submit' ) ); + + promptTextbox.keypress( ajaxCategories.handleCategoryInput ); + addButton.click( ajaxCategories.handleCategoryAdd ); + + promptContainer.append( promptTextbox ); + promptContainer.append( addButton ); + promptContainer.hide(); + + // Create delete link for each category. + $j( '.catlinks div span a' ).each( function( e ) { + // Create a remove link + var deleteLink = $j( '' ); + + deleteLink.click( ajaxCategories.handleDeleteLink ); + + $j( this ).after( deleteLink ); + } ); + + clElement.append( promptContainer ); + } +}; + +js2AddOnloadHook( ajaxCategories.setupAJAXCategories ); diff --git a/js2/apiProxyPage.js b/js2/apiProxyPage.js new file mode 100644 index 0000000000..f113a5d119 --- /dev/null +++ b/js2/apiProxyPage.js @@ -0,0 +1,28 @@ +/* +* mwProxy js2 page system. +* +* Invokes the apiProxy system +*/ + +/* + * Since this is proxy server set a pre-append debug flag to know which debug msgs are coming from where + */ + +mw.conf['debug_pre'] = 'Proxy'; + +if ( !mwApiProxyConfig ) + var mwApiProxyConfig = { }; + +// The default mwApiProxyConfig config +// (presently hard coded but should read from user and site config) +var mwApiProxyDefaultConfig = { + 'master_whitelist' : [ 'en.wikipedia.org', 'localhost', '127.1.1.100' ], + 'master_blacklist' : [] +}; + +// User white_list should also be checked and configured at runtime. +js2AddOnloadHook( function() { + // build our configuration from the default and mwApiProxyConfig vars + mwApiProxyConfig = $j.extend( true, mwApiProxyDefaultConfig, mwApiProxyConfig ); + $j.apiProxy( 'server', mwApiProxyConfig ); +} ); diff --git a/js2/editPage.js b/js2/editPage.js new file mode 100644 index 0000000000..15c47f9e52 --- /dev/null +++ b/js2/editPage.js @@ -0,0 +1,69 @@ +/* + * JS2-style replacement for MediaWiki edit.js + * (right now it just supports the toolbar) + */ + +// Setup configuration vars (if not set already) +if ( !mwAddMediaConfig ) + var mwAddMediaConfig = { }; + +// The default editPage AMW config +var defaultAddMediaConfig = { + 'profile': 'mediawiki_edit', + 'target_textbox': '#wpTextbox1', + // Note: selections in the textbox will take over the default query + 'default_query': wgTitle, + 'target_title': wgPageName, + // Here we can setup the content provider overrides + 'enabled_cps':['wiki_commons'], + // The local wiki API URL: + 'local_wiki_api_url': wgServer + wgScriptPath + '/api.php' +}; + +js2AddOnloadHook( function() { + js_log( "edit page js2AddOnloadHook::" ); + var amwConf = $j.extend( true, defaultAddMediaConfig, mwAddMediaConfig ); + // kind of tricky, it would be nice to use run on ready "loader" call here + var didWikiEditorBind = false; + + // Set-up the drag drop binding (will only work for html5 upload browsers) + // $j('textarea#wpTextbox1').dragFileUpload(); + + // set up the add-media-wizard binding: + if ( typeof $j.wikiEditor != 'undefined' ) { + // the below seems to be broken :( + $j( 'textarea#wpTextbox1' ).bind( 'wikiEditor-toolbar-buildSection-main', + function( e, section ) { + didWikiEditorBind = true; + if ( typeof section.groups.insert.tools.file !== 'undefined' ) { + section.groups.insert.tools.file.action = { + 'type': 'callback', + 'execute': function() { + js_log( 'click add media wiz' ); + $j.addMediaWiz( amwConf ); + } + }; + } + } + ); + } + // Add to old toolbar if wikiEditor did not remove '#toolbar' from the page: + setTimeout( function() { + if ( $j( '#btn-add-media-wiz' ).length == 0 && $j( '#toolbar' ).length != 0 ) { + js_log( 'Do old toolbar bind:' ); + didWikiEditorBind = true; + $j( '#toolbar' ).append( '' ); + $j( '#btn-add-media-wiz' ).addMediaWiz( + amwConf + ); + } else { + // Make sure the wikieditor got binded: + if ( !didWikiEditorBind ) { + js_log( 'Failed to bind via build section bind via target:' ); + $j( ".tool[rel='file']" ).unbind().addMediaWiz( amwConf ); + } + } + }, 120 ) + +} ); diff --git a/js2/js2stopgap.js b/js2/js2stopgap.js new file mode 100644 index 0000000000..801be99224 --- /dev/null +++ b/js2/js2stopgap.js @@ -0,0 +1,9509 @@ +/*! + * jQuery JavaScript Library v1.3.2 + * http://jquery.com/ + * + * Copyright (c) 2009 John Resig + * Dual licensed under the MIT and GPL licenses. + * http://docs.jquery.com/License + * + * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009) + * Revision: 6246 + */ +( function() { + +var + // Will speed up references to window, and allows munging its name. + window = this, + // Will speed up references to undefined, and allows munging its name. + undefined, + // Map over jQuery in case of overwrite + _jQuery = window.jQuery, + // Map over the $ in case of overwrite + _$ = window.$, + + jQuery = window.jQuery = window.$ = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + return new jQuery.fn.init( selector, context ); + }, + + // A simple way to check for HTML strings or ID strings + // (both of which we optimize for) + quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/, + // Is it a simple selector + isSimple = / ^ .[ ^ :# \[\.,]*$/; + +jQuery.fn = jQuery.prototype = { + init: function( selector, context ) { + // Make sure that a selection was provided + selector = selector || document; + + // Handle $(DOMElement) + if ( selector.nodeType ) { + this[0] = selector; + this.length = 1; + this.context = selector; + return this; + } + // Handle HTML strings + if ( typeof selector === "string" ) { + // Are we dealing with HTML string or an ID? + var match = quickExpr.exec( selector ); + + // Verify a match, and that no context was specified for #id + if ( match && ( match[1] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) + selector = jQuery.clean( [ match[1] ], context ); + + // HANDLE: $("#id") + else { + var elem = document.getElementById( match[3] ); + + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem && elem.id != match[3] ) + return jQuery().find( selector ); + + // Otherwise, we inject the element directly into the jQuery object + var ret = jQuery( elem || [] ); + ret.context = document; + ret.selector = selector; + return ret; + } + + // HANDLE: $(expr, [context]) + // (which is just equivalent to: $(content).find(expr) + } else + return jQuery( context ).find( selector ); + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) + return jQuery( document ).ready( selector ); + + // Make sure that old selector state is passed along + if ( selector.selector && selector.context ) { + this.selector = selector.selector; + this.context = selector.context; + } + + return this.setArray( jQuery.isArray( selector ) ? + selector : + jQuery.makeArray( selector ) ); + }, + + // Start with an empty selector + selector: "", + + // The current version of jQuery being used + jquery: "1.3.2", + + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num === undefined ? + + // Return a 'clean' array + Array.prototype.slice.call( this ) : + + // Return just the object + this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems, name, selector ) { + // Build a new jQuery matched element set + var ret = jQuery( elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + ret.context = this.context; + + if ( name === "find" ) + ret.selector = this.selector + ( this.selector ? " " : "" ) + selector; + else if ( name ) + ret.selector = this.selector + "." + name + "(" + selector + ")"; + + // Return the newly-formed element set + return ret; + }, + + // Force the current matched set of elements to become + // the specified array of elements (destroying the stack in the process) + // You should use pushStack() in order to do this, but maintain the stack + setArray: function( elems ) { + // Resetting the length to 0, then using the native Array push + // is a super-fast way to populate an object with array-like properties + this.length = 0; + Array.prototype.push.apply( this, elems ); + + return this; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + // Locate the position of the desired element + return jQuery.inArray( + // If it receives a jQuery object, the first element is used + elem && elem.jquery ? elem[0] : elem + , this ); + }, + + attr: function( name, value, type ) { + var options = name; + + // Look for the case where we're accessing a style value + if ( typeof name === "string" ) + if ( value === undefined ) + return this[0] && jQuery[ type || "attr" ]( this[0], name ); + + else { + options = { }; + options[ name ] = value; + } + + // Check to see if we're setting style values + return this.each( function( i ) { + // Set all the styles + for ( name in options ) + jQuery.attr( + type ? + this.style : + this, + name, jQuery.prop( this, options[ name ], type, i, name ) + ); + } ); + }, + + css: function( key, value ) { + // ignore negative width and height values + if ( ( key == 'width' || key == 'height' ) && parseFloat( value ) < 0 ) + value = undefined; + return this.attr( key, value, "curCSS" ); + }, + + text: function( text ) { + if ( typeof text !== "object" && text != null ) + return this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( text ) ); + + var ret = ""; + + jQuery.each( text || this, function() { + jQuery.each( this.childNodes, function() { + if ( this.nodeType != 8 ) + ret += this.nodeType != 1 ? + this.nodeValue : + jQuery.fn.text( [ this ] ); + } ); + } ); + + return ret; + }, + + wrapAll: function( html ) { + if ( this[0] ) { + // The elements to wrap the target around + var wrap = jQuery( html, this[0].ownerDocument ). clone (); + + if ( this[0].parentNode ) + wrap.insertBefore( this[0] ); + + wrap.map( function() { + var elem = this; + + while ( elem.firstChild ) + elem = elem.firstChild; + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + return this.each( function() { + jQuery( this ).contents().wrapAll( html ); + } ); + }, + + wrap: function( html ) { + return this.each( function() { + jQuery( this ).wrapAll( html ); + } ); + }, + + append: function() { + return this.domManip( arguments, true, function( elem ) { + if ( this.nodeType == 1 ) + this.appendChild( elem ); + } ); + }, + + prepend: function() { + return this.domManip( arguments, true, function( elem ) { + if ( this.nodeType == 1 ) + this.insertBefore( elem, this.firstChild ); + } ); + }, + + before: function() { + return this.domManip( arguments, false, function( elem ) { + this.parentNode.insertBefore( elem, this ); + } ); + }, + + after: function() { + return this.domManip( arguments, false, function( elem ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } ); + }, + + end: function() { + return this.prevObject || jQuery( [] ); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: [].push, + sort: [].sort, + splice: [].splice, + + find: function( selector ) { + if ( this.length === 1 ) { + var ret = this.pushStack( [], "find", selector ); + ret.length = 0; + jQuery.find( selector, this[0], ret ); + return ret; + } else { + return this.pushStack( jQuery.unique( jQuery.map( this, function( elem ) { + return jQuery.find( selector, elem ); + } ) ), "find", selector ); + } + }, + + clone : function( events ) { + // Do the clone + var ret = this.map( function() { + if ( !jQuery.support.noCloneEvent && !jQuery.isXMLDoc( this ) ) { + // IE copies events bound via attachEvent when + // using cloneNode. Calling detachEvent on the + // clone will also remove the events from the orignal + // In order to get around this, we use innerHTML. + // Unfortunately, this means some modifications to + // attributes in IE that are actually only stored + // as properties will not be copied (such as the + // the name attribute on an input). + var html = this.outerHTML; + if ( !html ) { + var div = this.ownerDocument.createElement( "div" ); + div.appendChild( this.cloneNode( true ) ); + html = div.innerHTML; + } + + return jQuery.clean( [ html.replace( / jQuery\d+="(?:\d+|null)"/g, "" ).replace( /^\s*/, "" ) ] )[0]; + } else + return this.cloneNode( true ); + } ); + + // Copy the events from the original to the clone + if ( events === true ) { + var orig = this.find( "*" ).andSelf(), i = 0; + + ret.find( "*" ).andSelf().each( function() { + if ( this.nodeName !== orig[i].nodeName ) + return; + + var events = jQuery.data( orig[i], "events" ); + + for ( var type in events ) { + for ( var handler in events[ type ] ) { + jQuery.event.add( this, type, events[ type ][ handler ], events[ type ][ handler ].data ); + } + } + + i++; + } ); + } + + // Return the cloned set + return ret; + }, + + filter: function( selector ) { + return this.pushStack( + jQuery.isFunction( selector ) && + jQuery.grep( this, function( elem, i ) { + return selector.call( elem, i ); + } ) || + + jQuery.multiFilter( selector, jQuery.grep( this, function( elem ) { + return elem.nodeType === 1; + } ) ), "filter", selector ); + }, + + closest: function( selector ) { + var pos = jQuery.expr.match.POS.test( selector ) ? jQuery( selector ) : null, + closer = 0; + + return this.map( function() { + var cur = this; + while ( cur && cur.ownerDocument ) { + if ( pos ? pos.index( cur ) > - 1 : jQuery( cur ).is( selector ) ) { + jQuery.data( cur, "closest", closer ); + return cur; + } + cur = cur.parentNode; + closer++; + } + } ); + }, + + not: function( selector ) { + if ( typeof selector === "string" ) + // test special case where just one selector is passed in + if ( isSimple.test( selector ) ) + return this.pushStack( jQuery.multiFilter( selector, this, true ), "not", selector ); + else + selector = jQuery.multiFilter( selector, this ); + + var isArrayLike = selector.length && selector[selector.length - 1] !== undefined && !selector.nodeType; + return this.filter( function() { + return isArrayLike ? jQuery.inArray( this, selector ) < 0 : this != selector; + } ); + }, + + add: function( selector ) { + return this.pushStack( jQuery.unique( jQuery.merge( + this.get(), + typeof selector === "string" ? + jQuery( selector ) : + jQuery.makeArray( selector ) + ) ) ); + }, + + is: function( selector ) { + return !!selector && jQuery.multiFilter( selector, this ).length > 0; + }, + + hasClass: function( selector ) { + return !!selector && this.is( "." + selector ); + }, + + val: function( value ) { + if ( value === undefined ) { + var elem = this[0]; + + if ( elem ) { + if ( jQuery.nodeName( elem, 'option' ) ) + return ( elem.attributes.value || { } ).specified ? elem.value : elem.text; + + // We need to handle select boxes special + if ( jQuery.nodeName( elem, "select" ) ) { + var index = elem.selectedIndex, + values = [], + options = elem.options, + one = elem.type == "select-one"; + + // Nothing was selected + if ( index < 0 ) + return null; + + // Loop through all the selected options + for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { + var option = options[ i ]; + + if ( option.selected ) { + // Get the specifc value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) + return value; + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + } + + // Everything else, we just grab the value + return ( elem.value || "" ).replace( /\r/g, "" ); + + } + + return undefined; + } + + if ( typeof value === "number" ) + value += ''; + + return this.each( function() { + if ( this.nodeType != 1 ) + return; + + if ( jQuery.isArray( value ) && / radio | checkbox / .test( this.type ) ) + this.checked = ( jQuery.inArray( this.value, value ) >= 0 || + jQuery.inArray( this.name, value ) >= 0 ); + + else if ( jQuery.nodeName( this, "select" ) ) { + var values = jQuery.makeArray( value ); + + jQuery( "option", this ).each( function() { + this.selected = ( jQuery.inArray( this.value, values ) >= 0 || + jQuery.inArray( this.text, values ) >= 0 ); + } ); + + if ( !values.length ) + this.selectedIndex = - 1; + + } else + this.value = value; + } ); + }, + + html: function( value ) { + return value === undefined ? + ( this[0] ? + this[0].innerHTML.replace( / jQuery\d+="(?:\d+|null)"/g, "" ) : + null ) : + this.empty().append( value ); + }, + + replaceWith: function( value ) { + return this.after( value ).remove(); + }, + + eq: function( i ) { + return this.slice( i, + i + 1 ); + }, + + slice: function() { + return this.pushStack( Array.prototype.slice.apply( this, arguments ), + "slice", Array.prototype.slice.call( arguments ).join( "," ) ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + andSelf: function() { + return this.add( this.prevObject ); + }, + + domManip: function( args, table, callback ) { + if ( this[0] ) { + var fragment = ( this[0].ownerDocument || this[0] ).createDocumentFragment(), + scripts = jQuery.clean( args, ( this[0].ownerDocument || this[0] ), fragment ), + first = fragment.firstChild; + + if ( first ) + for ( var i = 0, l = this.length; i < l; i++ ) + callback.call( root( this[i], first ), this.length > 1 || i > 0 ? + fragment.cloneNode( true ) : fragment ); + + if ( scripts ) + jQuery.each( scripts, evalScript ); + } + + return this; + + function root( elem, cur ) { + return table && jQuery.nodeName( elem, "table" ) && jQuery.nodeName( cur, "tr" ) ? + ( elem.getElementsByTagName( "tbody" )[0] || + elem.appendChild( elem.ownerDocument.createElement( "tbody" ) ) ) : + elem; + } + } +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; + +function evalScript( i, elem ) { + if ( elem.src ) + jQuery.ajax( { + url: elem.src, + async: false, + dataType: "script" + } ); + + else + jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" ); + + if ( elem.parentNode ) + elem.parentNode.removeChild( elem ); +} + +function now() { + return + new Date; +} + +jQuery.extend = jQuery.fn.extend = function() { + // copy reference to target object + var target = arguments[0] || { }, i = 1, length = arguments.length, deep = false, options; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[1] || { }; + // skip the boolean and the target + i = 2; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction( target ) ) + target = { }; + + // extend jQuery itself if only one argument is passed + if ( length == i ) { + target = this; + --i; + } + + for ( ; i < length; i++ ) + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) + // Extend the base object + for ( var name in options ) { + var src = target[ name ], copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) + continue; + + // Recurse if we're merging object values + if ( deep && copy && typeof copy === "object" && !copy.nodeType ) + target[ name ] = jQuery.extend( deep, + // Never move original objects, clone them + src || ( copy.length != null ? [ ] : { } ) + , copy ); + + // Don't bring in undefined values + else if ( copy !== undefined ) + target[ name ] = copy; + + } + + // Return the modified object + return target; +}; + +// exclude the following css properties to add px +var exclude = / z - ? index | font - ? weight | opacity | zoom | line - ? height /i, + // cache defaultView + defaultView = document.defaultView || { }, + toString = Object.prototype.toString; + +jQuery.extend( { + noConflict: function( deep ) { + window.$ = _$; + + if ( deep ) + window.jQuery = _jQuery; + + return jQuery; + }, + + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + return toString.call( obj ) === "[object Function]"; + }, + + isArray: function( obj ) { + return toString.call( obj ) === "[object Array]"; + }, + + // check if an element is in a (or is an) XML document + isXMLDoc: function( elem ) { + return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" || + !!elem.ownerDocument && jQuery.isXMLDoc( elem.ownerDocument ); + }, + + // Evalulates a script in a global context + globalEval: function( data ) { + if ( data && /\S/.test( data ) ) { + // Inspired by code by Andrea Giammarchi + // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html + var head = document.getElementsByTagName( "head" )[0] || document.documentElement, + script = document.createElement( "script" ); + + script.type = "text/javascript"; + if ( jQuery.support.scriptEval ) + script.appendChild( document.createTextNode( data ) ); + else + script.text = data; + + // Use insertBefore instead of appendChild to circumvent an IE6 bug. + // This arises when a base node is used (#2709). + head.insertBefore( script, head.firstChild ); + head.removeChild( script ); + } + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase(); + }, + + // args is for internal usage only + each: function( object, callback, args ) { + var name, i = 0, length = object.length; + + if ( args ) { + if ( length === undefined ) { + for ( name in object ) + if ( callback.apply( object[ name ], args ) === false ) + break; + } else + for ( ; i < length; ) + if ( callback.apply( object[ i++ ], args ) === false ) + break; + + // A special, fast, case for the most common use of each + } else { + if ( length === undefined ) { + for ( name in object ) + if ( callback.call( object[ name ], name, object[ name ] ) === false ) + break; + } else + for ( var value = object[0]; + i < length && callback.call( value, i, value ) !== false; value = object[++i] ) { } + } + + return object; + }, + + prop: function( elem, value, type, i, name ) { + // Handle executable functions + if ( jQuery.isFunction( value ) ) + value = value.call( elem, i ); + + // Handle passing in a number to a CSS property + return typeof value === "number" && type == "curCSS" && !exclude.test( name ) ? + value + "px" : + value; + }, + + className: { + // internal only, use addClass("class") + add: function( elem, classNames ) { + jQuery.each( ( classNames || "" ).split( /\s+/ ), function( i, className ) { + if ( elem.nodeType == 1 && !jQuery.className.has( elem.className, className ) ) + elem.className += ( elem.className ? " " : "" ) + className; + } ); + }, + + // internal only, use removeClass("class") + remove: function( elem, classNames ) { + if ( elem.nodeType == 1 ) + elem.className = classNames !== undefined ? + jQuery.grep( elem.className.split( /\s+/ ), function( className ) { + return !jQuery.className.has( classNames, className ); + } ).join( " " ) : + ""; + }, + + // internal only, use hasClass("class") + has: function( elem, className ) { + return elem && jQuery.inArray( className, ( elem.className || elem ).toString().split( /\s+/ ) ) > -1; + } + }, + + // A method for quickly swapping in/out CSS properties to get correct calculations + swap: function( elem, options, callback ) { + var old = { }; + // Remember the old values, and insert the new ones + for ( var name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + callback.call( elem ); + + // Revert the old values + for ( var name in options ) + elem.style[ name ] = old[ name ]; + }, + + css: function( elem, name, force, extra ) { + if ( name == "width" || name == "height" ) { + var val, props = { position: "absolute", visibility: "hidden", display:"block" }, which = name == "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ]; + + function getWH() { + val = name == "width" ? elem.offsetWidth : elem.offsetHeight; + + if ( extra === "border" ) + return; + + jQuery.each( which, function() { + if ( !extra ) + val -= parseFloat( jQuery.curCSS( elem, "padding" + this, true ) ) || 0; + if ( extra === "margin" ) + val += parseFloat( jQuery.curCSS( elem, "margin" + this, true ) ) || 0; + else + val -= parseFloat( jQuery.curCSS( elem, "border" + this + "Width", true ) ) || 0; + } ); + } + + if ( elem.offsetWidth !== 0 ) + getWH(); + else + jQuery.swap( elem, props, getWH ); + + return Math.max( 0, Math.round( val ) ); + } + + return jQuery.curCSS( elem, name, force ); + }, + + curCSS: function( elem, name, force ) { + var ret, style = elem.style; + + // We need to handle opacity special in IE + if ( name == "opacity" && !jQuery.support.opacity ) { + ret = jQuery.attr( style, "opacity" ); + + return ret == "" ? + "1" : + ret; + } + + // Make sure we're using the right name for getting the float value + if ( name.match( / float /i ) ) + name = styleFloat; + + if ( !force && style && style[ name ] ) + ret = style[ name ]; + + else if ( defaultView.getComputedStyle ) { + + // Only "float" is needed here + if ( name.match( / float /i ) ) + name = "float"; + + name = name.replace( / ( [A - Z] ) /g, "-$1" ).toLowerCase(); + + var computedStyle = defaultView.getComputedStyle( elem, null ); + + if ( computedStyle ) + ret = computedStyle.getPropertyValue( name ); + + // We should always get a number back from opacity + if ( name == "opacity" && ret == "" ) + ret = "1"; + + } else if ( elem.currentStyle ) { + var camelCase = name.replace( /\-(\w)/g, function( all, letter ) { + return letter.toUpperCase(); + } ); + + ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ]; + + // From the awesome hack by Dean Edwards + // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 + + // If we're not dealing with a regular pixel number + // but a number that has a weird ending, we need to convert it to pixels + if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) { + // Remember the original values + var left = style.left, rsLeft = elem.runtimeStyle.left; + + // Put in the new values to get a computed value out + elem.runtimeStyle.left = elem.currentStyle.left; + style.left = ret || 0; + ret = style.pixelLeft + "px"; + + // Revert the changed values + style.left = left; + elem.runtimeStyle.left = rsLeft; + } + } + + return ret; + }, + + clean: function( elems, context, fragment ) { + context = context || document; + + // !context.createElement fails in IE with an error but returns typeof 'object' + if ( typeof context.createElement === "undefined" ) + context = context.ownerDocument || context[0] && context[0].ownerDocument || document; + + // If a single string is passed in and it's a single tag + // just do a createElement and skip the rest + if ( !fragment && elems.length === 1 && typeof elems[0] === "string" ) { + var match = /^<(\w+)\s*\/?>$/.exec(elems[0]); + if ( match ) + return [ context.createElement( match[1] ) ]; + } + + var ret = [], scripts = [], div = context.createElement("div"); + + jQuery.each(elems, function(i, elem){ + if ( typeof elem === "number" ) + elem += ''; + + if ( !elem ) + return; + + // Convert html string into DOM nodes + if ( typeof elem === "string" ) { + // Fix "XHTML"-style tags in all browsers + elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){ + return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ? + all : + front + ">"; + }); + + // Trim whitespace, otherwise indexOf won't work as expected + var tags = elem.replace(/^\s+/, "").substring(0, 10).toLowerCase(); + + var wrap = + // option or optgroup + !tags.indexOf("", "" ] || + + !tags.indexOf("", "" ] || + + tags.match(/^<(thead|tbody|tfoot|colg|cap)/) && + [ 1, "", "
" ] || + + !tags.indexOf("", "" ] || + + // matched above + (!tags.indexOf("", "" ] || + + !tags.indexOf("", "" ] || + + // IE can't serialize and + + + + +

Sample Add Media Wizard

+ +
Add Media
+note only commons is enabled by default. For more options see source code.

+ + + + + +
Asset OutputHtml Output:
+ + + diff --git a/js2/mwEmbed/example_usage/Firefogg_Make_Advanced.html b/js2/mwEmbed/example_usage/Firefogg_Make_Advanced.html new file mode 100644 index 0000000000..d22744eb54 --- /dev/null +++ b/js2/mwEmbed/example_usage/Firefogg_Make_Advanced.html @@ -0,0 +1,96 @@ + + + + Firefogg - Make Ogg Video in your Browser + + + + + + +
+

+ + Firefogg +
+Make Ogg Video

+
+
+
Loading firefogg...
+
+ +
+
Built using firefogg, MwEmbed and jquery.ui. Supports + custom themes via the ThemeRoller Dev Tool + +
+ + diff --git a/js2/mwEmbed/example_usage/Multi_Upload.html b/js2/mwEmbed/example_usage/Multi_Upload.html new file mode 100644 index 0000000000..5a81028703 --- /dev/null +++ b/js2/mwEmbed/example_usage/Multi_Upload.html @@ -0,0 +1,27 @@ + + + + Sample Themed Player + + + + +

Multiple File Upload:

+
+

Drag and Drop Files here

+
+

Or select multiple Files here

+
+ + +
+ + + \ No newline at end of file diff --git a/js2/mwEmbed/example_usage/Player_Audio.html b/js2/mwEmbed/example_usage/Player_Audio.html new file mode 100644 index 0000000000..81e89f9b81 --- /dev/null +++ b/js2/mwEmbed/example_usage/Player_Audio.html @@ -0,0 +1,12 @@ + + + + + +Audio Player sample + + +

Audio Player

+ + + \ No newline at end of file diff --git a/js2/mwEmbed/example_usage/Player_RelatedVideos.html b/js2/mwEmbed/example_usage/Player_RelatedVideos.html new file mode 100644 index 0000000000..26f5180733 --- /dev/null +++ b/js2/mwEmbed/example_usage/Player_RelatedVideos.html @@ -0,0 +1,29 @@ + + + + Simple Video Tag Usage + + + +

Related Videos

+ + +
+
+ + + + +
+ Sample Related Videos
+
The Example Code ::: 
+ <video wikiTitleKey="File:B-36_bomber.ogg" durationHint="2" + poster="http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/B-36_bomber.ogg/mid-B-36_bomber.ogg.jpg&size=400x300" + src="http://upload.wikimedia.org/wikipedia/commons/0/0d/B-36_bomber.ogg"></video> +
+
+













  + + + diff --git a/js2/mwEmbed/example_usage/Player_Themable.html b/js2/mwEmbed/example_usage/Player_Themable.html new file mode 100644 index 0000000000..eb9439b114 --- /dev/null +++ b/js2/mwEmbed/example_usage/Player_Themable.html @@ -0,0 +1,38 @@ + + + + Sample Themed Player + + + + + +

Sample Themable Player:

+To play with dynamic Themes install Themeroller

+ +

+ + +Source Code used:
+ +
+ +
+ + +(kskin) Source Code used:
+ +
+ + + + + diff --git a/js2/mwEmbed/example_usage/Player_Timed_Text.html b/js2/mwEmbed/example_usage/Player_Timed_Text.html new file mode 100644 index 0000000000..bd7ea6cb57 --- /dev/null +++ b/js2/mwEmbed/example_usage/Player_Timed_Text.html @@ -0,0 +1,61 @@ + + + + sample mv embed + + + +

Mv_Embed Timed Text Examples:

+Click on the little lower right "CC" icon to expose the timed text + + + + + + + + + + + +
+ + + Metavid based ROE file using CMML
<video roe="http://metavid.org/w/index.php?title=Special:MvExportStream&stream_name=House_proceeding_07-18-06_00&t=1:23:16/1:23:44&feed_format=roe" ></video>
+ + +

Archive.org video with local SRTs (copied locally until we get srt over json for archive.org ;)

+
+ + + + diff --git a/js2/mwEmbed/example_usage/Sequence_Editor.html b/js2/mwEmbed/example_usage/Sequence_Editor.html new file mode 100644 index 0000000000..48014cdd93 --- /dev/null +++ b/js2/mwEmbed/example_usage/Sequence_Editor.html @@ -0,0 +1,39 @@ + + + + SMIL Sequence Editor example + + + + + + +
+ Loading sequence editor ... +
+ + + + diff --git a/js2/mwEmbed/example_usage/Sequence_Render.html b/js2/mwEmbed/example_usage/Sequence_Render.html new file mode 100644 index 0000000000..9d9c1f240c --- /dev/null +++ b/js2/mwEmbed/example_usage/Sequence_Render.html @@ -0,0 +1,68 @@ + + + + Seeking Render Example + + + + + + + + + + + +loading render system ... + + + + + diff --git a/js2/mwEmbed/example_usage/media/princess_archive_org/princess_iron_fan-cs.srt b/js2/mwEmbed/example_usage/media/princess_archive_org/princess_iron_fan-cs.srt new file mode 100644 index 0000000000..6cc0494f23 --- /dev/null +++ b/js2/mwEmbed/example_usage/media/princess_archive_org/princess_iron_fan-cs.srt @@ -0,0 +1,1397 @@ +1 +00:00:01,080 --> 00:00:09,070 +Princezna Železný Vějíř + +2 +00:02:03,109 --> 00:02:09,280 +Cesta na Východ je báječný dětský příběh, + +3 +00:02:09,280 --> 00:02:15,280 +ale svět ho často chybně označuje jako fantasy román. + +4 +00:02:15,280 --> 00:02:19,240 +Tento film byl vyroben za účelem + +5 +00:02:19,240 --> 00:02:24,240 +tréninku dětských srdcí a myslí. + +6 +00:02:24,240 --> 00:02:29,280 +Příběh je pravý, nezkažený fantazií. + +7 +00:02:29,280 --> 00:02:32,560 +Ohnivá hora, která brání v cestě skupině Tanga Senga + +8 +00:02:32,560 --> 00:02:41,039 +je metafora pro obtíže v životě. + +9 +00:02:41,039 --> 00:02:46,439 +Abychom je překonali, musíme si uchovat víru. +Musíme spolupracovat + +10 +00:02:46,439 --> 00:02:52,430 +abychom získali vějíř z palmových listů a udusili plameny. + +11 +00:02:52,839 --> 00:02:58,178 +Tripikata True Sutra + +12 +00:03:34,479 --> 00:03:37,789 +Už je přece podzim. Jakto, že je pořád takové vedro? + +13 +00:03:37,840 --> 00:03:42,349 +Hlupáku, neplácej nesmysly. Musíme si pospíšit a postupovat dál. + +14 +00:04:06,919 --> 00:04:09,349 +Wukongu, kde je to místo? + +15 +00:04:09,400 --> 00:04:13,669 +Musíme přejít tudy a dál na západ. Zaručeně. + +16 +00:04:13,719 --> 00:04:18,110 +A nemohli jsme zabloudit? + +17 +00:04:18,149 --> 00:04:21,700 +Proč je tu takové horko? + +18 +00:04:30,029 --> 00:04:31,649 +Mistře, podívejte! + +19 +00:04:31,650 --> 00:04:33,779 +Není to domek? Tam nahoře... + +20 +00:04:33,829 --> 00:04:38,100 +Pojďme si dovnitř na chvilku odpočinout. Souhlasíte? + +21 +00:04:59,389 --> 00:05:02,899 +Tohle místo se nazývá Ohnivá hora. + +22 +00:05:02,949 --> 00:05:06,019 +Oheň dosahuje stovky mil daleko. + +23 +00:05:06,069 --> 00:05:08,740 +Ani jediné stéblo trávy zde nemůže vyrůst. + +24 +00:05:08,790 --> 00:05:11,620 +Všechny čtyři roční období je tu horko. + +25 +00:05:11,680 --> 00:05:19,629 +Přes horu by nešlo projít ani s měděnou hlavou ani s železnýma rukama. + +26 +00:05:19,670 --> 00:05:23,579 +Co je tohle jenom za místo? Mistře, nebojte. + +27 +00:05:23,629 --> 00:05:27,139 +My tři jsme dost silní abychom dokázali projít. + +28 +00:05:27,189 --> 00:05:30,699 +Mistře, půjdu a podívám se na to. + +29 +00:08:06,310 --> 00:08:09,579 +Wukongu, jaké to bylo? + +30 +00:08:09,629 --> 00:08:11,819 +Špatné, špatné, moc špatné. + +31 +00:08:11,879 --> 00:08:15,910 +Kdybych byl jenom trochu pomalejší, měl bych kůži na ocase spálenou. + +32 +00:08:42,720 --> 00:08:47,600 +Urozený hostiteli, ohně jsou zde tak velké. + +33 +00:08:47,600 --> 00:08:49,669 +Jak zde mohou vyrůst nějaké plodiny? + +34 +00:08:49,710 --> 00:08:53,980 +Tisíc mil odsud žije princezna Železný Vějíř. + +35 +00:08:54,039 --> 00:08:56,500 +Ona má vějíř z palmových listů. + +36 +00:08:56,559 --> 00:08:59,070 +Zamávej s ním jednou a oheň ustane. + +37 +00:08:59,120 --> 00:09:01,629 +Dvakrát a začne foukat vítr. + +38 +00:09:01,679 --> 00:09:03,980 +Třikrát a spustí se déšť. + +39 +00:09:04,039 --> 00:09:07,509 +V nadcházejícím období pak pěstujeme a sklízíme. + +40 +00:09:07,559 --> 00:09:11,340 +Nicméně... požádat, aby princezna přišla + +41 +00:09:11,399 --> 00:09:14,870 +není tak úplně jednoduché. + +42 +00:09:14,909 --> 00:09:16,820 +Kde ona žije? + +43 +00:09:16,879 --> 00:09:20,190 +Žije v jeskyni Palmových Listů v hoře Smaragdových Mračen. + +44 +00:09:20,240 --> 00:09:23,669 +Žije tam sama? + +45 +00:09:23,720 --> 00:09:25,750 +Ona nemá manžela? + +46 +00:09:25,799 --> 00:09:29,580 +Její manžel je Král, Býčí Démon. + +47 +00:09:29,639 --> 00:09:32,200 +Cože? Její manžel je Starý Býk? + +48 +00:09:32,240 --> 00:09:36,789 +Hlupáku, ty ho znáš? Pojď si se mnou vypůjčit ten vějíř! + +49 +00:09:36,840 --> 00:09:41,750 +Vlastně... Starý Býk tam nežije. + +50 +00:09:41,799 --> 00:09:46,350 +Vyhledávat jeho ženu, když on není doma + +51 +00:09:46,399 --> 00:09:51,519 +není moc ... vhodné. + +52 +00:09:51,559 --> 00:09:58,309 +Ty... ty... Vy dva, jděte už. + +53 +00:09:58,360 --> 00:10:04,290 +Já... Já zůstanu a postarám se o mistra. + +54 +00:10:04,440 --> 00:10:11,269 +Sha Wujingu, jdi se svými dvěma učedníky. + +55 +00:10:38,571 --> 00:10:44,978 +jeskyně Palmových Listů + +56 +00:10:47,200 --> 00:10:51,549 +Hlupáku. První jdu vždy já. + +57 +00:10:51,600 --> 00:10:54,350 +Tentokrát jsi na řadě ty. + +58 +00:10:58,519 --> 00:11:04,909 +Juniore. Vždycky jdu první já, tak teď jsi na řadě ty. + +59 +00:11:04,960 --> 00:11:06,830 +Seniore... + +60 +00:11:06,879 --> 00:11:10,990 +Žádám tě, abys pro mistra udělal malou službu. Nemůžeš to udělat? + +61 +00:11:11,039 --> 00:11:14,309 +Dělej! + +62 +00:11:39,639 --> 00:11:43,039 +Prostý mnichu, odkud jsi přišel? + +63 +00:11:43,039 --> 00:11:49,870 +Velký Mudrc... Tang Seng... si žádá vaši princeznu... + +64 +00:11:49,919 --> 00:11:52,480 +Nesmysl! + +65 +00:12:47,549 --> 00:12:52,059 +Seniore... proč raději nejde vy? + +66 +00:12:52,120 --> 00:12:56,950 +Hlupáku, jdi ty! + +67 +00:12:57,000 --> 00:13:00,700 +Seiore, proč vy ne? + +68 +00:13:04,029 --> 00:13:07,460 +Líný hlupáku! + +69 +00:13:54,279 --> 00:13:57,899 +Velká Matko Hromů! Nezabíjejte mě, nechte mě jít! + +70 +00:13:57,960 --> 00:13:59,950 +Jdi a řekni tvé princezně, + +71 +00:14:00,000 --> 00:14:03,279 +že Sun Wukong si přišel půjčit její vějíř. + +72 +00:14:03,279 --> 00:14:08,399 +Ano, ano! Nech mě zmizet. Já hned půjdu. + +73 +00:14:29,559 --> 00:14:37,059 +Babičko, venku je Sun Wukong a ptá se na půjčení vějíře. + +74 +00:14:41,519 --> 00:14:44,149 +Rychle, přines mi můj meč. + +75 +00:15:01,639 --> 00:15:04,149 +Sune Wukongu, ty jsi zranil mého syna! + +76 +00:15:04,200 --> 00:15:08,549 +Ty se odvažuješ přijít si sem pro svou smrt? + +77 +00:15:08,600 --> 00:15:12,039 +Nikdy jsem tě nepotkal. Jak bych mohl ublížit tvému synovi? + +78 +00:15:12,039 --> 00:15:15,789 +Život mého syna Červeného Dítěte byl zničen. Není to to co děláš? + +79 +00:15:15,840 --> 00:15:20,389 +Tvůj syn je nyní s Bohyní Milosrdenství. Jak můžeš říci, že jsem ho zranil? + +80 +00:15:20,440 --> 00:15:23,750 +Dost řečí! Pojď sem ať tě můžu seknout svým mečem. + +81 +00:15:23,799 --> 00:15:26,149 +Pokud to podstoupíš tak ti půjčím svůj vějíř. + +82 +00:15:26,200 --> 00:15:28,549 +Opravdu? + +83 +00:15:56,799 --> 00:16:00,629 +Zastav! Rychle, dej mi vějíř. + +84 +00:17:53,630 --> 00:18:00,099 +Velký mudrci, nešli jste na západ? Proč jste se vrátili? + +85 +00:18:11,150 --> 00:18:17,140 +Princezna Železný Vějíř mě sem odfoukla jedním mávnutím svého vějíře. + +86 +00:18:17,190 --> 00:18:23,859 +To je skutečně úžasné, velký mudrci. Něco pro Vás mám. + +87 +00:18:28,509 --> 00:18:33,450 +Tohle je větrná perla. Když ji použijete + +88 +00:18:33,509 --> 00:18:36,140 +vaše srdce se zastaví jako kámen. + +89 +00:18:36,190 --> 00:18:39,180 +Princezna Železný Vějíř nebude schopná s Vámi vůbec pohnout. + +90 +00:18:39,230 --> 00:18:42,849 +Velký mudrci, podívejte se. + +91 +00:19:00,430 --> 00:19:02,539 +Děkuji. + +92 +00:19:06,069 --> 00:19:12,299 +Seniore... kde... + +93 +00:19:12,349 --> 00:19:18,690 +Kam ho to odfouklo? + +94 +00:19:18,750 --> 00:19:26,099 +Kdo by se o něj staral. Ať se opičák postará sám o sebe. Pojďme. + +95 +00:19:35,190 --> 00:19:37,259 +Seniore... seniore... + +96 +00:19:37,309 --> 00:19:43,470 +Vy... vy... + +97 +00:19:43,470 --> 00:19:50,220 +Kam vás ta stará paní odfoukla? + +98 +00:19:50,269 --> 00:19:57,180 +Hlupáku, teď je rozhodně řada na tobě abys šel. + +99 +00:19:57,230 --> 00:20:00,930 +Já nejdu. Jediné mávnutí vějíře + +100 +00:20:00,990 --> 00:20:03,450 +by mě mohlo odfouknout do nějaké daleké země. + +101 +00:20:03,509 --> 00:20:09,710 +Možná by bylo lepší, kdyby jste šel znovu. + +102 +00:20:09,710 --> 00:20:12,220 +Já nepůjdu. + +103 +00:20:17,789 --> 00:20:22,779 +Příště už tě nenechám odpálit. + +104 +00:20:56,150 --> 00:21:00,140 +Tentokrát se nepohnu a nezáleží na tom jak moc máchneš. + +105 +00:21:00,190 --> 00:21:05,210 +Buď si jistá mým slovem, slovem muže. + +106 +00:21:33,670 --> 00:21:38,579 +Seniore, jakto že její vějíř vás neodfouknul? + +107 +00:21:46,829 --> 00:21:50,099 +Dostaňme se dovnitř. + +108 +00:23:59,630 --> 00:24:04,180 +Rychle, dones vějíř Sunu Wukongovi. + +109 +00:24:14,869 --> 00:24:16,900 +Sune Wukongu, kde jsi? + +110 +00:24:16,950 --> 00:24:19,980 +Jsem ve tvém žaludku! + +111 +00:24:45,750 --> 00:24:48,539 +Sune Wukongu, ušetři mě! + +112 +00:24:48,589 --> 00:24:51,180 +Jenom tehdy, když mi dáš ten vějíř. + +113 +00:24:51,230 --> 00:24:56,539 +Slibuji. Dám ti to. Prosím, jdi ven! + +114 +00:25:00,230 --> 00:25:02,819 +Honem a přines vějíř. + +115 +00:25:07,430 --> 00:25:09,220 +Přinesli jsme vějíř. + +116 +00:25:09,279 --> 00:25:12,069 +Porč jsi ještě nevylezl? + +117 +00:25:12,109 --> 00:25:16,619 +Otevři ústa a já vylezu. + +118 +00:25:25,349 --> 00:25:29,420 +Sune Wukongu, proč jsi dosud nevylezl? + +119 +00:25:50,349 --> 00:25:55,579 +Já jsem zde. Půjč mi na chvíli ten vějíř a já ti ho vrátím. + +120 +00:26:32,549 --> 00:26:36,579 +Mistr už čekal dost dlouho. Pojďme už. + +121 +00:27:01,869 --> 00:27:04,900 +Posvátná kniha... Co je to posvátná kniha? + +122 +00:27:04,950 --> 00:27:10,029 +Posvátná kniha je zásadní pro spojení mezi nebem a zemí. + +123 +00:27:10,029 --> 00:27:14,180 +To je princip lidí. + +124 +00:27:14,230 --> 00:27:18,700 +Jenom ten, kdo se těch principů drží, + +125 +00:27:18,750 --> 00:27:25,339 +se může zbavit bolesti a žije dobrý život. + +126 +00:27:25,390 --> 00:27:29,940 +Žije správný a čestný život. + +127 +00:27:34,680 --> 00:27:36,349 +Naproti tomu... + +128 +00:27:36,390 --> 00:27:40,089 +ten, kdo tyto zásady nezná, + +129 +00:27:40,150 --> 00:27:46,380 +bude žít život plný utrpení. + +130 +00:27:46,430 --> 00:27:52,609 +A dokonce ani jeho syn a vnuk nedosáhnou štěstí. + +131 +00:27:52,670 --> 00:27:55,660 +Proč já chci dosáhnout posvátné knihy? + +132 +00:27:55,710 --> 00:28:01,299 +Protože lidé jsou nyní chyceni v utrpení. + +133 +00:28:01,349 --> 00:28:04,180 +Abychom dosáhni tohoto cíle, jdeme... + +134 +00:28:04,230 --> 00:28:12,500 +navštívit císaře Tangu a povíme mu o této komplikované záležitosti. + +135 +00:28:15,670 --> 00:28:17,819 +Dostali jste vějíř z palmových listů? + +136 +00:28:17,869 --> 00:28:19,400 +Máme ho. + +137 +00:28:19,401 --> 00:28:20,779 +To je ono? + +138 +00:28:22,829 --> 00:28:27,980 +Vznešený hostiteli, teď, když máme vějíř, + +139 +00:28:28,029 --> 00:28:32,140 +můžeme již jít. + +140 +00:28:32,190 --> 00:28:34,039 +Počkejte. + +141 +00:28:34,039 --> 00:28:39,789 +Všichni. Rád bych požádal Sage Senga, aby jste na pár dní zůstali. + +142 +00:28:39,829 --> 00:28:41,339 +Souhlasíte? + +143 +00:28:41,390 --> 00:28:43,460 +Ujednáno! + +144 +00:28:43,509 --> 00:28:45,890 +Děkuji Vám za Vaši laskavost. + +145 +00:28:45,950 --> 00:28:51,779 +Ale odejdeme dříve abychom dokončili náš úkol. + +146 +00:28:51,829 --> 00:28:56,180 +Dobrá tedy. Čestný učeň půjde nejprve k Ohnivé hoře. + +147 +00:28:56,230 --> 00:29:02,140 +Až uhasíš plameny, následuj Sage Senga. + +148 +00:29:02,190 --> 00:29:05,460 +V pořádku. Pokračujte. + +149 +00:30:24,470 --> 00:30:30,029 +Princezna Železný Vějíř je opravdu opovrženíhodná. Dala nám falešný vějíř! + +150 +00:30:30,029 --> 00:30:32,779 +Já ji zabiju! To je jisté. + +151 +00:30:32,829 --> 00:30:36,299 +Ne, zabíjení je špatná věc. + +152 +00:30:36,349 --> 00:30:39,579 +Nedovolím ti nikoho zabít. + +153 +00:30:39,630 --> 00:30:42,980 +Vymysleme něco jiného. + +154 +00:30:52,150 --> 00:30:56,220 +Seniore, jakto že Vás oklamala? + +155 +00:30:56,269 --> 00:30:58,539 +Po vší té námaze + +156 +00:30:58,589 --> 00:31:02,099 +jediné co jsme získali je falešný vějíř. + +157 +00:31:02,150 --> 00:31:06,500 +Směšné, směšné. + +158 +00:31:08,910 --> 00:31:10,420 +Pak tedy jděte! + +159 +00:31:10,470 --> 00:31:14,380 +Ano, půjdu, jdu, odcházím! + +160 +00:31:14,430 --> 00:31:16,908 +Jdu najít Krále Býčího Démona. + +161 +00:31:16,909 --> 00:31:19,940 +To je dobré řešení. + +162 +00:31:21,390 --> 00:31:24,439 +Parťáku, co si o tom myslíš? + +163 +00:31:24,440 --> 00:31:27,380 +Uvidíme jak to půjde. + +164 +00:33:07,190 --> 00:33:11,150 +Co myslíš, jsem dnes půvabná? + +165 +00:33:11,150 --> 00:33:13,779 +Nádherná, má drahá. + +166 +00:33:13,829 --> 00:33:17,059 +Doprovoď mě na procházku mimo jeskyni, ano? + +167 +00:33:17,109 --> 00:33:21,539 +Má drahá, proč nejdeš sama? + +168 +00:33:21,589 --> 00:33:24,819 +To je jasné proč. Jsem obyčejná venkovská holka. + +169 +00:33:24,869 --> 00:33:28,019 +Když půjdu ven tak to může způsobit, že ztratíš tvář. + +170 +00:33:28,069 --> 00:33:32,029 +Miláčku, proč to říkáš? + +171 +00:33:32,029 --> 00:33:37,500 +Pokračuj a já přijdu ven za chvilku, ano? + +172 +00:33:39,852 --> 00:33:44,557 +Jeskyně Smaragdových Mračen + +173 +00:35:28,030 --> 00:35:35,659 +Bohyně, ty jsi skutečný anděl co slétl dolů z nebes. + +174 +00:35:35,710 --> 00:35:37,900 +Kdo... kdo jsi? + +175 +00:35:37,949 --> 00:35:41,460 +Přišel jsem z jeskyně Palmových Listů abych našel krále Býčího Démona. + +176 +00:35:41,519 --> 00:35:43,980 +Jdi ode mě! + +177 +00:35:49,550 --> 00:35:52,940 +Bohyně, zpomal! + +178 +00:36:38,768 --> 00:36:40,133 +Jeskyně Smaragdových Mračen + +179 +00:36:44,230 --> 00:36:49,219 +Miláčku, kdo tě vystrašil? + +180 +00:36:49,269 --> 00:36:50,820 +Ty! + +181 +00:36:50,869 --> 00:36:54,340 +Jak bych tě mohl vystrašit? + +182 +00:36:56,909 --> 00:36:59,260 +Proč nejdeš zpátky do jeskyně Palmových Listů? + +183 +00:36:59,320 --> 00:37:01,699 +To by ti ušetřilo rozpaky. + +184 +00:37:01,750 --> 00:37:07,659 +Oni často posílají lidi aby tě našli a vystrašili mě. + +185 +00:37:07,710 --> 00:37:11,059 +Tady byl někdo kdo mě hledal? + +186 +00:37:11,110 --> 00:37:15,059 +Venku je prasečí mnich, který tě hledá. + +187 +00:37:15,119 --> 00:37:18,510 +On mě k smrti vyděsil. + +188 +00:37:18,550 --> 00:37:22,739 +Jak je tohle možné? Počkej chvíli. Půjdu se podívat ven. + +189 +00:37:50,670 --> 00:37:53,780 +Býku, starý příteli. + +190 +00:37:53,829 --> 00:37:58,139 +Tady vevnitř je nějaká moc krásná mladá dáma. + +191 +00:37:58,199 --> 00:38:03,889 +Hej, to je moje paní. Neopovažuj se ji obtěžovat. + +192 +00:38:03,930 --> 00:38:08,550 +Oh, to jsem nevěděl, prosím promiň mi! + +193 +00:38:08,550 --> 00:38:11,940 +Ty's to nevěděl, tak tě nemůžu obviňovat. A teď už jdi. + +194 +00:38:11,989 --> 00:38:16,099 +Ne, ne. Stále mám něco s čím potřebuji tvou pomoc. + +195 +00:38:18,469 --> 00:38:24,710 +Byli jsme na cestě získat posvátnou knihu když v tom jsme dorazili k Ohnivé hoře. + +196 +00:38:24,710 --> 00:38:27,300 +Prosím, požádej svou choť, + +197 +00:38:27,349 --> 00:38:30,820 +aby nám na chvíli půjčila vějíř z palmových listů. + +198 +00:38:30,880 --> 00:38:33,510 +V žádném případě! Tang Seng a Sun Wukong + +199 +00:38:33,510 --> 00:38:35,179 +jsou nepřátelé mého syna. + +200 +00:38:35,230 --> 00:38:38,739 +Moc rád bych na nich vykonal svou pomstu. + +201 +00:38:38,789 --> 00:38:44,969 +Tvůj syn je nyní s Bohyní Milosrdenství. Prosím, nebojuj. + +202 +00:38:45,030 --> 00:38:48,940 +Dobrá. Jsme staří přátelé tak s tebou nebudu bojovat. + +203 +00:38:49,000 --> 00:38:51,710 +Nyní jdi pryč! + +204 +00:39:38,389 --> 00:39:44,179 +Miláčku, ten prasečí mnich je můj přítel. + +205 +00:39:44,230 --> 00:39:46,500 +On vůbec nebyl poslán z jeskyně Palmových Listů. + +206 +00:39:46,550 --> 00:39:47,739 +Nevěřím ti. + +207 +00:39:47,789 --> 00:39:50,940 +Já ti nelžu! + +208 +00:39:50,989 --> 00:39:54,019 +Kde je ten mnich teď? + +209 +00:39:54,110 --> 00:39:57,780 +Už jsem ho zastrašil. + +210 +00:43:34,814 --> 00:43:40,987 +Jeskyně Palmových Listů + +211 +00:43:58,630 --> 00:44:01,340 +Král se vrátil. + +212 +00:44:01,389 --> 00:44:02,369 +Kde je babička? + +213 +00:44:02,429 --> 00:44:04,780 +Je uvnitř. + +214 +00:44:42,989 --> 00:44:48,219 +Jaká čest, že nás dnes navštívil král. + +215 +00:44:48,269 --> 00:44:52,260 +Slyšel jsem, že sem jsou Sun Wukong a Tang Seng. + +216 +00:44:52,320 --> 00:44:56,909 +Obávám se, že chtějí použít vějíř z palmových listů a přejít Ohnivou horu. + +217 +00:44:56,949 --> 00:45:00,860 +Ten opičák je jeden z těch co zranil našeho syna. + +218 +00:45:00,909 --> 00:45:08,489 +Dostanu ho dříve či později. Dosáhnu naší msty. + +219 +00:45:08,550 --> 00:45:12,699 +Miláčku, proč pláčeš? + +220 +00:45:12,750 --> 00:45:15,699 +Ten opičák už tady byl. + +221 +00:45:15,750 --> 00:45:18,860 +Odmítla jsem mu vějíř dát. + +222 +00:45:18,909 --> 00:45:22,260 +Nevím jak, ale dostal se mi do žaludku. + +223 +00:45:22,309 --> 00:45:25,500 +Bolelo to tak strašně, že jsem myslela že umřu. + +224 +00:45:25,550 --> 00:45:30,589 +Nakonec jsem neměla na výběr a dala jsem mu vějíř. + +225 +00:45:30,789 --> 00:45:35,260 +To je strašné. Jak's mu mohla dát vějíř? + +226 +00:45:38,320 --> 00:45:40,469 +Dala jsem mu falešný. + +227 +00:45:40,720 --> 00:45:43,019 +Falešný? + +228 +00:46:14,190 --> 00:46:19,860 +Večírek na oslavu návratu krále + +229 +00:46:19,909 --> 00:46:25,619 +Prosím, napijte se dobrého vína. + +230 +00:46:25,670 --> 00:46:34,179 +Kuřecí je voňavé, kachna je skvostná a vepřové je tučné. + +231 +00:46:34,239 --> 00:46:45,670 +Zkusím si zazpívat. Zkusím si dobře zatančit. + +232 +00:46:45,710 --> 00:46:54,500 +Musíš také ochutnat náš nejlepší nápoj. + +233 +00:47:03,590 --> 00:47:16,389 +Můj králi. Ty's pustil k vodě tu starou. + +234 +00:47:16,429 --> 00:47:22,610 +Ty miluješ jinou ženu. + +235 +00:47:22,670 --> 00:47:34,659 +Nespočet slz jsem pro tebe naplakala. + +236 +00:47:46,710 --> 00:47:55,699 +Když světlo zhasne a spustí se závěs, + +237 +00:47:55,750 --> 00:48:00,869 +budeš spát sám. + +238 +00:48:00,869 --> 00:48:05,510 +Ty také okusíš samotu. + +239 +00:48:05,510 --> 00:48:13,420 +Omluv mě, že ti nedělám společnost. + +240 +00:48:18,550 --> 00:48:24,619 +Dokonce i když jsme ve stejné posteli, + +241 +00:48:24,670 --> 00:48:34,340 +budeme spát pod oddělenými přikrývkami. + +242 +00:48:38,389 --> 00:48:42,380 +Králi. Jsem opilá. + +243 +00:48:55,070 --> 00:48:58,139 +Miláčku, kam jsi dala skutečný vějíř? + +244 +00:48:58,190 --> 00:49:05,460 +Ten opičák je velmi podvodný a prase je dokonce mnohem nadanější. + +245 +00:49:05,510 --> 00:49:09,780 +Když si nebudeš dávat pozor tak tě mohou obelstít. + +246 +00:49:18,360 --> 00:49:21,980 +Náš poklad je přímo tady. + +247 +00:49:31,429 --> 00:49:39,309 +Králi, na co myslíš? Proč si jej nevezmeš? + +248 +00:49:39,309 --> 00:49:40,847 +Můj poklade. + +249 +00:49:41,514 --> 00:49:44,150 +Jeskyně Smaragdových Mračen + +250 +00:49:44,250 --> 00:49:49,019 +Miláčku, dej si další pohár. Pij. + +251 +00:49:53,909 --> 00:49:59,510 +Zlatý drak mě požádal abych s ním dnes večer pil. + +252 +00:49:59,510 --> 00:50:01,420 +Potom bys měl jít. + +253 +00:50:01,469 --> 00:50:02,860 +Dobrá. + +254 +00:50:02,909 --> 00:50:06,610 +Měl bys pro dědečka připravit zlatooké zvíře. + +255 +00:50:06,670 --> 00:50:08,260 +Připravím. + +256 +00:50:08,320 --> 00:50:12,590 +Měl bys dnes večer pít trochu méně. + +257 +00:50:12,630 --> 00:50:15,739 +Jinak tě nebudu moci probudit. + +258 +00:50:15,800 --> 00:50:19,110 +To je strašné. Dědečkova zlatooká nestvůra zmizela! + +259 +00:50:19,150 --> 00:50:20,900 +Jste všichni hluší a slepí? + +260 +00:50:20,949 --> 00:50:24,030 +Jak mohla zmizet? + +261 +00:50:24,030 --> 00:50:27,900 +Miláčku, nestrachuj se o ně. + +262 +00:50:27,960 --> 00:50:31,710 +Bojím se, že Zhu Bajie ho mohl ukrást. + +263 +00:50:31,750 --> 00:50:35,260 +Možná bych měl prohledat jeskyni Palmových Listů. + +264 +00:50:35,320 --> 00:50:39,309 +Cože? Ty's to plánoval celou dobu. + +265 +00:50:42,280 --> 00:50:48,150 +Stále to chceš prohledat u té nestoudné ženy? + +266 +00:50:48,190 --> 00:50:50,699 +Prosím miláčku, neplakej. + +267 +00:50:50,750 --> 00:50:54,059 +Vrátím se brzy. + +268 +00:50:57,624 --> 00:51:01,194 +Jeskyně Palmových Listů + +269 +00:51:02,670 --> 00:51:07,300 +Pojď sem, napij se trochu! + +270 +00:51:10,349 --> 00:51:12,460 +Teď si můžu odpočinout. + +271 +00:51:12,510 --> 00:51:16,699 +Nemusíme se obávat, že jsme byli oloupeni o náš poklad. + +272 +00:51:16,750 --> 00:51:21,300 +Dokonce i když ho ukradli, tak nebudou vědět, že mají zatáhnout za hedvábnou nit. + +273 +00:51:21,360 --> 00:51:26,269 +Mají perlu, ale nebudou ji moci použít. + +274 +00:51:26,309 --> 00:51:31,780 +Zatáhnutí za nit ji promění na vějíř, že? + +275 +00:51:35,119 --> 00:51:38,070 +Králi, jsi opilý. + +276 +00:51:38,110 --> 00:51:44,019 +Zapomněl jsi na svůj vlastní poklad a ptáš se mě... + +277 +00:51:49,989 --> 00:51:53,690 +Madam, podívej se kdo já jsem. + +278 +00:52:00,320 --> 00:52:03,750 +Kdo jsi? + +279 +00:52:03,789 --> 00:52:09,889 +Já jsem Zhu Bajie, druhý pomocník Tanga Senga. + +280 +00:52:09,949 --> 00:52:14,780 +Omlouvám se, že jsem Vás rušil a díky! + +281 +00:52:19,079 --> 00:52:21,710 +Na shledanou! + +282 +00:53:06,829 --> 00:53:10,699 +Býkova žena je příliš koketní. + +283 +00:53:10,760 --> 00:53:14,710 +Všichni její podřízení jsou krásní. + +284 +00:53:14,750 --> 00:53:24,809 +Starý Čuník to skoro nedokázal. + +285 +00:53:24,869 --> 00:53:28,860 +Použil jsem chytré triky a taktiky. + +286 +00:53:28,909 --> 00:53:32,820 +Uloupil jsem jejich poklad. + +287 +00:53:32,880 --> 00:53:36,789 +To je ohromný výkon. + +288 +00:53:36,829 --> 00:53:38,300 +Písečný by měl klečet. + +289 +00:53:38,349 --> 00:53:40,730 +Opice by se měla učit ode mě. + +290 +00:53:40,789 --> 00:53:45,219 +Dokonce i Mistr bude v úžasu. + +291 +00:53:45,280 --> 00:53:49,190 +Starý Čuník je skutečně mistrovský. + +292 +00:53:49,230 --> 00:53:54,349 +Starý Čuník je skutečně mistrovský. + +293 +00:54:36,719 --> 00:54:40,469 +Hlupáku, jak to jde? + +294 +00:54:40,510 --> 00:54:42,809 +Nejen že jsem získal vějíř, + +295 +00:54:42,880 --> 00:54:48,789 +ale princezna Železný Vějíř byla půl dne mou ženou. + +296 +00:54:48,829 --> 00:54:51,699 +Udělal jsi to dobře. + +297 +00:54:58,150 --> 00:55:01,579 +Hej, ukaž mi ten vějíř. + +298 +00:55:16,030 --> 00:55:20,219 +Proč jsi ho smrštil? + +299 +00:55:40,550 --> 00:55:45,340 +Starý Čuníku, ty mě nepoznáváš, že? + +300 +00:55:45,389 --> 00:55:49,170 +Nedělej si ze mě legraci. + +301 +00:55:49,230 --> 00:55:52,139 +A kdo si z tebe dělá legraci? + +302 +00:56:42,869 --> 00:56:45,380 +Hlupáku, jak se to stalo? + +303 +00:56:45,429 --> 00:56:47,099 +Všechno bylo k ničemu. + +304 +00:56:47,150 --> 00:56:49,980 +Wunengu, vypůjčil jsi ten vějíř? + +305 +00:56:50,030 --> 00:56:53,340 +Našel jsem krále Býčího démona, ale on odmítl. + +306 +00:56:53,400 --> 00:56:59,190 +Potom jsem na sebe vzal jeho podobu. + +307 +00:56:59,230 --> 00:57:03,539 +Oklamal jsem princeznu Železný Vějíř aby mi dala vějíř. + +308 +00:57:03,590 --> 00:57:10,590 +Ale potom si Starý Býk vzal tvou podobu a vylákal ho na mě zpátky. + +309 +00:57:10,590 --> 00:57:12,739 +Schopnosti Starého Býka jsou vynikající. + +310 +00:57:12,800 --> 00:57:16,150 +Potom mě ještě zbil. + +311 +00:57:16,190 --> 00:57:21,380 +Jak jsi mohl získat vějíř a přitom zůstat tak hloupý? + +312 +00:57:21,429 --> 00:57:25,659 +Všechno se neotáčí kolem tebe! + +313 +00:57:30,750 --> 00:57:34,369 +Nebojuj. Musíme rychle vymyslet nějaké řešení. + +314 +00:57:34,429 --> 00:57:40,260 +Ve kterém směru není oheň? + +315 +00:57:40,320 --> 00:57:47,070 +Východ, jih, západ, sever. Oheň není jenom na západě. + +316 +00:57:47,119 --> 00:57:50,739 +Tak to nemáme jinou možnost než se vrátit. + +317 +00:57:50,789 --> 00:57:52,940 +Tato stezka je zablokovaná. Jaké máme jiné možnosti? + +318 +00:57:52,989 --> 00:57:55,219 +Bajie, nemluv tak. + +319 +00:57:55,269 --> 00:57:59,139 +Na naší cestě budou vždy překážky. + +320 +00:57:59,190 --> 00:58:04,539 +Abychom dokončili náš posvátný úkol, musíme být silní v naší víře. + +321 +00:58:04,590 --> 00:58:09,219 +Nemůžeme změnit náš plán jenom kvůli tomu, že jsme narazili na pár překážek. + +322 +00:58:09,280 --> 00:58:14,590 +Důvod proč jsme byli poraženi je ten, že jsme nespolupracovali. + +323 +00:58:14,630 --> 00:58:17,139 +Pokud tři z nás budou jako jeden, + +324 +00:58:17,190 --> 00:58:20,500 +dáme síly dohromady a zdoláme krále Býčího Démona. + +325 +00:58:20,550 --> 00:58:22,849 +A vítězství bude naše. + +326 +00:58:22,909 --> 00:58:26,030 +Slyšeli jsme Mistrův rozkaz + +327 +00:58:26,030 --> 00:58:30,139 +a budeme s králem Býčím Démonem bojovat až do konce. + +328 +00:58:30,190 --> 00:58:34,260 +až... až do konce. + +329 +00:58:34,320 --> 00:58:37,710 +To je skvělé! + +330 +00:58:37,750 --> 00:58:40,980 +Všichni jsme dokázali překonat nesnáze. + +331 +00:58:41,039 --> 00:58:43,869 +Doufám, že každý vynaloží veškeré úsilí + +332 +00:58:43,869 --> 00:58:49,579 +společně s mými učedníky k porážce krále Býčího Démona a uhasíme plameny Ohnivé hory. + +333 +00:58:49,630 --> 00:58:52,820 +Jinak toto neštěstí nikdy neskončí. + +334 +00:58:53,869 --> 00:58:57,489 +Slyšeli jsme Mistrovo nařízení na dosažení štěstí pro všechny. + +335 +00:58:57,550 --> 00:58:58,860 +Společně to dokážeme! + +336 +00:58:58,909 --> 00:59:00,519 +Hurá! + +337 +01:08:23,229 --> 01:08:25,609 +Babičko, to je strašné! + +338 +01:08:25,670 --> 01:08:30,789 +Dědeček je chycen. Pojď se rychle podívat. + +339 +01:08:54,470 --> 01:08:56,699 +Ještě není po boji. Ještě ne. + +340 +01:08:56,760 --> 01:08:58,710 +Pozor. Opatrně. + +341 +01:08:59,760 --> 01:09:05,789 +Nestvůro, jediné co musíš udělat je dát nám vějíř a ušetříme tvůj život. + +342 +01:09:05,840 --> 01:09:12,750 +Starý Býku, kde je vějíř? Odevzdej ho! + +343 +01:09:12,789 --> 01:09:19,340 +Moje ... moje choť... jej má. + +344 +01:09:25,239 --> 01:09:27,989 +Drahoušku, drahoušku! + +345 +01:09:28,029 --> 01:09:32,260 +Zachraň mě, rychle! + +346 +01:09:32,319 --> 01:09:35,109 +Dej jim vějíř. + +347 +01:09:35,149 --> 01:09:39,619 +Králi! Ano, ano. + +348 +01:09:43,399 --> 01:09:47,229 +Wukongu, jdi na to ještě jednou! + +349 +01:12:30,850 --> 01:12:46,599 +Konec + diff --git a/js2/mwEmbed/example_usage/media/princess_archive_org/princess_iron_fan-ru.srt b/js2/mwEmbed/example_usage/media/princess_archive_org/princess_iron_fan-ru.srt new file mode 100644 index 0000000000..9a9f8ab2ab --- /dev/null +++ b/js2/mwEmbed/example_usage/media/princess_archive_org/princess_iron_fan-ru.srt @@ -0,0 +1,1414 @@ +1 +00:00:01,080 --> 00:00:09,070 +Принцесса Железный Веер + +2 +00:02:03,109 --> 00:02:09,280 +Путешествие на Запад это замечательная детская история + +3 +00:02:09,280 --> 00:02:15,280 +но мир часто неправильно воспринимает ее, как фантастическую. + +4 +00:02:15,280 --> 00:02:19,240 +Этот фильм был сделан для того, чтобы + +5 +00:02:19,240 --> 00:02:24,240 +воспитать сердца и ума детей. + +6 +00:02:24,240 --> 00:02:29,280 +История чиста, не испорчена фантазией. + +7 +00:02:29,280 --> 00:02:32,560 +Огненная Гора, преграждающая дорогу Танскому монаху и его ученикам - + +8 +00:02:32,560 --> 00:02:41,039 +это аллегория жизненных трудностей. + +9 +00:02:41,039 --> 00:02:46,439 +Чтобы преодолеть их, нужно хранить веру. +Каждый должен сделать все, + +10 +00:02:46,439 --> 00:02:52,430 +чтобы получить веер пальмового листа и потушить огонь. + +11 +00:02:52,839 --> 00:02:58,178 +Tрипитака Истинная Сутра + +12 +00:03:34,479 --> 00:03:37,789 +Уже осень, как еще может быть так жарко? + +13 +00:03:37,840 --> 00:03:42,349 +Дурень, не болтай ерунды! Нам надо поспешить и найти верную дорогу. + +14 +00:04:06,919 --> 00:04:09,349 +Укун, где мы? + +15 +00:04:09,400 --> 00:04:13,669 +Наш путь на Запад лежит через эту местность, это уж точно. + +16 +00:04:13,719 --> 00:04:18,110 +Может, мы идем не в ту сторону ? + +17 +00:04:18,149 --> 00:04:21,700 +Почему здесь так жарко? + +18 +00:04:30,029 --> 00:04:31,649 +Наставник, смотрите! + +19 +00:04:31,650 --> 00:04:33,779 +Разве там не дом, впереди? + +20 +00:04:33,829 --> 00:04:38,100 +Давайте, зайдем и отдохнем немного, ладно? + +21 +00:04:59,389 --> 00:05:02,899 +Это место носит название Огненная Гора. + +22 +00:05:02,949 --> 00:05:06,019 +Огонь распространяется на сотни миль. + +23 +00:05:06,069 --> 00:05:08,740 +Ни одна травинка не может расти здесь. + +24 +00:05:08,790 --> 00:05:11,620 +Целый год жарко. + +25 +00:05:11,680 --> 00:05:19,629 +Вы не сможете пройти через эту гору даже если у вас голова из меди, а тело из железа. + +26 +00:05:19,670 --> 00:05:23,579 +Что это за место? Наставник, не волнуйся! + +27 +00:05:23,629 --> 00:05:27,139 +Трое из нас достаточно сильны, чтобы прокладывать дорогу! + +28 +00:05:27,189 --> 00:05:30,699 +Наставник, я пойду взглянуть! + +29 +00:08:06,310 --> 00:08:09,579 +Укун, ну что? + +30 +00:08:09,629 --> 00:08:11,819 +Плохо, плохо, очень плохо. + +31 +00:08:11,879 --> 00:08:15,910 +Если бы я немного замешкался, мой хвост бы сгорел. + +32 +00:08:42,720 --> 00:08:47,600 +Почтеный хозяин, огонь в ваших краях так велик. + +33 +00:08:47,600 --> 00:08:49,669 +Как вы можете что-то выращивать? + +34 +00:08:49,710 --> 00:08:53,980 +Тысяча миль отсюда живет принцесса Железный Веер. + +35 +00:08:54,039 --> 00:08:56,500 +У нее есть веер из листа пальмы. + +36 +00:08:56,559 --> 00:08:59,070 +Махнешь им раз, и огонь прекращается. + +37 +00:08:59,120 --> 00:09:01,629 +Два раза, и поднимается ветер. + +38 +00:09:01,679 --> 00:09:03,980 +Три раза, и начинает идти дождь. + +39 +00:09:04,039 --> 00:09:07,509 +И вот тогда, мы сеем и собираем урожай. + +40 +00:09:07,559 --> 00:09:11,340 +Однако уговорить эту принцессу прийти + +41 +00:09:11,399 --> 00:09:14,870 +довольно трудно. + +42 +00:09:14,909 --> 00:09:16,820 +Где она живет? + +43 +00:09:16,879 --> 00:09:20,190 +Она живет в Пещере Листа Пальмы на Горе Изумрудных Облаков. + +44 +00:09:20,240 --> 00:09:23,669 +Она там одна живет? + +45 +00:09:23,720 --> 00:09:25,750 +Разве у нее нет мужа? + +46 +00:09:25,799 --> 00:09:29,580 +Ее муж - Князь демонов с головой быка. + +47 +00:09:29,639 --> 00:09:32,200 +Значит, ее муж - Старый Бык? + +48 +00:09:32,240 --> 00:09:36,789 +Ты знаком с ним, дурень? Иди со мной за веером! + +49 +00:09:36,840 --> 00:09:41,750 +Фактически... Старый Бык не живет там. + +50 +00:09:41,799 --> 00:09:46,350 +Прийти к его жене, когда он не дома - + +51 +00:09:46,399 --> 00:09:51,519 +не очень ... осторожный поступок. + +52 +00:09:51,559 --> 00:09:58,309 +Вы ... вы ... двое идите + +53 +00:09:58,360 --> 00:10:04,290 +А я... я останусь здесь и буду охранять учителя. + +54 +00:10:04,440 --> 00:10:11,269 +Ша Удзин, иди вместе с братьями. + + + +55 +00:10:38,571 --> 00:10:44,978 +Пещера Листа Пальмы + +56 +00:10:47,200 --> 00:10:51,549 +Дурень, я всегда иду первым. + +57 +00:10:51,600 --> 00:10:54,350 +Теперь твоя очередь! + +58 +00:10:58,519 --> 00:11:04,909 +Младший! Я всегда иду первым, теперь твоя очередь! + +59 +00:11:04,960 --> 00:11:06,830 +Старший... + +60 +00:11:06,879 --> 00:11:10,990 +Я хочу, чтобы ты тоже немного постарался для наставника. Неужели это так трудно? + +61 +00:11:11,039 --> 00:11:14,309 +Веселей! + +62 +00:11:39,639 --> 00:11:43,039 +Бедный монах, откуда ты пришел? + +63 +00:11:43,039 --> 00:11:49,870 +Великий Мудрец... Танский монах ... хочет вашу принцессу... + +64 +00:11:49,919 --> 00:11:52,480 +Глупости! + +65 +00:12:47,549 --> 00:12:52,059 +Старший ... может тебе пойти следующим? + +66 +00:12:52,120 --> 00:12:56,950 +Дурень, иди ты! + +67 +00:12:57,000 --> 00:13:00,700 +Старший, почему не идешь? + +68 +00:13:04,029 --> 00:13:07,460 +Ленивый дурень! + +69 +00:13:54,279 --> 00:13:57,899 +Великий Бог Грома! Не убивай меня, позволь мне уйти! + +70 +00:13:57,960 --> 00:13:59,950 +Иди и доложи своей принцессе, + +71 +00:14:00,000 --> 00:14:03,279 +что явился Сунь Укун одолжить у нее веер. + +72 +00:14:03,279 --> 00:14:08,399 +Да, да! Отпусти, я сразу пойду. + +73 +00:14:29,559 --> 00:14:37,059 +Госпожа, пришел Сунь Укун, чтобы одолжить веер. + +74 +00:14:41,519 --> 00:14:44,149 +Живо принесите мне мой меч. + +75 +00:15:01,639 --> 00:15:04,149 +Сунь Укун, ты погубил моего сына! + +76 +00:15:04,200 --> 00:15:08,549 +И ты еще смеешь являться сюда на свою погибель? + +77 +00:15:08,600 --> 00:15:12,039 +Я никогда не встречал тебя прежде, как же я мог навредить твоему сыну? + +78 +00:15:12,039 --> 00:15:15,789 +Разве жизнь моего сына, Красного Ребенка, была разрушена не из-за тебя? + +79 +00:15:15,840 --> 00:15:20,389 +Твой сын теперь во власти Богини Милосердия, как ты можешь говорить, что я погубил его? + +80 +00:15:20,440 --> 00:15:23,750 +Довольно болтовни! Иди сюда и нагнись, я разрублю тебя своим мечом. + +81 +00:15:23,799 --> 00:15:26,149 +Если останешься жив, отдам тебе веер. + +82 +00:15:26,200 --> 00:15:28,549 +Правда? + +83 +00:15:56,799 --> 00:16:00,629 +Стой! Сейчас же отдавай веер! + + +84 +00:17:53,630 --> 00:18:00,099 +Великий Мудрец, разве вы не на Запад шли? Почему вы вернулись сюда? + +85 +00:18:11,150 --> 00:18:17,140 +Принцесса махнула веером, и поднялся страшный ветер, который принес меня сюда. + +86 +00:18:17,190 --> 00:18:23,859 +Это действительно странно, Великий Мудрец. У меня есть кое-что для тебя. + +87 +00:18:28,509 --> 00:18:33,450 +Это жемчужина против ветра. Когда ты примешь ее, + +88 +00:18:33,509 --> 00:18:36,140 +твое сердце станет устойчивым, как скала. + +89 +00:18:36,190 --> 00:18:39,180 +Веер принцессы не сможет сдвинуть тебя с места. + +90 +00:18:39,230 --> 00:18:42,849 +Великий Мудрец, подойди и посмотри. + +91 +00:19:00,430 --> 00:19:02,539 +Спасибо тебе. + +92 +00:19:06,069 --> 00:19:12,299 +Старший... где... к? + +93 +00:19:12,349 --> 00:19:18,690 +где его... носит? + +94 +00:19:18,750 --> 00:19:26,099 +Кто заботится о нем? Спасение обезьяны в ее руках. Пойдем. + +95 +00:19:35,190 --> 00:19:37,259 +Старший ... старший... + +96 +00:19:37,309 --> 00:19:43,470 +Ты... ты... + +97 +00:19:43,470 --> 00:19:50,220 +Куда тебя унесло из за той старухи? + +98 +00:19:50,269 --> 00:19:57,180 +Дурень, теперь определенно твоя очередь идти. + +99 +00:19:57,230 --> 00:20:00,930 +Я не пойду, одна воздушная волна ее веера + +100 +00:20:00,990 --> 00:20:03,450 +может унести меня на край света. + +101 +00:20:03,509 --> 00:20:09,710 +Наверное, лучше, если ты снова пойдешь. + +102 +00:20:09,710 --> 00:20:12,220 +Я не пойду. + +103 +00:20:17,789 --> 00:20:22,779 +В следующий раз я тебя не отпущу! + +104 +00:20:56,150 --> 00:21:00,140 +На сей раз я с места не сдвинусь, сколько бы ты ни махала, + +105 +00:21:00,190 --> 00:21:05,210 +это так же верно, как то, что я - человек! + +106 +00:21:33,670 --> 00:21:38,579 +Старший, почему ветер в этот раз не унес тебя? + +107 +00:21:46,829 --> 00:21:50,099 +Давай, взломим дверь. + +108 +00:23:59,630 --> 00:24:04,180 +Живо доставайте веер для Сунь Укуна! + +109 +00:24:14,869 --> 00:24:16,900 +Сунь Укун, где ты? + +110 +00:24:16,950 --> 00:24:19,980 +Я у тебя в животе! + +111 +00:24:45,750 --> 00:24:48,539 +Сунь Укун, смилуйся надо мной! + +112 +00:24:48,589 --> 00:24:51,180 +Только, если отдашь веер! + +113 +00:24:51,230 --> 00:24:56,539 +Я клянусь, я отдам. Пожалуйста, выходи! + +114 +00:25:00,230 --> 00:25:02,819 +Живо принесите веер. + +115 +00:25:07,430 --> 00:25:09,220 +Мы принесли веер. + +116 +00:25:09,279 --> 00:25:12,069 +Почему же ты не выходишь? + +117 +00:25:12,109 --> 00:25:16,619 +Открой рот, и я выйду. + +118 +00:25:25,349 --> 00:25:29,420 +Сунь Укун, почему ты не вышел? + +119 +00:25:50,349 --> 00:25:55,579 +Я здесь. Одолжи мне веер ненадолго и я верну его. + +120 +00:26:32,549 --> 00:26:36,579 +Наставник заждался, давайте поспешим! + + + +121 +00:27:01,869 --> 00:27:04,900 +Что такое священные книги? + +122 +00:27:04,950 --> 00:27:10,029 +Священные книги это законы неба и земли. + +123 +00:27:10,029 --> 00:27:14,180 +Они являются принципами человека. + +124 +00:27:14,230 --> 00:27:18,700 +Только тот, кто признает эти принципы, + +125 +00:27:18,750 --> 00:27:25,339 +сможет избавить себя от боли и жить хорошо, + +126 +00:27:25,390 --> 00:27:29,940 +жить честной, истинной жизнью. + +127 +00:27:34,680 --> 00:27:36,349 +И наоборот, + +128 +00:27:36,390 --> 00:27:40,089 +тот, кто не знает эти принципы, + +129 +00:27:40,150 --> 00:27:46,380 +будет жить жизнью, полной страдания. + +130 +00:27:46,430 --> 00:27:52,609 +Даже его сын или внук не достигнут счастья. + +131 +00:27:52,670 --> 00:27:55,660 +Почему я надеюсь получить священные книги? + +132 +00:27:55,710 --> 00:28:01,299 +Люди в наше время пойманы в ловушку страданий. + +133 +00:28:01,349 --> 00:28:04,180 +И чтобы это изменить, мы идем поклониться + +134 +00:28:04,230 --> 00:28:12,500 +Танскому императору и обсудить этот очень сложный вопрос. + + + + +135 +00:28:15,670 --> 00:28:17,819 +Вы добыли веер? + +136 +00:28:17,869 --> 00:28:19,400 +Он у нас. + +137 +00:28:19,401 --> 00:28:20,779 +Что это? + +138 +00:28:22,829 --> 00:28:27,980 +Благородные хозяева, теперь, когда у нас есть веер, + +139 +00:28:28,029 --> 00:28:32,140 +мы можем отдохнуть. + +140 +00:28:32,190 --> 00:28:34,039 +Держитесь. + +141 +00:28:34,039 --> 00:28:39,789 +Народ, я хотел бы попросить мудрого Сэнга погостить у нас еще нескольких дней. + +142 +00:28:39,829 --> 00:28:41,339 +Вы согласны? + +143 +00:28:41,390 --> 00:28:43,460 +Согласны! + +144 +00:28:43,509 --> 00:28:45,890 +Спасибо вам за вашу доброту. + +145 +00:28:45,950 --> 00:28:51,779 +Но чем скорее я уеду, тем скорее мы сможем завершить нашу задачу. + +146 +00:28:51,829 --> 00:28:56,180 +Очень хорошо, пусть благородный ученик сначала пойдет на Огненную Гору. + +147 +00:28:56,230 --> 00:29:02,140 +После гашения огней, продолжите следовать за мудрым Сэнгом. + +148 +00:29:02,190 --> 00:29:05,460 +Хорошо, вперед! + +149 +00:30:24,470 --> 00:30:30,029 +Принцесса действительно коварна, она дала нам фальшивый веер! + +150 +00:30:30,029 --> 00:30:32,779 +Я точно убью ее! + +151 +00:30:32,829 --> 00:30:36,299 +Нет, убивать нельзя. + +152 +00:30:36,349 --> 00:30:39,579 +Я не позволю вам никого убивать. + +153 +00:30:39,630 --> 00:30:42,980 +Давайте придумаем что-нибудь другое. + +154 +00:30:52,150 --> 00:30:56,220 +Старший, как она могла тебя одурачить? + +155 +00:30:56,269 --> 00:30:58,539 +После стольких усилий + +156 +00:30:58,589 --> 00:31:02,099 +все, чего мы достигли, оказалось фальшивым веером. + +157 +00:31:02,150 --> 00:31:06,500 +Смешно, смешно. + +158 +00:31:08,910 --> 00:31:10,420 +Тогда идешь ты! + +159 +00:31:10,470 --> 00:31:14,380 +Хорошо, я пойду, я пойду, я иду! + +160 +00:31:14,430 --> 00:31:16,908 +Я пойду искать Князя Демонов с головой быка. + +161 +00:31:16,909 --> 00:31:19,940 +Это хорошее решение. + +162 +00:31:21,390 --> 00:31:24,439 +Братец, что скажешь? + +163 +00:31:24,440 --> 00:31:27,380 +Мы будем следить за тобой. + + + +164 +00:33:07,190 --> 00:33:11,150 +Как ты считаешь, я хороша сегодня? + +165 +00:33:11,150 --> 00:33:13,779 +Ты красавица, крошка. + +166 +00:33:13,829 --> 00:33:17,059 +Пойди со мной на прогулку, ладно? + +167 +00:33:17,109 --> 00:33:21,539 +Моя крошка, может тебе лучше пойти одной. + +168 +00:33:21,589 --> 00:33:24,819 +Конечно, я всего лишь бедная девушка страны. + +169 +00:33:24,869 --> 00:33:28,019 +Сопровождение меня вне пещеры может скомпрометировать тебя. + +170 +00:33:28,069 --> 00:33:32,029 +Милая, что ты говоришь? + +171 +00:33:32,029 --> 00:33:37,500 +Иди вперед, а я выйду следом, хорошо? + +172 +00:33:39,852 --> 00:33:44,557 +Пещера Изумрудных Облаков + +173 +00:35:28,030 --> 00:35:35,659 +Божественная, вы и вправду ангел, сошедший с небес. + +174 +00:35:35,710 --> 00:35:37,900 +Кто ... кто вы? + +175 +00:35:37,949 --> 00:35:41,460 +Я пришел из Пещеры Листа Пальмы к Князю Демонов с головой быка. + +176 +00:35:41,519 --> 00:35:43,980 +Пустите меня! + +177 +00:35:49,550 --> 00:35:52,940 +Божественная, подожди! + +178 +00:36:38,768 --> 00:36:40,133 +Пещера Изумрудных Облаков + +179 +00:36:44,230 --> 00:36:49,219 +Крошка, кто тебя обидел? + +180 +00:36:49,269 --> 00:36:50,820 +Ты! + +181 +00:36:50,869 --> 00:36:54,340 +Чем я мог обидеть тебя? + +182 +00:36:56,909 --> 00:36:59,260 +Почему ты не возвращаешься в Пещеру Листа Пальмы? + +183 +00:36:59,320 --> 00:37:01,699 +У тебя было бы меньше хлопот. + +184 +00:37:01,750 --> 00:37:07,659 +За вами специально посылают людей, чтобы измываться надо мной. + +185 +00:37:07,710 --> 00:37:11,059 +За мной кто-то приходил? + +186 +00:37:11,110 --> 00:37:15,059 +Пришел монах с мордой свиньи, он ищет вас. + +187 +00:37:15,119 --> 00:37:18,510 +Он почти испугал меня до смерти. + +188 +00:37:18,550 --> 00:37:22,739 +Как это может быть? Подожди, я выйду взглянуть. + +189 +00:37:50,670 --> 00:37:53,780 +Бык, старина! + +190 +00:37:53,829 --> 00:37:58,139 +Здесь есть очень красивая девушка. + +191 +00:37:58,199 --> 00:38:03,889 +Эй, это же моя женщина! Зачем ты ее тиранишь? + +192 +00:38:03,930 --> 00:38:08,550 +Ой, я не знал, прости меня! + +193 +00:38:08,550 --> 00:38:11,940 +Ну раз не знал, не могу тебя винить. Можешь идти! + +194 +00:38:11,989 --> 00:38:16,099 +Нет, нет. Мне все еще нужна твоя помощь в одном деле. + +195 +00:38:18,469 --> 00:38:24,710 +Мы продолжаем наш путь за священными книгами и дошли до Огненной Горы. + +196 +00:38:24,710 --> 00:38:27,300 +Пожалуйста, попроси свою жену + +197 +00:38:27,349 --> 00:38:30,820 +одолжить нам пальмовый веер ненадолго. + +198 +00:38:30,880 --> 00:38:33,510 +Абсолютно нет! Танский монах Сенг и Сунь Укун - + +199 +00:38:33,510 --> 00:38:35,179 +враги моего сына. + +200 +00:38:35,230 --> 00:38:38,739 +Я жажду им отомстить. + +201 +00:38:38,789 --> 00:38:44,969 +Ваш сын теперь служит Богини Милосердия, пожалуйста, успокойся. + +202 +00:38:45,030 --> 00:38:48,940 +Хорошо, так как мы старые друзья, я не буду драться с тобой. + +203 +00:38:49,000 --> 00:38:51,710 +А теперь уходи! + +204 +00:39:38,389 --> 00:39:44,179 +Крошка, тот монах с мордой свиньи мой друг. + +205 +00:39:44,230 --> 00:39:46,500 +Его вообще не посылали из Пещеры Листа Пальмы. + +206 +00:39:46,550 --> 00:39:47,739 +Я не верю вам. + +207 +00:39:47,789 --> 00:39:50,940 +Я тебя не обманываю! + +208 +00:39:50,989 --> 00:39:54,019 +Где же он теперь? + +209 +00:39:54,110 --> 00:39:57,780 +Я уже прогнал его. + + + +210 +00:43:34,814 --> 00:43:40,987 +Пещера Листа Пальмы + +211 +00:43:58,630 --> 00:44:01,340 +Повелитель вернулся! + +212 +00:44:01,389 --> 00:44:02,369 +Где госпожа? + +213 +00:44:02,429 --> 00:44:04,780 +Она там. + +214 +00:44:42,989 --> 00:44:48,219 +Почему повелитель оказал такую честь и пришел сегодня? + +215 +00:44:48,269 --> 00:44:52,260 +Я услышал, что Сунь Укун и танский монах Сэнг идут сюда. + +216 +00:44:52,320 --> 00:44:56,909 +Я боюсь, что они хотят добыть веер пальмового листа, чтобы перейти Огненную Гору. + +217 +00:44:56,949 --> 00:45:00,860 +Та обезьяна - именно тот, кто вредил нашему сыну. + +218 +00:45:00,909 --> 00:45:08,489 +Рано или поздно я поймаю его, и мы отомстим. + +219 +00:45:08,550 --> 00:45:12,699 +Дорогая, почему ты плачешь? + +220 +00:45:12,750 --> 00:45:15,699 +Эта обезьяна уже была здесь. + +221 +00:45:15,750 --> 00:45:18,860 +Я отказалась дать ему веер. + +222 +00:45:18,909 --> 00:45:22,260 +Я не знаю как, но он проник ко мне в живот. + +223 +00:45:22,309 --> 00:45:25,500 +Мне было так плохо, я думала, что умру. + +224 +00:45:25,550 --> 00:45:30,589 +В итоге, мне пришлось отдать веер. + +225 +00:45:30,789 --> 00:45:35,260 +Какой ужас, как ты могла отдать ему веер? + +226 +00:45:38,320 --> 00:45:40,469 +Я дала ему поддельный. + +227 +00:45:40,720 --> 00:45:43,019 +Поддельный? + + +228 +00:46:14,190 --> 00:46:19,860 +Пир в честь повелителя + +229 +00:46:19,909 --> 00:46:25,619 +Пожалуйста выпей прекрасное вино. + +230 +00:46:25,670 --> 00:46:34,179 +Цыпленок ароматен, утка красива, и свинья жирна. + +231 +00:46:34,239 --> 00:46:45,670 +Я изо всех сил пытаюсь петь и танцевать. + +232 +00:46:45,710 --> 00:46:54,500 +Ты должна также изо всех сил пить. + +233 +00:47:03,590 --> 00:47:16,389 +Мой повелитель! Ты оставил прошлое. + +234 +00:47:16,429 --> 00:47:22,610 +Ты любишь другую женщину. + +235 +00:47:22,670 --> 00:47:34,659 +Бесчисленные слезы были пролиты ради тебя. + +236 +00:47:46,710 --> 00:47:55,699 +Когда свет погаснет и опустят занавески, + +237 +00:47:55,750 --> 00:48:00,869 +ты будешь спать один. + +238 +00:48:00,869 --> 00:48:05,510 +Ты также почувствуешь одинокость. + +239 +00:48:05,510 --> 00:48:13,420 +Извини, что не могу составить тебе компанию. + +240 +00:48:18,550 --> 00:48:24,619 +Даже если мы будем на той же кровати, + +241 +00:48:24,670 --> 00:48:34,340 +мы будем спать под отдельными листами. + +242 +00:48:38,389 --> 00:48:42,380 +Король, я пьяна. + +243 +00:48:55,070 --> 00:48:58,139 +Супруженька, куда же ты спрятала настоящий веер? + +244 +00:48:58,190 --> 00:49:05,460 +Эта обезьяна очень коварна, а кабан еще хитрее. + +245 +00:49:05,510 --> 00:49:09,780 +Если не будешь осторожной, они тебя могут обмануть. + +246 +00:49:18,360 --> 00:49:21,980 +Наше драгоценность прямо здесь. + +247 +00:49:31,429 --> 00:49:39,309 +Повелитель, о чем ты задумался? Почему не берешь ее? + +248 +00:49:39,309 --> 00:49:40,847 +Моя драгоценность. + +249 +00:49:41,514 --> 00:49:44,150 +Пещера Изумрудных Облаков + +250 +00:49:44,250 --> 00:49:49,019 +Крошка, бери другую чашку. Пей. + +251 +00:49:53,909 --> 00:49:59,510 +Золотой царь драконов попросил, чтобы я выпил с ним сегодня вечером. + +252 +00:49:59,510 --> 00:50:01,420 +Тогда вы должны пойти. + +253 +00:50:01,469 --> 00:50:02,860 +Правильно. + +254 +00:50:02,909 --> 00:50:06,610 +Подготовь золотое животное к дедушке. + +255 +00:50:06,670 --> 00:50:08,260 +Я мигом. + +256 +00:50:08,320 --> 00:50:12,590 +Вы должны выпить поменьше сегодня вечером. + +257 +00:50:12,630 --> 00:50:15,739 +Иначе я не смогу разбудить вас. + +258 +00:50:15,800 --> 00:50:19,110 +Какой ужас, золотое глазастое животное дедушки исчезло! + +259 +00:50:19,150 --> 00:50:20,900 +Действительно ли вы - все тугоухие и слепые? + +260 +00:50:20,949 --> 00:50:24,030 +Как оно могло просто исчезнуть? + +261 +00:50:24,030 --> 00:50:27,900 +Крошка, не спорь. + +262 +00:50:27,960 --> 00:50:31,710 +Я боюсь, что Джу Бацзе, возможно, украл его. + +263 +00:50:31,750 --> 00:50:35,260 +Может мне лучше пойти к Пещере Листа Пальмы. + +264 +00:50:35,320 --> 00:50:39,309 +Что? Все это заранее планировалось вами. + +265 +00:50:42,280 --> 00:50:48,150 +Вы все еще хотите вернуться к той бессовестной женщине? + +266 +00:50:48,190 --> 00:50:50,699 +Пожалуйста, крошка, не плачь. + +267 +00:50:50,750 --> 00:50:54,059 +Я скоро вернусь. + + +268 +00:50:57,624 --> 00:51:01,194 +Пещера Листа Пальмы + +269 +00:51:02,670 --> 00:51:07,300 +Иди сюда, выпей немного! + +270 +00:51:10,349 --> 00:51:12,460 +Теперь я могу быть спокоен. + +271 +00:51:12,510 --> 00:51:16,699 +Мы можем не волноваться по поводу нашей драгоценности. + +272 +00:51:16,750 --> 00:51:21,300 +Даже если бы они похитили веер, они бы все-равно не знали что надо тянуть шелковую нить. + +273 +00:51:21,360 --> 00:51:26,269 +Одна жемчужина ни на что не способна. + +274 +00:51:26,309 --> 00:51:31,780 +Натягивание нити превращает ее в веер, правильно? + +275 +00:51:35,119 --> 00:51:38,070 +Повелитель, ты пьян. + +276 +00:51:38,110 --> 00:51:44,019 +Ты забыл как пользоваться собственной драгоценностью и спрашиваешь у меня. + +277 +00:51:49,989 --> 00:51:53,690 +Женщина, посмотри, кто перед тобой. + +278 +00:52:00,320 --> 00:52:03,750 +Кто вы? + +279 +00:52:03,789 --> 00:52:09,889 +Я - второй ученик танского монаха, Джу Бацзе. + +280 +00:52:09,949 --> 00:52:14,780 +Извини за беспокойство, и спасибо! + +281 +00:52:19,079 --> 00:52:21,710 +Пока! + + +282 +00:53:06,829 --> 00:53:10,699 +Жена быка слишком кокетливая. + +283 +00:53:10,760 --> 00:53:14,710 +Все ее служанки красивы. + +284 +00:53:14,750 --> 00:53:24,809 +Старый Кабан почти не справился. + +285 +00:53:24,869 --> 00:53:28,860 +Используя умные уловки и тактику, + +286 +00:53:28,909 --> 00:53:32,820 +я украл их драгоценность. + +287 +00:53:32,880 --> 00:53:36,789 +Это большой подвиг. + +288 +00:53:36,829 --> 00:53:38,300 +Монах Песков должен мне поклониться. + +289 +00:53:38,349 --> 00:53:40,730 +Обезьяне следует у меня поучиться. + +290 +00:53:40,789 --> 00:53:45,219 +Даже наставник будет удивлен. + +291 +00:53:45,280 --> 00:53:49,190 +Старый Кабан действительно лучше всех. + +292 +00:53:49,230 --> 00:53:54,349 +Старый Кабан действительно лучше всех. + + +293 +00:54:36,719 --> 00:54:40,469 +Дурень, как идут дела? + +294 +00:54:40,510 --> 00:54:42,809 +Мало того, что я получил веер, + +295 +00:54:42,880 --> 00:54:48,789 +Еще и принцесса Железный Веер полдня была моей женой. + +296 +00:54:48,829 --> 00:54:51,699 +Тебе повезло. + +297 +00:54:58,150 --> 00:55:01,579 +Эй, покажи мне веер. + +298 +00:55:16,030 --> 00:55:20,219 +Почему ты уменьшил его? + +299 +00:55:40,550 --> 00:55:45,340 +Старая Свинья, ты узнаешь меня, верно? + +300 +00:55:45,389 --> 00:55:49,170 +Прекрати шутить со мной. + +301 +00:55:49,230 --> 00:55:52,139 +А разве с тобой кто-нибудь шутит? + + +302 +00:56:42,869 --> 00:56:45,380 +Дурень, как прошло? + +303 +00:56:45,429 --> 00:56:47,099 +Ничего не вышло. + +304 +00:56:47,150 --> 00:56:49,980 +Унэн, ты достал веер? + +305 +00:56:50,030 --> 00:56:53,340 +Я нашел Князя демонов, но он отказался. + +306 +00:56:53,400 --> 00:56:59,190 +Тогда я превратился в него. + +307 +00:56:59,230 --> 00:57:03,539 +Хитростью я выманил веер у Принцессы. + +308 +00:57:03,590 --> 00:57:10,590 +Но тогда Старый Бык превратился в тебя и тоже меня обманул. + +309 +00:57:10,590 --> 00:57:12,739 +Старый Бык обладает большой волшебной силой. + +310 +00:57:12,800 --> 00:57:16,150 +Он еще и меня побил. + +311 +00:57:16,190 --> 00:57:21,380 +Как же ты мог получить веер и оказаться таким дурнем? + +312 +00:57:21,429 --> 00:57:25,659 +Не воображай! + +313 +00:57:30,750 --> 00:57:34,369 +Не ссорьтесь, мы должны срочно что-то придумать. + +314 +00:57:34,429 --> 00:57:40,260 +Найти какой... какой-нибудь обход, где нет огня? + +315 +00:57:40,320 --> 00:57:47,070 +Из востока, юга, запада, севера, огонь распространяется только на Запад. + +316 +00:57:47,119 --> 00:57:50,739 +Поэтому мы можем только повернуть. + +317 +00:57:50,789 --> 00:57:52,940 +Эта дорога закрыта для нас, что еще можно делать? + +318 +00:57:52,989 --> 00:57:55,219 +Бадзе, не говори так. + +319 +00:57:55,269 --> 00:57:59,139 +На нашей дороге всегда будут преграды. + +320 +00:57:59,190 --> 00:58:04,539 +Чтобы завершить нашу священную задачу, мы должны быть сильными в нашей вере. + +321 +00:58:04,590 --> 00:58:09,219 +Мы не можем повернуть на полпути, если мы столкнулись с препятствиями. + +322 +00:58:09,280 --> 00:58:14,590 +Причина нашего поражения в том, что мы не боремся вместе. + +323 +00:58:14,630 --> 00:58:17,139 +Если вы, трое, объединитесь, + +324 +00:58:17,190 --> 00:58:20,500 +и общими усилиями будете сражаться с Князем Демонов, + +325 +00:58:20,550 --> 00:58:22,849 +вы обязательно победите. + +326 +00:58:22,909 --> 00:58:26,030 +Мы услышали наказ наставника + +327 +00:58:26,030 --> 00:58:30,139 +и будем сражаться с Князем Демонов до конца. + +328 +00:58:30,190 --> 00:58:34,260 +до... до конца + +329 +00:58:34,320 --> 00:58:37,710 +Замечательно! + +330 +00:58:37,750 --> 00:58:40,980 +Мы все справились с трудностями. + +331 +00:58:41,039 --> 00:58:43,869 +Я надеюсь, каждый будет стараться + +332 +00:58:43,869 --> 00:58:49,579 +вместе с моими учениками победить Князя Демонов и потушить пламя Огненной Горы. + +333 +00:58:49,630 --> 00:58:52,820 +Иначе страдание никогда не кончится. + +334 +00:58:53,869 --> 00:58:57,489 +Мы услышали наказ наставника, искать счастье для всех. + +335 +00:58:57,550 --> 00:58:58,860 +Все объединяйтесь! + +336 +00:58:58,909 --> 00:59:00,519 +Хорошо! + +337 +01:08:23,229 --> 01:08:25,609 +Госпожа, какой ужас! + +338 +01:08:25,670 --> 01:08:30,789 +Господин пойман в ловушку, идите скорее! + +339 +01:08:54,470 --> 01:08:56,699 +Борьба еще не решена, не решена. + +340 +01:08:56,760 --> 01:08:58,710 +Осторожно, осторожно. + +341 +01:08:59,760 --> 01:09:05,789 +Животное, все что ты должен - это отдать нам веер, и мы сохраним тебе жизнь. + +342 +01:09:05,840 --> 01:09:12,750 +Старый Бык, где веер? Отдай его! + +343 +01:09:12,789 --> 01:09:19,340 +Он... у моей жены. + +344 +01:09:25,239 --> 01:09:27,989 +Дорогая, милая. + +345 +01:09:28,029 --> 01:09:32,260 +Спаси меня скорее. + +346 +01:09:32,319 --> 01:09:35,109 +Отдай им веер. + +347 +01:09:35,149 --> 01:09:39,619 +Мой повелитель! Хорошо, хорошо! + +348 +01:09:43,399 --> 01:09:47,229 +Укун, иди еще раз! + +349 +01:12:30,850 --> 01:12:46,599 +Конец + diff --git a/js2/mwEmbed/example_usage/media/princess_archive_org/princess_iron_fan-zh-hant.srt b/js2/mwEmbed/example_usage/media/princess_archive_org/princess_iron_fan-zh-hant.srt new file mode 100644 index 0000000000..734c4bfc9b --- /dev/null +++ b/js2/mwEmbed/example_usage/media/princess_archive_org/princess_iron_fan-zh-hant.srt @@ -0,0 +1,1392 @@ +1 +00:00:01,080 --> 00:00:09,078 +片名:鐵扇公主 + +2 +00:02:03,119 --> 00:02:09,280 +西遊記,本為一部絕妙之童話 + +3 +00:02:09,280 --> 00:02:15,280 +特以世多誤解,致被目為神怪小說 + +4 +00:02:15,280 --> 00:02:19,240 +本片取材於是 + +5 +00:02:19,240 --> 00:02:24,240 +實為培育兒童心理而作 + +6 +00:02:24,240 --> 00:02:29,280 +故內容刪蕪存精,不涉神怪 + +7 +00:02:29,280 --> 00:02:32,560 +僅以唐僧等四人路阻火焰山 + +8 +00:02:32,560 --> 00:02:41,040 +以示人生途徑中之磨難 + +9 +00:02:41,040 --> 00:02:46,440 +欲求經此磨難,則必須堅持信念 +大眾一心 + +10 +00:02:46,440 --> 00:02:52,436 +始能獲得此撲滅凶焰之芭蕉扇 + +11 +00:03:34,480 --> 00:03:37,790 +現在已經秋天了,怎麼還這麼熱 + +12 +00:03:37,840 --> 00:03:42,356 +呆子,不要說廢話,趕路要緊 + +13 +00:04:06,920 --> 00:04:09,354 +悟空,這是到了什麼地方 + +14 +00:04:09,400 --> 00:04:13,678 +反正是我們上西天必定要經過的地方 + +15 +00:04:13,720 --> 00:04:18,111 +我們沒有走錯路線吧 + +16 +00:04:18,159 --> 00:04:22,311 +為什麼這個地方這麼樣的熱呢 + +17 +00:04:30,039 --> 00:04:31,711 +師傅,你看 + +18 +00:04:31,759 --> 00:04:33,795 +前面那兒,不是有一座房子了嗎 + +19 +00:04:33,839 --> 00:04:38,117 +我們大家進去歇息一會兒好吧 + +20 +00:04:59,399 --> 00:05:02,914 +這個地方名叫火焰山 + +21 +00:05:02,959 --> 00:05:06,031 +周圍有幾百里的火焰 + +22 +00:05:06,079 --> 00:05:08,752 +一根草都不生 + +23 +00:05:08,799 --> 00:05:11,632 +一年四季都是熱的 + +24 +00:05:11,680 --> 00:05:19,633 +就是銅頭鐵臂要經過那個山 +也得融化成水 + +25 +00:05:19,679 --> 00:05:23,592 +哪有這種事,師傅,你請放心 + +26 +00:05:23,639 --> 00:05:27,154 +我們三個人都有法子可以過去 + +27 +00:05:27,199 --> 00:05:30,714 +師傅,我去看看好吧 + +28 +00:08:06,319 --> 00:08:09,595 +悟空,你去看了怎麼樣 + +29 +00:08:09,639 --> 00:08:11,834 +厲害,厲害,真厲言 + +30 +00:08:11,880 --> 00:08:15,919 +要不是我跑得快,尾巴都燒光了 + +31 +00:08:42,720 --> 00:08:47,600 +老施主,這裡的火這樣大 + +32 +00:08:47,600 --> 00:08:49,670 +這五穀從哪兒來的 + +33 +00:08:49,719 --> 00:08:53,997 +你看這兒有一千多里的路 +有一位鐵扇公主 + +34 +00:08:54,040 --> 00:08:56,508 +她有一把芭蕉扇 + +35 +00:08:56,560 --> 00:08:59,074 +一扇呢,火就熄了 + +36 +00:08:59,120 --> 00:09:01,634 +兩扇呢,風就來了 + +37 +00:09:01,680 --> 00:09:03,989 +三扇呢,就下雨了 + +38 +00:09:04,040 --> 00:09:07,510 +我們就從這個時候播種收割 + +39 +00:09:07,560 --> 00:09:11,348 +不過,要請那位公主來 + +40 +00:09:11,400 --> 00:09:14,870 +可不是一件容易的事 + +41 +00:09:14,919 --> 00:09:16,830 +她住在什麼地方 + +42 +00:09:16,880 --> 00:09:20,190 +她住在翠雲山芭蕉洞 + +43 +00:09:20,240 --> 00:09:23,676 +是她一個人住在那兒嗎 + +44 +00:09:23,720 --> 00:09:25,756 +她有沒有丈夫啊 + +45 +00:09:25,800 --> 00:09:29,588 +她的丈夫是牛魔王 + +46 +00:09:29,640 --> 00:09:32,200 +原來是老牛 + +47 +00:09:32,240 --> 00:09:36,791 +呆子,你竟然認識他嗎? +跟我一塊兒借扇子去 + +48 +00:09:36,840 --> 00:09:41,755 +我…我知道老牛不住在那兒的 + +49 +00:09:41,800 --> 00:09:46,351 +在他男人不在家的時候 +我們去找他的女人 + +50 +00:09:46,400 --> 00:09:51,520 +這…這有點不大方便吧 + +51 +00:09:51,560 --> 00:09:58,318 +你們…兩個人…去吧 + +52 +00:09:58,360 --> 00:10:05,198 +我…我在…這兒…伺候師父 + +53 +00:10:05,240 --> 00:10:11,270 +悟淨,你也跟你兩個師兄一同去吧 + +54 +00:10:47,200 --> 00:10:51,557 +呆子,每次都是我去打頭陣的 + +55 +00:10:51,600 --> 00:10:54,353 +這次該你去了 + +56 +00:10:58,520 --> 00:11:04,914 +三弟,每次都是我去打頭陣 +這次該你去了 + +57 +00:11:04,960 --> 00:11:06,837 +大師兄 + +58 +00:11:06,880 --> 00:11:10,998 +我叫你去給師父出一點力 +你都不肯嗎 + +59 +00:11:11,040 --> 00:11:14,316 +快去… + +60 +00:11:39,640 --> 00:11:43,040 +你是哪兒跑來的野和尚 + +61 +00:11:43,040 --> 00:11:49,878 +大唐…聖僧…要你家…大公主… + +62 +00:11:49,920 --> 00:11:52,480 +胡說 + +63 +00:12:47,559 --> 00:12:52,075 +大…大師兄,還是你去吧 + +64 +00:12:52,120 --> 00:12:56,955 +呆子,你去 + +65 +00:12:57,000 --> 00:13:00,709 +大師兄,還是你去吧 + +66 +00:13:04,039 --> 00:13:07,475 +偷懶的東西 + +67 +00:13:54,280 --> 00:13:57,909 +好雷公菩薩,你饒了我放了我吧 + +68 +00:13:57,960 --> 00:13:59,951 +你跟你們公主說 + +69 +00:14:00,000 --> 00:14:03,280 +我孫悟空要來借芭蕉扇 + +70 +00:14:03,280 --> 00:14:08,400 +好,好,你放了我,我就去 + +71 +00:14:29,560 --> 00:14:37,069 +奶奶,外面有一個孫悟空 +要來借芭蕉扇 + +72 +00:14:41,520 --> 00:14:44,159 +快拿我的劍來 + +73 +00:15:01,640 --> 00:15:04,154 +孫悟空,害我兒子的仇人 + +74 +00:15:04,200 --> 00:15:08,557 +你今天也敢自己來送死嗎 + +75 +00:15:08,600 --> 00:15:12,040 +我是從來沒見過你,怎麼會害你的兒子 + +76 +00:15:12,040 --> 00:15:15,794 +我的孩子紅孩兒不是你害死的嗎 + +77 +00:15:15,840 --> 00:15:20,391 +令郎已成正果,怎麼說老孫害他呢 + +78 +00:15:20,440 --> 00:15:23,750 +少說廢話,伸過頭來讓我砍幾劍 + +79 +00:15:23,800 --> 00:15:26,155 +受得住我就把芭蕉扇借給你 + +80 +00:15:26,200 --> 00:15:28,555 +真的嗎 + +81 +00:15:56,800 --> 00:16:00,634 +慢著,快把扇子借給我 + +82 +00:17:53,639 --> 00:18:00,112 +大聖不保唐僧到西天去 +來到這兒做什麼 + +83 +00:18:11,159 --> 00:18:17,155 +我被鐵扇公主一扇扇到這兒來的 + +84 +00:18:17,199 --> 00:18:23,877 +大聖你來得巧極了 +我有一樣東西送給你 + +85 +00:18:28,519 --> 00:18:33,468 +這裡是一粒定風珠,大聖你有了這珠子 + +86 +00:18:33,519 --> 00:18:36,158 +可以使你的心堅定了 + +87 +00:18:36,199 --> 00:18:39,191 +保那鐵扇公主扇不動你了 + +88 +00:18:39,239 --> 00:18:42,868 +大聖你來看 + +89 +00:19:00,439 --> 00:19:02,555 +謝謝 + +90 +00:19:06,079 --> 00:19:12,314 +大…大師兄…不知給… + +91 +00:19:12,359 --> 00:19:18,707 +吹到什麼…地方去了 + +92 +00:19:18,759 --> 00:19:26,109 +管他呢,讓猴子也吃點舌頭,我們走 + +93 +00:19:35,199 --> 00:19:37,269 +大…大…師兄 + +94 +00:19:37,319 --> 00:19:43,479 +你…被…被…那… + +95 +00:19:43,479 --> 00:19:50,237 +大師兄,你被那個婆娘扇到 +什麼地方去了 + +96 +00:19:50,279 --> 00:19:57,196 +呆子,現在總該你去了 + +97 +00:19:57,239 --> 00:20:00,948 +我不去,我要是被她一扇 + +98 +00:20:00,999 --> 00:20:03,467 +簡直就認不得回來了 + +99 +00:20:03,519 --> 00:20:09,719 +還是…你再去一趟吧 + +100 +00:20:09,719 --> 00:20:12,233 +不去,不去 + +101 +00:20:17,799 --> 00:20:22,793 +下次輪到你,可不准再偷懶了 + +102 +00:20:56,159 --> 00:21:00,152 +這次你儘管扇,扇得我動一動 + +103 +00:21:00,199 --> 00:21:05,227 +我不算男子漢大丈夫 + +104 +00:21:33,679 --> 00:21:38,594 +大師兄,怎麼這回 +她的扇子沒有用啊 + +105 +00:21:46,839 --> 00:21:50,115 +我們來打進去 + +106 +00:23:59,639 --> 00:24:04,190 +快把芭蕉拿出來,給我孫悟空用一用 + +107 +00:24:14,879 --> 00:24:16,915 +孫悟空,你在什麼地方 + +108 +00:24:16,959 --> 00:24:19,996 +我在你肚子裡呢 + +109 +00:24:45,759 --> 00:24:48,557 +孫悟空,你饒了我的命吧 + +110 +00:24:48,599 --> 00:24:51,193 +你把扇子拿出來就是了 + +111 +00:24:51,239 --> 00:24:56,552 +我答應你就是了,請你快點出來吧 + +112 +00:25:00,239 --> 00:25:02,833 +快把扇子拿來 + +113 +00:25:07,439 --> 00:25:09,236 +扇子已經來了 + +114 +00:25:09,280 --> 00:25:12,078 +孫悟空你怎麼還不出來呢 + +115 +00:25:12,119 --> 00:25:16,635 +你把嘴張開來,我就出來了 + +116 +00:25:25,359 --> 00:25:29,432 +孫祖宗,你怎麼還不出來呢 + +117 +00:25:50,359 --> 00:25:55,592 +我在這兒呢,借給我用用就還你的 + +118 +00:26:32,559 --> 00:26:36,598 +師父等了好久了,我們快去吧 + +119 +00:27:01,879 --> 00:27:04,916 +經,經是什麼 + +120 +00:27:04,959 --> 00:27:10,039 +經是天地之間不能辨易的道理 + +121 +00:27:10,039 --> 00:27:14,191 +這個道理也就是做人的道理 + +122 +00:27:14,239 --> 00:27:18,710 +任何一個人有了這個道理 + +123 +00:27:18,759 --> 00:27:25,358 +才可以免去諸般痛苦 +好好的安居樂業 + +124 +00:27:25,399 --> 00:27:29,950 +實實在在的過日子 + +125 +00:27:34,680 --> 00:27:36,352 +反過來說 + +126 +00:27:36,399 --> 00:27:40,108 +要是做人不曉得這個道理 + +127 +00:27:40,159 --> 00:27:46,394 +就跟沉陷在苦海裡頭一樣 +一生一世 + +128 +00:27:46,439 --> 00:27:52,628 +甚至於子孫孫,都得不到幸福 + +129 +00:27:52,679 --> 00:27:55,671 +我為什麼要去取經 + +130 +00:27:55,719 --> 00:28:01,316 +就是因為現在的人都陷在苦海裡了 + +131 +00:28:01,359 --> 00:28:04,192 +要想成就這此些人 + +132 +00:28:04,239 --> 00:28:12,510 +所以在大唐皇帝面前討下這 +重大繁難的差事 + +133 +00:28:15,679 --> 00:28:17,829 +芭蕉扇借到了沒有 + +134 +00:28:17,879 --> 00:28:19,517 +借來了 + +135 +00:28:19,559 --> 00:28:22,790 +是不是這個 + +136 +00:28:22,839 --> 00:28:27,993 +諸位施主,現在扇子既然借到了 + +137 +00:28:28,039 --> 00:28:32,157 +貧僧師徒就要告辭了 + +138 +00:28:32,199 --> 00:28:34,040 +慢一點 + +139 +00:28:34,040 --> 00:28:39,797 +諸位,我想留聖僧在這兒多住幾天 + +140 +00:28:39,839 --> 00:28:41,352 +好不好啊 + +141 +00:28:41,399 --> 00:28:43,469 +好的,好的 + +142 +00:28:43,519 --> 00:28:45,908 +謝謝諸位的好意 + +143 +00:28:45,959 --> 00:28:51,795 +我早走一步就是早一步完成 +我們的任務 + +144 +00:28:51,839 --> 00:28:56,196 +那麼就請令高徒先到火焰山 + +145 +00:28:56,239 --> 00:29:02,155 +扇滅了火之後,再陪聖僧同行 + +146 +00:29:02,199 --> 00:29:05,475 +好,你就去吧 + +147 +00:30:24,479 --> 00:30:30,039 +鐵扇公主真可惡,拿假的芭蕉扇 +來騙我 + +148 +00:30:30,039 --> 00:30:32,792 +我非殺了她不可 + +149 +00:30:32,839 --> 00:30:36,309 +不,殺了她也是枉然 + +150 +00:30:36,359 --> 00:30:39,590 +我素來不願意你多殺人 + +151 +00:30:39,639 --> 00:30:42,995 +我們再想辦法 + +152 +00:30:52,159 --> 00:30:56,232 +師兄,怎麼你也會上她的當 + +153 +00:30:56,279 --> 00:30:58,554 +費了這麼許多的力氣 + +154 +00:30:58,599 --> 00:31:02,114 +卻弄了一把假的扇子來 + +155 +00:31:02,159 --> 00:31:06,516 +笑話,笑話 + +156 +00:31:08,919 --> 00:31:10,432 +那麼你去 + +157 +00:31:10,479 --> 00:31:14,392 +好好,我去我去,我就去 + +158 +00:31:14,439 --> 00:31:17,033 +我去找牛魔王 + +159 +00:31:17,119 --> 00:31:19,952 +這倒是一個好辦法 + +160 +00:31:21,399 --> 00:31:24,550 +師兄,你看好不好 + +161 +00:31:24,599 --> 00:31:27,397 +好,看你的了 + +162 +00:33:07,199 --> 00:33:11,159 +你看我今天化妝得好嗎 + +163 +00:33:11,159 --> 00:33:13,798 +好極了,我的小寶貝 + +164 +00:33:13,839 --> 00:33:17,070 +你陪我到洞外頭去走走,好不好 + +165 +00:33:17,119 --> 00:33:21,556 +我的寶貝,還是你一個人去吧 + +166 +00:33:21,599 --> 00:33:24,830 +本來嘛,我們這種草婆子 + +167 +00:33:24,879 --> 00:33:28,030 +跟你出去了會使你丟臉的 + +168 +00:33:28,079 --> 00:33:32,039 +小寶貝,這是什麼話呢 + +169 +00:33:32,039 --> 00:33:37,511 +你先去,我隨後就來好不好 + +170 +00:35:28,039 --> 00:35:35,673 +女菩薩,你真是天仙下凡 + +171 +00:35:35,719 --> 00:35:37,914 +你…你是什麼人 + +172 +00:35:37,959 --> 00:35:41,474 +我是從芭蕉洞來找牛魔王的 + +173 +00:35:41,520 --> 00:35:43,988 +快放手 + +174 +00:35:49,559 --> 00:35:52,949 +女菩薩,你慢點走 + +175 +00:36:44,239 --> 00:36:49,233 +小寶貝,誰來欺負你 + +176 +00:36:49,279 --> 00:36:50,837 +是你 + +177 +00:36:50,879 --> 00:36:54,349 +我哪裡捨得欺負你呢 + +178 +00:36:56,919 --> 00:36:59,274 +你還是回芭蕉洞去吧 + +179 +00:36:59,320 --> 00:37:01,709 +省得那個不要臉的東西 + +180 +00:37:01,759 --> 00:37:07,675 +時常派人來請你,欺負我 + +181 +00:37:07,719 --> 00:37:11,075 +你說有人來找我 + +182 +00:37:11,119 --> 00:37:15,078 +外邊有一個豬臉的和尚來請你 + +183 +00:37:15,120 --> 00:37:18,510 +差一點把我嚇死了 + +184 +00:37:18,559 --> 00:37:22,757 +真有這回事嗎?待我出去看一看 + +185 +00:37:50,679 --> 00:37:53,796 +牛大哥 + +186 +00:37:53,839 --> 00:37:58,151 +這裡頭有個頂漂亮的小娘們 + +187 +00:37:58,200 --> 00:38:03,991 +呸,那是我的女人,你為什麼要欺負她 + +188 +00:38:04,039 --> 00:38:08,559 +大哥,我不知那就是二嫂,請原瓊 + +189 +00:38:08,559 --> 00:38:11,949 +不知道不見罪,好啊,你走啊 + +190 +00:38:11,999 --> 00:38:16,117 +不不不,我還有事情請大哥幫忙 + +191 +00:38:18,479 --> 00:38:24,719 +小弟保唐僧取經,路過火焰山 + +192 +00:38:24,719 --> 00:38:27,313 +請大哥跟嫂子說一聲 + +193 +00:38:27,359 --> 00:38:30,829 +把這個芭蕉扇借來用一用 + +194 +00:38:30,880 --> 00:38:33,519 +不成,那唐僧和孫悟空 + +195 +00:38:33,519 --> 00:38:35,191 +是我孩子的仇人 + +196 +00:38:35,239 --> 00:38:38,754 +我正要抓他們報仇 + +197 +00:38:38,799 --> 00:38:44,988 +令郎已成正果,請大哥不必再計較吧 + +198 +00:38:45,039 --> 00:38:48,952 +好,看在我們從前的交情 +我不跟你計較 + +199 +00:38:49,000 --> 00:38:51,719 +那麼去吧 + +200 +00:39:38,399 --> 00:39:44,190 +寶貝,那個豬臉和尚 +是我從前一個朋友 + +201 +00:39:44,239 --> 00:39:46,514 +並不是芭蕉洞派來的 + +202 +00:39:46,559 --> 00:39:47,753 +我不相信 + +203 +00:39:47,799 --> 00:39:50,950 +我不騙你 + +204 +00:39:50,999 --> 00:39:54,036 +現在那個和尚到哪兒去了呢 + +205 +00:39:54,119 --> 00:39:57,794 +已經被我打走了 + +206 +00:43:58,639 --> 00:44:01,358 +大王回來了 + +207 +00:44:01,399 --> 00:44:02,388 +奶奶呢 + +208 +00:44:02,439 --> 00:44:04,794 +在裡邊 + +209 +00:44:42,999 --> 00:44:48,232 +今天是什麼風會把大王吹到這兒來的 + +210 +00:44:48,279 --> 00:44:52,272 +聽到孫悟空保唐僧快到這兒 + +211 +00:44:52,320 --> 00:44:56,916 +恐怕他要來借芭蕉扇過火焰山 + +212 +00:44:56,959 --> 00:45:00,872 +那猴子是害我們兒子的仇人 + +213 +00:45:00,919 --> 00:45:08,507 +早晚來了抓著他,讓我們夫妻出出恨 + +214 +00:45:08,559 --> 00:45:12,711 +夫人,你為什麼哭 + +215 +00:45:12,759 --> 00:45:15,717 +那猴子已經來過了 + +216 +00:45:15,759 --> 00:45:18,876 +是我不肯把扇子借給他 + +217 +00:45:18,919 --> 00:45:22,275 +不知道怎麼會跑到我的肚子裡來 + +218 +00:45:22,319 --> 00:45:25,516 +弄得我肚子痛得要命 + +219 +00:45:25,559 --> 00:45:31,399 +後來我沒有法子,只好把扇子借給他 + +220 +00:45:31,399 --> 00:45:38,271 +可惜可惜,你怎麼把扇子借給他 + +221 +00:45:38,320 --> 00:45:40,470 +拿去的是假的 + +222 +00:45:40,519 --> 00:45:43,033 +假的 + +223 +00:46:14,199 --> 00:46:19,876 +開筵慶祝大王歸 + +224 +00:46:19,919 --> 00:46:25,630 +好酒殷勤勸幾杯 + +225 +00:46:25,679 --> 00:46:34,189 +雞又香,鴨又美,豬又肥 + +226 +00:46:34,240 --> 00:46:45,674 +我盡量的歌,我盡量的舞 + +227 +00:46:45,719 --> 00:46:54,514 +你也要盡量的醉 + +228 +00:47:03,599 --> 00:47:16,399 +大王啊,你把舊人丟 + +229 +00:47:16,439 --> 00:47:22,628 +你愛新人媚 + +230 +00:47:22,679 --> 00:47:36,673 +為你淌了多少相思淚 + +231 +00:47:46,719 --> 00:47:55,718 +等一會燈兒吹帳兒垂 + +232 +00:47:55,759 --> 00:48:00,879 +你獨自兒睡 + +233 +00:48:00,879 --> 00:48:05,519 +也嘗嘗這個淒涼味 + +234 +00:48:05,519 --> 00:48:13,437 +恕我不奉陪 + +235 +00:48:18,559 --> 00:48:24,634 +就是同床 + +236 +00:48:24,679 --> 00:48:34,350 +我們各人蓋著各人的被 + +237 +00:48:38,399 --> 00:48:42,392 +大王,我醉了 + +238 +00:48:55,079 --> 00:48:58,151 +夫人,那真扇子你放在什麼地方 + +239 +00:48:58,199 --> 00:49:05,469 +那猴子花樣很多,而且那豬八戒 +本事更大 + +240 +00:49:05,519 --> 00:49:09,797 +當心給他們騙了去 + +241 +00:49:18,360 --> 00:49:21,989 +寶貝不是在這兒嗎 + +242 +00:49:31,439 --> 00:49:39,319 +大王,你出神想什麼呢? +還是收了吧 + +243 +00:49:39,319 --> 00:49:43,551 +小寶貝 + +244 +00:49:43,599 --> 00:49:49,037 +寶貝,你多喝一杯,你喝啊 + +245 +00:49:53,919 --> 00:49:59,519 +今兒晚上,金龍大王 +還要請我去喝酒呢 + +246 +00:49:59,519 --> 00:50:01,430 +那你就該去了 + +247 +00:50:01,479 --> 00:50:02,878 +是的 + +248 +00:50:02,919 --> 00:50:06,628 +你去替爺爺把金睛獸牽出去預備好 + +249 +00:50:06,679 --> 00:50:08,271 +是 + +250 +00:50:08,320 --> 00:50:12,598 +可是,你今兒個晚上去要少喝一點兒 + +251 +00:50:12,639 --> 00:50:15,756 +免得回來睡著叫不醒你 + +252 +00:50:15,800 --> 00:50:19,110 +不好了,爺爺那個金隋獸不見了 + +253 +00:50:19,159 --> 00:50:20,911 +你們全都是死人嗎 + +254 +00:50:20,959 --> 00:50:24,039 +家裡頭的東西怎麼會不見了呢 + +255 +00:50:24,039 --> 00:50:27,918 +寶貝,不要管他們吧 + +256 +00:50:27,960 --> 00:50:31,714 +恐怕是那豬八戒偷了去了 + +257 +00:50:31,759 --> 00:50:35,274 +說不定我要到芭蕉洞去一趟 + +258 +00:50:35,320 --> 00:50:39,313 +原來是你們做好了的圈套 + +259 +00:50:42,280 --> 00:50:48,150 +你還是要到那個不要臉的女人那兒去 + +260 +00:50:48,199 --> 00:50:50,713 +好寶貝,你不要哭了 + +261 +00:50:50,759 --> 00:50:54,069 +我去去就來的 + +262 +00:51:02,679 --> 00:51:07,309 +來來,喝喝 + +263 +00:51:10,359 --> 00:51:12,475 +我現在放心了 + +264 +00:51:12,519 --> 00:51:16,717 +不怕他們偷我們的寶貝 + +265 +00:51:16,759 --> 00:51:21,310 +他們就是偷了去 +不知道把那絲線一拉 + +266 +00:51:21,360 --> 00:51:26,275 +單是一顆珠子也沒有用處啊 + +267 +00:51:26,319 --> 00:51:31,791 +是不是那麼一拉就變成扇子 + +268 +00:51:35,120 --> 00:51:38,078 +大王,你今天喝醉了 + +269 +00:51:38,119 --> 00:51:44,035 +自己的寶貝都忘了,還來問我 + +270 +00:51:49,999 --> 00:51:53,708 +娘子,你看看我是誰 + +271 +00:52:00,320 --> 00:52:03,756 +你是什麼人 + +272 +00:52:03,799 --> 00:52:09,908 +我是唐僧的二徒弟,豬八戒 + +273 +00:52:09,959 --> 00:52:14,794 +對不住,謝謝你,打擾了 + +274 +00:52:19,080 --> 00:52:21,719 +再見 + +275 +00:53:06,839 --> 00:53:10,718 +牛大嫂太風騷 + +276 +00:53:10,760 --> 00:53:14,719 +眾小妖都俊俏 + +277 +00:53:14,759 --> 00:53:24,828 +老豬真有點受不了 + +278 +00:53:24,879 --> 00:53:28,872 +心機巧,手段妙 + +279 +00:53:28,919 --> 00:53:32,832 +居然騙得了無價寶 + +280 +00:53:32,880 --> 00:53:36,793 +這一番勞苦功高 + +281 +00:53:36,839 --> 00:53:38,318 +沙僧該拜倒 + +282 +00:53:38,359 --> 00:53:40,748 +猴兒該領教 + +283 +00:53:40,799 --> 00:53:45,236 +師父也要嚇一跳 + +284 +00:53:45,280 --> 00:53:49,193 +我老豬也有今朝 + +285 +00:53:49,239 --> 00:53:54,359 +我老豬也有今朝 + +286 +00:54:36,720 --> 00:54:40,474 +呆子,事情辦得怎麼樣了 + +287 +00:54:40,519 --> 00:54:42,828 +不僅扇子到手 + +288 +00:54:42,880 --> 00:54:48,796 +鐵扇公主並且還做了我 +半天的老婆 + +289 +00:54:48,839 --> 00:54:51,717 +這倒便宜了你了 + +290 +00:54:58,159 --> 00:55:01,595 +扇子拿來給我看看 + +291 +00:55:16,039 --> 00:55:20,237 +你怎麼會把它縮小了的呀 + +292 +00:55:40,559 --> 00:55:45,349 +老豬,你可認識我嗎 + +293 +00:55:45,399 --> 00:55:49,187 +你不要跟我開玩笑了 + +294 +00:55:49,239 --> 00:55:52,151 +誰跟你開玩笑 + +295 +00:56:42,879 --> 00:56:45,393 +呆子,你去了怎麼樣 + +296 +00:56:45,439 --> 00:56:47,111 +白跑了一趟 + +297 +00:56:47,159 --> 00:56:49,992 +悟能,扇子借來沒有 + +298 +00:56:50,039 --> 00:56:53,349 +我去找牛魔王,他不肯借 + +299 +00:56:53,400 --> 00:56:59,191 +後來,我又變成老牛的樣子 + +300 +00:56:59,239 --> 00:57:03,551 +在鐵扇公主那兒把扇子已經騙過來了 + +301 +00:57:03,599 --> 00:57:10,599 +誰知道他又變成你的樣子又給他騙回去了 + +302 +00:57:10,599 --> 00:57:12,749 +老牛的本領大 + +303 +00:57:12,800 --> 00:57:16,156 +我還被他揍了一頓呢 + +304 +00:57:16,199 --> 00:57:21,398 +呆子,你能辦這樣大的事那 +還算是呆子嗎 + +305 +00:57:21,439 --> 00:57:25,671 +事情不都環在你頭上 + +306 +00:57:30,759 --> 00:57:34,388 +你們不要吵了,趕緊再想辦法 + +307 +00:57:34,439 --> 00:57:40,275 +哪一方…沒…沒有火啊 + +308 +00:57:40,320 --> 00:57:47,078 +東南西北,只有西方有火 + +309 +00:57:47,120 --> 00:57:50,749 +那我們不是要走回去了嗎 + +310 +00:57:50,799 --> 00:57:52,949 +這路不通,不回去怎麼樣呢 + +311 +00:57:52,999 --> 00:57:55,229 +八戒,你不要這樣說 + +312 +00:57:55,279 --> 00:57:59,158 +要成功一件事情總是有阻礙的 + +313 +00:57:59,199 --> 00:58:04,557 +我們要做這樣神聖的事情 +就要堅定我們的信念 + +314 +00:58:04,599 --> 00:58:09,229 +不能因為有一點兒困難 +就中適改變我們的宗旨 + +315 +00:58:09,280 --> 00:58:14,593 +你們這次失敗的原因是由於 +既不同心又不合力 + +316 +00:58:14,639 --> 00:58:17,153 +假使你們三個人一條心 + +317 +00:58:17,199 --> 00:58:20,509 +合起力量,共同跟牛魔王決鬥 + +318 +00:58:20,559 --> 00:58:22,868 +事情一定可以成功的 + +319 +00:58:22,919 --> 00:58:26,039 +我們謹遵師父的命令 + +320 +00:58:26,039 --> 00:58:30,157 +去跟牛魔王爭一個誰勝誰敗 + +321 +00:58:30,199 --> 00:58:34,272 +誰…誰…誰勝誰敗 + +322 +00:58:34,320 --> 00:58:37,710 +那就好極了 + +323 +00:58:37,759 --> 00:58:40,990 +各位受他的害處也不小了 + +324 +00:58:41,040 --> 00:58:43,879 +希望各位也出此些力量 + +325 +00:58:43,879 --> 00:58:49,590 +跟小徒們共同征服牛魔王,消滅火焰山 + +326 +00:58:49,639 --> 00:58:53,837 +免除永遠的禍害 + +327 +00:58:53,879 --> 00:58:57,508 +我們聽從師父的命令,為大家謀幸福 + +328 +00:58:57,559 --> 00:58:58,878 +大家一起出力去 + +329 +00:58:58,919 --> 00:59:01,035 +好 + +330 +01:08:23,239 --> 01:08:25,628 +奶奶,不好了 + +331 +01:08:25,679 --> 01:08:30,799 +爺爺給人家抓住了,你快點去看看吧 + +332 +01:08:54,479 --> 01:08:56,709 +還不過來打,過來打 + +333 +01:08:56,760 --> 01:08:59,718 +慢一點,慢一點 + +334 +01:08:59,760 --> 01:09:05,790 +孽畜,只要你把扇子交出來,饒你不死 + +335 +01:09:05,840 --> 01:09:12,757 +老牛,扇子在什麼地方?快拿出來啊 + +336 +01:09:12,799 --> 01:09:19,352 +在我老…老婆那兒 + +337 +01:09:25,240 --> 01:09:27,993 +夫人,夫人,夫人 + +338 +01:09:28,039 --> 01:09:32,271 +你快點來救救我 + +339 +01:09:32,320 --> 01:09:35,118 +把扇子拿出來吧 + +340 +01:09:35,159 --> 01:09:39,630 +大王,好,好的 + +341 +01:09:43,400 --> 01:09:47,234 +悟空,你再去一趟吧 + diff --git a/js2/mwEmbed/example_usage/media/princess_archive_org/princess_iron_fan.srt b/js2/mwEmbed/example_usage/media/princess_archive_org/princess_iron_fan.srt new file mode 100644 index 0000000000..0852d36b32 --- /dev/null +++ b/js2/mwEmbed/example_usage/media/princess_archive_org/princess_iron_fan.srt @@ -0,0 +1,1396 @@ +1 +00:00:01,080 --> 00:00:09,070 +Princess Iron Fan + +2 +00:02:03,109 --> 00:02:09,280 +Journey to the West is a wonderful children's story, + +3 +00:02:09,280 --> 00:02:15,280 +but the world often misunderstands it as a fantasy novel. + +4 +00:02:15,280 --> 00:02:19,240 +This film was made for the purpose of + +5 +00:02:19,240 --> 00:02:24,240 +training the hearts and minds of children. + +6 +00:02:24,240 --> 00:02:29,280 +The story is pure, untainted by fantasy. + +7 +00:02:29,280 --> 00:02:32,560 +Fiery Mountain blocking the path of Tang Seng's company + +8 +00:02:32,560 --> 00:02:41,039 +is a metaphor for the difficulties in life. + +9 +00:02:41,039 --> 00:02:46,439 +In order to overcome them, one must keep faith. +Everybody must work together + +10 +00:02:46,439 --> 00:02:52,430 +in order to obtain the palm leaf fan and put out the flames. + +11 +00:02:52,839 --> 00:02:58,178 +Tripikata True Sutra + +12 +00:03:34,479 --> 00:03:37,789 +It's already autumn, how can it still be so warm? + +13 +00:03:37,840 --> 00:03:42,349 +Fool, don't talk rubbish. We should hurry and get on our way. + +14 +00:04:06,919 --> 00:04:09,349 +Wukong, where is this place? + +15 +00:04:09,400 --> 00:04:13,669 +We must pass through here to continue westwards, that much is certain. + +16 +00:04:13,719 --> 00:04:18,110 +Might we have taken the wrong path? + +17 +00:04:18,149 --> 00:04:21,700 +Why is it so hot here? + +18 +00:04:30,029 --> 00:04:31,649 +Master, look! + +19 +00:04:31,650 --> 00:04:33,779 +Isn't that a house up ahead? + +20 +00:04:33,829 --> 00:04:38,100 +Let's go in and rest for a while, OK? + +21 +00:04:59,389 --> 00:05:02,899 +This place is called Fiery Mountain. + +22 +00:05:02,949 --> 00:05:06,019 +The fire stretches for hundreds of miles. + +23 +00:05:06,069 --> 00:05:08,740 +Not single straw of grass can grow here. + +24 +00:05:08,790 --> 00:05:11,620 +The four seasons of the year are all warm. + +25 +00:05:11,680 --> 00:05:19,629 +You couldn't pass through the mountain even with a head of copper and arms of iron. + +26 +00:05:19,670 --> 00:05:23,579 +What kind of place is this? Master, don't worry! + +27 +00:05:23,629 --> 00:05:27,139 +The three of us are all strong enough to pass! + +28 +00:05:27,189 --> 00:05:30,699 +Master, I'll go and have a look! + +29 +00:08:06,310 --> 00:08:09,579 +Wukong, what was it like? + +30 +00:08:09,629 --> 00:08:11,819 +Bad, bad, very bad. + +31 +00:08:11,879 --> 00:08:15,910 +If I were any slower the fur on my tail would have been burned off. + +32 +00:08:42,720 --> 00:08:47,600 +Noble host, the fires here are so big. + +33 +00:08:47,600 --> 00:08:49,669 +How can you grow any crops? + +34 +00:08:49,710 --> 00:08:53,980 +A thousand miles from here lives Princess Iron Fan. + +35 +00:08:54,039 --> 00:08:56,500 +She has a palm leaf fan. + +36 +00:08:56,559 --> 00:08:59,070 +Wave the fan once and the fire goes out. + +37 +00:08:59,120 --> 00:09:01,629 +Twice and the wind starts blowing. + +38 +00:09:01,679 --> 00:09:03,980 +Three times and the rain starts coming down. + +39 +00:09:04,039 --> 00:09:07,509 +In the following period we plant and harvest. + +40 +00:09:07,559 --> 00:09:11,340 +However, asking that princess to come + +41 +00:09:11,399 --> 00:09:14,870 +is certainly no simple matter. + +42 +00:09:14,909 --> 00:09:16,820 +Where does she live? + +43 +00:09:16,879 --> 00:09:20,190 +She lives in Palm Leaf Cave at Emerald Cloud Mountain. + +44 +00:09:20,240 --> 00:09:23,669 +Does she live there alone? + +45 +00:09:23,720 --> 00:09:25,750 +Doesn't she have a husband? + +46 +00:09:25,799 --> 00:09:29,580 +Her husband is Bull Demon King. + +47 +00:09:29,639 --> 00:09:32,200 +What, her husband is Old Bull? + +48 +00:09:32,240 --> 00:09:36,789 +Fool, you know him? Come with me to borrow the fan! + +49 +00:09:36,840 --> 00:09:41,750 +Actually... Old Bull doesn't live there. + +50 +00:09:41,799 --> 00:09:46,350 +Looking for his woman when he isn't home + +51 +00:09:46,399 --> 00:09:51,519 +isn't very... appropriate. + +52 +00:09:51,559 --> 00:09:58,309 +You... you... the two of you go. + +53 +00:09:58,360 --> 00:10:04,290 +I... I'll stay here and serve Master. + +54 +00:10:04,440 --> 00:10:11,269 +Sha Wujing, go with your two fellow apprentices. + +55 +00:10:38,571 --> 00:10:44,978 +Palm Leaf Cave + +56 +00:10:47,200 --> 00:10:51,549 +Fool, I always go first. + +57 +00:10:51,600 --> 00:10:54,350 +This time it's your turn! + +58 +00:10:58,519 --> 00:11:04,909 +Junior! I always go first, this time it's your turn! + +59 +00:11:04,960 --> 00:11:06,830 +Senior... + +60 +00:11:06,879 --> 00:11:10,990 +I'm asking you to make a small effort for Master. Can't you do that? + +61 +00:11:11,039 --> 00:11:14,309 +Hurry up! + +62 +00:11:39,639 --> 00:11:43,039 +Simple monk, where did you come from? + +63 +00:11:43,039 --> 00:11:49,870 +The Great Sage... Tang Seng... wants your princess... + +64 +00:11:49,919 --> 00:11:52,480 +Nonsense! + +65 +00:12:47,549 --> 00:12:52,059 +Senior... why don't you go instead? + +66 +00:12:52,120 --> 00:12:56,950 +Fool, you go! + +67 +00:12:57,000 --> 00:13:00,700 +Senior, why don't you go? + +68 +00:13:04,029 --> 00:13:07,460 +Lazy fool! + +69 +00:13:54,279 --> 00:13:57,899 +Great God of Thunder! Don't kill me, let me go! + +70 +00:13:57,960 --> 00:13:59,950 +Go tell your princess + +71 +00:14:00,000 --> 00:14:03,279 +that Sun Wukong has come to borrow the fan. + +72 +00:14:03,279 --> 00:14:08,399 +Yes, yes! Let me loose, I'll go at once. + +73 +00:14:29,559 --> 00:14:37,059 +Grandma, there's a Sun Wukong outside asking to borrow the fan. + +74 +00:14:41,519 --> 00:14:44,149 +Quickly fetch my sword. + +75 +00:15:01,639 --> 00:15:04,149 +Sun Wukong, you hurt my son! + +76 +00:15:04,200 --> 00:15:08,549 +You dare come here to meet your death? + +77 +00:15:08,600 --> 00:15:12,039 +I've never met you before, how could I have harmed your son? + +78 +00:15:12,039 --> 00:15:15,789 +My son Red Child's life was ruined, wasn't that your doing? + +79 +00:15:15,840 --> 00:15:20,389 +Your son is with the Goddess of Mercy now, how can you say that I hurt him? + +80 +00:15:20,440 --> 00:15:23,750 +Enough rubbish! Come here and let me chop you with my sword. + +81 +00:15:23,799 --> 00:15:26,149 +If you can take it I'll lend you the fan. + +82 +00:15:26,200 --> 00:15:28,549 +Really? + +83 +00:15:56,799 --> 00:16:00,629 +Stop! Quickly give me the fan! + +84 +00:17:53,630 --> 00:18:00,099 +Great Sage, weren't you going west? Why have you come back here? + +85 +00:18:11,150 --> 00:18:17,140 +Princess Iron Fan blew me here with a single wave of her fan. + +86 +00:18:17,190 --> 00:18:23,859 +That's truly amazing, Great Sage. I have something for you. + +87 +00:18:28,509 --> 00:18:33,450 +This is a wind pearl. When you use it, + +88 +00:18:33,509 --> 00:18:36,140 +your heart will become steady as a rock. + +89 +00:18:36,190 --> 00:18:39,180 +Princess Iron Fan won't be able to move you. + +90 +00:18:39,230 --> 00:18:42,849 +Great Sage, come and have a look. + +91 +00:19:00,430 --> 00:19:02,539 +Thank you. + +92 +00:19:06,069 --> 00:19:12,299 +Senior... where... + +93 +00:19:12,349 --> 00:19:18,690 +where has he... been blown to? + +94 +00:19:18,750 --> 00:19:26,099 +Who cares about him? Let the monkey handle himself. Let's go. + +95 +00:19:35,190 --> 00:19:37,259 +Senior... senior... + +96 +00:19:37,309 --> 00:19:43,470 +You... you... + +97 +00:19:43,470 --> 00:19:50,220 +Where were you blown to by that old lady? + +98 +00:19:50,269 --> 00:19:57,180 +Fool, now it's definitely your turn to go. + +99 +00:19:57,230 --> 00:20:00,930 +I'm not going, a single wave of her fan + +100 +00:20:00,990 --> 00:20:03,450 +could blow me to some faraway land. + +101 +00:20:03,509 --> 00:20:09,710 +Maybe it's better if you go again. + +102 +00:20:09,710 --> 00:20:12,220 +I won't go. + +103 +00:20:17,789 --> 00:20:22,779 +Next time I won't let you off! + +104 +00:20:56,150 --> 00:21:00,140 +This time I won't move no matter how much you wave, + +105 +00:21:00,190 --> 00:21:05,210 +as sure as I call myself am a man! + +106 +00:21:33,670 --> 00:21:38,579 +Senior, how come this time her fan couldn't move you? + +107 +00:21:46,829 --> 00:21:50,099 +Let's break our way in. + +108 +00:23:59,630 --> 00:24:04,180 +Quickly bring out the fan for Sun Wukong! + +109 +00:24:14,869 --> 00:24:16,900 +Sun Wukong, where are you? + +110 +00:24:16,950 --> 00:24:19,980 +I'm in your stomach! + +111 +00:24:45,750 --> 00:24:48,539 +Sun Wukong, spare me! + +112 +00:24:48,589 --> 00:24:51,180 +Only if you give me the fan! + +113 +00:24:51,230 --> 00:24:56,539 +I promise, I'll give it to you. Please come out! + +114 +00:25:00,230 --> 00:25:02,819 +Hurry up and bring the fan. + +115 +00:25:07,430 --> 00:25:09,220 +We've brought out the fan. + +116 +00:25:09,279 --> 00:25:12,069 +Why haven't you come out? + +117 +00:25:12,109 --> 00:25:16,619 +Open your mouth and I'll come out. + +118 +00:25:25,349 --> 00:25:29,420 +Sun Wukong, why haven't you come out? + +119 +00:25:50,349 --> 00:25:55,579 +Here I am. Lend me the fan for a while, I'll return it. + +120 +00:26:32,549 --> 00:26:36,579 +Master has been waiting long enough, let's get going! + +121 +00:27:01,869 --> 00:27:04,900 +Scripture, what is scripture? + +122 +00:27:04,950 --> 00:27:10,029 +Scriptures are the principles that link heaven and earth. + +123 +00:27:10,029 --> 00:27:14,180 +They are the principles of man. + +124 +00:27:14,230 --> 00:27:18,700 +Only he who holds these principles + +125 +00:27:18,750 --> 00:27:25,339 +can rid himself of pain and live a good life, + +126 +00:27:25,390 --> 00:27:29,940 +live a true and honest life. + +127 +00:27:34,680 --> 00:27:36,349 +Conversely, + +128 +00:27:36,390 --> 00:27:40,089 +he who does not know these principles, + +129 +00:27:40,150 --> 00:27:46,380 +will live a life full of misery. + +130 +00:27:46,430 --> 00:27:52,609 +Even his son or grandson will not achieve happiness. + +131 +00:27:52,670 --> 00:27:55,660 +Why am I going to get the scripture? + +132 +00:27:55,710 --> 00:28:01,299 +Because men nowadays are trapped in misery. + +133 +00:28:01,349 --> 00:28:04,180 +In order to achieve this goal, we are going to + +134 +00:28:04,230 --> 00:28:12,500 +appear before the Tang emperor and discuss this very complicated matter. + +135 +00:28:15,670 --> 00:28:17,819 +Did you get the palm leaf fan? + +136 +00:28:17,869 --> 00:28:19,400 +We have it. + +137 +00:28:19,401 --> 00:28:20,779 +Is this it? + +138 +00:28:22,829 --> 00:28:27,980 +Noble hosts, now that we have the fan, + +139 +00:28:28,029 --> 00:28:32,140 +we will take our leave. + +140 +00:28:32,190 --> 00:28:34,039 +Hold on. + +141 +00:28:34,039 --> 00:28:39,789 +Everyone, I would like to ask Sage Seng to stay here for a few more days. + +142 +00:28:39,829 --> 00:28:41,339 +Do you agree? + +143 +00:28:41,390 --> 00:28:43,460 +Agreed! + +144 +00:28:43,509 --> 00:28:45,890 +Thank you for your kindness. + +145 +00:28:45,950 --> 00:28:51,779 +But the sooner I leave the sooner we can complete our task. + +146 +00:28:51,829 --> 00:28:56,180 +Very well, will the honorable apprentice first go to Fiery Mountain. + +147 +00:28:56,230 --> 00:29:02,140 +After extinguishing the flames, continue to follow Sage Seng. + +148 +00:29:02,190 --> 00:29:05,460 +All right, go ahead! + +149 +00:30:24,470 --> 00:30:30,029 +Princess Iron Fan is really despicable, she gave us a fake fan! + +150 +00:30:30,029 --> 00:30:32,779 +I'll kill her for sure! + +151 +00:30:32,829 --> 00:30:36,299 +No, killing her is the wrong thing to do. + +152 +00:30:36,349 --> 00:30:39,579 +I won't let you kill anyone. + +153 +00:30:39,630 --> 00:30:42,980 +Let's think of something else. + +154 +00:30:52,150 --> 00:30:56,220 +Senior, how could you be fooled by her? + +155 +00:30:56,269 --> 00:30:58,539 +After making such an effort + +156 +00:30:58,589 --> 00:31:02,099 +all we got was a fake fan. + +157 +00:31:02,150 --> 00:31:06,500 +Ridiculous, ridiculous. + +158 +00:31:08,910 --> 00:31:10,420 +Then you go! + +159 +00:31:10,470 --> 00:31:14,380 +OK, I'll go, I'll go, I'm going! + +160 +00:31:14,430 --> 00:31:16,908 +I'll go find Bull Demon King. + +161 +00:31:16,909 --> 00:31:19,940 +This is a good solution. + +162 +00:31:21,390 --> 00:31:24,439 +Partner, what do you think? + +163 +00:31:24,440 --> 00:31:27,380 +We'll see how you do. + +164 +00:33:07,190 --> 00:33:11,150 +What do you think, am I pretty today? + +165 +00:33:11,150 --> 00:33:13,779 +Beautiful, my baby. + +166 +00:33:13,829 --> 00:33:17,059 +Accompany me for a walk outside the cave, all right? + +167 +00:33:17,109 --> 00:33:21,539 +My baby, why don't you go by yourself. + +168 +00:33:21,589 --> 00:33:24,819 +Why of course, I'm just a plain country girl. + +169 +00:33:24,869 --> 00:33:28,019 +Taking me outside might cause you to lose face. + +170 +00:33:28,069 --> 00:33:32,029 +Baby, what are you saying? + +171 +00:33:32,029 --> 00:33:37,500 +You go ahead, I'll come out in a while, all right? + +172 +00:33:39,852 --> 00:33:44,557 +Emerald Cloud Cave + +173 +00:35:28,030 --> 00:35:35,659 +Goddess, you're truly an angel come down from heaven. + +174 +00:35:35,710 --> 00:35:37,900 +Who... who are you? + +175 +00:35:37,949 --> 00:35:41,460 +I've come from Palm Leaf Cave to look for Bull Demon King. + +176 +00:35:41,519 --> 00:35:43,980 +Let go of me! + +177 +00:35:49,550 --> 00:35:52,940 +Goddess, slow down! + +178 +00:36:38,768 --> 00:36:40,133 +Emerald Cloud Cave + +179 +00:36:44,230 --> 00:36:49,219 +Baby, who has bullied you? + +180 +00:36:49,269 --> 00:36:50,820 +You! + +181 +00:36:50,869 --> 00:36:54,340 +How could I bully you? + +182 +00:36:56,909 --> 00:36:59,260 +Why don't you go back to Palm Leaf Cave? + +183 +00:36:59,320 --> 00:37:01,699 +It would spare you some embarrassment. + +184 +00:37:01,750 --> 00:37:07,659 +They often send people to look for you, and bully me. + +185 +00:37:07,710 --> 00:37:11,059 +Has there been someone here to look for me? + +186 +00:37:11,110 --> 00:37:15,059 +There's a pig monk outside looking for you. + +187 +00:37:15,119 --> 00:37:18,510 +He almost scared me to death. + +188 +00:37:18,550 --> 00:37:22,739 +How can this be? Wait while I go out to have a look. + +189 +00:37:50,670 --> 00:37:53,780 +Bull, old friend! + +190 +00:37:53,829 --> 00:37:58,139 +There's a very beautiful young lady in here. + +191 +00:37:58,199 --> 00:38:03,889 +Hey, that's my woman! Why have you come to bother her? + +192 +00:38:03,930 --> 00:38:08,550 +Oh, I didn't know, please forgive me! + +193 +00:38:08,550 --> 00:38:11,940 +You didn't know, so I can't blame you. Off you go! + +194 +00:38:11,989 --> 00:38:16,099 +No, no. I still have something I need you to help me with. + +195 +00:38:18,469 --> 00:38:24,710 +We were on our way to retrieve the scriptures when we arrived at Fiery Mountain. + +196 +00:38:24,710 --> 00:38:27,300 +Please ask your wife + +197 +00:38:27,349 --> 00:38:30,820 +to lend us the palm leaf fan for a while. + +198 +00:38:30,880 --> 00:38:33,510 +Absolutely not! Tang Seng and Sun Wukong + +199 +00:38:33,510 --> 00:38:35,179 +are my son's enemies. + +200 +00:38:35,230 --> 00:38:38,739 +I'd love to take my revenge on them. + +201 +00:38:38,789 --> 00:38:44,969 +Your son is with the Goddess of Mercy now, please don't fight. + +202 +00:38:45,030 --> 00:38:48,940 +All right, since we are old friends, I won't fight you. + +203 +00:38:49,000 --> 00:38:51,710 +Now go away! + +204 +00:39:38,389 --> 00:39:44,179 +Baby, that pig monk is a friend of mine. + +205 +00:39:44,230 --> 00:39:46,500 +He wasn't sent from Palm Leaf Cave at all. + +206 +00:39:46,550 --> 00:39:47,739 +I don't believe you. + +207 +00:39:47,789 --> 00:39:50,940 +I'm not lying to you! + +208 +00:39:50,989 --> 00:39:54,019 +Where is that monk now? + +209 +00:39:54,110 --> 00:39:57,780 +I've already scared him away. + +210 +00:43:34,814 --> 00:43:40,987 +Palm Leaf Cave + +211 +00:43:58,630 --> 00:44:01,340 +The king has returned! + +212 +00:44:01,389 --> 00:44:02,369 +Where's grandma? + +213 +00:44:02,429 --> 00:44:04,780 +She's inside. + +214 +00:44:42,989 --> 00:44:48,219 +By what honor has the king come to visit today? + +215 +00:44:48,269 --> 00:44:52,260 +I heard that Sun Wukong and Tang Seng are coming here. + +216 +00:44:52,320 --> 00:44:56,909 +I'm afraid they want to use the palm leaf fan to pass Fiery Mountain. + +217 +00:44:56,949 --> 00:45:00,860 +That monkey is the one who harmed our son. + +218 +00:45:00,909 --> 00:45:08,489 +I'll get him sooner or later, we will have our revenge. + +219 +00:45:08,550 --> 00:45:12,699 +Darling, why are you crying? + +220 +00:45:12,750 --> 00:45:15,699 +That monkey has already been here. + +221 +00:45:15,750 --> 00:45:18,860 +I refused to give him the fan. + +222 +00:45:18,909 --> 00:45:22,260 +I don't know how, but he got inside my stomach. + +223 +00:45:22,309 --> 00:45:25,500 +It hurt so bad I thought I would die. + +224 +00:45:25,550 --> 00:45:30,589 +At last I had no choice but to give him the fan. + +225 +00:45:30,789 --> 00:45:35,260 +That's terrible, how could you give him the fan? + +226 +00:45:38,320 --> 00:45:40,469 +I gave him a false one. + +227 +00:45:40,720 --> 00:45:43,019 +A false one? + +228 +00:46:14,190 --> 00:46:19,860 +A banquet to celebrate the king's return + +229 +00:46:19,909 --> 00:46:25,619 +Please drink the fine wine. + +230 +00:46:25,670 --> 00:46:34,179 +The chicken is fragrant, the duck is beautiful, and the pig is fat. + +231 +00:46:34,239 --> 00:46:45,670 +I try my best to sing, I try my best to dance. + +232 +00:46:45,710 --> 00:46:54,500 +You must also try your best to drink. + +233 +00:47:03,590 --> 00:47:16,389 +My king! You dumped the old one. + +234 +00:47:16,429 --> 00:47:22,610 +You love another woman. + +235 +00:47:22,670 --> 00:47:34,659 +Countless tears were spilled for you. + +236 +00:47:46,710 --> 00:47:55,699 +When the light is out and the curtain is dropped, + +237 +00:47:55,750 --> 00:48:00,869 +you will sleep alone. + +238 +00:48:00,869 --> 00:48:05,510 +You too will taste loneliness. + +239 +00:48:05,510 --> 00:48:13,420 +Pardon me for not making you company. + +240 +00:48:18,550 --> 00:48:24,619 +Even if we are on the same bed, + +241 +00:48:24,670 --> 00:48:34,340 +we will sleep under separate sheets. + +242 +00:48:38,389 --> 00:48:42,380 +King, I'm drunk. + +243 +00:48:55,070 --> 00:48:58,139 +Darling, where did you put the real fan? + +244 +00:48:58,190 --> 00:49:05,460 +That monkey is very deceitful, and the pig has even greater skill. + +245 +00:49:05,510 --> 00:49:09,780 +If you're not careful they might trick you. + +246 +00:49:18,360 --> 00:49:21,980 +Our treasure is right here. + +247 +00:49:31,429 --> 00:49:39,309 +King, what are you thinking about? Why don't you take it? + +248 +00:49:39,309 --> 00:49:40,847 +My treasure. + +249 +00:49:41,514 --> 00:49:44,150 +Emerald Cloud Cave + +250 +00:49:44,250 --> 00:49:49,019 +Baby, have another cup. Drink. + +251 +00:49:53,909 --> 00:49:59,510 +Gold Dragon King has asked me to drink with him tonight + +252 +00:49:59,510 --> 00:50:01,420 +Then you should go. + +253 +00:50:01,469 --> 00:50:02,860 +That's right. + +254 +00:50:02,909 --> 00:50:06,610 +You should prepare the golden eyed beast for grandpa. + +255 +00:50:06,670 --> 00:50:08,260 +I will. + +256 +00:50:08,320 --> 00:50:12,590 +You should drink a little less tonight. + +257 +00:50:12,630 --> 00:50:15,739 +Otherwise I won't be able to wake you up. + +258 +00:50:15,800 --> 00:50:19,110 +It's terrible, grandpa's golden eyed beast has disappeared! + +259 +00:50:19,150 --> 00:50:20,900 +Are you all deaf and blind? + +260 +00:50:20,949 --> 00:50:24,030 +How could it just disappear? + +261 +00:50:24,030 --> 00:50:27,900 +Baby, don't mind them. + +262 +00:50:27,960 --> 00:50:31,710 +I'm afraid Zhu Bajie might have stolen it. + +263 +00:50:31,750 --> 00:50:35,260 +Maybe I should go over to Palm Leaf Cave. + +264 +00:50:35,320 --> 00:50:39,309 +What? You've had this planned all along. + +265 +00:50:42,280 --> 00:50:48,150 +You still want to go over to that shameless woman? + +266 +00:50:48,190 --> 00:50:50,699 +Please baby, don't cry. + +267 +00:50:50,750 --> 00:50:54,059 +I'll be back soon. + +268 +00:50:57,624 --> 00:51:01,194 +Palm Leaf Cave + +269 +00:51:02,670 --> 00:51:07,300 +Come over here, drink a little! + +270 +00:51:10,349 --> 00:51:12,460 +Now I can relax. + +271 +00:51:12,510 --> 00:51:16,699 +We don't have to worry about our treasure being stolen. + +272 +00:51:16,750 --> 00:51:21,300 +Even if they stole it, they wouldn't know to pull the silk thread. + +273 +00:51:21,360 --> 00:51:26,269 +Having just a pearl won't be of any use. + +274 +00:51:26,309 --> 00:51:31,780 +Pulling the thread will turn it into a fan, right? + +275 +00:51:35,119 --> 00:51:38,070 +King, you're drunk. + +276 +00:51:38,110 --> 00:51:44,019 +You forgot about your own treasure, and are asking me. + +277 +00:51:49,989 --> 00:51:53,690 +Lady, look at who I am. + +278 +00:52:00,320 --> 00:52:03,750 +Who are you? + +279 +00:52:03,789 --> 00:52:09,889 +I am Tang Seng's second apprentice, Zhu Bajie. + +280 +00:52:09,949 --> 00:52:14,780 +Sorry about bothering you, and thanks! + +281 +00:52:19,079 --> 00:52:21,710 +Bye! + +282 +00:53:06,829 --> 00:53:10,699 +Bull's wife is too flirtatious. + +283 +00:53:10,760 --> 00:53:14,710 +All her underlings are handsome. + +284 +00:53:14,750 --> 00:53:24,809 +Old Pig almost couldn't take it. + +285 +00:53:24,869 --> 00:53:28,860 +Using clever tricks and tactics, + +286 +00:53:28,909 --> 00:53:32,820 +I stole their treasure away. + +287 +00:53:32,880 --> 00:53:36,789 +This is a great accomplishment. + +288 +00:53:36,829 --> 00:53:38,300 +Sandy should be on his knees. + +289 +00:53:38,349 --> 00:53:40,730 +Monkey should learn from me. + +290 +00:53:40,789 --> 00:53:45,219 +Even Master will be astonished. + +291 +00:53:45,280 --> 00:53:49,190 +Old Pig is truly masterful. + +292 +00:53:49,230 --> 00:53:54,349 +Old Pig is truly masterful. + +293 +00:54:36,719 --> 00:54:40,469 +Fool, how are things going? + +294 +00:54:40,510 --> 00:54:42,809 +Not only did I get the fan, + +295 +00:54:42,880 --> 00:54:48,789 +Princess Iron Fan was my wife for half a day, too. + +296 +00:54:48,829 --> 00:54:51,699 +You got a good deal. + +297 +00:54:58,150 --> 00:55:01,579 +Hey, let me see the fan. + +298 +00:55:16,030 --> 00:55:20,219 +Why did you shrink it? + +299 +00:55:40,550 --> 00:55:45,340 +Old Pig, you do recognize me, right? + +300 +00:55:45,389 --> 00:55:49,170 +Stop joking around with me. + +301 +00:55:49,230 --> 00:55:52,139 +Who's joking around with you? + +302 +00:56:42,869 --> 00:56:45,380 +Fool, how did it go? + +303 +00:56:45,429 --> 00:56:47,099 +It was all for nothing. + +304 +00:56:47,150 --> 00:56:49,980 +Wuneng, did you borrow the fan? + +305 +00:56:50,030 --> 00:56:53,340 +I found Bull Demon King, but he refused. + +306 +00:56:53,400 --> 00:56:59,190 +Then, I turned into his look-alike. + +307 +00:56:59,230 --> 00:57:03,539 +I tricked Princess Iron Fan into giving me the fan. + +308 +00:57:03,590 --> 00:57:10,590 +But then Old Bull turned into your look-alike and tricked me into giving it back. + +309 +00:57:10,590 --> 00:57:12,739 +Old Bull's skills are great. + +310 +00:57:12,800 --> 00:57:16,150 +I got beaten up by him, too. + +311 +00:57:16,190 --> 00:57:21,380 +How could you get the fan and still be such a fool? + +312 +00:57:21,429 --> 00:57:25,659 +Not everything revolves around you! + +313 +00:57:30,750 --> 00:57:34,369 +Don't fight, we should quickly think of a solution. + +314 +00:57:34,429 --> 00:57:40,260 +In which... which direction is there no fire? + +315 +00:57:40,320 --> 00:57:47,070 +Of east, south, west, north, there's fire only to the west. + +316 +00:57:47,119 --> 00:57:50,739 +So we have no option but to go back. + +317 +00:57:50,789 --> 00:57:52,940 +This path is blocked, what other options do we have? + +318 +00:57:52,989 --> 00:57:55,219 +Bajie, don't talk like that. + +319 +00:57:55,269 --> 00:57:59,139 +There will always be obstacles in our path. + +320 +00:57:59,190 --> 00:58:04,539 +To complete our sacred task we must be strong in our faith. + +321 +00:58:04,590 --> 00:58:09,219 +We can't change our goal half way just because we encounter some obstacles. + +322 +00:58:09,280 --> 00:58:14,590 +The reason that we've been defeated is that we haven't worked together. + +323 +00:58:14,630 --> 00:58:17,139 +If the three of you work as one, + +324 +00:58:17,190 --> 00:58:20,500 +put your strength together to fight Bull Demon King, + +325 +00:58:20,550 --> 00:58:22,849 +then you will certainly be victorious. + +326 +00:58:22,909 --> 00:58:26,030 +We have heard the order of Master + +327 +00:58:26,030 --> 00:58:30,139 +and will fight Bull Demon King to the end. + +328 +00:58:30,190 --> 00:58:34,260 +to... to the end. + +329 +00:58:34,320 --> 00:58:37,710 +That's excellent! + +330 +00:58:37,750 --> 00:58:40,980 +We have all been through hardships. + +331 +00:58:41,039 --> 00:58:43,869 +I hope everyone will make an effort + +332 +00:58:43,869 --> 00:58:49,579 +together with my disciples to defeat Bull Demon King and put out the flames of Fiery Mountain. + +333 +00:58:49,630 --> 00:58:52,820 +Otherwise this misery will never end. + +334 +00:58:53,869 --> 00:58:57,489 +We have heard the order of Master, to seek happiness for all. + +335 +00:58:57,550 --> 00:58:58,860 +Everyone work together! + +336 +00:58:58,909 --> 00:59:00,519 +All right! + +337 +01:08:23,229 --> 01:08:25,609 +Grandma, it's terrible! + +338 +01:08:25,670 --> 01:08:30,789 +Grandpa has been trapped, come quickly and look! + +339 +01:08:54,470 --> 01:08:56,699 +The fight's not over yet, not over. + +340 +01:08:56,760 --> 01:08:58,710 +Careful, careful. + +341 +01:08:59,760 --> 01:09:05,789 +Beast, all you have to is give us the fan and we'll spare your life. + +342 +01:09:05,840 --> 01:09:12,750 +Old Bull, where is the fan? Hand it over! + +343 +01:09:12,789 --> 01:09:19,340 +My... my wife... has it. + +344 +01:09:25,239 --> 01:09:27,989 +Darling, darling! + +345 +01:09:28,029 --> 01:09:32,260 +Save me, hurry! + +346 +01:09:32,319 --> 01:09:35,109 +Give them the fan. + +347 +01:09:35,149 --> 01:09:39,619 +King! All right, all right! + +348 +01:09:43,399 --> 01:09:47,229 +Wukong, you go one more time! + +349 +01:12:30,850 --> 01:12:46,599 +The End diff --git a/js2/mwEmbed/example_usage/media/sample_smil.xml b/js2/mwEmbed/example_usage/media/sample_smil.xml new file mode 100644 index 0000000000..25ffecc2ae --- /dev/null +++ b/js2/mwEmbed/example_usage/media/sample_smil.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + diff --git a/js2/mwEmbed/jquery/jquery-1.3.2.js b/js2/mwEmbed/jquery/jquery-1.3.2.js new file mode 100644 index 0000000000..d2548a54cf --- /dev/null +++ b/js2/mwEmbed/jquery/jquery-1.3.2.js @@ -0,0 +1,3657 @@ +/*! + * jQuery JavaScript Library v1.3.2 + * http://jquery.com/ + * + * Copyright (c) 2009 John Resig + * Dual licensed under the MIT and GPL licenses. + * http://docs.jquery.com/License + * + * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009) + * Revision: 6246 + */ +(function(){ +var + // Will speed up references to window, and allows munging its name. + window = this, + // Will speed up references to undefined, and allows munging its name. + undefined, + // Map over jQuery in case of overwrite + _jQuery = window.jQuery, + // Map over the $ in case of overwrite + _$ = window.$, + jQuery = window.jQuery = window.$ = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + return new jQuery.fn.init( selector, context ); + }, + // A simple way to check for HTML strings or ID strings + // (both of which we optimize for) + quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/, + // Is it a simple selector + isSimple = /^.[^:#\[\.,]*$/; +jQuery.fn = jQuery.prototype = { + init: function( selector, context ) { + // Make sure that a selection was provided + selector = selector || document; + // Handle $(DOMElement) + if ( selector.nodeType ) { + this[0] = selector; + this.length = 1; + this.context = selector; + return this; + } + // Handle HTML strings + if ( typeof selector === "string" ) { + // Are we dealing with HTML string or an ID? + var match = quickExpr.exec( selector ); + // Verify a match, and that no context was specified for #id + if ( match && (match[1] || !context) ) { + // HANDLE: $(html) -> $(array) + if ( match[1] ) + selector = jQuery.clean( [ match[1] ], context ); + // HANDLE: $("#id") + else { + var elem = document.getElementById( match[3] ); + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem && elem.id != match[3] ) + return jQuery().find( selector ); + // Otherwise, we inject the element directly into the jQuery object + var ret = jQuery( elem || [] ); + ret.context = document; + ret.selector = selector; + return ret; + } + // HANDLE: $(expr, [context]) + // (which is just equivalent to: $(content).find(expr) + } else + return jQuery( context ).find( selector ); + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) + return jQuery( document ).ready( selector ); + // Make sure that old selector state is passed along + if ( selector.selector && selector.context ) { + this.selector = selector.selector; + this.context = selector.context; + } + return this.setArray(jQuery.isArray( selector ) ? + selector : + jQuery.makeArray(selector)); + }, + // Start with an empty selector + selector: "", + // The current version of jQuery being used + jquery: "1.3.2", + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num === undefined ? + // Return a 'clean' array + Array.prototype.slice.call( this ) : + // Return just the object + this[ num ]; + }, + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems, name, selector ) { + // Build a new jQuery matched element set + var ret = jQuery( elems ); + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + ret.context = this.context; + if ( name === "find" ) + ret.selector = this.selector + (this.selector ? " " : "") + selector; + else if ( name ) + ret.selector = this.selector + "." + name + "(" + selector + ")"; + // Return the newly-formed element set + return ret; + }, + // Force the current matched set of elements to become + // the specified array of elements (destroying the stack in the process) + // You should use pushStack() in order to do this, but maintain the stack + setArray: function( elems ) { + // Resetting the length to 0, then using the native Array push + // is a super-fast way to populate an object with array-like properties + this.length = 0; + Array.prototype.push.apply( this, elems ); + return this; + }, + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + // Locate the position of the desired element + return jQuery.inArray( + // If it receives a jQuery object, the first element is used + elem && elem.jquery ? elem[0] : elem + , this ); + }, + attr: function( name, value, type ) { + var options = name; + // Look for the case where we're accessing a style value + if ( typeof name === "string" ) + if ( value === undefined ) + return this[0] && jQuery[ type || "attr" ]( this[0], name ); + else { + options = {}; + options[ name ] = value; + } + // Check to see if we're setting style values + return this.each(function(i){ + // Set all the styles + for ( name in options ) + jQuery.attr( + type ? + this.style : + this, + name, jQuery.prop( this, options[ name ], type, i, name ) + ); + }); + }, + css: function( key, value ) { + // ignore negative width and height values + if ( (key == 'width' || key == 'height') && parseFloat(value) < 0 ) + value = undefined; + return this.attr( key, value, "curCSS" ); + }, + text: function( text ) { + if ( typeof text !== "object" && text != null ) + return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) ); + var ret = ""; + jQuery.each( text || this, function(){ + jQuery.each( this.childNodes, function(){ + if ( this.nodeType != 8 ) + ret += this.nodeType != 1 ? + this.nodeValue : + jQuery.fn.text( [ this ] ); + }); + }); + return ret; + }, + wrapAll: function( html ) { + if ( this[0] ) { + // The elements to wrap the target around + var wrap = jQuery( html, this[0].ownerDocument ).clone(); + if ( this[0].parentNode ) + wrap.insertBefore( this[0] ); + wrap.map(function(){ + var elem = this; + while ( elem.firstChild ) + elem = elem.firstChild; + return elem; + }).append(this); + } + return this; + }, + wrapInner: function( html ) { + return this.each(function(){ + jQuery( this ).contents().wrapAll( html ); + }); + }, + wrap: function( html ) { + return this.each(function(){ + jQuery( this ).wrapAll( html ); + }); + }, + append: function() { + return this.domManip(arguments, true, function(elem){ + if (this.nodeType == 1) + this.appendChild( elem ); + }); + }, + prepend: function() { + return this.domManip(arguments, true, function(elem){ + if (this.nodeType == 1) + this.insertBefore( elem, this.firstChild ); + }); + }, + before: function() { + return this.domManip(arguments, false, function(elem){ + this.parentNode.insertBefore( elem, this ); + }); + }, + after: function() { + return this.domManip(arguments, false, function(elem){ + this.parentNode.insertBefore( elem, this.nextSibling ); + }); + }, + end: function() { + return this.prevObject || jQuery( [] ); + }, + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: [].push, + sort: [].sort, + splice: [].splice, + find: function( selector ) { + if ( this.length === 1 ) { + var ret = this.pushStack( [], "find", selector ); + ret.length = 0; + jQuery.find( selector, this[0], ret ); + return ret; + } else { + return this.pushStack( jQuery.unique(jQuery.map(this, function(elem){ + return jQuery.find( selector, elem ); + })), "find", selector ); + } + }, + clone: function( events ) { + // Do the clone + var ret = this.map(function(){ + if ( !jQuery.support.noCloneEvent && !jQuery.isXMLDoc(this) ) { + // IE copies events bound via attachEvent when + // using cloneNode. Calling detachEvent on the + // clone will also remove the events from the orignal + // In order to get around this, we use innerHTML. + // Unfortunately, this means some modifications to + // attributes in IE that are actually only stored + // as properties will not be copied (such as the + // the name attribute on an input). + var html = this.outerHTML; + if ( !html ) { + var div = this.ownerDocument.createElement("div"); + div.appendChild( this.cloneNode(true) ); + html = div.innerHTML; + } + return jQuery.clean([html.replace(/ jQuery\d+="(?:\d+|null)"/g, "").replace(/^\s*/, "")])[0]; + } else + return this.cloneNode(true); + }); + // Copy the events from the original to the clone + if ( events === true ) { + var orig = this.find("*").andSelf(), i = 0; + ret.find("*").andSelf().each(function(){ + if ( this.nodeName !== orig[i].nodeName ) + return; + var events = jQuery.data( orig[i], "events" ); + for ( var type in events ) { + for ( var handler in events[ type ] ) { + jQuery.event.add( this, type, events[ type ][ handler ], events[ type ][ handler ].data ); + } + } + i++; + }); + } + // Return the cloned set + return ret; + }, + filter: function( selector ) { + return this.pushStack( + jQuery.isFunction( selector ) && + jQuery.grep(this, function(elem, i){ + return selector.call( elem, i ); + }) || + jQuery.multiFilter( selector, jQuery.grep(this, function(elem){ + return elem.nodeType === 1; + }) ), "filter", selector ); + }, + closest: function( selector ) { + var pos = jQuery.expr.match.POS.test( selector ) ? jQuery(selector) : null, + closer = 0; + return this.map(function(){ + var cur = this; + while ( cur && cur.ownerDocument ) { + if ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selector) ) { + jQuery.data(cur, "closest", closer); + return cur; + } + cur = cur.parentNode; + closer++; + } + }); + }, + not: function( selector ) { + if ( typeof selector === "string" ) + // test special case where just one selector is passed in + if ( isSimple.test( selector ) ) + return this.pushStack( jQuery.multiFilter( selector, this, true ), "not", selector ); + else + selector = jQuery.multiFilter( selector, this ); + var isArrayLike = selector.length && selector[selector.length - 1] !== undefined && !selector.nodeType; + return this.filter(function() { + return isArrayLike ? jQuery.inArray( this, selector ) < 0 : this != selector; + }); + }, + add: function( selector ) { + return this.pushStack( jQuery.unique( jQuery.merge( + this.get(), + typeof selector === "string" ? + jQuery( selector ) : + jQuery.makeArray( selector ) + ))); + }, + is: function( selector ) { + return !!selector && jQuery.multiFilter( selector, this ).length > 0; + }, + hasClass: function( selector ) { + return !!selector && this.is( "." + selector ); + }, + val: function( value ) { + if ( value === undefined ) { + var elem = this[0]; + if ( elem ) { + if( jQuery.nodeName( elem, 'option' ) ) + return (elem.attributes.value || {}).specified ? elem.value : elem.text; + + // We need to handle select boxes special + if ( jQuery.nodeName( elem, "select" ) ) { + var index = elem.selectedIndex, + values = [], + options = elem.options, + one = elem.type == "select-one"; + // Nothing was selected + if ( index < 0 ) + return null; + // Loop through all the selected options + for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { + var option = options[ i ]; + if ( option.selected ) { + // Get the specifc value for the option + value = jQuery(option).val(); + // We don't need an array for one selects + if ( one ) + return value; + // Multi-Selects return an array + values.push( value ); + } + } + return values; + } + // Everything else, we just grab the value + return (elem.value || "").replace(/\r/g, ""); + } + return undefined; + } + if ( typeof value === "number" ) + value += ''; + return this.each(function(){ + if ( this.nodeType != 1 ) + return; + if ( jQuery.isArray(value) && /radio|checkbox/.test( this.type ) ) + this.checked = (jQuery.inArray(this.value, value) >= 0 || + jQuery.inArray(this.name, value) >= 0); + else if ( jQuery.nodeName( this, "select" ) ) { + var values = jQuery.makeArray(value); + jQuery( "option", this ).each(function(){ + this.selected = (jQuery.inArray( this.value, values ) >= 0 || + jQuery.inArray( this.text, values ) >= 0); + }); + if ( !values.length ) + this.selectedIndex = -1; + } else + this.value = value; + }); + }, + html: function( value ) { + return value === undefined ? + (this[0] ? + this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g, "") : + null) : + this.empty().append( value ); + }, + replaceWith: function( value ) { + return this.after( value ).remove(); + }, + eq: function( i ) { + return this.slice( i, +i + 1 ); + }, + slice: function() { + return this.pushStack( Array.prototype.slice.apply( this, arguments ), + "slice", Array.prototype.slice.call(arguments).join(",") ); + }, + map: function( callback ) { + return this.pushStack( jQuery.map(this, function(elem, i){ + return callback.call( elem, i, elem ); + })); + }, + andSelf: function() { + return this.add( this.prevObject ); + }, + domManip: function( args, table, callback ) { + if ( this[0] ) { + var fragment = (this[0].ownerDocument || this[0]).createDocumentFragment(), + scripts = jQuery.clean( args, (this[0].ownerDocument || this[0]), fragment ), + first = fragment.firstChild; + if ( first ) + for ( var i = 0, l = this.length; i < l; i++ ) + callback.call( root(this[i], first), this.length > 1 || i > 0 ? + fragment.cloneNode(true) : fragment ); + + if ( scripts ) + jQuery.each( scripts, evalScript ); + } + return this; + + function root( elem, cur ) { + return table && jQuery.nodeName(elem, "table") && jQuery.nodeName(cur, "tr") ? + (elem.getElementsByTagName("tbody")[0] || + elem.appendChild(elem.ownerDocument.createElement("tbody"))) : + elem; + } + } +}; +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; +function evalScript( i, elem ) { + if ( elem.src ) + jQuery.ajax({ + url: elem.src, + async: false, + dataType: "script" + }); + else + jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" ); + if ( elem.parentNode ) + elem.parentNode.removeChild( elem ); +} +function now(){ + return +new Date; +} +jQuery.extend = jQuery.fn.extend = function() { + // copy reference to target object + var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options; + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction(target) ) + target = {}; + // extend jQuery itself if only one argument is passed + if ( length == i ) { + target = this; + --i; + } + for ( ; i < length; i++ ) + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) + // Extend the base object + for ( var name in options ) { + var src = target[ name ], copy = options[ name ]; + // Prevent never-ending loop + if ( target === copy ) + continue; + // Recurse if we're merging object values + if ( deep && copy && typeof copy === "object" && !copy.nodeType ) + target[ name ] = jQuery.extend( deep, + // Never move original objects, clone them + src || ( copy.length != null ? [ ] : { } ) + , copy ); + // Don't bring in undefined values + else if ( copy !== undefined ) + target[ name ] = copy; + } + // Return the modified object + return target; +}; +// exclude the following css properties to add px +var exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i, + // cache defaultView + defaultView = document.defaultView || {}, + toString = Object.prototype.toString; +jQuery.extend({ + noConflict: function( deep ) { + window.$ = _$; + if ( deep ) + window.jQuery = _jQuery; + return jQuery; + }, + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + return toString.call(obj) === "[object Function]"; + }, + isArray: function( obj ) { + return toString.call(obj) === "[object Array]"; + }, + // check if an element is in a (or is an) XML document + isXMLDoc: function( elem ) { + return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" || + !!elem.ownerDocument && jQuery.isXMLDoc( elem.ownerDocument ); + }, + // Evalulates a script in a global context + globalEval: function( data ) { + if ( data && /\S/.test(data) ) { + // Inspired by code by Andrea Giammarchi + // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html + var head = document.getElementsByTagName("head")[0] || document.documentElement, + script = document.createElement("script"); + script.type = "text/javascript"; + if ( jQuery.support.scriptEval ) + script.appendChild( document.createTextNode( data ) ); + else + script.text = data; + // Use insertBefore instead of appendChild to circumvent an IE6 bug. + // This arises when a base node is used (#2709). + head.insertBefore( script, head.firstChild ); + head.removeChild( script ); + } + }, + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase(); + }, + // args is for internal usage only + each: function( object, callback, args ) { + var name, i = 0, length = object.length; + if ( args ) { + if ( length === undefined ) { + for ( name in object ) + if ( callback.apply( object[ name ], args ) === false ) + break; + } else + for ( ; i < length; ) + if ( callback.apply( object[ i++ ], args ) === false ) + break; + // A special, fast, case for the most common use of each + } else { + if ( length === undefined ) { + for ( name in object ) + if ( callback.call( object[ name ], name, object[ name ] ) === false ) + break; + } else + for ( var value = object[0]; + i < length && callback.call( value, i, value ) !== false; value = object[++i] ){} + } + return object; + }, + prop: function( elem, value, type, i, name ) { + // Handle executable functions + if ( jQuery.isFunction( value ) ) + value = value.call( elem, i ); + // Handle passing in a number to a CSS property + return typeof value === "number" && type == "curCSS" && !exclude.test( name ) ? + value + "px" : + value; + }, + className: { + // internal only, use addClass("class") + add: function( elem, classNames ) { + jQuery.each((classNames || "").split(/\s+/), function(i, className){ + if ( elem.nodeType == 1 && !jQuery.className.has( elem.className, className ) ) + elem.className += (elem.className ? " " : "") + className; + }); + }, + // internal only, use removeClass("class") + remove: function( elem, classNames ) { + if (elem.nodeType == 1) + elem.className = classNames !== undefined ? + jQuery.grep(elem.className.split(/\s+/), function(className){ + return !jQuery.className.has( classNames, className ); + }).join(" ") : + ""; + }, + // internal only, use hasClass("class") + has: function( elem, className ) { + return elem && jQuery.inArray( className, (elem.className || elem).toString().split(/\s+/) ) > -1; + } + }, + // A method for quickly swapping in/out CSS properties to get correct calculations + swap: function( elem, options, callback ) { + var old = {}; + // Remember the old values, and insert the new ones + for ( var name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + callback.call( elem ); + // Revert the old values + for ( var name in options ) + elem.style[ name ] = old[ name ]; + }, + css: function( elem, name, force, extra ) { + if ( name == "width" || name == "height" ) { + var val, props = { position: "absolute", visibility: "hidden", display:"block" }, which = name == "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ]; + function getWH() { + val = name == "width" ? elem.offsetWidth : elem.offsetHeight; + if ( extra === "border" ) + return; + jQuery.each( which, function() { + if ( !extra ) + val -= parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0; + if ( extra === "margin" ) + val += parseFloat(jQuery.curCSS( elem, "margin" + this, true)) || 0; + else + val -= parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0; + }); + } + if ( elem.offsetWidth !== 0 ) + getWH(); + else + jQuery.swap( elem, props, getWH ); + return Math.max(0, Math.round(val)); + } + return jQuery.curCSS( elem, name, force ); + }, + curCSS: function( elem, name, force ) { + var ret, style = elem.style; + // We need to handle opacity special in IE + if ( name == "opacity" && !jQuery.support.opacity ) { + ret = jQuery.attr( style, "opacity" ); + return ret == "" ? + "1" : + ret; + } + // Make sure we're using the right name for getting the float value + if ( name.match( /float/i ) ) + name = styleFloat; + if ( !force && style && style[ name ] ) + ret = style[ name ]; + else if ( defaultView.getComputedStyle ) { + // Only "float" is needed here + if ( name.match( /float/i ) ) + name = "float"; + name = name.replace( /([A-Z])/g, "-$1" ).toLowerCase(); + var computedStyle = defaultView.getComputedStyle( elem, null ); + if ( computedStyle ) + ret = computedStyle.getPropertyValue( name ); + // We should always get a number back from opacity + if ( name == "opacity" && ret == "" ) + ret = "1"; + } else if ( elem.currentStyle ) { + var camelCase = name.replace(/\-(\w)/g, function(all, letter){ + return letter.toUpperCase(); + }); + ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ]; + // From the awesome hack by Dean Edwards + // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 + // If we're not dealing with a regular pixel number + // but a number that has a weird ending, we need to convert it to pixels + if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) { + // Remember the original values + var left = style.left, rsLeft = elem.runtimeStyle.left; + // Put in the new values to get a computed value out + elem.runtimeStyle.left = elem.currentStyle.left; + style.left = ret || 0; + ret = style.pixelLeft + "px"; + // Revert the changed values + style.left = left; + elem.runtimeStyle.left = rsLeft; + } + } + return ret; + }, + clean: function( elems, context, fragment ) { + context = context || document; + // !context.createElement fails in IE with an error but returns typeof 'object' + if ( typeof context.createElement === "undefined" ) + context = context.ownerDocument || context[0] && context[0].ownerDocument || document; + // If a single string is passed in and it's a single tag + // just do a createElement and skip the rest + if ( !fragment && elems.length === 1 && typeof elems[0] === "string" ) { + var match = /^<(\w+)\s*\/?>$/.exec(elems[0]); + if ( match ) + return [ context.createElement( match[1] ) ]; + } + var ret = [], scripts = [], div = context.createElement("div"); + jQuery.each(elems, function(i, elem){ + if ( typeof elem === "number" ) + elem += ''; + if ( !elem ) + return; + // Convert html string into DOM nodes + if ( typeof elem === "string" ) { + // Fix "XHTML"-style tags in all browsers + elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){ + return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ? + all : + front + ">"; + }); + // Trim whitespace, otherwise indexOf won't work as expected + var tags = elem.replace(/^\s+/, "").substring(0, 10).toLowerCase(); + var wrap = + // option or optgroup + !tags.indexOf("", "" ] || + !tags.indexOf("", "" ] || + tags.match(/^<(thead|tbody|tfoot|colg|cap)/) && + [ 1, "", "
" ] || + !tags.indexOf("", "" ] || + // matched above + (!tags.indexOf("", "" ] || + !tags.indexOf("", "" ] || + // IE can't serialize and + + + + + + + + + + + + + +

jQuery bgiframe - Visual Test

+

+
+
+ + + + + + + + + + + + + + + + + + + +
+ +
nothing
+
+
+
top:
+
'auto'
+ +
left:
+
'auto'
+ +
width:
+
'auto'
+ +
height:
+
'auto'
+
+
+
+
+
top:
+
0
+ +
left:
+
0
+ +
width:
+
'auto'
+ +
height:
+
'auto'
+
+
+
+
+
top:
+
-5
+ +
left:
+
-5
+ +
width:
+
270
+ +
height:
+
120
+
+
+
+
+
top:
+
0
+ +
left:
+
0
+ +
width:
+
260
+ +
height:
+
110
+
+
+
+
+
top:
+
'-5px'
+ +
left:
+
'-5px'
+ +
width:
+
'270px'
+ +
height:
+
'120px'
+
+
+
+
+
top:
+
'-.5em'
+ +
left:
+
'-.5em'
+ +
width:
+
'17em'
+ +
height:
+
'12em'
+
+
+
+
+
top:
+
'-.5em'
+ +
left:
+
'-.5em'
+ +
width:
+
'auto'
+ +
height:
+
'auto'
+
+
+
+
+
top:
+
'auto'
+ +
left:
+
'auto'
+ +
width:
+
'auto'
+ +
height:
+
'auto'
+ +
opacity:
+
false
+
+
+
+ + \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/external/cookie/jquery.cookie.min.js b/js2/mwEmbed/jquery/jquery.ui/external/cookie/jquery.cookie.min.js new file mode 100644 index 0000000000..cb09af9846 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/external/cookie/jquery.cookie.min.js @@ -0,0 +1,10 @@ +/** + * Cookie plugin + * + * Copyright (c) 2006 Klaus Hartl (stilbuero.de) + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + */ +jQuery.cookie=function(name,value,options){if(typeof value!='undefined'){options=options||{};if(value===null){value='';options=$.extend({},options);options.expires=-1;}var expires='';if(options.expires&&(typeof options.expires=='number'||options.expires.toUTCString)){var date;if(typeof options.expires=='number'){date=new Date();date.setTime(date.getTime()+(options.expires*24*60*60*1000));}else{date=options.expires;}expires='; expires='+date.toUTCString();}var path=options.path?'; path='+(options.path):'';var domain=options.domain?'; domain='+(options.domain):'';var secure=options.secure?'; secure':'';document.cookie=[name,'=',encodeURIComponent(value),expires,path,domain,secure].join('');}else{var cookieValue=null;if(document.cookie&&document.cookie!=''){var cookies=document.cookie.split(';');for(var i=0;i35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('q.5=x(k,d,a){4(m d!=\'H\'){a=a||{};4(d===p){d=\'\';a=$.A({},a);a.3=-1}2 g=\'\';4(a.3&&(m a.3==\'u\'||a.3.s)){2 f;4(m a.3==\'u\'){f=F C();f.B(f.z()+(a.3*y*o*o*v))}n{f=a.3}g=\'; 3=\'+f.s()}2 b=a.7?\'; 7=\'+(a.7):\'\';2 e=a.9?\'; 9=\'+(a.9):\'\';2 l=a.t?\'; t\':\'\';6.5=[k,\'=\',L(d),g,b,e,l].K(\'\')}n{2 h=p;4(6.5&&6.5!=\'\'){2 c=6.5.E(\';\');D(2 i=0;i/g, ">"); + n = n.replace(/"/g, """); + + return n; +} + +function diffString( o, n ) { + o = o.replace(/\s+$/, ''); + n = n.replace(/\s+$/, ''); + + var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/) ); + var str = ""; + + var oSpace = o.match(/\s+/g); + if (oSpace == null) { + oSpace = ["\n"]; + } else { + oSpace.push("\n"); + } + var nSpace = n.match(/\s+/g); + if (nSpace == null) { + nSpace = ["\n"]; + } else { + nSpace.push("\n"); + } + + if (out.n.length == 0) { + for (var i = 0; i < out.o.length; i++) { + str += '' + escape(out.o[i]) + oSpace[i] + ""; + } + } else { + if (out.n[0].text == null) { + for (n = 0; n < out.o.length && out.o[n].text == null; n++) { + str += '' + escape(out.o[n]) + oSpace[n] + ""; + } + } + + for ( var i = 0; i < out.n.length; i++ ) { + if (out.n[i].text == null) { + str += '' + escape(out.n[i]) + nSpace[i] + ""; + } else { + var pre = ""; + + for (n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) { + pre += '' + escape(out.o[n]) + oSpace[n] + ""; + } + str += " " + out.n[i].text + nSpace[i] + pre; + } + } + } + + return str; +} + +function randomColor() { + return "rgb(" + (Math.random() * 100) + "%, " + + (Math.random() * 100) + "%, " + + (Math.random() * 100) + "%)"; +} +function diffString2( o, n ) { + o = o.replace(/\s+$/, ''); + n = n.replace(/\s+$/, ''); + + var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/) ); + + var oSpace = o.match(/\s+/g); + if (oSpace == null) { + oSpace = ["\n"]; + } else { + oSpace.push("\n"); + } + var nSpace = n.match(/\s+/g); + if (nSpace == null) { + nSpace = ["\n"]; + } else { + nSpace.push("\n"); + } + + var os = ""; + var colors = new Array(); + for (var i = 0; i < out.o.length; i++) { + colors[i] = randomColor(); + + if (out.o[i].text != null) { + os += '' + + escape(out.o[i].text) + oSpace[i] + ""; + } else { + os += "" + escape(out.o[i]) + oSpace[i] + ""; + } + } + + var ns = ""; + for (var i = 0; i < out.n.length; i++) { + if (out.n[i].text != null) { + ns += '' + + escape(out.n[i].text) + nSpace[i] + ""; + } else { + ns += "" + escape(out.n[i]) + nSpace[i] + ""; + } + } + + return { o : os , n : ns }; +} + +function diff( o, n ) { + var ns = new Object(); + var os = new Object(); + + for ( var i = 0; i < n.length; i++ ) { + if ( ns[ n[i] ] == null ) + ns[ n[i] ] = { rows: new Array(), o: null }; + ns[ n[i] ].rows.push( i ); + } + + for ( var i = 0; i < o.length; i++ ) { + if ( os[ o[i] ] == null ) + os[ o[i] ] = { rows: new Array(), n: null }; + os[ o[i] ].rows.push( i ); + } + + for ( var i in ns ) { + if ( ns[i].rows.length == 1 && typeof(os[i]) != "undefined" && os[i].rows.length == 1 ) { + n[ ns[i].rows[0] ] = { text: n[ ns[i].rows[0] ], row: os[i].rows[0] }; + o[ os[i].rows[0] ] = { text: o[ os[i].rows[0] ], row: ns[i].rows[0] }; + } + } + + for ( var i = 0; i < n.length - 1; i++ ) { + if ( n[i].text != null && n[i+1].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null && + n[i+1] == o[ n[i].row + 1 ] ) { + n[i+1] = { text: n[i+1], row: n[i].row + 1 }; + o[n[i].row+1] = { text: o[n[i].row+1], row: i + 1 }; + } + } + + for ( var i = n.length - 1; i > 0; i-- ) { + if ( n[i].text != null && n[i-1].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null && + n[i-1] == o[ n[i].row - 1 ] ) { + n[i-1] = { text: n[i-1], row: n[i].row - 1 }; + o[n[i].row-1] = { text: o[n[i].row-1], row: i - 1 }; + } + } + + return { o: o, n: n }; +} + diff --git a/js2/mwEmbed/jquery/jquery.ui/external/qunit/testrunner.js b/js2/mwEmbed/jquery/jquery.ui/external/qunit/testrunner.js new file mode 100644 index 0000000000..4a408d319e --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/external/qunit/testrunner.js @@ -0,0 +1,780 @@ +/* + * QUnit - jQuery unit testrunner + * + * http://docs.jquery.com/QUnit + * + * Copyright (c) 2008 John Resig, Jörn Zaefferer + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * $Id: testrunner.js 6173 2009-02-02 20:09:32Z jeresig $ + */ + +(function($) { + +// Tests for equality any JavaScript type and structure without unexpected results. +// Discussions and reference: http://philrathe.com/articles/equiv +// Test suites: http://philrathe.com/tests/equiv +// Author: Philippe Rathé +var equiv = function () { + + var innerEquiv; // the real equiv function + var callers = []; // stack to decide between skip/abort functions + + // Determine what is o. + function hoozit(o) { + if (typeof o === "string") { + return "string"; + + } else if (typeof o === "boolean") { + return "boolean"; + + } else if (typeof o === "number") { + + if (isNaN(o)) { + return "nan"; + } else { + return "number"; + } + + } else if (typeof o === "undefined") { + return "undefined"; + + // consider: typeof null === object + } else if (o === null) { + return "null"; + + // consider: typeof [] === object + } else if (o instanceof Array) { + return "array"; + + // consider: typeof new Date() === object + } else if (o instanceof Date) { + return "date"; + + // consider: /./ instanceof Object; + // /./ instanceof RegExp; + // typeof /./ === "function"; // => false in IE and Opera, + // true in FF and Safari + } else if (o instanceof RegExp) { + return "regexp"; + + } else if (typeof o === "object") { + return "object"; + + } else if (o instanceof Function) { + return "function"; + } + } + + // Call the o related callback with the given arguments. + function bindCallbacks(o, callbacks, args) { + var prop = hoozit(o); + if (prop) { + if (hoozit(callbacks[prop]) === "function") { + return callbacks[prop].apply(callbacks, args); + } else { + return callbacks[prop]; // or undefined + } + } + } + + var callbacks = function () { + + // for string, boolean, number and null + function useStrictEquality(b, a) { + return a === b; + } + + return { + "string": useStrictEquality, + "boolean": useStrictEquality, + "number": useStrictEquality, + "null": useStrictEquality, + "undefined": useStrictEquality, + + "nan": function (b) { + return isNaN(b); + }, + + "date": function (b, a) { + return hoozit(b) === "date" && a.valueOf() === b.valueOf(); + }, + + "regexp": function (b, a) { + return hoozit(b) === "regexp" && + a.source === b.source && // the regex itself + a.global === b.global && // and its modifers (gmi) ... + a.ignoreCase === b.ignoreCase && + a.multiline === b.multiline; + }, + + // - skip when the property is a method of an instance (OOP) + // - abort otherwise, + // initial === would have catch identical references anyway + "function": function () { + var caller = callers[callers.length - 1]; + return caller !== Object && + typeof caller !== "undefined"; + }, + + "array": function (b, a) { + var i; + var len; + + // b could be an object literal here + if ( ! (hoozit(b) === "array")) { + return false; + } + + len = a.length; + if (len !== b.length) { // safe and faster + return false; + } + for (i = 0; i < len; i++) { + if( ! innerEquiv(a[i], b[i])) { + return false; + } + } + return true; + }, + + "object": function (b, a) { + var i; + var eq = true; // unless we can proove it + var aProperties = [], bProperties = []; // collection of strings + + // comparing constructors is more strict than using instanceof + if ( a.constructor !== b.constructor) { + return false; + } + + // stack constructor before traversing properties + callers.push(a.constructor); + + for (i in a) { // be strict: don't ensures hasOwnProperty and go deep + + aProperties.push(i); // collect a's properties + + if ( ! innerEquiv(a[i], b[i])) { + eq = false; + } + } + + callers.pop(); // unstack, we are done + + for (i in b) { + bProperties.push(i); // collect b's properties + } + + // Ensures identical properties name + return eq && innerEquiv(aProperties.sort(), bProperties.sort()); + } + }; + }(); + + innerEquiv = function () { // can take multiple arguments + var args = Array.prototype.slice.apply(arguments); + if (args.length < 2) { + return true; // end transition + } + + return (function (a, b) { + if (a === b) { + return true; // catch the most you can + + } else if (typeof a !== typeof b || a === null || b === null || typeof a === "undefined" || typeof b === "undefined") { + return false; // don't lose time with error prone cases + + } else { + return bindCallbacks(a, callbacks, [b, a]); + } + + // apply transition with (1..n) arguments + })(args[0], args[1]) && arguments.callee.apply(this, args.splice(1, args.length -1)); + }; + + return innerEquiv; +}(); // equiv + +var GETParams = $.map( location.search.slice(1).split('&'), decodeURIComponent ), + ngindex = $.inArray("noglobals", GETParams), + noglobals = ngindex !== -1; + +if( noglobals ) + GETParams.splice( ngindex, 1 ); + +var config = { + stats: { + all: 0, + bad: 0 + }, + queue: [], + // block until document ready + blocking: true, + //restrict modules/tests by get parameters + filters: GETParams, + isLocal: !!(window.location.protocol == 'file:') +}; + +// public API as global methods +$.extend(window, { + test: test, + module: module, + expect: expect, + ok: ok, + equals: equals, + start: start, + stop: stop, + reset: reset, + isLocal: config.isLocal, + same: function(a, b, message) { + push(equiv(a, b), a, b, message); + }, + QUnit: { + equiv: equiv, + ok: ok, + done: function(failures, total){}, + log: function(result, message){} + }, + // legacy methods below + isSet: isSet, + isObj: isObj, + compare: function() { + throw "compare is deprecated - use same() instead"; + }, + compare2: function() { + throw "compare2 is deprecated - use same() instead"; + }, + serialArray: function() { + throw "serialArray is deprecated - use jsDump.parse() instead"; + }, + q: q, + t: t, + url: url, + triggerEvent: triggerEvent +}); + +$(window).load(function() { + $('#userAgent').html(navigator.userAgent); + var head = $('
').insertAfter("#userAgent"); + $('').attr("disabled", true).prependTo(head).click(function() { + $('li.pass')[this.checked ? 'hide' : 'show'](); + }); + $('').attr("disabled", true).appendTo(head).click(function() { + $("li.fail:contains('missing test - untested code is broken code')").parent('ol').parent('li.fail')[this.checked ? 'hide' : 'show'](); + }); + $("#filter-missing").after(''); + runTest(); +}); + +function synchronize(callback) { + config.queue.push(callback); + if(!config.blocking) { + process(); + } +} + +function process() { + while(config.queue.length && !config.blocking) { + config.queue.shift()(); + } +} + +function stop(timeout) { + config.blocking = true; + if (timeout) + config.timeout = setTimeout(function() { + QUnit.ok( false, "Test timed out" ); + start(); + }, timeout); +} +function start() { + // A slight delay, to avoid any current callbacks + setTimeout(function() { + if(config.timeout) + clearTimeout(config.timeout); + config.blocking = false; + process(); + }, 13); +} + +function validTest( name ) { + var i = config.filters.length, + run = false; + + if( !i ) + return true; + + while( i-- ){ + var filter = config.filters[i], + not = filter.charAt(0) == '!'; + if( not ) + filter = filter.slice(1); + if( name.indexOf(filter) != -1 ) + return !not; + if( not ) + run = true; + } + return run; +} + +function runTest() { + config.blocking = false; + var started = +new Date; + config.fixture = document.getElementById('main').innerHTML; + config.ajaxSettings = $.ajaxSettings; + synchronize(function() { + $('

').html(['Tests completed in ', + +new Date - started, ' milliseconds.
', + '', config.stats.bad, ' tests of ', config.stats.all, ' failed.'] + .join('')) + .appendTo("body"); + $("#banner").addClass(config.stats.bad ? "fail" : "pass"); + QUnit.done( config.stats.bad, config.stats.all ); + }); +} + +var pollution; + +function saveGlobal(){ + pollution = [ ]; + + if( noglobals ) + for( var key in window ) + pollution.push(key); +} +function checkPollution( name ){ + var old = pollution; + saveGlobal(); + + if( pollution.length > old.length ){ + ok( false, "Introduced global variable(s): " + diff(old, pollution).join(", ") ); + config.expected++; + } +} + +function diff( clean, dirty ){ + return $.grep( dirty, function(name){ + return $.inArray( name, clean ) == -1; + }); +} + +function test(name, callback) { + if(config.currentModule) + name = config.currentModule + " module: " + name; + var lifecycle = $.extend({ + setup: function() {}, + teardown: function() {} + }, config.moduleLifecycle); + + if ( !validTest(name) ) + return; + + synchronize(function() { + config.assertions = []; + config.expected = null; + try { + if( !pollution ) + saveGlobal(); + lifecycle.setup(); + } catch(e) { + QUnit.ok( false, "Setup failed on " + name + ": " + e.message ); + } + }) + synchronize(function() { + try { + callback(); + } catch(e) { + if( typeof console != "undefined" && console.error && console.warn ) { + console.error("Test " + name + " died, exception and test follows"); + console.error(e); + console.warn(callback.toString()); + } + QUnit.ok( false, "Died on test #" + (config.assertions.length + 1) + ": " + e.message ); + // else next test will carry the responsibility + saveGlobal(); + } + }); + synchronize(function() { + try { + checkPollution(); + lifecycle.teardown(); + } catch(e) { + QUnit.ok( false, "Teardown failed on " + name + ": " + e.message ); + } + }) + synchronize(function() { + try { + reset(); + } catch(e) { + if( typeof console != "undefined" && console.error && console.warn ) { + console.error("reset() failed, following Test " + name + ", exception and reset fn follows"); + console.error(e); + console.warn(reset.toString()); + } + } + + if(config.expected && config.expected != config.assertions.length) { + QUnit.ok( false, "Expected " + config.expected + " assertions, but " + config.assertions.length + " were run" ); + } + + var good = 0, bad = 0; + var ol = $("

    ").hide(); + config.stats.all += config.assertions.length; + for ( var i = 0; i < config.assertions.length; i++ ) { + var assertion = config.assertions[i]; + $("
  1. ").addClass(assertion.result ? "pass" : "fail").text(assertion.message || "(no message)").appendTo(ol); + assertion.result ? good++ : bad++; + } + config.stats.bad += bad; + + var b = $("").html(name + " (" + bad + ", " + good + ", " + config.assertions.length + ")") + .click(function(){ + $(this).next().toggle(); + }) + .dblclick(function(event) { + var target = $(event.target).filter("strong").clone(); + if ( target.length ) { + target.children().remove(); + location.href = location.href.match(/^(.+?)(\?.*)?$/)[1] + "?" + encodeURIComponent($.trim(target.text())); + } + }); + + $("
  2. ").addClass(bad ? "fail" : "pass").append(b).append(ol).appendTo("#tests"); + + if(bad) { + $("#filter-pass").attr("disabled", null); + $("#filter-missing").attr("disabled", null); + } + }); +} + +// call on start of module test to prepend name to all tests +function module(name, lifecycle) { + config.currentModule = name; + config.moduleLifecycle = lifecycle; +} + +/** + * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through. + */ +function expect(asserts) { + config.expected = asserts; +} + +/** + * Resets the test setup. Useful for tests that modify the DOM. + */ +function reset() { + $("#main").html( config.fixture ); + $.event.global = {}; + $.ajaxSettings = $.extend({}, config.ajaxSettings); +} + +/** + * Asserts true. + * @example ok( $("a").size() > 5, "There must be at least 5 anchors" ); + */ +function ok(a, msg) { + QUnit.log(a, msg); + + config.assertions.push({ + result: !!a, + message: msg + }); +} + +/** + * Asserts that two arrays are the same + */ +function isSet(a, b, msg) { + function serialArray( a ) { + var r = []; + + if ( a && a.length ) + for ( var i = 0; i < a.length; i++ ) { + var str = a[i].nodeName; + if ( str ) { + str = str.toLowerCase(); + if ( a[i].id ) + str += "#" + a[i].id; + } else + str = a[i]; + r.push( str ); + } + + return "[ " + r.join(", ") + " ]"; + } + var ret = true; + if ( a && b && a.length != undefined && a.length == b.length ) { + for ( var i = 0; i < a.length; i++ ) + if ( a[i] != b[i] ) + ret = false; + } else + ret = false; + QUnit.ok( ret, !ret ? (msg + " expected: " + serialArray(b) + " result: " + serialArray(a)) : msg ); +} + +/** + * Asserts that two objects are equivalent + */ +function isObj(a, b, msg) { + var ret = true; + + if ( a && b ) { + for ( var i in a ) + if ( a[i] != b[i] ) + ret = false; + + for ( i in b ) + if ( a[i] != b[i] ) + ret = false; + } else + ret = false; + + QUnit.ok( ret, msg ); +} + +/** + * Returns an array of elements with the given IDs, eg. + * @example q("main", "foo", "bar") + * @result [
    , , ] + */ +function q() { + var r = []; + for ( var i = 0; i < arguments.length; i++ ) + r.push( document.getElementById( arguments[i] ) ); + return r; +} + +/** + * Asserts that a select matches the given IDs + * @example t("Check for something", "//[a]", ["foo", "baar"]); + * @result returns true if "//[a]" return two elements with the IDs 'foo' and 'baar' + */ +function t(a,b,c) { + var f = $(b); + var s = ""; + for ( var i = 0; i < f.length; i++ ) + s += (s && ",") + '"' + f[i].id + '"'; + isSet(f, q.apply(q,c), a + " (" + b + ")"); +} + +/** + * Add random number to url to stop IE from caching + * + * @example url("data/test.html") + * @result "data/test.html?10538358428943" + * + * @example url("data/test.php?foo=bar") + * @result "data/test.php?foo=bar&10538358345554" + */ +function url(value) { + return value + (/\?/.test(value) ? "&" : "?") + new Date().getTime() + "" + parseInt(Math.random()*100000); +} + +/** + * Checks that the first two arguments are equal, with an optional message. + * Prints out both actual and expected values. + * + * Prefered to ok( actual == expected, message ) + * + * @example equals( $.format("Received {0} bytes.", 2), "Received 2 bytes." ); + * + * @param Object actual + * @param Object expected + * @param String message (optional) + */ +function equals(actual, expected, message) { + push(expected == actual, actual, expected, message); +} + +function push(result, actual, expected, message) { + message = message || (result ? "okay" : "failed"); + QUnit.ok( result, result ? message + ": " + expected : message + ", expected: " + jsDump.parse(expected) + " result: " + jsDump.parse(actual) ); +} + +/** + * Trigger an event on an element. + * + * @example triggerEvent( document.body, "click" ); + * + * @param DOMElement elem + * @param String type + */ +function triggerEvent( elem, type, event ) { + if ( $.browser.mozilla || $.browser.opera ) { + event = document.createEvent("MouseEvents"); + event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView, + 0, 0, 0, 0, 0, false, false, false, false, 0, null); + elem.dispatchEvent( event ); + } else if ( $.browser.msie ) { + elem.fireEvent("on"+type); + } +} + +})(jQuery); + +/** + * jsDump + * Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com + * Licensed under BSD (http://www.opensource.org/licenses/bsd-license.php) + * Date: 5/15/2008 + * @projectDescription Advanced and extensible data dumping for Javascript. + * @version 1.0.0 + * @author Ariel Flesler + * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html} + */ +(function(){ + function quote( str ){ + return '"' + str.toString().replace(/"/g, '\\"') + '"'; + }; + function literal( o ){ + return o + ''; + }; + function join( pre, arr, post ){ + var s = jsDump.separator(), + base = jsDump.indent(); + inner = jsDump.indent(1); + if( arr.join ) + arr = arr.join( ',' + s + inner ); + if( !arr ) + return pre + post; + return [ pre, inner + arr, base + post ].join(s); + }; + function array( arr ){ + var i = arr.length, ret = Array(i); + this.up(); + while( i-- ) + ret[i] = this.parse( arr[i] ); + this.down(); + return join( '[', ret, ']' ); + }; + + var reName = /^function (\w+)/; + + var jsDump = window.jsDump = { + parse:function( obj, type ){//type is used mostly internally, you can fix a (custom)type in advance + var parser = this.parsers[ type || this.typeOf(obj) ]; + type = typeof parser; + + return type == 'function' ? parser.call( this, obj ) : + type == 'string' ? parser : + this.parsers.error; + }, + typeOf:function( obj ){ + var type = typeof obj, + f = 'function';//we'll use it 3 times, save it + return type != 'object' && type != f ? type : + !obj ? 'null' : + obj.exec ? 'regexp' :// some browsers (FF) consider regexps functions + obj.getHours ? 'date' : + obj.scrollBy ? 'window' : + obj.nodeName == '#document' ? 'document' : + obj.nodeName ? 'node' : + obj.item ? 'nodelist' : // Safari reports nodelists as functions + obj.callee ? 'arguments' : + obj.call || obj.constructor != Array && //an array would also fall on this hack + (obj+'').indexOf(f) != -1 ? f : //IE reports functions like alert, as objects + 'length' in obj ? 'array' : + type; + }, + separator:function(){ + return this.multiline ? this.HTML ? '
    ' : '\n' : this.HTML ? ' ' : ' '; + }, + indent:function( extra ){// extra can be a number, shortcut for increasing-calling-decreasing + if( !this.multiline ) + return ''; + var chr = this.indentChar; + if( this.HTML ) + chr = chr.replace(/\t/g,' ').replace(/ /g,' '); + return Array( this._depth_ + (extra||0) ).join(chr); + }, + up:function( a ){ + this._depth_ += a || 1; + }, + down:function( a ){ + this._depth_ -= a || 1; + }, + setParser:function( name, parser ){ + this.parsers[name] = parser; + }, + // The next 3 are exposed so you can use them + quote:quote, + literal:literal, + join:join, + // + _depth_: 1, + // This is the list of parsers, to modify them, use jsDump.setParser + parsers:{ + window: '[Window]', + document: '[Document]', + error:'[ERROR]', //when no parser is found, shouldn't happen + unknown: '[Unknown]', + 'null':'null', + undefined:'undefined', + 'function':function( fn ){ + var ret = 'function', + name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE + if( name ) + ret += ' ' + name; + ret += '('; + + ret = [ ret, this.parse( fn, 'functionArgs' ), '){'].join(''); + return join( ret, this.parse(fn,'functionCode'), '}' ); + }, + array: array, + nodelist: array, + arguments: array, + object:function( map ){ + var ret = [ ]; + this.up(); + for( var key in map ) + ret.push( this.parse(key,'key') + ': ' + this.parse(map[key]) ); + this.down(); + return join( '{', ret, '}' ); + }, + node:function( node ){ + var open = this.HTML ? '<' : '<', + close = this.HTML ? '>' : '>'; + + var tag = node.nodeName.toLowerCase(), + ret = open + tag; + + for( var a in this.DOMAttrs ){ + var val = node[this.DOMAttrs[a]]; + if( val ) + ret += ' ' + a + '=' + this.parse( val, 'attribute' ); + } + return ret + close + open + '/' + tag + close; + }, + functionArgs:function( fn ){//function calls it internally, it's the arguments part of the function + var l = fn.length; + if( !l ) return ''; + + var args = Array(l); + while( l-- ) + args[l] = String.fromCharCode(97+l);//97 is 'a' + return ' ' + args.join(', ') + ' '; + }, + key:quote, //object calls it internally, the key part of an item in a map + functionCode:'[code]', //function calls it internally, it's the content of the function + attribute:quote, //node calls it internally, it's an html attribute value + string:quote, + date:quote, + regexp:literal, //regex + number:literal, + 'boolean':literal + }, + DOMAttrs:{//attributes to dump from nodes, name=>realName + id:'id', + name:'name', + 'class':'className' + }, + HTML:false,//if true, entities are escaped ( <, >, \t, space and \n ) + indentChar:' ',//indentation unit + multiline:true //if true, items in a collection, are separated by a \n, else just a space. + }; + +})(); diff --git a/js2/mwEmbed/jquery/jquery.ui/external/qunit/testsuite.css b/js2/mwEmbed/jquery/jquery.ui/external/qunit/testsuite.css new file mode 100644 index 0000000000..dbfc43aee4 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/external/qunit/testsuite.css @@ -0,0 +1,120 @@ +body, div, h1 { font-family: 'trebuchet ms', verdana, arial; margin: 0; padding: 0 } +body {font-size: 10pt; } +h1 { padding: 15px; font-size: large; background-color: #06b; color: white; } +h1 a { color: white; } +h2 { padding: 10px; background-color: #eee; color: black; margin: 0; font-size: small; font-weight: normal } + +.pass { color: green; } +.fail { color: red; } +p.result { margin-left: 1em; } + +#banner { height: 2em; border-bottom: 1px solid white; } +h2.pass { background-color: green; } +h2.fail { background-color: red; } + +div.testrunner-toolbar { background: #eee; border-top: 1px solid black; padding: 10px; } + +ol#tests > li > strong { cursor:pointer; } + +div#fx-tests h4 { + background: red; +} + +div#fx-tests h4.pass { + background: green; +} + +div#fx-tests div.box { + background: red url(data/cow.jpg) no-repeat; + overflow: hidden; + border: 2px solid #000; +} + +div#fx-tests div.overflow { + overflow: visible; +} + +div.inline { + display: inline; +} + +div.autoheight { + height: auto; +} + +div.autowidth { + width: auto; +} + +div.autoopacity { + opacity: auto; +} + +div.largewidth { + width: 100px; +} + +div.largeheight { + height: 100px; +} + +div.largeopacity { + filter: progid:DXImageTransform.Microsoft.Alpha(opacity=100); +} + +div.medwidth { + width: 50px; +} + +div.medheight { + height: 50px; +} + +div.medopacity { + opacity: 0.5; + filter: progid:DXImageTransform.Microsoft.Alpha(opacity=50); +} + +div.nowidth { + width: 0px; +} + +div.noheight { + height: 0px; +} + +div.noopacity { + opacity: 0; + filter: progid:DXImageTransform.Microsoft.Alpha(opacity=0); +} + +div.hidden { + display: none; +} + +div#fx-tests div.widewidth { + background-repeat: repeat-x; +} + +div#fx-tests div.wideheight { + background-repeat: repeat-y; +} + +div#fx-tests div.widewidth.wideheight { + background-repeat: repeat; +} + +div#fx-tests div.noback { + background-image: none; +} + +div.chain, div.chain div { width: 100px; height: 20px; position: relative; float: left; } +div.chain div { position: absolute; top: 0px; left: 0px; } + +div.chain.test { background: red; } +div.chain.test div { background: green; } + +div.chain.out { background: green; } +div.chain.out div { background: red; display: none; } + +div#show-tests * { display: none; } diff --git a/js2/mwEmbed/jquery/jquery.ui/external/simulate/jquery.simulate.js b/js2/mwEmbed/jquery/jquery.ui/external/simulate/jquery.simulate.js new file mode 100644 index 0000000000..d52140bb86 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/external/simulate/jquery.simulate.js @@ -0,0 +1,152 @@ +/* + * jquery.simulate - simulate browser mouse and keyboard events + * + * Copyright (c) 2009 Eduardo Lundgren (eduardolundgren@gmail.com) + * and Richard D. Worth (rdworth@gmail.com) + * + * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) + * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses. + * + */ + +;(function($) { + +$.fn.extend({ + simulate: function(type, options) { + return this.each(function() { + var opt = $.extend({}, $.simulate.defaults, options || {}); + new $.simulate(this, type, opt); + }); + } +}); + +$.simulate = function(el, type, options) { + this.target = el; + this.options = options; + + if (/^drag$/.test(type)) { + this[type].apply(this, [this.target, options]); + } else { + this.simulateEvent(el, type, options); + } +} + +$.extend($.simulate.prototype, { + simulateEvent: function(el, type, options) { + var evt = this.createEvent(type, options); + this.dispatchEvent(el, type, evt, options); + return evt; + }, + createEvent: function(type, options) { + if (/^mouse(over|out|down|up|move)|(dbl)?click$/.test(type)) { + return this.mouseEvent(type, options); + } else if (/^key(up|down|press)$/.test(type)) { + return this.keyboardEvent(type, options); + } + }, + mouseEvent: function(type, options) { + var evt; + var e = $.extend({ + bubbles: true, cancelable: (type != "mousemove"), view: window, detail: 0, + screenX: 0, screenY: 0, clientX: 0, clientY: 0, + ctrlKey: false, altKey: false, shiftKey: false, metaKey: false, + button: 0, relatedTarget: undefined + }, options); + + var relatedTarget = $(e.relatedTarget)[0]; + + if ($.isFunction(document.createEvent)) { + evt = document.createEvent("MouseEvents"); + evt.initMouseEvent(type, e.bubbles, e.cancelable, e.view, e.detail, + e.screenX, e.screenY, e.clientX, e.clientY, + e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, + e.button, e.relatedTarget || document.body.parentNode); + } else if (document.createEventObject) { + evt = document.createEventObject(); + $.extend(evt, e); + evt.button = { 0:1, 1:4, 2:2 }[evt.button] || evt.button; + } + return evt; + }, + keyboardEvent: function(type, options) { + var evt; + + var e = $.extend({ bubbles: true, cancelable: true, view: window, + ctrlKey: false, altKey: false, shiftKey: false, metaKey: false, + keyCode: 0, charCode: 0 + }, options); + + if ($.isFunction(document.createEvent)) { + try { + evt = document.createEvent("KeyEvents"); + evt.initKeyEvent(type, e.bubbles, e.cancelable, e.view, + e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, + e.keyCode, e.charCode); + } catch(err) { + evt = document.createEvent("Events"); + evt.initEvent(type, e.bubbles, e.cancelable); + $.extend(evt, { view: e.view, + ctrlKey: e.ctrlKey, altKey: e.altKey, shiftKey: e.shiftKey, metaKey: e.metaKey, + keyCode: e.keyCode, charCode: e.charCode + }); + } + } else if (document.createEventObject) { + evt = document.createEventObject(); + $.extend(evt, e); + } + if ($.browser.msie || $.browser.opera) { + evt.keyCode = (e.charCode > 0) ? e.charCode : e.keyCode; + evt.charCode = undefined; + } + return evt; + }, + + dispatchEvent: function(el, type, evt) { + if (el.dispatchEvent) { + el.dispatchEvent(evt); + } else if (el.fireEvent) { + el.fireEvent('on' + type, evt); + } + return evt; + }, + + drag: function(el) { + var self = this, center = this.findCenter(this.target), + options = this.options, x = Math.floor(center.x), y = Math.floor(center.y), + dx = options.dx || 0, dy = options.dy || 0, target = this.target; + var coord = { clientX: x, clientY: y }; + this.simulateEvent(target, "mousedown", coord); + coord = { clientX: x + 1, clientY: y + 1 }; + this.simulateEvent(document, "mousemove", coord); + coord = { clientX: x + dx, clientY: y + dy }; + this.simulateEvent(document, "mousemove", coord); + this.simulateEvent(document, "mousemove", coord); + this.simulateEvent(target, "mouseup", coord); + }, + findCenter: function(el) { + var el = $(this.target), o = el.offset(); + return { + x: o.left + el.outerWidth() / 2, + y: o.top + el.outerHeight() / 2 + }; + } +}); + +$.extend($.simulate, { + defaults: { + speed: 'sync' + }, + VK_TAB: 9, + VK_ENTER: 13, + VK_ESC: 27, + VK_PGUP: 33, + VK_PGDN: 34, + VK_END: 35, + VK_HOME: 36, + VK_LEFT: 37, + VK_UP: 38, + VK_RIGHT: 39, + VK_DOWN: 40 +}); + +})(jQuery); diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-bg_diagonals-thick_20_666666_40x40.png b/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-bg_diagonals-thick_20_666666_40x40.png new file mode 100644 index 0000000000..64ece5707d Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-bg_diagonals-thick_20_666666_40x40.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-bg_flat_0_aaaaaa_40x100.png b/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-bg_flat_0_aaaaaa_40x100.png new file mode 100644 index 0000000000..5b5dab2ab7 Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-bg_flat_0_aaaaaa_40x100.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-bg_glass_55_fbf9ee_1x400.png b/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-bg_glass_55_fbf9ee_1x400.png new file mode 100644 index 0000000000..ad3d6346e0 Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-bg_glass_55_fbf9ee_1x400.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-bg_glass_65_ffffff_1x400.png b/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-bg_glass_65_ffffff_1x400.png new file mode 100644 index 0000000000..42ccba269b Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-bg_glass_65_ffffff_1x400.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-bg_glass_75_dadada_1x400.png b/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-bg_glass_75_dadada_1x400.png new file mode 100644 index 0000000000..5a46b47cb1 Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-bg_glass_75_dadada_1x400.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-bg_glass_75_e6e6e6_1x400.png b/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-bg_glass_75_e6e6e6_1x400.png new file mode 100644 index 0000000000..86c2baa655 Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-bg_glass_75_e6e6e6_1x400.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-bg_glass_75_ffffff_1x400.png b/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-bg_glass_75_ffffff_1x400.png new file mode 100644 index 0000000000..e65ca1297c Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-bg_glass_75_ffffff_1x400.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-bg_highlight-soft_75_cccccc_1x100.png b/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-bg_highlight-soft_75_cccccc_1x100.png new file mode 100644 index 0000000000..7c9fa6c6ed Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-bg_highlight-soft_75_cccccc_1x100.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-bg_inset-soft_95_fef1ec_1x100.png b/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-bg_inset-soft_95_fef1ec_1x100.png new file mode 100644 index 0000000000..0e05810fff Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-bg_inset-soft_95_fef1ec_1x100.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-icons_222222_256x240.png b/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-icons_222222_256x240.png new file mode 100644 index 0000000000..67560da9be Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-icons_222222_256x240.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-icons_2e83ff_256x240.png b/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-icons_2e83ff_256x240.png new file mode 100644 index 0000000000..b2c9052dea Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-icons_2e83ff_256x240.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-icons_454545_256x240.png b/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-icons_454545_256x240.png new file mode 100644 index 0000000000..0cd64a21a9 Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-icons_454545_256x240.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-icons_888888_256x240.png b/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-icons_888888_256x240.png new file mode 100644 index 0000000000..2e5180e473 Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-icons_888888_256x240.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-icons_cd0a0a_256x240.png b/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-icons_cd0a0a_256x240.png new file mode 100644 index 0000000000..2db88b796a Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/base/images/ui-icons_cd0a0a_256x240.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/base/jquery-ui-1.7.1.custom.css b/js2/mwEmbed/jquery/jquery.ui/themes/base/jquery-ui-1.7.1.custom.css new file mode 100644 index 0000000000..118def2207 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/themes/base/jquery-ui-1.7.1.custom.css @@ -0,0 +1,287 @@ + +/* +* jQuery UI CSS Framework +* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) +* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses. +* To view and modify this theme, visit http://jqueryui.com/themeroller/ +*/ + +/*** Begin CORE ***/ + +/* Layout helpers +----------------------------------*/ +.ui-helper-hidden { display: none; } +.ui-helper-hidden-accessible { position: absolute; left: -99999999px; } +.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } +.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } +.ui-helper-clearfix { display: inline-block; } +/* required comment for clearfix to work in Opera \*/ +* html .ui-helper-clearfix { height:1%; } +.ui-helper-clearfix { display:block; } +/* end clearfix */ +.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }*/ + + +/* Interaction Cues +----------------------------------*/ +.ui-state-disabled { cursor: default !important; } + + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { display: block; text-indents: -99999px; overflow: hidden; background-repeat: no-repeat; } + + +/* Misc visuals +----------------------------------*/ + +/* Overlays */ +.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } + +/*** End Core ***/ + + +/*** Begin THEME ***/ + +/* Component containers +----------------------------------*/ +.ui-widget { font-family: Arial,sans-serif/*{ffDefault}*/; font-size: 11px/*{fsDefault}*/; } +.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Arial,sans-serif/*{ffDefault}*/; font-size: 11px; } +.ui-widget-content { border: none/*{borderColorContent}*/; background: #ffffff/*{bgColorContent}*/ url(images/ui-bg_flat_75_ffffff_40x100.png) 50%/*{bgContentXPos}*/ 50%/*{bgContentYPos}*/ repeat-x/*{bgContentRepeat}*//*{bgContentRepeat}*/; color: #A9A9A9/*{fcContent}*/; } +.ui-widget-content a { color: #A9A9A9/*{fcContent}*/; } +.ui-widget-header { border: none/*{borderColorHeader}*/; background: #cccccc/*{bgColorHeader}*/ url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50%/*{bgHeaderXPos}*/ 50%/*{bgHeaderYPos}*/ repeat-x/*{bgHeaderRepeat}*//*{bgHeaderRepeat}*/; color: #565656/*{fcHeader}*/; font-weight: bold; } +.ui-widget-header a { color: #000/*{fcHeader}*/; } + + + +/* Interaction states +----------------------------------*/ +.ui-state-default, .ui-widget-content .ui-state-default { border: none/*{borderColorDefault}*/; background: none/*{bgColorDefault}*/ /*{bgDefaultXPos}*/ /*{bgDefaultYPos}*/ /*{bgDefaultRepeat}*//*{bgDefaultRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #333/*{fcDefault}*/; outline: none; } +.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #000/*{fcDefault}*/; text-decoration: none; outline: none; } +.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus { border: none/*{borderColorHover}*/; background: none/*{bgColorHover}*/ none /*{bgHoverXPos}*/ /*{bgHoverYPos}*/ /*{bgHoverRepeat}*//*{bgHoverRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #222/*{fcHover}*/; outline: none; } +.ui-state-hover a, .ui-state-hover a:hover { color: #000/*{fcHover}*/; text-decoration: none; outline: none; } +.ui-state-active, .ui-widget-content .ui-state-active { border: 1px solid #ccc/*{borderColorActive}*/; background: none/*{bgColorActive}*/ /*{bgActiveXPos}*/ 50%/*{bgActiveYPos}*/ repeat-x/*{bgActiveRepeat}*//*{bgActiveRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcActive}*/; outline: none; } +.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121/*{fcActive}*/; outline: none; text-decoration: none; } + +/* Interaction Cues +----------------------------------*/ +.ui-state-highlight, .ui-widget-content .ui-state-highlight {border: 1px solid #fcefa1/*{borderColorHighlight}*/; background: #fbf9ee/*{bgColorHighlight}*/ url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50%/*{bgHighlightXPos}*/ 50%/*{bgHighlightYPos}*/ repeat-x/*{bgHighlightRepeat}*//*{bgHighlightRepeat}*/; color: #363636/*{fcHighlight}*/; } +.ui-state-highlight a, .ui-widget-content .ui-state-highlight a { color: #363636/*{fcHighlight}*/; } +.ui-state-error, .ui-widget-content .ui-state-error {border: 1px solid #cd0a0a/*{borderColorError}*/; background: #fef1ec/*{bgColorError}*/ url(images/ui-bg_glass_95_fef1ec_1x400.png) 50%/*{bgErrorXPos}*/ 50%/*{bgErrorYPos}*/ repeat-x/*{bgErrorRepeat}*//*{bgErrorRepeat}*/; color: #cd0a0a/*{fcError}*/; } +.ui-state-error a, .ui-widget-content .ui-state-error a { color: #cd0a0a/*{fcError}*/; } +.ui-state-error-text, .ui-widget-content .ui-state-error-text { color: #cd0a0a/*{fcError}*/; } +.ui-state-disabled, .ui-widget-content .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } +.ui-priority-primary, .ui-widget-content .ui-priority-primary { font-weight: bold; } +.ui-priority-secondary, .ui-widget-content .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png)/*{iconsContent}*/; } +.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png)/*{iconsContent}*/; } +.ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png)/*{iconsHeader}*/; } +.ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png)/*{iconsDefault}*/; } +.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png)/*{iconsHover}*/; } +.ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png)/*{iconsActive}*/; } +.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png)/*{iconsHighlight}*/; } +.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png)/*{iconsError}*/; } + +/* positioning */ +.ui-icon-carat-1-n { background-position: 0 0; } +.ui-icon-carat-1-ne { background-position: -16px 0; } +.ui-icon-carat-1-e { background-position: -32px 0; } +.ui-icon-carat-1-se { background-position: -48px 0; } +.ui-icon-carat-1-s { background-position: -64px 0; } +.ui-icon-carat-1-sw { background-position: -80px 0; } +.ui-icon-carat-1-w { background-position: -96px 0; } +.ui-icon-carat-1-nw { background-position: -112px 0; } +.ui-icon-carat-2-n-s { background-position: -128px 0; } +.ui-icon-carat-2-e-w { background-position: -144px 0; } +.ui-icon-triangle-1-n { background-position: 0 -16px; } +.ui-icon-triangle-1-ne { background-position: -16px -16px; } +.ui-icon-triangle-1-e { background-position: -32px -16px; } +.ui-icon-triangle-1-se { background-position: -48px -16px; } +.ui-icon-triangle-1-s { background-position: -64px -16px; } +.ui-icon-triangle-1-sw { background-position: -80px -16px; } +.ui-icon-triangle-1-w { background-position: -96px -16px; } +.ui-icon-triangle-1-nw { background-position: -112px -16px; } +.ui-icon-triangle-2-n-s { background-position: -128px -16px; } +.ui-icon-triangle-2-e-w { background-position: -144px -16px; } +.ui-icon-arrow-1-n { background-position: 0 -32px; } +.ui-icon-arrow-1-ne { background-position: -16px -32px; } +.ui-icon-arrow-1-e { background-position: -32px -32px; } +.ui-icon-arrow-1-se { background-position: -48px -32px; } +.ui-icon-arrow-1-s { background-position: -64px -32px; } +.ui-icon-arrow-1-sw { background-position: -80px -32px; } +.ui-icon-arrow-1-w { background-position: -96px -32px; } +.ui-icon-arrow-1-nw { background-position: -112px -32px; } +.ui-icon-arrow-2-n-s { background-position: -128px -32px; } +.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } +.ui-icon-arrow-2-e-w { background-position: -160px -32px; } +.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } +.ui-icon-arrowstop-1-n { background-position: -192px -32px; } +.ui-icon-arrowstop-1-e { background-position: -208px -32px; } +.ui-icon-arrowstop-1-s { background-position: -224px -32px; } +.ui-icon-arrowstop-1-w { background-position: -240px -32px; } +.ui-icon-arrowthick-1-n { background-position: 0 -48px; } +.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } +.ui-icon-arrowthick-1-e { background-position: -32px -48px; } +.ui-icon-arrowthick-1-se { background-position: -48px -48px; } +.ui-icon-arrowthick-1-s { background-position: -64px -48px; } +.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } +.ui-icon-arrowthick-1-w { background-position: -96px -48px; } +.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } +.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } +.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } +.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } +.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } +.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } +.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } +.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } +.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } +.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } +.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } +.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } +.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } +.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } +.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } +.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } +.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } +.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } +.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } +.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } +.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } +.ui-icon-arrow-4 { background-position: 0 -80px; } +.ui-icon-arrow-4-diag { background-position: -16px -80px; } +.ui-icon-extlink { background-position: -32px -80px; } +.ui-icon-newwin { background-position: -48px -80px; } +.ui-icon-refresh { background-position: -64px -80px; } +.ui-icon-shuffle { background-position: -80px -80px; } +.ui-icon-transfer-e-w { background-position: -96px -80px; } +.ui-icon-transferthick-e-w { background-position: -112px -80px; } +.ui-icon-folder-collapsed { background-position: 0 -96px; } +.ui-icon-folder-open { background-position: -16px -96px; } +.ui-icon-document { background-position: -32px -96px; } +.ui-icon-document-b { background-position: -48px -96px; } +.ui-icon-note { background-position: -64px -96px; } +.ui-icon-mail-closed { background-position: -80px -96px; } +.ui-icon-mail-open { background-position: -96px -96px; } +.ui-icon-suitcase { background-position: -112px -96px; } +.ui-icon-comment { background-position: -128px -96px; } +.ui-icon-person { background-position: -144px -96px; } +.ui-icon-print { background-position: -160px -96px; } +.ui-icon-trash { background-position: -176px -96px; } +.ui-icon-locked { background-position: -192px -96px; } +.ui-icon-unlocked { background-position: -208px -96px; } +.ui-icon-bookmark { background-position: -224px -96px; } +.ui-icon-tag { background-position: -240px -96px; } +.ui-icon-home { background-position: 0 -112px; } +.ui-icon-flag { background-position: -16px -112px; } +.ui-icon-calendar { background-position: -32px -112px; } +.ui-icon-cart { background-position: -48px -112px; } +.ui-icon-pencil { background-position: -64px -112px; } +.ui-icon-clock { background-position: -80px -112px; } +.ui-icon-disk { background-position: -96px -112px; } +.ui-icon-calculator { background-position: -112px -112px; } +.ui-icon-zoomin { background-position: -128px -112px; } +.ui-icon-zoomout { background-position: -144px -112px; } +.ui-icon-search { background-position: -160px -112px; } +.ui-icon-wrench { background-position: -176px -112px; } +.ui-icon-gear { background-position: -192px -112px; } +.ui-icon-heart { background-position: -208px -112px; } +.ui-icon-star { background-position: -224px -112px; } +.ui-icon-link { background-position: -240px -112px; } +.ui-icon-cancel { background-position: 0 -128px; } +.ui-icon-plus { background-position: -16px -128px; } +.ui-icon-plusthick { background-position: -32px -128px; } +.ui-icon-minus { background-position: -48px -128px; } +.ui-icon-minusthick { background-position: -64px -128px; } +.ui-icon-close { background-position: -80px -128px; } +.ui-icon-closethick { background-position: -96px -128px; } +.ui-icon-key { background-position: -112px -128px; } +.ui-icon-lightbulb { background-position: -128px -128px; } +.ui-icon-scissors { background-position: -144px -128px; } +.ui-icon-clipboard { background-position: -160px -128px; } +.ui-icon-copy { background-position: -176px -128px; } +.ui-icon-contact { background-position: -192px -128px; } +.ui-icon-image { background-position: -208px -128px; } +.ui-icon-video { background-position: -224px -128px; } +.ui-icon-script { background-position: -240px -128px; } +.ui-icon-alert { background-position: 0 -144px; } +.ui-icon-info { background-position: -16px -144px; } +.ui-icon-notice { background-position: -32px -144px; } +.ui-icon-help { background-position: -48px -144px; } +.ui-icon-check { background-position: -64px -144px; } +.ui-icon-bullet { background-position: -80px -144px; } +.ui-icon-radio-off { background-position: -96px -144px; } +.ui-icon-radio-on { background-position: -112px -144px; } +.ui-icon-pin-w { background-position: -128px -144px; } +.ui-icon-pin-s { background-position: -144px -144px; } +.ui-icon-play { background-position: 0 -160px; } +.ui-icon-pause { background-position: -16px -160px; } +.ui-icon-seek-next { background-position: -32px -160px; } +.ui-icon-seek-prev { background-position: -48px -160px; } +.ui-icon-seek-end { background-position: -64px -160px; } +.ui-icon-seek-first { background-position: -80px -160px; } +.ui-icon-stop { background-position: -96px -160px; } +.ui-icon-eject { background-position: -112px -160px; } +.ui-icon-volume-off { background-position: -128px -160px; } +.ui-icon-volume-on { background-position: -144px -160px; } +.ui-icon-power { background-position: 0 -176px; } +.ui-icon-signal-diag { background-position: -16px -176px; } +.ui-icon-signal { background-position: -32px -176px; } +.ui-icon-battery-0 { background-position: -48px -176px; } +.ui-icon-battery-1 { background-position: -64px -176px; } +.ui-icon-battery-2 { background-position: -80px -176px; } +.ui-icon-battery-3 { background-position: -96px -176px; } +.ui-icon-circle-plus { background-position: 0 -192px; } +.ui-icon-circle-minus { background-position: -16px -192px; } +.ui-icon-circle-close { background-position: -32px -192px; } +.ui-icon-circle-triangle-e { background-position: -48px -192px; } +.ui-icon-circle-triangle-s { background-position: -64px -192px; } +.ui-icon-circle-triangle-w { background-position: -80px -192px; } +.ui-icon-circle-triangle-n { background-position: -96px -192px; } +.ui-icon-circle-arrow-e { background-position: -112px -192px; } +.ui-icon-circle-arrow-s { background-position: -128px -192px; } +.ui-icon-circle-arrow-w { background-position: -144px -192px; } +.ui-icon-circle-arrow-n { background-position: -160px -192px; } +.ui-icon-circle-zoomin { background-position: -176px -192px; } +.ui-icon-circle-zoomout { background-position: -192px -192px; } +.ui-icon-circle-check { background-position: -208px -192px; } +.ui-icon-circlesmall-plus { background-position: 0 -208px; } +.ui-icon-circlesmall-minus { background-position: -16px -208px; } +.ui-icon-circlesmall-close { background-position: -32px -208px; } +.ui-icon-squaresmall-plus { background-position: -48px -208px; } +.ui-icon-squaresmall-minus { background-position: -64px -208px; } +.ui-icon-squaresmall-close { background-position: -80px -208px; } +.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } +.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } +.ui-icon-grip-solid-vertical { background-position: -32px -224px; } +.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } +.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } +.ui-icon-grip-diagonal-se { background-position: -80px -224px; } + + +/* Misc visuals +----------------------------------*/ + +/* Corner radius */ +.ui-corner-tl { -moz-border-radius-topleft: 5px/*{cornerRadius}*/; -webkit-border-top-left-radius: 5px/*{cornerRadius}*/; } +.ui-corner-tr { -moz-border-radius-topright: 5px/*{cornerRadius}*/; -webkit-border-top-right-radius: 5px/*{cornerRadius}*/; } +.ui-corner-bl { -moz-border-radius-bottomleft: 5px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 5px/*{cornerRadius}*/; } +.ui-corner-br { -moz-border-radius-bottomright: 5px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 5px/*{cornerRadius}*/; } +.ui-corner-top { -moz-border-radius-topleft: 5px/*{cornerRadius}*/; -webkit-border-top-left-radius: 5px/*{cornerRadius}*/; -moz-border-radius-topright: 5px/*{cornerRadius}*/; -webkit-border-top-right-radius: 5px/*{cornerRadius}*/; } +.ui-corner-bottom { -moz-border-radius-bottomleft: 5px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 5px/*{cornerRadius}*/; -moz-border-radius-bottomright: 5px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 5px/*{cornerRadius}*/; } +.ui-corner-right { -moz-border-radius-topright: 5px/*{cornerRadius}*/; -webkit-border-top-right-radius: 5px/*{cornerRadius}*/; -moz-border-radius-bottomright: 5px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 5px/*{cornerRadius}*/; } +.ui-corner-left { -moz-border-radius-topleft: 5px/*{cornerRadius}*/; -webkit-border-top-left-radius: 5px/*{cornerRadius}*/; -moz-border-radius-bottomleft: 5px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 5px/*{cornerRadius}*/; } +.ui-corner-all { -moz-border-radius: 5px/*{cornerRadius}*/; -webkit-border-radius: 5px/*{cornerRadius}*/; } + +/* Overlays */ +.ui-widget-overlay { background: #aaaaaa/*{bgColorOverlay}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50%/*{bgOverlayXPos}*/ 50%/*{bgOverlayYPos}*/ repeat-x/*{bgOverlayRepeat}*//*{bgOverlayRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityOverlay}*/; } +.ui-widget-shadow { margin: -8px/*{offsetTopShadow}*/ 0 0 -8px/*{offsetLeftShadow}*/; padding: 8px/*{thicknessShadow}*/; background: #aaaaaa/*{bgColorShadow}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50%/*{bgShadowXPos}*/ 50%/*{bgShadowYPos}*/ repeat-x/*{bgShadowRepeat}*//*{bgShadowRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityShadow}*/; -moz-border-radius: 8px/*{cornerRadiusShadow}*/; -webkit-border-radius: 8px/*{cornerRadiusShadow}*/; } + + + diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/base/ui.accordion.css b/js2/mwEmbed/jquery/jquery.ui/themes/base/ui.accordion.css new file mode 100644 index 0000000000..ee1b1b640b --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/themes/base/ui.accordion.css @@ -0,0 +1,9 @@ +/* Accordion +----------------------------------*/ +.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; } +.ui-accordion .ui-accordion-li-fix { display: inline; } +.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; } +.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em 2.2em; } +.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; } +.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; } +.ui-accordion .ui-accordion-content-active { display: block; } \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/base/ui.all.css b/js2/mwEmbed/jquery/jquery.ui/themes/base/ui.all.css new file mode 100644 index 0000000000..543e4c3bc9 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/themes/base/ui.all.css @@ -0,0 +1,2 @@ +@import "ui.base.css"; +@import "ui.theme.css"; diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/base/ui.base.css b/js2/mwEmbed/jquery/jquery.ui/themes/base/ui.base.css new file mode 100644 index 0000000000..d716095081 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/themes/base/ui.base.css @@ -0,0 +1,8 @@ +@import url("ui.core.css"); +@import url("ui.resizable.css"); +@import url("ui.accordion.css"); +@import url("ui.dialog.css"); +@import url("ui.slider.css"); +@import url("ui.tabs.css"); +@import url("ui.datepicker.css"); +@import url("ui.progressbar.css"); \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/base/ui.core.css b/js2/mwEmbed/jquery/jquery.ui/themes/base/ui.core.css new file mode 100644 index 0000000000..c2f18f2c08 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/themes/base/ui.core.css @@ -0,0 +1,37 @@ +/* +* jQuery UI CSS Framework +* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) +* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses. +*/ + +/* Layout helpers +----------------------------------*/ +.ui-helper-hidden { display: none; } +.ui-helper-hidden-accessible { position: absolute; left: -99999999px; } +.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } +.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } +.ui-helper-clearfix { display: inline-block; } +/* required comment for clearfix to work in Opera \*/ +* html .ui-helper-clearfix { height:1%; } +.ui-helper-clearfix { display:block; } +/* end clearfix */ +.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } + + +/* Interaction Cues +----------------------------------*/ +.ui-state-disabled { cursor: default !important; } + + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } + + +/* Misc visuals +----------------------------------*/ + +/* Overlays */ +.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/base/ui.datepicker.css b/js2/mwEmbed/jquery/jquery.ui/themes/base/ui.datepicker.css new file mode 100644 index 0000000000..d18ee6396b --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/themes/base/ui.datepicker.css @@ -0,0 +1,62 @@ +/* Datepicker +----------------------------------*/ +.ui-datepicker { width: 17em; padding: .2em .2em 0; } +.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; } +.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; } +.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; } +.ui-datepicker .ui-datepicker-prev { left:2px; } +.ui-datepicker .ui-datepicker-next { right:2px; } +.ui-datepicker .ui-datepicker-prev-hover { left:1px; } +.ui-datepicker .ui-datepicker-next-hover { right:1px; } +.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; } +.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } +.ui-datepicker .ui-datepicker-title select { float:left; font-size:1em; margin:1px 0; } +.ui-datepicker select.ui-datepicker-month-year {width: 100%;} +.ui-datepicker select.ui-datepicker-month, +.ui-datepicker select.ui-datepicker-year { width: 49%;} +.ui-datepicker .ui-datepicker-title select.ui-datepicker-year { float: right; } +.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; } +.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; } +.ui-datepicker td { border: 0; padding: 1px; } +.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; } +.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; } +.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } +.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; } + +/* with multiple calendars */ +.ui-datepicker.ui-datepicker-multi { width:auto; } +.ui-datepicker-multi .ui-datepicker-group { float:left; } +.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } +.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } +.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } +.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } +.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } +.ui-datepicker-row-break { clear:both; width:100%; } + +/* RTL support */ +.ui-datepicker-rtl { direction: rtl; } +.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; } +.ui-datepicker-rtl .ui-datepicker-group { float:right; } +.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; } +.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; } + +/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */ +.ui-datepicker-cover { + display: none; /*sorry for IE5*/ + display/**/: block; /*sorry for IE5*/ + position: absolute; /*must have*/ + z-index: -1; /*must have*/ + filter: mask(); /*must have*/ + top: -4px; /*must have*/ + left: -4px; /*must have*/ + width: 200px; /*must have*/ + height: 200px; /*must have*/ +} \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/base/ui.dialog.css b/js2/mwEmbed/jquery/jquery.ui/themes/base/ui.dialog.css new file mode 100644 index 0000000000..2997595b7d --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/themes/base/ui.dialog.css @@ -0,0 +1,13 @@ +/* Dialog +----------------------------------*/ +.ui-dialog { position: relative; padding: .2em; width: 300px; } +.ui-dialog .ui-dialog-titlebar { padding: .5em .3em .3em 1em; position: relative; } +.ui-dialog .ui-dialog-title { float: left; margin: .1em 0 .2em; } +.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; } +.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; } +.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; } +.ui-dialog .ui-dialog-content { border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; } +.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; } +.ui-dialog .ui-dialog-buttonpane button { float: right; margin: .5em .4em .5em 0; cursor: pointer; padding: .2em .6em .3em .6em; line-height: 1.4em; width:auto; overflow:visible; } +.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; } +.ui-draggable .ui-dialog-titlebar { cursor: move; } diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/base/ui.progressbar.css b/js2/mwEmbed/jquery/jquery.ui/themes/base/ui.progressbar.css new file mode 100644 index 0000000000..bc0939ecfa --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/themes/base/ui.progressbar.css @@ -0,0 +1,4 @@ +/* Progressbar +----------------------------------*/ +.ui-progressbar { height:2em; text-align: left; } +.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; } \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/base/ui.resizable.css b/js2/mwEmbed/jquery/jquery.ui/themes/base/ui.resizable.css new file mode 100644 index 0000000000..44efeb2e86 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/themes/base/ui.resizable.css @@ -0,0 +1,13 @@ +/* Resizable +----------------------------------*/ +.ui-resizable { position: relative;} +.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;} +.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } +.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0px; } +.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0px; } +.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0px; height: 100%; } +.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0px; height: 100%; } +.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } +.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } +.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } +.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;} \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/base/ui.slider.css b/js2/mwEmbed/jquery/jquery.ui/themes/base/ui.slider.css new file mode 100644 index 0000000000..4c5621879e --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/themes/base/ui.slider.css @@ -0,0 +1,17 @@ +/* Slider +----------------------------------*/ +.ui-slider { position: relative; text-align: left; } +.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; } +.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; } + +.ui-slider-horizontal { height: .8em; } +.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; } +.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } +.ui-slider-horizontal .ui-slider-range-min { left: 0; } +.ui-slider-horizontal .ui-slider-range-max { right: 0; } + +.ui-slider-vertical { width: .8em; height: 100px; } +.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; } +.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; } +.ui-slider-vertical .ui-slider-range-min { bottom: 0; } +.ui-slider-vertical .ui-slider-range-max { top: 0; } \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/base/ui.tabs.css b/js2/mwEmbed/jquery/jquery.ui/themes/base/ui.tabs.css new file mode 100644 index 0000000000..3ca6b9a0a9 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/themes/base/ui.tabs.css @@ -0,0 +1,11 @@ +/* Tabs +----------------------------------*/ +.ui-tabs { padding: .2em; zoom: 1; } +.ui-tabs .ui-tabs-nav { list-style: none; position: relative; padding: .2em .2em 0; } +.ui-tabs .ui-tabs-nav li { position: relative; float: left; border-bottom-width: 0 !important; margin: 0 .2em -1px 0; padding: 0; } +.ui-tabs .ui-tabs-nav li a { float: left; text-decoration: none; padding: .5em 1em; } +.ui-tabs .ui-tabs-nav li.ui-tabs-selected { padding-bottom: 1px; border-bottom-width: 0; } +.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; } +.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ +.ui-tabs .ui-tabs-panel { padding: 1em 1.4em; display: block; border-width: 0; background: none; } +.ui-tabs .ui-tabs-hide { display: none !important; } diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/base/ui.theme.css b/js2/mwEmbed/jquery/jquery.ui/themes/base/ui.theme.css new file mode 100644 index 0000000000..014fcfc678 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/themes/base/ui.theme.css @@ -0,0 +1,243 @@ +/* +* jQuery UI CSS Framework +* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) +* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses. +* To view and modify this theme, visit http://jqueryui.com/themeroller/ +*/ + + +/* Component containers +----------------------------------*/ +.ui-widget { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1.1em/*{fsDefault}*/; } +.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1em; } +.ui-widget-content { border: 1px solid #aaaaaa/*{borderColorContent}*/; background: #ffffff/*{bgColorContent}*/ url(images/ui-bg_glass_75_ffffff_1x400.png)/*{bgImgUrlContent}*/ 0/*{bgContentXPos}*/ 0/*{bgContentYPos}*/ repeat-x/*{bgContentRepeat}*/; color: #222222/*{fcContent}*/; } +.ui-widget-content a { color: #222222/*{fcContent}*/; } +.ui-widget-header { border: 1px solid #aaaaaa/*{borderColorHeader}*/; background: #cccccc/*{bgColorHeader}*/ url(images/ui-bg_highlight-soft_75_cccccc_1x100.png)/*{bgImgUrlHeader}*/ 0/*{bgHeaderXPos}*/ 50%/*{bgHeaderYPos}*/ repeat-x/*{bgHeaderRepeat}*/; color: #222222/*{fcHeader}*/; font-weight: bold; } +.ui-widget-header a { color: #222222/*{fcHeader}*/; } + +/* Interaction states +----------------------------------*/ +.ui-state-default, .ui-widget-content .ui-state-default { border: 1px solid #d3d3d3/*{borderColorDefault}*/; background: #e6e6e6/*{bgColorDefault}*/ url(images/ui-bg_glass_75_e6e6e6_1x400.png)/*{bgImgUrlDefault}*/ 0/*{bgDefaultXPos}*/ 50%/*{bgDefaultYPos}*/ repeat-x/*{bgDefaultRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #555555/*{fcDefault}*/; outline: none; } +.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555/*{fcDefault}*/; text-decoration: none; outline: none; } +.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus { border: 1px solid #999999/*{borderColorHover}*/; background: #dadada/*{bgColorHover}*/ url(images/ui-bg_glass_75_dadada_1x400.png)/*{bgImgUrlHover}*/ 0/*{bgHoverXPos}*/ 50%/*{bgHoverYPos}*/ repeat-x/*{bgHoverRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcHover}*/; outline: none; } +.ui-state-hover a, .ui-state-hover a:hover { color: #212121/*{fcHover}*/; text-decoration: none; outline: none; } +.ui-state-active, .ui-widget-content .ui-state-active { border: 1px solid #aaaaaa/*{borderColorActive}*/; background: #ffffff/*{bgColorActive}*/ url(images/ui-bg_glass_65_ffffff_1x400.png)/*{bgImgUrlActive}*/ 0/*{bgActiveXPos}*/ 50%/*{bgActiveYPos}*/ repeat-x/*{bgActiveRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcActive}*/; outline: none; } +.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121/*{fcActive}*/; outline: none; text-decoration: none; } + +/* Interaction Cues +----------------------------------*/ +.ui-state-highlight, .ui-widget-content .ui-state-highlight {border: 1px solid #fcefa1/*{borderColorHighlight}*/; background: #fbf9ee/*{bgColorHighlight}*/ url(images/ui-bg_glass_55_fbf9ee_1x400.png)/*{bgImgUrlHighlight}*/ 0/*{bgHighlightXPos}*/ 50%/*{bgHighlightYPos}*/ repeat-x/*{bgHighlightRepeat}*/; color: #363636/*{fcHighlight}*/; } +.ui-state-highlight a, .ui-widget-content .ui-state-highlight a { color: #363636/*{fcHighlight}*/; } +.ui-state-error, .ui-widget-content .ui-state-error {border: 1px solid #cd0a0a/*{borderColorError}*/; background: #fef1ec/*{bgColorError}*/ url(images/ui-bg_inset-soft_95_fef1ec_1x100.png)/*{bgImgUrlError}*/ 0/*{bgErrorXPos}*/ 50%/*{bgErrorYPos}*/ repeat-x/*{bgErrorRepeat}*/; color: #cd0a0a/*{fcError}*/; } +.ui-state-error a, .ui-widget-content .ui-state-error a { color: #363636/*{fcError}*/; } +.ui-state-error-text, .ui-widget-content .ui-state-error-text { color: #cd0a0a/*{fcError}*/; } +.ui-state-disabled, .ui-widget-content .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } +.ui-priority-primary, .ui-widget-content .ui-priority-primary { font-weight: bold; } +.ui-priority-secondary, .ui-widget-content .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png)/*{iconsContent}*/; } +.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png)/*{iconsContent}*/; } +.ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png)/*{iconsHeader}*/; } +.ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png)/*{iconsDefault}*/; } +.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png)/*{iconsHover}*/; } +.ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png)/*{iconsActive}*/; } +.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png)/*{iconsHighlight}*/; } +.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png)/*{iconsError}*/; } + +/* positioning */ +.ui-icon-carat-1-n { background-position: 0 0; } +.ui-icon-carat-1-ne { background-position: -16px 0; } +.ui-icon-carat-1-e { background-position: -32px 0; } +.ui-icon-carat-1-se { background-position: -48px 0; } +.ui-icon-carat-1-s { background-position: -64px 0; } +.ui-icon-carat-1-sw { background-position: -80px 0; } +.ui-icon-carat-1-w { background-position: -96px 0; } +.ui-icon-carat-1-nw { background-position: -112px 0; } +.ui-icon-carat-2-n-s { background-position: -128px 0; } +.ui-icon-carat-2-e-w { background-position: -144px 0; } +.ui-icon-triangle-1-n { background-position: 0 -16px; } +.ui-icon-triangle-1-ne { background-position: -16px -16px; } +.ui-icon-triangle-1-e { background-position: -32px -16px; } +.ui-icon-triangle-1-se { background-position: -48px -16px; } +.ui-icon-triangle-1-s { background-position: -64px -16px; } +.ui-icon-triangle-1-sw { background-position: -80px -16px; } +.ui-icon-triangle-1-w { background-position: -96px -16px; } +.ui-icon-triangle-1-nw { background-position: -112px -16px; } +.ui-icon-triangle-2-n-s { background-position: -128px -16px; } +.ui-icon-triangle-2-e-w { background-position: -144px -16px; } +.ui-icon-arrow-1-n { background-position: 0 -32px; } +.ui-icon-arrow-1-ne { background-position: -16px -32px; } +.ui-icon-arrow-1-e { background-position: -32px -32px; } +.ui-icon-arrow-1-se { background-position: -48px -32px; } +.ui-icon-arrow-1-s { background-position: -64px -32px; } +.ui-icon-arrow-1-sw { background-position: -80px -32px; } +.ui-icon-arrow-1-w { background-position: -96px -32px; } +.ui-icon-arrow-1-nw { background-position: -112px -32px; } +.ui-icon-arrow-2-n-s { background-position: -128px -32px; } +.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } +.ui-icon-arrow-2-e-w { background-position: -160px -32px; } +.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } +.ui-icon-arrowstop-1-n { background-position: -192px -32px; } +.ui-icon-arrowstop-1-e { background-position: -208px -32px; } +.ui-icon-arrowstop-1-s { background-position: -224px -32px; } +.ui-icon-arrowstop-1-w { background-position: -240px -32px; } +.ui-icon-arrowthick-1-n { background-position: 0 -48px; } +.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } +.ui-icon-arrowthick-1-e { background-position: -32px -48px; } +.ui-icon-arrowthick-1-se { background-position: -48px -48px; } +.ui-icon-arrowthick-1-s { background-position: -64px -48px; } +.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } +.ui-icon-arrowthick-1-w { background-position: -96px -48px; } +.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } +.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } +.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } +.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } +.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } +.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } +.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } +.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } +.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } +.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } +.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } +.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } +.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } +.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } +.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } +.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } +.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } +.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } +.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } +.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } +.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } +.ui-icon-arrow-4 { background-position: 0 -80px; } +.ui-icon-arrow-4-diag { background-position: -16px -80px; } +.ui-icon-extlink { background-position: -32px -80px; } +.ui-icon-newwin { background-position: -48px -80px; } +.ui-icon-refresh { background-position: -64px -80px; } +.ui-icon-shuffle { background-position: -80px -80px; } +.ui-icon-transfer-e-w { background-position: -96px -80px; } +.ui-icon-transferthick-e-w { background-position: -112px -80px; } +.ui-icon-folder-collapsed { background-position: 0 -96px; } +.ui-icon-folder-open { background-position: -16px -96px; } +.ui-icon-document { background-position: -32px -96px; } +.ui-icon-document-b { background-position: -48px -96px; } +.ui-icon-note { background-position: -64px -96px; } +.ui-icon-mail-closed { background-position: -80px -96px; } +.ui-icon-mail-open { background-position: -96px -96px; } +.ui-icon-suitcase { background-position: -112px -96px; } +.ui-icon-comment { background-position: -128px -96px; } +.ui-icon-person { background-position: -144px -96px; } +.ui-icon-print { background-position: -160px -96px; } +.ui-icon-trash { background-position: -176px -96px; } +.ui-icon-locked { background-position: -192px -96px; } +.ui-icon-unlocked { background-position: -208px -96px; } +.ui-icon-bookmark { background-position: -224px -96px; } +.ui-icon-tag { background-position: -240px -96px; } +.ui-icon-home { background-position: 0 -112px; } +.ui-icon-flag { background-position: -16px -112px; } +.ui-icon-calendar { background-position: -32px -112px; } +.ui-icon-cart { background-position: -48px -112px; } +.ui-icon-pencil { background-position: -64px -112px; } +.ui-icon-clock { background-position: -80px -112px; } +.ui-icon-disk { background-position: -96px -112px; } +.ui-icon-calculator { background-position: -112px -112px; } +.ui-icon-zoomin { background-position: -128px -112px; } +.ui-icon-zoomout { background-position: -144px -112px; } +.ui-icon-search { background-position: -160px -112px; } +.ui-icon-wrench { background-position: -176px -112px; } +.ui-icon-gear { background-position: -192px -112px; } +.ui-icon-heart { background-position: -208px -112px; } +.ui-icon-star { background-position: -224px -112px; } +.ui-icon-link { background-position: -240px -112px; } +.ui-icon-cancel { background-position: 0 -128px; } +.ui-icon-plus { background-position: -16px -128px; } +.ui-icon-plusthick { background-position: -32px -128px; } +.ui-icon-minus { background-position: -48px -128px; } +.ui-icon-minusthick { background-position: -64px -128px; } +.ui-icon-close { background-position: -80px -128px; } +.ui-icon-closethick { background-position: -96px -128px; } +.ui-icon-key { background-position: -112px -128px; } +.ui-icon-lightbulb { background-position: -128px -128px; } +.ui-icon-scissors { background-position: -144px -128px; } +.ui-icon-clipboard { background-position: -160px -128px; } +.ui-icon-copy { background-position: -176px -128px; } +.ui-icon-contact { background-position: -192px -128px; } +.ui-icon-image { background-position: -208px -128px; } +.ui-icon-video { background-position: -224px -128px; } +.ui-icon-script { background-position: -240px -128px; } +.ui-icon-alert { background-position: 0 -144px; } +.ui-icon-info { background-position: -16px -144px; } +.ui-icon-notice { background-position: -32px -144px; } +.ui-icon-help { background-position: -48px -144px; } +.ui-icon-check { background-position: -64px -144px; } +.ui-icon-bullet { background-position: -80px -144px; } +.ui-icon-radio-off { background-position: -96px -144px; } +.ui-icon-radio-on { background-position: -112px -144px; } +.ui-icon-pin-w { background-position: -128px -144px; } +.ui-icon-pin-s { background-position: -144px -144px; } +.ui-icon-play { background-position: 0 -160px; } +.ui-icon-pause { background-position: -16px -160px; } +.ui-icon-seek-next { background-position: -32px -160px; } +.ui-icon-seek-prev { background-position: -48px -160px; } +.ui-icon-seek-end { background-position: -64px -160px; } +.ui-icon-seek-first { background-position: -80px -160px; } +.ui-icon-stop { background-position: -96px -160px; } +.ui-icon-eject { background-position: -112px -160px; } +.ui-icon-volume-off { background-position: -128px -160px; } +.ui-icon-volume-on { background-position: -144px -160px; } +.ui-icon-power { background-position: 0 -176px; } +.ui-icon-signal-diag { background-position: -16px -176px; } +.ui-icon-signal { background-position: -32px -176px; } +.ui-icon-battery-0 { background-position: -48px -176px; } +.ui-icon-battery-1 { background-position: -64px -176px; } +.ui-icon-battery-2 { background-position: -80px -176px; } +.ui-icon-battery-3 { background-position: -96px -176px; } +.ui-icon-circle-plus { background-position: 0 -192px; } +.ui-icon-circle-minus { background-position: -16px -192px; } +.ui-icon-circle-close { background-position: -32px -192px; } +.ui-icon-circle-triangle-e { background-position: -48px -192px; } +.ui-icon-circle-triangle-s { background-position: -64px -192px; } +.ui-icon-circle-triangle-w { background-position: -80px -192px; } +.ui-icon-circle-triangle-n { background-position: -96px -192px; } +.ui-icon-circle-arrow-e { background-position: -112px -192px; } +.ui-icon-circle-arrow-s { background-position: -128px -192px; } +.ui-icon-circle-arrow-w { background-position: -144px -192px; } +.ui-icon-circle-arrow-n { background-position: -160px -192px; } +.ui-icon-circle-zoomin { background-position: -176px -192px; } +.ui-icon-circle-zoomout { background-position: -192px -192px; } +.ui-icon-circle-check { background-position: -208px -192px; } +.ui-icon-circlesmall-plus { background-position: 0 -208px; } +.ui-icon-circlesmall-minus { background-position: -16px -208px; } +.ui-icon-circlesmall-close { background-position: -32px -208px; } +.ui-icon-squaresmall-plus { background-position: -48px -208px; } +.ui-icon-squaresmall-minus { background-position: -64px -208px; } +.ui-icon-squaresmall-close { background-position: -80px -208px; } +.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } +.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } +.ui-icon-grip-solid-vertical { background-position: -32px -224px; } +.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } +.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } +.ui-icon-grip-diagonal-se { background-position: -80px -224px; } + + +/* Misc visuals +----------------------------------*/ + +/* Corner radius */ +.ui-corner-tl { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; -webkit-border-top-left-radius: 4px/*{cornerRadius}*/; } +.ui-corner-tr { -moz-border-radius-topright: 4px/*{cornerRadius}*/; -webkit-border-top-right-radius: 4px/*{cornerRadius}*/; } +.ui-corner-bl { -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; } +.ui-corner-br { -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; } +.ui-corner-top { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; -webkit-border-top-left-radius: 4px/*{cornerRadius}*/; -moz-border-radius-topright: 4px/*{cornerRadius}*/; -webkit-border-top-right-radius: 4px/*{cornerRadius}*/; } +.ui-corner-bottom { -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; } +.ui-corner-right { -moz-border-radius-topright: 4px/*{cornerRadius}*/; -webkit-border-top-right-radius: 4px/*{cornerRadius}*/; -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; } +.ui-corner-left { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; -webkit-border-top-left-radius: 4px/*{cornerRadius}*/; -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; } +.ui-corner-all { -moz-border-radius: 4px/*{cornerRadius}*/; -webkit-border-radius: 4px/*{cornerRadius}*/; } + +/* Overlays */ +.ui-widget-overlay { background: #aaaaaa/*{bgColorOverlay}*/ none/*{bgImgUrlOverlay}*/ 0/*{bgOverlayXPos}*/ 0/*{bgOverlayYPos}*/ repeat-x/*{bgOverlayRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityOverlay}*/; } +.ui-widget-shadow { margin: -4px/*{offsetTopShadow}*/ 0 0 -4px/*{offsetLeftShadow}*/; padding: 4px/*{thicknessShadow}*/; background: #aaaaaa/*{bgColorShadow}*/ none/*{bgImgUrlShadow}*/ 0/*{bgShadowXPos}*/ 0/*{bgShadowYPos}*/ repeat-x/*{bgShadowRepeat}*/; opacity: .35;filter:Alpha(Opacity=35)/*{opacityShadow}*/; -moz-border-radius: 4px/*{cornerRadiusShadow}*/; -webkit-border-radius: 4px/*{cornerRadiusShadow}*/; } \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-bg_flat_0_aaaaaa_40x100.png b/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-bg_flat_0_aaaaaa_40x100.png new file mode 100644 index 0000000000..5b5dab2ab7 Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-bg_flat_0_aaaaaa_40x100.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-bg_flat_55_fbec88_40x100.png b/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-bg_flat_55_fbec88_40x100.png new file mode 100644 index 0000000000..47acaadd73 Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-bg_flat_55_fbec88_40x100.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-bg_glass_75_d0e5f5_1x400.png b/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-bg_glass_75_d0e5f5_1x400.png new file mode 100644 index 0000000000..9fb564f8d0 Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-bg_glass_75_d0e5f5_1x400.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-bg_glass_85_dfeffc_1x400.png b/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-bg_glass_85_dfeffc_1x400.png new file mode 100644 index 0000000000..014951529c Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-bg_glass_85_dfeffc_1x400.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-bg_glass_95_fef1ec_1x400.png b/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-bg_glass_95_fef1ec_1x400.png new file mode 100644 index 0000000000..4443fdc1a1 Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-bg_glass_95_fef1ec_1x400.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-bg_gloss-wave_55_5c9ccc_500x100.png b/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-bg_gloss-wave_55_5c9ccc_500x100.png new file mode 100644 index 0000000000..81ecc362d5 Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-bg_gloss-wave_55_5c9ccc_500x100.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-bg_inset-hard_100_f5f8f9_1x100.png b/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-bg_inset-hard_100_f5f8f9_1x100.png new file mode 100644 index 0000000000..4f3faf8aa8 Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-bg_inset-hard_100_f5f8f9_1x100.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-bg_inset-hard_100_fcfdfd_1x100.png b/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-bg_inset-hard_100_fcfdfd_1x100.png new file mode 100644 index 0000000000..38c38335d0 Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-bg_inset-hard_100_fcfdfd_1x100.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-icons_217bc0_256x240.png b/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-icons_217bc0_256x240.png new file mode 100644 index 0000000000..9c8845833b Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-icons_217bc0_256x240.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-icons_2e83ff_256x240.png b/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-icons_2e83ff_256x240.png new file mode 100644 index 0000000000..b425c446d2 Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-icons_2e83ff_256x240.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-icons_469bdd_256x240.png b/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-icons_469bdd_256x240.png new file mode 100644 index 0000000000..5e7915fa70 Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-icons_469bdd_256x240.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-icons_6da8d5_256x240.png b/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-icons_6da8d5_256x240.png new file mode 100644 index 0000000000..60e20ca189 Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-icons_6da8d5_256x240.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-icons_cd0a0a_256x240.png b/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-icons_cd0a0a_256x240.png new file mode 100644 index 0000000000..2db88b796a Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-icons_cd0a0a_256x240.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-icons_d8e7f3_256x240.png b/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-icons_d8e7f3_256x240.png new file mode 100644 index 0000000000..2c8aac4612 Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-icons_d8e7f3_256x240.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-icons_f9bd01_256x240.png b/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-icons_f9bd01_256x240.png new file mode 100644 index 0000000000..e81603f5ce Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/redmond/images/ui-icons_f9bd01_256x240.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/redmond/jquery-ui-1.7.1.custom.css b/js2/mwEmbed/jquery/jquery.ui/themes/redmond/jquery-ui-1.7.1.custom.css new file mode 100644 index 0000000000..5876717e4c --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/themes/redmond/jquery-ui-1.7.1.custom.css @@ -0,0 +1,404 @@ +/* +* jQuery UI CSS Framework +* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) +* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses. +*/ + +/* Layout helpers +----------------------------------*/ +.ui-helper-hidden { display: none; } +.ui-helper-hidden-accessible { position: absolute; left: -99999999px; } +.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } +.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } +.ui-helper-clearfix { display: inline-block; } +/* required comment for clearfix to work in Opera \*/ +* html .ui-helper-clearfix { height:1%; } +.ui-helper-clearfix { display:block; } +/* end clearfix */ +.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } + + +/* Interaction Cues +----------------------------------*/ +.ui-state-disabled { cursor: default !important; } + + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } + + +/* Misc visuals +----------------------------------*/ + +/* Overlays */ +.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } + +/* +* jQuery UI CSS Framework +* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) +* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses. +* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Lucida%20Grande,%20Lucida%20Sans,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=5px&bgColorHeader=5c9ccc&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=55&borderColorHeader=4297d7&fcHeader=ffffff&iconColorHeader=d8e7f3&bgColorContent=fcfdfd&bgTextureContent=06_inset_hard.png&bgImgOpacityContent=100&borderColorContent=a6c9e2&fcContent=222222&iconColorContent=469bdd&bgColorDefault=dfeffc&bgTextureDefault=02_glass.png&bgImgOpacityDefault=85&borderColorDefault=c5dbec&fcDefault=2e6e9e&iconColorDefault=6da8d5&bgColorHover=d0e5f5&bgTextureHover=02_glass.png&bgImgOpacityHover=75&borderColorHover=79b7e7&fcHover=1d5987&iconColorHover=217bc0&bgColorActive=f5f8f9&bgTextureActive=06_inset_hard.png&bgImgOpacityActive=100&borderColorActive=79b7e7&fcActive=e17009&iconColorActive=f9bd01&bgColorHighlight=fbec88&bgTextureHighlight=01_flat.png&bgImgOpacityHighlight=55&borderColorHighlight=fad42e&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=02_glass.png&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px +*/ + + +/* Component containers +----------------------------------*/ +.ui-widget { font-family: Lucida Grande, Lucida Sans, Arial, sans-serif; font-size: 1.1em; } +.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Lucida Grande, Lucida Sans, Arial, sans-serif; font-size: 1em; } +.ui-widget-content { border: 1px solid #a6c9e2; background: #fcfdfd url(images/ui-bg_inset-hard_100_fcfdfd_1x100.png) 50% bottom repeat-x; color: #222222; } +.ui-widget-content a { color: #222222; } +.ui-widget-header { border: 1px solid #4297d7; background: #5c9ccc url(images/ui-bg_gloss-wave_55_5c9ccc_500x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; } +.ui-widget-header a { color: #ffffff; } + +/* Interaction states +----------------------------------*/ +.ui-state-default, .ui-widget-content .ui-state-default { border: 1px solid #c5dbec; background: #dfeffc url(images/ui-bg_glass_85_dfeffc_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #2e6e9e; outline: none; } +.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #2e6e9e; text-decoration: none; outline: none; } +.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus { border: 1px solid #79b7e7; background: #d0e5f5 url(images/ui-bg_glass_75_d0e5f5_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #1d5987; outline: none; } +.ui-state-hover a, .ui-state-hover a:hover { color: #1d5987; text-decoration: none; outline: none; } +.ui-state-active, .ui-widget-content .ui-state-active { border: 1px solid #79b7e7; background: #f5f8f9 url(images/ui-bg_inset-hard_100_f5f8f9_1x100.png) 50% 50% repeat-x; font-weight: bold; color: #e17009; outline: none; } +.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #e17009; outline: none; text-decoration: none; } + +/* Interaction Cues +----------------------------------*/ +.ui-state-highlight, .ui-widget-content .ui-state-highlight {border: 1px solid #fad42e; background: #fbec88 url(images/ui-bg_flat_55_fbec88_40x100.png) 50% 50% repeat-x; color: #363636; } +.ui-state-highlight a, .ui-widget-content .ui-state-highlight a { color: #363636; } +.ui-state-error, .ui-widget-content .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; } +.ui-state-error a, .ui-widget-content .ui-state-error a { color: #cd0a0a; } +.ui-state-error-text, .ui-widget-content .ui-state-error-text { color: #cd0a0a; } +.ui-state-disabled, .ui-widget-content .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } +.ui-priority-primary, .ui-widget-content .ui-priority-primary { font-weight: bold; } +.ui-priority-secondary, .ui-widget-content .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_469bdd_256x240.png); } +.ui-widget-content .ui-icon {background-image: url(images/ui-icons_469bdd_256x240.png); } +.ui-widget-header .ui-icon {background-image: url(images/ui-icons_d8e7f3_256x240.png); } +.ui-state-default .ui-icon { background-image: url(images/ui-icons_6da8d5_256x240.png); } +.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_217bc0_256x240.png); } +.ui-state-active .ui-icon {background-image: url(images/ui-icons_f9bd01_256x240.png); } +.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); } +.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); } + +/* positioning */ +.ui-icon-carat-1-n { background-position: 0 0; } +.ui-icon-carat-1-ne { background-position: -16px 0; } +.ui-icon-carat-1-e { background-position: -32px 0; } +.ui-icon-carat-1-se { background-position: -48px 0; } +.ui-icon-carat-1-s { background-position: -64px 0; } +.ui-icon-carat-1-sw { background-position: -80px 0; } +.ui-icon-carat-1-w { background-position: -96px 0; } +.ui-icon-carat-1-nw { background-position: -112px 0; } +.ui-icon-carat-2-n-s { background-position: -128px 0; } +.ui-icon-carat-2-e-w { background-position: -144px 0; } +.ui-icon-triangle-1-n { background-position: 0 -16px; } +.ui-icon-triangle-1-ne { background-position: -16px -16px; } +.ui-icon-triangle-1-e { background-position: -32px -16px; } +.ui-icon-triangle-1-se { background-position: -48px -16px; } +.ui-icon-triangle-1-s { background-position: -64px -16px; } +.ui-icon-triangle-1-sw { background-position: -80px -16px; } +.ui-icon-triangle-1-w { background-position: -96px -16px; } +.ui-icon-triangle-1-nw { background-position: -112px -16px; } +.ui-icon-triangle-2-n-s { background-position: -128px -16px; } +.ui-icon-triangle-2-e-w { background-position: -144px -16px; } +.ui-icon-arrow-1-n { background-position: 0 -32px; } +.ui-icon-arrow-1-ne { background-position: -16px -32px; } +.ui-icon-arrow-1-e { background-position: -32px -32px; } +.ui-icon-arrow-1-se { background-position: -48px -32px; } +.ui-icon-arrow-1-s { background-position: -64px -32px; } +.ui-icon-arrow-1-sw { background-position: -80px -32px; } +.ui-icon-arrow-1-w { background-position: -96px -32px; } +.ui-icon-arrow-1-nw { background-position: -112px -32px; } +.ui-icon-arrow-2-n-s { background-position: -128px -32px; } +.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } +.ui-icon-arrow-2-e-w { background-position: -160px -32px; } +.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } +.ui-icon-arrowstop-1-n { background-position: -192px -32px; } +.ui-icon-arrowstop-1-e { background-position: -208px -32px; } +.ui-icon-arrowstop-1-s { background-position: -224px -32px; } +.ui-icon-arrowstop-1-w { background-position: -240px -32px; } +.ui-icon-arrowthick-1-n { background-position: 0 -48px; } +.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } +.ui-icon-arrowthick-1-e { background-position: -32px -48px; } +.ui-icon-arrowthick-1-se { background-position: -48px -48px; } +.ui-icon-arrowthick-1-s { background-position: -64px -48px; } +.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } +.ui-icon-arrowthick-1-w { background-position: -96px -48px; } +.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } +.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } +.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } +.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } +.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } +.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } +.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } +.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } +.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } +.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } +.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } +.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } +.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } +.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } +.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } +.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } +.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } +.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } +.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } +.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } +.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } +.ui-icon-arrow-4 { background-position: 0 -80px; } +.ui-icon-arrow-4-diag { background-position: -16px -80px; } +.ui-icon-extlink { background-position: -32px -80px; } +.ui-icon-newwin { background-position: -48px -80px; } +.ui-icon-refresh { background-position: -64px -80px; } +.ui-icon-shuffle { background-position: -80px -80px; } +.ui-icon-transfer-e-w { background-position: -96px -80px; } +.ui-icon-transferthick-e-w { background-position: -112px -80px; } +.ui-icon-folder-collapsed { background-position: 0 -96px; } +.ui-icon-folder-open { background-position: -16px -96px; } +.ui-icon-document { background-position: -32px -96px; } +.ui-icon-document-b { background-position: -48px -96px; } +.ui-icon-note { background-position: -64px -96px; } +.ui-icon-mail-closed { background-position: -80px -96px; } +.ui-icon-mail-open { background-position: -96px -96px; } +.ui-icon-suitcase { background-position: -112px -96px; } +.ui-icon-comment { background-position: -128px -96px; } +.ui-icon-person { background-position: -144px -96px; } +.ui-icon-print { background-position: -160px -96px; } +.ui-icon-trash { background-position: -176px -96px; } +.ui-icon-locked { background-position: -192px -96px; } +.ui-icon-unlocked { background-position: -208px -96px; } +.ui-icon-bookmark { background-position: -224px -96px; } +.ui-icon-tag { background-position: -240px -96px; } +.ui-icon-home { background-position: 0 -112px; } +.ui-icon-flag { background-position: -16px -112px; } +.ui-icon-calendar { background-position: -32px -112px; } +.ui-icon-cart { background-position: -48px -112px; } +.ui-icon-pencil { background-position: -64px -112px; } +.ui-icon-clock { background-position: -80px -112px; } +.ui-icon-disk { background-position: -96px -112px; } +.ui-icon-calculator { background-position: -112px -112px; } +.ui-icon-zoomin { background-position: -128px -112px; } +.ui-icon-zoomout { background-position: -144px -112px; } +.ui-icon-search { background-position: -160px -112px; } +.ui-icon-wrench { background-position: -176px -112px; } +.ui-icon-gear { background-position: -192px -112px; } +.ui-icon-heart { background-position: -208px -112px; } +.ui-icon-star { background-position: -224px -112px; } +.ui-icon-link { background-position: -240px -112px; } +.ui-icon-cancel { background-position: 0 -128px; } +.ui-icon-plus { background-position: -16px -128px; } +.ui-icon-plusthick { background-position: -32px -128px; } +.ui-icon-minus { background-position: -48px -128px; } +.ui-icon-minusthick { background-position: -64px -128px; } +.ui-icon-close { background-position: -80px -128px; } +.ui-icon-closethick { background-position: -96px -128px; } +.ui-icon-key { background-position: -112px -128px; } +.ui-icon-lightbulb { background-position: -128px -128px; } +.ui-icon-scissors { background-position: -144px -128px; } +.ui-icon-clipboard { background-position: -160px -128px; } +.ui-icon-copy { background-position: -176px -128px; } +.ui-icon-contact { background-position: -192px -128px; } +.ui-icon-image { background-position: -208px -128px; } +.ui-icon-video { background-position: -224px -128px; } +.ui-icon-script { background-position: -240px -128px; } +.ui-icon-alert { background-position: 0 -144px; } +.ui-icon-info { background-position: -16px -144px; } +.ui-icon-notice { background-position: -32px -144px; } +.ui-icon-help { background-position: -48px -144px; } +.ui-icon-check { background-position: -64px -144px; } +.ui-icon-bullet { background-position: -80px -144px; } +.ui-icon-radio-off { background-position: -96px -144px; } +.ui-icon-radio-on { background-position: -112px -144px; } +.ui-icon-pin-w { background-position: -128px -144px; } +.ui-icon-pin-s { background-position: -144px -144px; } +.ui-icon-play { background-position: 0 -160px; } +.ui-icon-pause { background-position: -16px -160px; } +.ui-icon-seek-next { background-position: -32px -160px; } +.ui-icon-seek-prev { background-position: -48px -160px; } +.ui-icon-seek-end { background-position: -64px -160px; } +.ui-icon-seek-first { background-position: -80px -160px; } +.ui-icon-stop { background-position: -96px -160px; } +.ui-icon-eject { background-position: -112px -160px; } +.ui-icon-volume-off { background-position: -128px -160px; } +.ui-icon-volume-on { background-position: -144px -160px; } +.ui-icon-power { background-position: 0 -176px; } +.ui-icon-signal-diag { background-position: -16px -176px; } +.ui-icon-signal { background-position: -32px -176px; } +.ui-icon-battery-0 { background-position: -48px -176px; } +.ui-icon-battery-1 { background-position: -64px -176px; } +.ui-icon-battery-2 { background-position: -80px -176px; } +.ui-icon-battery-3 { background-position: -96px -176px; } +.ui-icon-circle-plus { background-position: 0 -192px; } +.ui-icon-circle-minus { background-position: -16px -192px; } +.ui-icon-circle-close { background-position: -32px -192px; } +.ui-icon-circle-triangle-e { background-position: -48px -192px; } +.ui-icon-circle-triangle-s { background-position: -64px -192px; } +.ui-icon-circle-triangle-w { background-position: -80px -192px; } +.ui-icon-circle-triangle-n { background-position: -96px -192px; } +.ui-icon-circle-arrow-e { background-position: -112px -192px; } +.ui-icon-circle-arrow-s { background-position: -128px -192px; } +.ui-icon-circle-arrow-w { background-position: -144px -192px; } +.ui-icon-circle-arrow-n { background-position: -160px -192px; } +.ui-icon-circle-zoomin { background-position: -176px -192px; } +.ui-icon-circle-zoomout { background-position: -192px -192px; } +.ui-icon-circle-check { background-position: -208px -192px; } +.ui-icon-circlesmall-plus { background-position: 0 -208px; } +.ui-icon-circlesmall-minus { background-position: -16px -208px; } +.ui-icon-circlesmall-close { background-position: -32px -208px; } +.ui-icon-squaresmall-plus { background-position: -48px -208px; } +.ui-icon-squaresmall-minus { background-position: -64px -208px; } +.ui-icon-squaresmall-close { background-position: -80px -208px; } +.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } +.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } +.ui-icon-grip-solid-vertical { background-position: -32px -224px; } +.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } +.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } +.ui-icon-grip-diagonal-se { background-position: -80px -224px; } + + +/* Misc visuals +----------------------------------*/ + +/* Corner radius */ +.ui-corner-tl { -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; } +.ui-corner-tr { -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; } +.ui-corner-bl { -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; } +.ui-corner-br { -moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; } +.ui-corner-top { -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; } +.ui-corner-bottom { -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; } +.ui-corner-right { -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; -moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; } +.ui-corner-left { -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; } +.ui-corner-all { -moz-border-radius: 5px; -webkit-border-radius: 5px; } + +/* Overlays */ +.ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); } +.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -webkit-border-radius: 8px; }/* Accordion +----------------------------------*/ +.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; } +.ui-accordion .ui-accordion-li-fix { display: inline; } +.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; } +.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em 2.2em; } +.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; } +.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; } +.ui-accordion .ui-accordion-content-active { display: block; }/* Datepicker +----------------------------------*/ +.ui-datepicker { width: 17em; padding: .2em .2em 0; } +.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; } +.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; } +.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; } +.ui-datepicker .ui-datepicker-prev { left:2px; } +.ui-datepicker .ui-datepicker-next { right:2px; } +.ui-datepicker .ui-datepicker-prev-hover { left:1px; } +.ui-datepicker .ui-datepicker-next-hover { right:1px; } +.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; } +.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } +.ui-datepicker .ui-datepicker-title select { float:left; font-size:1em; margin:1px 0; } +.ui-datepicker select.ui-datepicker-month-year {width: 100%;} +.ui-datepicker select.ui-datepicker-month, +.ui-datepicker select.ui-datepicker-year { width: 49%;} +.ui-datepicker .ui-datepicker-title select.ui-datepicker-year { float: right; } +.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; } +.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; } +.ui-datepicker td { border: 0; padding: 1px; } +.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; } +.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; } +.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } +.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; } + +/* with multiple calendars */ +.ui-datepicker.ui-datepicker-multi { width:auto; } +.ui-datepicker-multi .ui-datepicker-group { float:left; } +.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } +.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } +.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } +.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } +.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } +.ui-datepicker-row-break { clear:both; width:100%; } + +/* RTL support */ +.ui-datepicker-rtl { direction: rtl; } +.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; } +.ui-datepicker-rtl .ui-datepicker-group { float:right; } +.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; } +.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; } + +/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */ +.ui-datepicker-cover { + display: none; /*sorry for IE5*/ + display/**/: block; /*sorry for IE5*/ + position: absolute; /*must have*/ + z-index: -1; /*must have*/ + filter: mask(); /*must have*/ + top: -4px; /*must have*/ + left: -4px; /*must have*/ + width: 200px; /*must have*/ + height: 200px; /*must have*/ +}/* Dialog +----------------------------------*/ +.ui-dialog { position: relative; padding: .2em; width: 300px; } +.ui-dialog .ui-dialog-titlebar { padding: .5em .3em .3em 1em; position: relative; } +.ui-dialog .ui-dialog-title { float: left; margin: .1em 0 .2em; } +.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; } +.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; } +.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; } +.ui-dialog .ui-dialog-content { border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; } +.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; } +.ui-dialog .ui-dialog-buttonpane button { float: right; margin: .5em .4em .5em 0; cursor: pointer; padding: .2em .6em .3em .6em; line-height: 1.4em; width:auto; overflow:visible; } +.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; } +.ui-draggable .ui-dialog-titlebar { cursor: move; } +/* Progressbar +----------------------------------*/ +.ui-progressbar { height:2em; text-align: left; } +.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }/* Resizable +----------------------------------*/ +.ui-resizable { position: relative;} +.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;} +.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } +.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0px; } +.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0px; } +.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0px; height: 100%; } +.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0px; height: 100%; } +.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } +.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } +.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } +.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/* Slider +----------------------------------*/ +.ui-slider { position: relative; text-align: left; } +.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; } +.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; } + +.ui-slider-horizontal { height: .8em; } +.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; } +.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } +.ui-slider-horizontal .ui-slider-range-min { left: 0; } +.ui-slider-horizontal .ui-slider-range-max { right: 0; } + +.ui-slider-vertical { width: .8em; height: 100px; } +.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; } +.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; } +.ui-slider-vertical .ui-slider-range-min { bottom: 0; } +.ui-slider-vertical .ui-slider-range-max { top: 0; }/* Tabs +----------------------------------*/ +.ui-tabs { padding: .2em; zoom: 1; } +.ui-tabs .ui-tabs-nav { list-style: none; position: relative; padding: .2em .2em 0; } +.ui-tabs .ui-tabs-nav li { position: relative; float: left; border-bottom-width: 0 !important; margin: 0 .2em -1px 0; padding: 0; } +.ui-tabs .ui-tabs-nav li a { float: left; text-decoration: none; padding: .5em 1em; } +.ui-tabs .ui-tabs-nav li.ui-tabs-selected { padding-bottom: 1px; border-bottom-width: 0; } +.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; } +.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ +.ui-tabs .ui-tabs-panel { padding: 1em 1.4em; display: block; border-width: 0; background: none; } +.ui-tabs .ui-tabs-hide { display: none !important; } diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-bg_diagonals-thick_20_666666_40x40.png b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-bg_diagonals-thick_20_666666_40x40.png new file mode 100644 index 0000000000..64ece5707d Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-bg_diagonals-thick_20_666666_40x40.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png new file mode 100644 index 0000000000..5b5dab2ab7 Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-bg_flat_75_ffffff_40x100.png b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-bg_flat_75_ffffff_40x100.png new file mode 100644 index 0000000000..ac8b229af9 Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-bg_flat_75_ffffff_40x100.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png new file mode 100644 index 0000000000..ad3d6346e0 Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-bg_glass_65_ffffff_1x400.png b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-bg_glass_65_ffffff_1x400.png new file mode 100644 index 0000000000..42ccba269b Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-bg_glass_65_ffffff_1x400.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-bg_glass_75_dadada_1x400.png b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-bg_glass_75_dadada_1x400.png new file mode 100644 index 0000000000..5a46b47cb1 Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-bg_glass_75_dadada_1x400.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png new file mode 100644 index 0000000000..86c2baa655 Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png new file mode 100644 index 0000000000..4443fdc1a1 Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png new file mode 100644 index 0000000000..7c9fa6c6ed Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-icons_222222_256x240.png b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-icons_222222_256x240.png new file mode 100644 index 0000000000..67560da9be Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-icons_222222_256x240.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-icons_2e83ff_256x240.png b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-icons_2e83ff_256x240.png new file mode 100644 index 0000000000..b425c446d2 Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-icons_2e83ff_256x240.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-icons_454545_256x240.png b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-icons_454545_256x240.png new file mode 100644 index 0000000000..0cd64a21a9 Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-icons_454545_256x240.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-icons_888888_256x240.png b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-icons_888888_256x240.png new file mode 100644 index 0000000000..2e5180e473 Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-icons_888888_256x240.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-icons_cd0a0a_256x240.png b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-icons_cd0a0a_256x240.png new file mode 100644 index 0000000000..2db88b796a Binary files /dev/null and b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/images/ui-icons_cd0a0a_256x240.png differ diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/jquery-ui-1.7.1.custom.css b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/jquery-ui-1.7.1.custom.css new file mode 100644 index 0000000000..303ec94aec --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/jquery-ui-1.7.1.custom.css @@ -0,0 +1,404 @@ +/* +* jQuery UI CSS Framework +* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) +* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses. +*/ + +/* Layout helpers +----------------------------------*/ +.ui-helper-hidden { display: none; } +.ui-helper-hidden-accessible { position: absolute; left: -99999999px; } +.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } +.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } +.ui-helper-clearfix { display: inline-block; } +/* required comment for clearfix to work in Opera \*/ +* html .ui-helper-clearfix { height:1%; } +.ui-helper-clearfix { display:block; } +/* end clearfix */ +.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } + + +/* Interaction Cues +----------------------------------*/ +.ui-state-disabled { cursor: default !important; } + + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } + + +/* Misc visuals +----------------------------------*/ + +/* Overlays */ +.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } + +/* +* jQuery UI CSS Framework +* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) +* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses. +* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana,Arial,sans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=03_highlight_soft.png&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=01_flat.png&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=02_glass.png&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=02_glass.png&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=02_glass.png&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px +*/ + + +/* Component containers +----------------------------------*/ +.ui-widget { font-family: Verdana,Arial,sans-serif; font-size: 1.1em; } +.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif; font-size: 1em; } +.ui-widget-content { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x; color: #222222; } +.ui-widget-content a { color: #222222; } +.ui-widget-header { border: 1px solid #aaaaaa; background: #cccccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x; color: #222222; font-weight: bold; } +.ui-widget-header a { color: #222222; } + +/* Interaction states +----------------------------------*/ +.ui-state-default, .ui-widget-content .ui-state-default { border: 1px solid #d3d3d3; background: #e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #555555; outline: none; } +.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555; text-decoration: none; outline: none; } +.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus { border: 1px solid #999999; background: #dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; outline: none; } +.ui-state-hover a, .ui-state-hover a:hover { color: #212121; text-decoration: none; outline: none; } +.ui-state-active, .ui-widget-content .ui-state-active { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; outline: none; } +.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121; outline: none; text-decoration: none; } + +/* Interaction Cues +----------------------------------*/ +.ui-state-highlight, .ui-widget-content .ui-state-highlight {border: 1px solid #fcefa1; background: #fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x; color: #363636; } +.ui-state-highlight a, .ui-widget-content .ui-state-highlight a { color: #363636; } +.ui-state-error, .ui-widget-content .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; } +.ui-state-error a, .ui-widget-content .ui-state-error a { color: #cd0a0a; } +.ui-state-error-text, .ui-widget-content .ui-state-error-text { color: #cd0a0a; } +.ui-state-disabled, .ui-widget-content .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } +.ui-priority-primary, .ui-widget-content .ui-priority-primary { font-weight: bold; } +.ui-priority-secondary, .ui-widget-content .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); } +.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); } +.ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); } +.ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png); } +.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); } +.ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); } +.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); } +.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); } + +/* positioning */ +.ui-icon-carat-1-n { background-position: 0 0; } +.ui-icon-carat-1-ne { background-position: -16px 0; } +.ui-icon-carat-1-e { background-position: -32px 0; } +.ui-icon-carat-1-se { background-position: -48px 0; } +.ui-icon-carat-1-s { background-position: -64px 0; } +.ui-icon-carat-1-sw { background-position: -80px 0; } +.ui-icon-carat-1-w { background-position: -96px 0; } +.ui-icon-carat-1-nw { background-position: -112px 0; } +.ui-icon-carat-2-n-s { background-position: -128px 0; } +.ui-icon-carat-2-e-w { background-position: -144px 0; } +.ui-icon-triangle-1-n { background-position: 0 -16px; } +.ui-icon-triangle-1-ne { background-position: -16px -16px; } +.ui-icon-triangle-1-e { background-position: -32px -16px; } +.ui-icon-triangle-1-se { background-position: -48px -16px; } +.ui-icon-triangle-1-s { background-position: -64px -16px; } +.ui-icon-triangle-1-sw { background-position: -80px -16px; } +.ui-icon-triangle-1-w { background-position: -96px -16px; } +.ui-icon-triangle-1-nw { background-position: -112px -16px; } +.ui-icon-triangle-2-n-s { background-position: -128px -16px; } +.ui-icon-triangle-2-e-w { background-position: -144px -16px; } +.ui-icon-arrow-1-n { background-position: 0 -32px; } +.ui-icon-arrow-1-ne { background-position: -16px -32px; } +.ui-icon-arrow-1-e { background-position: -32px -32px; } +.ui-icon-arrow-1-se { background-position: -48px -32px; } +.ui-icon-arrow-1-s { background-position: -64px -32px; } +.ui-icon-arrow-1-sw { background-position: -80px -32px; } +.ui-icon-arrow-1-w { background-position: -96px -32px; } +.ui-icon-arrow-1-nw { background-position: -112px -32px; } +.ui-icon-arrow-2-n-s { background-position: -128px -32px; } +.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } +.ui-icon-arrow-2-e-w { background-position: -160px -32px; } +.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } +.ui-icon-arrowstop-1-n { background-position: -192px -32px; } +.ui-icon-arrowstop-1-e { background-position: -208px -32px; } +.ui-icon-arrowstop-1-s { background-position: -224px -32px; } +.ui-icon-arrowstop-1-w { background-position: -240px -32px; } +.ui-icon-arrowthick-1-n { background-position: 0 -48px; } +.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } +.ui-icon-arrowthick-1-e { background-position: -32px -48px; } +.ui-icon-arrowthick-1-se { background-position: -48px -48px; } +.ui-icon-arrowthick-1-s { background-position: -64px -48px; } +.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } +.ui-icon-arrowthick-1-w { background-position: -96px -48px; } +.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } +.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } +.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } +.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } +.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } +.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } +.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } +.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } +.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } +.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } +.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } +.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } +.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } +.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } +.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } +.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } +.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } +.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } +.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } +.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } +.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } +.ui-icon-arrow-4 { background-position: 0 -80px; } +.ui-icon-arrow-4-diag { background-position: -16px -80px; } +.ui-icon-extlink { background-position: -32px -80px; } +.ui-icon-newwin { background-position: -48px -80px; } +.ui-icon-refresh { background-position: -64px -80px; } +.ui-icon-shuffle { background-position: -80px -80px; } +.ui-icon-transfer-e-w { background-position: -96px -80px; } +.ui-icon-transferthick-e-w { background-position: -112px -80px; } +.ui-icon-folder-collapsed { background-position: 0 -96px; } +.ui-icon-folder-open { background-position: -16px -96px; } +.ui-icon-document { background-position: -32px -96px; } +.ui-icon-document-b { background-position: -48px -96px; } +.ui-icon-note { background-position: -64px -96px; } +.ui-icon-mail-closed { background-position: -80px -96px; } +.ui-icon-mail-open { background-position: -96px -96px; } +.ui-icon-suitcase { background-position: -112px -96px; } +.ui-icon-comment { background-position: -128px -96px; } +.ui-icon-person { background-position: -144px -96px; } +.ui-icon-print { background-position: -160px -96px; } +.ui-icon-trash { background-position: -176px -96px; } +.ui-icon-locked { background-position: -192px -96px; } +.ui-icon-unlocked { background-position: -208px -96px; } +.ui-icon-bookmark { background-position: -224px -96px; } +.ui-icon-tag { background-position: -240px -96px; } +.ui-icon-home { background-position: 0 -112px; } +.ui-icon-flag { background-position: -16px -112px; } +.ui-icon-calendar { background-position: -32px -112px; } +.ui-icon-cart { background-position: -48px -112px; } +.ui-icon-pencil { background-position: -64px -112px; } +.ui-icon-clock { background-position: -80px -112px; } +.ui-icon-disk { background-position: -96px -112px; } +.ui-icon-calculator { background-position: -112px -112px; } +.ui-icon-zoomin { background-position: -128px -112px; } +.ui-icon-zoomout { background-position: -144px -112px; } +.ui-icon-search { background-position: -160px -112px; } +.ui-icon-wrench { background-position: -176px -112px; } +.ui-icon-gear { background-position: -192px -112px; } +.ui-icon-heart { background-position: -208px -112px; } +.ui-icon-star { background-position: -224px -112px; } +.ui-icon-link { background-position: -240px -112px; } +.ui-icon-cancel { background-position: 0 -128px; } +.ui-icon-plus { background-position: -16px -128px; } +.ui-icon-plusthick { background-position: -32px -128px; } +.ui-icon-minus { background-position: -48px -128px; } +.ui-icon-minusthick { background-position: -64px -128px; } +.ui-icon-close { background-position: -80px -128px; } +.ui-icon-closethick { background-position: -96px -128px; } +.ui-icon-key { background-position: -112px -128px; } +.ui-icon-lightbulb { background-position: -128px -128px; } +.ui-icon-scissors { background-position: -144px -128px; } +.ui-icon-clipboard { background-position: -160px -128px; } +.ui-icon-copy { background-position: -176px -128px; } +.ui-icon-contact { background-position: -192px -128px; } +.ui-icon-image { background-position: -208px -128px; } +.ui-icon-video { background-position: -224px -128px; } +.ui-icon-script { background-position: -240px -128px; } +.ui-icon-alert { background-position: 0 -144px; } +.ui-icon-info { background-position: -16px -144px; } +.ui-icon-notice { background-position: -32px -144px; } +.ui-icon-help { background-position: -48px -144px; } +.ui-icon-check { background-position: -64px -144px; } +.ui-icon-bullet { background-position: -80px -144px; } +.ui-icon-radio-off { background-position: -96px -144px; } +.ui-icon-radio-on { background-position: -112px -144px; } +.ui-icon-pin-w { background-position: -128px -144px; } +.ui-icon-pin-s { background-position: -144px -144px; } +.ui-icon-play { background-position: 0 -160px; } +.ui-icon-pause { background-position: -16px -160px; } +.ui-icon-seek-next { background-position: -32px -160px; } +.ui-icon-seek-prev { background-position: -48px -160px; } +.ui-icon-seek-end { background-position: -64px -160px; } +.ui-icon-seek-first { background-position: -80px -160px; } +.ui-icon-stop { background-position: -96px -160px; } +.ui-icon-eject { background-position: -112px -160px; } +.ui-icon-volume-off { background-position: -128px -160px; } +.ui-icon-volume-on { background-position: -144px -160px; } +.ui-icon-power { background-position: 0 -176px; } +.ui-icon-signal-diag { background-position: -16px -176px; } +.ui-icon-signal { background-position: -32px -176px; } +.ui-icon-battery-0 { background-position: -48px -176px; } +.ui-icon-battery-1 { background-position: -64px -176px; } +.ui-icon-battery-2 { background-position: -80px -176px; } +.ui-icon-battery-3 { background-position: -96px -176px; } +.ui-icon-circle-plus { background-position: 0 -192px; } +.ui-icon-circle-minus { background-position: -16px -192px; } +.ui-icon-circle-close { background-position: -32px -192px; } +.ui-icon-circle-triangle-e { background-position: -48px -192px; } +.ui-icon-circle-triangle-s { background-position: -64px -192px; } +.ui-icon-circle-triangle-w { background-position: -80px -192px; } +.ui-icon-circle-triangle-n { background-position: -96px -192px; } +.ui-icon-circle-arrow-e { background-position: -112px -192px; } +.ui-icon-circle-arrow-s { background-position: -128px -192px; } +.ui-icon-circle-arrow-w { background-position: -144px -192px; } +.ui-icon-circle-arrow-n { background-position: -160px -192px; } +.ui-icon-circle-zoomin { background-position: -176px -192px; } +.ui-icon-circle-zoomout { background-position: -192px -192px; } +.ui-icon-circle-check { background-position: -208px -192px; } +.ui-icon-circlesmall-plus { background-position: 0 -208px; } +.ui-icon-circlesmall-minus { background-position: -16px -208px; } +.ui-icon-circlesmall-close { background-position: -32px -208px; } +.ui-icon-squaresmall-plus { background-position: -48px -208px; } +.ui-icon-squaresmall-minus { background-position: -64px -208px; } +.ui-icon-squaresmall-close { background-position: -80px -208px; } +.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } +.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } +.ui-icon-grip-solid-vertical { background-position: -32px -224px; } +.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } +.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } +.ui-icon-grip-diagonal-se { background-position: -80px -224px; } + + +/* Misc visuals +----------------------------------*/ + +/* Corner radius */ +.ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; } +.ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; } +.ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; } +.ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; } +.ui-corner-top { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; } +.ui-corner-bottom { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; } +.ui-corner-right { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; } +.ui-corner-left { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; } +.ui-corner-all { -moz-border-radius: 4px; -webkit-border-radius: 4px; } + +/* Overlays */ +.ui-widget-overlay { background: #aaaaaa url(images/ui-bg_diagonals-thick_20_666666_40x40.png) 50% 50% repeat; opacity: .30;filter:Alpha(Opacity=30); } +.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -webkit-border-radius: 8px; }/* Accordion +----------------------------------*/ +.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; } +.ui-accordion .ui-accordion-li-fix { display: inline; } +.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; } +.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em 2.2em; } +.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; } +.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; } +.ui-accordion .ui-accordion-content-active { display: block; }/* Datepicker +----------------------------------*/ +.ui-datepicker { width: 17em; padding: .2em .2em 0; } +.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; } +.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; } +.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; } +.ui-datepicker .ui-datepicker-prev { left:2px; } +.ui-datepicker .ui-datepicker-next { right:2px; } +.ui-datepicker .ui-datepicker-prev-hover { left:1px; } +.ui-datepicker .ui-datepicker-next-hover { right:1px; } +.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; } +.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } +.ui-datepicker .ui-datepicker-title select { float:left; font-size:1em; margin:1px 0; } +.ui-datepicker select.ui-datepicker-month-year {width: 100%;} +.ui-datepicker select.ui-datepicker-month, +.ui-datepicker select.ui-datepicker-year { width: 49%;} +.ui-datepicker .ui-datepicker-title select.ui-datepicker-year { float: right; } +.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; } +.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; } +.ui-datepicker td { border: 0; padding: 1px; } +.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; } +.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; } +.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } +.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; } + +/* with multiple calendars */ +.ui-datepicker.ui-datepicker-multi { width:auto; } +.ui-datepicker-multi .ui-datepicker-group { float:left; } +.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } +.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } +.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } +.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } +.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } +.ui-datepicker-row-break { clear:both; width:100%; } + +/* RTL support */ +.ui-datepicker-rtl { direction: rtl; } +.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; } +.ui-datepicker-rtl .ui-datepicker-group { float:right; } +.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; } +.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; } + +/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */ +.ui-datepicker-cover { + display: none; /*sorry for IE5*/ + display/**/: block; /*sorry for IE5*/ + position: absolute; /*must have*/ + z-index: -1; /*must have*/ + filter: mask(); /*must have*/ + top: -4px; /*must have*/ + left: -4px; /*must have*/ + width: 200px; /*must have*/ + height: 200px; /*must have*/ +}/* Dialog +----------------------------------*/ +.ui-dialog { position: relative; padding: .2em; width: 300px; } +.ui-dialog .ui-dialog-titlebar { padding: .5em .3em .3em 1em; position: relative; } +.ui-dialog .ui-dialog-title { float: left; margin: .1em 0 .2em; } +.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; } +.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; } +.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; } +.ui-dialog .ui-dialog-content { border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; } +.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; } +.ui-dialog .ui-dialog-buttonpane button { float: right; margin: .5em .4em .5em 0; cursor: pointer; padding: .2em .6em .3em .6em; line-height: 1.4em; width:auto; overflow:visible; } +.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; } +.ui-draggable .ui-dialog-titlebar { cursor: move; } +/* Progressbar +----------------------------------*/ +.ui-progressbar { height:2em; text-align: left; } +.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }/* Resizable +----------------------------------*/ +.ui-resizable { position: relative;} +.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;} +.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } +.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0px; } +.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0px; } +.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0px; height: 100%; } +.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0px; height: 100%; } +.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } +.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } +.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } +.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/* Slider +----------------------------------*/ +.ui-slider { position: relative; text-align: left; } +.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; } +.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; } + +.ui-slider-horizontal { height: .8em; } +.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; } +.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } +.ui-slider-horizontal .ui-slider-range-min { left: 0; } +.ui-slider-horizontal .ui-slider-range-max { right: 0; } + +.ui-slider-vertical { width: .8em; height: 100px; } +.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; } +.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; } +.ui-slider-vertical .ui-slider-range-min { bottom: 0; } +.ui-slider-vertical .ui-slider-range-max { top: 0; }/* Tabs +----------------------------------*/ +.ui-tabs { padding: .2em; zoom: 1; } +.ui-tabs .ui-tabs-nav { list-style: none; position: relative; padding: .2em .2em 0; } +.ui-tabs .ui-tabs-nav li { position: relative; float: left; border-bottom-width: 0 !important; margin: 0 .2em -1px 0; padding: 0; } +.ui-tabs .ui-tabs-nav li a { float: left; text-decoration: none; padding: .5em 1em; } +.ui-tabs .ui-tabs-nav li.ui-tabs-selected { padding-bottom: 1px; border-bottom-width: 0; } +.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; } +.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ +.ui-tabs .ui-tabs-panel { padding: 1em 1.4em; display: block; border-width: 0; background: none; } +.ui-tabs .ui-tabs-hide { display: none !important; } diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/ui.accordion.css b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/ui.accordion.css new file mode 100644 index 0000000000..ee1b1b640b --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/ui.accordion.css @@ -0,0 +1,9 @@ +/* Accordion +----------------------------------*/ +.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; } +.ui-accordion .ui-accordion-li-fix { display: inline; } +.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; } +.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em 2.2em; } +.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; } +.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; } +.ui-accordion .ui-accordion-content-active { display: block; } \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/ui.all.css b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/ui.all.css new file mode 100644 index 0000000000..543e4c3bc9 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/ui.all.css @@ -0,0 +1,2 @@ +@import "ui.base.css"; +@import "ui.theme.css"; diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/ui.base.css b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/ui.base.css new file mode 100644 index 0000000000..d716095081 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/ui.base.css @@ -0,0 +1,8 @@ +@import url("ui.core.css"); +@import url("ui.resizable.css"); +@import url("ui.accordion.css"); +@import url("ui.dialog.css"); +@import url("ui.slider.css"); +@import url("ui.tabs.css"); +@import url("ui.datepicker.css"); +@import url("ui.progressbar.css"); \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/ui.core.css b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/ui.core.css new file mode 100644 index 0000000000..c2f18f2c08 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/ui.core.css @@ -0,0 +1,37 @@ +/* +* jQuery UI CSS Framework +* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) +* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses. +*/ + +/* Layout helpers +----------------------------------*/ +.ui-helper-hidden { display: none; } +.ui-helper-hidden-accessible { position: absolute; left: -99999999px; } +.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } +.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } +.ui-helper-clearfix { display: inline-block; } +/* required comment for clearfix to work in Opera \*/ +* html .ui-helper-clearfix { height:1%; } +.ui-helper-clearfix { display:block; } +/* end clearfix */ +.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } + + +/* Interaction Cues +----------------------------------*/ +.ui-state-disabled { cursor: default !important; } + + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } + + +/* Misc visuals +----------------------------------*/ + +/* Overlays */ +.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/ui.datepicker.css b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/ui.datepicker.css new file mode 100644 index 0000000000..d18ee6396b --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/ui.datepicker.css @@ -0,0 +1,62 @@ +/* Datepicker +----------------------------------*/ +.ui-datepicker { width: 17em; padding: .2em .2em 0; } +.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; } +.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; } +.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; } +.ui-datepicker .ui-datepicker-prev { left:2px; } +.ui-datepicker .ui-datepicker-next { right:2px; } +.ui-datepicker .ui-datepicker-prev-hover { left:1px; } +.ui-datepicker .ui-datepicker-next-hover { right:1px; } +.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; } +.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } +.ui-datepicker .ui-datepicker-title select { float:left; font-size:1em; margin:1px 0; } +.ui-datepicker select.ui-datepicker-month-year {width: 100%;} +.ui-datepicker select.ui-datepicker-month, +.ui-datepicker select.ui-datepicker-year { width: 49%;} +.ui-datepicker .ui-datepicker-title select.ui-datepicker-year { float: right; } +.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; } +.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; } +.ui-datepicker td { border: 0; padding: 1px; } +.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; } +.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; } +.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } +.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; } + +/* with multiple calendars */ +.ui-datepicker.ui-datepicker-multi { width:auto; } +.ui-datepicker-multi .ui-datepicker-group { float:left; } +.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } +.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } +.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } +.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } +.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } +.ui-datepicker-row-break { clear:both; width:100%; } + +/* RTL support */ +.ui-datepicker-rtl { direction: rtl; } +.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; } +.ui-datepicker-rtl .ui-datepicker-group { float:right; } +.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; } +.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; } + +/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */ +.ui-datepicker-cover { + display: none; /*sorry for IE5*/ + display/**/: block; /*sorry for IE5*/ + position: absolute; /*must have*/ + z-index: -1; /*must have*/ + filter: mask(); /*must have*/ + top: -4px; /*must have*/ + left: -4px; /*must have*/ + width: 200px; /*must have*/ + height: 200px; /*must have*/ +} \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/ui.dialog.css b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/ui.dialog.css new file mode 100644 index 0000000000..2997595b7d --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/ui.dialog.css @@ -0,0 +1,13 @@ +/* Dialog +----------------------------------*/ +.ui-dialog { position: relative; padding: .2em; width: 300px; } +.ui-dialog .ui-dialog-titlebar { padding: .5em .3em .3em 1em; position: relative; } +.ui-dialog .ui-dialog-title { float: left; margin: .1em 0 .2em; } +.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; } +.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; } +.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; } +.ui-dialog .ui-dialog-content { border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; } +.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; } +.ui-dialog .ui-dialog-buttonpane button { float: right; margin: .5em .4em .5em 0; cursor: pointer; padding: .2em .6em .3em .6em; line-height: 1.4em; width:auto; overflow:visible; } +.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; } +.ui-draggable .ui-dialog-titlebar { cursor: move; } diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/ui.progressbar.css b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/ui.progressbar.css new file mode 100644 index 0000000000..bc0939ecfa --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/ui.progressbar.css @@ -0,0 +1,4 @@ +/* Progressbar +----------------------------------*/ +.ui-progressbar { height:2em; text-align: left; } +.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; } \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/ui.resizable.css b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/ui.resizable.css new file mode 100644 index 0000000000..44efeb2e86 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/ui.resizable.css @@ -0,0 +1,13 @@ +/* Resizable +----------------------------------*/ +.ui-resizable { position: relative;} +.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;} +.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } +.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0px; } +.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0px; } +.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0px; height: 100%; } +.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0px; height: 100%; } +.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } +.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } +.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } +.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;} \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/ui.slider.css b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/ui.slider.css new file mode 100644 index 0000000000..4c5621879e --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/ui.slider.css @@ -0,0 +1,17 @@ +/* Slider +----------------------------------*/ +.ui-slider { position: relative; text-align: left; } +.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; } +.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; } + +.ui-slider-horizontal { height: .8em; } +.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; } +.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } +.ui-slider-horizontal .ui-slider-range-min { left: 0; } +.ui-slider-horizontal .ui-slider-range-max { right: 0; } + +.ui-slider-vertical { width: .8em; height: 100px; } +.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; } +.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; } +.ui-slider-vertical .ui-slider-range-min { bottom: 0; } +.ui-slider-vertical .ui-slider-range-max { top: 0; } \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/ui.tabs.css b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/ui.tabs.css new file mode 100644 index 0000000000..3ca6b9a0a9 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/ui.tabs.css @@ -0,0 +1,11 @@ +/* Tabs +----------------------------------*/ +.ui-tabs { padding: .2em; zoom: 1; } +.ui-tabs .ui-tabs-nav { list-style: none; position: relative; padding: .2em .2em 0; } +.ui-tabs .ui-tabs-nav li { position: relative; float: left; border-bottom-width: 0 !important; margin: 0 .2em -1px 0; padding: 0; } +.ui-tabs .ui-tabs-nav li a { float: left; text-decoration: none; padding: .5em 1em; } +.ui-tabs .ui-tabs-nav li.ui-tabs-selected { padding-bottom: 1px; border-bottom-width: 0; } +.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; } +.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ +.ui-tabs .ui-tabs-panel { padding: 1em 1.4em; display: block; border-width: 0; background: none; } +.ui-tabs .ui-tabs-hide { display: none !important; } diff --git a/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/ui.theme.css b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/ui.theme.css new file mode 100644 index 0000000000..10f76b4612 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/themes/smoothness/ui.theme.css @@ -0,0 +1,245 @@ + + +/* +* jQuery UI CSS Framework +* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) +* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses. +* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana,Arial,sans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=03_highlight_soft.png&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=01_flat.png&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=02_glass.png&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=02_glass.png&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=02_glass.png&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px +*/ + + +/* Component containers +----------------------------------*/ +.ui-widget { font-family: Verdana,Arial,sans-serif; font-size: 1.1em; } +.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif; font-size: 1em; } +.ui-widget-content { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x; color: #222222; } +.ui-widget-content a { color: #222222; } +.ui-widget-header { border: 1px solid #aaaaaa; background: #cccccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x; color: #222222; font-weight: bold; } +.ui-widget-header a { color: #222222; } + +/* Interaction states +----------------------------------*/ +.ui-state-default, .ui-widget-content .ui-state-default { border: 1px solid #d3d3d3; background: #e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #555555; outline: none; } +.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555; text-decoration: none; outline: none; } +.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus { border: 1px solid #999999; background: #dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; outline: none; } +.ui-state-hover a, .ui-state-hover a:hover { color: #212121; text-decoration: none; outline: none; } +.ui-state-active, .ui-widget-content .ui-state-active { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; outline: none; } +.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121; outline: none; text-decoration: none; } + +/* Interaction Cues +----------------------------------*/ +.ui-state-highlight, .ui-widget-content .ui-state-highlight {border: 1px solid #fcefa1; background: #fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x; color: #363636; } +.ui-state-highlight a, .ui-widget-content .ui-state-highlight a { color: #363636; } +.ui-state-error, .ui-widget-content .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; } +.ui-state-error a, .ui-widget-content .ui-state-error a { color: #cd0a0a; } +.ui-state-error-text, .ui-widget-content .ui-state-error-text { color: #cd0a0a; } +.ui-state-disabled, .ui-widget-content .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } +.ui-priority-primary, .ui-widget-content .ui-priority-primary { font-weight: bold; } +.ui-priority-secondary, .ui-widget-content .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); } +.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); } +.ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); } +.ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png); } +.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); } +.ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); } +.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); } +.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); } + +/* positioning */ +.ui-icon-carat-1-n { background-position: 0 0; } +.ui-icon-carat-1-ne { background-position: -16px 0; } +.ui-icon-carat-1-e { background-position: -32px 0; } +.ui-icon-carat-1-se { background-position: -48px 0; } +.ui-icon-carat-1-s { background-position: -64px 0; } +.ui-icon-carat-1-sw { background-position: -80px 0; } +.ui-icon-carat-1-w { background-position: -96px 0; } +.ui-icon-carat-1-nw { background-position: -112px 0; } +.ui-icon-carat-2-n-s { background-position: -128px 0; } +.ui-icon-carat-2-e-w { background-position: -144px 0; } +.ui-icon-triangle-1-n { background-position: 0 -16px; } +.ui-icon-triangle-1-ne { background-position: -16px -16px; } +.ui-icon-triangle-1-e { background-position: -32px -16px; } +.ui-icon-triangle-1-se { background-position: -48px -16px; } +.ui-icon-triangle-1-s { background-position: -64px -16px; } +.ui-icon-triangle-1-sw { background-position: -80px -16px; } +.ui-icon-triangle-1-w { background-position: -96px -16px; } +.ui-icon-triangle-1-nw { background-position: -112px -16px; } +.ui-icon-triangle-2-n-s { background-position: -128px -16px; } +.ui-icon-triangle-2-e-w { background-position: -144px -16px; } +.ui-icon-arrow-1-n { background-position: 0 -32px; } +.ui-icon-arrow-1-ne { background-position: -16px -32px; } +.ui-icon-arrow-1-e { background-position: -32px -32px; } +.ui-icon-arrow-1-se { background-position: -48px -32px; } +.ui-icon-arrow-1-s { background-position: -64px -32px; } +.ui-icon-arrow-1-sw { background-position: -80px -32px; } +.ui-icon-arrow-1-w { background-position: -96px -32px; } +.ui-icon-arrow-1-nw { background-position: -112px -32px; } +.ui-icon-arrow-2-n-s { background-position: -128px -32px; } +.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } +.ui-icon-arrow-2-e-w { background-position: -160px -32px; } +.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } +.ui-icon-arrowstop-1-n { background-position: -192px -32px; } +.ui-icon-arrowstop-1-e { background-position: -208px -32px; } +.ui-icon-arrowstop-1-s { background-position: -224px -32px; } +.ui-icon-arrowstop-1-w { background-position: -240px -32px; } +.ui-icon-arrowthick-1-n { background-position: 0 -48px; } +.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } +.ui-icon-arrowthick-1-e { background-position: -32px -48px; } +.ui-icon-arrowthick-1-se { background-position: -48px -48px; } +.ui-icon-arrowthick-1-s { background-position: -64px -48px; } +.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } +.ui-icon-arrowthick-1-w { background-position: -96px -48px; } +.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } +.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } +.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } +.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } +.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } +.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } +.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } +.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } +.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } +.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } +.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } +.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } +.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } +.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } +.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } +.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } +.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } +.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } +.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } +.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } +.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } +.ui-icon-arrow-4 { background-position: 0 -80px; } +.ui-icon-arrow-4-diag { background-position: -16px -80px; } +.ui-icon-extlink { background-position: -32px -80px; } +.ui-icon-newwin { background-position: -48px -80px; } +.ui-icon-refresh { background-position: -64px -80px; } +.ui-icon-shuffle { background-position: -80px -80px; } +.ui-icon-transfer-e-w { background-position: -96px -80px; } +.ui-icon-transferthick-e-w { background-position: -112px -80px; } +.ui-icon-folder-collapsed { background-position: 0 -96px; } +.ui-icon-folder-open { background-position: -16px -96px; } +.ui-icon-document { background-position: -32px -96px; } +.ui-icon-document-b { background-position: -48px -96px; } +.ui-icon-note { background-position: -64px -96px; } +.ui-icon-mail-closed { background-position: -80px -96px; } +.ui-icon-mail-open { background-position: -96px -96px; } +.ui-icon-suitcase { background-position: -112px -96px; } +.ui-icon-comment { background-position: -128px -96px; } +.ui-icon-person { background-position: -144px -96px; } +.ui-icon-print { background-position: -160px -96px; } +.ui-icon-trash { background-position: -176px -96px; } +.ui-icon-locked { background-position: -192px -96px; } +.ui-icon-unlocked { background-position: -208px -96px; } +.ui-icon-bookmark { background-position: -224px -96px; } +.ui-icon-tag { background-position: -240px -96px; } +.ui-icon-home { background-position: 0 -112px; } +.ui-icon-flag { background-position: -16px -112px; } +.ui-icon-calendar { background-position: -32px -112px; } +.ui-icon-cart { background-position: -48px -112px; } +.ui-icon-pencil { background-position: -64px -112px; } +.ui-icon-clock { background-position: -80px -112px; } +.ui-icon-disk { background-position: -96px -112px; } +.ui-icon-calculator { background-position: -112px -112px; } +.ui-icon-zoomin { background-position: -128px -112px; } +.ui-icon-zoomout { background-position: -144px -112px; } +.ui-icon-search { background-position: -160px -112px; } +.ui-icon-wrench { background-position: -176px -112px; } +.ui-icon-gear { background-position: -192px -112px; } +.ui-icon-heart { background-position: -208px -112px; } +.ui-icon-star { background-position: -224px -112px; } +.ui-icon-link { background-position: -240px -112px; } +.ui-icon-cancel { background-position: 0 -128px; } +.ui-icon-plus { background-position: -16px -128px; } +.ui-icon-plusthick { background-position: -32px -128px; } +.ui-icon-minus { background-position: -48px -128px; } +.ui-icon-minusthick { background-position: -64px -128px; } +.ui-icon-close { background-position: -80px -128px; } +.ui-icon-closethick { background-position: -96px -128px; } +.ui-icon-key { background-position: -112px -128px; } +.ui-icon-lightbulb { background-position: -128px -128px; } +.ui-icon-scissors { background-position: -144px -128px; } +.ui-icon-clipboard { background-position: -160px -128px; } +.ui-icon-copy { background-position: -176px -128px; } +.ui-icon-contact { background-position: -192px -128px; } +.ui-icon-image { background-position: -208px -128px; } +.ui-icon-video { background-position: -224px -128px; } +.ui-icon-script { background-position: -240px -128px; } +.ui-icon-alert { background-position: 0 -144px; } +.ui-icon-info { background-position: -16px -144px; } +.ui-icon-notice { background-position: -32px -144px; } +.ui-icon-help { background-position: -48px -144px; } +.ui-icon-check { background-position: -64px -144px; } +.ui-icon-bullet { background-position: -80px -144px; } +.ui-icon-radio-off { background-position: -96px -144px; } +.ui-icon-radio-on { background-position: -112px -144px; } +.ui-icon-pin-w { background-position: -128px -144px; } +.ui-icon-pin-s { background-position: -144px -144px; } +.ui-icon-play { background-position: 0 -160px; } +.ui-icon-pause { background-position: -16px -160px; } +.ui-icon-seek-next { background-position: -32px -160px; } +.ui-icon-seek-prev { background-position: -48px -160px; } +.ui-icon-seek-end { background-position: -64px -160px; } +.ui-icon-seek-first { background-position: -80px -160px; } +.ui-icon-stop { background-position: -96px -160px; } +.ui-icon-eject { background-position: -112px -160px; } +.ui-icon-volume-off { background-position: -128px -160px; } +.ui-icon-volume-on { background-position: -144px -160px; } +.ui-icon-power { background-position: 0 -176px; } +.ui-icon-signal-diag { background-position: -16px -176px; } +.ui-icon-signal { background-position: -32px -176px; } +.ui-icon-battery-0 { background-position: -48px -176px; } +.ui-icon-battery-1 { background-position: -64px -176px; } +.ui-icon-battery-2 { background-position: -80px -176px; } +.ui-icon-battery-3 { background-position: -96px -176px; } +.ui-icon-circle-plus { background-position: 0 -192px; } +.ui-icon-circle-minus { background-position: -16px -192px; } +.ui-icon-circle-close { background-position: -32px -192px; } +.ui-icon-circle-triangle-e { background-position: -48px -192px; } +.ui-icon-circle-triangle-s { background-position: -64px -192px; } +.ui-icon-circle-triangle-w { background-position: -80px -192px; } +.ui-icon-circle-triangle-n { background-position: -96px -192px; } +.ui-icon-circle-arrow-e { background-position: -112px -192px; } +.ui-icon-circle-arrow-s { background-position: -128px -192px; } +.ui-icon-circle-arrow-w { background-position: -144px -192px; } +.ui-icon-circle-arrow-n { background-position: -160px -192px; } +.ui-icon-circle-zoomin { background-position: -176px -192px; } +.ui-icon-circle-zoomout { background-position: -192px -192px; } +.ui-icon-circle-check { background-position: -208px -192px; } +.ui-icon-circlesmall-plus { background-position: 0 -208px; } +.ui-icon-circlesmall-minus { background-position: -16px -208px; } +.ui-icon-circlesmall-close { background-position: -32px -208px; } +.ui-icon-squaresmall-plus { background-position: -48px -208px; } +.ui-icon-squaresmall-minus { background-position: -64px -208px; } +.ui-icon-squaresmall-close { background-position: -80px -208px; } +.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } +.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } +.ui-icon-grip-solid-vertical { background-position: -32px -224px; } +.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } +.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } +.ui-icon-grip-diagonal-se { background-position: -80px -224px; } + + +/* Misc visuals +----------------------------------*/ + +/* Corner radius */ +.ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; } +.ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; } +.ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; } +.ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; } +.ui-corner-top { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; } +.ui-corner-bottom { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; } +.ui-corner-right { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; } +.ui-corner-left { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; } +.ui-corner-all { -moz-border-radius: 4px; -webkit-border-radius: 4px; } + +/* Overlays */ +.ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); } +.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -webkit-border-radius: 8px; } \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/effects.blind.js b/js2/mwEmbed/jquery/jquery.ui/ui/effects.blind.js new file mode 100644 index 0000000000..e49d96c1a0 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/effects.blind.js @@ -0,0 +1,49 @@ +/* + * jQuery UI Effects Blind 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Blind + * + * Depends: + * effects.core.js + */ +(function($) { + +$.effects.blind = function(o) { + + return this.queue(function() { + + // Create element + var el = $(this), props = ['position','top','left']; + + // Set options + var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode + var direction = o.options.direction || 'vertical'; // Default direction + + // Adjust + $.effects.save(el, props); el.show(); // Save & Show + var wrapper = $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper + var ref = (direction == 'vertical') ? 'height' : 'width'; + var distance = (direction == 'vertical') ? wrapper.height() : wrapper.width(); + if(mode == 'show') wrapper.css(ref, 0); // Shift + + // Animation + var animation = {}; + animation[ref] = mode == 'show' ? distance : 0; + + // Animate + wrapper.animate(animation, o.duration, o.options.easing, function() { + if(mode == 'hide') el.hide(); // Hide + $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore + if(o.callback) o.callback.apply(el[0], arguments); // Callback + el.dequeue(); + }); + + }); + +}; + +})(jQuery); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/effects.bounce.js b/js2/mwEmbed/jquery/jquery.ui/ui/effects.bounce.js new file mode 100644 index 0000000000..fae3d1e58b --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/effects.bounce.js @@ -0,0 +1,78 @@ +/* + * jQuery UI Effects Bounce 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Bounce + * + * Depends: + * effects.core.js + */ +(function($) { + +$.effects.bounce = function(o) { + + return this.queue(function() { + + // Create element + var el = $(this), props = ['position','top','left']; + + // Set options + var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode + var direction = o.options.direction || 'up'; // Default direction + var distance = o.options.distance || 20; // Default distance + var times = o.options.times || 5; // Default # of times + var speed = o.duration || 250; // Default speed per bounce + if (/show|hide/.test(mode)) props.push('opacity'); // Avoid touching opacity to prevent clearType and PNG issues in IE + + // Adjust + $.effects.save(el, props); el.show(); // Save & Show + $.effects.createWrapper(el); // Create Wrapper + var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left'; + var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg'; + var distance = o.options.distance || (ref == 'top' ? el.outerHeight({margin:true}) / 3 : el.outerWidth({margin:true}) / 3); + if (mode == 'show') el.css('opacity', 0).css(ref, motion == 'pos' ? -distance : distance); // Shift + if (mode == 'hide') distance = distance / (times * 2); + if (mode != 'hide') times--; + + // Animate + if (mode == 'show') { // Show Bounce + var animation = {opacity: 1}; + animation[ref] = (motion == 'pos' ? '+=' : '-=') + distance; + el.animate(animation, speed / 2, o.options.easing); + distance = distance / 2; + times--; + }; + for (var i = 0; i < times; i++) { // Bounces + var animation1 = {}, animation2 = {}; + animation1[ref] = (motion == 'pos' ? '-=' : '+=') + distance; + animation2[ref] = (motion == 'pos' ? '+=' : '-=') + distance; + el.animate(animation1, speed / 2, o.options.easing).animate(animation2, speed / 2, o.options.easing); + distance = (mode == 'hide') ? distance * 2 : distance / 2; + }; + if (mode == 'hide') { // Last Bounce + var animation = {opacity: 0}; + animation[ref] = (motion == 'pos' ? '-=' : '+=') + distance; + el.animate(animation, speed / 2, o.options.easing, function(){ + el.hide(); // Hide + $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore + if(o.callback) o.callback.apply(this, arguments); // Callback + }); + } else { + var animation1 = {}, animation2 = {}; + animation1[ref] = (motion == 'pos' ? '-=' : '+=') + distance; + animation2[ref] = (motion == 'pos' ? '+=' : '-=') + distance; + el.animate(animation1, speed / 2, o.options.easing).animate(animation2, speed / 2, o.options.easing, function(){ + $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore + if(o.callback) o.callback.apply(this, arguments); // Callback + }); + }; + el.queue('fx', function() { el.dequeue(); }); + el.dequeue(); + }); + +}; + +})(jQuery); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/effects.clip.js b/js2/mwEmbed/jquery/jquery.ui/ui/effects.clip.js new file mode 100644 index 0000000000..a14a19471a --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/effects.clip.js @@ -0,0 +1,54 @@ +/* + * jQuery UI Effects Clip 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Clip + * + * Depends: + * effects.core.js + */ +(function($) { + +$.effects.clip = function(o) { + + return this.queue(function() { + + // Create element + var el = $(this), props = ['position','top','left','height','width']; + + // Set options + var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode + var direction = o.options.direction || 'vertical'; // Default direction + + // Adjust + $.effects.save(el, props); el.show(); // Save & Show + var wrapper = $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper + var animate = el[0].tagName == 'IMG' ? wrapper : el; + var ref = { + size: (direction == 'vertical') ? 'height' : 'width', + position: (direction == 'vertical') ? 'top' : 'left' + }; + var distance = (direction == 'vertical') ? animate.height() : animate.width(); + if(mode == 'show') { animate.css(ref.size, 0); animate.css(ref.position, distance / 2); } // Shift + + // Animation + var animation = {}; + animation[ref.size] = mode == 'show' ? distance : 0; + animation[ref.position] = mode == 'show' ? 0 : distance / 2; + + // Animate + animate.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() { + if(mode == 'hide') el.hide(); // Hide + $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore + if(o.callback) o.callback.apply(el[0], arguments); // Callback + el.dequeue(); + }}); + + }); + +}; + +})(jQuery); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/effects.core.js b/js2/mwEmbed/jquery/jquery.ui/ui/effects.core.js new file mode 100644 index 0000000000..c52a312aa7 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/effects.core.js @@ -0,0 +1,543 @@ +/* + * jQuery UI Effects 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/ + */ +;jQuery.effects || (function($) { + +$.effects = { + version: "1.7.1", + + // Saves a set of properties in a data storage + save: function(element, set) { + for(var i=0; i < set.length; i++) { + if(set[i] !== null) element.data("ec.storage."+set[i], element[0].style[set[i]]); + } + }, + + // Restores a set of previously saved properties from a data storage + restore: function(element, set) { + for(var i=0; i < set.length; i++) { + if(set[i] !== null) element.css(set[i], element.data("ec.storage."+set[i])); + } + }, + + setMode: function(el, mode) { + if (mode == 'toggle') mode = el.is(':hidden') ? 'show' : 'hide'; // Set for toggle + return mode; + }, + + getBaseline: function(origin, original) { // Translates a [top,left] array into a baseline value + // this should be a little more flexible in the future to handle a string & hash + var y, x; + switch (origin[0]) { + case 'top': y = 0; break; + case 'middle': y = 0.5; break; + case 'bottom': y = 1; break; + default: y = origin[0] / original.height; + }; + switch (origin[1]) { + case 'left': x = 0; break; + case 'center': x = 0.5; break; + case 'right': x = 1; break; + default: x = origin[1] / original.width; + }; + return {x: x, y: y}; + }, + + // Wraps the element around a wrapper that copies position properties + createWrapper: function(element) { + + //if the element is already wrapped, return it + if (element.parent().is('.ui-effects-wrapper')) + return element.parent(); + + //Cache width,height and float properties of the element, and create a wrapper around it + var props = { width: element.outerWidth(true), height: element.outerHeight(true), 'float': element.css('float') }; + element.wrap('
    '); + var wrapper = element.parent(); + + //Transfer the positioning of the element to the wrapper + if (element.css('position') == 'static') { + wrapper.css({ position: 'relative' }); + element.css({ position: 'relative'} ); + } else { + var top = element.css('top'); if(isNaN(parseInt(top,10))) top = 'auto'; + var left = element.css('left'); if(isNaN(parseInt(left,10))) left = 'auto'; + wrapper.css({ position: element.css('position'), top: top, left: left, zIndex: element.css('z-index') }).show(); + element.css({position: 'relative', top: 0, left: 0 }); + } + + wrapper.css(props); + return wrapper; + }, + + removeWrapper: function(element) { + if (element.parent().is('.ui-effects-wrapper')) + return element.parent().replaceWith(element); + return element; + }, + + setTransition: function(element, list, factor, value) { + value = value || {}; + $.each(list, function(i, x){ + unit = element.cssUnit(x); + if (unit[0] > 0) value[x] = unit[0] * factor + unit[1]; + }); + return value; + }, + + //Base function to animate from one class to another in a seamless transition + animateClass: function(value, duration, easing, callback) { + + var cb = (typeof easing == "function" ? easing : (callback ? callback : null)); + var ea = (typeof easing == "string" ? easing : null); + + return this.each(function() { + + var offset = {}; var that = $(this); var oldStyleAttr = that.attr("style") || ''; + if(typeof oldStyleAttr == 'object') oldStyleAttr = oldStyleAttr["cssText"]; /* Stupidly in IE, style is a object.. */ + if(value.toggle) { that.hasClass(value.toggle) ? value.remove = value.toggle : value.add = value.toggle; } + + //Let's get a style offset + var oldStyle = $.extend({}, (document.defaultView ? document.defaultView.getComputedStyle(this,null) : this.currentStyle)); + if(value.add) that.addClass(value.add); if(value.remove) that.removeClass(value.remove); + var newStyle = $.extend({}, (document.defaultView ? document.defaultView.getComputedStyle(this,null) : this.currentStyle)); + if(value.add) that.removeClass(value.add); if(value.remove) that.addClass(value.remove); + + // The main function to form the object for animation + for(var n in newStyle) { + if( typeof newStyle[n] != "function" && newStyle[n] /* No functions and null properties */ + && n.indexOf("Moz") == -1 && n.indexOf("length") == -1 /* No mozilla spezific render properties. */ + && newStyle[n] != oldStyle[n] /* Only values that have changed are used for the animation */ + && (n.match(/color/i) || (!n.match(/color/i) && !isNaN(parseInt(newStyle[n],10)))) /* Only things that can be parsed to integers or colors */ + && (oldStyle.position != "static" || (oldStyle.position == "static" && !n.match(/left|top|bottom|right/))) /* No need for positions when dealing with static positions */ + ) offset[n] = newStyle[n]; + } + + that.animate(offset, duration, ea, function() { // Animate the newly constructed offset object + // Change style attribute back to original. For stupid IE, we need to clear the damn object. + if(typeof $(this).attr("style") == 'object') { $(this).attr("style")["cssText"] = ""; $(this).attr("style")["cssText"] = oldStyleAttr; } else $(this).attr("style", oldStyleAttr); + if(value.add) $(this).addClass(value.add); if(value.remove) $(this).removeClass(value.remove); + if(cb) cb.apply(this, arguments); + }); + + }); + } +}; + + +function _normalizeArguments(a, m) { + + var o = a[1] && a[1].constructor == Object ? a[1] : {}; if(m) o.mode = m; + var speed = a[1] && a[1].constructor != Object ? a[1] : (o.duration ? o.duration : a[2]); //either comes from options.duration or the secon/third argument + speed = $.fx.off ? 0 : typeof speed === "number" ? speed : $.fx.speeds[speed] || $.fx.speeds._default; + var callback = o.callback || ( $.isFunction(a[1]) && a[1] ) || ( $.isFunction(a[2]) && a[2] ) || ( $.isFunction(a[3]) && a[3] ); + + return [a[0], o, speed, callback]; + +} + +//Extend the methods of jQuery +$.fn.extend({ + + //Save old methods + _show: $.fn.show, + _hide: $.fn.hide, + __toggle: $.fn.toggle, + _addClass: $.fn.addClass, + _removeClass: $.fn.removeClass, + _toggleClass: $.fn.toggleClass, + + // New effect methods + effect: function(fx, options, speed, callback) { + return $.effects[fx] ? $.effects[fx].call(this, {method: fx, options: options || {}, duration: speed, callback: callback }) : null; + }, + + show: function() { + if(!arguments[0] || (arguments[0].constructor == Number || (/(slow|normal|fast)/).test(arguments[0]))) + return this._show.apply(this, arguments); + else { + return this.effect.apply(this, _normalizeArguments(arguments, 'show')); + } + }, + + hide: function() { + if(!arguments[0] || (arguments[0].constructor == Number || (/(slow|normal|fast)/).test(arguments[0]))) + return this._hide.apply(this, arguments); + else { + return this.effect.apply(this, _normalizeArguments(arguments, 'hide')); + } + }, + + toggle: function(){ + if(!arguments[0] || (arguments[0].constructor == Number || (/(slow|normal|fast)/).test(arguments[0])) || (arguments[0].constructor == Function)) + return this.__toggle.apply(this, arguments); + else { + return this.effect.apply(this, _normalizeArguments(arguments, 'toggle')); + } + }, + + addClass: function(classNames, speed, easing, callback) { + return speed ? $.effects.animateClass.apply(this, [{ add: classNames },speed,easing,callback]) : this._addClass(classNames); + }, + removeClass: function(classNames,speed,easing,callback) { + return speed ? $.effects.animateClass.apply(this, [{ remove: classNames },speed,easing,callback]) : this._removeClass(classNames); + }, + toggleClass: function(classNames,speed,easing,callback) { + return ( (typeof speed !== "boolean") && speed ) ? $.effects.animateClass.apply(this, [{ toggle: classNames },speed,easing,callback]) : this._toggleClass(classNames, speed); + }, + morph: function(remove,add,speed,easing,callback) { + return $.effects.animateClass.apply(this, [{ add: add, remove: remove },speed,easing,callback]); + }, + switchClass: function() { + return this.morph.apply(this, arguments); + }, + + // helper functions + cssUnit: function(key) { + var style = this.css(key), val = []; + $.each( ['em','px','%','pt'], function(i, unit){ + if(style.indexOf(unit) > 0) + val = [parseFloat(style), unit]; + }); + return val; + } +}); + +/* + * jQuery Color Animations + * Copyright 2007 John Resig + * Released under the MIT and GPL licenses. + */ + +// We override the animation for all of these color styles +$.each(['backgroundColor', 'borderBottomColor', 'borderLeftColor', 'borderRightColor', 'borderTopColor', 'color', 'outlineColor'], function(i,attr){ + $.fx.step[attr] = function(fx) { + if ( fx.state == 0 ) { + fx.start = getColor( fx.elem, attr ); + fx.end = getRGB( fx.end ); + } + + fx.elem.style[attr] = "rgb(" + [ + Math.max(Math.min( parseInt((fx.pos * (fx.end[0] - fx.start[0])) + fx.start[0],10), 255), 0), + Math.max(Math.min( parseInt((fx.pos * (fx.end[1] - fx.start[1])) + fx.start[1],10), 255), 0), + Math.max(Math.min( parseInt((fx.pos * (fx.end[2] - fx.start[2])) + fx.start[2],10), 255), 0) + ].join(",") + ")"; + }; +}); + +// Color Conversion functions from highlightFade +// By Blair Mitchelmore +// http://jquery.offput.ca/highlightFade/ + +// Parse strings looking for color tuples [255,255,255] +function getRGB(color) { + var result; + + // Check if we're already dealing with an array of colors + if ( color && color.constructor == Array && color.length == 3 ) + return color; + + // Look for rgb(num,num,num) + if (result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color)) + return [parseInt(result[1],10), parseInt(result[2],10), parseInt(result[3],10)]; + + // Look for rgb(num%,num%,num%) + if (result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(color)) + return [parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55]; + + // Look for #a0b1c2 + if (result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color)) + return [parseInt(result[1],16), parseInt(result[2],16), parseInt(result[3],16)]; + + // Look for #fff + if (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color)) + return [parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16)]; + + // Look for rgba(0, 0, 0, 0) == transparent in Safari 3 + if (result = /rgba\(0, 0, 0, 0\)/.exec(color)) + return colors['transparent']; + + // Otherwise, we're most likely dealing with a named color + return colors[$.trim(color).toLowerCase()]; +} + +function getColor(elem, attr) { + var color; + + do { + color = $.curCSS(elem, attr); + + // Keep going until we find an element that has color, or we hit the body + if ( color != '' && color != 'transparent' || $.nodeName(elem, "body") ) + break; + + attr = "backgroundColor"; + } while ( elem = elem.parentNode ); + + return getRGB(color); +}; + +// Some named colors to work with +// From Interface by Stefan Petre +// http://interface.eyecon.ro/ + +var colors = { + aqua:[0,255,255], + azure:[240,255,255], + beige:[245,245,220], + black:[0,0,0], + blue:[0,0,255], + brown:[165,42,42], + cyan:[0,255,255], + darkblue:[0,0,139], + darkcyan:[0,139,139], + darkgrey:[169,169,169], + darkgreen:[0,100,0], + darkkhaki:[189,183,107], + darkmagenta:[139,0,139], + darkolivegreen:[85,107,47], + darkorange:[255,140,0], + darkorchid:[153,50,204], + darkred:[139,0,0], + darksalmon:[233,150,122], + darkviolet:[148,0,211], + fuchsia:[255,0,255], + gold:[255,215,0], + green:[0,128,0], + indigo:[75,0,130], + khaki:[240,230,140], + lightblue:[173,216,230], + lightcyan:[224,255,255], + lightgreen:[144,238,144], + lightgrey:[211,211,211], + lightpink:[255,182,193], + lightyellow:[255,255,224], + lime:[0,255,0], + magenta:[255,0,255], + maroon:[128,0,0], + navy:[0,0,128], + olive:[128,128,0], + orange:[255,165,0], + pink:[255,192,203], + purple:[128,0,128], + violet:[128,0,128], + red:[255,0,0], + silver:[192,192,192], + white:[255,255,255], + yellow:[255,255,0], + transparent: [255,255,255] +}; + +/* + * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/ + * + * Uses the built in easing capabilities added In jQuery 1.1 + * to offer multiple easing options + * + * TERMS OF USE - jQuery Easing + * + * Open source under the BSD License. + * + * Copyright 2008 George McGinley Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the author nor the names of contributors may be used to endorse + * or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * +*/ + +// t: current time, b: begInnIng value, c: change In value, d: duration +$.easing.jswing = $.easing.swing; + +$.extend($.easing, +{ + def: 'easeOutQuad', + swing: function (x, t, b, c, d) { + //alert($.easing.default); + return $.easing[$.easing.def](x, t, b, c, d); + }, + easeInQuad: function (x, t, b, c, d) { + return c*(t/=d)*t + b; + }, + easeOutQuad: function (x, t, b, c, d) { + return -c *(t/=d)*(t-2) + b; + }, + easeInOutQuad: function (x, t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t + b; + return -c/2 * ((--t)*(t-2) - 1) + b; + }, + easeInCubic: function (x, t, b, c, d) { + return c*(t/=d)*t*t + b; + }, + easeOutCubic: function (x, t, b, c, d) { + return c*((t=t/d-1)*t*t + 1) + b; + }, + easeInOutCubic: function (x, t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t*t + b; + return c/2*((t-=2)*t*t + 2) + b; + }, + easeInQuart: function (x, t, b, c, d) { + return c*(t/=d)*t*t*t + b; + }, + easeOutQuart: function (x, t, b, c, d) { + return -c * ((t=t/d-1)*t*t*t - 1) + b; + }, + easeInOutQuart: function (x, t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t*t*t + b; + return -c/2 * ((t-=2)*t*t*t - 2) + b; + }, + easeInQuint: function (x, t, b, c, d) { + return c*(t/=d)*t*t*t*t + b; + }, + easeOutQuint: function (x, t, b, c, d) { + return c*((t=t/d-1)*t*t*t*t + 1) + b; + }, + easeInOutQuint: function (x, t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b; + return c/2*((t-=2)*t*t*t*t + 2) + b; + }, + easeInSine: function (x, t, b, c, d) { + return -c * Math.cos(t/d * (Math.PI/2)) + c + b; + }, + easeOutSine: function (x, t, b, c, d) { + return c * Math.sin(t/d * (Math.PI/2)) + b; + }, + easeInOutSine: function (x, t, b, c, d) { + return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b; + }, + easeInExpo: function (x, t, b, c, d) { + return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b; + }, + easeOutExpo: function (x, t, b, c, d) { + return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b; + }, + easeInOutExpo: function (x, t, b, c, d) { + if (t==0) return b; + if (t==d) return b+c; + if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b; + return c/2 * (-Math.pow(2, -10 * --t) + 2) + b; + }, + easeInCirc: function (x, t, b, c, d) { + return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b; + }, + easeOutCirc: function (x, t, b, c, d) { + return c * Math.sqrt(1 - (t=t/d-1)*t) + b; + }, + easeInOutCirc: function (x, t, b, c, d) { + if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b; + return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b; + }, + easeInElastic: function (x, t, b, c, d) { + var s=1.70158;var p=0;var a=c; + if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; + if (a < Math.abs(c)) { a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (c/a); + return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; + }, + easeOutElastic: function (x, t, b, c, d) { + var s=1.70158;var p=0;var a=c; + if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; + if (a < Math.abs(c)) { a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (c/a); + return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b; + }, + easeInOutElastic: function (x, t, b, c, d) { + var s=1.70158;var p=0;var a=c; + if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5); + if (a < Math.abs(c)) { a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (c/a); + if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; + return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b; + }, + easeInBack: function (x, t, b, c, d, s) { + if (s == undefined) s = 1.70158; + return c*(t/=d)*t*((s+1)*t - s) + b; + }, + easeOutBack: function (x, t, b, c, d, s) { + if (s == undefined) s = 1.70158; + return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b; + }, + easeInOutBack: function (x, t, b, c, d, s) { + if (s == undefined) s = 1.70158; + if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b; + return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b; + }, + easeInBounce: function (x, t, b, c, d) { + return c - $.easing.easeOutBounce (x, d-t, 0, c, d) + b; + }, + easeOutBounce: function (x, t, b, c, d) { + if ((t/=d) < (1/2.75)) { + return c*(7.5625*t*t) + b; + } else if (t < (2/2.75)) { + return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b; + } else if (t < (2.5/2.75)) { + return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b; + } else { + return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b; + } + }, + easeInOutBounce: function (x, t, b, c, d) { + if (t < d/2) return $.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b; + return $.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b; + } +}); + +/* + * + * TERMS OF USE - EASING EQUATIONS + * + * Open source under the BSD License. + * + * Copyright 2001 Robert Penner + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the author nor the names of contributors may be used to endorse + * or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +})(jQuery); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/effects.drop.js b/js2/mwEmbed/jquery/jquery.ui/ui/effects.drop.js new file mode 100644 index 0000000000..2a3ffd4848 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/effects.drop.js @@ -0,0 +1,50 @@ +/* + * jQuery UI Effects Drop 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Drop + * + * Depends: + * effects.core.js + */ +(function($) { + +$.effects.drop = function(o) { + + return this.queue(function() { + + // Create element + var el = $(this), props = ['position','top','left','opacity']; + + // Set options + var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode + var direction = o.options.direction || 'left'; // Default Direction + + // Adjust + $.effects.save(el, props); el.show(); // Save & Show + $.effects.createWrapper(el); // Create Wrapper + var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left'; + var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg'; + var distance = o.options.distance || (ref == 'top' ? el.outerHeight({margin:true}) / 2 : el.outerWidth({margin:true}) / 2); + if (mode == 'show') el.css('opacity', 0).css(ref, motion == 'pos' ? -distance : distance); // Shift + + // Animation + var animation = {opacity: mode == 'show' ? 1 : 0}; + animation[ref] = (mode == 'show' ? (motion == 'pos' ? '+=' : '-=') : (motion == 'pos' ? '-=' : '+=')) + distance; + + // Animate + el.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() { + if(mode == 'hide') el.hide(); // Hide + $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore + if(o.callback) o.callback.apply(this, arguments); // Callback + el.dequeue(); + }}); + + }); + +}; + +})(jQuery); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/effects.explode.js b/js2/mwEmbed/jquery/jquery.ui/ui/effects.explode.js new file mode 100644 index 0000000000..5bfc85460c --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/effects.explode.js @@ -0,0 +1,79 @@ +/* + * jQuery UI Effects Explode 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Explode + * + * Depends: + * effects.core.js + */ +(function($) { + +$.effects.explode = function(o) { + + return this.queue(function() { + + var rows = o.options.pieces ? Math.round(Math.sqrt(o.options.pieces)) : 3; + var cells = o.options.pieces ? Math.round(Math.sqrt(o.options.pieces)) : 3; + + o.options.mode = o.options.mode == 'toggle' ? ($(this).is(':visible') ? 'hide' : 'show') : o.options.mode; + var el = $(this).show().css('visibility', 'hidden'); + var offset = el.offset(); + + //Substract the margins - not fixing the problem yet. + offset.top -= parseInt(el.css("marginTop"),10) || 0; + offset.left -= parseInt(el.css("marginLeft"),10) || 0; + + var width = el.outerWidth(true); + var height = el.outerHeight(true); + + for(var i=0;i
    ') + .css({ + position: 'absolute', + visibility: 'visible', + left: -j*(width/cells), + top: -i*(height/rows) + }) + .parent() + .addClass('ui-effects-explode') + .css({ + position: 'absolute', + overflow: 'hidden', + width: width/cells, + height: height/rows, + left: offset.left + j*(width/cells) + (o.options.mode == 'show' ? (j-Math.floor(cells/2))*(width/cells) : 0), + top: offset.top + i*(height/rows) + (o.options.mode == 'show' ? (i-Math.floor(rows/2))*(height/rows) : 0), + opacity: o.options.mode == 'show' ? 0 : 1 + }).animate({ + left: offset.left + j*(width/cells) + (o.options.mode == 'show' ? 0 : (j-Math.floor(cells/2))*(width/cells)), + top: offset.top + i*(height/rows) + (o.options.mode == 'show' ? 0 : (i-Math.floor(rows/2))*(height/rows)), + opacity: o.options.mode == 'show' ? 1 : 0 + }, o.duration || 500); + } + } + + // Set a timeout, to call the callback approx. when the other animations have finished + setTimeout(function() { + + o.options.mode == 'show' ? el.css({ visibility: 'visible' }) : el.css({ visibility: 'visible' }).hide(); + if(o.callback) o.callback.apply(el[0]); // Callback + el.dequeue(); + + $('div.ui-effects-explode').remove(); + + }, o.duration || 500); + + + }); + +}; + +})(jQuery); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/effects.fold.js b/js2/mwEmbed/jquery/jquery.ui/ui/effects.fold.js new file mode 100644 index 0000000000..77f8a9dfdb --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/effects.fold.js @@ -0,0 +1,56 @@ +/* + * jQuery UI Effects Fold 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Fold + * + * Depends: + * effects.core.js + */ +(function($) { + +$.effects.fold = function(o) { + + return this.queue(function() { + + // Create element + var el = $(this), props = ['position','top','left']; + + // Set options + var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode + var size = o.options.size || 15; // Default fold size + var horizFirst = !(!o.options.horizFirst); // Ensure a boolean value + var duration = o.duration ? o.duration / 2 : $.fx.speeds._default / 2; + + // Adjust + $.effects.save(el, props); el.show(); // Save & Show + var wrapper = $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper + var widthFirst = ((mode == 'show') != horizFirst); + var ref = widthFirst ? ['width', 'height'] : ['height', 'width']; + var distance = widthFirst ? [wrapper.width(), wrapper.height()] : [wrapper.height(), wrapper.width()]; + var percent = /([0-9]+)%/.exec(size); + if(percent) size = parseInt(percent[1],10) / 100 * distance[mode == 'hide' ? 0 : 1]; + if(mode == 'show') wrapper.css(horizFirst ? {height: 0, width: size} : {height: size, width: 0}); // Shift + + // Animation + var animation1 = {}, animation2 = {}; + animation1[ref[0]] = mode == 'show' ? distance[0] : size; + animation2[ref[1]] = mode == 'show' ? distance[1] : 0; + + // Animate + wrapper.animate(animation1, duration, o.options.easing) + .animate(animation2, duration, o.options.easing, function() { + if(mode == 'hide') el.hide(); // Hide + $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore + if(o.callback) o.callback.apply(el[0], arguments); // Callback + el.dequeue(); + }); + + }); + +}; + +})(jQuery); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/effects.highlight.js b/js2/mwEmbed/jquery/jquery.ui/ui/effects.highlight.js new file mode 100644 index 0000000000..680bacd7d6 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/effects.highlight.js @@ -0,0 +1,48 @@ +/* + * jQuery UI Effects Highlight 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Highlight + * + * Depends: + * effects.core.js + */ +(function($) { + +$.effects.highlight = function(o) { + + return this.queue(function() { + + // Create element + var el = $(this), props = ['backgroundImage','backgroundColor','opacity']; + + // Set options + var mode = $.effects.setMode(el, o.options.mode || 'show'); // Set Mode + var color = o.options.color || "#ffff99"; // Default highlight color + var oldColor = el.css("backgroundColor"); + + // Adjust + $.effects.save(el, props); el.show(); // Save & Show + el.css({backgroundImage: 'none', backgroundColor: color}); // Shift + + // Animation + var animation = {backgroundColor: oldColor }; + if (mode == "hide") animation['opacity'] = 0; + + // Animate + el.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() { + if(mode == "hide") el.hide(); + $.effects.restore(el, props); + if (mode == "show" && $.browser.msie) this.style.removeAttribute('filter'); + if(o.callback) o.callback.apply(this, arguments); + el.dequeue(); + }}); + + }); + +}; + +})(jQuery); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/effects.pulsate.js b/js2/mwEmbed/jquery/jquery.ui/ui/effects.pulsate.js new file mode 100644 index 0000000000..e845634605 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/effects.pulsate.js @@ -0,0 +1,56 @@ +/* + * jQuery UI Effects Pulsate 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Pulsate + * + * Depends: + * effects.core.js + */ +(function($) { + +$.effects.pulsate = function(o) { + + return this.queue(function() { + + // Create element + var el = $(this); + + // Set options + var mode = $.effects.setMode(el, o.options.mode || 'show'); // Set Mode + var times = o.options.times || 5; // Default # of times + var duration = o.duration ? o.duration / 2 : $.fx.speeds._default / 2; + + // Adjust + if (mode == 'hide') times--; + if (el.is(':hidden')) { // Show fadeIn + el.css('opacity', 0); + el.show(); // Show + el.animate({opacity: 1}, duration, o.options.easing); + times = times-2; + } + + // Animate + for (var i = 0; i < times; i++) { // Pulsate + el.animate({opacity: 0}, duration, o.options.easing).animate({opacity: 1}, duration, o.options.easing); + }; + if (mode == 'hide') { // Last Pulse + el.animate({opacity: 0}, duration, o.options.easing, function(){ + el.hide(); // Hide + if(o.callback) o.callback.apply(this, arguments); // Callback + }); + } else { + el.animate({opacity: 0}, duration, o.options.easing).animate({opacity: 1}, duration, o.options.easing, function(){ + if(o.callback) o.callback.apply(this, arguments); // Callback + }); + }; + el.queue('fx', function() { el.dequeue(); }); + el.dequeue(); + }); + +}; + +})(jQuery); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/effects.scale.js b/js2/mwEmbed/jquery/jquery.ui/ui/effects.scale.js new file mode 100644 index 0000000000..e02dca0869 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/effects.scale.js @@ -0,0 +1,180 @@ +/* + * jQuery UI Effects Scale 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Scale + * + * Depends: + * effects.core.js + */ +(function($) { + +$.effects.puff = function(o) { + + return this.queue(function() { + + // Create element + var el = $(this); + + // Set options + var options = $.extend(true, {}, o.options); + var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode + var percent = parseInt(o.options.percent,10) || 150; // Set default puff percent + options.fade = true; // It's not a puff if it doesn't fade! :) + var original = {height: el.height(), width: el.width()}; // Save original + + // Adjust + var factor = percent / 100; + el.from = (mode == 'hide') ? original : {height: original.height * factor, width: original.width * factor}; + + // Animation + options.from = el.from; + options.percent = (mode == 'hide') ? percent : 100; + options.mode = mode; + + // Animate + el.effect('scale', options, o.duration, o.callback); + el.dequeue(); + }); + +}; + +$.effects.scale = function(o) { + + return this.queue(function() { + + // Create element + var el = $(this); + + // Set options + var options = $.extend(true, {}, o.options); + var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode + var percent = parseInt(o.options.percent,10) || (parseInt(o.options.percent,10) == 0 ? 0 : (mode == 'hide' ? 0 : 100)); // Set default scaling percent + var direction = o.options.direction || 'both'; // Set default axis + var origin = o.options.origin; // The origin of the scaling + if (mode != 'effect') { // Set default origin and restore for show/hide + options.origin = origin || ['middle','center']; + options.restore = true; + } + var original = {height: el.height(), width: el.width()}; // Save original + el.from = o.options.from || (mode == 'show' ? {height: 0, width: 0} : original); // Default from state + + // Adjust + var factor = { // Set scaling factor + y: direction != 'horizontal' ? (percent / 100) : 1, + x: direction != 'vertical' ? (percent / 100) : 1 + }; + el.to = {height: original.height * factor.y, width: original.width * factor.x}; // Set to state + + if (o.options.fade) { // Fade option to support puff + if (mode == 'show') {el.from.opacity = 0; el.to.opacity = 1;}; + if (mode == 'hide') {el.from.opacity = 1; el.to.opacity = 0;}; + }; + + // Animation + options.from = el.from; options.to = el.to; options.mode = mode; + + // Animate + el.effect('size', options, o.duration, o.callback); + el.dequeue(); + }); + +}; + +$.effects.size = function(o) { + + return this.queue(function() { + + // Create element + var el = $(this), props = ['position','top','left','width','height','overflow','opacity']; + var props1 = ['position','top','left','overflow','opacity']; // Always restore + var props2 = ['width','height','overflow']; // Copy for children + var cProps = ['fontSize']; + var vProps = ['borderTopWidth', 'borderBottomWidth', 'paddingTop', 'paddingBottom']; + var hProps = ['borderLeftWidth', 'borderRightWidth', 'paddingLeft', 'paddingRight']; + + // Set options + var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode + var restore = o.options.restore || false; // Default restore + var scale = o.options.scale || 'both'; // Default scale mode + var origin = o.options.origin; // The origin of the sizing + var original = {height: el.height(), width: el.width()}; // Save original + el.from = o.options.from || original; // Default from state + el.to = o.options.to || original; // Default to state + // Adjust + if (origin) { // Calculate baseline shifts + var baseline = $.effects.getBaseline(origin, original); + el.from.top = (original.height - el.from.height) * baseline.y; + el.from.left = (original.width - el.from.width) * baseline.x; + el.to.top = (original.height - el.to.height) * baseline.y; + el.to.left = (original.width - el.to.width) * baseline.x; + }; + var factor = { // Set scaling factor + from: {y: el.from.height / original.height, x: el.from.width / original.width}, + to: {y: el.to.height / original.height, x: el.to.width / original.width} + }; + if (scale == 'box' || scale == 'both') { // Scale the css box + if (factor.from.y != factor.to.y) { // Vertical props scaling + props = props.concat(vProps); + el.from = $.effects.setTransition(el, vProps, factor.from.y, el.from); + el.to = $.effects.setTransition(el, vProps, factor.to.y, el.to); + }; + if (factor.from.x != factor.to.x) { // Horizontal props scaling + props = props.concat(hProps); + el.from = $.effects.setTransition(el, hProps, factor.from.x, el.from); + el.to = $.effects.setTransition(el, hProps, factor.to.x, el.to); + }; + }; + if (scale == 'content' || scale == 'both') { // Scale the content + if (factor.from.y != factor.to.y) { // Vertical props scaling + props = props.concat(cProps); + el.from = $.effects.setTransition(el, cProps, factor.from.y, el.from); + el.to = $.effects.setTransition(el, cProps, factor.to.y, el.to); + }; + }; + $.effects.save(el, restore ? props : props1); el.show(); // Save & Show + $.effects.createWrapper(el); // Create Wrapper + el.css('overflow','hidden').css(el.from); // Shift + + // Animate + if (scale == 'content' || scale == 'both') { // Scale the children + vProps = vProps.concat(['marginTop','marginBottom']).concat(cProps); // Add margins/font-size + hProps = hProps.concat(['marginLeft','marginRight']); // Add margins + props2 = props.concat(vProps).concat(hProps); // Concat + el.find("*[width]").each(function(){ + child = $(this); + if (restore) $.effects.save(child, props2); + var c_original = {height: child.height(), width: child.width()}; // Save original + child.from = {height: c_original.height * factor.from.y, width: c_original.width * factor.from.x}; + child.to = {height: c_original.height * factor.to.y, width: c_original.width * factor.to.x}; + if (factor.from.y != factor.to.y) { // Vertical props scaling + child.from = $.effects.setTransition(child, vProps, factor.from.y, child.from); + child.to = $.effects.setTransition(child, vProps, factor.to.y, child.to); + }; + if (factor.from.x != factor.to.x) { // Horizontal props scaling + child.from = $.effects.setTransition(child, hProps, factor.from.x, child.from); + child.to = $.effects.setTransition(child, hProps, factor.to.x, child.to); + }; + child.css(child.from); // Shift children + child.animate(child.to, o.duration, o.options.easing, function(){ + if (restore) $.effects.restore(child, props2); // Restore children + }); // Animate children + }); + }; + + // Animate + el.animate(el.to, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() { + if(mode == 'hide') el.hide(); // Hide + $.effects.restore(el, restore ? props : props1); $.effects.removeWrapper(el); // Restore + if(o.callback) o.callback.apply(this, arguments); // Callback + el.dequeue(); + }}); + + }); + +}; + +})(jQuery); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/effects.shake.js b/js2/mwEmbed/jquery/jquery.ui/ui/effects.shake.js new file mode 100644 index 0000000000..3bcf822da2 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/effects.shake.js @@ -0,0 +1,57 @@ +/* + * jQuery UI Effects Shake 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Shake + * + * Depends: + * effects.core.js + */ +(function($) { + +$.effects.shake = function(o) { + + return this.queue(function() { + + // Create element + var el = $(this), props = ['position','top','left']; + + // Set options + var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode + var direction = o.options.direction || 'left'; // Default direction + var distance = o.options.distance || 20; // Default distance + var times = o.options.times || 3; // Default # of times + var speed = o.duration || o.options.duration || 140; // Default speed per shake + + // Adjust + $.effects.save(el, props); el.show(); // Save & Show + $.effects.createWrapper(el); // Create Wrapper + var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left'; + var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg'; + + // Animation + var animation = {}, animation1 = {}, animation2 = {}; + animation[ref] = (motion == 'pos' ? '-=' : '+=') + distance; + animation1[ref] = (motion == 'pos' ? '+=' : '-=') + distance * 2; + animation2[ref] = (motion == 'pos' ? '-=' : '+=') + distance * 2; + + // Animate + el.animate(animation, speed, o.options.easing); + for (var i = 1; i < times; i++) { // Shakes + el.animate(animation1, speed, o.options.easing).animate(animation2, speed, o.options.easing); + }; + el.animate(animation1, speed, o.options.easing). + animate(animation, speed / 2, o.options.easing, function(){ // Last shake + $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore + if(o.callback) o.callback.apply(this, arguments); // Callback + }); + el.queue('fx', function() { el.dequeue(); }); + el.dequeue(); + }); + +}; + +})(jQuery); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/effects.slide.js b/js2/mwEmbed/jquery/jquery.ui/ui/effects.slide.js new file mode 100644 index 0000000000..1085ae62de --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/effects.slide.js @@ -0,0 +1,50 @@ +/* + * jQuery UI Effects Slide 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Slide + * + * Depends: + * effects.core.js + */ +(function($) { + +$.effects.slide = function(o) { + + return this.queue(function() { + + // Create element + var el = $(this), props = ['position','top','left']; + + // Set options + var mode = $.effects.setMode(el, o.options.mode || 'show'); // Set Mode + var direction = o.options.direction || 'left'; // Default Direction + + // Adjust + $.effects.save(el, props); el.show(); // Save & Show + $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper + var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left'; + var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg'; + var distance = o.options.distance || (ref == 'top' ? el.outerHeight({margin:true}) : el.outerWidth({margin:true})); + if (mode == 'show') el.css(ref, motion == 'pos' ? -distance : distance); // Shift + + // Animation + var animation = {}; + animation[ref] = (mode == 'show' ? (motion == 'pos' ? '+=' : '-=') : (motion == 'pos' ? '-=' : '+=')) + distance; + + // Animate + el.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() { + if(mode == 'hide') el.hide(); // Hide + $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore + if(o.callback) o.callback.apply(this, arguments); // Callback + el.dequeue(); + }}); + + }); + +}; + +})(jQuery); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/effects.transfer.js b/js2/mwEmbed/jquery/jquery.ui/ui/effects.transfer.js new file mode 100644 index 0000000000..b042cfd8d5 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/effects.transfer.js @@ -0,0 +1,45 @@ +/* + * jQuery UI Effects Transfer 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Transfer + * + * Depends: + * effects.core.js + */ +(function($) { + +$.effects.transfer = function(o) { + return this.queue(function() { + var elem = $(this), + target = $(o.options.to), + endPosition = target.offset(), + animation = { + top: endPosition.top, + left: endPosition.left, + height: target.innerHeight(), + width: target.innerWidth() + }, + startPosition = elem.offset(), + transfer = $('
    ') + .appendTo(document.body) + .addClass(o.options.className) + .css({ + top: startPosition.top, + left: startPosition.left, + height: elem.innerHeight(), + width: elem.innerWidth(), + position: 'absolute' + }) + .animate(animation, o.duration, o.options.easing, function() { + transfer.remove(); + (o.callback && o.callback.apply(elem[0], arguments)); + elem.dequeue(); + }); + }); +}; + +})(jQuery); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/jquery-ui-i18n.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/jquery-ui-i18n.js new file mode 100644 index 0000000000..2d90b4f070 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/jquery-ui-i18n.js @@ -0,0 +1,771 @@ +/* Arabic Translation for jQuery UI date picker plugin. */ +/* Khaled Al Horani -- koko.dw@gmail.com */ +/* خالد الحوراني -- koko.dw@gmail.com */ +/* NOTE: monthNames are the original months names and they are the Arabic names, not the new months name فبراير - يناير and there isn't any Arabic roots for these months */ +jQuery(function($){ + $.datepicker.regional['ar'] = { + closeText: 'إغلاق', + prevText: '<السابق', + nextText: 'التالي>', + currentText: 'اليوم', + monthNames: ['كانون الثاني', 'شباط', 'آذار', 'نيسان', 'آذار', 'حزيران', + 'تموز', 'آب', 'أيلول', 'تشرين الأول', 'تشرين الثاني', 'كانون الأول'], + monthNamesShort: ['1','2','3','4','5','6','7','8','9','10','11','12'], + dayNames: ['السبت', 'الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة'], + dayNamesShort: ['سبت', 'أحد', 'اثنين', 'ثلاثاء', 'أربعاء', 'خميس', 'جمعة'], + dayNamesMin: ['سبت', 'أحد', 'اثنين', 'ثلاثاء', 'أربعاء', 'خميس', 'جمعة'], + dateFormat: 'dd/mm/yy', firstDay: 0, + isRTL: true}; + $.datepicker.setDefaults($.datepicker.regional['ar']); +});/* Bulgarian initialisation for the jQuery UI date picker plugin. */ +/* Written by Stoyan Kyosev (http://svest.org). */ +jQuery(function($){ + $.datepicker.regional['bg'] = { + closeText: 'затвори', + prevText: '<назад', + nextText: 'напред>', + nextBigText: '>>', + currentText: 'днес', + monthNames: ['Януари','Февруари','Март','Април','Май','Юни', + 'Юли','Август','Септември','Октомври','Ноември','Декември'], + monthNamesShort: ['Яну','Фев','Мар','Апр','Май','Юни', + 'Юли','Авг','Сеп','Окт','Нов','Дек'], + dayNames: ['Неделя','Понеделник','Вторник','Сряда','Четвъртък','Петък','Събота'], + dayNamesShort: ['Нед','Пон','Вто','Сря','Чет','Пет','Съб'], + dayNamesMin: ['Не','По','Вт','Ср','Че','Пе','Съ'], + dateFormat: 'dd.mm.yy', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['bg']); +}); +/* Inicialitzaci� en catal� per a l'extenci� 'calendar' per jQuery. */ +/* Writers: (joan.leon@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['ca'] = { + closeText: 'Tancar', + prevText: '<Ant', + nextText: 'Seg>', + currentText: 'Avui', + monthNames: ['Gener','Febrer','Març','Abril','Maig','Juny', + 'Juliol','Agost','Setembre','Octubre','Novembre','Desembre'], + monthNamesShort: ['Gen','Feb','Mar','Abr','Mai','Jun', + 'Jul','Ago','Set','Oct','Nov','Des'], + dayNames: ['Diumenge','Dilluns','Dimarts','Dimecres','Dijous','Divendres','Dissabte'], + dayNamesShort: ['Dug','Dln','Dmt','Dmc','Djs','Dvn','Dsb'], + dayNamesMin: ['Dg','Dl','Dt','Dc','Dj','Dv','Ds'], + dateFormat: 'mm/dd/yy', firstDay: 0, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['ca']); +});/* Czech initialisation for the jQuery UI date picker plugin. */ +/* Written by Tomas Muller (tomas@tomas-muller.net). */ +jQuery(function($){ + $.datepicker.regional['cs'] = { + closeText: 'Zavřít', + prevText: '<Dříve', + nextText: 'Později>', + currentText: 'Nyní', + monthNames: ['leden','únor','březen','duben','květen','červen', + 'červenec','srpen','září','říjen','listopad','prosinec'], + monthNamesShort: ['led','úno','bře','dub','kvě','čer', + 'čvc','srp','zář','říj','lis','pro'], + dayNames: ['neděle', 'pondělí', 'úterý', 'středa', 'čtvrtek', 'pátek', 'sobota'], + dayNamesShort: ['ne', 'po', 'út', 'st', 'čt', 'pá', 'so'], + dayNamesMin: ['ne','po','út','st','čt','pá','so'], + dateFormat: 'dd.mm.yy', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['cs']); +}); +/* Danish initialisation for the jQuery UI date picker plugin. */ +/* Written by Jan Christensen ( deletestuff@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['da'] = { + closeText: 'Luk', + prevText: '<Forrige', + nextText: 'Næste>', + currentText: 'Idag', + monthNames: ['Januar','Februar','Marts','April','Maj','Juni', + 'Juli','August','September','Oktober','November','December'], + monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun', + 'Jul','Aug','Sep','Okt','Nov','Dec'], + dayNames: ['Søndag','Mandag','Tirsdag','Onsdag','Torsdag','Fredag','Lørdag'], + dayNamesShort: ['Søn','Man','Tir','Ons','Tor','Fre','Lør'], + dayNamesMin: ['Sø','Ma','Ti','On','To','Fr','Lø'], + dateFormat: 'dd-mm-yy', firstDay: 0, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['da']); +}); +/* German initialisation for the jQuery UI date picker plugin. */ +/* Written by Milian Wolff (mail@milianw.de). */ +jQuery(function($){ + $.datepicker.regional['de'] = { + closeText: 'schließen', + prevText: '<zurück', + nextText: 'Vor>', + currentText: 'heute', + monthNames: ['Januar','Februar','März','April','Mai','Juni', + 'Juli','August','September','Oktober','November','Dezember'], + monthNamesShort: ['Jan','Feb','Mär','Apr','Mai','Jun', + 'Jul','Aug','Sep','Okt','Nov','Dez'], + dayNames: ['Sonntag','Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag'], + dayNamesShort: ['So','Mo','Di','Mi','Do','Fr','Sa'], + dayNamesMin: ['So','Mo','Di','Mi','Do','Fr','Sa'], + dateFormat: 'dd.mm.yy', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['de']); +}); +/* Greek (el) initialisation for the jQuery UI date picker plugin. */ +/* Written by Alex Cicovic (http://www.alexcicovic.com) */ +jQuery(function($){ + $.datepicker.regional['el'] = { + closeText: 'Κλείσιμο', + prevText: 'Προηγούμενος', + nextText: 'Επόμενος', + currentText: 'Τρέχων Μήνας', + monthNames: ['Ιανουάριος','Φεβρουάριος','Μάρτιος','Απρίλιος','Μάιος','Ιούνιος', + 'Ιούλιος','Αύγουστος','Σεπτέμβριος','Οκτώβριος','Νοέμβριος','Δεκέμβριος'], + monthNamesShort: ['Ιαν','Φεβ','Μαρ','Απρ','Μαι','Ιουν', + 'Ιουλ','Αυγ','Σεπ','Οκτ','Νοε','Δεκ'], + dayNames: ['Κυριακή','Δευτέρα','Τρίτη','Τετάρτη','Πέμπτη','Παρασκευή','Σάββατο'], + dayNamesShort: ['Κυρ','Δευ','Τρι','Τετ','Πεμ','Παρ','Σαβ'], + dayNamesMin: ['Κυ','Δε','Τρ','Τε','Πε','Πα','Σα'], + dateFormat: 'dd/mm/yy', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['el']); +});/* Esperanto initialisation for the jQuery UI date picker plugin. */ +/* Written by Olivier M. (olivierweb@ifrance.com). */ +jQuery(function($){ + $.datepicker.regional['eo'] = { + closeText: 'Fermi', + prevText: '<Anta', + nextText: 'Sekv>', + currentText: 'Nuna', + monthNames: ['Januaro','Februaro','Marto','Aprilo','Majo','Junio', + 'Julio','AÅ­gusto','Septembro','Oktobro','Novembro','Decembro'], + monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun', + 'Jul','AÅ­g','Sep','Okt','Nov','Dec'], + dayNames: ['Dimanĉo','Lundo','Mardo','Merkredo','Ä´aÅ­do','Vendredo','Sabato'], + dayNamesShort: ['Dim','Lun','Mar','Mer','Ä´aÅ­','Ven','Sab'], + dayNamesMin: ['Di','Lu','Ma','Me','Ä´a','Ve','Sa'], + dateFormat: 'dd/mm/yy', firstDay: 0, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['eo']); +}); +/* Inicializaci�n en espa�ol para la extensi�n 'UI date picker' para jQuery. */ +/* Traducido por Vester (xvester@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['es'] = { + closeText: 'Cerrar', + prevText: '<Ant', + nextText: 'Sig>', + currentText: 'Hoy', + monthNames: ['Enero','Febrero','Marzo','Abril','Mayo','Junio', + 'Julio','Agosto','Septiembre','Octubre','Noviembre','Diciembre'], + monthNamesShort: ['Ene','Feb','Mar','Abr','May','Jun', + 'Jul','Ago','Sep','Oct','Nov','Dic'], + dayNames: ['Domingo','Lunes','Martes','Miércoles','Jueves','Viernes','Sábado'], + dayNamesShort: ['Dom','Lun','Mar','Mié','Juv','Vie','Sáb'], + dayNamesMin: ['Do','Lu','Ma','Mi','Ju','Vi','Sá'], + dateFormat: 'dd/mm/yy', firstDay: 0, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['es']); +});/* Persian (Farsi) Translation for the jQuery UI date picker plugin. */ +/* Javad Mowlanezhad -- jmowla@gmail.com */ +/* Jalali calendar should supported soon! (Its implemented but I have to test it) */ +jQuery(function($) { + $.datepicker.regional['fa'] = { + closeText: 'بستن', + prevText: '<قبلي', + nextText: 'بعدي>', + currentText: 'امروز', + monthNames: ['فروردين','ارديبهشت','خرداد','تير','مرداد','شهريور', + 'مهر','آبان','آذر','دي','بهمن','اسفند'], + monthNamesShort: ['1','2','3','4','5','6','7','8','9','10','11','12'], + dayNames: ['يکشنبه','دوشنبه','سه‌شنبه','چهارشنبه','پنجشنبه','جمعه','شنبه'], + dayNamesShort: ['ي','د','س','چ','Ù¾','ج', 'Ø´'], + dayNamesMin: ['ي','د','س','چ','Ù¾','ج', 'Ø´'], + dateFormat: 'yy/mm/dd', firstDay: 6, + isRTL: true}; + $.datepicker.setDefaults($.datepicker.regional['fa']); +});/* Finnish initialisation for the jQuery UI date picker plugin. */ +/* Written by Harri Kilpi� (harrikilpio@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['fi'] = { + closeText: 'Sulje', + prevText: '«Edellinen', + nextText: 'Seuraava»', + currentText: 'Tänään', + monthNames: ['Tammikuu','Helmikuu','Maaliskuu','Huhtikuu','Toukokuu','Kesäkuu', + 'Heinäkuu','Elokuu','Syyskuu','Lokakuu','Marraskuu','Joulukuu'], + monthNamesShort: ['Tammi','Helmi','Maalis','Huhti','Touko','Kesä', + 'Heinä','Elo','Syys','Loka','Marras','Joulu'], + dayNamesShort: ['Su','Ma','Ti','Ke','To','Pe','Su'], + dayNames: ['Sunnuntai','Maanantai','Tiistai','Keskiviikko','Torstai','Perjantai','Lauantai'], + dayNamesMin: ['Su','Ma','Ti','Ke','To','Pe','La'], + dateFormat: 'dd.mm.yy', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['fi']); +}); +/* French initialisation for the jQuery UI date picker plugin. */ +/* Written by Keith Wood (kbwood@virginbroadband.com.au) and Stéphane Nahmani (sholby@sholby.net). */ +jQuery(function($){ + $.datepicker.regional['fr'] = { + closeText: 'Fermer', + prevText: '<Préc', + nextText: 'Suiv>', + currentText: 'Courant', + monthNames: ['Janvier','Février','Mars','Avril','Mai','Juin', + 'Juillet','Août','Septembre','Octobre','Novembre','Décembre'], + monthNamesShort: ['Jan','Fév','Mar','Avr','Mai','Jun', + 'Jul','Aoû','Sep','Oct','Nov','Déc'], + dayNames: ['Dimanche','Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi'], + dayNamesShort: ['Dim','Lun','Mar','Mer','Jeu','Ven','Sam'], + dayNamesMin: ['Di','Lu','Ma','Me','Je','Ve','Sa'], + dateFormat: 'dd/mm/yy', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['fr']); +});/* Hebrew initialisation for the UI Datepicker extension. */ +/* Written by Amir Hardon (ahardon at gmail dot com). */ +jQuery(function($){ + $.datepicker.regional['he'] = { + closeText: 'סגור', + prevText: '<הקודם', + nextText: 'הבא>', + currentText: 'היום', + monthNames: ['ינואר','פברואר','מרץ','אפריל','מאי','יוני', + 'יולי','אוגוסט','ספטמבר','אוקטובר','נובמבר','דצמבר'], + monthNamesShort: ['1','2','3','4','5','6', + '7','8','9','10','11','12'], + dayNames: ['ראשון','שני','שלישי','רביעי','חמישי','שישי','שבת'], + dayNamesShort: ['א\'','ב\'','ג\'','ד\'','ה\'','ו\'','שבת'], + dayNamesMin: ['א\'','ב\'','ג\'','ד\'','ה\'','ו\'','שבת'], + dateFormat: 'dd/mm/yy', firstDay: 0, + isRTL: true}; + $.datepicker.setDefaults($.datepicker.regional['he']); +}); +/* Croatian i18n for the jQuery UI date picker plugin. */ +/* Written by Vjekoslav Nesek. */ +jQuery(function($){ + $.datepicker.regional['hr'] = { + closeText: 'Zatvori', + prevText: '<', + nextText: '>', + currentText: 'Danas', + monthNames: ['Siječanj','Veljača','Ožujak','Travanj','Svibanj','Lipani', + 'Srpanj','Kolovoz','Rujan','Listopad','Studeni','Prosinac'], + monthNamesShort: ['Sij','Velj','Ožu','Tra','Svi','Lip', + 'Srp','Kol','Ruj','Lis','Stu','Pro'], + dayNames: ['Nedjalja','Ponedjeljak','Utorak','Srijeda','Četvrtak','Petak','Subota'], + dayNamesShort: ['Ned','Pon','Uto','Sri','Čet','Pet','Sub'], + dayNamesMin: ['Ne','Po','Ut','Sr','Če','Pe','Su'], + dateFormat: 'dd.mm.yy.', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['hr']); +});/* Hungarian initialisation for the jQuery UI date picker plugin. */ +/* Written by Istvan Karaszi (jquerycalendar@spam.raszi.hu). */ +jQuery(function($){ + $.datepicker.regional['hu'] = { + closeText: 'bezárás', + prevText: '« vissza', + nextText: 'előre »', + currentText: 'ma', + monthNames: ['Január', 'Február', 'Március', 'Április', 'Május', 'Június', + 'Július', 'Augusztus', 'Szeptember', 'Október', 'November', 'December'], + monthNamesShort: ['Jan', 'Feb', 'Már', 'Ápr', 'Máj', 'Jún', + 'Júl', 'Aug', 'Szep', 'Okt', 'Nov', 'Dec'], + dayNames: ['Vasámap', 'Hétfö', 'Kedd', 'Szerda', 'Csütörtök', 'Péntek', 'Szombat'], + dayNamesShort: ['Vas', 'Hét', 'Ked', 'Sze', 'Csü', 'Pén', 'Szo'], + dayNamesMin: ['V', 'H', 'K', 'Sze', 'Cs', 'P', 'Szo'], + dateFormat: 'yy-mm-dd', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['hu']); +}); +/* Armenian(UTF-8) initialisation for the jQuery UI date picker plugin. */ +/* Written by Levon Zakaryan (levon.zakaryan@gmail.com)*/ +jQuery(function($){ + $.datepicker.regional['hy'] = { + closeText: 'Փակել', + prevText: '<Նախ.', + nextText: 'Հաջ.>', + currentText: 'Այսօր', + monthNames: ['Հունվար','Փետրվար','Մարտ','Ապրիլ','Մայիս','Հունիս', + 'Հուլիս','Օգոստոս','Սեպտեմբեր','Հոկտեմբեր','Նոյեմբեր','Դեկտեմբեր'], + monthNamesShort: ['Հունվ','Փետր','Մարտ','Ապր','Մայիս','Հունիս', + 'Հուլ','Օգս','Սեպ','Հոկ','Նոյ','Ô´Õ¥Õ¯'], + dayNames: ['կիրակի','եկուշաբթի','երեքշաբթի','չորեքշաբթի','Õ°Õ«Õ¶Õ£Õ·Õ¡Õ¢Õ©Õ«','ուրբաթ','Õ·Õ¡Õ¢Õ¡Õ©'], + dayNamesShort: ['կիր','երկ','երք','չրք','Õ°Õ¶Õ£','ուրբ','Õ·Õ¢Õ©'], + dayNamesMin: ['կիր','երկ','երք','չրք','Õ°Õ¶Õ£','ուրբ','Õ·Õ¢Õ©'], + dateFormat: 'dd.mm.yy', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['hy']); +});/* Indonesian initialisation for the jQuery UI date picker plugin. */ +/* Written by Deden Fathurahman (dedenf@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['id'] = { + closeText: 'Tutup', + prevText: '<mundur', + nextText: 'maju>', + currentText: 'hari ini', + monthNames: ['Januari','Februari','Maret','April','Mei','Juni', + 'Juli','Agustus','September','Oktober','Nopember','Desember'], + monthNamesShort: ['Jan','Feb','Mar','Apr','Mei','Jun', + 'Jul','Agus','Sep','Okt','Nop','Des'], + dayNames: ['Minggu','Senin','Selasa','Rabu','Kamis','Jumat','Sabtu'], + dayNamesShort: ['Min','Sen','Sel','Rab','kam','Jum','Sab'], + dayNamesMin: ['Mg','Sn','Sl','Rb','Km','jm','Sb'], + dateFormat: 'dd/mm/yy', firstDay: 0, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['id']); +});/* Icelandic initialisation for the jQuery UI date picker plugin. */ +/* Written by Haukur H. Thorsson (haukur@eskill.is). */ +jQuery(function($){ + $.datepicker.regional['is'] = { + closeText: 'Loka', + prevText: '< Fyrri', + nextText: 'Næsti >', + currentText: 'Í dag', + monthNames: ['Janúar','Febrúar','Mars','Apríl','Maí','Júní', + 'Júlí','Ágúst','September','Október','Nóvember','Desember'], + monthNamesShort: ['Jan','Feb','Mar','Apr','Maí','Jún', + 'Júl','Ágú','Sep','Okt','Nóv','Des'], + dayNames: ['Sunnudagur','Mánudagur','Þriðjudagur','Miðvikudagur','Fimmtudagur','Föstudagur','Laugardagur'], + dayNamesShort: ['Sun','Mán','Þri','Mið','Fim','Fös','Lau'], + dayNamesMin: ['Su','Má','Þr','Mi','Fi','Fö','La'], + dateFormat: 'dd/mm/yy', firstDay: 0, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['is']); +});/* Italian initialisation for the jQuery UI date picker plugin. */ +/* Written by Apaella (apaella@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['it'] = { + closeText: 'Chiudi', + prevText: '<Prec', + nextText: 'Succ>', + currentText: 'Oggi', + monthNames: ['Gennaio','Febbraio','Marzo','Aprile','Maggio','Giugno', + 'Luglio','Agosto','Settembre','Ottobre','Novembre','Dicembre'], + monthNamesShort: ['Gen','Feb','Mar','Apr','Mag','Giu', + 'Lug','Ago','Set','Ott','Nov','Dic'], + dayNames: ['Domenica','Lunedì','Martedì','Mercoledì','Giovedì','Venerdì','Sabato'], + dayNamesShort: ['Dom','Lun','Mar','Mer','Gio','Ven','Sab'], + dayNamesMin: ['Do','Lu','Ma','Me','Gio','Ve','Sa'], + dateFormat: 'dd/mm/yy', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['it']); +}); +/* Japanese initialisation for the jQuery UI date picker plugin. */ +/* Written by Kentaro SATO (kentaro@ranvis.com). */ +jQuery(function($){ + $.datepicker.regional['ja'] = { + closeText: '閉じる', + prevText: '<前', + nextText: '次>', + currentText: '今日', + monthNames: ['1月','2月','3月','4月','5月','6月', + '7月','8月','9月','10月','11月','12月'], + monthNamesShort: ['1月','2月','3月','4月','5月','6月', + '7月','8月','9月','10月','11月','12月'], + dayNames: ['日曜日','月曜日','火曜日','水曜日','木曜日','金曜日','土曜日'], + dayNamesShort: ['日','月','火','æ°´','木','金','土'], + dayNamesMin: ['日','月','火','æ°´','木','金','土'], + dateFormat: 'yy/mm/dd', firstDay: 0, + isRTL: false, + showMonthAfterYear: true}; + $.datepicker.setDefaults($.datepicker.regional['ja']); +});/* Korean initialisation for the jQuery calendar extension. */ +/* Written by DaeKwon Kang (ncrash.dk@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['ko'] = { + closeText: '닫기', + prevText: '이전달', + nextText: '다음달', + currentText: '오늘', + monthNames: ['1월(JAN)','2월(FEB)','3월(MAR)','4월(APR)','5월(MAY)','6월(JUN)', + '7월(JUL)','8월(AUG)','9월(SEP)','10월(OCT)','11월(NOV)','12월(DEC)'], + monthNamesShort: ['1월(JAN)','2월(FEB)','3월(MAR)','4월(APR)','5월(MAY)','6월(JUN)', + '7월(JUL)','8월(AUG)','9월(SEP)','10월(OCT)','11월(NOV)','12월(DEC)'], + dayNames: ['일','월','화','수','목','금','토'], + dayNamesShort: ['일','월','화','수','목','금','토'], + dayNamesMin: ['일','월','화','수','목','금','토'], + dateFormat: 'yy-mm-dd', firstDay: 0, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['ko']); +});/* Lithuanian (UTF-8) initialisation for the jQuery UI date picker plugin. */ +/* @author Arturas Paleicikas */ +jQuery(function($){ + $.datepicker.regional['lt'] = { + closeText: 'Uždaryti', + prevText: '<Atgal', + nextText: 'Pirmyn>', + currentText: 'Å iandien', + monthNames: ['Sausis','Vasaris','Kovas','Balandis','Gegužė','Birželis', + 'Liepa','RugpjÅ«tis','Rugsėjis','Spalis','Lapkritis','Gruodis'], + monthNamesShort: ['Sau','Vas','Kov','Bal','Geg','Bir', + 'Lie','Rugp','Rugs','Spa','Lap','Gru'], + dayNames: ['sekmadienis','pirmadienis','antradienis','trečiadienis','ketvirtadienis','penktadienis','Å¡eÅ¡tadienis'], + dayNamesShort: ['sek','pir','ant','tre','ket','pen','Å¡eÅ¡'], + dayNamesMin: ['Se','Pr','An','Tr','Ke','Pe','Å e'], + dateFormat: 'yy-mm-dd', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['lt']); +});/* Latvian (UTF-8) initialisation for the jQuery UI date picker plugin. */ +/* @author Arturas Paleicikas */ +jQuery(function($){ + $.datepicker.regional['lv'] = { + closeText: 'Aizvērt', + prevText: 'Iepr', + nextText: 'Nāka', + currentText: 'Å odien', + monthNames: ['Janvāris','Februāris','Marts','AprÄ«lis','Maijs','JÅ«nijs', + 'JÅ«lijs','Augusts','Septembris','Oktobris','Novembris','Decembris'], + monthNamesShort: ['Jan','Feb','Mar','Apr','Mai','JÅ«n', + 'JÅ«l','Aug','Sep','Okt','Nov','Dec'], + dayNames: ['svētdiena','pirmdiena','otrdiena','treÅ¡diena','ceturtdiena','piektdiena','sestdiena'], + dayNamesShort: ['svt','prm','otr','tre','ctr','pkt','sst'], + dayNamesMin: ['Sv','Pr','Ot','Tr','Ct','Pk','Ss'], + dateFormat: 'dd-mm-yy', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['lv']); +});/* Malaysian initialisation for the jQuery UI date picker plugin. */ +/* Written by Mohd Nawawi Mohamad Jamili (nawawi@ronggeng.net). */ +jQuery(function($){ + $.datepicker.regional['ms'] = { + closeText: 'Tutup', + prevText: '<Sebelum', + nextText: 'Selepas>', + currentText: 'hari ini', + monthNames: ['Januari','Februari','Mac','April','Mei','Jun', + 'Julai','Ogos','September','Oktober','November','Disember'], + monthNamesShort: ['Jan','Feb','Mac','Apr','Mei','Jun', + 'Jul','Ogo','Sep','Okt','Nov','Dis'], + dayNames: ['Ahad','Isnin','Selasa','Rabu','Khamis','Jumaat','Sabtu'], + dayNamesShort: ['Aha','Isn','Sel','Rab','kha','Jum','Sab'], + dayNamesMin: ['Ah','Is','Se','Ra','Kh','Ju','Sa'], + dateFormat: 'dd/mm/yy', firstDay: 0, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['ms']); +});/* Dutch (UTF-8) initialisation for the jQuery UI date picker plugin. */ +/* Written by Mathias Bynens */ +jQuery(function($){ + $.datepicker.regional.nl = { + closeText: 'Sluiten', + prevText: '←', + nextText: '→', + currentText: 'Vandaag', + monthNames: ['januari', 'februari', 'maart', 'april', 'mei', 'juni', + 'juli', 'augustus', 'september', 'oktober', 'november', 'december'], + monthNamesShort: ['jan', 'feb', 'maa', 'apr', 'mei', 'jun', + 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'], + dayNames: ['zondag', 'maandag', 'dinsdag', 'woensdag', 'donderdag', 'vrijdag', 'zaterdag'], + dayNamesShort: ['zon', 'maa', 'din', 'woe', 'don', 'vri', 'zat'], + dayNamesMin: ['zo', 'ma', 'di', 'wo', 'do', 'vr', 'za'], + dateFormat: 'dd/mm/yy', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional.nl); +});/* Norwegian initialisation for the jQuery UI date picker plugin. */ +/* Written by Naimdjon Takhirov (naimdjon@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['no'] = { + closeText: 'Lukk', + prevText: '«Forrige', + nextText: 'Neste»', + currentText: 'I dag', + monthNames: ['Januar','Februar','Mars','April','Mai','Juni', + 'Juli','August','September','Oktober','November','Desember'], + monthNamesShort: ['Jan','Feb','Mar','Apr','Mai','Jun', + 'Jul','Aug','Sep','Okt','Nov','Des'], + dayNamesShort: ['Søn','Man','Tir','Ons','Tor','Fre','Lør'], + dayNames: ['Søndag','Mandag','Tirsdag','Onsdag','Torsdag','Fredag','Lørdag'], + dayNamesMin: ['Sø','Ma','Ti','On','To','Fr','Lø'], + dateFormat: 'yy-mm-dd', firstDay: 0, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['no']); +}); +/* Polish initialisation for the jQuery UI date picker plugin. */ +/* Written by Jacek Wysocki (jacek.wysocki@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['pl'] = { + closeText: 'Zamknij', + prevText: '<Poprzedni', + nextText: 'Następny>', + currentText: 'Dziś', + monthNames: ['Styczeń','Luty','Marzec','Kwiecień','Maj','Czerwiec', + 'Lipiec','Sierpień','Wrzesień','Październik','Listopad','Grudzień'], + monthNamesShort: ['Sty','Lu','Mar','Kw','Maj','Cze', + 'Lip','Sie','Wrz','Pa','Lis','Gru'], + dayNames: ['Niedziela','Poniedzialek','Wtorek','Środa','Czwartek','Piątek','Sobota'], + dayNamesShort: ['Nie','Pn','Wt','Śr','Czw','Pt','So'], + dayNamesMin: ['N','Pn','Wt','Śr','Cz','Pt','So'], + dateFormat: 'yy-mm-dd', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['pl']); +}); +/* Brazilian initialisation for the jQuery UI date picker plugin. */ +/* Written by Leonildo Costa Silva (leocsilva@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['pt-BR'] = { + closeText: 'Fechar', + prevText: '<Anterior', + nextText: 'Próximo>', + currentText: 'Hoje', + monthNames: ['Janeiro','Fevereiro','Março','Abril','Maio','Junho', + 'Julho','Agosto','Setembro','Outubro','Novembro','Dezembro'], + monthNamesShort: ['Jan','Fev','Mar','Abr','Mai','Jun', + 'Jul','Ago','Set','Out','Nov','Dez'], + dayNames: ['Domingo','Segunda-feira','Terça-feira','Quarta-feira','Quinta-feira','Sexta-feira','Sabado'], + dayNamesShort: ['Dom','Seg','Ter','Qua','Qui','Sex','Sab'], + dayNamesMin: ['Dom','Seg','Ter','Qua','Qui','Sex','Sab'], + dateFormat: 'dd/mm/yy', firstDay: 0, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['pt-BR']); +});/* Romanian initialisation for the jQuery UI date picker plugin. + * + * Written by Edmond L. (ll_edmond@walla.com) + * and Ionut G. Stan (ionut.g.stan@gmail.com) + */ +jQuery(function($){ + $.datepicker.regional['ro'] = { + closeText: 'Închide', + prevText: '« Luna precedentă', + nextText: 'Luna următoare »', + currentText: 'Azi', + monthNames: ['Ianuarie','Februarie','Martie','Aprilie','Mai','Iunie', + 'Iulie','August','Septembrie','Octombrie','Noiembrie','Decembrie'], + monthNamesShort: ['Ian', 'Feb', 'Mar', 'Apr', 'Mai', 'Iun', + 'Iul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + dayNames: ['Duminică', 'Luni', 'MarÅ£i', 'Miercuri', 'Joi', 'Vineri', 'Sâmbătă'], + dayNamesShort: ['Dum', 'Lun', 'Mar', 'Mie', 'Joi', 'Vin', 'Sâm'], + dayNamesMin: ['Du','Lu','Ma','Mi','Jo','Vi','Sâ'], + dateFormat: 'dd MM yy', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['ro']); +}); +/* Russian (UTF-8) initialisation for the jQuery UI date picker plugin. */ +/* Written by Andrew Stromnov (stromnov@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['ru'] = { + closeText: 'Закрыть', + prevText: '<Пред', + nextText: 'След>', + currentText: 'Сегодня', + monthNames: ['Январь','Февраль','Март','Апрель','Май','Июнь', + 'Июль','Август','Сентябрь','Октябрь','Ноябрь','Декабрь'], + monthNamesShort: ['Янв','Фев','Мар','Апр','Май','Июн', + 'Июл','Авг','Сен','Окт','Ноя','Дек'], + dayNames: ['воскресенье','понедельник','вторник','среда','четверг','пятница','суббота'], + dayNamesShort: ['вск','пнд','втр','срд','чтв','птн','сбт'], + dayNamesMin: ['Вс','Пн','Вт','Ср','Чт','Пт','Сб'], + dateFormat: 'dd.mm.yy', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['ru']); +});/* Slovak initialisation for the jQuery UI date picker plugin. */ +/* Written by Vojtech Rinik (vojto@hmm.sk). */ +jQuery(function($){ + $.datepicker.regional['sk'] = { + closeText: 'ZavrieÅ¥', + prevText: '<Predchádzajúci', + nextText: 'Nasledujúci>', + currentText: 'Dnes', + monthNames: ['Január','Február','Marec','Apríl','Máj','Jún', + 'Júl','August','September','Október','November','December'], + monthNamesShort: ['Jan','Feb','Mar','Apr','Máj','Jún', + 'Júl','Aug','Sep','Okt','Nov','Dec'], + dayNames: ['Nedel\'a','Pondelok','Utorok','Streda','Å tvrtok','Piatok','Sobota'], + dayNamesShort: ['Ned','Pon','Uto','Str','Å tv','Pia','Sob'], + dayNamesMin: ['Ne','Po','Ut','St','Å t','Pia','So'], + dateFormat: 'dd.mm.yy', firstDay: 0, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['sk']); +}); +/* Slovenian initialisation for the jQuery UI date picker plugin. */ +/* Written by Jaka Jancar (jaka@kubje.org). */ +/* c = č, s = š z = ž C = Č S = Š Z = Ž */ +jQuery(function($){ + $.datepicker.regional['sl'] = { + closeText: 'Zapri', + prevText: '<Prejšnji', + nextText: 'Naslednji>', + currentText: 'Trenutni', + monthNames: ['Januar','Februar','Marec','April','Maj','Junij', + 'Julij','Avgust','September','Oktober','November','December'], + monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun', + 'Jul','Avg','Sep','Okt','Nov','Dec'], + dayNames: ['Nedelja','Ponedeljek','Torek','Sreda','Četrtek','Petek','Sobota'], + dayNamesShort: ['Ned','Pon','Tor','Sre','Čet','Pet','Sob'], + dayNamesMin: ['Ne','Po','To','Sr','Če','Pe','So'], + dateFormat: 'dd.mm.yy', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['sl']); +}); +/* Albanian initialisation for the jQuery UI date picker plugin. */ +/* Written by Flakron Bytyqi (flakron@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['sq'] = { + closeText: 'mbylle', + prevText: '<mbrapa', + nextText: 'Përpara>', + currentText: 'sot', + monthNames: ['Janar','Shkurt','Mars','Prill','Maj','Qershor', + 'Korrik','Gusht','Shtator','Tetor','Nëntor','Dhjetor'], + monthNamesShort: ['Jan','Shk','Mar','Pri','Maj','Qer', + 'Kor','Gus','Sht','Tet','Nën','Dhj'], + dayNames: ['E Diel','E Hënë','E Martë','E Mërkurë','E Enjte','E Premte','E Shtune'], + dayNamesShort: ['Di','Hë','Ma','Më','En','Pr','Sh'], + dayNamesMin: ['Di','Hë','Ma','Më','En','Pr','Sh'], + dateFormat: 'dd.mm.yy', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['sq']); +}); +/* Serbian i18n for the jQuery UI date picker plugin. */ +/* Written by Dejan Dimić. */ +jQuery(function($){ + $.datepicker.regional['sr-SR'] = { + closeText: 'Zatvori', + prevText: '<', + nextText: '>', + currentText: 'Danas', + monthNames: ['Januar','Februar','Mart','April','Maj','Jun', + 'Jul','Avgust','Septembar','Oktobar','Novembar','Decembar'], + monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun', + 'Jul','Avg','Sep','Okt','Nov','Dec'], + dayNames: ['Nedelja','Ponedeljak','Utorak','Sreda','Četvrtak','Petak','Subota'], + dayNamesShort: ['Ned','Pon','Uto','Sre','Čet','Pet','Sub'], + dayNamesMin: ['Ne','Po','Ut','Sr','Če','Pe','Su'], + dateFormat: 'dd/mm/yy', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['sr-SR']); +}); +/* Serbian i18n for the jQuery UI date picker plugin. */ +/* Written by Dejan Dimić. */ +jQuery(function($){ + $.datepicker.regional['sr'] = { + closeText: 'Затвори', + prevText: '<', + nextText: '>', + currentText: 'Данас', + monthNames: ['Јануар','Фебруар','Март','Април','Мај','Јун', + 'Јул','Август','Септембар','Октобар','Новембар','Децембар'], + monthNamesShort: ['Јан','Феб','Мар','Апр','Мај','Јун', + 'Јул','Авг','Сеп','Окт','Нов','Дец'], + dayNames: ['Недеља','Понедељак','Уторак','Среда','Четвртак','Петак','Субота'], + dayNamesShort: ['Нед','Пон','Уто','Сре','Чет','Пет','Суб'], + dayNamesMin: ['Не','По','Ут','Ср','Че','Пе','Су'], + dateFormat: 'dd/mm/yy', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['sr']); +}); +/* Swedish initialisation for the jQuery UI date picker plugin. */ +/* Written by Anders Ekdahl ( anders@nomadiz.se). */ +jQuery(function($){ + $.datepicker.regional['sv'] = { + closeText: 'Stäng', + prevText: '«Förra', + nextText: 'Nästa»', + currentText: 'Idag', + monthNames: ['Januari','Februari','Mars','April','Maj','Juni', + 'Juli','Augusti','September','Oktober','November','December'], + monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun', + 'Jul','Aug','Sep','Okt','Nov','Dec'], + dayNamesShort: ['Sön','MÃ¥n','Tis','Ons','Tor','Fre','Lör'], + dayNames: ['Söndag','MÃ¥ndag','Tisdag','Onsdag','Torsdag','Fredag','Lördag'], + dayNamesMin: ['Sö','MÃ¥','Ti','On','To','Fr','Lö'], + dateFormat: 'yy-mm-dd', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['sv']); +}); +/* Thai initialisation for the jQuery UI date picker plugin. */ +/* Written by pipo (pipo@sixhead.com). */ +jQuery(function($){ + $.datepicker.regional['th'] = { + closeText: 'ปิด', + prevText: '« à¸¢à¹‰à¸­à¸™', + nextText: 'ถัดไป »', + currentText: 'วันนี้', + monthNames: ['มกราคม','กุมภาพันธ์','มีนาคม','เมษายน','พฤษภาคม','มิถุนายน', + 'กรกฏาคม','สิงหาคม','กันยายน','ตุลาคม','พฤศจิกายน','ธันวาคม'], + monthNamesShort: ['ม.ค.','ก.พ.','มี.ค.','เม.ย.','พ.ค.','มิ.ย.', + 'ก.ค.','ส.ค.','ก.ย.','ต.ค.','พ.ย.','ธ.ค.'], + dayNames: ['อาทิตย์','จันทร์','อังคาร','พุธ','พฤหัสบดี','ศุกร์','เสาร์'], + dayNamesShort: ['อา.','จ.','อ.','พ.','พฤ.','ศ.','ส.'], + dayNamesMin: ['อา.','จ.','อ.','พ.','พฤ.','ศ.','ส.'], + dateFormat: 'dd/mm/yy', firstDay: 0, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['th']); +});/* Turkish initialisation for the jQuery UI date picker plugin. */ +/* Written by Izzet Emre Erkan (kara@karalamalar.net). */ +jQuery(function($){ + $.datepicker.regional['tr'] = { + closeText: 'kapat', + prevText: '<geri', + nextText: 'ileri>', + currentText: 'bugün', + monthNames: ['Ocak','Şubat','Mart','Nisan','Mayıs','Haziran', + 'Temmuz','Ağustos','Eylül','Ekim','Kasım','Aralık'], + monthNamesShort: ['Oca','Şub','Mar','Nis','May','Haz', + 'Tem','Ağu','Eyl','Eki','Kas','Ara'], + dayNames: ['Pazar','Pazartesi','Salı','Çarşamba','Perşembe','Cuma','Cumartesi'], + dayNamesShort: ['Pz','Pt','Sa','Ça','Pe','Cu','Ct'], + dayNamesMin: ['Pz','Pt','Sa','Ça','Pe','Cu','Ct'], + dateFormat: 'dd.mm.yy', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['tr']); +});/* Ukrainian (UTF-8) initialisation for the jQuery UI date picker plugin. */ +/* Written by Maxim Drogobitskiy (maxdao@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['uk'] = { + clearText: 'Очистити', clearStatus: '', + closeText: 'Закрити', closeStatus: '', + prevText: '<', prevStatus: '', + prevBigText: '<<', prevBigStatus: '', + nextText: '>', nextStatus: '', + nextBigText: '>>', nextBigStatus: '', + currentText: 'Сьогодні', currentStatus: '', + monthNames: ['Січень','Лютий','Березень','Квітень','Травень','Червень', + 'Липень','Серпень','Вересень','Жовтень','Листопад','Грудень'], + monthNamesShort: ['Січ','Лют','Бер','Кві','Тра','Чер', + 'Лип','Сер','Вер','Жов','Лис','Гру'], + monthStatus: '', yearStatus: '', + weekHeader: 'Не', weekStatus: '', + dayNames: ['неділя','понеділок','вівторок','середа','четвер','п’ятниця','субота'], + dayNamesShort: ['нед','пнд','вів','срд','чтв','птн','сбт'], + dayNamesMin: ['Нд','Пн','Вт','Ср','Чт','Пт','Сб'], + dayStatus: 'DD', dateStatus: 'D, M d', + dateFormat: 'dd/mm/yy', firstDay: 1, + initStatus: '', isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['uk']); +});/* Chinese initialisation for the jQuery UI date picker plugin. */ +/* Written by Cloudream (cloudream@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['zh-CN'] = { + closeText: '关闭', + prevText: '<上月', + nextText: '下月>', + currentText: '今天', + monthNames: ['一月','二月','三月','四月','五月','六月', + '七月','八月','九月','十月','十一月','十二月'], + monthNamesShort: ['一','二','三','四','五','六', + '七','八','九','十','十一','十二'], + dayNames: ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'], + dayNamesShort: ['周日','周一','周二','周三','周四','周五','周六'], + dayNamesMin: ['日','一','二','三','四','五','六'], + dateFormat: 'yy-mm-dd', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['zh-CN']); +}); +/* Chinese initialisation for the jQuery UI date picker plugin. */ +/* Written by Ressol (ressol@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['zh-TW'] = { + closeText: '關閉', + prevText: '<上月', + nextText: '下月>', + currentText: '今天', + monthNames: ['一月','二月','三月','四月','五月','六月', + '七月','八月','九月','十月','十一月','十二月'], + monthNamesShort: ['一','二','三','四','五','六', + '七','八','九','十','十一','十二'], + dayNames: ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'], + dayNamesShort: ['周日','周一','周二','周三','周四','周五','周六'], + dayNamesMin: ['日','一','二','三','四','五','六'], + dateFormat: 'yy/mm/dd', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['zh-TW']); +}); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-ar.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-ar.js new file mode 100644 index 0000000000..b605878912 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-ar.js @@ -0,0 +1,20 @@ +/* Arabic Translation for jQuery UI date picker plugin. */ +/* Khaled Al Horani -- koko.dw@gmail.com */ +/* خالد الحوراني -- koko.dw@gmail.com */ +/* NOTE: monthNames are the original months names and they are the Arabic names, not the new months name فبراير - يناير and there isn't any Arabic roots for these months */ +jQuery(function($){ + $.datepicker.regional['ar'] = { + closeText: 'إغلاق', + prevText: '<السابق', + nextText: 'التالي>', + currentText: 'اليوم', + monthNames: ['كانون الثاني', 'شباط', 'آذار', 'نيسان', 'آذار', 'حزيران', + 'تموز', 'آب', 'أيلول', 'تشرين الأول', 'تشرين الثاني', 'كانون الأول'], + monthNamesShort: ['1','2','3','4','5','6','7','8','9','10','11','12'], + dayNames: ['السبت', 'الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة'], + dayNamesShort: ['سبت', 'أحد', 'اثنين', 'ثلاثاء', 'أربعاء', 'خميس', 'جمعة'], + dayNamesMin: ['سبت', 'أحد', 'اثنين', 'ثلاثاء', 'أربعاء', 'خميس', 'جمعة'], + dateFormat: 'dd/mm/yy', firstDay: 0, + isRTL: true}; + $.datepicker.setDefaults($.datepicker.regional['ar']); +}); \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-bg.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-bg.js new file mode 100644 index 0000000000..a73884ef29 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-bg.js @@ -0,0 +1,20 @@ +/* Bulgarian initialisation for the jQuery UI date picker plugin. */ +/* Written by Stoyan Kyosev (http://svest.org). */ +jQuery(function($){ + $.datepicker.regional['bg'] = { + closeText: 'затвори', + prevText: '<назад', + nextText: 'напред>', + nextBigText: '>>', + currentText: 'днес', + monthNames: ['Януари','Февруари','Март','Април','Май','Юни', + 'Юли','Август','Септември','Октомври','Ноември','Декември'], + monthNamesShort: ['Яну','Фев','Мар','Апр','Май','Юни', + 'Юли','Авг','Сеп','Окт','Нов','Дек'], + dayNames: ['Неделя','Понеделник','Вторник','Сряда','Четвъртък','Петък','Събота'], + dayNamesShort: ['Нед','Пон','Вто','Сря','Чет','Пет','Съб'], + dayNamesMin: ['Не','По','Вт','Ср','Че','Пе','Съ'], + dateFormat: 'dd.mm.yy', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['bg']); +}); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-ca.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-ca.js new file mode 100644 index 0000000000..ad47af0bb3 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-ca.js @@ -0,0 +1,19 @@ +/* Inicialitzaci� en catal� per a l'extenci� 'calendar' per jQuery. */ +/* Writers: (joan.leon@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['ca'] = { + closeText: 'Tancar', + prevText: '<Ant', + nextText: 'Seg>', + currentText: 'Avui', + monthNames: ['Gener','Febrer','Març','Abril','Maig','Juny', + 'Juliol','Agost','Setembre','Octubre','Novembre','Desembre'], + monthNamesShort: ['Gen','Feb','Mar','Abr','Mai','Jun', + 'Jul','Ago','Set','Oct','Nov','Des'], + dayNames: ['Diumenge','Dilluns','Dimarts','Dimecres','Dijous','Divendres','Dissabte'], + dayNamesShort: ['Dug','Dln','Dmt','Dmc','Djs','Dvn','Dsb'], + dayNamesMin: ['Dg','Dl','Dt','Dc','Dj','Dv','Ds'], + dateFormat: 'mm/dd/yy', firstDay: 0, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['ca']); +}); \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-cs.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-cs.js new file mode 100644 index 0000000000..334ae2f463 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-cs.js @@ -0,0 +1,19 @@ +/* Czech initialisation for the jQuery UI date picker plugin. */ +/* Written by Tomas Muller (tomas@tomas-muller.net). */ +jQuery(function($){ + $.datepicker.regional['cs'] = { + closeText: 'Zavřít', + prevText: '<Dříve', + nextText: 'Později>', + currentText: 'Nyní', + monthNames: ['leden','únor','březen','duben','květen','červen', + 'červenec','srpen','září','říjen','listopad','prosinec'], + monthNamesShort: ['led','úno','bře','dub','kvě','čer', + 'čvc','srp','zář','říj','lis','pro'], + dayNames: ['neděle', 'pondělí', 'úterý', 'středa', 'čtvrtek', 'pátek', 'sobota'], + dayNamesShort: ['ne', 'po', 'út', 'st', 'čt', 'pá', 'so'], + dayNamesMin: ['ne','po','út','st','čt','pá','so'], + dateFormat: 'dd.mm.yy', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['cs']); +}); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-da.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-da.js new file mode 100644 index 0000000000..8ad1e2cc34 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-da.js @@ -0,0 +1,19 @@ +/* Danish initialisation for the jQuery UI date picker plugin. */ +/* Written by Jan Christensen ( deletestuff@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['da'] = { + closeText: 'Luk', + prevText: '<Forrige', + nextText: 'Næste>', + currentText: 'Idag', + monthNames: ['Januar','Februar','Marts','April','Maj','Juni', + 'Juli','August','September','Oktober','November','December'], + monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun', + 'Jul','Aug','Sep','Okt','Nov','Dec'], + dayNames: ['Søndag','Mandag','Tirsdag','Onsdag','Torsdag','Fredag','Lørdag'], + dayNamesShort: ['Søn','Man','Tir','Ons','Tor','Fre','Lør'], + dayNamesMin: ['Sø','Ma','Ti','On','To','Fr','Lø'], + dateFormat: 'dd-mm-yy', firstDay: 0, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['da']); +}); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-de.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-de.js new file mode 100644 index 0000000000..f9299c8155 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-de.js @@ -0,0 +1,19 @@ +/* German initialisation for the jQuery UI date picker plugin. */ +/* Written by Milian Wolff (mail@milianw.de). */ +jQuery(function($){ + $.datepicker.regional['de'] = { + closeText: 'schließen', + prevText: '<zurück', + nextText: 'Vor>', + currentText: 'heute', + monthNames: ['Januar','Februar','März','April','Mai','Juni', + 'Juli','August','September','Oktober','November','Dezember'], + monthNamesShort: ['Jan','Feb','Mär','Apr','Mai','Jun', + 'Jul','Aug','Sep','Okt','Nov','Dez'], + dayNames: ['Sonntag','Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag'], + dayNamesShort: ['So','Mo','Di','Mi','Do','Fr','Sa'], + dayNamesMin: ['So','Mo','Di','Mi','Do','Fr','Sa'], + dateFormat: 'dd.mm.yy', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['de']); +}); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-el.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-el.js new file mode 100644 index 0000000000..535080da0f --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-el.js @@ -0,0 +1,19 @@ +/* Greek (el) initialisation for the jQuery UI date picker plugin. */ +/* Written by Alex Cicovic (http://www.alexcicovic.com) */ +jQuery(function($){ + $.datepicker.regional['el'] = { + closeText: 'Κλείσιμο', + prevText: 'Προηγούμενος', + nextText: 'Επόμενος', + currentText: 'Τρέχων Μήνας', + monthNames: ['Ιανουάριος','Φεβρουάριος','Μάρτιος','Απρίλιος','Μάιος','Ιούνιος', + 'Ιούλιος','Αύγουστος','Σεπτέμβριος','Οκτώβριος','Νοέμβριος','Δεκέμβριος'], + monthNamesShort: ['Ιαν','Φεβ','Μαρ','Απρ','Μαι','Ιουν', + 'Ιουλ','Αυγ','Σεπ','Οκτ','Νοε','Δεκ'], + dayNames: ['Κυριακή','Δευτέρα','Τρίτη','Τετάρτη','Πέμπτη','Παρασκευή','Σάββατο'], + dayNamesShort: ['Κυρ','Δευ','Τρι','Τετ','Πεμ','Παρ','Σαβ'], + dayNamesMin: ['Κυ','Δε','Τρ','Τε','Πε','Πα','Σα'], + dateFormat: 'dd/mm/yy', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['el']); +}); \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-eo.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-eo.js new file mode 100644 index 0000000000..28abac4a3a --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-eo.js @@ -0,0 +1,19 @@ +/* Esperanto initialisation for the jQuery UI date picker plugin. */ +/* Written by Olivier M. (olivierweb@ifrance.com). */ +jQuery(function($){ + $.datepicker.regional['eo'] = { + closeText: 'Fermi', + prevText: '<Anta', + nextText: 'Sekv>', + currentText: 'Nuna', + monthNames: ['Januaro','Februaro','Marto','Aprilo','Majo','Junio', + 'Julio','AÅ­gusto','Septembro','Oktobro','Novembro','Decembro'], + monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun', + 'Jul','AÅ­g','Sep','Okt','Nov','Dec'], + dayNames: ['Dimanĉo','Lundo','Mardo','Merkredo','Ä´aÅ­do','Vendredo','Sabato'], + dayNamesShort: ['Dim','Lun','Mar','Mer','Ä´aÅ­','Ven','Sab'], + dayNamesMin: ['Di','Lu','Ma','Me','Ä´a','Ve','Sa'], + dateFormat: 'dd/mm/yy', firstDay: 0, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['eo']); +}); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-es.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-es.js new file mode 100644 index 0000000000..0a699afe77 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-es.js @@ -0,0 +1,19 @@ +/* Inicializaci�n en espa�ol para la extensi�n 'UI date picker' para jQuery. */ +/* Traducido por Vester (xvester@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['es'] = { + closeText: 'Cerrar', + prevText: '<Ant', + nextText: 'Sig>', + currentText: 'Hoy', + monthNames: ['Enero','Febrero','Marzo','Abril','Mayo','Junio', + 'Julio','Agosto','Septiembre','Octubre','Noviembre','Diciembre'], + monthNamesShort: ['Ene','Feb','Mar','Abr','May','Jun', + 'Jul','Ago','Sep','Oct','Nov','Dic'], + dayNames: ['Domingo','Lunes','Martes','Miércoles','Jueves','Viernes','Sábado'], + dayNamesShort: ['Dom','Lun','Mar','Mié','Juv','Vie','Sáb'], + dayNamesMin: ['Do','Lu','Ma','Mi','Ju','Vi','Sá'], + dateFormat: 'dd/mm/yy', firstDay: 0, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['es']); +}); \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-fa.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-fa.js new file mode 100644 index 0000000000..e40e1acd48 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-fa.js @@ -0,0 +1,19 @@ +/* Persian (Farsi) Translation for the jQuery UI date picker plugin. */ +/* Javad Mowlanezhad -- jmowla@gmail.com */ +/* Jalali calendar should supported soon! (Its implemented but I have to test it) */ +jQuery(function($) { + $.datepicker.regional['fa'] = { + closeText: 'بستن', + prevText: '<قبلي', + nextText: 'بعدي>', + currentText: 'امروز', + monthNames: ['فروردين','ارديبهشت','خرداد','تير','مرداد','شهريور', + 'مهر','آبان','آذر','دي','بهمن','اسفند'], + monthNamesShort: ['1','2','3','4','5','6','7','8','9','10','11','12'], + dayNames: ['يکشنبه','دوشنبه','سه‌شنبه','چهارشنبه','پنجشنبه','جمعه','شنبه'], + dayNamesShort: ['ي','د','س','چ','Ù¾','ج', 'Ø´'], + dayNamesMin: ['ي','د','س','چ','Ù¾','ج', 'Ø´'], + dateFormat: 'yy/mm/dd', firstDay: 6, + isRTL: true}; + $.datepicker.setDefaults($.datepicker.regional['fa']); +}); \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-fi.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-fi.js new file mode 100644 index 0000000000..980e0bbbce --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-fi.js @@ -0,0 +1,19 @@ +/* Finnish initialisation for the jQuery UI date picker plugin. */ +/* Written by Harri Kilpi� (harrikilpio@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['fi'] = { + closeText: 'Sulje', + prevText: '«Edellinen', + nextText: 'Seuraava»', + currentText: 'Tänään', + monthNames: ['Tammikuu','Helmikuu','Maaliskuu','Huhtikuu','Toukokuu','Kesäkuu', + 'Heinäkuu','Elokuu','Syyskuu','Lokakuu','Marraskuu','Joulukuu'], + monthNamesShort: ['Tammi','Helmi','Maalis','Huhti','Touko','Kesä', + 'Heinä','Elo','Syys','Loka','Marras','Joulu'], + dayNamesShort: ['Su','Ma','Ti','Ke','To','Pe','Su'], + dayNames: ['Sunnuntai','Maanantai','Tiistai','Keskiviikko','Torstai','Perjantai','Lauantai'], + dayNamesMin: ['Su','Ma','Ti','Ke','To','Pe','La'], + dateFormat: 'dd.mm.yy', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['fi']); +}); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-fr.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-fr.js new file mode 100644 index 0000000000..02edda29de --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-fr.js @@ -0,0 +1,19 @@ +/* French initialisation for the jQuery UI date picker plugin. */ +/* Written by Keith Wood (kbwood@virginbroadband.com.au) and Stéphane Nahmani (sholby@sholby.net). */ +jQuery(function($){ + $.datepicker.regional['fr'] = { + closeText: 'Fermer', + prevText: '<Préc', + nextText: 'Suiv>', + currentText: 'Courant', + monthNames: ['Janvier','Février','Mars','Avril','Mai','Juin', + 'Juillet','Août','Septembre','Octobre','Novembre','Décembre'], + monthNamesShort: ['Jan','Fév','Mar','Avr','Mai','Jun', + 'Jul','Aoû','Sep','Oct','Nov','Déc'], + dayNames: ['Dimanche','Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi'], + dayNamesShort: ['Dim','Lun','Mar','Mer','Jeu','Ven','Sam'], + dayNamesMin: ['Di','Lu','Ma','Me','Je','Ve','Sa'], + dateFormat: 'dd/mm/yy', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['fr']); +}); \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-he.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-he.js new file mode 100644 index 0000000000..38e0a03e2d --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-he.js @@ -0,0 +1,19 @@ +/* Hebrew initialisation for the UI Datepicker extension. */ +/* Written by Amir Hardon (ahardon at gmail dot com). */ +jQuery(function($){ + $.datepicker.regional['he'] = { + closeText: 'סגור', + prevText: '<הקודם', + nextText: 'הבא>', + currentText: 'היום', + monthNames: ['ינואר','פברואר','מרץ','אפריל','מאי','יוני', + 'יולי','אוגוסט','ספטמבר','אוקטובר','נובמבר','דצמבר'], + monthNamesShort: ['1','2','3','4','5','6', + '7','8','9','10','11','12'], + dayNames: ['ראשון','שני','שלישי','רביעי','חמישי','שישי','שבת'], + dayNamesShort: ['א\'','ב\'','ג\'','ד\'','ה\'','ו\'','שבת'], + dayNamesMin: ['א\'','ב\'','ג\'','ד\'','ה\'','ו\'','שבת'], + dateFormat: 'dd/mm/yy', firstDay: 0, + isRTL: true}; + $.datepicker.setDefaults($.datepicker.regional['he']); +}); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-hr.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-hr.js new file mode 100644 index 0000000000..78e4006582 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-hr.js @@ -0,0 +1,19 @@ +/* Croatian i18n for the jQuery UI date picker plugin. */ +/* Written by Vjekoslav Nesek. */ +jQuery(function($){ + $.datepicker.regional['hr'] = { + closeText: 'Zatvori', + prevText: '<', + nextText: '>', + currentText: 'Danas', + monthNames: ['Siječanj','Veljača','Ožujak','Travanj','Svibanj','Lipani', + 'Srpanj','Kolovoz','Rujan','Listopad','Studeni','Prosinac'], + monthNamesShort: ['Sij','Velj','Ožu','Tra','Svi','Lip', + 'Srp','Kol','Ruj','Lis','Stu','Pro'], + dayNames: ['Nedjalja','Ponedjeljak','Utorak','Srijeda','Četvrtak','Petak','Subota'], + dayNamesShort: ['Ned','Pon','Uto','Sri','Čet','Pet','Sub'], + dayNamesMin: ['Ne','Po','Ut','Sr','Če','Pe','Su'], + dateFormat: 'dd.mm.yy.', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['hr']); +}); \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-hu.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-hu.js new file mode 100644 index 0000000000..ee102acd09 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-hu.js @@ -0,0 +1,19 @@ +/* Hungarian initialisation for the jQuery UI date picker plugin. */ +/* Written by Istvan Karaszi (jquerycalendar@spam.raszi.hu). */ +jQuery(function($){ + $.datepicker.regional['hu'] = { + closeText: 'bezárás', + prevText: '« vissza', + nextText: 'előre »', + currentText: 'ma', + monthNames: ['Január', 'Február', 'Március', 'Április', 'Május', 'Június', + 'Július', 'Augusztus', 'Szeptember', 'Október', 'November', 'December'], + monthNamesShort: ['Jan', 'Feb', 'Már', 'Ápr', 'Máj', 'Jún', + 'Júl', 'Aug', 'Szep', 'Okt', 'Nov', 'Dec'], + dayNames: ['Vasámap', 'Hétfö', 'Kedd', 'Szerda', 'Csütörtök', 'Péntek', 'Szombat'], + dayNamesShort: ['Vas', 'Hét', 'Ked', 'Sze', 'Csü', 'Pén', 'Szo'], + dayNamesMin: ['V', 'H', 'K', 'Sze', 'Cs', 'P', 'Szo'], + dateFormat: 'yy-mm-dd', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['hu']); +}); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-hy.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-hy.js new file mode 100644 index 0000000000..1ffbeaae07 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-hy.js @@ -0,0 +1,19 @@ +/* Armenian(UTF-8) initialisation for the jQuery UI date picker plugin. */ +/* Written by Levon Zakaryan (levon.zakaryan@gmail.com)*/ +jQuery(function($){ + $.datepicker.regional['hy'] = { + closeText: 'Փակել', + prevText: '<Նախ.', + nextText: 'Հաջ.>', + currentText: 'Այսօր', + monthNames: ['Հունվար','Փետրվար','Մարտ','Ապրիլ','Մայիս','Հունիս', + 'Հուլիս','Օգոստոս','Սեպտեմբեր','Հոկտեմբեր','Նոյեմբեր','Դեկտեմբեր'], + monthNamesShort: ['Հունվ','Փետր','Մարտ','Ապր','Մայիս','Հունիս', + 'Հուլ','Օգս','Սեպ','Հոկ','Նոյ','Ô´Õ¥Õ¯'], + dayNames: ['կիրակի','եկուշաբթի','երեքշաբթի','չորեքշաբթի','Õ°Õ«Õ¶Õ£Õ·Õ¡Õ¢Õ©Õ«','ուրբաթ','Õ·Õ¡Õ¢Õ¡Õ©'], + dayNamesShort: ['կիր','երկ','երք','չրք','Õ°Õ¶Õ£','ուրբ','Õ·Õ¢Õ©'], + dayNamesMin: ['կիր','երկ','երք','չրք','Õ°Õ¶Õ£','ուրբ','Õ·Õ¢Õ©'], + dateFormat: 'dd.mm.yy', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['hy']); +}); \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-id.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-id.js new file mode 100644 index 0000000000..e5246c85d1 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-id.js @@ -0,0 +1,19 @@ +/* Indonesian initialisation for the jQuery UI date picker plugin. */ +/* Written by Deden Fathurahman (dedenf@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['id'] = { + closeText: 'Tutup', + prevText: '<mundur', + nextText: 'maju>', + currentText: 'hari ini', + monthNames: ['Januari','Februari','Maret','April','Mei','Juni', + 'Juli','Agustus','September','Oktober','Nopember','Desember'], + monthNamesShort: ['Jan','Feb','Mar','Apr','Mei','Jun', + 'Jul','Agus','Sep','Okt','Nop','Des'], + dayNames: ['Minggu','Senin','Selasa','Rabu','Kamis','Jumat','Sabtu'], + dayNamesShort: ['Min','Sen','Sel','Rab','kam','Jum','Sab'], + dayNamesMin: ['Mg','Sn','Sl','Rb','Km','jm','Sb'], + dateFormat: 'dd/mm/yy', firstDay: 0, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['id']); +}); \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-is.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-is.js new file mode 100644 index 0000000000..68c1a07d41 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-is.js @@ -0,0 +1,19 @@ +/* Icelandic initialisation for the jQuery UI date picker plugin. */ +/* Written by Haukur H. Thorsson (haukur@eskill.is). */ +jQuery(function($){ + $.datepicker.regional['is'] = { + closeText: 'Loka', + prevText: '< Fyrri', + nextText: 'Næsti >', + currentText: 'Í dag', + monthNames: ['Janúar','Febrúar','Mars','Apríl','Maí','Júní', + 'Júlí','Ágúst','September','Október','Nóvember','Desember'], + monthNamesShort: ['Jan','Feb','Mar','Apr','Maí','Jún', + 'Júl','Ágú','Sep','Okt','Nóv','Des'], + dayNames: ['Sunnudagur','Mánudagur','Þriðjudagur','Miðvikudagur','Fimmtudagur','Föstudagur','Laugardagur'], + dayNamesShort: ['Sun','Mán','Þri','Mið','Fim','Fös','Lau'], + dayNamesMin: ['Su','Má','Þr','Mi','Fi','Fö','La'], + dateFormat: 'dd/mm/yy', firstDay: 0, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['is']); +}); \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-it.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-it.js new file mode 100644 index 0000000000..f3e691e5e0 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-it.js @@ -0,0 +1,19 @@ +/* Italian initialisation for the jQuery UI date picker plugin. */ +/* Written by Apaella (apaella@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['it'] = { + closeText: 'Chiudi', + prevText: '<Prec', + nextText: 'Succ>', + currentText: 'Oggi', + monthNames: ['Gennaio','Febbraio','Marzo','Aprile','Maggio','Giugno', + 'Luglio','Agosto','Settembre','Ottobre','Novembre','Dicembre'], + monthNamesShort: ['Gen','Feb','Mar','Apr','Mag','Giu', + 'Lug','Ago','Set','Ott','Nov','Dic'], + dayNames: ['Domenica','Lunedì','Martedì','Mercoledì','Giovedì','Venerdì','Sabato'], + dayNamesShort: ['Dom','Lun','Mar','Mer','Gio','Ven','Sab'], + dayNamesMin: ['Do','Lu','Ma','Me','Gio','Ve','Sa'], + dateFormat: 'dd/mm/yy', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['it']); +}); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-ja.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-ja.js new file mode 100644 index 0000000000..a6a5f45ce7 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-ja.js @@ -0,0 +1,20 @@ +/* Japanese initialisation for the jQuery UI date picker plugin. */ +/* Written by Kentaro SATO (kentaro@ranvis.com). */ +jQuery(function($){ + $.datepicker.regional['ja'] = { + closeText: '閉じる', + prevText: '<前', + nextText: '次>', + currentText: '今日', + monthNames: ['1月','2月','3月','4月','5月','6月', + '7月','8月','9月','10月','11月','12月'], + monthNamesShort: ['1月','2月','3月','4月','5月','6月', + '7月','8月','9月','10月','11月','12月'], + dayNames: ['日曜日','月曜日','火曜日','水曜日','木曜日','金曜日','土曜日'], + dayNamesShort: ['日','月','火','æ°´','木','金','土'], + dayNamesMin: ['日','月','火','æ°´','木','金','土'], + dateFormat: 'yy/mm/dd', firstDay: 0, + isRTL: false, + showMonthAfterYear: true}; + $.datepicker.setDefaults($.datepicker.regional['ja']); +}); \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-ko.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-ko.js new file mode 100644 index 0000000000..53ede91423 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-ko.js @@ -0,0 +1,19 @@ +/* Korean initialisation for the jQuery calendar extension. */ +/* Written by DaeKwon Kang (ncrash.dk@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['ko'] = { + closeText: '닫기', + prevText: '이전달', + nextText: '다음달', + currentText: '오늘', + monthNames: ['1월(JAN)','2월(FEB)','3월(MAR)','4월(APR)','5월(MAY)','6월(JUN)', + '7월(JUL)','8월(AUG)','9월(SEP)','10월(OCT)','11월(NOV)','12월(DEC)'], + monthNamesShort: ['1월(JAN)','2월(FEB)','3월(MAR)','4월(APR)','5월(MAY)','6월(JUN)', + '7월(JUL)','8월(AUG)','9월(SEP)','10월(OCT)','11월(NOV)','12월(DEC)'], + dayNames: ['일','월','화','수','목','금','토'], + dayNamesShort: ['일','월','화','수','목','금','토'], + dayNamesMin: ['일','월','화','수','목','금','토'], + dateFormat: 'yy-mm-dd', firstDay: 0, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['ko']); +}); \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-lt.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-lt.js new file mode 100644 index 0000000000..a8a6aa1a4e --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-lt.js @@ -0,0 +1,19 @@ +/* Lithuanian (UTF-8) initialisation for the jQuery UI date picker plugin. */ +/* @author Arturas Paleicikas */ +jQuery(function($){ + $.datepicker.regional['lt'] = { + closeText: 'Uždaryti', + prevText: '<Atgal', + nextText: 'Pirmyn>', + currentText: 'Å iandien', + monthNames: ['Sausis','Vasaris','Kovas','Balandis','Gegužė','Birželis', + 'Liepa','RugpjÅ«tis','Rugsėjis','Spalis','Lapkritis','Gruodis'], + monthNamesShort: ['Sau','Vas','Kov','Bal','Geg','Bir', + 'Lie','Rugp','Rugs','Spa','Lap','Gru'], + dayNames: ['sekmadienis','pirmadienis','antradienis','trečiadienis','ketvirtadienis','penktadienis','Å¡eÅ¡tadienis'], + dayNamesShort: ['sek','pir','ant','tre','ket','pen','Å¡eÅ¡'], + dayNamesMin: ['Se','Pr','An','Tr','Ke','Pe','Å e'], + dateFormat: 'yy-mm-dd', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['lt']); +}); \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-lv.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-lv.js new file mode 100644 index 0000000000..12c32f83cc --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-lv.js @@ -0,0 +1,19 @@ +/* Latvian (UTF-8) initialisation for the jQuery UI date picker plugin. */ +/* @author Arturas Paleicikas */ +jQuery(function($){ + $.datepicker.regional['lv'] = { + closeText: 'Aizvērt', + prevText: 'Iepr', + nextText: 'Nāka', + currentText: 'Å odien', + monthNames: ['Janvāris','Februāris','Marts','AprÄ«lis','Maijs','JÅ«nijs', + 'JÅ«lijs','Augusts','Septembris','Oktobris','Novembris','Decembris'], + monthNamesShort: ['Jan','Feb','Mar','Apr','Mai','JÅ«n', + 'JÅ«l','Aug','Sep','Okt','Nov','Dec'], + dayNames: ['svētdiena','pirmdiena','otrdiena','treÅ¡diena','ceturtdiena','piektdiena','sestdiena'], + dayNamesShort: ['svt','prm','otr','tre','ctr','pkt','sst'], + dayNamesMin: ['Sv','Pr','Ot','Tr','Ct','Pk','Ss'], + dateFormat: 'dd-mm-yy', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['lv']); +}); \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-ms.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-ms.js new file mode 100644 index 0000000000..fa253059f9 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-ms.js @@ -0,0 +1,19 @@ +/* Malaysian initialisation for the jQuery UI date picker plugin. */ +/* Written by Mohd Nawawi Mohamad Jamili (nawawi@ronggeng.net). */ +jQuery(function($){ + $.datepicker.regional['ms'] = { + closeText: 'Tutup', + prevText: '<Sebelum', + nextText: 'Selepas>', + currentText: 'hari ini', + monthNames: ['Januari','Februari','Mac','April','Mei','Jun', + 'Julai','Ogos','September','Oktober','November','Disember'], + monthNamesShort: ['Jan','Feb','Mac','Apr','Mei','Jun', + 'Jul','Ogo','Sep','Okt','Nov','Dis'], + dayNames: ['Ahad','Isnin','Selasa','Rabu','Khamis','Jumaat','Sabtu'], + dayNamesShort: ['Aha','Isn','Sel','Rab','kha','Jum','Sab'], + dayNamesMin: ['Ah','Is','Se','Ra','Kh','Ju','Sa'], + dateFormat: 'dd/mm/yy', firstDay: 0, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['ms']); +}); \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-nl.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-nl.js new file mode 100644 index 0000000000..938dc5ef6a --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-nl.js @@ -0,0 +1,19 @@ +/* Dutch (UTF-8) initialisation for the jQuery UI date picker plugin. */ +/* Written by Mathias Bynens */ +jQuery(function($){ + $.datepicker.regional.nl = { + closeText: 'Sluiten', + prevText: '←', + nextText: '→', + currentText: 'Vandaag', + monthNames: ['januari', 'februari', 'maart', 'april', 'mei', 'juni', + 'juli', 'augustus', 'september', 'oktober', 'november', 'december'], + monthNamesShort: ['jan', 'feb', 'maa', 'apr', 'mei', 'jun', + 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'], + dayNames: ['zondag', 'maandag', 'dinsdag', 'woensdag', 'donderdag', 'vrijdag', 'zaterdag'], + dayNamesShort: ['zon', 'maa', 'din', 'woe', 'don', 'vri', 'zat'], + dayNamesMin: ['zo', 'ma', 'di', 'wo', 'do', 'vr', 'za'], + dateFormat: 'dd/mm/yy', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional.nl); +}); \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-no.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-no.js new file mode 100644 index 0000000000..efe5b0de41 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-no.js @@ -0,0 +1,19 @@ +/* Norwegian initialisation for the jQuery UI date picker plugin. */ +/* Written by Naimdjon Takhirov (naimdjon@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['no'] = { + closeText: 'Lukk', + prevText: '«Forrige', + nextText: 'Neste»', + currentText: 'I dag', + monthNames: ['Januar','Februar','Mars','April','Mai','Juni', + 'Juli','August','September','Oktober','November','Desember'], + monthNamesShort: ['Jan','Feb','Mar','Apr','Mai','Jun', + 'Jul','Aug','Sep','Okt','Nov','Des'], + dayNamesShort: ['Søn','Man','Tir','Ons','Tor','Fre','Lør'], + dayNames: ['Søndag','Mandag','Tirsdag','Onsdag','Torsdag','Fredag','Lørdag'], + dayNamesMin: ['Sø','Ma','Ti','On','To','Fr','Lø'], + dateFormat: 'yy-mm-dd', firstDay: 0, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['no']); +}); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-pl.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-pl.js new file mode 100644 index 0000000000..0ce38bea8b --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-pl.js @@ -0,0 +1,19 @@ +/* Polish initialisation for the jQuery UI date picker plugin. */ +/* Written by Jacek Wysocki (jacek.wysocki@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['pl'] = { + closeText: 'Zamknij', + prevText: '<Poprzedni', + nextText: 'Następny>', + currentText: 'Dziś', + monthNames: ['Styczeń','Luty','Marzec','Kwiecień','Maj','Czerwiec', + 'Lipiec','Sierpień','Wrzesień','Październik','Listopad','Grudzień'], + monthNamesShort: ['Sty','Lu','Mar','Kw','Maj','Cze', + 'Lip','Sie','Wrz','Pa','Lis','Gru'], + dayNames: ['Niedziela','Poniedzialek','Wtorek','Środa','Czwartek','Piątek','Sobota'], + dayNamesShort: ['Nie','Pn','Wt','Śr','Czw','Pt','So'], + dayNamesMin: ['N','Pn','Wt','Śr','Cz','Pt','So'], + dateFormat: 'yy-mm-dd', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['pl']); +}); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-pt-BR.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-pt-BR.js new file mode 100644 index 0000000000..e3ac652b3a --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-pt-BR.js @@ -0,0 +1,19 @@ +/* Brazilian initialisation for the jQuery UI date picker plugin. */ +/* Written by Leonildo Costa Silva (leocsilva@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['pt-BR'] = { + closeText: 'Fechar', + prevText: '<Anterior', + nextText: 'Próximo>', + currentText: 'Hoje', + monthNames: ['Janeiro','Fevereiro','Março','Abril','Maio','Junho', + 'Julho','Agosto','Setembro','Outubro','Novembro','Dezembro'], + monthNamesShort: ['Jan','Fev','Mar','Abr','Mai','Jun', + 'Jul','Ago','Set','Out','Nov','Dez'], + dayNames: ['Domingo','Segunda-feira','Terça-feira','Quarta-feira','Quinta-feira','Sexta-feira','Sabado'], + dayNamesShort: ['Dom','Seg','Ter','Qua','Qui','Sex','Sab'], + dayNamesMin: ['Dom','Seg','Ter','Qua','Qui','Sex','Sab'], + dateFormat: 'dd/mm/yy', firstDay: 0, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['pt-BR']); +}); \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-ro.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-ro.js new file mode 100644 index 0000000000..ec4033cc7f --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-ro.js @@ -0,0 +1,22 @@ +/* Romanian initialisation for the jQuery UI date picker plugin. + * + * Written by Edmond L. (ll_edmond@walla.com) + * and Ionut G. Stan (ionut.g.stan@gmail.com) + */ +jQuery(function($){ + $.datepicker.regional['ro'] = { + closeText: 'Închide', + prevText: '« Luna precedentă', + nextText: 'Luna următoare »', + currentText: 'Azi', + monthNames: ['Ianuarie','Februarie','Martie','Aprilie','Mai','Iunie', + 'Iulie','August','Septembrie','Octombrie','Noiembrie','Decembrie'], + monthNamesShort: ['Ian', 'Feb', 'Mar', 'Apr', 'Mai', 'Iun', + 'Iul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + dayNames: ['Duminică', 'Luni', 'MarÅ£i', 'Miercuri', 'Joi', 'Vineri', 'Sâmbătă'], + dayNamesShort: ['Dum', 'Lun', 'Mar', 'Mie', 'Joi', 'Vin', 'Sâm'], + dayNamesMin: ['Du','Lu','Ma','Mi','Jo','Vi','Sâ'], + dateFormat: 'dd MM yy', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['ro']); +}); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-ru.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-ru.js new file mode 100644 index 0000000000..62752c7f58 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-ru.js @@ -0,0 +1,19 @@ +/* Russian (UTF-8) initialisation for the jQuery UI date picker plugin. */ +/* Written by Andrew Stromnov (stromnov@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['ru'] = { + closeText: 'Закрыть', + prevText: '<Пред', + nextText: 'След>', + currentText: 'Сегодня', + monthNames: ['Январь','Февраль','Март','Апрель','Май','Июнь', + 'Июль','Август','Сентябрь','Октябрь','Ноябрь','Декабрь'], + monthNamesShort: ['Янв','Фев','Мар','Апр','Май','Июн', + 'Июл','Авг','Сен','Окт','Ноя','Дек'], + dayNames: ['воскресенье','понедельник','вторник','среда','четверг','пятница','суббота'], + dayNamesShort: ['вск','пнд','втр','срд','чтв','птн','сбт'], + dayNamesMin: ['Вс','Пн','Вт','Ср','Чт','Пт','Сб'], + dateFormat: 'dd.mm.yy', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['ru']); +}); \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-sk.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-sk.js new file mode 100644 index 0000000000..a023ffa77f --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-sk.js @@ -0,0 +1,19 @@ +/* Slovak initialisation for the jQuery UI date picker plugin. */ +/* Written by Vojtech Rinik (vojto@hmm.sk). */ +jQuery(function($){ + $.datepicker.regional['sk'] = { + closeText: 'ZavrieÅ¥', + prevText: '<Predchádzajúci', + nextText: 'Nasledujúci>', + currentText: 'Dnes', + monthNames: ['Január','Február','Marec','Apríl','Máj','Jún', + 'Júl','August','September','Október','November','December'], + monthNamesShort: ['Jan','Feb','Mar','Apr','Máj','Jún', + 'Júl','Aug','Sep','Okt','Nov','Dec'], + dayNames: ['Nedel\'a','Pondelok','Utorok','Streda','Å tvrtok','Piatok','Sobota'], + dayNamesShort: ['Ned','Pon','Uto','Str','Å tv','Pia','Sob'], + dayNamesMin: ['Ne','Po','Ut','St','Å t','Pia','So'], + dateFormat: 'dd.mm.yy', firstDay: 0, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['sk']); +}); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-sl.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-sl.js new file mode 100644 index 0000000000..480a4d8137 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-sl.js @@ -0,0 +1,20 @@ +/* Slovenian initialisation for the jQuery UI date picker plugin. */ +/* Written by Jaka Jancar (jaka@kubje.org). */ +/* c = č, s = š z = ž C = Č S = Š Z = Ž */ +jQuery(function($){ + $.datepicker.regional['sl'] = { + closeText: 'Zapri', + prevText: '<Prejšnji', + nextText: 'Naslednji>', + currentText: 'Trenutni', + monthNames: ['Januar','Februar','Marec','April','Maj','Junij', + 'Julij','Avgust','September','Oktober','November','December'], + monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun', + 'Jul','Avg','Sep','Okt','Nov','Dec'], + dayNames: ['Nedelja','Ponedeljek','Torek','Sreda','Četrtek','Petek','Sobota'], + dayNamesShort: ['Ned','Pon','Tor','Sre','Čet','Pet','Sob'], + dayNamesMin: ['Ne','Po','To','Sr','Če','Pe','So'], + dateFormat: 'dd.mm.yy', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['sl']); +}); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-sq.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-sq.js new file mode 100644 index 0000000000..ac67e68c8b --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-sq.js @@ -0,0 +1,19 @@ +/* Albanian initialisation for the jQuery UI date picker plugin. */ +/* Written by Flakron Bytyqi (flakron@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['sq'] = { + closeText: 'mbylle', + prevText: '<mbrapa', + nextText: 'Përpara>', + currentText: 'sot', + monthNames: ['Janar','Shkurt','Mars','Prill','Maj','Qershor', + 'Korrik','Gusht','Shtator','Tetor','Nëntor','Dhjetor'], + monthNamesShort: ['Jan','Shk','Mar','Pri','Maj','Qer', + 'Kor','Gus','Sht','Tet','Nën','Dhj'], + dayNames: ['E Diel','E Hënë','E Martë','E Mërkurë','E Enjte','E Premte','E Shtune'], + dayNamesShort: ['Di','Hë','Ma','Më','En','Pr','Sh'], + dayNamesMin: ['Di','Hë','Ma','Më','En','Pr','Sh'], + dateFormat: 'dd.mm.yy', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['sq']); +}); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-sr-SR.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-sr-SR.js new file mode 100644 index 0000000000..059fc3831c --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-sr-SR.js @@ -0,0 +1,19 @@ +/* Serbian i18n for the jQuery UI date picker plugin. */ +/* Written by Dejan Dimić. */ +jQuery(function($){ + $.datepicker.regional['sr-SR'] = { + closeText: 'Zatvori', + prevText: '<', + nextText: '>', + currentText: 'Danas', + monthNames: ['Januar','Februar','Mart','April','Maj','Jun', + 'Jul','Avgust','Septembar','Oktobar','Novembar','Decembar'], + monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun', + 'Jul','Avg','Sep','Okt','Nov','Dec'], + dayNames: ['Nedelja','Ponedeljak','Utorak','Sreda','Četvrtak','Petak','Subota'], + dayNamesShort: ['Ned','Pon','Uto','Sre','Čet','Pet','Sub'], + dayNamesMin: ['Ne','Po','Ut','Sr','Če','Pe','Su'], + dateFormat: 'dd/mm/yy', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['sr-SR']); +}); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-sr.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-sr.js new file mode 100644 index 0000000000..179458ba0d --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-sr.js @@ -0,0 +1,19 @@ +/* Serbian i18n for the jQuery UI date picker plugin. */ +/* Written by Dejan Dimić. */ +jQuery(function($){ + $.datepicker.regional['sr'] = { + closeText: 'Затвори', + prevText: '<', + nextText: '>', + currentText: 'Данас', + monthNames: ['Јануар','Фебруар','Март','Април','Мај','Јун', + 'Јул','Август','Септембар','Октобар','Новембар','Децембар'], + monthNamesShort: ['Јан','Феб','Мар','Апр','Мај','Јун', + 'Јул','Авг','Сеп','Окт','Нов','Дец'], + dayNames: ['Недеља','Понедељак','Уторак','Среда','Четвртак','Петак','Субота'], + dayNamesShort: ['Нед','Пон','Уто','Сре','Чет','Пет','Суб'], + dayNamesMin: ['Не','По','Ут','Ср','Че','Пе','Су'], + dateFormat: 'dd/mm/yy', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['sr']); +}); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-sv.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-sv.js new file mode 100644 index 0000000000..47c4b24e4d --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-sv.js @@ -0,0 +1,19 @@ +/* Swedish initialisation for the jQuery UI date picker plugin. */ +/* Written by Anders Ekdahl ( anders@nomadiz.se). */ +jQuery(function($){ + $.datepicker.regional['sv'] = { + closeText: 'Stäng', + prevText: '«Förra', + nextText: 'Nästa»', + currentText: 'Idag', + monthNames: ['Januari','Februari','Mars','April','Maj','Juni', + 'Juli','Augusti','September','Oktober','November','December'], + monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun', + 'Jul','Aug','Sep','Okt','Nov','Dec'], + dayNamesShort: ['Sön','MÃ¥n','Tis','Ons','Tor','Fre','Lör'], + dayNames: ['Söndag','MÃ¥ndag','Tisdag','Onsdag','Torsdag','Fredag','Lördag'], + dayNamesMin: ['Sö','MÃ¥','Ti','On','To','Fr','Lö'], + dateFormat: 'yy-mm-dd', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['sv']); +}); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-th.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-th.js new file mode 100644 index 0000000000..3c2a02b5e0 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-th.js @@ -0,0 +1,19 @@ +/* Thai initialisation for the jQuery UI date picker plugin. */ +/* Written by pipo (pipo@sixhead.com). */ +jQuery(function($){ + $.datepicker.regional['th'] = { + closeText: 'ปิด', + prevText: '« à¸¢à¹‰à¸­à¸™', + nextText: 'ถัดไป »', + currentText: 'วันนี้', + monthNames: ['มกราคม','กุมภาพันธ์','มีนาคม','เมษายน','พฤษภาคม','มิถุนายน', + 'กรกฏาคม','สิงหาคม','กันยายน','ตุลาคม','พฤศจิกายน','ธันวาคม'], + monthNamesShort: ['ม.ค.','ก.พ.','มี.ค.','เม.ย.','พ.ค.','มิ.ย.', + 'ก.ค.','ส.ค.','ก.ย.','ต.ค.','พ.ย.','ธ.ค.'], + dayNames: ['อาทิตย์','จันทร์','อังคาร','พุธ','พฤหัสบดี','ศุกร์','เสาร์'], + dayNamesShort: ['อา.','จ.','อ.','พ.','พฤ.','ศ.','ส.'], + dayNamesMin: ['อา.','จ.','อ.','พ.','พฤ.','ศ.','ส.'], + dateFormat: 'dd/mm/yy', firstDay: 0, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['th']); +}); \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-tr.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-tr.js new file mode 100644 index 0000000000..5817b2ac06 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-tr.js @@ -0,0 +1,19 @@ +/* Turkish initialisation for the jQuery UI date picker plugin. */ +/* Written by Izzet Emre Erkan (kara@karalamalar.net). */ +jQuery(function($){ + $.datepicker.regional['tr'] = { + closeText: 'kapat', + prevText: '<geri', + nextText: 'ileri>', + currentText: 'bugün', + monthNames: ['Ocak','Şubat','Mart','Nisan','Mayıs','Haziran', + 'Temmuz','Ağustos','Eylül','Ekim','Kasım','Aralık'], + monthNamesShort: ['Oca','Şub','Mar','Nis','May','Haz', + 'Tem','Ağu','Eyl','Eki','Kas','Ara'], + dayNames: ['Pazar','Pazartesi','Salı','Çarşamba','Perşembe','Cuma','Cumartesi'], + dayNamesShort: ['Pz','Pt','Sa','Ça','Pe','Cu','Ct'], + dayNamesMin: ['Pz','Pt','Sa','Ça','Pe','Cu','Ct'], + dateFormat: 'dd.mm.yy', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['tr']); +}); \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-uk.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-uk.js new file mode 100644 index 0000000000..1043d7cd81 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-uk.js @@ -0,0 +1,25 @@ +/* Ukrainian (UTF-8) initialisation for the jQuery UI date picker plugin. */ +/* Written by Maxim Drogobitskiy (maxdao@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['uk'] = { + clearText: 'Очистити', clearStatus: '', + closeText: 'Закрити', closeStatus: '', + prevText: '<', prevStatus: '', + prevBigText: '<<', prevBigStatus: '', + nextText: '>', nextStatus: '', + nextBigText: '>>', nextBigStatus: '', + currentText: 'Сьогодні', currentStatus: '', + monthNames: ['Січень','Лютий','Березень','Квітень','Травень','Червень', + 'Липень','Серпень','Вересень','Жовтень','Листопад','Грудень'], + monthNamesShort: ['Січ','Лют','Бер','Кві','Тра','Чер', + 'Лип','Сер','Вер','Жов','Лис','Гру'], + monthStatus: '', yearStatus: '', + weekHeader: 'Не', weekStatus: '', + dayNames: ['неділя','понеділок','вівторок','середа','четвер','п’ятниця','субота'], + dayNamesShort: ['нед','пнд','вів','срд','чтв','птн','сбт'], + dayNamesMin: ['Нд','Пн','Вт','Ср','Чт','Пт','Сб'], + dayStatus: 'DD', dateStatus: 'D, M d', + dateFormat: 'dd/mm/yy', firstDay: 1, + initStatus: '', isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['uk']); +}); \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-zh-CN.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-zh-CN.js new file mode 100644 index 0000000000..e3a69dc6d9 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-zh-CN.js @@ -0,0 +1,19 @@ +/* Chinese initialisation for the jQuery UI date picker plugin. */ +/* Written by Cloudream (cloudream@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['zh-CN'] = { + closeText: '关闭', + prevText: '<上月', + nextText: '下月>', + currentText: '今天', + monthNames: ['一月','二月','三月','四月','五月','六月', + '七月','八月','九月','十月','十一月','十二月'], + monthNamesShort: ['一','二','三','四','五','六', + '七','八','九','十','十一','十二'], + dayNames: ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'], + dayNamesShort: ['周日','周一','周二','周三','周四','周五','周六'], + dayNamesMin: ['日','一','二','三','四','五','六'], + dateFormat: 'yy-mm-dd', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['zh-CN']); +}); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-zh-TW.js b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-zh-TW.js new file mode 100644 index 0000000000..9cb49b72bb --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/i18n/ui.datepicker-zh-TW.js @@ -0,0 +1,19 @@ +/* Chinese initialisation for the jQuery UI date picker plugin. */ +/* Written by Ressol (ressol@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['zh-TW'] = { + closeText: '關閉', + prevText: '<上月', + nextText: '下月>', + currentText: '今天', + monthNames: ['一月','二月','三月','四月','五月','六月', + '七月','八月','九月','十月','十一月','十二月'], + monthNamesShort: ['一','二','三','四','五','六', + '七','八','九','十','十一','十二'], + dayNames: ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'], + dayNamesShort: ['周日','周一','周二','周三','周四','周五','周六'], + dayNamesMin: ['日','一','二','三','四','五','六'], + dateFormat: 'yy/mm/dd', firstDay: 1, + isRTL: false}; + $.datepicker.setDefaults($.datepicker.regional['zh-TW']); +}); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/jquery-ui-1.7.1.custom.js b/js2/mwEmbed/jquery/jquery.ui/ui/jquery-ui-1.7.1.custom.js new file mode 100644 index 0000000000..eac07e6c25 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/jquery-ui-1.7.1.custom.js @@ -0,0 +1,9074 @@ +/* + * jQuery UI 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI + */ +;jQuery.ui || (function($) { + +var _remove = $.fn.remove, + isFF2 = $.browser.mozilla && (parseFloat($.browser.version) < 1.9); + +//Helper functions and ui object +$.ui = { + version: "1.7.1", + + // $.ui.plugin is deprecated. Use the proxy pattern instead. + plugin: { + add: function(module, option, set) { + var proto = $.ui[module].prototype; + for(var i in set) { + proto.plugins[i] = proto.plugins[i] || []; + proto.plugins[i].push([option, set[i]]); + } + }, + call: function(instance, name, args) { + var set = instance.plugins[name]; + if(!set || !instance.element[0].parentNode) { return; } + + for (var i = 0; i < set.length; i++) { + if (instance.options[set[i][0]]) { + set[i][1].apply(instance.element, args); + } + } + } + }, + + contains: function(a, b) { + return document.compareDocumentPosition + ? a.compareDocumentPosition(b) & 16 + : a !== b && a.contains(b); + }, + + hasScroll: function(el, a) { + + //If overflow is hidden, the element might have extra content, but the user wants to hide it + if ($(el).css('overflow') == 'hidden') { return false; } + + var scroll = (a && a == 'left') ? 'scrollLeft' : 'scrollTop', + has = false; + + if (el[scroll] > 0) { return true; } + + // TODO: determine which cases actually cause this to happen + // if the element doesn't have the scroll set, see if it's possible to + // set the scroll + el[scroll] = 1; + has = (el[scroll] > 0); + el[scroll] = 0; + return has; + }, + + isOverAxis: function(x, reference, size) { + //Determines when x coordinate is over "b" element axis + return (x > reference) && (x < (reference + size)); + }, + + isOver: function(y, x, top, left, height, width) { + //Determines when x, y coordinates is over "b" element + return $.ui.isOverAxis(y, top, height) && $.ui.isOverAxis(x, left, width); + }, + + keyCode: { + BACKSPACE: 8, + CAPS_LOCK: 20, + COMMA: 188, + CONTROL: 17, + DELETE: 46, + DOWN: 40, + END: 35, + ENTER: 13, + ESCAPE: 27, + HOME: 36, + INSERT: 45, + LEFT: 37, + NUMPAD_ADD: 107, + NUMPAD_DECIMAL: 110, + NUMPAD_DIVIDE: 111, + NUMPAD_ENTER: 108, + NUMPAD_MULTIPLY: 106, + NUMPAD_SUBTRACT: 109, + PAGE_DOWN: 34, + PAGE_UP: 33, + PERIOD: 190, + RIGHT: 39, + SHIFT: 16, + SPACE: 32, + TAB: 9, + UP: 38 + } +}; + +// WAI-ARIA normalization +if (isFF2) { + var attr = $.attr, + removeAttr = $.fn.removeAttr, + ariaNS = "http://www.w3.org/2005/07/aaa", + ariaState = /^aria-/, + ariaRole = /^wairole:/; + + $.attr = function(elem, name, value) { + var set = value !== undefined; + + return (name == 'role' + ? (set + ? attr.call(this, elem, name, "wairole:" + value) + : (attr.apply(this, arguments) || "").replace(ariaRole, "")) + : (ariaState.test(name) + ? (set + ? elem.setAttributeNS(ariaNS, + name.replace(ariaState, "aaa:"), value) + : attr.call(this, elem, name.replace(ariaState, "aaa:"))) + : attr.apply(this, arguments))); + }; + + $.fn.removeAttr = function(name) { + return (ariaState.test(name) + ? this.each(function() { + this.removeAttributeNS(ariaNS, name.replace(ariaState, "")); + }) : removeAttr.call(this, name)); + }; +} + +//jQuery plugins +$.fn.extend({ + remove: function() { + // Safari has a native remove event which actually removes DOM elements, + // so we have to use triggerHandler instead of trigger (#3037). + $("*", this).add(this).each(function() { + $(this).triggerHandler("remove"); + }); + return _remove.apply(this, arguments ); + }, + + enableSelection: function() { + return this + .attr('unselectable', 'off') + .css('MozUserSelect', '') + .unbind('selectstart.ui'); + }, + + disableSelection: function() { + return this + .attr('unselectable', 'on') + .css('MozUserSelect', 'none') + .bind('selectstart.ui', function() { return false; }); + }, + + scrollParent: function() { + var scrollParent; + if(($.browser.msie && (/(static|relative)/).test(this.css('position'))) || (/absolute/).test(this.css('position'))) { + scrollParent = this.parents().filter(function() { + return (/(relative|absolute|fixed)/).test($.curCSS(this,'position',1)) && (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1)); + }).eq(0); + } else { + scrollParent = this.parents().filter(function() { + return (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1)); + }).eq(0); + } + + return (/fixed/).test(this.css('position')) || !scrollParent.length ? $(document) : scrollParent; + } +}); + + +//Additional selectors +$.extend($.expr[':'], { + data: function(elem, i, match) { + return !!$.data(elem, match[3]); + }, + + focusable: function(element) { + var nodeName = element.nodeName.toLowerCase(), + tabIndex = $.attr(element, 'tabindex'); + return (/input|select|textarea|button|object/.test(nodeName) + ? !element.disabled + : 'a' == nodeName || 'area' == nodeName + ? element.href || !isNaN(tabIndex) + : !isNaN(tabIndex)) + // the element and all of its ancestors must be visible + // the browser may report that the area is hidden + && !$(element)['area' == nodeName ? 'parents' : 'closest'](':hidden').length; + }, + + tabbable: function(element) { + var tabIndex = $.attr(element, 'tabindex'); + return (isNaN(tabIndex) || tabIndex >= 0) && $(element).is(':focusable'); + } +}); + + +// $.widget is a factory to create jQuery plugins +// taking some boilerplate code out of the plugin code +function getter(namespace, plugin, method, args) { + function getMethods(type) { + var methods = $[namespace][plugin][type] || []; + return (typeof methods == 'string' ? methods.split(/,?\s+/) : methods); + } + + var methods = getMethods('getter'); + if (args.length == 1 && typeof args[0] == 'string') { + methods = methods.concat(getMethods('getterSetter')); + } + return ($.inArray(method, methods) != -1); +} + +$.widget = function(name, prototype) { + var namespace = name.split(".")[0]; + name = name.split(".")[1]; + + // create plugin method + $.fn[name] = function(options) { + var isMethodCall = (typeof options == 'string'), + args = Array.prototype.slice.call(arguments, 1); + + // prevent calls to internal methods + if (isMethodCall && options.substring(0, 1) == '_') { + return this; + } + + // handle getter methods + if (isMethodCall && getter(namespace, name, options, args)) { + var instance = $.data(this[0], name); + return (instance ? instance[options].apply(instance, args) + : undefined); + } + + // handle initialization and non-getter methods + return this.each(function() { + var instance = $.data(this, name); + + // constructor + (!instance && !isMethodCall && + $.data(this, name, new $[namespace][name](this, options))._init()); + + // method call + (instance && isMethodCall && $.isFunction(instance[options]) && + instance[options].apply(instance, args)); + }); + }; + + // create widget constructor + $[namespace] = $[namespace] || {}; + $[namespace][name] = function(element, options) { + var self = this; + + this.namespace = namespace; + this.widgetName = name; + this.widgetEventPrefix = $[namespace][name].eventPrefix || name; + this.widgetBaseClass = namespace + '-' + name; + + this.options = $.extend({}, + $.widget.defaults, + $[namespace][name].defaults, + $.metadata && $.metadata.get(element)[name], + options); + + this.element = $(element) + .bind('setData.' + name, function(event, key, value) { + if (event.target == element) { + return self._setData(key, value); + } + }) + .bind('getData.' + name, function(event, key) { + if (event.target == element) { + return self._getData(key); + } + }) + .bind('remove', function() { + return self.destroy(); + }); + }; + + // add widget prototype + $[namespace][name].prototype = $.extend({}, $.widget.prototype, prototype); + + // TODO: merge getter and getterSetter properties from widget prototype + // and plugin prototype + $[namespace][name].getterSetter = 'option'; +}; + +$.widget.prototype = { + _init: function() {}, + destroy: function() { + this.element.removeData(this.widgetName) + .removeClass(this.widgetBaseClass + '-disabled' + ' ' + this.namespace + '-state-disabled') + .removeAttr('aria-disabled'); + }, + + option: function(key, value) { + var options = key, + self = this; + + if (typeof key == "string") { + if (value === undefined) { + return this._getData(key); + } + options = {}; + options[key] = value; + } + + $.each(options, function(key, value) { + self._setData(key, value); + }); + }, + _getData: function(key) { + return this.options[key]; + }, + _setData: function(key, value) { + this.options[key] = value; + + if (key == 'disabled') { + this.element + [value ? 'addClass' : 'removeClass']( + this.widgetBaseClass + '-disabled' + ' ' + + this.namespace + '-state-disabled') + .attr("aria-disabled", value); + } + }, + + enable: function() { + this._setData('disabled', false); + }, + disable: function() { + this._setData('disabled', true); + }, + + _trigger: function(type, event, data) { + var callback = this.options[type], + eventName = (type == this.widgetEventPrefix + ? type : this.widgetEventPrefix + type); + + event = $.Event(event); + event.type = eventName; + + // copy original event properties over to the new event + // this would happen if we could call $.event.fix instead of $.Event + // but we don't have a way to force an event to be fixed multiple times + if (event.originalEvent) { + for (var i = $.event.props.length, prop; i;) { + prop = $.event.props[--i]; + event[prop] = event.originalEvent[prop]; + } + } + + this.element.trigger(event, data); + + return !($.isFunction(callback) && callback.call(this.element[0], event, data) === false + || event.isDefaultPrevented()); + } +}; + +$.widget.defaults = { + disabled: false +}; + + +/** Mouse Interaction Plugin **/ + +$.ui.mouse = { + _mouseInit: function() { + var self = this; + + this.element + .bind('mousedown.'+this.widgetName, function(event) { + return self._mouseDown(event); + }) + .bind('click.'+this.widgetName, function(event) { + if(self._preventClickEvent) { + self._preventClickEvent = false; + event.stopImmediatePropagation(); + return false; + } + }); + + // Prevent text selection in IE + if ($.browser.msie) { + this._mouseUnselectable = this.element.attr('unselectable'); + this.element.attr('unselectable', 'on'); + } + + this.started = false; + }, + + // TODO: make sure destroying one instance of mouse doesn't mess with + // other instances of mouse + _mouseDestroy: function() { + this.element.unbind('.'+this.widgetName); + + // Restore text selection in IE + ($.browser.msie + && this.element.attr('unselectable', this._mouseUnselectable)); + }, + + _mouseDown: function(event) { + // don't let more than one widget handle mouseStart + // TODO: figure out why we have to use originalEvent + event.originalEvent = event.originalEvent || {}; + if (event.originalEvent.mouseHandled) { return; } + + // we may have missed mouseup (out of window) + (this._mouseStarted && this._mouseUp(event)); + + this._mouseDownEvent = event; + + var self = this, + btnIsLeft = (event.which == 1), + elIsCancel = (typeof this.options.cancel == "string" ? $(event.target).parents().add(event.target).filter(this.options.cancel).length : false); + if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) { + return true; + } + + this.mouseDelayMet = !this.options.delay; + if (!this.mouseDelayMet) { + this._mouseDelayTimer = setTimeout(function() { + self.mouseDelayMet = true; + }, this.options.delay); + } + + if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { + this._mouseStarted = (this._mouseStart(event) !== false); + if (!this._mouseStarted) { + event.preventDefault(); + return true; + } + } + + // these delegates are required to keep context + this._mouseMoveDelegate = function(event) { + return self._mouseMove(event); + }; + this._mouseUpDelegate = function(event) { + return self._mouseUp(event); + }; + $(document) + .bind('mousemove.'+this.widgetName, this._mouseMoveDelegate) + .bind('mouseup.'+this.widgetName, this._mouseUpDelegate); + + // preventDefault() is used to prevent the selection of text here - + // however, in Safari, this causes select boxes not to be selectable + // anymore, so this fix is needed + ($.browser.safari || event.preventDefault()); + + event.originalEvent.mouseHandled = true; + return true; + }, + + _mouseMove: function(event) { + // IE mouseup check - mouseup happened when mouse was out of window + if ($.browser.msie && !event.button) { + return this._mouseUp(event); + } + + if (this._mouseStarted) { + this._mouseDrag(event); + return event.preventDefault(); + } + + if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { + this._mouseStarted = + (this._mouseStart(this._mouseDownEvent, event) !== false); + (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event)); + } + + return !this._mouseStarted; + }, + + _mouseUp: function(event) { + $(document) + .unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate) + .unbind('mouseup.'+this.widgetName, this._mouseUpDelegate); + + if (this._mouseStarted) { + this._mouseStarted = false; + this._preventClickEvent = (event.target == this._mouseDownEvent.target); + this._mouseStop(event); + } + + return false; + }, + + _mouseDistanceMet: function(event) { + return (Math.max( + Math.abs(this._mouseDownEvent.pageX - event.pageX), + Math.abs(this._mouseDownEvent.pageY - event.pageY) + ) >= this.options.distance + ); + }, + + _mouseDelayMet: function(event) { + return this.mouseDelayMet; + }, + + // These are placeholder methods, to be overriden by extending plugin + _mouseStart: function(event) {}, + _mouseDrag: function(event) {}, + _mouseStop: function(event) {}, + _mouseCapture: function(event) { return true; } +}; + +$.ui.mouse.defaults = { + cancel: null, + distance: 1, + delay: 0 +}; + +})(jQuery); +/* + * jQuery UI Draggable 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Draggables + * + * Depends: + * ui.core.js + */ +(function($) { + +$.widget("ui.draggable", $.extend({}, $.ui.mouse, { + + _init: function() { + + if (this.options.helper == 'original' && !(/^(?:r|a|f)/).test(this.element.css("position"))) + this.element[0].style.position = 'relative'; + + (this.options.addClasses && this.element.addClass("ui-draggable")); + (this.options.disabled && this.element.addClass("ui-draggable-disabled")); + + this._mouseInit(); + + }, + + destroy: function() { + if(!this.element.data('draggable')) return; + this.element + .removeData("draggable") + .unbind(".draggable") + .removeClass("ui-draggable" + + " ui-draggable-dragging" + + " ui-draggable-disabled"); + this._mouseDestroy(); + }, + + _mouseCapture: function(event) { + + var o = this.options; + + if (this.helper || o.disabled || $(event.target).is('.ui-resizable-handle')) + return false; + + //Quit if we're not on a valid handle + this.handle = this._getHandle(event); + if (!this.handle) + return false; + + return true; + + }, + + _mouseStart: function(event) { + + var o = this.options; + + //Create and append the visible helper + this.helper = this._createHelper(event); + + //Cache the helper size + this._cacheHelperProportions(); + + //If ddmanager is used for droppables, set the global draggable + if($.ui.ddmanager) + $.ui.ddmanager.current = this; + + /* + * - Position generation - + * This block generates everything position related - it's the core of draggables. + */ + + //Cache the margins of the original element + this._cacheMargins(); + + //Store the helper's css position + this.cssPosition = this.helper.css("position"); + this.scrollParent = this.helper.scrollParent(); + + //The element's absolute position on the page minus margins + this.offset = this.element.offset(); + this.offset = { + top: this.offset.top - this.margins.top, + left: this.offset.left - this.margins.left + }; + + $.extend(this.offset, { + click: { //Where the click happened, relative to the element + left: event.pageX - this.offset.left, + top: event.pageY - this.offset.top + }, + parent: this._getParentOffset(), + relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper + }); + + //Generate the original position + this.originalPosition = this._generatePosition(event); + this.originalPageX = event.pageX; + this.originalPageY = event.pageY; + + //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied + if(o.cursorAt) + this._adjustOffsetFromHelper(o.cursorAt); + + //Set a containment if given in the options + if(o.containment) + this._setContainment(); + + //Call plugins and callbacks + this._trigger("start", event); + + //Recache the helper size + this._cacheHelperProportions(); + + //Prepare the droppable offsets + if ($.ui.ddmanager && !o.dropBehaviour) + $.ui.ddmanager.prepareOffsets(this, event); + + this.helper.addClass("ui-draggable-dragging"); + this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position + return true; + }, + + _mouseDrag: function(event, noPropagation) { + + //Compute the helpers position + this.position = this._generatePosition(event); + this.positionAbs = this._convertPositionTo("absolute"); + + //Call plugins and callbacks and use the resulting position if something is returned + if (!noPropagation) { + var ui = this._uiHash(); + this._trigger('drag', event, ui); + this.position = ui.position; + } + + if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px'; + if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px'; + if($.ui.ddmanager) $.ui.ddmanager.drag(this, event); + + return false; + }, + + _mouseStop: function(event) { + + //If we are using droppables, inform the manager about the drop + var dropped = false; + if ($.ui.ddmanager && !this.options.dropBehaviour) + dropped = $.ui.ddmanager.drop(this, event); + + //if a drop comes from outside (a sortable) + if(this.dropped) { + dropped = this.dropped; + this.dropped = false; + } + + if((this.options.revert == "invalid" && !dropped) || (this.options.revert == "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) { + var self = this; + $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() { + self._trigger("stop", event); + self._clear(); + }); + } else { + this._trigger("stop", event); + this._clear(); + } + + return false; + }, + + _getHandle: function(event) { + + var handle = !this.options.handle || !$(this.options.handle, this.element).length ? true : false; + $(this.options.handle, this.element) + .find("*") + .andSelf() + .each(function() { + if(this == event.target) handle = true; + }); + + return handle; + + }, + + _createHelper: function(event) { + + var o = this.options; + var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper == 'clone' ? this.element.clone() : this.element); + + if(!helper.parents('body').length) + helper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo)); + + if(helper[0] != this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) + helper.css("position", "absolute"); + + return helper; + + }, + + _adjustOffsetFromHelper: function(obj) { + if(obj.left != undefined) this.offset.click.left = obj.left + this.margins.left; + if(obj.right != undefined) this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; + if(obj.top != undefined) this.offset.click.top = obj.top + this.margins.top; + if(obj.bottom != undefined) this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; + }, + + _getParentOffset: function() { + + //Get the offsetParent and cache its position + this.offsetParent = this.helper.offsetParent(); + var po = this.offsetParent.offset(); + + // This is a special case where we need to modify a offset calculated on start, since the following happened: + // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent + // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that + // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag + if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) { + po.left += this.scrollParent.scrollLeft(); + po.top += this.scrollParent.scrollTop(); + } + + if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information + || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix + po = { top: 0, left: 0 }; + + return { + top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), + left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) + }; + + }, + + _getRelativeOffset: function() { + + if(this.cssPosition == "relative") { + var p = this.element.position(); + return { + top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), + left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() + }; + } else { + return { top: 0, left: 0 }; + } + + }, + + _cacheMargins: function() { + this.margins = { + left: (parseInt(this.element.css("marginLeft"),10) || 0), + top: (parseInt(this.element.css("marginTop"),10) || 0) + }; + }, + + _cacheHelperProportions: function() { + this.helperProportions = { + width: this.helper.outerWidth(), + height: this.helper.outerHeight() + }; + }, + + _setContainment: function() { + + var o = this.options; + if(o.containment == 'parent') o.containment = this.helper[0].parentNode; + if(o.containment == 'document' || o.containment == 'window') this.containment = [ + 0 - this.offset.relative.left - this.offset.parent.left, + 0 - this.offset.relative.top - this.offset.parent.top, + $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left, + ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top + ]; + + if(!(/^(document|window|parent)$/).test(o.containment) && o.containment.constructor != Array) { + var ce = $(o.containment)[0]; if(!ce) return; + var co = $(o.containment).offset(); + var over = ($(ce).css("overflow") != 'hidden'); + + this.containment = [ + co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left, + co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top, + co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left, + co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top + ]; + } else if(o.containment.constructor == Array) { + this.containment = o.containment; + } + + }, + + _convertPositionTo: function(d, pos) { + + if(!pos) pos = this.position; + var mod = d == "absolute" ? 1 : -1; + var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); + + return { + top: ( + pos.top // The absolute mouse position + + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent + + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border) + - ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) + ), + left: ( + pos.left // The absolute mouse position + + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent + + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border) + - ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) + ) + }; + + }, + + _generatePosition: function(event) { + + var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); + + // This is another very weird special case that only happens for relative elements: + // 1. If the css position is relative + // 2. and the scroll parent is the document or similar to the offset parent + // we have to refresh the relative offset during the scroll so there are no jumps + if(this.cssPosition == 'relative' && !(this.scrollParent[0] != document && this.scrollParent[0] != this.offsetParent[0])) { + this.offset.relative = this._getRelativeOffset(); + } + + var pageX = event.pageX; + var pageY = event.pageY; + + /* + * - Position constraining - + * Constrain the position to a mix of grid, containment. + */ + + if(this.originalPosition) { //If we are not dragging yet, we won't check for options + + if(this.containment) { + if(event.pageX - this.offset.click.left < this.containment[0]) pageX = this.containment[0] + this.offset.click.left; + if(event.pageY - this.offset.click.top < this.containment[1]) pageY = this.containment[1] + this.offset.click.top; + if(event.pageX - this.offset.click.left > this.containment[2]) pageX = this.containment[2] + this.offset.click.left; + if(event.pageY - this.offset.click.top > this.containment[3]) pageY = this.containment[3] + this.offset.click.top; + } + + if(o.grid) { + var top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1]; + pageY = this.containment ? (!(top - this.offset.click.top < this.containment[1] || top - this.offset.click.top > this.containment[3]) ? top : (!(top - this.offset.click.top < this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; + + var left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0]; + pageX = this.containment ? (!(left - this.offset.click.left < this.containment[0] || left - this.offset.click.left > this.containment[2]) ? left : (!(left - this.offset.click.left < this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; + } + + } + + return { + top: ( + pageY // The absolute mouse position + - this.offset.click.top // Click offset (relative to the element) + - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent + - this.offset.parent.top // The offsetParent's offset without borders (offset + border) + + ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) + ), + left: ( + pageX // The absolute mouse position + - this.offset.click.left // Click offset (relative to the element) + - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent + - this.offset.parent.left // The offsetParent's offset without borders (offset + border) + + ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) + ) + }; + + }, + + _clear: function() { + this.helper.removeClass("ui-draggable-dragging"); + if(this.helper[0] != this.element[0] && !this.cancelHelperRemoval) this.helper.remove(); + //if($.ui.ddmanager) $.ui.ddmanager.current = null; + this.helper = null; + this.cancelHelperRemoval = false; + }, + + // From now on bulk stuff - mainly helpers + + _trigger: function(type, event, ui) { + ui = ui || this._uiHash(); + $.ui.plugin.call(this, type, [event, ui]); + if(type == "drag") this.positionAbs = this._convertPositionTo("absolute"); //The absolute position has to be recalculated after plugins + return $.widget.prototype._trigger.call(this, type, event, ui); + }, + + plugins: {}, + + _uiHash: function(event) { + return { + helper: this.helper, + position: this.position, + absolutePosition: this.positionAbs, //deprecated + offset: this.positionAbs + }; + } + +})); + +$.extend($.ui.draggable, { + version: "1.7.1", + eventPrefix: "drag", + defaults: { + addClasses: true, + appendTo: "parent", + axis: false, + cancel: ":input,option", + connectToSortable: false, + containment: false, + cursor: "auto", + cursorAt: false, + delay: 0, + distance: 1, + grid: false, + handle: false, + helper: "original", + iframeFix: false, + opacity: false, + refreshPositions: false, + revert: false, + revertDuration: 500, + scope: "default", + scroll: true, + scrollSensitivity: 20, + scrollSpeed: 20, + snap: false, + snapMode: "both", + snapTolerance: 20, + stack: false, + zIndex: false + } +}); + +$.ui.plugin.add("draggable", "connectToSortable", { + start: function(event, ui) { + + var inst = $(this).data("draggable"), o = inst.options, + uiSortable = $.extend({}, ui, { item: inst.element }); + inst.sortables = []; + $(o.connectToSortable).each(function() { + var sortable = $.data(this, 'sortable'); + if (sortable && !sortable.options.disabled) { + inst.sortables.push({ + instance: sortable, + shouldRevert: sortable.options.revert + }); + sortable._refreshItems(); //Do a one-time refresh at start to refresh the containerCache + sortable._trigger("activate", event, uiSortable); + } + }); + + }, + stop: function(event, ui) { + + //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper + var inst = $(this).data("draggable"), + uiSortable = $.extend({}, ui, { item: inst.element }); + + $.each(inst.sortables, function() { + if(this.instance.isOver) { + + this.instance.isOver = 0; + + inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance + this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work) + + //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: 'valid/invalid' + if(this.shouldRevert) this.instance.options.revert = true; + + //Trigger the stop of the sortable + this.instance._mouseStop(event); + + this.instance.options.helper = this.instance.options._helper; + + //If the helper has been the original item, restore properties in the sortable + if(inst.options.helper == 'original') + this.instance.currentItem.css({ top: 'auto', left: 'auto' }); + + } else { + this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance + this.instance._trigger("deactivate", event, uiSortable); + } + + }); + + }, + drag: function(event, ui) { + + var inst = $(this).data("draggable"), self = this; + + var checkPos = function(o) { + var dyClick = this.offset.click.top, dxClick = this.offset.click.left; + var helperTop = this.positionAbs.top, helperLeft = this.positionAbs.left; + var itemHeight = o.height, itemWidth = o.width; + var itemTop = o.top, itemLeft = o.left; + + return $.ui.isOver(helperTop + dyClick, helperLeft + dxClick, itemTop, itemLeft, itemHeight, itemWidth); + }; + + $.each(inst.sortables, function(i) { + + //Copy over some variables to allow calling the sortable's native _intersectsWith + this.instance.positionAbs = inst.positionAbs; + this.instance.helperProportions = inst.helperProportions; + this.instance.offset.click = inst.offset.click; + + if(this.instance._intersectsWith(this.instance.containerCache)) { + + //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once + if(!this.instance.isOver) { + + this.instance.isOver = 1; + //Now we fake the start of dragging for the sortable instance, + //by cloning the list group item, appending it to the sortable and using it as inst.currentItem + //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one) + this.instance.currentItem = $(self).clone().appendTo(this.instance.element).data("sortable-item", true); + this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it + this.instance.options.helper = function() { return ui.helper[0]; }; + + event.target = this.instance.currentItem[0]; + this.instance._mouseCapture(event, true); + this.instance._mouseStart(event, true, true); + + //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes + this.instance.offset.click.top = inst.offset.click.top; + this.instance.offset.click.left = inst.offset.click.left; + this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left; + this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top; + + inst._trigger("toSortable", event); + inst.dropped = this.instance.element; //draggable revert needs that + //hack so receive/update callbacks work (mostly) + inst.currentItem = inst.element; + this.instance.fromOutside = inst; + + } + + //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable + if(this.instance.currentItem) this.instance._mouseDrag(event); + + } else { + + //If it doesn't intersect with the sortable, and it intersected before, + //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval + if(this.instance.isOver) { + + this.instance.isOver = 0; + this.instance.cancelHelperRemoval = true; + + //Prevent reverting on this forced stop + this.instance.options.revert = false; + + // The out event needs to be triggered independently + this.instance._trigger('out', event, this.instance._uiHash(this.instance)); + + this.instance._mouseStop(event, true); + this.instance.options.helper = this.instance.options._helper; + + //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size + this.instance.currentItem.remove(); + if(this.instance.placeholder) this.instance.placeholder.remove(); + + inst._trigger("fromSortable", event); + inst.dropped = false; //draggable revert needs that + } + + }; + + }); + + } +}); + +$.ui.plugin.add("draggable", "cursor", { + start: function(event, ui) { + var t = $('body'), o = $(this).data('draggable').options; + if (t.css("cursor")) o._cursor = t.css("cursor"); + t.css("cursor", o.cursor); + }, + stop: function(event, ui) { + var o = $(this).data('draggable').options; + if (o._cursor) $('body').css("cursor", o._cursor); + } +}); + +$.ui.plugin.add("draggable", "iframeFix", { + start: function(event, ui) { + var o = $(this).data('draggable').options; + $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() { + $('
    ') + .css({ + width: this.offsetWidth+"px", height: this.offsetHeight+"px", + position: "absolute", opacity: "0.001", zIndex: 1000 + }) + .css($(this).offset()) + .appendTo("body"); + }); + }, + stop: function(event, ui) { + $("div.ui-draggable-iframeFix").each(function() { this.parentNode.removeChild(this); }); //Remove frame helpers + } +}); + +$.ui.plugin.add("draggable", "opacity", { + start: function(event, ui) { + var t = $(ui.helper), o = $(this).data('draggable').options; + if(t.css("opacity")) o._opacity = t.css("opacity"); + t.css('opacity', o.opacity); + }, + stop: function(event, ui) { + var o = $(this).data('draggable').options; + if(o._opacity) $(ui.helper).css('opacity', o._opacity); + } +}); + +$.ui.plugin.add("draggable", "scroll", { + start: function(event, ui) { + var i = $(this).data("draggable"); + if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') i.overflowOffset = i.scrollParent.offset(); + }, + drag: function(event, ui) { + + var i = $(this).data("draggable"), o = i.options, scrolled = false; + + if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') { + + if(!o.axis || o.axis != 'x') { + if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) + i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed; + else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity) + i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed; + } + + if(!o.axis || o.axis != 'y') { + if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) + i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed; + else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity) + i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed; + } + + } else { + + if(!o.axis || o.axis != 'x') { + if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) + scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); + else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) + scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); + } + + if(!o.axis || o.axis != 'y') { + if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) + scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); + else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) + scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); + } + + } + + if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) + $.ui.ddmanager.prepareOffsets(i, event); + + } +}); + +$.ui.plugin.add("draggable", "snap", { + start: function(event, ui) { + + var i = $(this).data("draggable"), o = i.options; + i.snapElements = []; + + $(o.snap.constructor != String ? ( o.snap.items || ':data(draggable)' ) : o.snap).each(function() { + var $t = $(this); var $o = $t.offset(); + if(this != i.element[0]) i.snapElements.push({ + item: this, + width: $t.outerWidth(), height: $t.outerHeight(), + top: $o.top, left: $o.left + }); + }); + + }, + drag: function(event, ui) { + + var inst = $(this).data("draggable"), o = inst.options; + var d = o.snapTolerance; + + var x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width, + y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height; + + for (var i = inst.snapElements.length - 1; i >= 0; i--){ + + var l = inst.snapElements[i].left, r = l + inst.snapElements[i].width, + t = inst.snapElements[i].top, b = t + inst.snapElements[i].height; + + //Yes, I know, this is insane ;) + if(!((l-d < x1 && x1 < r+d && t-d < y1 && y1 < b+d) || (l-d < x1 && x1 < r+d && t-d < y2 && y2 < b+d) || (l-d < x2 && x2 < r+d && t-d < y1 && y1 < b+d) || (l-d < x2 && x2 < r+d && t-d < y2 && y2 < b+d))) { + if(inst.snapElements[i].snapping) (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); + inst.snapElements[i].snapping = false; + continue; + } + + if(o.snapMode != 'inner') { + var ts = Math.abs(t - y2) <= d; + var bs = Math.abs(b - y1) <= d; + var ls = Math.abs(l - x2) <= d; + var rs = Math.abs(r - x1) <= d; + if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top; + if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top; + if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left; + if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left; + } + + var first = (ts || bs || ls || rs); + + if(o.snapMode != 'outer') { + var ts = Math.abs(t - y1) <= d; + var bs = Math.abs(b - y2) <= d; + var ls = Math.abs(l - x1) <= d; + var rs = Math.abs(r - x2) <= d; + if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top; + if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top; + if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left; + if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left; + } + + if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) + (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); + inst.snapElements[i].snapping = (ts || bs || ls || rs || first); + + }; + + } +}); + +$.ui.plugin.add("draggable", "stack", { + start: function(event, ui) { + + var o = $(this).data("draggable").options; + + var group = $.makeArray($(o.stack.group)).sort(function(a,b) { + return (parseInt($(a).css("zIndex"),10) || o.stack.min) - (parseInt($(b).css("zIndex"),10) || o.stack.min); + }); + + $(group).each(function(i) { + this.style.zIndex = o.stack.min + i; + }); + + this[0].style.zIndex = o.stack.min + group.length; + + } +}); + +$.ui.plugin.add("draggable", "zIndex", { + start: function(event, ui) { + var t = $(ui.helper), o = $(this).data("draggable").options; + if(t.css("zIndex")) o._zIndex = t.css("zIndex"); + t.css('zIndex', o.zIndex); + }, + stop: function(event, ui) { + var o = $(this).data("draggable").options; + if(o._zIndex) $(ui.helper).css('zIndex', o._zIndex); + } +}); + +})(jQuery); +/* + * jQuery UI Droppable 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Droppables + * + * Depends: + * ui.core.js + * ui.draggable.js + */ +(function($) { + +$.widget("ui.droppable", { + + _init: function() { + + var o = this.options, accept = o.accept; + this.isover = 0; this.isout = 1; + + this.options.accept = this.options.accept && $.isFunction(this.options.accept) ? this.options.accept : function(d) { + return d.is(accept); + }; + + //Store the droppable's proportions + this.proportions = { width: this.element[0].offsetWidth, height: this.element[0].offsetHeight }; + + // Add the reference and positions to the manager + $.ui.ddmanager.droppables[this.options.scope] = $.ui.ddmanager.droppables[this.options.scope] || []; + $.ui.ddmanager.droppables[this.options.scope].push(this); + + (this.options.addClasses && this.element.addClass("ui-droppable")); + + }, + + destroy: function() { + var drop = $.ui.ddmanager.droppables[this.options.scope]; + for ( var i = 0; i < drop.length; i++ ) + if ( drop[i] == this ) + drop.splice(i, 1); + + this.element + .removeClass("ui-droppable ui-droppable-disabled") + .removeData("droppable") + .unbind(".droppable"); + }, + + _setData: function(key, value) { + + if(key == 'accept') { + this.options.accept = value && $.isFunction(value) ? value : function(d) { + return d.is(value); + }; + } else { + $.widget.prototype._setData.apply(this, arguments); + } + + }, + + _activate: function(event) { + var draggable = $.ui.ddmanager.current; + if(this.options.activeClass) this.element.addClass(this.options.activeClass); + (draggable && this._trigger('activate', event, this.ui(draggable))); + }, + + _deactivate: function(event) { + var draggable = $.ui.ddmanager.current; + if(this.options.activeClass) this.element.removeClass(this.options.activeClass); + (draggable && this._trigger('deactivate', event, this.ui(draggable))); + }, + + _over: function(event) { + + var draggable = $.ui.ddmanager.current; + if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element + + if (this.options.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { + if(this.options.hoverClass) this.element.addClass(this.options.hoverClass); + this._trigger('over', event, this.ui(draggable)); + } + + }, + + _out: function(event) { + + var draggable = $.ui.ddmanager.current; + if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element + + if (this.options.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { + if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass); + this._trigger('out', event, this.ui(draggable)); + } + + }, + + _drop: function(event,custom) { + + var draggable = custom || $.ui.ddmanager.current; + if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return false; // Bail if draggable and droppable are same element + + var childrenIntersection = false; + this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function() { + var inst = $.data(this, 'droppable'); + if(inst.options.greedy && $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance)) { + childrenIntersection = true; return false; + } + }); + if(childrenIntersection) return false; + + if(this.options.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { + if(this.options.activeClass) this.element.removeClass(this.options.activeClass); + if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass); + this._trigger('drop', event, this.ui(draggable)); + return this.element; + } + + return false; + + }, + + ui: function(c) { + return { + draggable: (c.currentItem || c.element), + helper: c.helper, + position: c.position, + absolutePosition: c.positionAbs, //deprecated + offset: c.positionAbs + }; + } + +}); + +$.extend($.ui.droppable, { + version: "1.7.1", + eventPrefix: 'drop', + defaults: { + accept: '*', + activeClass: false, + addClasses: true, + greedy: false, + hoverClass: false, + scope: 'default', + tolerance: 'intersect' + } +}); + +$.ui.intersect = function(draggable, droppable, toleranceMode) { + + if (!droppable.offset) return false; + + var x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width, + y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height; + var l = droppable.offset.left, r = l + droppable.proportions.width, + t = droppable.offset.top, b = t + droppable.proportions.height; + + switch (toleranceMode) { + case 'fit': + return (l < x1 && x2 < r + && t < y1 && y2 < b); + break; + case 'intersect': + return (l < x1 + (draggable.helperProportions.width / 2) // Right Half + && x2 - (draggable.helperProportions.width / 2) < r // Left Half + && t < y1 + (draggable.helperProportions.height / 2) // Bottom Half + && y2 - (draggable.helperProportions.height / 2) < b ); // Top Half + break; + case 'pointer': + var draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left), + draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top), + isOver = $.ui.isOver(draggableTop, draggableLeft, t, l, droppable.proportions.height, droppable.proportions.width); + return isOver; + break; + case 'touch': + return ( + (y1 >= t && y1 <= b) || // Top edge touching + (y2 >= t && y2 <= b) || // Bottom edge touching + (y1 < t && y2 > b) // Surrounded vertically + ) && ( + (x1 >= l && x1 <= r) || // Left edge touching + (x2 >= l && x2 <= r) || // Right edge touching + (x1 < l && x2 > r) // Surrounded horizontally + ); + break; + default: + return false; + break; + } + +}; + +/* + This manager tracks offsets of draggables and droppables +*/ +$.ui.ddmanager = { + current: null, + droppables: { 'default': [] }, + prepareOffsets: function(t, event) { + + var m = $.ui.ddmanager.droppables[t.options.scope]; + var type = event ? event.type : null; // workaround for #2317 + var list = (t.currentItem || t.element).find(":data(droppable)").andSelf(); + + droppablesLoop: for (var i = 0; i < m.length; i++) { + + if(m[i].options.disabled || (t && !m[i].options.accept.call(m[i].element[0],(t.currentItem || t.element)))) continue; //No disabled and non-accepted + for (var j=0; j < list.length; j++) { if(list[j] == m[i].element[0]) { m[i].proportions.height = 0; continue droppablesLoop; } }; //Filter out elements in the current dragged item + m[i].visible = m[i].element.css("display") != "none"; if(!m[i].visible) continue; //If the element is not visible, continue + + m[i].offset = m[i].element.offset(); + m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight }; + + if(type == "mousedown") m[i]._activate.call(m[i], event); //Activate the droppable if used directly from draggables + + } + + }, + drop: function(draggable, event) { + + var dropped = false; + $.each($.ui.ddmanager.droppables[draggable.options.scope], function() { + + if(!this.options) return; + if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance)) + dropped = this._drop.call(this, event); + + if (!this.options.disabled && this.visible && this.options.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { + this.isout = 1; this.isover = 0; + this._deactivate.call(this, event); + } + + }); + return dropped; + + }, + drag: function(draggable, event) { + + //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse. + if(draggable.options.refreshPositions) $.ui.ddmanager.prepareOffsets(draggable, event); + + //Run through all droppables and check their positions based on specific tolerance options + + $.each($.ui.ddmanager.droppables[draggable.options.scope], function() { + + if(this.options.disabled || this.greedyChild || !this.visible) return; + var intersects = $.ui.intersect(draggable, this, this.options.tolerance); + + var c = !intersects && this.isover == 1 ? 'isout' : (intersects && this.isover == 0 ? 'isover' : null); + if(!c) return; + + var parentInstance; + if (this.options.greedy) { + var parent = this.element.parents(':data(droppable):eq(0)'); + if (parent.length) { + parentInstance = $.data(parent[0], 'droppable'); + parentInstance.greedyChild = (c == 'isover' ? 1 : 0); + } + } + + // we just moved into a greedy child + if (parentInstance && c == 'isover') { + parentInstance['isover'] = 0; + parentInstance['isout'] = 1; + parentInstance._out.call(parentInstance, event); + } + + this[c] = 1; this[c == 'isout' ? 'isover' : 'isout'] = 0; + this[c == "isover" ? "_over" : "_out"].call(this, event); + + // we just moved out of a greedy child + if (parentInstance && c == 'isout') { + parentInstance['isout'] = 0; + parentInstance['isover'] = 1; + parentInstance._over.call(parentInstance, event); + } + }); + + } +}; + +})(jQuery); +/* + * jQuery UI Resizable 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Resizables + * + * Depends: + * ui.core.js + */ +(function($) { + +$.widget("ui.resizable", $.extend({}, $.ui.mouse, { + + _init: function() { + + var self = this, o = this.options; + this.element.addClass("ui-resizable"); + + $.extend(this, { + _aspectRatio: !!(o.aspectRatio), + aspectRatio: o.aspectRatio, + originalElement: this.element, + _proportionallyResizeElements: [], + _helper: o.helper || o.ghost || o.animate ? o.helper || 'ui-resizable-helper' : null + }); + + //Wrap the element if it cannot hold child nodes + if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) { + + //Opera fix for relative positioning + if (/relative/.test(this.element.css('position')) && $.browser.opera) + this.element.css({ position: 'relative', top: 'auto', left: 'auto' }); + + //Create a wrapper element and set the wrapper to the new current internal element + this.element.wrap( + $('
    ').css({ + position: this.element.css('position'), + width: this.element.outerWidth(), + height: this.element.outerHeight(), + top: this.element.css('top'), + left: this.element.css('left') + }) + ); + + //Overwrite the original this.element + this.element = this.element.parent().data( + "resizable", this.element.data('resizable') + ); + + this.elementIsWrapper = true; + + //Move margins to the wrapper + this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") }); + this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0}); + + //Prevent Safari textarea resize + this.originalResizeStyle = this.originalElement.css('resize'); + this.originalElement.css('resize', 'none'); + + //Push the actual element to our proportionallyResize internal array + this._proportionallyResizeElements.push(this.originalElement.css({ position: 'static', zoom: 1, display: 'block' })); + + // avoid IE jump (hard set the margin) + this.originalElement.css({ margin: this.originalElement.css('margin') }); + + // fix handlers offset + this._proportionallyResize(); + + } + + this.handles = o.handles || (!$('.ui-resizable-handle', this.element).length ? "e,s,se" : { n: '.ui-resizable-n', e: '.ui-resizable-e', s: '.ui-resizable-s', w: '.ui-resizable-w', se: '.ui-resizable-se', sw: '.ui-resizable-sw', ne: '.ui-resizable-ne', nw: '.ui-resizable-nw' }); + if(this.handles.constructor == String) { + + if(this.handles == 'all') this.handles = 'n,e,s,w,se,sw,ne,nw'; + var n = this.handles.split(","); this.handles = {}; + + for(var i = 0; i < n.length; i++) { + + var handle = $.trim(n[i]), hname = 'ui-resizable-'+handle; + var axis = $('
    '); + + // increase zIndex of sw, se, ne, nw axis + //TODO : this modifies original option + if(/sw|se|ne|nw/.test(handle)) axis.css({ zIndex: ++o.zIndex }); + + //TODO : What's going on here? + if ('se' == handle) { + axis.addClass('ui-icon ui-icon-gripsmall-diagonal-se'); + }; + + //Insert into internal handles object and append to element + this.handles[handle] = '.ui-resizable-'+handle; + this.element.append(axis); + } + + } + + this._renderAxis = function(target) { + + target = target || this.element; + + for(var i in this.handles) { + + if(this.handles[i].constructor == String) + this.handles[i] = $(this.handles[i], this.element).show(); + + //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls) + if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) { + + var axis = $(this.handles[i], this.element), padWrapper = 0; + + //Checking the correct pad and border + padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth(); + + //The padding type i have to apply... + var padPos = [ 'padding', + /ne|nw|n/.test(i) ? 'Top' : + /se|sw|s/.test(i) ? 'Bottom' : + /^e$/.test(i) ? 'Right' : 'Left' ].join(""); + + target.css(padPos, padWrapper); + + this._proportionallyResize(); + + } + + //TODO: What's that good for? There's not anything to be executed left + if(!$(this.handles[i]).length) + continue; + + } + }; + + //TODO: make renderAxis a prototype function + this._renderAxis(this.element); + + this._handles = $('.ui-resizable-handle', this.element) + .disableSelection(); + + //Matching axis name + this._handles.mouseover(function() { + if (!self.resizing) { + if (this.className) + var axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i); + //Axis, default = se + self.axis = axis && axis[1] ? axis[1] : 'se'; + } + }); + + //If we want to auto hide the elements + if (o.autoHide) { + this._handles.hide(); + $(this.element) + .addClass("ui-resizable-autohide") + .hover(function() { + $(this).removeClass("ui-resizable-autohide"); + self._handles.show(); + }, + function(){ + if (!self.resizing) { + $(this).addClass("ui-resizable-autohide"); + self._handles.hide(); + } + }); + } + + //Initialize the mouse interaction + this._mouseInit(); + + }, + + destroy: function() { + + this._mouseDestroy(); + + var _destroy = function(exp) { + $(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing") + .removeData("resizable").unbind(".resizable").find('.ui-resizable-handle').remove(); + }; + + //TODO: Unwrap at same DOM position + if (this.elementIsWrapper) { + _destroy(this.element); + var wrapper = this.element; + wrapper.parent().append( + this.originalElement.css({ + position: wrapper.css('position'), + width: wrapper.outerWidth(), + height: wrapper.outerHeight(), + top: wrapper.css('top'), + left: wrapper.css('left') + }) + ).end().remove(); + } + + this.originalElement.css('resize', this.originalResizeStyle); + _destroy(this.originalElement); + + }, + + _mouseCapture: function(event) { + + var handle = false; + for(var i in this.handles) { + if($(this.handles[i])[0] == event.target) handle = true; + } + + return this.options.disabled || !!handle; + + }, + + _mouseStart: function(event) { + + var o = this.options, iniPos = this.element.position(), el = this.element; + + this.resizing = true; + this.documentScroll = { top: $(document).scrollTop(), left: $(document).scrollLeft() }; + + // bugfix for http://dev.jquery.com/ticket/1749 + if (el.is('.ui-draggable') || (/absolute/).test(el.css('position'))) { + el.css({ position: 'absolute', top: iniPos.top, left: iniPos.left }); + } + + //Opera fixing relative position + if ($.browser.opera && (/relative/).test(el.css('position'))) + el.css({ position: 'relative', top: 'auto', left: 'auto' }); + + this._renderProxy(); + + var curleft = num(this.helper.css('left')), curtop = num(this.helper.css('top')); + + if (o.containment) { + curleft += $(o.containment).scrollLeft() || 0; + curtop += $(o.containment).scrollTop() || 0; + } + + //Store needed variables + this.offset = this.helper.offset(); + this.position = { left: curleft, top: curtop }; + this.size = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; + this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; + this.originalPosition = { left: curleft, top: curtop }; + this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() }; + this.originalMousePosition = { left: event.pageX, top: event.pageY }; + + //Aspect Ratio + this.aspectRatio = (typeof o.aspectRatio == 'number') ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1); + + var cursor = $('.ui-resizable-' + this.axis).css('cursor'); + $('body').css('cursor', cursor == 'auto' ? this.axis + '-resize' : cursor); + + el.addClass("ui-resizable-resizing"); + this._propagate("start", event); + return true; + }, + + _mouseDrag: function(event) { + + //Increase performance, avoid regex + var el = this.helper, o = this.options, props = {}, + self = this, smp = this.originalMousePosition, a = this.axis; + + var dx = (event.pageX-smp.left)||0, dy = (event.pageY-smp.top)||0; + var trigger = this._change[a]; + if (!trigger) return false; + + // Calculate the attrs that will be change + var data = trigger.apply(this, [event, dx, dy]), ie6 = $.browser.msie && $.browser.version < 7, csdif = this.sizeDiff; + + if (this._aspectRatio || event.shiftKey) + data = this._updateRatio(data, event); + + data = this._respectSize(data, event); + + // plugins callbacks need to be called first + this._propagate("resize", event); + + el.css({ + top: this.position.top + "px", left: this.position.left + "px", + width: this.size.width + "px", height: this.size.height + "px" + }); + + if (!this._helper && this._proportionallyResizeElements.length) + this._proportionallyResize(); + + this._updateCache(data); + + // calling the user callback at the end + this._trigger('resize', event, this.ui()); + + return false; + }, + + _mouseStop: function(event) { + + this.resizing = false; + var o = this.options, self = this; + + if(this._helper) { + var pr = this._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName), + soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height, + soffsetw = ista ? 0 : self.sizeDiff.width; + + var s = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth) }, + left = (parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left)) || null, + top = (parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top)) || null; + + if (!o.animate) + this.element.css($.extend(s, { top: top, left: left })); + + self.helper.height(self.size.height); + self.helper.width(self.size.width); + + if (this._helper && !o.animate) this._proportionallyResize(); + } + + $('body').css('cursor', 'auto'); + + this.element.removeClass("ui-resizable-resizing"); + + this._propagate("stop", event); + + if (this._helper) this.helper.remove(); + return false; + + }, + + _updateCache: function(data) { + var o = this.options; + this.offset = this.helper.offset(); + if (isNumber(data.left)) this.position.left = data.left; + if (isNumber(data.top)) this.position.top = data.top; + if (isNumber(data.height)) this.size.height = data.height; + if (isNumber(data.width)) this.size.width = data.width; + }, + + _updateRatio: function(data, event) { + + var o = this.options, cpos = this.position, csize = this.size, a = this.axis; + + if (data.height) data.width = (csize.height * this.aspectRatio); + else if (data.width) data.height = (csize.width / this.aspectRatio); + + if (a == 'sw') { + data.left = cpos.left + (csize.width - data.width); + data.top = null; + } + if (a == 'nw') { + data.top = cpos.top + (csize.height - data.height); + data.left = cpos.left + (csize.width - data.width); + } + + return data; + }, + + _respectSize: function(data, event) { + + var el = this.helper, o = this.options, pRatio = this._aspectRatio || event.shiftKey, a = this.axis, + ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height), + isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height); + + if (isminw) data.width = o.minWidth; + if (isminh) data.height = o.minHeight; + if (ismaxw) data.width = o.maxWidth; + if (ismaxh) data.height = o.maxHeight; + + var dw = this.originalPosition.left + this.originalSize.width, dh = this.position.top + this.size.height; + var cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a); + + if (isminw && cw) data.left = dw - o.minWidth; + if (ismaxw && cw) data.left = dw - o.maxWidth; + if (isminh && ch) data.top = dh - o.minHeight; + if (ismaxh && ch) data.top = dh - o.maxHeight; + + // fixing jump error on top/left - bug #2330 + var isNotwh = !data.width && !data.height; + if (isNotwh && !data.left && data.top) data.top = null; + else if (isNotwh && !data.top && data.left) data.left = null; + + return data; + }, + + _proportionallyResize: function() { + + var o = this.options; + if (!this._proportionallyResizeElements.length) return; + var element = this.helper || this.element; + + for (var i=0; i < this._proportionallyResizeElements.length; i++) { + + var prel = this._proportionallyResizeElements[i]; + + if (!this.borderDif) { + var b = [prel.css('borderTopWidth'), prel.css('borderRightWidth'), prel.css('borderBottomWidth'), prel.css('borderLeftWidth')], + p = [prel.css('paddingTop'), prel.css('paddingRight'), prel.css('paddingBottom'), prel.css('paddingLeft')]; + + this.borderDif = $.map(b, function(v, i) { + var border = parseInt(v,10)||0, padding = parseInt(p[i],10)||0; + return border + padding; + }); + } + + if ($.browser.msie && !(!($(element).is(':hidden') || $(element).parents(':hidden').length))) + continue; + + prel.css({ + height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0, + width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0 + }); + + }; + + }, + + _renderProxy: function() { + + var el = this.element, o = this.options; + this.elementOffset = el.offset(); + + if(this._helper) { + + this.helper = this.helper || $('
    '); + + // fix ie6 offset TODO: This seems broken + var ie6 = $.browser.msie && $.browser.version < 7, ie6offset = (ie6 ? 1 : 0), + pxyoffset = ( ie6 ? 2 : -1 ); + + this.helper.addClass(this._helper).css({ + width: this.element.outerWidth() + pxyoffset, + height: this.element.outerHeight() + pxyoffset, + position: 'absolute', + left: this.elementOffset.left - ie6offset +'px', + top: this.elementOffset.top - ie6offset +'px', + zIndex: ++o.zIndex //TODO: Don't modify option + }); + + this.helper + .appendTo("body") + .disableSelection(); + + } else { + this.helper = this.element; + } + + }, + + _change: { + e: function(event, dx, dy) { + return { width: this.originalSize.width + dx }; + }, + w: function(event, dx, dy) { + var o = this.options, cs = this.originalSize, sp = this.originalPosition; + return { left: sp.left + dx, width: cs.width - dx }; + }, + n: function(event, dx, dy) { + var o = this.options, cs = this.originalSize, sp = this.originalPosition; + return { top: sp.top + dy, height: cs.height - dy }; + }, + s: function(event, dx, dy) { + return { height: this.originalSize.height + dy }; + }, + se: function(event, dx, dy) { + return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy])); + }, + sw: function(event, dx, dy) { + return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy])); + }, + ne: function(event, dx, dy) { + return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy])); + }, + nw: function(event, dx, dy) { + return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy])); + } + }, + + _propagate: function(n, event) { + $.ui.plugin.call(this, n, [event, this.ui()]); + (n != "resize" && this._trigger(n, event, this.ui())); + }, + + plugins: {}, + + ui: function() { + return { + originalElement: this.originalElement, + element: this.element, + helper: this.helper, + position: this.position, + size: this.size, + originalSize: this.originalSize, + originalPosition: this.originalPosition + }; + } + +})); + +$.extend($.ui.resizable, { + version: "1.7.1", + eventPrefix: "resize", + defaults: { + alsoResize: false, + animate: false, + animateDuration: "slow", + animateEasing: "swing", + aspectRatio: false, + autoHide: false, + cancel: ":input,option", + containment: false, + delay: 0, + distance: 1, + ghost: false, + grid: false, + handles: "e,s,se", + helper: false, + maxHeight: null, + maxWidth: null, + minHeight: 10, + minWidth: 10, + zIndex: 1000 + } +}); + +/* + * Resizable Extensions + */ + +$.ui.plugin.add("resizable", "alsoResize", { + + start: function(event, ui) { + + var self = $(this).data("resizable"), o = self.options; + + _store = function(exp) { + $(exp).each(function() { + $(this).data("resizable-alsoresize", { + width: parseInt($(this).width(), 10), height: parseInt($(this).height(), 10), + left: parseInt($(this).css('left'), 10), top: parseInt($(this).css('top'), 10) + }); + }); + }; + + if (typeof(o.alsoResize) == 'object' && !o.alsoResize.parentNode) { + if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); } + else { $.each(o.alsoResize, function(exp, c) { _store(exp); }); } + }else{ + _store(o.alsoResize); + } + }, + + resize: function(event, ui){ + var self = $(this).data("resizable"), o = self.options, os = self.originalSize, op = self.originalPosition; + + var delta = { + height: (self.size.height - os.height) || 0, width: (self.size.width - os.width) || 0, + top: (self.position.top - op.top) || 0, left: (self.position.left - op.left) || 0 + }, + + _alsoResize = function(exp, c) { + $(exp).each(function() { + var el = $(this), start = $(this).data("resizable-alsoresize"), style = {}, css = c && c.length ? c : ['width', 'height', 'top', 'left']; + + $.each(css || ['width', 'height', 'top', 'left'], function(i, prop) { + var sum = (start[prop]||0) + (delta[prop]||0); + if (sum && sum >= 0) + style[prop] = sum || null; + }); + + //Opera fixing relative position + if (/relative/.test(el.css('position')) && $.browser.opera) { + self._revertToRelativePosition = true; + el.css({ position: 'absolute', top: 'auto', left: 'auto' }); + } + + el.css(style); + }); + }; + + if (typeof(o.alsoResize) == 'object' && !o.alsoResize.nodeType) { + $.each(o.alsoResize, function(exp, c) { _alsoResize(exp, c); }); + }else{ + _alsoResize(o.alsoResize); + } + }, + + stop: function(event, ui){ + var self = $(this).data("resizable"); + + //Opera fixing relative position + if (self._revertToRelativePosition && $.browser.opera) { + self._revertToRelativePosition = false; + el.css({ position: 'relative' }); + } + + $(this).removeData("resizable-alsoresize-start"); + } +}); + +$.ui.plugin.add("resizable", "animate", { + + stop: function(event, ui) { + var self = $(this).data("resizable"), o = self.options; + + var pr = self._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName), + soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height, + soffsetw = ista ? 0 : self.sizeDiff.width; + + var style = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth) }, + left = (parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left)) || null, + top = (parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top)) || null; + + self.element.animate( + $.extend(style, top && left ? { top: top, left: left } : {}), { + duration: o.animateDuration, + easing: o.animateEasing, + step: function() { + + var data = { + width: parseInt(self.element.css('width'), 10), + height: parseInt(self.element.css('height'), 10), + top: parseInt(self.element.css('top'), 10), + left: parseInt(self.element.css('left'), 10) + }; + + if (pr && pr.length) $(pr[0]).css({ width: data.width, height: data.height }); + + // propagating resize, and updating values for each animation step + self._updateCache(data); + self._propagate("resize", event); + + } + } + ); + } + +}); + +$.ui.plugin.add("resizable", "containment", { + + start: function(event, ui) { + var self = $(this).data("resizable"), o = self.options, el = self.element; + var oc = o.containment, ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc; + if (!ce) return; + + self.containerElement = $(ce); + + if (/document/.test(oc) || oc == document) { + self.containerOffset = { left: 0, top: 0 }; + self.containerPosition = { left: 0, top: 0 }; + + self.parentData = { + element: $(document), left: 0, top: 0, + width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight + }; + } + + // i'm a node, so compute top, left, right, bottom + else { + var element = $(ce), p = []; + $([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); }); + + self.containerOffset = element.offset(); + self.containerPosition = element.position(); + self.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) }; + + var co = self.containerOffset, ch = self.containerSize.height, cw = self.containerSize.width, + width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw ), height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch); + + self.parentData = { + element: ce, left: co.left, top: co.top, width: width, height: height + }; + } + }, + + resize: function(event, ui) { + var self = $(this).data("resizable"), o = self.options, + ps = self.containerSize, co = self.containerOffset, cs = self.size, cp = self.position, + pRatio = self._aspectRatio || event.shiftKey, cop = { top:0, left:0 }, ce = self.containerElement; + + if (ce[0] != document && (/static/).test(ce.css('position'))) cop = co; + + if (cp.left < (self._helper ? co.left : 0)) { + self.size.width = self.size.width + (self._helper ? (self.position.left - co.left) : (self.position.left - cop.left)); + if (pRatio) self.size.height = self.size.width / o.aspectRatio; + self.position.left = o.helper ? co.left : 0; + } + + if (cp.top < (self._helper ? co.top : 0)) { + self.size.height = self.size.height + (self._helper ? (self.position.top - co.top) : self.position.top); + if (pRatio) self.size.width = self.size.height * o.aspectRatio; + self.position.top = self._helper ? co.top : 0; + } + + self.offset.left = self.parentData.left+self.position.left; + self.offset.top = self.parentData.top+self.position.top; + + var woset = Math.abs( (self._helper ? self.offset.left - cop.left : (self.offset.left - cop.left)) + self.sizeDiff.width ), + hoset = Math.abs( (self._helper ? self.offset.top - cop.top : (self.offset.top - co.top)) + self.sizeDiff.height ); + + var isParent = self.containerElement.get(0) == self.element.parent().get(0), + isOffsetRelative = /relative|absolute/.test(self.containerElement.css('position')); + + if(isParent && isOffsetRelative) woset -= self.parentData.left; + + if (woset + self.size.width >= self.parentData.width) { + self.size.width = self.parentData.width - woset; + if (pRatio) self.size.height = self.size.width / self.aspectRatio; + } + + if (hoset + self.size.height >= self.parentData.height) { + self.size.height = self.parentData.height - hoset; + if (pRatio) self.size.width = self.size.height * self.aspectRatio; + } + }, + + stop: function(event, ui){ + var self = $(this).data("resizable"), o = self.options, cp = self.position, + co = self.containerOffset, cop = self.containerPosition, ce = self.containerElement; + + var helper = $(self.helper), ho = helper.offset(), w = helper.outerWidth() - self.sizeDiff.width, h = helper.outerHeight() - self.sizeDiff.height; + + if (self._helper && !o.animate && (/relative/).test(ce.css('position'))) + $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); + + if (self._helper && !o.animate && (/static/).test(ce.css('position'))) + $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); + + } +}); + +$.ui.plugin.add("resizable", "ghost", { + + start: function(event, ui) { + + var self = $(this).data("resizable"), o = self.options, cs = self.size; + + self.ghost = self.originalElement.clone(); + self.ghost + .css({ opacity: .25, display: 'block', position: 'relative', height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 }) + .addClass('ui-resizable-ghost') + .addClass(typeof o.ghost == 'string' ? o.ghost : ''); + + self.ghost.appendTo(self.helper); + + }, + + resize: function(event, ui){ + var self = $(this).data("resizable"), o = self.options; + if (self.ghost) self.ghost.css({ position: 'relative', height: self.size.height, width: self.size.width }); + }, + + stop: function(event, ui){ + var self = $(this).data("resizable"), o = self.options; + if (self.ghost && self.helper) self.helper.get(0).removeChild(self.ghost.get(0)); + } + +}); + +$.ui.plugin.add("resizable", "grid", { + + resize: function(event, ui) { + var self = $(this).data("resizable"), o = self.options, cs = self.size, os = self.originalSize, op = self.originalPosition, a = self.axis, ratio = o._aspectRatio || event.shiftKey; + o.grid = typeof o.grid == "number" ? [o.grid, o.grid] : o.grid; + var ox = Math.round((cs.width - os.width) / (o.grid[0]||1)) * (o.grid[0]||1), oy = Math.round((cs.height - os.height) / (o.grid[1]||1)) * (o.grid[1]||1); + + if (/^(se|s|e)$/.test(a)) { + self.size.width = os.width + ox; + self.size.height = os.height + oy; + } + else if (/^(ne)$/.test(a)) { + self.size.width = os.width + ox; + self.size.height = os.height + oy; + self.position.top = op.top - oy; + } + else if (/^(sw)$/.test(a)) { + self.size.width = os.width + ox; + self.size.height = os.height + oy; + self.position.left = op.left - ox; + } + else { + self.size.width = os.width + ox; + self.size.height = os.height + oy; + self.position.top = op.top - oy; + self.position.left = op.left - ox; + } + } + +}); + +var num = function(v) { + return parseInt(v, 10) || 0; +}; + +var isNumber = function(value) { + return !isNaN(parseInt(value, 10)); +}; + +})(jQuery); +/* + * jQuery UI Selectable 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Selectables + * + * Depends: + * ui.core.js + */ +(function($) { + +$.widget("ui.selectable", $.extend({}, $.ui.mouse, { + + _init: function() { + var self = this; + + this.element.addClass("ui-selectable"); + + this.dragged = false; + + // cache selectee children based on filter + var selectees; + this.refresh = function() { + selectees = $(self.options.filter, self.element[0]); + selectees.each(function() { + var $this = $(this); + var pos = $this.offset(); + $.data(this, "selectable-item", { + element: this, + $element: $this, + left: pos.left, + top: pos.top, + right: pos.left + $this.outerWidth(), + bottom: pos.top + $this.outerHeight(), + startselected: false, + selected: $this.hasClass('ui-selected'), + selecting: $this.hasClass('ui-selecting'), + unselecting: $this.hasClass('ui-unselecting') + }); + }); + }; + this.refresh(); + + this.selectees = selectees.addClass("ui-selectee"); + + this._mouseInit(); + + this.helper = $(document.createElement('div')) + .css({border:'1px dotted black'}) + .addClass("ui-selectable-helper"); + }, + + destroy: function() { + this.element + .removeClass("ui-selectable ui-selectable-disabled") + .removeData("selectable") + .unbind(".selectable"); + this._mouseDestroy(); + }, + + _mouseStart: function(event) { + var self = this; + + this.opos = [event.pageX, event.pageY]; + + if (this.options.disabled) + return; + + var options = this.options; + + this.selectees = $(options.filter, this.element[0]); + + this._trigger("start", event); + + $(options.appendTo).append(this.helper); + // position helper (lasso) + this.helper.css({ + "z-index": 100, + "position": "absolute", + "left": event.clientX, + "top": event.clientY, + "width": 0, + "height": 0 + }); + + if (options.autoRefresh) { + this.refresh(); + } + + this.selectees.filter('.ui-selected').each(function() { + var selectee = $.data(this, "selectable-item"); + selectee.startselected = true; + if (!event.metaKey) { + selectee.$element.removeClass('ui-selected'); + selectee.selected = false; + selectee.$element.addClass('ui-unselecting'); + selectee.unselecting = true; + // selectable UNSELECTING callback + self._trigger("unselecting", event, { + unselecting: selectee.element + }); + } + }); + + $(event.target).parents().andSelf().each(function() { + var selectee = $.data(this, "selectable-item"); + if (selectee) { + selectee.$element.removeClass("ui-unselecting").addClass('ui-selecting'); + selectee.unselecting = false; + selectee.selecting = true; + selectee.selected = true; + // selectable SELECTING callback + self._trigger("selecting", event, { + selecting: selectee.element + }); + return false; + } + }); + + }, + + _mouseDrag: function(event) { + var self = this; + this.dragged = true; + + if (this.options.disabled) + return; + + var options = this.options; + + var x1 = this.opos[0], y1 = this.opos[1], x2 = event.pageX, y2 = event.pageY; + if (x1 > x2) { var tmp = x2; x2 = x1; x1 = tmp; } + if (y1 > y2) { var tmp = y2; y2 = y1; y1 = tmp; } + this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1}); + + this.selectees.each(function() { + var selectee = $.data(this, "selectable-item"); + //prevent helper from being selected if appendTo: selectable + if (!selectee || selectee.element == self.element[0]) + return; + var hit = false; + if (options.tolerance == 'touch') { + hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) ); + } else if (options.tolerance == 'fit') { + hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2); + } + + if (hit) { + // SELECT + if (selectee.selected) { + selectee.$element.removeClass('ui-selected'); + selectee.selected = false; + } + if (selectee.unselecting) { + selectee.$element.removeClass('ui-unselecting'); + selectee.unselecting = false; + } + if (!selectee.selecting) { + selectee.$element.addClass('ui-selecting'); + selectee.selecting = true; + // selectable SELECTING callback + self._trigger("selecting", event, { + selecting: selectee.element + }); + } + } else { + // UNSELECT + if (selectee.selecting) { + if (event.metaKey && selectee.startselected) { + selectee.$element.removeClass('ui-selecting'); + selectee.selecting = false; + selectee.$element.addClass('ui-selected'); + selectee.selected = true; + } else { + selectee.$element.removeClass('ui-selecting'); + selectee.selecting = false; + if (selectee.startselected) { + selectee.$element.addClass('ui-unselecting'); + selectee.unselecting = true; + } + // selectable UNSELECTING callback + self._trigger("unselecting", event, { + unselecting: selectee.element + }); + } + } + if (selectee.selected) { + if (!event.metaKey && !selectee.startselected) { + selectee.$element.removeClass('ui-selected'); + selectee.selected = false; + + selectee.$element.addClass('ui-unselecting'); + selectee.unselecting = true; + // selectable UNSELECTING callback + self._trigger("unselecting", event, { + unselecting: selectee.element + }); + } + } + } + }); + + return false; + }, + + _mouseStop: function(event) { + var self = this; + + this.dragged = false; + + var options = this.options; + + $('.ui-unselecting', this.element[0]).each(function() { + var selectee = $.data(this, "selectable-item"); + selectee.$element.removeClass('ui-unselecting'); + selectee.unselecting = false; + selectee.startselected = false; + self._trigger("unselected", event, { + unselected: selectee.element + }); + }); + $('.ui-selecting', this.element[0]).each(function() { + var selectee = $.data(this, "selectable-item"); + selectee.$element.removeClass('ui-selecting').addClass('ui-selected'); + selectee.selecting = false; + selectee.selected = true; + selectee.startselected = true; + self._trigger("selected", event, { + selected: selectee.element + }); + }); + this._trigger("stop", event); + + this.helper.remove(); + + return false; + } + +})); + +$.extend($.ui.selectable, { + version: "1.7.1", + defaults: { + appendTo: 'body', + autoRefresh: true, + cancel: ":input,option", + delay: 0, + distance: 0, + filter: '*', + tolerance: 'touch' + } +}); + +})(jQuery); +/* + * jQuery UI Sortable 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Sortables + * + * Depends: + * ui.core.js + */ +(function($) { + +$.widget("ui.sortable", $.extend({}, $.ui.mouse, { + _init: function() { + + var o = this.options; + this.containerCache = {}; + this.element.addClass("ui-sortable"); + + //Get the items + this.refresh(); + + //Let's determine if the items are floating + this.floating = this.items.length ? (/left|right/).test(this.items[0].item.css('float')) : false; + + //Let's determine the parent's offset + this.offset = this.element.offset(); + + //Initialize mouse events for interaction + this._mouseInit(); + + }, + + destroy: function() { + this.element + .removeClass("ui-sortable ui-sortable-disabled") + .removeData("sortable") + .unbind(".sortable"); + this._mouseDestroy(); + + for ( var i = this.items.length - 1; i >= 0; i-- ) + this.items[i].item.removeData("sortable-item"); + }, + + _mouseCapture: function(event, overrideHandle) { + + if (this.reverting) { + return false; + } + + if(this.options.disabled || this.options.type == 'static') return false; + + //We have to refresh the items data once first + this._refreshItems(event); + + //Find out if the clicked node (or one of its parents) is a actual item in this.items + var currentItem = null, self = this, nodes = $(event.target).parents().each(function() { + if($.data(this, 'sortable-item') == self) { + currentItem = $(this); + return false; + } + }); + if($.data(event.target, 'sortable-item') == self) currentItem = $(event.target); + + if(!currentItem) return false; + if(this.options.handle && !overrideHandle) { + var validHandle = false; + + $(this.options.handle, currentItem).find("*").andSelf().each(function() { if(this == event.target) validHandle = true; }); + if(!validHandle) return false; + } + + this.currentItem = currentItem; + this._removeCurrentsFromItems(); + return true; + + }, + + _mouseStart: function(event, overrideHandle, noActivation) { + + var o = this.options, self = this; + this.currentContainer = this; + + //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture + this.refreshPositions(); + + //Create and append the visible helper + this.helper = this._createHelper(event); + + //Cache the helper size + this._cacheHelperProportions(); + + /* + * - Position generation - + * This block generates everything position related - it's the core of draggables. + */ + + //Cache the margins of the original element + this._cacheMargins(); + + //Get the next scrolling parent + this.scrollParent = this.helper.scrollParent(); + + //The element's absolute position on the page minus margins + this.offset = this.currentItem.offset(); + this.offset = { + top: this.offset.top - this.margins.top, + left: this.offset.left - this.margins.left + }; + + // Only after we got the offset, we can change the helper's position to absolute + // TODO: Still need to figure out a way to make relative sorting possible + this.helper.css("position", "absolute"); + this.cssPosition = this.helper.css("position"); + + $.extend(this.offset, { + click: { //Where the click happened, relative to the element + left: event.pageX - this.offset.left, + top: event.pageY - this.offset.top + }, + parent: this._getParentOffset(), + relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper + }); + + //Generate the original position + this.originalPosition = this._generatePosition(event); + this.originalPageX = event.pageX; + this.originalPageY = event.pageY; + + //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied + if(o.cursorAt) + this._adjustOffsetFromHelper(o.cursorAt); + + //Cache the former DOM position + this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] }; + + //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way + if(this.helper[0] != this.currentItem[0]) { + this.currentItem.hide(); + } + + //Create the placeholder + this._createPlaceholder(); + + //Set a containment if given in the options + if(o.containment) + this._setContainment(); + + if(o.cursor) { // cursor option + if ($('body').css("cursor")) this._storedCursor = $('body').css("cursor"); + $('body').css("cursor", o.cursor); + } + + if(o.opacity) { // opacity option + if (this.helper.css("opacity")) this._storedOpacity = this.helper.css("opacity"); + this.helper.css("opacity", o.opacity); + } + + if(o.zIndex) { // zIndex option + if (this.helper.css("zIndex")) this._storedZIndex = this.helper.css("zIndex"); + this.helper.css("zIndex", o.zIndex); + } + + //Prepare scrolling + if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') + this.overflowOffset = this.scrollParent.offset(); + + //Call callbacks + this._trigger("start", event, this._uiHash()); + + //Recache the helper size + if(!this._preserveHelperProportions) + this._cacheHelperProportions(); + + + //Post 'activate' events to possible containers + if(!noActivation) { + for (var i = this.containers.length - 1; i >= 0; i--) { this.containers[i]._trigger("activate", event, self._uiHash(this)); } + } + + //Prepare possible droppables + if($.ui.ddmanager) + $.ui.ddmanager.current = this; + + if ($.ui.ddmanager && !o.dropBehaviour) + $.ui.ddmanager.prepareOffsets(this, event); + + this.dragging = true; + + this.helper.addClass("ui-sortable-helper"); + this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position + return true; + + }, + + _mouseDrag: function(event) { + + //Compute the helpers position + this.position = this._generatePosition(event); + this.positionAbs = this._convertPositionTo("absolute"); + + if (!this.lastPositionAbs) { + this.lastPositionAbs = this.positionAbs; + } + + //Do scrolling + if(this.options.scroll) { + var o = this.options, scrolled = false; + if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') { + + if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) + this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed; + else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) + this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed; + + if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) + this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed; + else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) + this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed; + + } else { + + if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) + scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); + else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) + scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); + + if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) + scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); + else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) + scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); + + } + + if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) + $.ui.ddmanager.prepareOffsets(this, event); + } + + //Regenerate the absolute position used for position checks + this.positionAbs = this._convertPositionTo("absolute"); + + //Set the helper position + if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px'; + if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px'; + + //Rearrange + for (var i = this.items.length - 1; i >= 0; i--) { + + //Cache variables and intersection, continue if no intersection + var item = this.items[i], itemElement = item.item[0], intersection = this._intersectsWithPointer(item); + if (!intersection) continue; + + if(itemElement != this.currentItem[0] //cannot intersect with itself + && this.placeholder[intersection == 1 ? "next" : "prev"]()[0] != itemElement //no useless actions that have been done before + && !$.ui.contains(this.placeholder[0], itemElement) //no action if the item moved is the parent of the item checked + && (this.options.type == 'semi-dynamic' ? !$.ui.contains(this.element[0], itemElement) : true) + ) { + + this.direction = intersection == 1 ? "down" : "up"; + + if (this.options.tolerance == "pointer" || this._intersectsWithSides(item)) { + this._rearrange(event, item); + } else { + break; + } + + this._trigger("change", event, this._uiHash()); + break; + } + } + + //Post events to containers + this._contactContainers(event); + + //Interconnect with droppables + if($.ui.ddmanager) $.ui.ddmanager.drag(this, event); + + //Call callbacks + this._trigger('sort', event, this._uiHash()); + + this.lastPositionAbs = this.positionAbs; + return false; + + }, + + _mouseStop: function(event, noPropagation) { + + if(!event) return; + + //If we are using droppables, inform the manager about the drop + if ($.ui.ddmanager && !this.options.dropBehaviour) + $.ui.ddmanager.drop(this, event); + + if(this.options.revert) { + var self = this; + var cur = self.placeholder.offset(); + + self.reverting = true; + + $(this.helper).animate({ + left: cur.left - this.offset.parent.left - self.margins.left + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft), + top: cur.top - this.offset.parent.top - self.margins.top + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop) + }, parseInt(this.options.revert, 10) || 500, function() { + self._clear(event); + }); + } else { + this._clear(event, noPropagation); + } + + return false; + + }, + + cancel: function() { + + var self = this; + + if(this.dragging) { + + this._mouseUp(); + + if(this.options.helper == "original") + this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); + else + this.currentItem.show(); + + //Post deactivating events to containers + for (var i = this.containers.length - 1; i >= 0; i--){ + this.containers[i]._trigger("deactivate", null, self._uiHash(this)); + if(this.containers[i].containerCache.over) { + this.containers[i]._trigger("out", null, self._uiHash(this)); + this.containers[i].containerCache.over = 0; + } + } + + } + + //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! + if(this.placeholder[0].parentNode) this.placeholder[0].parentNode.removeChild(this.placeholder[0]); + if(this.options.helper != "original" && this.helper && this.helper[0].parentNode) this.helper.remove(); + + $.extend(this, { + helper: null, + dragging: false, + reverting: false, + _noFinalSort: null + }); + + if(this.domPosition.prev) { + $(this.domPosition.prev).after(this.currentItem); + } else { + $(this.domPosition.parent).prepend(this.currentItem); + } + + return true; + + }, + + serialize: function(o) { + + var items = this._getItemsAsjQuery(o && o.connected); + var str = []; o = o || {}; + + $(items).each(function() { + var res = ($(o.item || this).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/)); + if(res) str.push((o.key || res[1]+'[]')+'='+(o.key && o.expression ? res[1] : res[2])); + }); + + return str.join('&'); + + }, + + toArray: function(o) { + + var items = this._getItemsAsjQuery(o && o.connected); + var ret = []; o = o || {}; + + items.each(function() { ret.push($(o.item || this).attr(o.attribute || 'id') || ''); }); + return ret; + + }, + + /* Be careful with the following core functions */ + _intersectsWith: function(item) { + + var x1 = this.positionAbs.left, + x2 = x1 + this.helperProportions.width, + y1 = this.positionAbs.top, + y2 = y1 + this.helperProportions.height; + + var l = item.left, + r = l + item.width, + t = item.top, + b = t + item.height; + + var dyClick = this.offset.click.top, + dxClick = this.offset.click.left; + + var isOverElement = (y1 + dyClick) > t && (y1 + dyClick) < b && (x1 + dxClick) > l && (x1 + dxClick) < r; + + if( this.options.tolerance == "pointer" + || this.options.forcePointerForContainers + || (this.options.tolerance != "pointer" && this.helperProportions[this.floating ? 'width' : 'height'] > item[this.floating ? 'width' : 'height']) + ) { + return isOverElement; + } else { + + return (l < x1 + (this.helperProportions.width / 2) // Right Half + && x2 - (this.helperProportions.width / 2) < r // Left Half + && t < y1 + (this.helperProportions.height / 2) // Bottom Half + && y2 - (this.helperProportions.height / 2) < b ); // Top Half + + } + }, + + _intersectsWithPointer: function(item) { + + var isOverElementHeight = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height), + isOverElementWidth = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width), + isOverElement = isOverElementHeight && isOverElementWidth, + verticalDirection = this._getDragVerticalDirection(), + horizontalDirection = this._getDragHorizontalDirection(); + + if (!isOverElement) + return false; + + return this.floating ? + ( ((horizontalDirection && horizontalDirection == "right") || verticalDirection == "down") ? 2 : 1 ) + : ( verticalDirection && (verticalDirection == "down" ? 2 : 1) ); + + }, + + _intersectsWithSides: function(item) { + + var isOverBottomHalf = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height), + isOverRightHalf = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width), + verticalDirection = this._getDragVerticalDirection(), + horizontalDirection = this._getDragHorizontalDirection(); + + if (this.floating && horizontalDirection) { + return ((horizontalDirection == "right" && isOverRightHalf) || (horizontalDirection == "left" && !isOverRightHalf)); + } else { + return verticalDirection && ((verticalDirection == "down" && isOverBottomHalf) || (verticalDirection == "up" && !isOverBottomHalf)); + } + + }, + + _getDragVerticalDirection: function() { + var delta = this.positionAbs.top - this.lastPositionAbs.top; + return delta != 0 && (delta > 0 ? "down" : "up"); + }, + + _getDragHorizontalDirection: function() { + var delta = this.positionAbs.left - this.lastPositionAbs.left; + return delta != 0 && (delta > 0 ? "right" : "left"); + }, + + refresh: function(event) { + this._refreshItems(event); + this.refreshPositions(); + }, + + _connectWith: function() { + var options = this.options; + return options.connectWith.constructor == String + ? [options.connectWith] + : options.connectWith; + }, + + _getItemsAsjQuery: function(connected) { + + var self = this; + var items = []; + var queries = []; + var connectWith = this._connectWith(); + + if(connectWith && connected) { + for (var i = connectWith.length - 1; i >= 0; i--){ + var cur = $(connectWith[i]); + for (var j = cur.length - 1; j >= 0; j--){ + var inst = $.data(cur[j], 'sortable'); + if(inst && inst != this && !inst.options.disabled) { + queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper"), inst]); + } + }; + }; + } + + queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper"), this]); + + for (var i = queries.length - 1; i >= 0; i--){ + queries[i][0].each(function() { + items.push(this); + }); + }; + + return $(items); + + }, + + _removeCurrentsFromItems: function() { + + var list = this.currentItem.find(":data(sortable-item)"); + + for (var i=0; i < this.items.length; i++) { + + for (var j=0; j < list.length; j++) { + if(list[j] == this.items[i].item[0]) + this.items.splice(i,1); + }; + + }; + + }, + + _refreshItems: function(event) { + + this.items = []; + this.containers = [this]; + var items = this.items; + var self = this; + var queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]]; + var connectWith = this._connectWith(); + + if(connectWith) { + for (var i = connectWith.length - 1; i >= 0; i--){ + var cur = $(connectWith[i]); + for (var j = cur.length - 1; j >= 0; j--){ + var inst = $.data(cur[j], 'sortable'); + if(inst && inst != this && !inst.options.disabled) { + queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]); + this.containers.push(inst); + } + }; + }; + } + + for (var i = queries.length - 1; i >= 0; i--) { + var targetData = queries[i][1]; + var _queries = queries[i][0]; + + for (var j=0, queriesLength = _queries.length; j < queriesLength; j++) { + var item = $(_queries[j]); + + item.data('sortable-item', targetData); // Data for target checking (mouse manager) + + items.push({ + item: item, + instance: targetData, + width: 0, height: 0, + left: 0, top: 0 + }); + }; + }; + + }, + + refreshPositions: function(fast) { + + //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change + if(this.offsetParent && this.helper) { + this.offset.parent = this._getParentOffset(); + } + + for (var i = this.items.length - 1; i >= 0; i--){ + var item = this.items[i]; + + //We ignore calculating positions of all connected containers when we're not over them + if(item.instance != this.currentContainer && this.currentContainer && item.item[0] != this.currentItem[0]) + continue; + + var t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item; + + if (!fast) { + item.width = t.outerWidth(); + item.height = t.outerHeight(); + } + + var p = t.offset(); + item.left = p.left; + item.top = p.top; + }; + + if(this.options.custom && this.options.custom.refreshContainers) { + this.options.custom.refreshContainers.call(this); + } else { + for (var i = this.containers.length - 1; i >= 0; i--){ + var p = this.containers[i].element.offset(); + this.containers[i].containerCache.left = p.left; + this.containers[i].containerCache.top = p.top; + this.containers[i].containerCache.width = this.containers[i].element.outerWidth(); + this.containers[i].containerCache.height = this.containers[i].element.outerHeight(); + }; + } + + }, + + _createPlaceholder: function(that) { + + var self = that || this, o = self.options; + + if(!o.placeholder || o.placeholder.constructor == String) { + var className = o.placeholder; + o.placeholder = { + element: function() { + + var el = $(document.createElement(self.currentItem[0].nodeName)) + .addClass(className || self.currentItem[0].className+" ui-sortable-placeholder") + .removeClass("ui-sortable-helper")[0]; + + if(!className) + el.style.visibility = "hidden"; + + return el; + }, + update: function(container, p) { + + // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that + // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified + if(className && !o.forcePlaceholderSize) return; + + //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item + if(!p.height()) { p.height(self.currentItem.innerHeight() - parseInt(self.currentItem.css('paddingTop')||0, 10) - parseInt(self.currentItem.css('paddingBottom')||0, 10)); }; + if(!p.width()) { p.width(self.currentItem.innerWidth() - parseInt(self.currentItem.css('paddingLeft')||0, 10) - parseInt(self.currentItem.css('paddingRight')||0, 10)); }; + } + }; + } + + //Create the placeholder + self.placeholder = $(o.placeholder.element.call(self.element, self.currentItem)); + + //Append it after the actual current item + self.currentItem.after(self.placeholder); + + //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317) + o.placeholder.update(self, self.placeholder); + + }, + + _contactContainers: function(event) { + for (var i = this.containers.length - 1; i >= 0; i--){ + + if(this._intersectsWith(this.containers[i].containerCache)) { + if(!this.containers[i].containerCache.over) { + + if(this.currentContainer != this.containers[i]) { + + //When entering a new container, we will find the item with the least distance and append our item near it + var dist = 10000; var itemWithLeastDistance = null; var base = this.positionAbs[this.containers[i].floating ? 'left' : 'top']; + for (var j = this.items.length - 1; j >= 0; j--) { + if(!$.ui.contains(this.containers[i].element[0], this.items[j].item[0])) continue; + var cur = this.items[j][this.containers[i].floating ? 'left' : 'top']; + if(Math.abs(cur - base) < dist) { + dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j]; + } + } + + if(!itemWithLeastDistance && !this.options.dropOnEmpty) //Check if dropOnEmpty is enabled + continue; + + this.currentContainer = this.containers[i]; + itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[i].element, true); + this._trigger("change", event, this._uiHash()); + this.containers[i]._trigger("change", event, this._uiHash(this)); + + //Update the placeholder + this.options.placeholder.update(this.currentContainer, this.placeholder); + + } + + this.containers[i]._trigger("over", event, this._uiHash(this)); + this.containers[i].containerCache.over = 1; + } + } else { + if(this.containers[i].containerCache.over) { + this.containers[i]._trigger("out", event, this._uiHash(this)); + this.containers[i].containerCache.over = 0; + } + } + + }; + }, + + _createHelper: function(event) { + + var o = this.options; + var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper == 'clone' ? this.currentItem.clone() : this.currentItem); + + if(!helper.parents('body').length) //Add the helper to the DOM if that didn't happen already + $(o.appendTo != 'parent' ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]); + + if(helper[0] == this.currentItem[0]) + this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") }; + + if(helper[0].style.width == '' || o.forceHelperSize) helper.width(this.currentItem.width()); + if(helper[0].style.height == '' || o.forceHelperSize) helper.height(this.currentItem.height()); + + return helper; + + }, + + _adjustOffsetFromHelper: function(obj) { + if(obj.left != undefined) this.offset.click.left = obj.left + this.margins.left; + if(obj.right != undefined) this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; + if(obj.top != undefined) this.offset.click.top = obj.top + this.margins.top; + if(obj.bottom != undefined) this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; + }, + + _getParentOffset: function() { + + + //Get the offsetParent and cache its position + this.offsetParent = this.helper.offsetParent(); + var po = this.offsetParent.offset(); + + // This is a special case where we need to modify a offset calculated on start, since the following happened: + // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent + // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that + // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag + if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) { + po.left += this.scrollParent.scrollLeft(); + po.top += this.scrollParent.scrollTop(); + } + + if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information + || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix + po = { top: 0, left: 0 }; + + return { + top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), + left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) + }; + + }, + + _getRelativeOffset: function() { + + if(this.cssPosition == "relative") { + var p = this.currentItem.position(); + return { + top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), + left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() + }; + } else { + return { top: 0, left: 0 }; + } + + }, + + _cacheMargins: function() { + this.margins = { + left: (parseInt(this.currentItem.css("marginLeft"),10) || 0), + top: (parseInt(this.currentItem.css("marginTop"),10) || 0) + }; + }, + + _cacheHelperProportions: function() { + this.helperProportions = { + width: this.helper.outerWidth(), + height: this.helper.outerHeight() + }; + }, + + _setContainment: function() { + + var o = this.options; + if(o.containment == 'parent') o.containment = this.helper[0].parentNode; + if(o.containment == 'document' || o.containment == 'window') this.containment = [ + 0 - this.offset.relative.left - this.offset.parent.left, + 0 - this.offset.relative.top - this.offset.parent.top, + $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left, + ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top + ]; + + if(!(/^(document|window|parent)$/).test(o.containment)) { + var ce = $(o.containment)[0]; + var co = $(o.containment).offset(); + var over = ($(ce).css("overflow") != 'hidden'); + + this.containment = [ + co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left, + co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top, + co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left, + co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top + ]; + } + + }, + + _convertPositionTo: function(d, pos) { + + if(!pos) pos = this.position; + var mod = d == "absolute" ? 1 : -1; + var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); + + return { + top: ( + pos.top // The absolute mouse position + + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent + + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border) + - ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) + ), + left: ( + pos.left // The absolute mouse position + + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent + + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border) + - ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) + ) + }; + + }, + + _generatePosition: function(event) { + + var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); + + // This is another very weird special case that only happens for relative elements: + // 1. If the css position is relative + // 2. and the scroll parent is the document or similar to the offset parent + // we have to refresh the relative offset during the scroll so there are no jumps + if(this.cssPosition == 'relative' && !(this.scrollParent[0] != document && this.scrollParent[0] != this.offsetParent[0])) { + this.offset.relative = this._getRelativeOffset(); + } + + var pageX = event.pageX; + var pageY = event.pageY; + + /* + * - Position constraining - + * Constrain the position to a mix of grid, containment. + */ + + if(this.originalPosition) { //If we are not dragging yet, we won't check for options + + if(this.containment) { + if(event.pageX - this.offset.click.left < this.containment[0]) pageX = this.containment[0] + this.offset.click.left; + if(event.pageY - this.offset.click.top < this.containment[1]) pageY = this.containment[1] + this.offset.click.top; + if(event.pageX - this.offset.click.left > this.containment[2]) pageX = this.containment[2] + this.offset.click.left; + if(event.pageY - this.offset.click.top > this.containment[3]) pageY = this.containment[3] + this.offset.click.top; + } + + if(o.grid) { + var top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1]; + pageY = this.containment ? (!(top - this.offset.click.top < this.containment[1] || top - this.offset.click.top > this.containment[3]) ? top : (!(top - this.offset.click.top < this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; + + var left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0]; + pageX = this.containment ? (!(left - this.offset.click.left < this.containment[0] || left - this.offset.click.left > this.containment[2]) ? left : (!(left - this.offset.click.left < this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; + } + + } + + return { + top: ( + pageY // The absolute mouse position + - this.offset.click.top // Click offset (relative to the element) + - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent + - this.offset.parent.top // The offsetParent's offset without borders (offset + border) + + ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) + ), + left: ( + pageX // The absolute mouse position + - this.offset.click.left // Click offset (relative to the element) + - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent + - this.offset.parent.left // The offsetParent's offset without borders (offset + border) + + ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) + ) + }; + + }, + + _rearrange: function(event, i, a, hardRefresh) { + + a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction == 'down' ? i.item[0] : i.item[0].nextSibling)); + + //Various things done here to improve the performance: + // 1. we create a setTimeout, that calls refreshPositions + // 2. on the instance, we have a counter variable, that get's higher after every append + // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same + // 4. this lets only the last addition to the timeout stack through + this.counter = this.counter ? ++this.counter : 1; + var self = this, counter = this.counter; + + window.setTimeout(function() { + if(counter == self.counter) self.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove + },0); + + }, + + _clear: function(event, noPropagation) { + + this.reverting = false; + // We delay all events that have to be triggered to after the point where the placeholder has been removed and + // everything else normalized again + var delayedTriggers = [], self = this; + + // We first have to update the dom position of the actual currentItem + // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088) + if(!this._noFinalSort && this.currentItem[0].parentNode) this.placeholder.before(this.currentItem); + this._noFinalSort = null; + + if(this.helper[0] == this.currentItem[0]) { + for(var i in this._storedCSS) { + if(this._storedCSS[i] == 'auto' || this._storedCSS[i] == 'static') this._storedCSS[i] = ''; + } + this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); + } else { + this.currentItem.show(); + } + + if(this.fromOutside && !noPropagation) delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); }); + if((this.fromOutside || this.domPosition.prev != this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent != this.currentItem.parent()[0]) && !noPropagation) delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed + if(!$.ui.contains(this.element[0], this.currentItem[0])) { //Node was moved out of the current element + if(!noPropagation) delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); }); + for (var i = this.containers.length - 1; i >= 0; i--){ + if($.ui.contains(this.containers[i].element[0], this.currentItem[0]) && !noPropagation) { + delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.containers[i])); + delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.containers[i])); + } + }; + }; + + //Post events to containers + for (var i = this.containers.length - 1; i >= 0; i--){ + if(!noPropagation) delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i])); + if(this.containers[i].containerCache.over) { + delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); }; }).call(this, this.containers[i])); + this.containers[i].containerCache.over = 0; + } + } + + //Do what was originally in plugins + if(this._storedCursor) $('body').css("cursor", this._storedCursor); //Reset cursor + if(this._storedOpacity) this.helper.css("opacity", this._storedOpacity); //Reset cursor + if(this._storedZIndex) this.helper.css("zIndex", this._storedZIndex == 'auto' ? '' : this._storedZIndex); //Reset z-index + + this.dragging = false; + if(this.cancelHelperRemoval) { + if(!noPropagation) { + this._trigger("beforeStop", event, this._uiHash()); + for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events + this._trigger("stop", event, this._uiHash()); + } + return false; + } + + if(!noPropagation) this._trigger("beforeStop", event, this._uiHash()); + + //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! + this.placeholder[0].parentNode.removeChild(this.placeholder[0]); + + if(this.helper[0] != this.currentItem[0]) this.helper.remove(); this.helper = null; + + if(!noPropagation) { + for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events + this._trigger("stop", event, this._uiHash()); + } + + this.fromOutside = false; + return true; + + }, + + _trigger: function() { + if ($.widget.prototype._trigger.apply(this, arguments) === false) { + this.cancel(); + } + }, + + _uiHash: function(inst) { + var self = inst || this; + return { + helper: self.helper, + placeholder: self.placeholder || $([]), + position: self.position, + absolutePosition: self.positionAbs, //deprecated + offset: self.positionAbs, + item: self.currentItem, + sender: inst ? inst.element : null + }; + } + +})); + +$.extend($.ui.sortable, { + getter: "serialize toArray", + version: "1.7.1", + eventPrefix: "sort", + defaults: { + appendTo: "parent", + axis: false, + cancel: ":input,option", + connectWith: false, + containment: false, + cursor: 'auto', + cursorAt: false, + delay: 0, + distance: 1, + dropOnEmpty: true, + forcePlaceholderSize: false, + forceHelperSize: false, + grid: false, + handle: false, + helper: "original", + items: '> *', + opacity: false, + placeholder: false, + revert: false, + scroll: true, + scrollSensitivity: 20, + scrollSpeed: 20, + scope: "default", + tolerance: "intersect", + zIndex: 1000 + } +}); + +})(jQuery); +/* + * jQuery UI Accordion 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Accordion + * + * Depends: + * ui.core.js + */ +(function($) { + +$.widget("ui.accordion", { + + _init: function() { + + var o = this.options, self = this; + this.running = 0; + + // if the user set the alwaysOpen option on init + // then we need to set the collapsible option + // if they set both on init, collapsible will take priority + if (o.collapsible == $.ui.accordion.defaults.collapsible && + o.alwaysOpen != $.ui.accordion.defaults.alwaysOpen) { + o.collapsible = !o.alwaysOpen; + } + + if ( o.navigation ) { + var current = this.element.find("a").filter(o.navigationFilter); + if ( current.length ) { + if ( current.filter(o.header).length ) { + this.active = current; + } else { + this.active = current.parent().parent().prev(); + current.addClass("ui-accordion-content-active"); + } + } + } + + this.element.addClass("ui-accordion ui-widget ui-helper-reset"); + + // in lack of child-selectors in CSS we need to mark top-LIs in a UL-accordion for some IE-fix + if (this.element[0].nodeName == "UL") { + this.element.children("li").addClass("ui-accordion-li-fix"); + } + + this.headers = this.element.find(o.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all") + .bind("mouseenter.accordion", function(){ $(this).addClass('ui-state-hover'); }) + .bind("mouseleave.accordion", function(){ $(this).removeClass('ui-state-hover'); }) + .bind("focus.accordion", function(){ $(this).addClass('ui-state-focus'); }) + .bind("blur.accordion", function(){ $(this).removeClass('ui-state-focus'); }); + + this.headers + .next() + .addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom"); + + this.active = this._findActive(this.active || o.active).toggleClass("ui-state-default").toggleClass("ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top"); + this.active.next().addClass('ui-accordion-content-active'); + + //Append icon elements + $("").addClass("ui-icon " + o.icons.header).prependTo(this.headers); + this.active.find(".ui-icon").toggleClass(o.icons.header).toggleClass(o.icons.headerSelected); + + // IE7-/Win - Extra vertical space in lists fixed + if ($.browser.msie) { + this.element.find('a').css('zoom', '1'); + } + + this.resize(); + + //ARIA + this.element.attr('role','tablist'); + + this.headers + .attr('role','tab') + .bind('keydown', function(event) { return self._keydown(event); }) + .next() + .attr('role','tabpanel'); + + this.headers + .not(this.active || "") + .attr('aria-expanded','false') + .attr("tabIndex", "-1") + .next() + .hide(); + + // make sure at least one header is in the tab order + if (!this.active.length) { + this.headers.eq(0).attr('tabIndex','0'); + } else { + this.active + .attr('aria-expanded','true') + .attr('tabIndex', '0'); + } + + // only need links in taborder for Safari + if (!$.browser.safari) + this.headers.find('a').attr('tabIndex','-1'); + + if (o.event) { + this.headers.bind((o.event) + ".accordion", function(event) { return self._clickHandler.call(self, event, this); }); + } + + }, + + destroy: function() { + var o = this.options; + + this.element + .removeClass("ui-accordion ui-widget ui-helper-reset") + .removeAttr("role") + .unbind('.accordion') + .removeData('accordion'); + + this.headers + .unbind(".accordion") + .removeClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-corner-top") + .removeAttr("role").removeAttr("aria-expanded").removeAttr("tabindex"); + + this.headers.find("a").removeAttr("tabindex"); + this.headers.children(".ui-icon").remove(); + var contents = this.headers.next().css("display", "").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active"); + if (o.autoHeight || o.fillHeight) { + contents.css("height", ""); + } + }, + + _setData: function(key, value) { + if(key == 'alwaysOpen') { key = 'collapsible'; value = !value; } + $.widget.prototype._setData.apply(this, arguments); + }, + + _keydown: function(event) { + + var o = this.options, keyCode = $.ui.keyCode; + + if (o.disabled || event.altKey || event.ctrlKey) + return; + + var length = this.headers.length; + var currentIndex = this.headers.index(event.target); + var toFocus = false; + + switch(event.keyCode) { + case keyCode.RIGHT: + case keyCode.DOWN: + toFocus = this.headers[(currentIndex + 1) % length]; + break; + case keyCode.LEFT: + case keyCode.UP: + toFocus = this.headers[(currentIndex - 1 + length) % length]; + break; + case keyCode.SPACE: + case keyCode.ENTER: + return this._clickHandler({ target: event.target }, event.target); + } + + if (toFocus) { + $(event.target).attr('tabIndex','-1'); + $(toFocus).attr('tabIndex','0'); + toFocus.focus(); + return false; + } + + return true; + + }, + + resize: function() { + + var o = this.options, maxHeight; + + if (o.fillSpace) { + + if($.browser.msie) { var defOverflow = this.element.parent().css('overflow'); this.element.parent().css('overflow', 'hidden'); } + maxHeight = this.element.parent().height(); + if($.browser.msie) { this.element.parent().css('overflow', defOverflow); } + + this.headers.each(function() { + maxHeight -= $(this).outerHeight(); + }); + + var maxPadding = 0; + this.headers.next().each(function() { + maxPadding = Math.max(maxPadding, $(this).innerHeight() - $(this).height()); + }).height(Math.max(0, maxHeight - maxPadding)) + .css('overflow', 'auto'); + + } else if ( o.autoHeight ) { + maxHeight = 0; + this.headers.next().each(function() { + maxHeight = Math.max(maxHeight, $(this).outerHeight()); + }).height(maxHeight); + } + + }, + + activate: function(index) { + // call clickHandler with custom event + var active = this._findActive(index)[0]; + this._clickHandler({ target: active }, active); + }, + + _findActive: function(selector) { + return selector + ? typeof selector == "number" + ? this.headers.filter(":eq(" + selector + ")") + : this.headers.not(this.headers.not(selector)) + : selector === false + ? $([]) + : this.headers.filter(":eq(0)"); + }, + + _clickHandler: function(event, target) { + + var o = this.options; + if (o.disabled) return false; + + // called only when using activate(false) to close all parts programmatically + if (!event.target && o.collapsible) { + this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all") + .find(".ui-icon").removeClass(o.icons.headerSelected).addClass(o.icons.header); + this.active.next().addClass('ui-accordion-content-active'); + var toHide = this.active.next(), + data = { + options: o, + newHeader: $([]), + oldHeader: o.active, + newContent: $([]), + oldContent: toHide + }, + toShow = (this.active = $([])); + this._toggle(toShow, toHide, data); + return false; + } + + // get the click target + var clicked = $(event.currentTarget || target); + var clickedIsActive = clicked[0] == this.active[0]; + + // if animations are still active, or the active header is the target, ignore click + if (this.running || (!o.collapsible && clickedIsActive)) { + return false; + } + + // switch classes + this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all") + .find(".ui-icon").removeClass(o.icons.headerSelected).addClass(o.icons.header); + this.active.next().addClass('ui-accordion-content-active'); + if (!clickedIsActive) { + clicked.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top") + .find(".ui-icon").removeClass(o.icons.header).addClass(o.icons.headerSelected); + clicked.next().addClass('ui-accordion-content-active'); + } + + // find elements to show and hide + var toShow = clicked.next(), + toHide = this.active.next(), + data = { + options: o, + newHeader: clickedIsActive && o.collapsible ? $([]) : clicked, + oldHeader: this.active, + newContent: clickedIsActive && o.collapsible ? $([]) : toShow.find('> *'), + oldContent: toHide.find('> *') + }, + down = this.headers.index( this.active[0] ) > this.headers.index( clicked[0] ); + + this.active = clickedIsActive ? $([]) : clicked; + this._toggle(toShow, toHide, data, clickedIsActive, down); + + return false; + + }, + + _toggle: function(toShow, toHide, data, clickedIsActive, down) { + + var o = this.options, self = this; + + this.toShow = toShow; + this.toHide = toHide; + this.data = data; + + var complete = function() { if(!self) return; return self._completed.apply(self, arguments); }; + + // trigger changestart event + this._trigger("changestart", null, this.data); + + // count elements to animate + this.running = toHide.size() === 0 ? toShow.size() : toHide.size(); + + if (o.animated) { + + var animOptions = {}; + + if ( o.collapsible && clickedIsActive ) { + animOptions = { + toShow: $([]), + toHide: toHide, + complete: complete, + down: down, + autoHeight: o.autoHeight || o.fillSpace + }; + } else { + animOptions = { + toShow: toShow, + toHide: toHide, + complete: complete, + down: down, + autoHeight: o.autoHeight || o.fillSpace + }; + } + + if (!o.proxied) { + o.proxied = o.animated; + } + + if (!o.proxiedDuration) { + o.proxiedDuration = o.duration; + } + + o.animated = $.isFunction(o.proxied) ? + o.proxied(animOptions) : o.proxied; + + o.duration = $.isFunction(o.proxiedDuration) ? + o.proxiedDuration(animOptions) : o.proxiedDuration; + + var animations = $.ui.accordion.animations, + duration = o.duration, + easing = o.animated; + + if (!animations[easing]) { + animations[easing] = function(options) { + this.slide(options, { + easing: easing, + duration: duration || 700 + }); + }; + } + + animations[easing](animOptions); + + } else { + + if (o.collapsible && clickedIsActive) { + toShow.toggle(); + } else { + toHide.hide(); + toShow.show(); + } + + complete(true); + + } + + toHide.prev().attr('aria-expanded','false').attr("tabIndex", "-1").blur(); + toShow.prev().attr('aria-expanded','true').attr("tabIndex", "0").focus(); + + }, + + _completed: function(cancel) { + + var o = this.options; + + this.running = cancel ? 0 : --this.running; + if (this.running) return; + + if (o.clearStyle) { + this.toShow.add(this.toHide).css({ + height: "", + overflow: "" + }); + } + + this._trigger('change', null, this.data); + } + +}); + + +$.extend($.ui.accordion, { + version: "1.7.1", + defaults: { + active: null, + alwaysOpen: true, //deprecated, use collapsible + animated: 'slide', + autoHeight: true, + clearStyle: false, + collapsible: false, + event: "click", + fillSpace: false, + header: "> li > :first-child,> :not(li):even", + icons: { + header: "ui-icon-triangle-1-e", + headerSelected: "ui-icon-triangle-1-s" + }, + navigation: false, + navigationFilter: function() { + return this.href.toLowerCase() == location.href.toLowerCase(); + } + }, + animations: { + slide: function(options, additions) { + options = $.extend({ + easing: "swing", + duration: 300 + }, options, additions); + if ( !options.toHide.size() ) { + options.toShow.animate({height: "show"}, options); + return; + } + if ( !options.toShow.size() ) { + options.toHide.animate({height: "hide"}, options); + return; + } + var overflow = options.toShow.css('overflow'), + percentDone, + showProps = {}, + hideProps = {}, + fxAttrs = [ "height", "paddingTop", "paddingBottom" ], + originalWidth; + // fix width before calculating height of hidden element + var s = options.toShow; + originalWidth = s[0].style.width; + s.width( parseInt(s.parent().width(),10) - parseInt(s.css("paddingLeft"),10) - parseInt(s.css("paddingRight"),10) - (parseInt(s.css("borderLeftWidth"),10) || 0) - (parseInt(s.css("borderRightWidth"),10) || 0) ); + + $.each(fxAttrs, function(i, prop) { + hideProps[prop] = 'hide'; + + var parts = ('' + $.css(options.toShow[0], prop)).match(/^([\d+-.]+)(.*)$/); + showProps[prop] = { + value: parts[1], + unit: parts[2] || 'px' + }; + }); + options.toShow.css({ height: 0, overflow: 'hidden' }).show(); + options.toHide.filter(":hidden").each(options.complete).end().filter(":visible").animate(hideProps,{ + step: function(now, settings) { + // only calculate the percent when animating height + // IE gets very inconsistent results when animating elements + // with small values, which is common for padding + if (settings.prop == 'height') { + percentDone = (settings.now - settings.start) / (settings.end - settings.start); + } + + options.toShow[0].style[settings.prop] = + (percentDone * showProps[settings.prop].value) + showProps[settings.prop].unit; + }, + duration: options.duration, + easing: options.easing, + complete: function() { + if ( !options.autoHeight ) { + options.toShow.css("height", ""); + } + options.toShow.css("width", originalWidth); + options.toShow.css({overflow: overflow}); + options.complete(); + } + }); + }, + bounceslide: function(options) { + this.slide(options, { + easing: options.down ? "easeOutBounce" : "swing", + duration: options.down ? 1000 : 200 + }); + }, + easeslide: function(options) { + this.slide(options, { + easing: "easeinout", + duration: 700 + }); + } + } +}); + +})(jQuery); +/* + * jQuery UI Dialog 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Dialog + * + * Depends: + * ui.core.js + * ui.draggable.js + * ui.resizable.js + */ +(function($) { + +var setDataSwitch = { + dragStart: "start.draggable", + drag: "drag.draggable", + dragStop: "stop.draggable", + maxHeight: "maxHeight.resizable", + minHeight: "minHeight.resizable", + maxWidth: "maxWidth.resizable", + minWidth: "minWidth.resizable", + resizeStart: "start.resizable", + resize: "drag.resizable", + resizeStop: "stop.resizable" + }, + + uiDialogClasses = + 'ui-dialog ' + + 'ui-widget ' + + 'ui-widget-content ' + + 'ui-corner-all '; + +$.widget("ui.dialog", { + + _init: function() { + this.originalTitle = this.element.attr('title'); + + var self = this, + options = this.options, + + title = options.title || this.originalTitle || ' ', + titleId = $.ui.dialog.getTitleId(this.element), + + uiDialog = (this.uiDialog = $('
    ')) + .appendTo(document.body) + .hide() + .addClass(uiDialogClasses + options.dialogClass) + .css({ + position: 'absolute', + overflow: 'hidden', + zIndex: options.zIndex + }) + // setting tabIndex makes the div focusable + // setting outline to 0 prevents a border on focus in Mozilla + .attr('tabIndex', -1).css('outline', 0).keydown(function(event) { + (options.closeOnEscape && event.keyCode + && event.keyCode == $.ui.keyCode.ESCAPE && self.close(event)); + }) + .attr({ + role: 'dialog', + 'aria-labelledby': titleId + }) + .mousedown(function(event) { + self.moveToTop(false, event); + }), + + uiDialogContent = this.element + .show() + .removeAttr('title') + .addClass( + 'ui-dialog-content ' + + 'ui-widget-content') + .appendTo(uiDialog), + + uiDialogTitlebar = (this.uiDialogTitlebar = $('
    ')) + .addClass( + 'ui-dialog-titlebar ' + + 'ui-widget-header ' + + 'ui-corner-all ' + + 'ui-helper-clearfix' + ) + .prependTo(uiDialog), + + uiDialogTitlebarClose = $('') + .addClass( + 'ui-dialog-titlebar-close ' + + 'ui-corner-all' + ) + .attr('role', 'button') + .hover( + function() { + uiDialogTitlebarClose.addClass('ui-state-hover'); + }, + function() { + uiDialogTitlebarClose.removeClass('ui-state-hover'); + } + ) + .focus(function() { + uiDialogTitlebarClose.addClass('ui-state-focus'); + }) + .blur(function() { + uiDialogTitlebarClose.removeClass('ui-state-focus'); + }) + .mousedown(function(ev) { + ev.stopPropagation(); + }) + .click(function(event) { + self.close(event); + return false; + }) + .appendTo(uiDialogTitlebar), + + uiDialogTitlebarCloseText = (this.uiDialogTitlebarCloseText = $('')) + .addClass( + 'ui-icon ' + + 'ui-icon-closethick' + ) + .text(options.closeText) + .appendTo(uiDialogTitlebarClose), + + uiDialogTitle = $('') + .addClass('ui-dialog-title') + .attr('id', titleId) + .html(title) + .prependTo(uiDialogTitlebar); + + uiDialogTitlebar.find("*").add(uiDialogTitlebar).disableSelection(); + + (options.draggable && $.fn.draggable && this._makeDraggable()); + (options.resizable && $.fn.resizable && this._makeResizable()); + + this._createButtons(options.buttons); + this._isOpen = false; + + (options.bgiframe && $.fn.bgiframe && uiDialog.bgiframe()); + (options.autoOpen && this.open()); + + }, + + destroy: function() { + (this.overlay && this.overlay.destroy()); + this.uiDialog.hide(); + this.element + .unbind('.dialog') + .removeData('dialog') + .removeClass('ui-dialog-content ui-widget-content') + .hide().appendTo('body'); + this.uiDialog.remove(); + + (this.originalTitle && this.element.attr('title', this.originalTitle)); + }, + + close: function(event) { + var self = this; + + if (false === self._trigger('beforeclose', event)) { + return; + } + + (self.overlay && self.overlay.destroy()); + self.uiDialog.unbind('keypress.ui-dialog'); + + (self.options.hide + ? self.uiDialog.hide(self.options.hide, function() { + self._trigger('close', event); + }) + : self.uiDialog.hide() && self._trigger('close', event)); + + $.ui.dialog.overlay.resize(); + + self._isOpen = false; + }, + + isOpen: function() { + return this._isOpen; + }, + + // the force parameter allows us to move modal dialogs to their correct + // position on open + moveToTop: function(force, event) { + + if ((this.options.modal && !force) + || (!this.options.stack && !this.options.modal)) { + return this._trigger('focus', event); + } + + if (this.options.zIndex > $.ui.dialog.maxZ) { + $.ui.dialog.maxZ = this.options.zIndex; + } + (this.overlay && this.overlay.$el.css('z-index', $.ui.dialog.overlay.maxZ = ++$.ui.dialog.maxZ)); + + //Save and then restore scroll since Opera 9.5+ resets when parent z-Index is changed. + // http://ui.jquery.com/bugs/ticket/3193 + var saveScroll = { scrollTop: this.element.attr('scrollTop'), scrollLeft: this.element.attr('scrollLeft') }; + this.uiDialog.css('z-index', ++$.ui.dialog.maxZ); + this.element.attr(saveScroll); + this._trigger('focus', event); + }, + + open: function() { + if (this._isOpen) { return; } + + var options = this.options, + uiDialog = this.uiDialog; + + this.overlay = options.modal ? new $.ui.dialog.overlay(this) : null; + (uiDialog.next().length && uiDialog.appendTo('body')); + this._size(); + this._position(options.position); + uiDialog.show(options.show); + this.moveToTop(true); + + // prevent tabbing out of modal dialogs + (options.modal && uiDialog.bind('keypress.ui-dialog', function(event) { + if (event.keyCode != $.ui.keyCode.TAB) { + return; + } + + var tabbables = $(':tabbable', this), + first = tabbables.filter(':first')[0], + last = tabbables.filter(':last')[0]; + + if (event.target == last && !event.shiftKey) { + setTimeout(function() { + first.focus(); + }, 1); + } else if (event.target == first && event.shiftKey) { + setTimeout(function() { + last.focus(); + }, 1); + } + })); + + // set focus to the first tabbable element in the content area or the first button + // if there are no tabbable elements, set focus on the dialog itself + $([]) + .add(uiDialog.find('.ui-dialog-content :tabbable:first')) + .add(uiDialog.find('.ui-dialog-buttonpane :tabbable:first')) + .add(uiDialog) + .filter(':first') + .focus(); + + this._trigger('open'); + this._isOpen = true; + }, + + _createButtons: function(buttons) { + var self = this, + hasButtons = false, + uiDialogButtonPane = $('
    ') + .addClass( + 'ui-dialog-buttonpane ' + + 'ui-widget-content ' + + 'ui-helper-clearfix' + ); + + // if we already have a button pane, remove it + this.uiDialog.find('.ui-dialog-buttonpane').remove(); + + (typeof buttons == 'object' && buttons !== null && + $.each(buttons, function() { return !(hasButtons = true); })); + if (hasButtons) { + $.each(buttons, function(name, fn) { + $('') + .addClass( + 'ui-state-default ' + + 'ui-corner-all' + ) + .text(name) + .click(function() { fn.apply(self.element[0], arguments); }) + .hover( + function() { + $(this).addClass('ui-state-hover'); + }, + function() { + $(this).removeClass('ui-state-hover'); + } + ) + .focus(function() { + $(this).addClass('ui-state-focus'); + }) + .blur(function() { + $(this).removeClass('ui-state-focus'); + }) + .appendTo(uiDialogButtonPane); + }); + uiDialogButtonPane.appendTo(this.uiDialog); + } + }, + + _makeDraggable: function() { + var self = this, + options = this.options, + heightBeforeDrag; + + this.uiDialog.draggable({ + cancel: '.ui-dialog-content', + handle: '.ui-dialog-titlebar', + containment: 'document', + start: function() { + heightBeforeDrag = options.height; + $(this).height($(this).height()).addClass("ui-dialog-dragging"); + (options.dragStart && options.dragStart.apply(self.element[0], arguments)); + }, + drag: function() { + (options.drag && options.drag.apply(self.element[0], arguments)); + }, + stop: function() { + $(this).removeClass("ui-dialog-dragging").height(heightBeforeDrag); + (options.dragStop && options.dragStop.apply(self.element[0], arguments)); + $.ui.dialog.overlay.resize(); + } + }); + }, + + _makeResizable: function(handles) { + handles = (handles === undefined ? this.options.resizable : handles); + var self = this, + options = this.options, + resizeHandles = typeof handles == 'string' + ? handles + : 'n,e,s,w,se,sw,ne,nw'; + + this.uiDialog.resizable({ + cancel: '.ui-dialog-content', + alsoResize: this.element, + maxWidth: options.maxWidth, + maxHeight: options.maxHeight, + minWidth: options.minWidth, + minHeight: options.minHeight, + start: function() { + $(this).addClass("ui-dialog-resizing"); + (options.resizeStart && options.resizeStart.apply(self.element[0], arguments)); + }, + resize: function() { + (options.resize && options.resize.apply(self.element[0], arguments)); + }, + handles: resizeHandles, + stop: function() { + $(this).removeClass("ui-dialog-resizing"); + options.height = $(this).height(); + options.width = $(this).width(); + (options.resizeStop && options.resizeStop.apply(self.element[0], arguments)); + $.ui.dialog.overlay.resize(); + } + }) + .find('.ui-resizable-se').addClass('ui-icon ui-icon-grip-diagonal-se'); + }, + + _position: function(pos) { + var wnd = $(window), doc = $(document), + pTop = doc.scrollTop(), pLeft = doc.scrollLeft(), + minTop = pTop; + + if ($.inArray(pos, ['center','top','right','bottom','left']) >= 0) { + pos = [ + pos == 'right' || pos == 'left' ? pos : 'center', + pos == 'top' || pos == 'bottom' ? pos : 'middle' + ]; + } + if (pos.constructor != Array) { + pos = ['center', 'middle']; + } + if (pos[0].constructor == Number) { + pLeft += pos[0]; + } else { + switch (pos[0]) { + case 'left': + pLeft += 0; + break; + case 'right': + pLeft += wnd.width() - this.uiDialog.outerWidth(); + break; + default: + case 'center': + pLeft += (wnd.width() - this.uiDialog.outerWidth()) / 2; + } + } + if (pos[1].constructor == Number) { + pTop += pos[1]; + } else { + switch (pos[1]) { + case 'top': + pTop += 0; + break; + case 'bottom': + pTop += wnd.height() - this.uiDialog.outerHeight(); + break; + default: + case 'middle': + pTop += (wnd.height() - this.uiDialog.outerHeight()) / 2; + } + } + + // prevent the dialog from being too high (make sure the titlebar + // is accessible) + pTop = Math.max(pTop, minTop); + this.uiDialog.css({top: pTop, left: pLeft}); + }, + + _setData: function(key, value){ + (setDataSwitch[key] && this.uiDialog.data(setDataSwitch[key], value)); + switch (key) { + case "buttons": + this._createButtons(value); + break; + case "closeText": + this.uiDialogTitlebarCloseText.text(value); + break; + case "dialogClass": + this.uiDialog + .removeClass(this.options.dialogClass) + .addClass(uiDialogClasses + value); + break; + case "draggable": + (value + ? this._makeDraggable() + : this.uiDialog.draggable('destroy')); + break; + case "height": + this.uiDialog.height(value); + break; + case "position": + this._position(value); + break; + case "resizable": + var uiDialog = this.uiDialog, + isResizable = this.uiDialog.is(':data(resizable)'); + + // currently resizable, becoming non-resizable + (isResizable && !value && uiDialog.resizable('destroy')); + + // currently resizable, changing handles + (isResizable && typeof value == 'string' && + uiDialog.resizable('option', 'handles', value)); + + // currently non-resizable, becoming resizable + (isResizable || this._makeResizable(value)); + break; + case "title": + $(".ui-dialog-title", this.uiDialogTitlebar).html(value || ' '); + break; + case "width": + this.uiDialog.width(value); + break; + } + + $.widget.prototype._setData.apply(this, arguments); + }, + + _size: function() { + /* If the user has resized the dialog, the .ui-dialog and .ui-dialog-content + * divs will both have width and height set, so we need to reset them + */ + var options = this.options; + + // reset content sizing + this.element.css({ + height: 0, + minHeight: 0, + width: 'auto' + }); + + // reset wrapper sizing + // determine the height of all the non-content elements + var nonContentHeight = this.uiDialog.css({ + height: 'auto', + width: options.width + }) + .height(); + + this.element + .css({ + minHeight: Math.max(options.minHeight - nonContentHeight, 0), + height: options.height == 'auto' + ? 'auto' + : Math.max(options.height - nonContentHeight, 0) + }); + } +}); + +$.extend($.ui.dialog, { + version: "1.7.1", + defaults: { + autoOpen: true, + bgiframe: false, + buttons: {}, + closeOnEscape: true, + closeText: 'close', + dialogClass: '', + draggable: true, + hide: null, + height: 'auto', + maxHeight: false, + maxWidth: false, + minHeight: 150, + minWidth: 150, + modal: false, + position: 'center', + resizable: true, + show: null, + stack: true, + title: '', + width: 300, + zIndex: 1000 + }, + + getter: 'isOpen', + + uuid: 0, + maxZ: 0, + + getTitleId: function($el) { + return 'ui-dialog-title-' + ($el.attr('id') || ++this.uuid); + }, + + overlay: function(dialog) { + this.$el = $.ui.dialog.overlay.create(dialog); + } +}); + +$.extend($.ui.dialog.overlay, { + instances: [], + maxZ: 0, + events: $.map('focus,mousedown,mouseup,keydown,keypress,click'.split(','), + function(event) { return event + '.dialog-overlay'; }).join(' '), + create: function(dialog) { + if (this.instances.length === 0) { + // prevent use of anchors and inputs + // we use a setTimeout in case the overlay is created from an + // event that we're going to be cancelling (see #2804) + setTimeout(function() { + $(document).bind($.ui.dialog.overlay.events, function(event) { + var dialogZ = $(event.target).parents('.ui-dialog').css('zIndex') || 0; + return (dialogZ > $.ui.dialog.overlay.maxZ); + }); + }, 1); + + // allow closing by pressing the escape key + $(document).bind('keydown.dialog-overlay', function(event) { + (dialog.options.closeOnEscape && event.keyCode + && event.keyCode == $.ui.keyCode.ESCAPE && dialog.close(event)); + }); + + // handle window resize + $(window).bind('resize.dialog-overlay', $.ui.dialog.overlay.resize); + } + + var $el = $('
    ').appendTo(document.body) + .addClass('ui-widget-overlay').css({ + width: this.width(), + height: this.height() + }); + + (dialog.options.bgiframe && $.fn.bgiframe && $el.bgiframe()); + + this.instances.push($el); + return $el; + }, + + destroy: function($el) { + this.instances.splice($.inArray(this.instances, $el), 1); + + if (this.instances.length === 0) { + $([document, window]).unbind('.dialog-overlay'); + } + + $el.remove(); + }, + + height: function() { + // handle IE 6 + if ($.browser.msie && $.browser.version < 7) { + var scrollHeight = Math.max( + document.documentElement.scrollHeight, + document.body.scrollHeight + ); + var offsetHeight = Math.max( + document.documentElement.offsetHeight, + document.body.offsetHeight + ); + + if (scrollHeight < offsetHeight) { + return $(window).height() + 'px'; + } else { + return scrollHeight + 'px'; + } + // handle "good" browsers + } else { + return $(document).height() + 'px'; + } + }, + + width: function() { + // handle IE 6 + if ($.browser.msie && $.browser.version < 7) { + var scrollWidth = Math.max( + document.documentElement.scrollWidth, + document.body.scrollWidth + ); + var offsetWidth = Math.max( + document.documentElement.offsetWidth, + document.body.offsetWidth + ); + + if (scrollWidth < offsetWidth) { + return $(window).width() + 'px'; + } else { + return scrollWidth + 'px'; + } + // handle "good" browsers + } else { + return $(document).width() + 'px'; + } + }, + + resize: function() { + /* If the dialog is draggable and the user drags it past the + * right edge of the window, the document becomes wider so we + * need to stretch the overlay. If the user then drags the + * dialog back to the left, the document will become narrower, + * so we need to shrink the overlay to the appropriate size. + * This is handled by shrinking the overlay before setting it + * to the full document size. + */ + var $overlays = $([]); + $.each($.ui.dialog.overlay.instances, function() { + $overlays = $overlays.add(this); + }); + + $overlays.css({ + width: 0, + height: 0 + }).css({ + width: $.ui.dialog.overlay.width(), + height: $.ui.dialog.overlay.height() + }); + } +}); + +$.extend($.ui.dialog.overlay.prototype, { + destroy: function() { + $.ui.dialog.overlay.destroy(this.$el); + } +}); + +})(jQuery); +/* + * jQuery UI Slider 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Slider + * + * Depends: + * ui.core.js + */ + +(function($) { + +$.widget("ui.slider", $.extend({}, $.ui.mouse, { + + _init: function() { + + var self = this, o = this.options; + this._keySliding = false; + this._handleIndex = null; + this._detectOrientation(); + this._mouseInit(); + + this.element + .addClass("ui-slider" + + " ui-slider-" + this.orientation + + " ui-widget" + + " ui-widget-content" + + " ui-corner-all"); + + this.range = $([]); + + if (o.range) { + + if (o.range === true) { + this.range = $('
    '); + if (!o.values) o.values = [this._valueMin(), this._valueMin()]; + if (o.values.length && o.values.length != 2) { + o.values = [o.values[0], o.values[0]]; + } + } else { + this.range = $('
    '); + } + + this.range + .appendTo(this.element) + .addClass("ui-slider-range"); + + if (o.range == "min" || o.range == "max") { + this.range.addClass("ui-slider-range-" + o.range); + } + + // note: this isn't the most fittingly semantic framework class for this element, + // but worked best visually with a variety of themes + this.range.addClass("ui-widget-header"); + + } + + if ($(".ui-slider-handle", this.element).length == 0) + $('
    ') + .appendTo(this.element) + .addClass("ui-slider-handle"); + + if (o.values && o.values.length) { + while ($(".ui-slider-handle", this.element).length < o.values.length) + $('') + .appendTo(this.element) + .addClass("ui-slider-handle"); + } + + this.handles = $(".ui-slider-handle", this.element) + .addClass("ui-state-default" + + " ui-corner-all"); + + this.handle = this.handles.eq(0); + + this.handles.add(this.range).filter("a") + .click(function(event) { event.preventDefault(); }) + .hover(function() { $(this).addClass('ui-state-hover'); }, function() { $(this).removeClass('ui-state-hover'); }) + .focus(function() { $(".ui-slider .ui-state-focus").removeClass('ui-state-focus'); $(this).addClass('ui-state-focus'); }) + .blur(function() { $(this).removeClass('ui-state-focus'); }); + + this.handles.each(function(i) { + $(this).data("index.ui-slider-handle", i); + }); + + this.handles.keydown(function(event) { + + var ret = true; + + var index = $(this).data("index.ui-slider-handle"); + + if (self.options.disabled) + return; + + switch (event.keyCode) { + case $.ui.keyCode.HOME: + case $.ui.keyCode.END: + case $.ui.keyCode.UP: + case $.ui.keyCode.RIGHT: + case $.ui.keyCode.DOWN: + case $.ui.keyCode.LEFT: + ret = false; + if (!self._keySliding) { + self._keySliding = true; + $(this).addClass("ui-state-active"); + self._start(event, index); + } + break; + } + + var curVal, newVal, step = self._step(); + if (self.options.values && self.options.values.length) { + curVal = newVal = self.values(index); + } else { + curVal = newVal = self.value(); + } + + switch (event.keyCode) { + case $.ui.keyCode.HOME: + newVal = self._valueMin(); + break; + case $.ui.keyCode.END: + newVal = self._valueMax(); + break; + case $.ui.keyCode.UP: + case $.ui.keyCode.RIGHT: + if(curVal == self._valueMax()) return; + newVal = curVal + step; + break; + case $.ui.keyCode.DOWN: + case $.ui.keyCode.LEFT: + if(curVal == self._valueMin()) return; + newVal = curVal - step; + break; + } + + self._slide(event, index, newVal); + + return ret; + + }).keyup(function(event) { + + var index = $(this).data("index.ui-slider-handle"); + + if (self._keySliding) { + self._stop(event, index); + self._change(event, index); + self._keySliding = false; + $(this).removeClass("ui-state-active"); + } + + }); + + this._refreshValue(); + + }, + + destroy: function() { + + this.handles.remove(); + this.range.remove(); + + this.element + .removeClass("ui-slider" + + " ui-slider-horizontal" + + " ui-slider-vertical" + + " ui-slider-disabled" + + " ui-widget" + + " ui-widget-content" + + " ui-corner-all") + .removeData("slider") + .unbind(".slider"); + + this._mouseDestroy(); + + }, + + _mouseCapture: function(event) { + + var o = this.options; + + if (o.disabled) + return false; + + this.elementSize = { + width: this.element.outerWidth(), + height: this.element.outerHeight() + }; + this.elementOffset = this.element.offset(); + + var position = { x: event.pageX, y: event.pageY }; + var normValue = this._normValueFromMouse(position); + + var distance = this._valueMax() - this._valueMin() + 1, closestHandle; + var self = this, index; + this.handles.each(function(i) { + var thisDistance = Math.abs(normValue - self.values(i)); + if (distance > thisDistance) { + distance = thisDistance; + closestHandle = $(this); + index = i; + } + }); + + // workaround for bug #3736 (if both handles of a range are at 0, + // the first is always used as the one with least distance, + // and moving it is obviously prevented by preventing negative ranges) + if(o.range == true && this.values(1) == o.min) { + closestHandle = $(this.handles[++index]); + } + + this._start(event, index); + + self._handleIndex = index; + + closestHandle + .addClass("ui-state-active") + .focus(); + + var offset = closestHandle.offset(); + var mouseOverHandle = !$(event.target).parents().andSelf().is('.ui-slider-handle'); + this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : { + left: event.pageX - offset.left - (closestHandle.width() / 2), + top: event.pageY - offset.top + - (closestHandle.height() / 2) + - (parseInt(closestHandle.css('borderTopWidth'),10) || 0) + - (parseInt(closestHandle.css('borderBottomWidth'),10) || 0) + + (parseInt(closestHandle.css('marginTop'),10) || 0) + }; + + normValue = this._normValueFromMouse(position); + this._slide(event, index, normValue); + return true; + + }, + + _mouseStart: function(event) { + return true; + }, + + _mouseDrag: function(event) { + + var position = { x: event.pageX, y: event.pageY }; + var normValue = this._normValueFromMouse(position); + + this._slide(event, this._handleIndex, normValue); + + return false; + + }, + + _mouseStop: function(event) { + + this.handles.removeClass("ui-state-active"); + this._stop(event, this._handleIndex); + this._change(event, this._handleIndex); + this._handleIndex = null; + this._clickOffset = null; + + return false; + + }, + + _detectOrientation: function() { + this.orientation = this.options.orientation == 'vertical' ? 'vertical' : 'horizontal'; + }, + + _normValueFromMouse: function(position) { + + var pixelTotal, pixelMouse; + if ('horizontal' == this.orientation) { + pixelTotal = this.elementSize.width; + pixelMouse = position.x - this.elementOffset.left - (this._clickOffset ? this._clickOffset.left : 0); + } else { + pixelTotal = this.elementSize.height; + pixelMouse = position.y - this.elementOffset.top - (this._clickOffset ? this._clickOffset.top : 0); + } + + var percentMouse = (pixelMouse / pixelTotal); + if (percentMouse > 1) percentMouse = 1; + if (percentMouse < 0) percentMouse = 0; + if ('vertical' == this.orientation) + percentMouse = 1 - percentMouse; + + var valueTotal = this._valueMax() - this._valueMin(), + valueMouse = percentMouse * valueTotal, + valueMouseModStep = valueMouse % this.options.step, + normValue = this._valueMin() + valueMouse - valueMouseModStep; + + if (valueMouseModStep > (this.options.step / 2)) + normValue += this.options.step; + + // Since JavaScript has problems with large floats, round + // the final value to 5 digits after the decimal point (see #4124) + return parseFloat(normValue.toFixed(5)); + + }, + + _start: function(event, index) { + var uiHash = { + handle: this.handles[index], + value: this.value() + }; + if (this.options.values && this.options.values.length) { + uiHash.value = this.values(index) + uiHash.values = this.values() + } + this._trigger("start", event, uiHash); + }, + + _slide: function(event, index, newVal) { + + var handle = this.handles[index]; + + if (this.options.values && this.options.values.length) { + + var otherVal = this.values(index ? 0 : 1); + + if ((index == 0 && newVal >= otherVal) || (index == 1 && newVal <= otherVal)) + newVal = otherVal; + + if (newVal != this.values(index)) { + var newValues = this.values(); + newValues[index] = newVal; + // A slide can be canceled by returning false from the slide callback + var allowed = this._trigger("slide", event, { + handle: this.handles[index], + value: newVal, + values: newValues + }); + var otherVal = this.values(index ? 0 : 1); + if (allowed !== false) { + this.values(index, newVal, ( event.type == 'mousedown' && this.options.animate ), true); + } + } + + } else { + + if (newVal != this.value()) { + // A slide can be canceled by returning false from the slide callback + var allowed = this._trigger("slide", event, { + handle: this.handles[index], + value: newVal + }); + if (allowed !== false) { + this._setData('value', newVal, ( event.type == 'mousedown' && this.options.animate )); + } + + } + + } + + }, + + _stop: function(event, index) { + var uiHash = { + handle: this.handles[index], + value: this.value() + }; + if (this.options.values && this.options.values.length) { + uiHash.value = this.values(index) + uiHash.values = this.values() + } + this._trigger("stop", event, uiHash); + }, + + _change: function(event, index) { + var uiHash = { + handle: this.handles[index], + value: this.value() + }; + if (this.options.values && this.options.values.length) { + uiHash.value = this.values(index) + uiHash.values = this.values() + } + this._trigger("change", event, uiHash); + }, + + value: function(newValue) { + + if (arguments.length) { + this._setData("value", newValue); + this._change(null, 0); + } + + return this._value(); + + }, + + values: function(index, newValue, animated, noPropagation) { + + if (arguments.length > 1) { + this.options.values[index] = newValue; + this._refreshValue(animated); + if(!noPropagation) this._change(null, index); + } + + if (arguments.length) { + if (this.options.values && this.options.values.length) { + return this._values(index); + } else { + return this.value(); + } + } else { + return this._values(); + } + + }, + + _setData: function(key, value, animated) { + + $.widget.prototype._setData.apply(this, arguments); + + switch (key) { + case 'orientation': + + this._detectOrientation(); + + this.element + .removeClass("ui-slider-horizontal ui-slider-vertical") + .addClass("ui-slider-" + this.orientation); + this._refreshValue(animated); + break; + case 'value': + this._refreshValue(animated); + break; + } + + }, + + _step: function() { + var step = this.options.step; + return step; + }, + + _value: function() { + + var val = this.options.value; + if (val < this._valueMin()) val = this._valueMin(); + if (val > this._valueMax()) val = this._valueMax(); + + return val; + + }, + + _values: function(index) { + + if (arguments.length) { + var val = this.options.values[index]; + if (val < this._valueMin()) val = this._valueMin(); + if (val > this._valueMax()) val = this._valueMax(); + + return val; + } else { + return this.options.values; + } + + }, + + _valueMin: function() { + var valueMin = this.options.min; + return valueMin; + }, + + _valueMax: function() { + var valueMax = this.options.max; + return valueMax; + }, + + _refreshValue: function(animate) { + + var oRange = this.options.range, o = this.options, self = this; + + if (this.options.values && this.options.values.length) { + var vp0, vp1; + this.handles.each(function(i, j) { + var valPercent = (self.values(i) - self._valueMin()) / (self._valueMax() - self._valueMin()) * 100; + var _set = {}; _set[self.orientation == 'horizontal' ? 'left' : 'bottom'] = valPercent + '%'; + $(this).stop(1,1)[animate ? 'animate' : 'css'](_set, o.animate); + if (self.options.range === true) { + if (self.orientation == 'horizontal') { + (i == 0) && self.range.stop(1,1)[animate ? 'animate' : 'css']({ left: valPercent + '%' }, o.animate); + (i == 1) && self.range[animate ? 'animate' : 'css']({ width: (valPercent - lastValPercent) + '%' }, { queue: false, duration: o.animate }); + } else { + (i == 0) && self.range.stop(1,1)[animate ? 'animate' : 'css']({ bottom: (valPercent) + '%' }, o.animate); + (i == 1) && self.range[animate ? 'animate' : 'css']({ height: (valPercent - lastValPercent) + '%' }, { queue: false, duration: o.animate }); + } + } + lastValPercent = valPercent; + }); + } else { + var value = this.value(), + valueMin = this._valueMin(), + valueMax = this._valueMax(), + valPercent = valueMax != valueMin + ? (value - valueMin) / (valueMax - valueMin) * 100 + : 0; + var _set = {}; _set[self.orientation == 'horizontal' ? 'left' : 'bottom'] = valPercent + '%'; + this.handle.stop(1,1)[animate ? 'animate' : 'css'](_set, o.animate); + + (oRange == "min") && (this.orientation == "horizontal") && this.range.stop(1,1)[animate ? 'animate' : 'css']({ width: valPercent + '%' }, o.animate); + (oRange == "max") && (this.orientation == "horizontal") && this.range[animate ? 'animate' : 'css']({ width: (100 - valPercent) + '%' }, { queue: false, duration: o.animate }); + (oRange == "min") && (this.orientation == "vertical") && this.range.stop(1,1)[animate ? 'animate' : 'css']({ height: valPercent + '%' }, o.animate); + (oRange == "max") && (this.orientation == "vertical") && this.range[animate ? 'animate' : 'css']({ height: (100 - valPercent) + '%' }, { queue: false, duration: o.animate }); + } + + } + +})); + +$.extend($.ui.slider, { + getter: "value values", + version: "1.7.1", + eventPrefix: "slide", + defaults: { + animate: false, + delay: 0, + distance: 0, + max: 100, + min: 0, + orientation: 'horizontal', + range: false, + step: 1, + value: 0, + values: null + } +}); + +})(jQuery); +/* + * jQuery UI Tabs 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Tabs + * + * Depends: + * ui.core.js + */ +(function($) { + +$.widget("ui.tabs", { + + _init: function() { + if (this.options.deselectable !== undefined) { + this.options.collapsible = this.options.deselectable; + } + this._tabify(true); + }, + + _setData: function(key, value) { + if (key == 'selected') { + if (this.options.collapsible && value == this.options.selected) { + return; + } + this.select(value); + } + else { + this.options[key] = value; + if (key == 'deselectable') { + this.options.collapsible = value; + } + this._tabify(); + } + }, + + _tabId: function(a) { + return a.title && a.title.replace(/\s/g, '_').replace(/[^A-Za-z0-9\-_:\.]/g, '') || + this.options.idPrefix + $.data(a); + }, + + _sanitizeSelector: function(hash) { + return hash.replace(/:/g, '\\:'); // we need this because an id may contain a ":" + }, + + _cookie: function() { + var cookie = this.cookie || (this.cookie = this.options.cookie.name || 'ui-tabs-' + $.data(this.list[0])); + return $.cookie.apply(null, [cookie].concat($.makeArray(arguments))); + }, + + _ui: function(tab, panel) { + return { + tab: tab, + panel: panel, + index: this.anchors.index(tab) + }; + }, + + _cleanup: function() { + // restore all former loading tabs labels + this.lis.filter('.ui-state-processing').removeClass('ui-state-processing') + .find('span:data(label.tabs)') + .each(function() { + var el = $(this); + el.html(el.data('label.tabs')).removeData('label.tabs'); + }); + }, + + _tabify: function(init) { + + this.list = this.element.children('ul:first'); + this.lis = $('li:has(a[href])', this.list); + this.anchors = this.lis.map(function() { return $('a', this)[0]; }); + this.panels = $([]); + + var self = this, o = this.options; + + var fragmentId = /^#.+/; // Safari 2 reports '#' for an empty hash + this.anchors.each(function(i, a) { + var href = $(a).attr('href'); + + // For dynamically created HTML that contains a hash as href IE < 8 expands + // such href to the full page url with hash and then misinterprets tab as ajax. + // Same consideration applies for an added tab with a fragment identifier + // since a[href=#fragment-identifier] does unexpectedly not match. + // Thus normalize href attribute... + var hrefBase = href.split('#')[0], baseEl; + if (hrefBase && (hrefBase === location.toString().split('#')[0] || + (baseEl = $('base')[0]) && hrefBase === baseEl.href)) { + href = a.hash; + a.href = href; + } + + // inline tab + if (fragmentId.test(href)) { + self.panels = self.panels.add(self._sanitizeSelector(href)); + } + + // remote tab + else if (href != '#') { // prevent loading the page itself if href is just "#" + $.data(a, 'href.tabs', href); // required for restore on destroy + + // TODO until #3808 is fixed strip fragment identifier from url + // (IE fails to load from such url) + $.data(a, 'load.tabs', href.replace(/#.*$/, '')); // mutable data + + var id = self._tabId(a); + a.href = '#' + id; + var $panel = $('#' + id); + if (!$panel.length) { + $panel = $(o.panelTemplate).attr('id', id).addClass('ui-tabs-panel ui-widget-content ui-corner-bottom') + .insertAfter(self.panels[i - 1] || self.list); + $panel.data('destroy.tabs', true); + } + self.panels = self.panels.add($panel); + } + + // invalid tab href + else { + o.disabled.push(i); + } + }); + + // initialization from scratch + if (init) { + + // attach necessary classes for styling + this.element.addClass('ui-tabs ui-widget ui-widget-content ui-corner-all'); + this.list.addClass('ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all'); + this.lis.addClass('ui-state-default ui-corner-top'); + this.panels.addClass('ui-tabs-panel ui-widget-content ui-corner-bottom'); + + // Selected tab + // use "selected" option or try to retrieve: + // 1. from fragment identifier in url + // 2. from cookie + // 3. from selected class attribute on
  3. + if (o.selected === undefined) { + if (location.hash) { + this.anchors.each(function(i, a) { + if (a.hash == location.hash) { + o.selected = i; + return false; // break + } + }); + } + if (typeof o.selected != 'number' && o.cookie) { + o.selected = parseInt(self._cookie(), 10); + } + if (typeof o.selected != 'number' && this.lis.filter('.ui-tabs-selected').length) { + o.selected = this.lis.index(this.lis.filter('.ui-tabs-selected')); + } + o.selected = o.selected || 0; + } + else if (o.selected === null) { // usage of null is deprecated, TODO remove in next release + o.selected = -1; + } + + // sanity check - default to first tab... + o.selected = ((o.selected >= 0 && this.anchors[o.selected]) || o.selected < 0) ? o.selected : 0; + + // Take disabling tabs via class attribute from HTML + // into account and update option properly. + // A selected tab cannot become disabled. + o.disabled = $.unique(o.disabled.concat( + $.map(this.lis.filter('.ui-state-disabled'), + function(n, i) { return self.lis.index(n); } ) + )).sort(); + + if ($.inArray(o.selected, o.disabled) != -1) { + o.disabled.splice($.inArray(o.selected, o.disabled), 1); + } + + // highlight selected tab + this.panels.addClass('ui-tabs-hide'); + this.lis.removeClass('ui-tabs-selected ui-state-active'); + if (o.selected >= 0 && this.anchors.length) { // check for length avoids error when initializing empty list + this.panels.eq(o.selected).removeClass('ui-tabs-hide'); + this.lis.eq(o.selected).addClass('ui-tabs-selected ui-state-active'); + + // seems to be expected behavior that the show callback is fired + self.element.queue("tabs", function() { + self._trigger('show', null, self._ui(self.anchors[o.selected], self.panels[o.selected])); + }); + + this.load(o.selected); + } + + // clean up to avoid memory leaks in certain versions of IE 6 + $(window).bind('unload', function() { + self.lis.add(self.anchors).unbind('.tabs'); + self.lis = self.anchors = self.panels = null; + }); + + } + // update selected after add/remove + else { + o.selected = this.lis.index(this.lis.filter('.ui-tabs-selected')); + } + + // update collapsible + this.element[o.collapsible ? 'addClass' : 'removeClass']('ui-tabs-collapsible'); + + // set or update cookie after init and add/remove respectively + if (o.cookie) { + this._cookie(o.selected, o.cookie); + } + + // disable tabs + for (var i = 0, li; (li = this.lis[i]); i++) { + $(li)[$.inArray(i, o.disabled) != -1 && + !$(li).hasClass('ui-tabs-selected') ? 'addClass' : 'removeClass']('ui-state-disabled'); + } + + // reset cache if switching from cached to not cached + if (o.cache === false) { + this.anchors.removeData('cache.tabs'); + } + + // remove all handlers before, tabify may run on existing tabs after add or option change + this.lis.add(this.anchors).unbind('.tabs'); + + if (o.event != 'mouseover') { + var addState = function(state, el) { + if (el.is(':not(.ui-state-disabled)')) { + el.addClass('ui-state-' + state); + } + }; + var removeState = function(state, el) { + el.removeClass('ui-state-' + state); + }; + this.lis.bind('mouseover.tabs', function() { + addState('hover', $(this)); + }); + this.lis.bind('mouseout.tabs', function() { + removeState('hover', $(this)); + }); + this.anchors.bind('focus.tabs', function() { + addState('focus', $(this).closest('li')); + }); + this.anchors.bind('blur.tabs', function() { + removeState('focus', $(this).closest('li')); + }); + } + + // set up animations + var hideFx, showFx; + if (o.fx) { + if ($.isArray(o.fx)) { + hideFx = o.fx[0]; + showFx = o.fx[1]; + } + else { + hideFx = showFx = o.fx; + } + } + + // Reset certain styles left over from animation + // and prevent IE's ClearType bug... + function resetStyle($el, fx) { + $el.css({ display: '' }); + if ($.browser.msie && fx.opacity) { + $el[0].style.removeAttribute('filter'); + } + } + + // Show a tab... + var showTab = showFx ? + function(clicked, $show) { + $(clicked).closest('li').removeClass('ui-state-default').addClass('ui-tabs-selected ui-state-active'); + $show.hide().removeClass('ui-tabs-hide') // avoid flicker that way + .animate(showFx, showFx.duration || 'normal', function() { + resetStyle($show, showFx); + self._trigger('show', null, self._ui(clicked, $show[0])); + }); + } : + function(clicked, $show) { + $(clicked).closest('li').removeClass('ui-state-default').addClass('ui-tabs-selected ui-state-active'); + $show.removeClass('ui-tabs-hide'); + self._trigger('show', null, self._ui(clicked, $show[0])); + }; + + // Hide a tab, $show is optional... + var hideTab = hideFx ? + function(clicked, $hide) { + $hide.animate(hideFx, hideFx.duration || 'normal', function() { + self.lis.removeClass('ui-tabs-selected ui-state-active').addClass('ui-state-default'); + $hide.addClass('ui-tabs-hide'); + resetStyle($hide, hideFx); + self.element.dequeue("tabs"); + }); + } : + function(clicked, $hide, $show) { + self.lis.removeClass('ui-tabs-selected ui-state-active').addClass('ui-state-default'); + $hide.addClass('ui-tabs-hide'); + self.element.dequeue("tabs"); + }; + + // attach tab event handler, unbind to avoid duplicates from former tabifying... + this.anchors.bind(o.event + '.tabs', function() { + var el = this, $li = $(this).closest('li'), $hide = self.panels.filter(':not(.ui-tabs-hide)'), + $show = $(self._sanitizeSelector(this.hash)); + + // If tab is already selected and not collapsible or tab disabled or + // or is already loading or click callback returns false stop here. + // Check if click handler returns false last so that it is not executed + // for a disabled or loading tab! + if (($li.hasClass('ui-tabs-selected') && !o.collapsible) || + $li.hasClass('ui-state-disabled') || + $li.hasClass('ui-state-processing') || + self._trigger('select', null, self._ui(this, $show[0])) === false) { + this.blur(); + return false; + } + + o.selected = self.anchors.index(this); + + self.abort(); + + // if tab may be closed + if (o.collapsible) { + if ($li.hasClass('ui-tabs-selected')) { + o.selected = -1; + + if (o.cookie) { + self._cookie(o.selected, o.cookie); + } + + self.element.queue("tabs", function() { + hideTab(el, $hide); + }).dequeue("tabs"); + + this.blur(); + return false; + } + else if (!$hide.length) { + if (o.cookie) { + self._cookie(o.selected, o.cookie); + } + + self.element.queue("tabs", function() { + showTab(el, $show); + }); + + self.load(self.anchors.index(this)); // TODO make passing in node possible, see also http://dev.jqueryui.com/ticket/3171 + + this.blur(); + return false; + } + } + + if (o.cookie) { + self._cookie(o.selected, o.cookie); + } + + // show new tab + if ($show.length) { + if ($hide.length) { + self.element.queue("tabs", function() { + hideTab(el, $hide); + }); + } + self.element.queue("tabs", function() { + showTab(el, $show); + }); + + self.load(self.anchors.index(this)); + } + else { + throw 'jQuery UI Tabs: Mismatching fragment identifier.'; + } + + // Prevent IE from keeping other link focussed when using the back button + // and remove dotted border from clicked link. This is controlled via CSS + // in modern browsers; blur() removes focus from address bar in Firefox + // which can become a usability and annoying problem with tabs('rotate'). + if ($.browser.msie) { + this.blur(); + } + + }); + + // disable click in any case + this.anchors.bind('click.tabs', function(){return false;}); + + }, + + destroy: function() { + var o = this.options; + + this.abort(); + + this.element.unbind('.tabs') + .removeClass('ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible') + .removeData('tabs'); + + this.list.removeClass('ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all'); + + this.anchors.each(function() { + var href = $.data(this, 'href.tabs'); + if (href) { + this.href = href; + } + var $this = $(this).unbind('.tabs'); + $.each(['href', 'load', 'cache'], function(i, prefix) { + $this.removeData(prefix + '.tabs'); + }); + }); + + this.lis.unbind('.tabs').add(this.panels).each(function() { + if ($.data(this, 'destroy.tabs')) { + $(this).remove(); + } + else { + $(this).removeClass([ + 'ui-state-default', + 'ui-corner-top', + 'ui-tabs-selected', + 'ui-state-active', + 'ui-state-hover', + 'ui-state-focus', + 'ui-state-disabled', + 'ui-tabs-panel', + 'ui-widget-content', + 'ui-corner-bottom', + 'ui-tabs-hide' + ].join(' ')); + } + }); + + if (o.cookie) { + this._cookie(null, o.cookie); + } + }, + + add: function(url, label, index) { + if (index === undefined) { + index = this.anchors.length; // append by default + } + + var self = this, o = this.options, + $li = $(o.tabTemplate.replace(/#\{href\}/g, url).replace(/#\{label\}/g, label)), + id = !url.indexOf('#') ? url.replace('#', '') : this._tabId($('a', $li)[0]); + + $li.addClass('ui-state-default ui-corner-top').data('destroy.tabs', true); + + // try to find an existing element before creating a new one + var $panel = $('#' + id); + if (!$panel.length) { + $panel = $(o.panelTemplate).attr('id', id).data('destroy.tabs', true); + } + $panel.addClass('ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide'); + + if (index >= this.lis.length) { + $li.appendTo(this.list); + $panel.appendTo(this.list[0].parentNode); + } + else { + $li.insertBefore(this.lis[index]); + $panel.insertBefore(this.panels[index]); + } + + o.disabled = $.map(o.disabled, + function(n, i) { return n >= index ? ++n : n; }); + + this._tabify(); + + if (this.anchors.length == 1) { // after tabify + $li.addClass('ui-tabs-selected ui-state-active'); + $panel.removeClass('ui-tabs-hide'); + this.element.queue("tabs", function() { + self._trigger('show', null, self._ui(self.anchors[0], self.panels[0])); + }); + + this.load(0); + } + + // callback + this._trigger('add', null, this._ui(this.anchors[index], this.panels[index])); + }, + + remove: function(index) { + var o = this.options, $li = this.lis.eq(index).remove(), + $panel = this.panels.eq(index).remove(); + + // If selected tab was removed focus tab to the right or + // in case the last tab was removed the tab to the left. + if ($li.hasClass('ui-tabs-selected') && this.anchors.length > 1) { + this.select(index + (index + 1 < this.anchors.length ? 1 : -1)); + } + + o.disabled = $.map($.grep(o.disabled, function(n, i) { return n != index; }), + function(n, i) { return n >= index ? --n : n; }); + + this._tabify(); + + // callback + this._trigger('remove', null, this._ui($li.find('a')[0], $panel[0])); + }, + + enable: function(index) { + var o = this.options; + if ($.inArray(index, o.disabled) == -1) { + return; + } + + this.lis.eq(index).removeClass('ui-state-disabled'); + o.disabled = $.grep(o.disabled, function(n, i) { return n != index; }); + + // callback + this._trigger('enable', null, this._ui(this.anchors[index], this.panels[index])); + }, + + disable: function(index) { + var self = this, o = this.options; + if (index != o.selected) { // cannot disable already selected tab + this.lis.eq(index).addClass('ui-state-disabled'); + + o.disabled.push(index); + o.disabled.sort(); + + // callback + this._trigger('disable', null, this._ui(this.anchors[index], this.panels[index])); + } + }, + + select: function(index) { + if (typeof index == 'string') { + index = this.anchors.index(this.anchors.filter('[href$=' + index + ']')); + } + else if (index === null) { // usage of null is deprecated, TODO remove in next release + index = -1; + } + if (index == -1 && this.options.collapsible) { + index = this.options.selected; + } + + this.anchors.eq(index).trigger(this.options.event + '.tabs'); + }, + + load: function(index) { + var self = this, o = this.options, a = this.anchors.eq(index)[0], url = $.data(a, 'load.tabs'); + + this.abort(); + + // not remote or from cache + if (!url || this.element.queue("tabs").length !== 0 && $.data(a, 'cache.tabs')) { + this.element.dequeue("tabs"); + return; + } + + // load remote from here on + this.lis.eq(index).addClass('ui-state-processing'); + + if (o.spinner) { + var span = $('span', a); + span.data('label.tabs', span.html()).html(o.spinner); + } + + this.xhr = $.ajax($.extend({}, o.ajaxOptions, { + url: url, + success: function(r, s) { + $(self._sanitizeSelector(a.hash)).html(r); + + // take care of tab labels + self._cleanup(); + + if (o.cache) { + $.data(a, 'cache.tabs', true); // if loaded once do not load them again + } + + // callbacks + self._trigger('load', null, self._ui(self.anchors[index], self.panels[index])); + try { + o.ajaxOptions.success(r, s); + } + catch (e) {} + + // last, so that load event is fired before show... + self.element.dequeue("tabs"); + } + })); + }, + + abort: function() { + // stop possibly running animations + this.element.queue([]); + this.panels.stop(false, true); + + // terminate pending requests from other tabs + if (this.xhr) { + this.xhr.abort(); + delete this.xhr; + } + + // take care of tab labels + this._cleanup(); + + }, + + url: function(index, url) { + this.anchors.eq(index).removeData('cache.tabs').data('load.tabs', url); + }, + + length: function() { + return this.anchors.length; + } + +}); + +$.extend($.ui.tabs, { + version: '1.7.1', + getter: 'length', + defaults: { + ajaxOptions: null, + cache: false, + cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true } + collapsible: false, + disabled: [], + event: 'click', + fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 } + idPrefix: 'ui-tabs-', + panelTemplate: '
    ', + spinner: 'Loading…', + tabTemplate: '
  4. #{label}
  5. ' + } +}); + +/* + * Tabs Extensions + */ + +/* + * Rotate + */ +$.extend($.ui.tabs.prototype, { + rotation: null, + rotate: function(ms, continuing) { + + var self = this, o = this.options; + + var rotate = self._rotate || (self._rotate = function(e) { + clearTimeout(self.rotation); + self.rotation = setTimeout(function() { + var t = o.selected; + self.select( ++t < self.anchors.length ? t : 0 ); + }, ms); + + if (e) { + e.stopPropagation(); + } + }); + + var stop = self._unrotate || (self._unrotate = !continuing ? + function(e) { + if (e.clientX) { // in case of a true click + self.rotate(null); + } + } : + function(e) { + t = o.selected; + rotate(); + }); + + // start rotation + if (ms) { + this.element.bind('tabsshow', rotate); + this.anchors.bind(o.event + '.tabs', stop); + rotate(); + } + // stop rotation + else { + clearTimeout(self.rotation); + this.element.unbind('tabsshow', rotate); + this.anchors.unbind(o.event + '.tabs', stop); + delete this._rotate; + delete this._unrotate; + } + } +}); + +})(jQuery); +/* + * jQuery UI Datepicker 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Datepicker + * + * Depends: + * ui.core.js + */ + +(function($) { // hide the namespace + +$.extend($.ui, { datepicker: { version: "1.7.1" } }); + +var PROP_NAME = 'datepicker'; + +/* Date picker manager. + Use the singleton instance of this class, $.datepicker, to interact with the date picker. + Settings for (groups of) date pickers are maintained in an instance object, + allowing multiple different settings on the same page. */ + +function Datepicker() { + this.debug = false; // Change this to true to start debugging + this._curInst = null; // The current instance in use + this._keyEvent = false; // If the last event was a key event + this._disabledInputs = []; // List of date picker inputs that have been disabled + this._datepickerShowing = false; // True if the popup picker is showing , false if not + this._inDialog = false; // True if showing within a "dialog", false if not + this._mainDivId = 'ui-datepicker-div'; // The ID of the main datepicker division + this._inlineClass = 'ui-datepicker-inline'; // The name of the inline marker class + this._appendClass = 'ui-datepicker-append'; // The name of the append marker class + this._triggerClass = 'ui-datepicker-trigger'; // The name of the trigger marker class + this._dialogClass = 'ui-datepicker-dialog'; // The name of the dialog marker class + this._disableClass = 'ui-datepicker-disabled'; // The name of the disabled covering marker class + this._unselectableClass = 'ui-datepicker-unselectable'; // The name of the unselectable cell marker class + this._currentClass = 'ui-datepicker-current-day'; // The name of the current day marker class + this._dayOverClass = 'ui-datepicker-days-cell-over'; // The name of the day hover marker class + this.regional = []; // Available regional settings, indexed by language code + this.regional[''] = { // Default regional settings + closeText: 'Done', // Display text for close link + prevText: 'Prev', // Display text for previous month link + nextText: 'Next', // Display text for next month link + currentText: 'Today', // Display text for current month link + monthNames: ['January','February','March','April','May','June', + 'July','August','September','October','November','December'], // Names of months for drop-down and formatting + monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], // For formatting + dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], // For formatting + dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], // For formatting + dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'], // Column headings for days starting at Sunday + dateFormat: 'mm/dd/yy', // See format options on parseDate + firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ... + isRTL: false // True if right-to-left language, false if left-to-right + }; + this._defaults = { // Global defaults for all the date picker instances + showOn: 'focus', // 'focus' for popup on focus, + // 'button' for trigger button, or 'both' for either + showAnim: 'show', // Name of jQuery animation for popup + showOptions: {}, // Options for enhanced animations + defaultDate: null, // Used when field is blank: actual date, + // +/-number for offset from today, null for today + appendText: '', // Display text following the input box, e.g. showing the format + buttonText: '...', // Text for trigger button + buttonImage: '', // URL for trigger button image + buttonImageOnly: false, // True if the image appears alone, false if it appears on a button + hideIfNoPrevNext: false, // True to hide next/previous month links + // if not applicable, false to just disable them + navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links + gotoCurrent: false, // True if today link goes back to current selection instead + changeMonth: false, // True if month can be selected directly, false if only prev/next + changeYear: false, // True if year can be selected directly, false if only prev/next + showMonthAfterYear: false, // True if the year select precedes month, false for month then year + yearRange: '-10:+10', // Range of years to display in drop-down, + // either relative to current year (-nn:+nn) or absolute (nnnn:nnnn) + showOtherMonths: false, // True to show dates in other months, false to leave blank + calculateWeek: this.iso8601Week, // How to calculate the week of the year, + // takes a Date and returns the number of the week for it + shortYearCutoff: '+10', // Short year values < this are in the current century, + // > this are in the previous century, + // string value starting with '+' for current year + value + minDate: null, // The earliest selectable date, or null for no limit + maxDate: null, // The latest selectable date, or null for no limit + duration: 'normal', // Duration of display/closure + beforeShowDay: null, // Function that takes a date and returns an array with + // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or '', + // [2] = cell title (optional), e.g. $.datepicker.noWeekends + beforeShow: null, // Function that takes an input field and + // returns a set of custom settings for the date picker + onSelect: null, // Define a callback function when a date is selected + onChangeMonthYear: null, // Define a callback function when the month or year is changed + onClose: null, // Define a callback function when the datepicker is closed + numberOfMonths: 1, // Number of months to show at a time + showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0) + stepMonths: 1, // Number of months to step back/forward + stepBigMonths: 12, // Number of months to step back/forward for the big links + altField: '', // Selector for an alternate field to store selected dates into + altFormat: '', // The date format to use for the alternate field + constrainInput: true, // The input is constrained by the current date format + showButtonPanel: false // True to show button panel, false to not show it + }; + $.extend(this._defaults, this.regional['']); + this.dpDiv = $('
    '); +} + +$.extend(Datepicker.prototype, { + /* Class name added to elements to indicate already configured with a date picker. */ + markerClassName: 'hasDatepicker', + + /* Debug logging (if enabled). */ + log: function () { + if (this.debug) + console.log.apply('', arguments); + }, + + /* Override the default settings for all instances of the date picker. + @param settings object - the new settings to use as defaults (anonymous object) + @return the manager object */ + setDefaults: function(settings) { + extendRemove(this._defaults, settings || {}); + return this; + }, + + /* Attach the date picker to a jQuery selection. + @param target element - the target input field or division or span + @param settings object - the new settings to use for this date picker instance (anonymous) */ + _attachDatepicker: function(target, settings) { + // check for settings on the control itself - in namespace 'date:' + var inlineSettings = null; + for (var attrName in this._defaults) { + var attrValue = target.getAttribute('date:' + attrName); + if (attrValue) { + inlineSettings = inlineSettings || {}; + try { + inlineSettings[attrName] = eval(attrValue); + } catch (err) { + inlineSettings[attrName] = attrValue; + } + } + } + var nodeName = target.nodeName.toLowerCase(); + var inline = (nodeName == 'div' || nodeName == 'span'); + if (!target.id) + target.id = 'dp' + (++this.uuid); + var inst = this._newInst($(target), inline); + inst.settings = $.extend({}, settings || {}, inlineSettings || {}); + if (nodeName == 'input') { + this._connectDatepicker(target, inst); + } else if (inline) { + this._inlineDatepicker(target, inst); + } + }, + + /* Create a new instance object. */ + _newInst: function(target, inline) { + var id = target[0].id.replace(/([:\[\]\.])/g, '\\\\$1'); // escape jQuery meta chars + return {id: id, input: target, // associated target + selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection + drawMonth: 0, drawYear: 0, // month being drawn + inline: inline, // is datepicker inline or not + dpDiv: (!inline ? this.dpDiv : // presentation div + $('
    '))}; + }, + + /* Attach the date picker to an input field. */ + _connectDatepicker: function(target, inst) { + var input = $(target); + inst.trigger = $([]); + if (input.hasClass(this.markerClassName)) + return; + var appendText = this._get(inst, 'appendText'); + var isRTL = this._get(inst, 'isRTL'); + if (appendText) + input[isRTL ? 'before' : 'after']('' + appendText + ''); + var showOn = this._get(inst, 'showOn'); + if (showOn == 'focus' || showOn == 'both') // pop-up date picker when in the marked field + input.focus(this._showDatepicker); + if (showOn == 'button' || showOn == 'both') { // pop-up date picker when button clicked + var buttonText = this._get(inst, 'buttonText'); + var buttonImage = this._get(inst, 'buttonImage'); + inst.trigger = $(this._get(inst, 'buttonImageOnly') ? + $('').addClass(this._triggerClass). + attr({ src: buttonImage, alt: buttonText, title: buttonText }) : + $('').addClass(this._triggerClass). + html(buttonImage == '' ? buttonText : $('').attr( + { src:buttonImage, alt:buttonText, title:buttonText }))); + input[isRTL ? 'before' : 'after'](inst.trigger); + inst.trigger.click(function() { + if ($.datepicker._datepickerShowing && $.datepicker._lastInput == target) + $.datepicker._hideDatepicker(); + else + $.datepicker._showDatepicker(target); + return false; + }); + } + input.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress). + bind("setData.datepicker", function(event, key, value) { + inst.settings[key] = value; + }).bind("getData.datepicker", function(event, key) { + return this._get(inst, key); + }); + $.data(target, PROP_NAME, inst); + }, + + /* Attach an inline date picker to a div. */ + _inlineDatepicker: function(target, inst) { + var divSpan = $(target); + if (divSpan.hasClass(this.markerClassName)) + return; + divSpan.addClass(this.markerClassName).append(inst.dpDiv). + bind("setData.datepicker", function(event, key, value){ + inst.settings[key] = value; + }).bind("getData.datepicker", function(event, key){ + return this._get(inst, key); + }); + $.data(target, PROP_NAME, inst); + this._setDate(inst, this._getDefaultDate(inst)); + this._updateDatepicker(inst); + this._updateAlternate(inst); + }, + + /* Pop-up the date picker in a "dialog" box. + @param input element - ignored + @param dateText string - the initial date to display (in the current format) + @param onSelect function - the function(dateText) to call when a date is selected + @param settings object - update the dialog date picker instance's settings (anonymous object) + @param pos int[2] - coordinates for the dialog's position within the screen or + event - with x/y coordinates or + leave empty for default (screen centre) + @return the manager object */ + _dialogDatepicker: function(input, dateText, onSelect, settings, pos) { + var inst = this._dialogInst; // internal instance + if (!inst) { + var id = 'dp' + (++this.uuid); + this._dialogInput = $(''); + this._dialogInput.keydown(this._doKeyDown); + $('body').append(this._dialogInput); + inst = this._dialogInst = this._newInst(this._dialogInput, false); + inst.settings = {}; + $.data(this._dialogInput[0], PROP_NAME, inst); + } + extendRemove(inst.settings, settings || {}); + this._dialogInput.val(dateText); + + this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null); + if (!this._pos) { + var browserWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; + var browserHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; + var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; + var scrollY = document.documentElement.scrollTop || document.body.scrollTop; + this._pos = // should use actual width/height below + [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY]; + } + + // move input on screen for focus, but hidden behind dialog + this._dialogInput.css('left', this._pos[0] + 'px').css('top', this._pos[1] + 'px'); + inst.settings.onSelect = onSelect; + this._inDialog = true; + this.dpDiv.addClass(this._dialogClass); + this._showDatepicker(this._dialogInput[0]); + if ($.blockUI) + $.blockUI(this.dpDiv); + $.data(this._dialogInput[0], PROP_NAME, inst); + return this; + }, + + /* Detach a datepicker from its control. + @param target element - the target input field or division or span */ + _destroyDatepicker: function(target) { + var $target = $(target); + var inst = $.data(target, PROP_NAME); + if (!$target.hasClass(this.markerClassName)) { + return; + } + var nodeName = target.nodeName.toLowerCase(); + $.removeData(target, PROP_NAME); + if (nodeName == 'input') { + inst.trigger.remove(); + $target.siblings('.' + this._appendClass).remove().end(). + removeClass(this.markerClassName). + unbind('focus', this._showDatepicker). + unbind('keydown', this._doKeyDown). + unbind('keypress', this._doKeyPress); + } else if (nodeName == 'div' || nodeName == 'span') + $target.removeClass(this.markerClassName).empty(); + }, + + /* Enable the date picker to a jQuery selection. + @param target element - the target input field or division or span */ + _enableDatepicker: function(target) { + var $target = $(target); + var inst = $.data(target, PROP_NAME); + if (!$target.hasClass(this.markerClassName)) { + return; + } + var nodeName = target.nodeName.toLowerCase(); + if (nodeName == 'input') { + target.disabled = false; + inst.trigger.filter("button"). + each(function() { this.disabled = false; }).end(). + filter("img"). + css({opacity: '1.0', cursor: ''}); + } + else if (nodeName == 'div' || nodeName == 'span') { + var inline = $target.children('.' + this._inlineClass); + inline.children().removeClass('ui-state-disabled'); + } + this._disabledInputs = $.map(this._disabledInputs, + function(value) { return (value == target ? null : value); }); // delete entry + }, + + /* Disable the date picker to a jQuery selection. + @param target element - the target input field or division or span */ + _disableDatepicker: function(target) { + var $target = $(target); + var inst = $.data(target, PROP_NAME); + if (!$target.hasClass(this.markerClassName)) { + return; + } + var nodeName = target.nodeName.toLowerCase(); + if (nodeName == 'input') { + target.disabled = true; + inst.trigger.filter("button"). + each(function() { this.disabled = true; }).end(). + filter("img"). + css({opacity: '0.5', cursor: 'default'}); + } + else if (nodeName == 'div' || nodeName == 'span') { + var inline = $target.children('.' + this._inlineClass); + inline.children().addClass('ui-state-disabled'); + } + this._disabledInputs = $.map(this._disabledInputs, + function(value) { return (value == target ? null : value); }); // delete entry + this._disabledInputs[this._disabledInputs.length] = target; + }, + + /* Is the first field in a jQuery collection disabled as a datepicker? + @param target element - the target input field or division or span + @return boolean - true if disabled, false if enabled */ + _isDisabledDatepicker: function(target) { + if (!target) { + return false; + } + for (var i = 0; i < this._disabledInputs.length; i++) { + if (this._disabledInputs[i] == target) + return true; + } + return false; + }, + + /* Retrieve the instance data for the target control. + @param target element - the target input field or division or span + @return object - the associated instance data + @throws error if a jQuery problem getting data */ + _getInst: function(target) { + try { + return $.data(target, PROP_NAME); + } + catch (err) { + throw 'Missing instance data for this datepicker'; + } + }, + + /* Update the settings for a date picker attached to an input field or division. + @param target element - the target input field or division or span + @param name object - the new settings to update or + string - the name of the setting to change or + @param value any - the new value for the setting (omit if above is an object) */ + _optionDatepicker: function(target, name, value) { + var settings = name || {}; + if (typeof name == 'string') { + settings = {}; + settings[name] = value; + } + var inst = this._getInst(target); + if (inst) { + if (this._curInst == inst) { + this._hideDatepicker(null); + } + extendRemove(inst.settings, settings); + var date = new Date(); + extendRemove(inst, {rangeStart: null, // start of range + endDay: null, endMonth: null, endYear: null, // end of range + selectedDay: date.getDate(), selectedMonth: date.getMonth(), + selectedYear: date.getFullYear(), // starting point + currentDay: date.getDate(), currentMonth: date.getMonth(), + currentYear: date.getFullYear(), // current selection + drawMonth: date.getMonth(), drawYear: date.getFullYear()}); // month being drawn + this._updateDatepicker(inst); + } + }, + + // change method deprecated + _changeDatepicker: function(target, name, value) { + this._optionDatepicker(target, name, value); + }, + + /* Redraw the date picker attached to an input field or division. + @param target element - the target input field or division or span */ + _refreshDatepicker: function(target) { + var inst = this._getInst(target); + if (inst) { + this._updateDatepicker(inst); + } + }, + + /* Set the dates for a jQuery selection. + @param target element - the target input field or division or span + @param date Date - the new date + @param endDate Date - the new end date for a range (optional) */ + _setDateDatepicker: function(target, date, endDate) { + var inst = this._getInst(target); + if (inst) { + this._setDate(inst, date, endDate); + this._updateDatepicker(inst); + this._updateAlternate(inst); + } + }, + + /* Get the date(s) for the first entry in a jQuery selection. + @param target element - the target input field or division or span + @return Date - the current date or + Date[2] - the current dates for a range */ + _getDateDatepicker: function(target) { + var inst = this._getInst(target); + if (inst && !inst.inline) + this._setDateFromField(inst); + return (inst ? this._getDate(inst) : null); + }, + + /* Handle keystrokes. */ + _doKeyDown: function(event) { + var inst = $.datepicker._getInst(event.target); + var handled = true; + var isRTL = inst.dpDiv.is('.ui-datepicker-rtl'); + inst._keyEvent = true; + if ($.datepicker._datepickerShowing) + switch (event.keyCode) { + case 9: $.datepicker._hideDatepicker(null, ''); + break; // hide on tab out + case 13: var sel = $('td.' + $.datepicker._dayOverClass + + ', td.' + $.datepicker._currentClass, inst.dpDiv); + if (sel[0]) + $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]); + else + $.datepicker._hideDatepicker(null, $.datepicker._get(inst, 'duration')); + return false; // don't submit the form + break; // select the value on enter + case 27: $.datepicker._hideDatepicker(null, $.datepicker._get(inst, 'duration')); + break; // hide on escape + case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ? + -$.datepicker._get(inst, 'stepBigMonths') : + -$.datepicker._get(inst, 'stepMonths')), 'M'); + break; // previous month/year on page up/+ ctrl + case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ? + +$.datepicker._get(inst, 'stepBigMonths') : + +$.datepicker._get(inst, 'stepMonths')), 'M'); + break; // next month/year on page down/+ ctrl + case 35: if (event.ctrlKey || event.metaKey) $.datepicker._clearDate(event.target); + handled = event.ctrlKey || event.metaKey; + break; // clear on ctrl or command +end + case 36: if (event.ctrlKey || event.metaKey) $.datepicker._gotoToday(event.target); + handled = event.ctrlKey || event.metaKey; + break; // current on ctrl or command +home + case 37: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), 'D'); + handled = event.ctrlKey || event.metaKey; + // -1 day on ctrl or command +left + if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ? + -$.datepicker._get(inst, 'stepBigMonths') : + -$.datepicker._get(inst, 'stepMonths')), 'M'); + // next month/year on alt +left on Mac + break; + case 38: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, -7, 'D'); + handled = event.ctrlKey || event.metaKey; + break; // -1 week on ctrl or command +up + case 39: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), 'D'); + handled = event.ctrlKey || event.metaKey; + // +1 day on ctrl or command +right + if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ? + +$.datepicker._get(inst, 'stepBigMonths') : + +$.datepicker._get(inst, 'stepMonths')), 'M'); + // next month/year on alt +right + break; + case 40: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, +7, 'D'); + handled = event.ctrlKey || event.metaKey; + break; // +1 week on ctrl or command +down + default: handled = false; + } + else if (event.keyCode == 36 && event.ctrlKey) // display the date picker on ctrl+home + $.datepicker._showDatepicker(this); + else { + handled = false; + } + if (handled) { + event.preventDefault(); + event.stopPropagation(); + } + }, + + /* Filter entered characters - based on date format. */ + _doKeyPress: function(event) { + var inst = $.datepicker._getInst(event.target); + if ($.datepicker._get(inst, 'constrainInput')) { + var chars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')); + var chr = String.fromCharCode(event.charCode == undefined ? event.keyCode : event.charCode); + return event.ctrlKey || (chr < ' ' || !chars || chars.indexOf(chr) > -1); + } + }, + + /* Pop-up the date picker for a given input field. + @param input element - the input field attached to the date picker or + event - if triggered by focus */ + _showDatepicker: function(input) { + input = input.target || input; + if (input.nodeName.toLowerCase() != 'input') // find from button/image trigger + input = $('input', input.parentNode)[0]; + if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput == input) // already here + return; + var inst = $.datepicker._getInst(input); + var beforeShow = $.datepicker._get(inst, 'beforeShow'); + extendRemove(inst.settings, (beforeShow ? beforeShow.apply(input, [input, inst]) : {})); + $.datepicker._hideDatepicker(null, ''); + $.datepicker._lastInput = input; + $.datepicker._setDateFromField(inst); + if ($.datepicker._inDialog) // hide cursor + input.value = ''; + if (!$.datepicker._pos) { // position below input + $.datepicker._pos = $.datepicker._findPos(input); + $.datepicker._pos[1] += input.offsetHeight; // add the height + } + var isFixed = false; + $(input).parents().each(function() { + isFixed |= $(this).css('position') == 'fixed'; + return !isFixed; + }); + if (isFixed && $.browser.opera) { // correction for Opera when fixed and scrolled + $.datepicker._pos[0] -= document.documentElement.scrollLeft; + $.datepicker._pos[1] -= document.documentElement.scrollTop; + } + var offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]}; + $.datepicker._pos = null; + inst.rangeStart = null; + // determine sizing offscreen + inst.dpDiv.css({position: 'absolute', display: 'block', top: '-1000px'}); + $.datepicker._updateDatepicker(inst); + // fix width for dynamic number of date pickers + // and adjust position before showing + offset = $.datepicker._checkOffset(inst, offset, isFixed); + inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ? + 'static' : (isFixed ? 'fixed' : 'absolute')), display: 'none', + left: offset.left + 'px', top: offset.top + 'px'}); + if (!inst.inline) { + var showAnim = $.datepicker._get(inst, 'showAnim') || 'show'; + var duration = $.datepicker._get(inst, 'duration'); + var postProcess = function() { + $.datepicker._datepickerShowing = true; + if ($.browser.msie && parseInt($.browser.version,10) < 7) // fix IE < 7 select problems + $('iframe.ui-datepicker-cover').css({width: inst.dpDiv.width() + 4, + height: inst.dpDiv.height() + 4}); + }; + if ($.effects && $.effects[showAnim]) + inst.dpDiv.show(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess); + else + inst.dpDiv[showAnim](duration, postProcess); + if (duration == '') + postProcess(); + if (inst.input[0].type != 'hidden') + inst.input[0].focus(); + $.datepicker._curInst = inst; + } + }, + + /* Generate the date picker content. */ + _updateDatepicker: function(inst) { + var dims = {width: inst.dpDiv.width() + 4, + height: inst.dpDiv.height() + 4}; + var self = this; + inst.dpDiv.empty().append(this._generateHTML(inst)) + .find('iframe.ui-datepicker-cover'). + css({width: dims.width, height: dims.height}) + .end() + .find('button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a') + .bind('mouseout', function(){ + $(this).removeClass('ui-state-hover'); + if(this.className.indexOf('ui-datepicker-prev') != -1) $(this).removeClass('ui-datepicker-prev-hover'); + if(this.className.indexOf('ui-datepicker-next') != -1) $(this).removeClass('ui-datepicker-next-hover'); + }) + .bind('mouseover', function(){ + if (!self._isDisabledDatepicker( inst.inline ? inst.dpDiv.parent()[0] : inst.input[0])) { + $(this).parents('.ui-datepicker-calendar').find('a').removeClass('ui-state-hover'); + $(this).addClass('ui-state-hover'); + if(this.className.indexOf('ui-datepicker-prev') != -1) $(this).addClass('ui-datepicker-prev-hover'); + if(this.className.indexOf('ui-datepicker-next') != -1) $(this).addClass('ui-datepicker-next-hover'); + } + }) + .end() + .find('.' + this._dayOverClass + ' a') + .trigger('mouseover') + .end(); + var numMonths = this._getNumberOfMonths(inst); + var cols = numMonths[1]; + var width = 17; + if (cols > 1) { + inst.dpDiv.addClass('ui-datepicker-multi-' + cols).css('width', (width * cols) + 'em'); + } else { + inst.dpDiv.removeClass('ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4').width(''); + } + inst.dpDiv[(numMonths[0] != 1 || numMonths[1] != 1 ? 'add' : 'remove') + + 'Class']('ui-datepicker-multi'); + inst.dpDiv[(this._get(inst, 'isRTL') ? 'add' : 'remove') + + 'Class']('ui-datepicker-rtl'); + if (inst.input && inst.input[0].type != 'hidden' && inst == $.datepicker._curInst) + $(inst.input[0]).focus(); + }, + + /* Check positioning to remain on screen. */ + _checkOffset: function(inst, offset, isFixed) { + var dpWidth = inst.dpDiv.outerWidth(); + var dpHeight = inst.dpDiv.outerHeight(); + var inputWidth = inst.input ? inst.input.outerWidth() : 0; + var inputHeight = inst.input ? inst.input.outerHeight() : 0; + var viewWidth = (window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth) + $(document).scrollLeft(); + var viewHeight = (window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight) + $(document).scrollTop(); + + offset.left -= (this._get(inst, 'isRTL') ? (dpWidth - inputWidth) : 0); + offset.left -= (isFixed && offset.left == inst.input.offset().left) ? $(document).scrollLeft() : 0; + offset.top -= (isFixed && offset.top == (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0; + + // now check if datepicker is showing outside window viewport - move to a better place if so. + offset.left -= (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ? Math.abs(offset.left + dpWidth - viewWidth) : 0; + offset.top -= (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ? Math.abs(offset.top + dpHeight + inputHeight*2 - viewHeight) : 0; + + return offset; + }, + + /* Find an object's position on the screen. */ + _findPos: function(obj) { + while (obj && (obj.type == 'hidden' || obj.nodeType != 1)) { + obj = obj.nextSibling; + } + var position = $(obj).offset(); + return [position.left, position.top]; + }, + + /* Hide the date picker from view. + @param input element - the input field attached to the date picker + @param duration string - the duration over which to close the date picker */ + _hideDatepicker: function(input, duration) { + var inst = this._curInst; + if (!inst || (input && inst != $.data(input, PROP_NAME))) + return; + if (inst.stayOpen) + this._selectDate('#' + inst.id, this._formatDate(inst, + inst.currentDay, inst.currentMonth, inst.currentYear)); + inst.stayOpen = false; + if (this._datepickerShowing) { + duration = (duration != null ? duration : this._get(inst, 'duration')); + var showAnim = this._get(inst, 'showAnim'); + var postProcess = function() { + $.datepicker._tidyDialog(inst); + }; + if (duration != '' && $.effects && $.effects[showAnim]) + inst.dpDiv.hide(showAnim, $.datepicker._get(inst, 'showOptions'), + duration, postProcess); + else + inst.dpDiv[(duration == '' ? 'hide' : (showAnim == 'slideDown' ? 'slideUp' : + (showAnim == 'fadeIn' ? 'fadeOut' : 'hide')))](duration, postProcess); + if (duration == '') + this._tidyDialog(inst); + var onClose = this._get(inst, 'onClose'); + if (onClose) + onClose.apply((inst.input ? inst.input[0] : null), + [(inst.input ? inst.input.val() : ''), inst]); // trigger custom callback + this._datepickerShowing = false; + this._lastInput = null; + if (this._inDialog) { + this._dialogInput.css({ position: 'absolute', left: '0', top: '-100px' }); + if ($.blockUI) { + $.unblockUI(); + $('body').append(this.dpDiv); + } + } + this._inDialog = false; + } + this._curInst = null; + }, + + /* Tidy up after a dialog display. */ + _tidyDialog: function(inst) { + inst.dpDiv.removeClass(this._dialogClass).unbind('.ui-datepicker-calendar'); + }, + + /* Close date picker if clicked elsewhere. */ + _checkExternalClick: function(event) { + if (!$.datepicker._curInst) + return; + var $target = $(event.target); + if (($target.parents('#' + $.datepicker._mainDivId).length == 0) && + !$target.hasClass($.datepicker.markerClassName) && + !$target.hasClass($.datepicker._triggerClass) && + $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI)) + $.datepicker._hideDatepicker(null, ''); + }, + + /* Adjust one of the date sub-fields. */ + _adjustDate: function(id, offset, period) { + var target = $(id); + var inst = this._getInst(target[0]); + if (this._isDisabledDatepicker(target[0])) { + return; + } + this._adjustInstDate(inst, offset + + (period == 'M' ? this._get(inst, 'showCurrentAtPos') : 0), // undo positioning + period); + this._updateDatepicker(inst); + }, + + /* Action for current link. */ + _gotoToday: function(id) { + var target = $(id); + var inst = this._getInst(target[0]); + if (this._get(inst, 'gotoCurrent') && inst.currentDay) { + inst.selectedDay = inst.currentDay; + inst.drawMonth = inst.selectedMonth = inst.currentMonth; + inst.drawYear = inst.selectedYear = inst.currentYear; + } + else { + var date = new Date(); + inst.selectedDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = date.getFullYear(); + } + this._notifyChange(inst); + this._adjustDate(target); + }, + + /* Action for selecting a new month/year. */ + _selectMonthYear: function(id, select, period) { + var target = $(id); + var inst = this._getInst(target[0]); + inst._selectingMonthYear = false; + inst['selected' + (period == 'M' ? 'Month' : 'Year')] = + inst['draw' + (period == 'M' ? 'Month' : 'Year')] = + parseInt(select.options[select.selectedIndex].value,10); + this._notifyChange(inst); + this._adjustDate(target); + }, + + /* Restore input focus after not changing month/year. */ + _clickMonthYear: function(id) { + var target = $(id); + var inst = this._getInst(target[0]); + if (inst.input && inst._selectingMonthYear && !$.browser.msie) + inst.input[0].focus(); + inst._selectingMonthYear = !inst._selectingMonthYear; + }, + + /* Action for selecting a day. */ + _selectDay: function(id, month, year, td) { + var target = $(id); + if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) { + return; + } + var inst = this._getInst(target[0]); + inst.selectedDay = inst.currentDay = $('a', td).html(); + inst.selectedMonth = inst.currentMonth = month; + inst.selectedYear = inst.currentYear = year; + if (inst.stayOpen) { + inst.endDay = inst.endMonth = inst.endYear = null; + } + this._selectDate(id, this._formatDate(inst, + inst.currentDay, inst.currentMonth, inst.currentYear)); + if (inst.stayOpen) { + inst.rangeStart = this._daylightSavingAdjust( + new Date(inst.currentYear, inst.currentMonth, inst.currentDay)); + this._updateDatepicker(inst); + } + }, + + /* Erase the input field and hide the date picker. */ + _clearDate: function(id) { + var target = $(id); + var inst = this._getInst(target[0]); + inst.stayOpen = false; + inst.endDay = inst.endMonth = inst.endYear = inst.rangeStart = null; + this._selectDate(target, ''); + }, + + /* Update the input field with the selected date. */ + _selectDate: function(id, dateStr) { + var target = $(id); + var inst = this._getInst(target[0]); + dateStr = (dateStr != null ? dateStr : this._formatDate(inst)); + if (inst.input) + inst.input.val(dateStr); + this._updateAlternate(inst); + var onSelect = this._get(inst, 'onSelect'); + if (onSelect) + onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback + else if (inst.input) + inst.input.trigger('change'); // fire the change event + if (inst.inline) + this._updateDatepicker(inst); + else if (!inst.stayOpen) { + this._hideDatepicker(null, this._get(inst, 'duration')); + this._lastInput = inst.input[0]; + if (typeof(inst.input[0]) != 'object') + inst.input[0].focus(); // restore focus + this._lastInput = null; + } + }, + + /* Update any alternate field to synchronise with the main field. */ + _updateAlternate: function(inst) { + var altField = this._get(inst, 'altField'); + if (altField) { // update alternate field too + var altFormat = this._get(inst, 'altFormat') || this._get(inst, 'dateFormat'); + var date = this._getDate(inst); + dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst)); + $(altField).each(function() { $(this).val(dateStr); }); + } + }, + + /* Set as beforeShowDay function to prevent selection of weekends. + @param date Date - the date to customise + @return [boolean, string] - is this date selectable?, what is its CSS class? */ + noWeekends: function(date) { + var day = date.getDay(); + return [(day > 0 && day < 6), '']; + }, + + /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition. + @param date Date - the date to get the week for + @return number - the number of the week within the year that contains this date */ + iso8601Week: function(date) { + var checkDate = new Date(date.getFullYear(), date.getMonth(), date.getDate()); + var firstMon = new Date(checkDate.getFullYear(), 1 - 1, 4); // First week always contains 4 Jan + var firstDay = firstMon.getDay() || 7; // Day of week: Mon = 1, ..., Sun = 7 + firstMon.setDate(firstMon.getDate() + 1 - firstDay); // Preceding Monday + if (firstDay < 4 && checkDate < firstMon) { // Adjust first three days in year if necessary + checkDate.setDate(checkDate.getDate() - 3); // Generate for previous year + return $.datepicker.iso8601Week(checkDate); + } else if (checkDate > new Date(checkDate.getFullYear(), 12 - 1, 28)) { // Check last three days in year + firstDay = new Date(checkDate.getFullYear() + 1, 1 - 1, 4).getDay() || 7; + if (firstDay > 4 && (checkDate.getDay() || 7) < firstDay - 3) { // Adjust if necessary + return 1; + } + } + return Math.floor(((checkDate - firstMon) / 86400000) / 7) + 1; // Weeks to given date + }, + + /* Parse a string value into a date object. + See formatDate below for the possible formats. + + @param format string - the expected format of the date + @param value string - the date in the above format + @param settings Object - attributes include: + shortYearCutoff number - the cutoff year for determining the century (optional) + dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) + dayNames string[7] - names of the days from Sunday (optional) + monthNamesShort string[12] - abbreviated names of the months (optional) + monthNames string[12] - names of the months (optional) + @return Date - the extracted date value or null if value is blank */ + parseDate: function (format, value, settings) { + if (format == null || value == null) + throw 'Invalid arguments'; + value = (typeof value == 'object' ? value.toString() : value + ''); + if (value == '') + return null; + var shortYearCutoff = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff; + var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort; + var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames; + var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort; + var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames; + var year = -1; + var month = -1; + var day = -1; + var doy = -1; + var literal = false; + // Check whether a format character is doubled + var lookAhead = function(match) { + var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match); + if (matches) + iFormat++; + return matches; + }; + // Extract a number from the string value + var getNumber = function(match) { + lookAhead(match); + var origSize = (match == '@' ? 14 : (match == 'y' ? 4 : (match == 'o' ? 3 : 2))); + var size = origSize; + var num = 0; + while (size > 0 && iValue < value.length && + value.charAt(iValue) >= '0' && value.charAt(iValue) <= '9') { + num = num * 10 + parseInt(value.charAt(iValue++),10); + size--; + } + if (size == origSize) + throw 'Missing number at position ' + iValue; + return num; + }; + // Extract a name from the string value and convert to an index + var getName = function(match, shortNames, longNames) { + var names = (lookAhead(match) ? longNames : shortNames); + var size = 0; + for (var j = 0; j < names.length; j++) + size = Math.max(size, names[j].length); + var name = ''; + var iInit = iValue; + while (size > 0 && iValue < value.length) { + name += value.charAt(iValue++); + for (var i = 0; i < names.length; i++) + if (name == names[i]) + return i + 1; + size--; + } + throw 'Unknown name at position ' + iInit; + }; + // Confirm that a literal character matches the string value + var checkLiteral = function() { + if (value.charAt(iValue) != format.charAt(iFormat)) + throw 'Unexpected literal at position ' + iValue; + iValue++; + }; + var iValue = 0; + for (var iFormat = 0; iFormat < format.length; iFormat++) { + if (literal) + if (format.charAt(iFormat) == "'" && !lookAhead("'")) + literal = false; + else + checkLiteral(); + else + switch (format.charAt(iFormat)) { + case 'd': + day = getNumber('d'); + break; + case 'D': + getName('D', dayNamesShort, dayNames); + break; + case 'o': + doy = getNumber('o'); + break; + case 'm': + month = getNumber('m'); + break; + case 'M': + month = getName('M', monthNamesShort, monthNames); + break; + case 'y': + year = getNumber('y'); + break; + case '@': + var date = new Date(getNumber('@')); + year = date.getFullYear(); + month = date.getMonth() + 1; + day = date.getDate(); + break; + case "'": + if (lookAhead("'")) + checkLiteral(); + else + literal = true; + break; + default: + checkLiteral(); + } + } + if (year == -1) + year = new Date().getFullYear(); + else if (year < 100) + year += new Date().getFullYear() - new Date().getFullYear() % 100 + + (year <= shortYearCutoff ? 0 : -100); + if (doy > -1) { + month = 1; + day = doy; + do { + var dim = this._getDaysInMonth(year, month - 1); + if (day <= dim) + break; + month++; + day -= dim; + } while (true); + } + var date = this._daylightSavingAdjust(new Date(year, month - 1, day)); + if (date.getFullYear() != year || date.getMonth() + 1 != month || date.getDate() != day) + throw 'Invalid date'; // E.g. 31/02/* + return date; + }, + + /* Standard date formats. */ + ATOM: 'yy-mm-dd', // RFC 3339 (ISO 8601) + COOKIE: 'D, dd M yy', + ISO_8601: 'yy-mm-dd', + RFC_822: 'D, d M y', + RFC_850: 'DD, dd-M-y', + RFC_1036: 'D, d M y', + RFC_1123: 'D, d M yy', + RFC_2822: 'D, d M yy', + RSS: 'D, d M y', // RFC 822 + TIMESTAMP: '@', + W3C: 'yy-mm-dd', // ISO 8601 + + /* Format a date object into a string value. + The format can be combinations of the following: + d - day of month (no leading zero) + dd - day of month (two digit) + o - day of year (no leading zeros) + oo - day of year (three digit) + D - day name short + DD - day name long + m - month of year (no leading zero) + mm - month of year (two digit) + M - month name short + MM - month name long + y - year (two digit) + yy - year (four digit) + @ - Unix timestamp (ms since 01/01/1970) + '...' - literal text + '' - single quote + + @param format string - the desired format of the date + @param date Date - the date value to format + @param settings Object - attributes include: + dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) + dayNames string[7] - names of the days from Sunday (optional) + monthNamesShort string[12] - abbreviated names of the months (optional) + monthNames string[12] - names of the months (optional) + @return string - the date in the above format */ + formatDate: function (format, date, settings) { + if (!date) + return ''; + var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort; + var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames; + var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort; + var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames; + // Check whether a format character is doubled + var lookAhead = function(match) { + var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match); + if (matches) + iFormat++; + return matches; + }; + // Format a number, with leading zero if necessary + var formatNumber = function(match, value, len) { + var num = '' + value; + if (lookAhead(match)) + while (num.length < len) + num = '0' + num; + return num; + }; + // Format a name, short or long as requested + var formatName = function(match, value, shortNames, longNames) { + return (lookAhead(match) ? longNames[value] : shortNames[value]); + }; + var output = ''; + var literal = false; + if (date) + for (var iFormat = 0; iFormat < format.length; iFormat++) { + if (literal) + if (format.charAt(iFormat) == "'" && !lookAhead("'")) + literal = false; + else + output += format.charAt(iFormat); + else + switch (format.charAt(iFormat)) { + case 'd': + output += formatNumber('d', date.getDate(), 2); + break; + case 'D': + output += formatName('D', date.getDay(), dayNamesShort, dayNames); + break; + case 'o': + var doy = date.getDate(); + for (var m = date.getMonth() - 1; m >= 0; m--) + doy += this._getDaysInMonth(date.getFullYear(), m); + output += formatNumber('o', doy, 3); + break; + case 'm': + output += formatNumber('m', date.getMonth() + 1, 2); + break; + case 'M': + output += formatName('M', date.getMonth(), monthNamesShort, monthNames); + break; + case 'y': + output += (lookAhead('y') ? date.getFullYear() : + (date.getYear() % 100 < 10 ? '0' : '') + date.getYear() % 100); + break; + case '@': + output += date.getTime(); + break; + case "'": + if (lookAhead("'")) + output += "'"; + else + literal = true; + break; + default: + output += format.charAt(iFormat); + } + } + return output; + }, + + /* Extract all possible characters from the date format. */ + _possibleChars: function (format) { + var chars = ''; + var literal = false; + for (var iFormat = 0; iFormat < format.length; iFormat++) + if (literal) + if (format.charAt(iFormat) == "'" && !lookAhead("'")) + literal = false; + else + chars += format.charAt(iFormat); + else + switch (format.charAt(iFormat)) { + case 'd': case 'm': case 'y': case '@': + chars += '0123456789'; + break; + case 'D': case 'M': + return null; // Accept anything + case "'": + if (lookAhead("'")) + chars += "'"; + else + literal = true; + break; + default: + chars += format.charAt(iFormat); + } + return chars; + }, + + /* Get a setting value, defaulting if necessary. */ + _get: function(inst, name) { + return inst.settings[name] !== undefined ? + inst.settings[name] : this._defaults[name]; + }, + + /* Parse existing date and initialise date picker. */ + _setDateFromField: function(inst) { + var dateFormat = this._get(inst, 'dateFormat'); + var dates = inst.input ? inst.input.val() : null; + inst.endDay = inst.endMonth = inst.endYear = null; + var date = defaultDate = this._getDefaultDate(inst); + var settings = this._getFormatConfig(inst); + try { + date = this.parseDate(dateFormat, dates, settings) || defaultDate; + } catch (event) { + this.log(event); + date = defaultDate; + } + inst.selectedDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = date.getFullYear(); + inst.currentDay = (dates ? date.getDate() : 0); + inst.currentMonth = (dates ? date.getMonth() : 0); + inst.currentYear = (dates ? date.getFullYear() : 0); + this._adjustInstDate(inst); + }, + + /* Retrieve the default date shown on opening. */ + _getDefaultDate: function(inst) { + var date = this._determineDate(this._get(inst, 'defaultDate'), new Date()); + var minDate = this._getMinMaxDate(inst, 'min', true); + var maxDate = this._getMinMaxDate(inst, 'max'); + date = (minDate && date < minDate ? minDate : date); + date = (maxDate && date > maxDate ? maxDate : date); + return date; + }, + + /* A date may be specified as an exact value or a relative one. */ + _determineDate: function(date, defaultDate) { + var offsetNumeric = function(offset) { + var date = new Date(); + date.setDate(date.getDate() + offset); + return date; + }; + var offsetString = function(offset, getDaysInMonth) { + var date = new Date(); + var year = date.getFullYear(); + var month = date.getMonth(); + var day = date.getDate(); + var pattern = /([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g; + var matches = pattern.exec(offset); + while (matches) { + switch (matches[2] || 'd') { + case 'd' : case 'D' : + day += parseInt(matches[1],10); break; + case 'w' : case 'W' : + day += parseInt(matches[1],10) * 7; break; + case 'm' : case 'M' : + month += parseInt(matches[1],10); + day = Math.min(day, getDaysInMonth(year, month)); + break; + case 'y': case 'Y' : + year += parseInt(matches[1],10); + day = Math.min(day, getDaysInMonth(year, month)); + break; + } + matches = pattern.exec(offset); + } + return new Date(year, month, day); + }; + date = (date == null ? defaultDate : + (typeof date == 'string' ? offsetString(date, this._getDaysInMonth) : + (typeof date == 'number' ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : date))); + date = (date && date.toString() == 'Invalid Date' ? defaultDate : date); + if (date) { + date.setHours(0); + date.setMinutes(0); + date.setSeconds(0); + date.setMilliseconds(0); + } + return this._daylightSavingAdjust(date); + }, + + /* Handle switch to/from daylight saving. + Hours may be non-zero on daylight saving cut-over: + > 12 when midnight changeover, but then cannot generate + midnight datetime, so jump to 1AM, otherwise reset. + @param date (Date) the date to check + @return (Date) the corrected date */ + _daylightSavingAdjust: function(date) { + if (!date) return null; + date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0); + return date; + }, + + /* Set the date(s) directly. */ + _setDate: function(inst, date, endDate) { + var clear = !(date); + var origMonth = inst.selectedMonth; + var origYear = inst.selectedYear; + date = this._determineDate(date, new Date()); + inst.selectedDay = inst.currentDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = inst.currentMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = inst.currentYear = date.getFullYear(); + if (origMonth != inst.selectedMonth || origYear != inst.selectedYear) + this._notifyChange(inst); + this._adjustInstDate(inst); + if (inst.input) { + inst.input.val(clear ? '' : this._formatDate(inst)); + } + }, + + /* Retrieve the date(s) directly. */ + _getDate: function(inst) { + var startDate = (!inst.currentYear || (inst.input && inst.input.val() == '') ? null : + this._daylightSavingAdjust(new Date( + inst.currentYear, inst.currentMonth, inst.currentDay))); + return startDate; + }, + + /* Generate the HTML for the current state of the date picker. */ + _generateHTML: function(inst) { + var today = new Date(); + today = this._daylightSavingAdjust( + new Date(today.getFullYear(), today.getMonth(), today.getDate())); // clear time + var isRTL = this._get(inst, 'isRTL'); + var showButtonPanel = this._get(inst, 'showButtonPanel'); + var hideIfNoPrevNext = this._get(inst, 'hideIfNoPrevNext'); + var navigationAsDateFormat = this._get(inst, 'navigationAsDateFormat'); + var numMonths = this._getNumberOfMonths(inst); + var showCurrentAtPos = this._get(inst, 'showCurrentAtPos'); + var stepMonths = this._get(inst, 'stepMonths'); + var stepBigMonths = this._get(inst, 'stepBigMonths'); + var isMultiMonth = (numMonths[0] != 1 || numMonths[1] != 1); + var currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) : + new Date(inst.currentYear, inst.currentMonth, inst.currentDay))); + var minDate = this._getMinMaxDate(inst, 'min', true); + var maxDate = this._getMinMaxDate(inst, 'max'); + var drawMonth = inst.drawMonth - showCurrentAtPos; + var drawYear = inst.drawYear; + if (drawMonth < 0) { + drawMonth += 12; + drawYear--; + } + if (maxDate) { + var maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(), + maxDate.getMonth() - numMonths[1] + 1, maxDate.getDate())); + maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw); + while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) { + drawMonth--; + if (drawMonth < 0) { + drawMonth = 11; + drawYear--; + } + } + } + inst.drawMonth = drawMonth; + inst.drawYear = drawYear; + var prevText = this._get(inst, 'prevText'); + prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText, + this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)), + this._getFormatConfig(inst))); + var prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ? + '' + prevText + '' : + (hideIfNoPrevNext ? '' : '' + prevText + '')); + var nextText = this._get(inst, 'nextText'); + nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText, + this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)), + this._getFormatConfig(inst))); + var next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ? + '' + nextText + '' : + (hideIfNoPrevNext ? '' : '' + nextText + '')); + var currentText = this._get(inst, 'currentText'); + var gotoDate = (this._get(inst, 'gotoCurrent') && inst.currentDay ? currentDate : today); + currentText = (!navigationAsDateFormat ? currentText : + this.formatDate(currentText, gotoDate, this._getFormatConfig(inst))); + var controls = (!inst.inline ? '' : ''); + var buttonPanel = (showButtonPanel) ? '
    ' + (isRTL ? controls : '') + + (this._isInRange(inst, gotoDate) ? '' : '') + (isRTL ? '' : controls) + '
    ' : ''; + var firstDay = parseInt(this._get(inst, 'firstDay'),10); + firstDay = (isNaN(firstDay) ? 0 : firstDay); + var dayNames = this._get(inst, 'dayNames'); + var dayNamesShort = this._get(inst, 'dayNamesShort'); + var dayNamesMin = this._get(inst, 'dayNamesMin'); + var monthNames = this._get(inst, 'monthNames'); + var monthNamesShort = this._get(inst, 'monthNamesShort'); + var beforeShowDay = this._get(inst, 'beforeShowDay'); + var showOtherMonths = this._get(inst, 'showOtherMonths'); + var calculateWeek = this._get(inst, 'calculateWeek') || this.iso8601Week; + var endDate = inst.endDay ? this._daylightSavingAdjust( + new Date(inst.endYear, inst.endMonth, inst.endDay)) : currentDate; + var defaultDate = this._getDefaultDate(inst); + var html = ''; + for (var row = 0; row < numMonths[0]; row++) { + var group = ''; + for (var col = 0; col < numMonths[1]; col++) { + var selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay)); + var cornerClass = ' ui-corner-all'; + var calender = ''; + if (isMultiMonth) { + calender += '
    '; + } + calender += '
    ' + + (/all|left/.test(cornerClass) && row == 0 ? (isRTL ? next : prev) : '') + + (/all|right/.test(cornerClass) && row == 0 ? (isRTL ? prev : next) : '') + + this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate, + selectedDate, row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers + '
    ' + + ''; + var thead = ''; + for (var dow = 0; dow < 7; dow++) { // days of the week + var day = (dow + firstDay) % 7; + thead += '= 5 ? ' class="ui-datepicker-week-end"' : '') + '>' + + '' + dayNamesMin[day] + ''; + } + calender += thead + ''; + var daysInMonth = this._getDaysInMonth(drawYear, drawMonth); + if (drawYear == inst.selectedYear && drawMonth == inst.selectedMonth) + inst.selectedDay = Math.min(inst.selectedDay, daysInMonth); + var leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7; + var numRows = (isMultiMonth ? 6 : Math.ceil((leadDays + daysInMonth) / 7)); // calculate the number of rows to generate + var printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays)); + for (var dRow = 0; dRow < numRows; dRow++) { // create date picker rows + calender += ''; + var tbody = ''; + for (var dow = 0; dow < 7; dow++) { // create date picker days + var daySettings = (beforeShowDay ? + beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, '']); + var otherMonth = (printDate.getMonth() != drawMonth); + var unselectable = otherMonth || !daySettings[0] || + (minDate && printDate < minDate) || (maxDate && printDate > maxDate); + tbody += ''; // display for this month + printDate.setDate(printDate.getDate() + 1); + printDate = this._daylightSavingAdjust(printDate); + } + calender += tbody + ''; + } + drawMonth++; + if (drawMonth > 11) { + drawMonth = 0; + drawYear++; + } + calender += '
    ' + // actions + (otherMonth ? (showOtherMonths ? printDate.getDate() : ' ') : // display for other months + (unselectable ? '' + printDate.getDate() + '' : '' + printDate.getDate() + '')) + '
    ' + (isMultiMonth ? '
    ' + + ((numMonths[0] > 0 && col == numMonths[1]-1) ? '
    ' : '') : ''); + group += calender; + } + html += group; + } + html += buttonPanel + ($.browser.msie && parseInt($.browser.version,10) < 7 && !inst.inline ? + '' : ''); + inst._keyEvent = false; + return html; + }, + + /* Generate the month and year header. */ + _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate, + selectedDate, secondary, monthNames, monthNamesShort) { + minDate = (inst.rangeStart && minDate && selectedDate < minDate ? selectedDate : minDate); + var changeMonth = this._get(inst, 'changeMonth'); + var changeYear = this._get(inst, 'changeYear'); + var showMonthAfterYear = this._get(inst, 'showMonthAfterYear'); + var html = '
    '; + var monthHtml = ''; + // month selection + if (secondary || !changeMonth) + monthHtml += '' + monthNames[drawMonth] + ' '; + else { + var inMinYear = (minDate && minDate.getFullYear() == drawYear); + var inMaxYear = (maxDate && maxDate.getFullYear() == drawYear); + monthHtml += ''; + } + if (!showMonthAfterYear) + html += monthHtml + ((secondary || changeMonth || changeYear) && (!(changeMonth && changeYear)) ? ' ' : ''); + // year selection + if (secondary || !changeYear) + html += '' + drawYear + ''; + else { + // determine range of years to display + var years = this._get(inst, 'yearRange').split(':'); + var year = 0; + var endYear = 0; + if (years.length != 2) { + year = drawYear - 10; + endYear = drawYear + 10; + } else if (years[0].charAt(0) == '+' || years[0].charAt(0) == '-') { + year = drawYear + parseInt(years[0], 10); + endYear = drawYear + parseInt(years[1], 10); + } else { + year = parseInt(years[0], 10); + endYear = parseInt(years[1], 10); + } + year = (minDate ? Math.max(year, minDate.getFullYear()) : year); + endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear); + html += ''; + } + if (showMonthAfterYear) + html += (secondary || changeMonth || changeYear ? ' ' : '') + monthHtml; + html += '
    '; // Close datepicker_header + return html; + }, + + /* Adjust one of the date sub-fields. */ + _adjustInstDate: function(inst, offset, period) { + var year = inst.drawYear + (period == 'Y' ? offset : 0); + var month = inst.drawMonth + (period == 'M' ? offset : 0); + var day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + + (period == 'D' ? offset : 0); + var date = this._daylightSavingAdjust(new Date(year, month, day)); + // ensure it is within the bounds set + var minDate = this._getMinMaxDate(inst, 'min', true); + var maxDate = this._getMinMaxDate(inst, 'max'); + date = (minDate && date < minDate ? minDate : date); + date = (maxDate && date > maxDate ? maxDate : date); + inst.selectedDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = date.getFullYear(); + if (period == 'M' || period == 'Y') + this._notifyChange(inst); + }, + + /* Notify change of month/year. */ + _notifyChange: function(inst) { + var onChange = this._get(inst, 'onChangeMonthYear'); + if (onChange) + onChange.apply((inst.input ? inst.input[0] : null), + [inst.selectedYear, inst.selectedMonth + 1, inst]); + }, + + /* Determine the number of months to show. */ + _getNumberOfMonths: function(inst) { + var numMonths = this._get(inst, 'numberOfMonths'); + return (numMonths == null ? [1, 1] : (typeof numMonths == 'number' ? [1, numMonths] : numMonths)); + }, + + /* Determine the current maximum date - ensure no time components are set - may be overridden for a range. */ + _getMinMaxDate: function(inst, minMax, checkRange) { + var date = this._determineDate(this._get(inst, minMax + 'Date'), null); + return (!checkRange || !inst.rangeStart ? date : + (!date || inst.rangeStart > date ? inst.rangeStart : date)); + }, + + /* Find the number of days in a given month. */ + _getDaysInMonth: function(year, month) { + return 32 - new Date(year, month, 32).getDate(); + }, + + /* Find the day of the week of the first of a month. */ + _getFirstDayOfMonth: function(year, month) { + return new Date(year, month, 1).getDay(); + }, + + /* Determines if we should allow a "next/prev" month display change. */ + _canAdjustMonth: function(inst, offset, curYear, curMonth) { + var numMonths = this._getNumberOfMonths(inst); + var date = this._daylightSavingAdjust(new Date( + curYear, curMonth + (offset < 0 ? offset : numMonths[1]), 1)); + if (offset < 0) + date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth())); + return this._isInRange(inst, date); + }, + + /* Is the given date in the accepted range? */ + _isInRange: function(inst, date) { + // during range selection, use minimum of selected date and range start + var newMinDate = (!inst.rangeStart ? null : this._daylightSavingAdjust( + new Date(inst.selectedYear, inst.selectedMonth, inst.selectedDay))); + newMinDate = (newMinDate && inst.rangeStart < newMinDate ? inst.rangeStart : newMinDate); + var minDate = newMinDate || this._getMinMaxDate(inst, 'min'); + var maxDate = this._getMinMaxDate(inst, 'max'); + return ((!minDate || date >= minDate) && (!maxDate || date <= maxDate)); + }, + + /* Provide the configuration settings for formatting/parsing. */ + _getFormatConfig: function(inst) { + var shortYearCutoff = this._get(inst, 'shortYearCutoff'); + shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff : + new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10)); + return {shortYearCutoff: shortYearCutoff, + dayNamesShort: this._get(inst, 'dayNamesShort'), dayNames: this._get(inst, 'dayNames'), + monthNamesShort: this._get(inst, 'monthNamesShort'), monthNames: this._get(inst, 'monthNames')}; + }, + + /* Format the given date for display. */ + _formatDate: function(inst, day, month, year) { + if (!day) { + inst.currentDay = inst.selectedDay; + inst.currentMonth = inst.selectedMonth; + inst.currentYear = inst.selectedYear; + } + var date = (day ? (typeof day == 'object' ? day : + this._daylightSavingAdjust(new Date(year, month, day))) : + this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay))); + return this.formatDate(this._get(inst, 'dateFormat'), date, this._getFormatConfig(inst)); + } +}); + +/* jQuery extend now ignores nulls! */ +function extendRemove(target, props) { + $.extend(target, props); + for (var name in props) + if (props[name] == null || props[name] == undefined) + target[name] = props[name]; + return target; +}; + +/* Determine whether an object is an array. */ +function isArray(a) { + return (a && (($.browser.safari && typeof a == 'object' && a.length) || + (a.constructor && a.constructor.toString().match(/\Array\(\)/)))); +}; + +/* Invoke the datepicker functionality. + @param options string - a command, optionally followed by additional parameters or + Object - settings for attaching new datepicker functionality + @return jQuery object */ +$.fn.datepicker = function(options){ + + /* Initialise the date picker. */ + if (!$.datepicker.initialized) { + $(document).mousedown($.datepicker._checkExternalClick). + find('body').append($.datepicker.dpDiv); + $.datepicker.initialized = true; + } + + var otherArgs = Array.prototype.slice.call(arguments, 1); + if (typeof options == 'string' && (options == 'isDisabled' || options == 'getDate')) + return $.datepicker['_' + options + 'Datepicker']. + apply($.datepicker, [this[0]].concat(otherArgs)); + return this.each(function() { + typeof options == 'string' ? + $.datepicker['_' + options + 'Datepicker']. + apply($.datepicker, [this].concat(otherArgs)) : + $.datepicker._attachDatepicker(this, options); + }); +}; + +$.datepicker = new Datepicker(); // singleton instance +$.datepicker.initialized = false; +$.datepicker.uuid = new Date().getTime(); +$.datepicker.version = "1.7.1"; + +// Workaround for #4055 +// Add another global to avoid noConflict issues with inline event handlers +window.DP_jQuery = $; + +})(jQuery); +/* + * jQuery UI Progressbar 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Progressbar + * + * Depends: + * ui.core.js + */ +(function($) { + +$.widget("ui.progressbar", { + + _init: function() { + + this.element + .addClass("ui-progressbar" + + " ui-widget" + + " ui-widget-content" + + " ui-corner-all") + .attr({ + role: "progressbar", + "aria-valuemin": this._valueMin(), + "aria-valuemax": this._valueMax(), + "aria-valuenow": this._value() + }); + + this.valueDiv = $('
    ').appendTo(this.element); + + this._refreshValue(); + + }, + + destroy: function() { + + this.element + .removeClass("ui-progressbar" + + " ui-widget" + + " ui-widget-content" + + " ui-corner-all") + .removeAttr("role") + .removeAttr("aria-valuemin") + .removeAttr("aria-valuemax") + .removeAttr("aria-valuenow") + .removeData("progressbar") + .unbind(".progressbar"); + + this.valueDiv.remove(); + + $.widget.prototype.destroy.apply(this, arguments); + + }, + + value: function(newValue) { + arguments.length && this._setData("value", newValue); + return this._value(); + }, + + _setData: function(key, value) { + + switch (key) { + case 'value': + this.options.value = value; + this._refreshValue(); + this._trigger('change', null, {}); + break; + } + + $.widget.prototype._setData.apply(this, arguments); + + }, + + _value: function() { + + var val = this.options.value; + if (val < this._valueMin()) val = this._valueMin(); + if (val > this._valueMax()) val = this._valueMax(); + + return val; + + }, + + _valueMin: function() { + var valueMin = 0; + return valueMin; + }, + + _valueMax: function() { + var valueMax = 100; + return valueMax; + }, + + _refreshValue: function() { + var value = this.value(); + this.valueDiv[value == this._valueMax() ? 'addClass' : 'removeClass']("ui-corner-right"); + this.valueDiv.width(value + '%'); + this.element.attr("aria-valuenow", value); + } + +}); + +$.extend($.ui.progressbar, { + version: "1.7.1", + defaults: { + value: 0 + } +}); + +})(jQuery); +/* + * jQuery UI Effects 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/ + */ +;jQuery.effects || (function($) { + +$.effects = { + version: "1.7.1", + + // Saves a set of properties in a data storage + save: function(element, set) { + for(var i=0; i < set.length; i++) { + if(set[i] !== null) element.data("ec.storage."+set[i], element[0].style[set[i]]); + } + }, + + // Restores a set of previously saved properties from a data storage + restore: function(element, set) { + for(var i=0; i < set.length; i++) { + if(set[i] !== null) element.css(set[i], element.data("ec.storage."+set[i])); + } + }, + + setMode: function(el, mode) { + if (mode == 'toggle') mode = el.is(':hidden') ? 'show' : 'hide'; // Set for toggle + return mode; + }, + + getBaseline: function(origin, original) { // Translates a [top,left] array into a baseline value + // this should be a little more flexible in the future to handle a string & hash + var y, x; + switch (origin[0]) { + case 'top': y = 0; break; + case 'middle': y = 0.5; break; + case 'bottom': y = 1; break; + default: y = origin[0] / original.height; + }; + switch (origin[1]) { + case 'left': x = 0; break; + case 'center': x = 0.5; break; + case 'right': x = 1; break; + default: x = origin[1] / original.width; + }; + return {x: x, y: y}; + }, + + // Wraps the element around a wrapper that copies position properties + createWrapper: function(element) { + + //if the element is already wrapped, return it + if (element.parent().is('.ui-effects-wrapper')) + return element.parent(); + + //Cache width,height and float properties of the element, and create a wrapper around it + var props = { width: element.outerWidth(true), height: element.outerHeight(true), 'float': element.css('float') }; + element.wrap('
    '); + var wrapper = element.parent(); + + //Transfer the positioning of the element to the wrapper + if (element.css('position') == 'static') { + wrapper.css({ position: 'relative' }); + element.css({ position: 'relative'} ); + } else { + var top = element.css('top'); if(isNaN(parseInt(top,10))) top = 'auto'; + var left = element.css('left'); if(isNaN(parseInt(left,10))) left = 'auto'; + wrapper.css({ position: element.css('position'), top: top, left: left, zIndex: element.css('z-index') }).show(); + element.css({position: 'relative', top: 0, left: 0 }); + } + + wrapper.css(props); + return wrapper; + }, + + removeWrapper: function(element) { + if (element.parent().is('.ui-effects-wrapper')) + return element.parent().replaceWith(element); + return element; + }, + + setTransition: function(element, list, factor, value) { + value = value || {}; + $.each(list, function(i, x){ + unit = element.cssUnit(x); + if (unit[0] > 0) value[x] = unit[0] * factor + unit[1]; + }); + return value; + }, + + //Base function to animate from one class to another in a seamless transition + animateClass: function(value, duration, easing, callback) { + + var cb = (typeof easing == "function" ? easing : (callback ? callback : null)); + var ea = (typeof easing == "string" ? easing : null); + + return this.each(function() { + + var offset = {}; var that = $(this); var oldStyleAttr = that.attr("style") || ''; + if(typeof oldStyleAttr == 'object') oldStyleAttr = oldStyleAttr["cssText"]; /* Stupidly in IE, style is a object.. */ + if(value.toggle) { that.hasClass(value.toggle) ? value.remove = value.toggle : value.add = value.toggle; } + + //Let's get a style offset + var oldStyle = $.extend({}, (document.defaultView ? document.defaultView.getComputedStyle(this,null) : this.currentStyle)); + if(value.add) that.addClass(value.add); if(value.remove) that.removeClass(value.remove); + var newStyle = $.extend({}, (document.defaultView ? document.defaultView.getComputedStyle(this,null) : this.currentStyle)); + if(value.add) that.removeClass(value.add); if(value.remove) that.addClass(value.remove); + + // The main function to form the object for animation + for(var n in newStyle) { + if( typeof newStyle[n] != "function" && newStyle[n] /* No functions and null properties */ + && n.indexOf("Moz") == -1 && n.indexOf("length") == -1 /* No mozilla spezific render properties. */ + && newStyle[n] != oldStyle[n] /* Only values that have changed are used for the animation */ + && (n.match(/color/i) || (!n.match(/color/i) && !isNaN(parseInt(newStyle[n],10)))) /* Only things that can be parsed to integers or colors */ + && (oldStyle.position != "static" || (oldStyle.position == "static" && !n.match(/left|top|bottom|right/))) /* No need for positions when dealing with static positions */ + ) offset[n] = newStyle[n]; + } + + that.animate(offset, duration, ea, function() { // Animate the newly constructed offset object + // Change style attribute back to original. For stupid IE, we need to clear the damn object. + if(typeof $(this).attr("style") == 'object') { $(this).attr("style")["cssText"] = ""; $(this).attr("style")["cssText"] = oldStyleAttr; } else $(this).attr("style", oldStyleAttr); + if(value.add) $(this).addClass(value.add); if(value.remove) $(this).removeClass(value.remove); + if(cb) cb.apply(this, arguments); + }); + + }); + } +}; + + +function _normalizeArguments(a, m) { + + var o = a[1] && a[1].constructor == Object ? a[1] : {}; if(m) o.mode = m; + var speed = a[1] && a[1].constructor != Object ? a[1] : (o.duration ? o.duration : a[2]); //either comes from options.duration or the secon/third argument + speed = $.fx.off ? 0 : typeof speed === "number" ? speed : $.fx.speeds[speed] || $.fx.speeds._default; + var callback = o.callback || ( $.isFunction(a[1]) && a[1] ) || ( $.isFunction(a[2]) && a[2] ) || ( $.isFunction(a[3]) && a[3] ); + + return [a[0], o, speed, callback]; + +} + +//Extend the methods of jQuery +$.fn.extend({ + + //Save old methods + _show: $.fn.show, + _hide: $.fn.hide, + __toggle: $.fn.toggle, + _addClass: $.fn.addClass, + _removeClass: $.fn.removeClass, + _toggleClass: $.fn.toggleClass, + + // New effect methods + effect: function(fx, options, speed, callback) { + return $.effects[fx] ? $.effects[fx].call(this, {method: fx, options: options || {}, duration: speed, callback: callback }) : null; + }, + + show: function() { + if(!arguments[0] || (arguments[0].constructor == Number || (/(slow|normal|fast)/).test(arguments[0]))) + return this._show.apply(this, arguments); + else { + return this.effect.apply(this, _normalizeArguments(arguments, 'show')); + } + }, + + hide: function() { + if(!arguments[0] || (arguments[0].constructor == Number || (/(slow|normal|fast)/).test(arguments[0]))) + return this._hide.apply(this, arguments); + else { + return this.effect.apply(this, _normalizeArguments(arguments, 'hide')); + } + }, + + toggle: function(){ + if(!arguments[0] || (arguments[0].constructor == Number || (/(slow|normal|fast)/).test(arguments[0])) || (arguments[0].constructor == Function)) + return this.__toggle.apply(this, arguments); + else { + return this.effect.apply(this, _normalizeArguments(arguments, 'toggle')); + } + }, + + addClass: function(classNames, speed, easing, callback) { + return speed ? $.effects.animateClass.apply(this, [{ add: classNames },speed,easing,callback]) : this._addClass(classNames); + }, + removeClass: function(classNames,speed,easing,callback) { + return speed ? $.effects.animateClass.apply(this, [{ remove: classNames },speed,easing,callback]) : this._removeClass(classNames); + }, + toggleClass: function(classNames,speed,easing,callback) { + return ( (typeof speed !== "boolean") && speed ) ? $.effects.animateClass.apply(this, [{ toggle: classNames },speed,easing,callback]) : this._toggleClass(classNames, speed); + }, + morph: function(remove,add,speed,easing,callback) { + return $.effects.animateClass.apply(this, [{ add: add, remove: remove },speed,easing,callback]); + }, + switchClass: function() { + return this.morph.apply(this, arguments); + }, + + // helper functions + cssUnit: function(key) { + var style = this.css(key), val = []; + $.each( ['em','px','%','pt'], function(i, unit){ + if(style.indexOf(unit) > 0) + val = [parseFloat(style), unit]; + }); + return val; + } +}); + +/* + * jQuery Color Animations + * Copyright 2007 John Resig + * Released under the MIT and GPL licenses. + */ + +// We override the animation for all of these color styles +$.each(['backgroundColor', 'borderBottomColor', 'borderLeftColor', 'borderRightColor', 'borderTopColor', 'color', 'outlineColor'], function(i,attr){ + $.fx.step[attr] = function(fx) { + if ( fx.state == 0 ) { + fx.start = getColor( fx.elem, attr ); + fx.end = getRGB( fx.end ); + } + + fx.elem.style[attr] = "rgb(" + [ + Math.max(Math.min( parseInt((fx.pos * (fx.end[0] - fx.start[0])) + fx.start[0],10), 255), 0), + Math.max(Math.min( parseInt((fx.pos * (fx.end[1] - fx.start[1])) + fx.start[1],10), 255), 0), + Math.max(Math.min( parseInt((fx.pos * (fx.end[2] - fx.start[2])) + fx.start[2],10), 255), 0) + ].join(",") + ")"; + }; +}); + +// Color Conversion functions from highlightFade +// By Blair Mitchelmore +// http://jquery.offput.ca/highlightFade/ + +// Parse strings looking for color tuples [255,255,255] +function getRGB(color) { + var result; + + // Check if we're already dealing with an array of colors + if ( color && color.constructor == Array && color.length == 3 ) + return color; + + // Look for rgb(num,num,num) + if (result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color)) + return [parseInt(result[1],10), parseInt(result[2],10), parseInt(result[3],10)]; + + // Look for rgb(num%,num%,num%) + if (result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(color)) + return [parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55]; + + // Look for #a0b1c2 + if (result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color)) + return [parseInt(result[1],16), parseInt(result[2],16), parseInt(result[3],16)]; + + // Look for #fff + if (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color)) + return [parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16)]; + + // Look for rgba(0, 0, 0, 0) == transparent in Safari 3 + if (result = /rgba\(0, 0, 0, 0\)/.exec(color)) + return colors['transparent']; + + // Otherwise, we're most likely dealing with a named color + return colors[$.trim(color).toLowerCase()]; +} + +function getColor(elem, attr) { + var color; + + do { + color = $.curCSS(elem, attr); + + // Keep going until we find an element that has color, or we hit the body + if ( color != '' && color != 'transparent' || $.nodeName(elem, "body") ) + break; + + attr = "backgroundColor"; + } while ( elem = elem.parentNode ); + + return getRGB(color); +}; + +// Some named colors to work with +// From Interface by Stefan Petre +// http://interface.eyecon.ro/ + +var colors = { + aqua:[0,255,255], + azure:[240,255,255], + beige:[245,245,220], + black:[0,0,0], + blue:[0,0,255], + brown:[165,42,42], + cyan:[0,255,255], + darkblue:[0,0,139], + darkcyan:[0,139,139], + darkgrey:[169,169,169], + darkgreen:[0,100,0], + darkkhaki:[189,183,107], + darkmagenta:[139,0,139], + darkolivegreen:[85,107,47], + darkorange:[255,140,0], + darkorchid:[153,50,204], + darkred:[139,0,0], + darksalmon:[233,150,122], + darkviolet:[148,0,211], + fuchsia:[255,0,255], + gold:[255,215,0], + green:[0,128,0], + indigo:[75,0,130], + khaki:[240,230,140], + lightblue:[173,216,230], + lightcyan:[224,255,255], + lightgreen:[144,238,144], + lightgrey:[211,211,211], + lightpink:[255,182,193], + lightyellow:[255,255,224], + lime:[0,255,0], + magenta:[255,0,255], + maroon:[128,0,0], + navy:[0,0,128], + olive:[128,128,0], + orange:[255,165,0], + pink:[255,192,203], + purple:[128,0,128], + violet:[128,0,128], + red:[255,0,0], + silver:[192,192,192], + white:[255,255,255], + yellow:[255,255,0], + transparent: [255,255,255] +}; + +/* + * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/ + * + * Uses the built in easing capabilities added In jQuery 1.1 + * to offer multiple easing options + * + * TERMS OF USE - jQuery Easing + * + * Open source under the BSD License. + * + * Copyright 2008 George McGinley Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the author nor the names of contributors may be used to endorse + * or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * +*/ + +// t: current time, b: begInnIng value, c: change In value, d: duration +$.easing.jswing = $.easing.swing; + +$.extend($.easing, +{ + def: 'easeOutQuad', + swing: function (x, t, b, c, d) { + //alert($.easing.default); + return $.easing[$.easing.def](x, t, b, c, d); + }, + easeInQuad: function (x, t, b, c, d) { + return c*(t/=d)*t + b; + }, + easeOutQuad: function (x, t, b, c, d) { + return -c *(t/=d)*(t-2) + b; + }, + easeInOutQuad: function (x, t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t + b; + return -c/2 * ((--t)*(t-2) - 1) + b; + }, + easeInCubic: function (x, t, b, c, d) { + return c*(t/=d)*t*t + b; + }, + easeOutCubic: function (x, t, b, c, d) { + return c*((t=t/d-1)*t*t + 1) + b; + }, + easeInOutCubic: function (x, t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t*t + b; + return c/2*((t-=2)*t*t + 2) + b; + }, + easeInQuart: function (x, t, b, c, d) { + return c*(t/=d)*t*t*t + b; + }, + easeOutQuart: function (x, t, b, c, d) { + return -c * ((t=t/d-1)*t*t*t - 1) + b; + }, + easeInOutQuart: function (x, t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t*t*t + b; + return -c/2 * ((t-=2)*t*t*t - 2) + b; + }, + easeInQuint: function (x, t, b, c, d) { + return c*(t/=d)*t*t*t*t + b; + }, + easeOutQuint: function (x, t, b, c, d) { + return c*((t=t/d-1)*t*t*t*t + 1) + b; + }, + easeInOutQuint: function (x, t, b, c, d) { + if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b; + return c/2*((t-=2)*t*t*t*t + 2) + b; + }, + easeInSine: function (x, t, b, c, d) { + return -c * Math.cos(t/d * (Math.PI/2)) + c + b; + }, + easeOutSine: function (x, t, b, c, d) { + return c * Math.sin(t/d * (Math.PI/2)) + b; + }, + easeInOutSine: function (x, t, b, c, d) { + return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b; + }, + easeInExpo: function (x, t, b, c, d) { + return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b; + }, + easeOutExpo: function (x, t, b, c, d) { + return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b; + }, + easeInOutExpo: function (x, t, b, c, d) { + if (t==0) return b; + if (t==d) return b+c; + if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b; + return c/2 * (-Math.pow(2, -10 * --t) + 2) + b; + }, + easeInCirc: function (x, t, b, c, d) { + return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b; + }, + easeOutCirc: function (x, t, b, c, d) { + return c * Math.sqrt(1 - (t=t/d-1)*t) + b; + }, + easeInOutCirc: function (x, t, b, c, d) { + if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b; + return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b; + }, + easeInElastic: function (x, t, b, c, d) { + var s=1.70158;var p=0;var a=c; + if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; + if (a < Math.abs(c)) { a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (c/a); + return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; + }, + easeOutElastic: function (x, t, b, c, d) { + var s=1.70158;var p=0;var a=c; + if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; + if (a < Math.abs(c)) { a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (c/a); + return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b; + }, + easeInOutElastic: function (x, t, b, c, d) { + var s=1.70158;var p=0;var a=c; + if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5); + if (a < Math.abs(c)) { a=c; var s=p/4; } + else var s = p/(2*Math.PI) * Math.asin (c/a); + if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; + return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b; + }, + easeInBack: function (x, t, b, c, d, s) { + if (s == undefined) s = 1.70158; + return c*(t/=d)*t*((s+1)*t - s) + b; + }, + easeOutBack: function (x, t, b, c, d, s) { + if (s == undefined) s = 1.70158; + return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b; + }, + easeInOutBack: function (x, t, b, c, d, s) { + if (s == undefined) s = 1.70158; + if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b; + return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b; + }, + easeInBounce: function (x, t, b, c, d) { + return c - $.easing.easeOutBounce (x, d-t, 0, c, d) + b; + }, + easeOutBounce: function (x, t, b, c, d) { + if ((t/=d) < (1/2.75)) { + return c*(7.5625*t*t) + b; + } else if (t < (2/2.75)) { + return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b; + } else if (t < (2.5/2.75)) { + return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b; + } else { + return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b; + } + }, + easeInOutBounce: function (x, t, b, c, d) { + if (t < d/2) return $.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b; + return $.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b; + } +}); + +/* + * + * TERMS OF USE - EASING EQUATIONS + * + * Open source under the BSD License. + * + * Copyright 2001 Robert Penner + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the author nor the names of contributors may be used to endorse + * or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +})(jQuery); +/* + * jQuery UI Effects Blind 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Blind + * + * Depends: + * effects.core.js + */ +(function($) { + +$.effects.blind = function(o) { + + return this.queue(function() { + + // Create element + var el = $(this), props = ['position','top','left']; + + // Set options + var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode + var direction = o.options.direction || 'vertical'; // Default direction + + // Adjust + $.effects.save(el, props); el.show(); // Save & Show + var wrapper = $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper + var ref = (direction == 'vertical') ? 'height' : 'width'; + var distance = (direction == 'vertical') ? wrapper.height() : wrapper.width(); + if(mode == 'show') wrapper.css(ref, 0); // Shift + + // Animation + var animation = {}; + animation[ref] = mode == 'show' ? distance : 0; + + // Animate + wrapper.animate(animation, o.duration, o.options.easing, function() { + if(mode == 'hide') el.hide(); // Hide + $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore + if(o.callback) o.callback.apply(el[0], arguments); // Callback + el.dequeue(); + }); + + }); + +}; + +})(jQuery); +/* + * jQuery UI Effects Bounce 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Bounce + * + * Depends: + * effects.core.js + */ +(function($) { + +$.effects.bounce = function(o) { + + return this.queue(function() { + + // Create element + var el = $(this), props = ['position','top','left']; + + // Set options + var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode + var direction = o.options.direction || 'up'; // Default direction + var distance = o.options.distance || 20; // Default distance + var times = o.options.times || 5; // Default # of times + var speed = o.duration || 250; // Default speed per bounce + if (/show|hide/.test(mode)) props.push('opacity'); // Avoid touching opacity to prevent clearType and PNG issues in IE + + // Adjust + $.effects.save(el, props); el.show(); // Save & Show + $.effects.createWrapper(el); // Create Wrapper + var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left'; + var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg'; + var distance = o.options.distance || (ref == 'top' ? el.outerHeight({margin:true}) / 3 : el.outerWidth({margin:true}) / 3); + if (mode == 'show') el.css('opacity', 0).css(ref, motion == 'pos' ? -distance : distance); // Shift + if (mode == 'hide') distance = distance / (times * 2); + if (mode != 'hide') times--; + + // Animate + if (mode == 'show') { // Show Bounce + var animation = {opacity: 1}; + animation[ref] = (motion == 'pos' ? '+=' : '-=') + distance; + el.animate(animation, speed / 2, o.options.easing); + distance = distance / 2; + times--; + }; + for (var i = 0; i < times; i++) { // Bounces + var animation1 = {}, animation2 = {}; + animation1[ref] = (motion == 'pos' ? '-=' : '+=') + distance; + animation2[ref] = (motion == 'pos' ? '+=' : '-=') + distance; + el.animate(animation1, speed / 2, o.options.easing).animate(animation2, speed / 2, o.options.easing); + distance = (mode == 'hide') ? distance * 2 : distance / 2; + }; + if (mode == 'hide') { // Last Bounce + var animation = {opacity: 0}; + animation[ref] = (motion == 'pos' ? '-=' : '+=') + distance; + el.animate(animation, speed / 2, o.options.easing, function(){ + el.hide(); // Hide + $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore + if(o.callback) o.callback.apply(this, arguments); // Callback + }); + } else { + var animation1 = {}, animation2 = {}; + animation1[ref] = (motion == 'pos' ? '-=' : '+=') + distance; + animation2[ref] = (motion == 'pos' ? '+=' : '-=') + distance; + el.animate(animation1, speed / 2, o.options.easing).animate(animation2, speed / 2, o.options.easing, function(){ + $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore + if(o.callback) o.callback.apply(this, arguments); // Callback + }); + }; + el.queue('fx', function() { el.dequeue(); }); + el.dequeue(); + }); + +}; + +})(jQuery); +/* + * jQuery UI Effects Clip 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Clip + * + * Depends: + * effects.core.js + */ +(function($) { + +$.effects.clip = function(o) { + + return this.queue(function() { + + // Create element + var el = $(this), props = ['position','top','left','height','width']; + + // Set options + var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode + var direction = o.options.direction || 'vertical'; // Default direction + + // Adjust + $.effects.save(el, props); el.show(); // Save & Show + var wrapper = $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper + var animate = el[0].tagName == 'IMG' ? wrapper : el; + var ref = { + size: (direction == 'vertical') ? 'height' : 'width', + position: (direction == 'vertical') ? 'top' : 'left' + }; + var distance = (direction == 'vertical') ? animate.height() : animate.width(); + if(mode == 'show') { animate.css(ref.size, 0); animate.css(ref.position, distance / 2); } // Shift + + // Animation + var animation = {}; + animation[ref.size] = mode == 'show' ? distance : 0; + animation[ref.position] = mode == 'show' ? 0 : distance / 2; + + // Animate + animate.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() { + if(mode == 'hide') el.hide(); // Hide + $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore + if(o.callback) o.callback.apply(el[0], arguments); // Callback + el.dequeue(); + }}); + + }); + +}; + +})(jQuery); +/* + * jQuery UI Effects Drop 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Drop + * + * Depends: + * effects.core.js + */ +(function($) { + +$.effects.drop = function(o) { + + return this.queue(function() { + + // Create element + var el = $(this), props = ['position','top','left','opacity']; + + // Set options + var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode + var direction = o.options.direction || 'left'; // Default Direction + + // Adjust + $.effects.save(el, props); el.show(); // Save & Show + $.effects.createWrapper(el); // Create Wrapper + var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left'; + var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg'; + var distance = o.options.distance || (ref == 'top' ? el.outerHeight({margin:true}) / 2 : el.outerWidth({margin:true}) / 2); + if (mode == 'show') el.css('opacity', 0).css(ref, motion == 'pos' ? -distance : distance); // Shift + + // Animation + var animation = {opacity: mode == 'show' ? 1 : 0}; + animation[ref] = (mode == 'show' ? (motion == 'pos' ? '+=' : '-=') : (motion == 'pos' ? '-=' : '+=')) + distance; + + // Animate + el.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() { + if(mode == 'hide') el.hide(); // Hide + $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore + if(o.callback) o.callback.apply(this, arguments); // Callback + el.dequeue(); + }}); + + }); + +}; + +})(jQuery); +/* + * jQuery UI Effects Explode 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Explode + * + * Depends: + * effects.core.js + */ +(function($) { + +$.effects.explode = function(o) { + + return this.queue(function() { + + var rows = o.options.pieces ? Math.round(Math.sqrt(o.options.pieces)) : 3; + var cells = o.options.pieces ? Math.round(Math.sqrt(o.options.pieces)) : 3; + + o.options.mode = o.options.mode == 'toggle' ? ($(this).is(':visible') ? 'hide' : 'show') : o.options.mode; + var el = $(this).show().css('visibility', 'hidden'); + var offset = el.offset(); + + //Substract the margins - not fixing the problem yet. + offset.top -= parseInt(el.css("marginTop"),10) || 0; + offset.left -= parseInt(el.css("marginLeft"),10) || 0; + + var width = el.outerWidth(true); + var height = el.outerHeight(true); + + for(var i=0;i
') + .css({ + position: 'absolute', + visibility: 'visible', + left: -j*(width/cells), + top: -i*(height/rows) + }) + .parent() + .addClass('ui-effects-explode') + .css({ + position: 'absolute', + overflow: 'hidden', + width: width/cells, + height: height/rows, + left: offset.left + j*(width/cells) + (o.options.mode == 'show' ? (j-Math.floor(cells/2))*(width/cells) : 0), + top: offset.top + i*(height/rows) + (o.options.mode == 'show' ? (i-Math.floor(rows/2))*(height/rows) : 0), + opacity: o.options.mode == 'show' ? 0 : 1 + }).animate({ + left: offset.left + j*(width/cells) + (o.options.mode == 'show' ? 0 : (j-Math.floor(cells/2))*(width/cells)), + top: offset.top + i*(height/rows) + (o.options.mode == 'show' ? 0 : (i-Math.floor(rows/2))*(height/rows)), + opacity: o.options.mode == 'show' ? 1 : 0 + }, o.duration || 500); + } + } + + // Set a timeout, to call the callback approx. when the other animations have finished + setTimeout(function() { + + o.options.mode == 'show' ? el.css({ visibility: 'visible' }) : el.css({ visibility: 'visible' }).hide(); + if(o.callback) o.callback.apply(el[0]); // Callback + el.dequeue(); + + $('div.ui-effects-explode').remove(); + + }, o.duration || 500); + + + }); + +}; + +})(jQuery); +/* + * jQuery UI Effects Fold 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Fold + * + * Depends: + * effects.core.js + */ +(function($) { + +$.effects.fold = function(o) { + + return this.queue(function() { + + // Create element + var el = $(this), props = ['position','top','left']; + + // Set options + var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode + var size = o.options.size || 15; // Default fold size + var horizFirst = !(!o.options.horizFirst); // Ensure a boolean value + var duration = o.duration ? o.duration / 2 : $.fx.speeds._default / 2; + + // Adjust + $.effects.save(el, props); el.show(); // Save & Show + var wrapper = $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper + var widthFirst = ((mode == 'show') != horizFirst); + var ref = widthFirst ? ['width', 'height'] : ['height', 'width']; + var distance = widthFirst ? [wrapper.width(), wrapper.height()] : [wrapper.height(), wrapper.width()]; + var percent = /([0-9]+)%/.exec(size); + if(percent) size = parseInt(percent[1],10) / 100 * distance[mode == 'hide' ? 0 : 1]; + if(mode == 'show') wrapper.css(horizFirst ? {height: 0, width: size} : {height: size, width: 0}); // Shift + + // Animation + var animation1 = {}, animation2 = {}; + animation1[ref[0]] = mode == 'show' ? distance[0] : size; + animation2[ref[1]] = mode == 'show' ? distance[1] : 0; + + // Animate + wrapper.animate(animation1, duration, o.options.easing) + .animate(animation2, duration, o.options.easing, function() { + if(mode == 'hide') el.hide(); // Hide + $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore + if(o.callback) o.callback.apply(el[0], arguments); // Callback + el.dequeue(); + }); + + }); + +}; + +})(jQuery); +/* + * jQuery UI Effects Highlight 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Highlight + * + * Depends: + * effects.core.js + */ +(function($) { + +$.effects.highlight = function(o) { + + return this.queue(function() { + + // Create element + var el = $(this), props = ['backgroundImage','backgroundColor','opacity']; + + // Set options + var mode = $.effects.setMode(el, o.options.mode || 'show'); // Set Mode + var color = o.options.color || "#ffff99"; // Default highlight color + var oldColor = el.css("backgroundColor"); + + // Adjust + $.effects.save(el, props); el.show(); // Save & Show + el.css({backgroundImage: 'none', backgroundColor: color}); // Shift + + // Animation + var animation = {backgroundColor: oldColor }; + if (mode == "hide") animation['opacity'] = 0; + + // Animate + el.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() { + if(mode == "hide") el.hide(); + $.effects.restore(el, props); + if (mode == "show" && $.browser.msie) this.style.removeAttribute('filter'); + if(o.callback) o.callback.apply(this, arguments); + el.dequeue(); + }}); + + }); + +}; + +})(jQuery); +/* + * jQuery UI Effects Pulsate 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Pulsate + * + * Depends: + * effects.core.js + */ +(function($) { + +$.effects.pulsate = function(o) { + + return this.queue(function() { + + // Create element + var el = $(this); + + // Set options + var mode = $.effects.setMode(el, o.options.mode || 'show'); // Set Mode + var times = o.options.times || 5; // Default # of times + var duration = o.duration ? o.duration / 2 : $.fx.speeds._default / 2; + + // Adjust + if (mode == 'hide') times--; + if (el.is(':hidden')) { // Show fadeIn + el.css('opacity', 0); + el.show(); // Show + el.animate({opacity: 1}, duration, o.options.easing); + times = times-2; + } + + // Animate + for (var i = 0; i < times; i++) { // Pulsate + el.animate({opacity: 0}, duration, o.options.easing).animate({opacity: 1}, duration, o.options.easing); + }; + if (mode == 'hide') { // Last Pulse + el.animate({opacity: 0}, duration, o.options.easing, function(){ + el.hide(); // Hide + if(o.callback) o.callback.apply(this, arguments); // Callback + }); + } else { + el.animate({opacity: 0}, duration, o.options.easing).animate({opacity: 1}, duration, o.options.easing, function(){ + if(o.callback) o.callback.apply(this, arguments); // Callback + }); + }; + el.queue('fx', function() { el.dequeue(); }); + el.dequeue(); + }); + +}; + +})(jQuery); +/* + * jQuery UI Effects Scale 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Scale + * + * Depends: + * effects.core.js + */ +(function($) { + +$.effects.puff = function(o) { + + return this.queue(function() { + + // Create element + var el = $(this); + + // Set options + var options = $.extend(true, {}, o.options); + var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode + var percent = parseInt(o.options.percent,10) || 150; // Set default puff percent + options.fade = true; // It's not a puff if it doesn't fade! :) + var original = {height: el.height(), width: el.width()}; // Save original + + // Adjust + var factor = percent / 100; + el.from = (mode == 'hide') ? original : {height: original.height * factor, width: original.width * factor}; + + // Animation + options.from = el.from; + options.percent = (mode == 'hide') ? percent : 100; + options.mode = mode; + + // Animate + el.effect('scale', options, o.duration, o.callback); + el.dequeue(); + }); + +}; + +$.effects.scale = function(o) { + + return this.queue(function() { + + // Create element + var el = $(this); + + // Set options + var options = $.extend(true, {}, o.options); + var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode + var percent = parseInt(o.options.percent,10) || (parseInt(o.options.percent,10) == 0 ? 0 : (mode == 'hide' ? 0 : 100)); // Set default scaling percent + var direction = o.options.direction || 'both'; // Set default axis + var origin = o.options.origin; // The origin of the scaling + if (mode != 'effect') { // Set default origin and restore for show/hide + options.origin = origin || ['middle','center']; + options.restore = true; + } + var original = {height: el.height(), width: el.width()}; // Save original + el.from = o.options.from || (mode == 'show' ? {height: 0, width: 0} : original); // Default from state + + // Adjust + var factor = { // Set scaling factor + y: direction != 'horizontal' ? (percent / 100) : 1, + x: direction != 'vertical' ? (percent / 100) : 1 + }; + el.to = {height: original.height * factor.y, width: original.width * factor.x}; // Set to state + + if (o.options.fade) { // Fade option to support puff + if (mode == 'show') {el.from.opacity = 0; el.to.opacity = 1;}; + if (mode == 'hide') {el.from.opacity = 1; el.to.opacity = 0;}; + }; + + // Animation + options.from = el.from; options.to = el.to; options.mode = mode; + + // Animate + el.effect('size', options, o.duration, o.callback); + el.dequeue(); + }); + +}; + +$.effects.size = function(o) { + + return this.queue(function() { + + // Create element + var el = $(this), props = ['position','top','left','width','height','overflow','opacity']; + var props1 = ['position','top','left','overflow','opacity']; // Always restore + var props2 = ['width','height','overflow']; // Copy for children + var cProps = ['fontSize']; + var vProps = ['borderTopWidth', 'borderBottomWidth', 'paddingTop', 'paddingBottom']; + var hProps = ['borderLeftWidth', 'borderRightWidth', 'paddingLeft', 'paddingRight']; + + // Set options + var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode + var restore = o.options.restore || false; // Default restore + var scale = o.options.scale || 'both'; // Default scale mode + var origin = o.options.origin; // The origin of the sizing + var original = {height: el.height(), width: el.width()}; // Save original + el.from = o.options.from || original; // Default from state + el.to = o.options.to || original; // Default to state + // Adjust + if (origin) { // Calculate baseline shifts + var baseline = $.effects.getBaseline(origin, original); + el.from.top = (original.height - el.from.height) * baseline.y; + el.from.left = (original.width - el.from.width) * baseline.x; + el.to.top = (original.height - el.to.height) * baseline.y; + el.to.left = (original.width - el.to.width) * baseline.x; + }; + var factor = { // Set scaling factor + from: {y: el.from.height / original.height, x: el.from.width / original.width}, + to: {y: el.to.height / original.height, x: el.to.width / original.width} + }; + if (scale == 'box' || scale == 'both') { // Scale the css box + if (factor.from.y != factor.to.y) { // Vertical props scaling + props = props.concat(vProps); + el.from = $.effects.setTransition(el, vProps, factor.from.y, el.from); + el.to = $.effects.setTransition(el, vProps, factor.to.y, el.to); + }; + if (factor.from.x != factor.to.x) { // Horizontal props scaling + props = props.concat(hProps); + el.from = $.effects.setTransition(el, hProps, factor.from.x, el.from); + el.to = $.effects.setTransition(el, hProps, factor.to.x, el.to); + }; + }; + if (scale == 'content' || scale == 'both') { // Scale the content + if (factor.from.y != factor.to.y) { // Vertical props scaling + props = props.concat(cProps); + el.from = $.effects.setTransition(el, cProps, factor.from.y, el.from); + el.to = $.effects.setTransition(el, cProps, factor.to.y, el.to); + }; + }; + $.effects.save(el, restore ? props : props1); el.show(); // Save & Show + $.effects.createWrapper(el); // Create Wrapper + el.css('overflow','hidden').css(el.from); // Shift + + // Animate + if (scale == 'content' || scale == 'both') { // Scale the children + vProps = vProps.concat(['marginTop','marginBottom']).concat(cProps); // Add margins/font-size + hProps = hProps.concat(['marginLeft','marginRight']); // Add margins + props2 = props.concat(vProps).concat(hProps); // Concat + el.find("*[width]").each(function(){ + child = $(this); + if (restore) $.effects.save(child, props2); + var c_original = {height: child.height(), width: child.width()}; // Save original + child.from = {height: c_original.height * factor.from.y, width: c_original.width * factor.from.x}; + child.to = {height: c_original.height * factor.to.y, width: c_original.width * factor.to.x}; + if (factor.from.y != factor.to.y) { // Vertical props scaling + child.from = $.effects.setTransition(child, vProps, factor.from.y, child.from); + child.to = $.effects.setTransition(child, vProps, factor.to.y, child.to); + }; + if (factor.from.x != factor.to.x) { // Horizontal props scaling + child.from = $.effects.setTransition(child, hProps, factor.from.x, child.from); + child.to = $.effects.setTransition(child, hProps, factor.to.x, child.to); + }; + child.css(child.from); // Shift children + child.animate(child.to, o.duration, o.options.easing, function(){ + if (restore) $.effects.restore(child, props2); // Restore children + }); // Animate children + }); + }; + + // Animate + el.animate(el.to, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() { + if(mode == 'hide') el.hide(); // Hide + $.effects.restore(el, restore ? props : props1); $.effects.removeWrapper(el); // Restore + if(o.callback) o.callback.apply(this, arguments); // Callback + el.dequeue(); + }}); + + }); + +}; + +})(jQuery); +/* + * jQuery UI Effects Shake 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Shake + * + * Depends: + * effects.core.js + */ +(function($) { + +$.effects.shake = function(o) { + + return this.queue(function() { + + // Create element + var el = $(this), props = ['position','top','left']; + + // Set options + var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode + var direction = o.options.direction || 'left'; // Default direction + var distance = o.options.distance || 20; // Default distance + var times = o.options.times || 3; // Default # of times + var speed = o.duration || o.options.duration || 140; // Default speed per shake + + // Adjust + $.effects.save(el, props); el.show(); // Save & Show + $.effects.createWrapper(el); // Create Wrapper + var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left'; + var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg'; + + // Animation + var animation = {}, animation1 = {}, animation2 = {}; + animation[ref] = (motion == 'pos' ? '-=' : '+=') + distance; + animation1[ref] = (motion == 'pos' ? '+=' : '-=') + distance * 2; + animation2[ref] = (motion == 'pos' ? '-=' : '+=') + distance * 2; + + // Animate + el.animate(animation, speed, o.options.easing); + for (var i = 1; i < times; i++) { // Shakes + el.animate(animation1, speed, o.options.easing).animate(animation2, speed, o.options.easing); + }; + el.animate(animation1, speed, o.options.easing). + animate(animation, speed / 2, o.options.easing, function(){ // Last shake + $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore + if(o.callback) o.callback.apply(this, arguments); // Callback + }); + el.queue('fx', function() { el.dequeue(); }); + el.dequeue(); + }); + +}; + +})(jQuery); +/* + * jQuery UI Effects Slide 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Slide + * + * Depends: + * effects.core.js + */ +(function($) { + +$.effects.slide = function(o) { + + return this.queue(function() { + + // Create element + var el = $(this), props = ['position','top','left']; + + // Set options + var mode = $.effects.setMode(el, o.options.mode || 'show'); // Set Mode + var direction = o.options.direction || 'left'; // Default Direction + + // Adjust + $.effects.save(el, props); el.show(); // Save & Show + $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper + var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left'; + var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg'; + var distance = o.options.distance || (ref == 'top' ? el.outerHeight({margin:true}) : el.outerWidth({margin:true})); + if (mode == 'show') el.css(ref, motion == 'pos' ? -distance : distance); // Shift + + // Animation + var animation = {}; + animation[ref] = (mode == 'show' ? (motion == 'pos' ? '+=' : '-=') : (motion == 'pos' ? '-=' : '+=')) + distance; + + // Animate + el.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() { + if(mode == 'hide') el.hide(); // Hide + $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore + if(o.callback) o.callback.apply(this, arguments); // Callback + el.dequeue(); + }}); + + }); + +}; + +})(jQuery); +/* + * jQuery UI Effects Transfer 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Effects/Transfer + * + * Depends: + * effects.core.js + */ +(function($) { + +$.effects.transfer = function(o) { + return this.queue(function() { + var elem = $(this), + target = $(o.options.to), + endPosition = target.offset(), + animation = { + top: endPosition.top, + left: endPosition.left, + height: target.innerHeight(), + width: target.innerWidth() + }, + startPosition = elem.offset(), + transfer = $('
') + .appendTo(document.body) + .addClass(o.options.className) + .css({ + top: startPosition.top, + left: startPosition.left, + height: elem.innerHeight(), + width: elem.innerWidth(), + position: 'absolute' + }) + .animate(animation, o.duration, o.options.easing, function() { + transfer.remove(); + (o.callback && o.callback.apply(elem[0], arguments)); + elem.dequeue(); + }); + }); +}; + +})(jQuery); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/ui.accordion.js b/js2/mwEmbed/jquery/jquery.ui/ui/ui.accordion.js new file mode 100644 index 0000000000..0e94df1642 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/ui.accordion.js @@ -0,0 +1,477 @@ +/* + * jQuery UI Accordion 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Accordion + * + * Depends: + * ui.core.js + */ +(function($) { + +$.widget("ui.accordion", { + + _init: function() { + + var o = this.options, self = this; + this.running = 0; + + // if the user set the alwaysOpen option on init + // then we need to set the collapsible option + // if they set both on init, collapsible will take priority + if (o.collapsible == $.ui.accordion.defaults.collapsible && + o.alwaysOpen != $.ui.accordion.defaults.alwaysOpen) { + o.collapsible = !o.alwaysOpen; + } + + if ( o.navigation ) { + var current = this.element.find("a").filter(o.navigationFilter); + if ( current.length ) { + if ( current.filter(o.header).length ) { + this.active = current; + } else { + this.active = current.parent().parent().prev(); + current.addClass("ui-accordion-content-active"); + } + } + } + + this.element.addClass("ui-accordion ui-widget ui-helper-reset"); + + // in lack of child-selectors in CSS we need to mark top-LIs in a UL-accordion for some IE-fix + if (this.element[0].nodeName == "UL") { + this.element.children("li").addClass("ui-accordion-li-fix"); + } + + this.headers = this.element.find(o.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all") + .bind("mouseenter.accordion", function(){ $(this).addClass('ui-state-hover'); }) + .bind("mouseleave.accordion", function(){ $(this).removeClass('ui-state-hover'); }) + .bind("focus.accordion", function(){ $(this).addClass('ui-state-focus'); }) + .bind("blur.accordion", function(){ $(this).removeClass('ui-state-focus'); }); + + this.headers + .next() + .addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom"); + + this.active = this._findActive(this.active || o.active).toggleClass("ui-state-default").toggleClass("ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top"); + this.active.next().addClass('ui-accordion-content-active'); + + //Append icon elements + $("").addClass("ui-icon " + o.icons.header).prependTo(this.headers); + this.active.find(".ui-icon").toggleClass(o.icons.header).toggleClass(o.icons.headerSelected); + + // IE7-/Win - Extra vertical space in lists fixed + if ($.browser.msie) { + this.element.find('a').css('zoom', '1'); + } + + this.resize(); + + //ARIA + this.element.attr('role','tablist'); + + this.headers + .attr('role','tab') + .bind('keydown', function(event) { return self._keydown(event); }) + .next() + .attr('role','tabpanel'); + + this.headers + .not(this.active || "") + .attr('aria-expanded','false') + .attr("tabIndex", "-1") + .next() + .hide(); + + // make sure at least one header is in the tab order + if (!this.active.length) { + this.headers.eq(0).attr('tabIndex','0'); + } else { + this.active + .attr('aria-expanded','true') + .attr('tabIndex', '0'); + } + + // only need links in taborder for Safari + if (!$.browser.safari) + this.headers.find('a').attr('tabIndex','-1'); + + if (o.event) { + this.headers.bind((o.event) + ".accordion", function(event) { return self._clickHandler.call(self, event, this); }); + } + + }, + + destroy: function() { + var o = this.options; + + this.element + .removeClass("ui-accordion ui-widget ui-helper-reset") + .removeAttr("role") + .unbind('.accordion') + .removeData('accordion'); + + this.headers + .unbind(".accordion") + .removeClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-corner-top") + .removeAttr("role").removeAttr("aria-expanded").removeAttr("tabindex"); + + this.headers.find("a").removeAttr("tabindex"); + this.headers.children(".ui-icon").remove(); + var contents = this.headers.next().css("display", "").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active"); + if (o.autoHeight || o.fillHeight) { + contents.css("height", ""); + } + }, + + _setData: function(key, value) { + if(key == 'alwaysOpen') { key = 'collapsible'; value = !value; } + $.widget.prototype._setData.apply(this, arguments); + }, + + _keydown: function(event) { + + var o = this.options, keyCode = $.ui.keyCode; + + if (o.disabled || event.altKey || event.ctrlKey) + return; + + var length = this.headers.length; + var currentIndex = this.headers.index(event.target); + var toFocus = false; + + switch(event.keyCode) { + case keyCode.RIGHT: + case keyCode.DOWN: + toFocus = this.headers[(currentIndex + 1) % length]; + break; + case keyCode.LEFT: + case keyCode.UP: + toFocus = this.headers[(currentIndex - 1 + length) % length]; + break; + case keyCode.SPACE: + case keyCode.ENTER: + return this._clickHandler({ target: event.target }, event.target); + } + + if (toFocus) { + $(event.target).attr('tabIndex','-1'); + $(toFocus).attr('tabIndex','0'); + toFocus.focus(); + return false; + } + + return true; + + }, + + resize: function() { + + var o = this.options, maxHeight; + + if (o.fillSpace) { + + if($.browser.msie) { var defOverflow = this.element.parent().css('overflow'); this.element.parent().css('overflow', 'hidden'); } + maxHeight = this.element.parent().height(); + if($.browser.msie) { this.element.parent().css('overflow', defOverflow); } + + this.headers.each(function() { + maxHeight -= $(this).outerHeight(); + }); + + var maxPadding = 0; + this.headers.next().each(function() { + maxPadding = Math.max(maxPadding, $(this).innerHeight() - $(this).height()); + }).height(Math.max(0, maxHeight - maxPadding)) + .css('overflow', 'auto'); + + } else if ( o.autoHeight ) { + maxHeight = 0; + this.headers.next().each(function() { + maxHeight = Math.max(maxHeight, $(this).outerHeight()); + }).height(maxHeight); + } + + }, + + activate: function(index) { + // call clickHandler with custom event + var active = this._findActive(index)[0]; + this._clickHandler({ target: active }, active); + }, + + _findActive: function(selector) { + return selector + ? typeof selector == "number" + ? this.headers.filter(":eq(" + selector + ")") + : this.headers.not(this.headers.not(selector)) + : selector === false + ? $([]) + : this.headers.filter(":eq(0)"); + }, + + _clickHandler: function(event, target) { + + var o = this.options; + if (o.disabled) return false; + + // called only when using activate(false) to close all parts programmatically + if (!event.target && o.collapsible) { + this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all") + .find(".ui-icon").removeClass(o.icons.headerSelected).addClass(o.icons.header); + this.active.next().addClass('ui-accordion-content-active'); + var toHide = this.active.next(), + data = { + options: o, + newHeader: $([]), + oldHeader: o.active, + newContent: $([]), + oldContent: toHide + }, + toShow = (this.active = $([])); + this._toggle(toShow, toHide, data); + return false; + } + + // get the click target + var clicked = $(event.currentTarget || target); + var clickedIsActive = clicked[0] == this.active[0]; + + // if animations are still active, or the active header is the target, ignore click + if (this.running || (!o.collapsible && clickedIsActive)) { + return false; + } + + // switch classes + this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all") + .find(".ui-icon").removeClass(o.icons.headerSelected).addClass(o.icons.header); + this.active.next().addClass('ui-accordion-content-active'); + if (!clickedIsActive) { + clicked.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top") + .find(".ui-icon").removeClass(o.icons.header).addClass(o.icons.headerSelected); + clicked.next().addClass('ui-accordion-content-active'); + } + + // find elements to show and hide + var toShow = clicked.next(), + toHide = this.active.next(), + data = { + options: o, + newHeader: clickedIsActive && o.collapsible ? $([]) : clicked, + oldHeader: this.active, + newContent: clickedIsActive && o.collapsible ? $([]) : toShow.find('> *'), + oldContent: toHide.find('> *') + }, + down = this.headers.index( this.active[0] ) > this.headers.index( clicked[0] ); + + this.active = clickedIsActive ? $([]) : clicked; + this._toggle(toShow, toHide, data, clickedIsActive, down); + + return false; + + }, + + _toggle: function(toShow, toHide, data, clickedIsActive, down) { + + var o = this.options, self = this; + + this.toShow = toShow; + this.toHide = toHide; + this.data = data; + + var complete = function() { if(!self) return; return self._completed.apply(self, arguments); }; + + // trigger changestart event + this._trigger("changestart", null, this.data); + + // count elements to animate + this.running = toHide.size() === 0 ? toShow.size() : toHide.size(); + + if (o.animated) { + + var animOptions = {}; + + if ( o.collapsible && clickedIsActive ) { + animOptions = { + toShow: $([]), + toHide: toHide, + complete: complete, + down: down, + autoHeight: o.autoHeight || o.fillSpace + }; + } else { + animOptions = { + toShow: toShow, + toHide: toHide, + complete: complete, + down: down, + autoHeight: o.autoHeight || o.fillSpace + }; + } + + if (!o.proxied) { + o.proxied = o.animated; + } + + if (!o.proxiedDuration) { + o.proxiedDuration = o.duration; + } + + o.animated = $.isFunction(o.proxied) ? + o.proxied(animOptions) : o.proxied; + + o.duration = $.isFunction(o.proxiedDuration) ? + o.proxiedDuration(animOptions) : o.proxiedDuration; + + var animations = $.ui.accordion.animations, + duration = o.duration, + easing = o.animated; + + if (!animations[easing]) { + animations[easing] = function(options) { + this.slide(options, { + easing: easing, + duration: duration || 700 + }); + }; + } + + animations[easing](animOptions); + + } else { + + if (o.collapsible && clickedIsActive) { + toShow.toggle(); + } else { + toHide.hide(); + toShow.show(); + } + + complete(true); + + } + + toHide.prev().attr('aria-expanded','false').attr("tabIndex", "-1").blur(); + toShow.prev().attr('aria-expanded','true').attr("tabIndex", "0").focus(); + + }, + + _completed: function(cancel) { + + var o = this.options; + + this.running = cancel ? 0 : --this.running; + if (this.running) return; + + if (o.clearStyle) { + this.toShow.add(this.toHide).css({ + height: "", + overflow: "" + }); + } + + this._trigger('change', null, this.data); + } + +}); + + +$.extend($.ui.accordion, { + version: "1.7.1", + defaults: { + active: null, + alwaysOpen: true, //deprecated, use collapsible + animated: 'slide', + autoHeight: true, + clearStyle: false, + collapsible: false, + event: "click", + fillSpace: false, + header: "> li > :first-child,> :not(li):even", + icons: { + header: "ui-icon-triangle-1-e", + headerSelected: "ui-icon-triangle-1-s" + }, + navigation: false, + navigationFilter: function() { + return this.href.toLowerCase() == location.href.toLowerCase(); + } + }, + animations: { + slide: function(options, additions) { + options = $.extend({ + easing: "swing", + duration: 300 + }, options, additions); + if ( !options.toHide.size() ) { + options.toShow.animate({height: "show"}, options); + return; + } + if ( !options.toShow.size() ) { + options.toHide.animate({height: "hide"}, options); + return; + } + var overflow = options.toShow.css('overflow'), + percentDone, + showProps = {}, + hideProps = {}, + fxAttrs = [ "height", "paddingTop", "paddingBottom" ], + originalWidth; + // fix width before calculating height of hidden element + var s = options.toShow; + originalWidth = s[0].style.width; + s.width( parseInt(s.parent().width(),10) - parseInt(s.css("paddingLeft"),10) - parseInt(s.css("paddingRight"),10) - (parseInt(s.css("borderLeftWidth"),10) || 0) - (parseInt(s.css("borderRightWidth"),10) || 0) ); + + $.each(fxAttrs, function(i, prop) { + hideProps[prop] = 'hide'; + + var parts = ('' + $.css(options.toShow[0], prop)).match(/^([\d+-.]+)(.*)$/); + showProps[prop] = { + value: parts[1], + unit: parts[2] || 'px' + }; + }); + options.toShow.css({ height: 0, overflow: 'hidden' }).show(); + options.toHide.filter(":hidden").each(options.complete).end().filter(":visible").animate(hideProps,{ + step: function(now, settings) { + // only calculate the percent when animating height + // IE gets very inconsistent results when animating elements + // with small values, which is common for padding + if (settings.prop == 'height') { + percentDone = (settings.now - settings.start) / (settings.end - settings.start); + } + + options.toShow[0].style[settings.prop] = + (percentDone * showProps[settings.prop].value) + showProps[settings.prop].unit; + }, + duration: options.duration, + easing: options.easing, + complete: function() { + if ( !options.autoHeight ) { + options.toShow.css("height", ""); + } + options.toShow.css("width", originalWidth); + options.toShow.css({overflow: overflow}); + options.complete(); + } + }); + }, + bounceslide: function(options) { + this.slide(options, { + easing: options.down ? "easeOutBounce" : "swing", + duration: options.down ? 1000 : 200 + }); + }, + easeslide: function(options) { + this.slide(options, { + easing: "easeinout", + duration: 700 + }); + } + } +}); + +})(jQuery); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/ui.core.js b/js2/mwEmbed/jquery/jquery.ui/ui/ui.core.js new file mode 100644 index 0000000000..601d0a85c4 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/ui.core.js @@ -0,0 +1,519 @@ +/* + * jQuery UI 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI + */ +;jQuery.ui || (function($) { + +var _remove = $.fn.remove, + isFF2 = $.browser.mozilla && (parseFloat($.browser.version) < 1.9); + +//Helper functions and ui object +$.ui = { + version: "1.7.1", + + // $.ui.plugin is deprecated. Use the proxy pattern instead. + plugin: { + add: function(module, option, set) { + var proto = $.ui[module].prototype; + for(var i in set) { + proto.plugins[i] = proto.plugins[i] || []; + proto.plugins[i].push([option, set[i]]); + } + }, + call: function(instance, name, args) { + var set = instance.plugins[name]; + if(!set || !instance.element[0].parentNode) { return; } + + for (var i = 0; i < set.length; i++) { + if (instance.options[set[i][0]]) { + set[i][1].apply(instance.element, args); + } + } + } + }, + + contains: function(a, b) { + return document.compareDocumentPosition + ? a.compareDocumentPosition(b) & 16 + : a !== b && a.contains(b); + }, + + hasScroll: function(el, a) { + + //If overflow is hidden, the element might have extra content, but the user wants to hide it + if ($(el).css('overflow') == 'hidden') { return false; } + + var scroll = (a && a == 'left') ? 'scrollLeft' : 'scrollTop', + has = false; + + if (el[scroll] > 0) { return true; } + + // TODO: determine which cases actually cause this to happen + // if the element doesn't have the scroll set, see if it's possible to + // set the scroll + el[scroll] = 1; + has = (el[scroll] > 0); + el[scroll] = 0; + return has; + }, + + isOverAxis: function(x, reference, size) { + //Determines when x coordinate is over "b" element axis + return (x > reference) && (x < (reference + size)); + }, + + isOver: function(y, x, top, left, height, width) { + //Determines when x, y coordinates is over "b" element + return $.ui.isOverAxis(y, top, height) && $.ui.isOverAxis(x, left, width); + }, + + keyCode: { + BACKSPACE: 8, + CAPS_LOCK: 20, + COMMA: 188, + CONTROL: 17, + DELETE: 46, + DOWN: 40, + END: 35, + ENTER: 13, + ESCAPE: 27, + HOME: 36, + INSERT: 45, + LEFT: 37, + NUMPAD_ADD: 107, + NUMPAD_DECIMAL: 110, + NUMPAD_DIVIDE: 111, + NUMPAD_ENTER: 108, + NUMPAD_MULTIPLY: 106, + NUMPAD_SUBTRACT: 109, + PAGE_DOWN: 34, + PAGE_UP: 33, + PERIOD: 190, + RIGHT: 39, + SHIFT: 16, + SPACE: 32, + TAB: 9, + UP: 38 + } +}; + +// WAI-ARIA normalization +if (isFF2) { + var attr = $.attr, + removeAttr = $.fn.removeAttr, + ariaNS = "http://www.w3.org/2005/07/aaa", + ariaState = /^aria-/, + ariaRole = /^wairole:/; + + $.attr = function(elem, name, value) { + var set = value !== undefined; + + return (name == 'role' + ? (set + ? attr.call(this, elem, name, "wairole:" + value) + : (attr.apply(this, arguments) || "").replace(ariaRole, "")) + : (ariaState.test(name) + ? (set + ? elem.setAttributeNS(ariaNS, + name.replace(ariaState, "aaa:"), value) + : attr.call(this, elem, name.replace(ariaState, "aaa:"))) + : attr.apply(this, arguments))); + }; + + $.fn.removeAttr = function(name) { + return (ariaState.test(name) + ? this.each(function() { + this.removeAttributeNS(ariaNS, name.replace(ariaState, "")); + }) : removeAttr.call(this, name)); + }; +} + +//jQuery plugins +$.fn.extend({ + remove: function() { + // Safari has a native remove event which actually removes DOM elements, + // so we have to use triggerHandler instead of trigger (#3037). + $("*", this).add(this).each(function() { + $(this).triggerHandler("remove"); + }); + return _remove.apply(this, arguments ); + }, + + enableSelection: function() { + return this + .attr('unselectable', 'off') + .css('MozUserSelect', '') + .unbind('selectstart.ui'); + }, + + disableSelection: function() { + return this + .attr('unselectable', 'on') + .css('MozUserSelect', 'none') + .bind('selectstart.ui', function() { return false; }); + }, + + scrollParent: function() { + var scrollParent; + if(($.browser.msie && (/(static|relative)/).test(this.css('position'))) || (/absolute/).test(this.css('position'))) { + scrollParent = this.parents().filter(function() { + return (/(relative|absolute|fixed)/).test($.curCSS(this,'position',1)) && (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1)); + }).eq(0); + } else { + scrollParent = this.parents().filter(function() { + return (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1)); + }).eq(0); + } + + return (/fixed/).test(this.css('position')) || !scrollParent.length ? $(document) : scrollParent; + } +}); + + +//Additional selectors +$.extend($.expr[':'], { + data: function(elem, i, match) { + return !!$.data(elem, match[3]); + }, + + focusable: function(element) { + var nodeName = element.nodeName.toLowerCase(), + tabIndex = $.attr(element, 'tabindex'); + return (/input|select|textarea|button|object/.test(nodeName) + ? !element.disabled + : 'a' == nodeName || 'area' == nodeName + ? element.href || !isNaN(tabIndex) + : !isNaN(tabIndex)) + // the element and all of its ancestors must be visible + // the browser may report that the area is hidden + && !$(element)['area' == nodeName ? 'parents' : 'closest'](':hidden').length; + }, + + tabbable: function(element) { + var tabIndex = $.attr(element, 'tabindex'); + return (isNaN(tabIndex) || tabIndex >= 0) && $(element).is(':focusable'); + } +}); + + +// $.widget is a factory to create jQuery plugins +// taking some boilerplate code out of the plugin code +function getter(namespace, plugin, method, args) { + function getMethods(type) { + var methods = $[namespace][plugin][type] || []; + return (typeof methods == 'string' ? methods.split(/,?\s+/) : methods); + } + + var methods = getMethods('getter'); + if (args.length == 1 && typeof args[0] == 'string') { + methods = methods.concat(getMethods('getterSetter')); + } + return ($.inArray(method, methods) != -1); +} + +$.widget = function(name, prototype) { + var namespace = name.split(".")[0]; + name = name.split(".")[1]; + + // create plugin method + $.fn[name] = function(options) { + var isMethodCall = (typeof options == 'string'), + args = Array.prototype.slice.call(arguments, 1); + + // prevent calls to internal methods + if (isMethodCall && options.substring(0, 1) == '_') { + return this; + } + + // handle getter methods + if (isMethodCall && getter(namespace, name, options, args)) { + var instance = $.data(this[0], name); + return (instance ? instance[options].apply(instance, args) + : undefined); + } + + // handle initialization and non-getter methods + return this.each(function() { + var instance = $.data(this, name); + + // constructor + (!instance && !isMethodCall && + $.data(this, name, new $[namespace][name](this, options))._init()); + + // method call + (instance && isMethodCall && $.isFunction(instance[options]) && + instance[options].apply(instance, args)); + }); + }; + + // create widget constructor + $[namespace] = $[namespace] || {}; + $[namespace][name] = function(element, options) { + var self = this; + + this.namespace = namespace; + this.widgetName = name; + this.widgetEventPrefix = $[namespace][name].eventPrefix || name; + this.widgetBaseClass = namespace + '-' + name; + + this.options = $.extend({}, + $.widget.defaults, + $[namespace][name].defaults, + $.metadata && $.metadata.get(element)[name], + options); + + this.element = $(element) + .bind('setData.' + name, function(event, key, value) { + if (event.target == element) { + return self._setData(key, value); + } + }) + .bind('getData.' + name, function(event, key) { + if (event.target == element) { + return self._getData(key); + } + }) + .bind('remove', function() { + return self.destroy(); + }); + }; + + // add widget prototype + $[namespace][name].prototype = $.extend({}, $.widget.prototype, prototype); + + // TODO: merge getter and getterSetter properties from widget prototype + // and plugin prototype + $[namespace][name].getterSetter = 'option'; +}; + +$.widget.prototype = { + _init: function() {}, + destroy: function() { + this.element.removeData(this.widgetName) + .removeClass(this.widgetBaseClass + '-disabled' + ' ' + this.namespace + '-state-disabled') + .removeAttr('aria-disabled'); + }, + + option: function(key, value) { + var options = key, + self = this; + + if (typeof key == "string") { + if (value === undefined) { + return this._getData(key); + } + options = {}; + options[key] = value; + } + + $.each(options, function(key, value) { + self._setData(key, value); + }); + }, + _getData: function(key) { + return this.options[key]; + }, + _setData: function(key, value) { + this.options[key] = value; + + if (key == 'disabled') { + this.element + [value ? 'addClass' : 'removeClass']( + this.widgetBaseClass + '-disabled' + ' ' + + this.namespace + '-state-disabled') + .attr("aria-disabled", value); + } + }, + + enable: function() { + this._setData('disabled', false); + }, + disable: function() { + this._setData('disabled', true); + }, + + _trigger: function(type, event, data) { + var callback = this.options[type], + eventName = (type == this.widgetEventPrefix + ? type : this.widgetEventPrefix + type); + + event = $.Event(event); + event.type = eventName; + + // copy original event properties over to the new event + // this would happen if we could call $.event.fix instead of $.Event + // but we don't have a way to force an event to be fixed multiple times + if (event.originalEvent) { + for (var i = $.event.props.length, prop; i;) { + prop = $.event.props[--i]; + event[prop] = event.originalEvent[prop]; + } + } + + this.element.trigger(event, data); + + return !($.isFunction(callback) && callback.call(this.element[0], event, data) === false + || event.isDefaultPrevented()); + } +}; + +$.widget.defaults = { + disabled: false +}; + + +/** Mouse Interaction Plugin **/ + +$.ui.mouse = { + _mouseInit: function() { + var self = this; + + this.element + .bind('mousedown.'+this.widgetName, function(event) { + return self._mouseDown(event); + }) + .bind('click.'+this.widgetName, function(event) { + if(self._preventClickEvent) { + self._preventClickEvent = false; + event.stopImmediatePropagation(); + return false; + } + }); + + // Prevent text selection in IE + if ($.browser.msie) { + this._mouseUnselectable = this.element.attr('unselectable'); + this.element.attr('unselectable', 'on'); + } + + this.started = false; + }, + + // TODO: make sure destroying one instance of mouse doesn't mess with + // other instances of mouse + _mouseDestroy: function() { + this.element.unbind('.'+this.widgetName); + + // Restore text selection in IE + ($.browser.msie + && this.element.attr('unselectable', this._mouseUnselectable)); + }, + + _mouseDown: function(event) { + // don't let more than one widget handle mouseStart + // TODO: figure out why we have to use originalEvent + event.originalEvent = event.originalEvent || {}; + if (event.originalEvent.mouseHandled) { return; } + + // we may have missed mouseup (out of window) + (this._mouseStarted && this._mouseUp(event)); + + this._mouseDownEvent = event; + + var self = this, + btnIsLeft = (event.which == 1), + elIsCancel = (typeof this.options.cancel == "string" ? $(event.target).parents().add(event.target).filter(this.options.cancel).length : false); + if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) { + return true; + } + + this.mouseDelayMet = !this.options.delay; + if (!this.mouseDelayMet) { + this._mouseDelayTimer = setTimeout(function() { + self.mouseDelayMet = true; + }, this.options.delay); + } + + if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { + this._mouseStarted = (this._mouseStart(event) !== false); + if (!this._mouseStarted) { + event.preventDefault(); + return true; + } + } + + // these delegates are required to keep context + this._mouseMoveDelegate = function(event) { + return self._mouseMove(event); + }; + this._mouseUpDelegate = function(event) { + return self._mouseUp(event); + }; + $(document) + .bind('mousemove.'+this.widgetName, this._mouseMoveDelegate) + .bind('mouseup.'+this.widgetName, this._mouseUpDelegate); + + // preventDefault() is used to prevent the selection of text here - + // however, in Safari, this causes select boxes not to be selectable + // anymore, so this fix is needed + ($.browser.safari || event.preventDefault()); + + event.originalEvent.mouseHandled = true; + return true; + }, + + _mouseMove: function(event) { + // IE mouseup check - mouseup happened when mouse was out of window + if ($.browser.msie && !event.button) { + return this._mouseUp(event); + } + + if (this._mouseStarted) { + this._mouseDrag(event); + return event.preventDefault(); + } + + if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { + this._mouseStarted = + (this._mouseStart(this._mouseDownEvent, event) !== false); + (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event)); + } + + return !this._mouseStarted; + }, + + _mouseUp: function(event) { + $(document) + .unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate) + .unbind('mouseup.'+this.widgetName, this._mouseUpDelegate); + + if (this._mouseStarted) { + this._mouseStarted = false; + this._preventClickEvent = (event.target == this._mouseDownEvent.target); + this._mouseStop(event); + } + + return false; + }, + + _mouseDistanceMet: function(event) { + return (Math.max( + Math.abs(this._mouseDownEvent.pageX - event.pageX), + Math.abs(this._mouseDownEvent.pageY - event.pageY) + ) >= this.options.distance + ); + }, + + _mouseDelayMet: function(event) { + return this.mouseDelayMet; + }, + + // These are placeholder methods, to be overriden by extending plugin + _mouseStart: function(event) {}, + _mouseDrag: function(event) {}, + _mouseStop: function(event) {}, + _mouseCapture: function(event) { return true; } +}; + +$.ui.mouse.defaults = { + cancel: null, + distance: 1, + delay: 0 +}; + +})(jQuery); \ No newline at end of file diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/ui.datepicker.js b/js2/mwEmbed/jquery/jquery.ui/ui/ui.datepicker.js new file mode 100644 index 0000000000..d3aa5c2b47 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/ui.datepicker.js @@ -0,0 +1,1630 @@ +/* + * jQuery UI Datepicker 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Datepicker + * + * Depends: + * ui.core.js + */ + +(function($) { // hide the namespace + +$.extend($.ui, { datepicker: { version: "1.7.1" } }); + +var PROP_NAME = 'datepicker'; + +/* Date picker manager. + Use the singleton instance of this class, $.datepicker, to interact with the date picker. + Settings for (groups of) date pickers are maintained in an instance object, + allowing multiple different settings on the same page. */ + +function Datepicker() { + this.debug = false; // Change this to true to start debugging + this._curInst = null; // The current instance in use + this._keyEvent = false; // If the last event was a key event + this._disabledInputs = []; // List of date picker inputs that have been disabled + this._datepickerShowing = false; // True if the popup picker is showing , false if not + this._inDialog = false; // True if showing within a "dialog", false if not + this._mainDivId = 'ui-datepicker-div'; // The ID of the main datepicker division + this._inlineClass = 'ui-datepicker-inline'; // The name of the inline marker class + this._appendClass = 'ui-datepicker-append'; // The name of the append marker class + this._triggerClass = 'ui-datepicker-trigger'; // The name of the trigger marker class + this._dialogClass = 'ui-datepicker-dialog'; // The name of the dialog marker class + this._disableClass = 'ui-datepicker-disabled'; // The name of the disabled covering marker class + this._unselectableClass = 'ui-datepicker-unselectable'; // The name of the unselectable cell marker class + this._currentClass = 'ui-datepicker-current-day'; // The name of the current day marker class + this._dayOverClass = 'ui-datepicker-days-cell-over'; // The name of the day hover marker class + this.regional = []; // Available regional settings, indexed by language code + this.regional[''] = { // Default regional settings + closeText: 'Done', // Display text for close link + prevText: 'Prev', // Display text for previous month link + nextText: 'Next', // Display text for next month link + currentText: 'Today', // Display text for current month link + monthNames: ['January','February','March','April','May','June', + 'July','August','September','October','November','December'], // Names of months for drop-down and formatting + monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], // For formatting + dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], // For formatting + dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], // For formatting + dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'], // Column headings for days starting at Sunday + dateFormat: 'mm/dd/yy', // See format options on parseDate + firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ... + isRTL: false // True if right-to-left language, false if left-to-right + }; + this._defaults = { // Global defaults for all the date picker instances + showOn: 'focus', // 'focus' for popup on focus, + // 'button' for trigger button, or 'both' for either + showAnim: 'show', // Name of jQuery animation for popup + showOptions: {}, // Options for enhanced animations + defaultDate: null, // Used when field is blank: actual date, + // +/-number for offset from today, null for today + appendText: '', // Display text following the input box, e.g. showing the format + buttonText: '...', // Text for trigger button + buttonImage: '', // URL for trigger button image + buttonImageOnly: false, // True if the image appears alone, false if it appears on a button + hideIfNoPrevNext: false, // True to hide next/previous month links + // if not applicable, false to just disable them + navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links + gotoCurrent: false, // True if today link goes back to current selection instead + changeMonth: false, // True if month can be selected directly, false if only prev/next + changeYear: false, // True if year can be selected directly, false if only prev/next + showMonthAfterYear: false, // True if the year select precedes month, false for month then year + yearRange: '-10:+10', // Range of years to display in drop-down, + // either relative to current year (-nn:+nn) or absolute (nnnn:nnnn) + showOtherMonths: false, // True to show dates in other months, false to leave blank + calculateWeek: this.iso8601Week, // How to calculate the week of the year, + // takes a Date and returns the number of the week for it + shortYearCutoff: '+10', // Short year values < this are in the current century, + // > this are in the previous century, + // string value starting with '+' for current year + value + minDate: null, // The earliest selectable date, or null for no limit + maxDate: null, // The latest selectable date, or null for no limit + duration: 'normal', // Duration of display/closure + beforeShowDay: null, // Function that takes a date and returns an array with + // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or '', + // [2] = cell title (optional), e.g. $.datepicker.noWeekends + beforeShow: null, // Function that takes an input field and + // returns a set of custom settings for the date picker + onSelect: null, // Define a callback function when a date is selected + onChangeMonthYear: null, // Define a callback function when the month or year is changed + onClose: null, // Define a callback function when the datepicker is closed + numberOfMonths: 1, // Number of months to show at a time + showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0) + stepMonths: 1, // Number of months to step back/forward + stepBigMonths: 12, // Number of months to step back/forward for the big links + altField: '', // Selector for an alternate field to store selected dates into + altFormat: '', // The date format to use for the alternate field + constrainInput: true, // The input is constrained by the current date format + showButtonPanel: false // True to show button panel, false to not show it + }; + $.extend(this._defaults, this.regional['']); + this.dpDiv = $('
'); +} + +$.extend(Datepicker.prototype, { + /* Class name added to elements to indicate already configured with a date picker. */ + markerClassName: 'hasDatepicker', + + /* Debug logging (if enabled). */ + log: function () { + if (this.debug) + console.log.apply('', arguments); + }, + + /* Override the default settings for all instances of the date picker. + @param settings object - the new settings to use as defaults (anonymous object) + @return the manager object */ + setDefaults: function(settings) { + extendRemove(this._defaults, settings || {}); + return this; + }, + + /* Attach the date picker to a jQuery selection. + @param target element - the target input field or division or span + @param settings object - the new settings to use for this date picker instance (anonymous) */ + _attachDatepicker: function(target, settings) { + // check for settings on the control itself - in namespace 'date:' + var inlineSettings = null; + for (var attrName in this._defaults) { + var attrValue = target.getAttribute('date:' + attrName); + if (attrValue) { + inlineSettings = inlineSettings || {}; + try { + inlineSettings[attrName] = eval(attrValue); + } catch (err) { + inlineSettings[attrName] = attrValue; + } + } + } + var nodeName = target.nodeName.toLowerCase(); + var inline = (nodeName == 'div' || nodeName == 'span'); + if (!target.id) + target.id = 'dp' + (++this.uuid); + var inst = this._newInst($(target), inline); + inst.settings = $.extend({}, settings || {}, inlineSettings || {}); + if (nodeName == 'input') { + this._connectDatepicker(target, inst); + } else if (inline) { + this._inlineDatepicker(target, inst); + } + }, + + /* Create a new instance object. */ + _newInst: function(target, inline) { + var id = target[0].id.replace(/([:\[\]\.])/g, '\\\\$1'); // escape jQuery meta chars + return {id: id, input: target, // associated target + selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection + drawMonth: 0, drawYear: 0, // month being drawn + inline: inline, // is datepicker inline or not + dpDiv: (!inline ? this.dpDiv : // presentation div + $('
'))}; + }, + + /* Attach the date picker to an input field. */ + _connectDatepicker: function(target, inst) { + var input = $(target); + inst.trigger = $([]); + if (input.hasClass(this.markerClassName)) + return; + var appendText = this._get(inst, 'appendText'); + var isRTL = this._get(inst, 'isRTL'); + if (appendText) + input[isRTL ? 'before' : 'after']('' + appendText + ''); + var showOn = this._get(inst, 'showOn'); + if (showOn == 'focus' || showOn == 'both') // pop-up date picker when in the marked field + input.focus(this._showDatepicker); + if (showOn == 'button' || showOn == 'both') { // pop-up date picker when button clicked + var buttonText = this._get(inst, 'buttonText'); + var buttonImage = this._get(inst, 'buttonImage'); + inst.trigger = $(this._get(inst, 'buttonImageOnly') ? + $('').addClass(this._triggerClass). + attr({ src: buttonImage, alt: buttonText, title: buttonText }) : + $('').addClass(this._triggerClass). + html(buttonImage == '' ? buttonText : $('').attr( + { src:buttonImage, alt:buttonText, title:buttonText }))); + input[isRTL ? 'before' : 'after'](inst.trigger); + inst.trigger.click(function() { + if ($.datepicker._datepickerShowing && $.datepicker._lastInput == target) + $.datepicker._hideDatepicker(); + else + $.datepicker._showDatepicker(target); + return false; + }); + } + input.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress). + bind("setData.datepicker", function(event, key, value) { + inst.settings[key] = value; + }).bind("getData.datepicker", function(event, key) { + return this._get(inst, key); + }); + $.data(target, PROP_NAME, inst); + }, + + /* Attach an inline date picker to a div. */ + _inlineDatepicker: function(target, inst) { + var divSpan = $(target); + if (divSpan.hasClass(this.markerClassName)) + return; + divSpan.addClass(this.markerClassName).append(inst.dpDiv). + bind("setData.datepicker", function(event, key, value){ + inst.settings[key] = value; + }).bind("getData.datepicker", function(event, key){ + return this._get(inst, key); + }); + $.data(target, PROP_NAME, inst); + this._setDate(inst, this._getDefaultDate(inst)); + this._updateDatepicker(inst); + this._updateAlternate(inst); + }, + + /* Pop-up the date picker in a "dialog" box. + @param input element - ignored + @param dateText string - the initial date to display (in the current format) + @param onSelect function - the function(dateText) to call when a date is selected + @param settings object - update the dialog date picker instance's settings (anonymous object) + @param pos int[2] - coordinates for the dialog's position within the screen or + event - with x/y coordinates or + leave empty for default (screen centre) + @return the manager object */ + _dialogDatepicker: function(input, dateText, onSelect, settings, pos) { + var inst = this._dialogInst; // internal instance + if (!inst) { + var id = 'dp' + (++this.uuid); + this._dialogInput = $(''); + this._dialogInput.keydown(this._doKeyDown); + $('body').append(this._dialogInput); + inst = this._dialogInst = this._newInst(this._dialogInput, false); + inst.settings = {}; + $.data(this._dialogInput[0], PROP_NAME, inst); + } + extendRemove(inst.settings, settings || {}); + this._dialogInput.val(dateText); + + this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null); + if (!this._pos) { + var browserWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; + var browserHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; + var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; + var scrollY = document.documentElement.scrollTop || document.body.scrollTop; + this._pos = // should use actual width/height below + [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY]; + } + + // move input on screen for focus, but hidden behind dialog + this._dialogInput.css('left', this._pos[0] + 'px').css('top', this._pos[1] + 'px'); + inst.settings.onSelect = onSelect; + this._inDialog = true; + this.dpDiv.addClass(this._dialogClass); + this._showDatepicker(this._dialogInput[0]); + if ($.blockUI) + $.blockUI(this.dpDiv); + $.data(this._dialogInput[0], PROP_NAME, inst); + return this; + }, + + /* Detach a datepicker from its control. + @param target element - the target input field or division or span */ + _destroyDatepicker: function(target) { + var $target = $(target); + var inst = $.data(target, PROP_NAME); + if (!$target.hasClass(this.markerClassName)) { + return; + } + var nodeName = target.nodeName.toLowerCase(); + $.removeData(target, PROP_NAME); + if (nodeName == 'input') { + inst.trigger.remove(); + $target.siblings('.' + this._appendClass).remove().end(). + removeClass(this.markerClassName). + unbind('focus', this._showDatepicker). + unbind('keydown', this._doKeyDown). + unbind('keypress', this._doKeyPress); + } else if (nodeName == 'div' || nodeName == 'span') + $target.removeClass(this.markerClassName).empty(); + }, + + /* Enable the date picker to a jQuery selection. + @param target element - the target input field or division or span */ + _enableDatepicker: function(target) { + var $target = $(target); + var inst = $.data(target, PROP_NAME); + if (!$target.hasClass(this.markerClassName)) { + return; + } + var nodeName = target.nodeName.toLowerCase(); + if (nodeName == 'input') { + target.disabled = false; + inst.trigger.filter("button"). + each(function() { this.disabled = false; }).end(). + filter("img"). + css({opacity: '1.0', cursor: ''}); + } + else if (nodeName == 'div' || nodeName == 'span') { + var inline = $target.children('.' + this._inlineClass); + inline.children().removeClass('ui-state-disabled'); + } + this._disabledInputs = $.map(this._disabledInputs, + function(value) { return (value == target ? null : value); }); // delete entry + }, + + /* Disable the date picker to a jQuery selection. + @param target element - the target input field or division or span */ + _disableDatepicker: function(target) { + var $target = $(target); + var inst = $.data(target, PROP_NAME); + if (!$target.hasClass(this.markerClassName)) { + return; + } + var nodeName = target.nodeName.toLowerCase(); + if (nodeName == 'input') { + target.disabled = true; + inst.trigger.filter("button"). + each(function() { this.disabled = true; }).end(). + filter("img"). + css({opacity: '0.5', cursor: 'default'}); + } + else if (nodeName == 'div' || nodeName == 'span') { + var inline = $target.children('.' + this._inlineClass); + inline.children().addClass('ui-state-disabled'); + } + this._disabledInputs = $.map(this._disabledInputs, + function(value) { return (value == target ? null : value); }); // delete entry + this._disabledInputs[this._disabledInputs.length] = target; + }, + + /* Is the first field in a jQuery collection disabled as a datepicker? + @param target element - the target input field or division or span + @return boolean - true if disabled, false if enabled */ + _isDisabledDatepicker: function(target) { + if (!target) { + return false; + } + for (var i = 0; i < this._disabledInputs.length; i++) { + if (this._disabledInputs[i] == target) + return true; + } + return false; + }, + + /* Retrieve the instance data for the target control. + @param target element - the target input field or division or span + @return object - the associated instance data + @throws error if a jQuery problem getting data */ + _getInst: function(target) { + try { + return $.data(target, PROP_NAME); + } + catch (err) { + throw 'Missing instance data for this datepicker'; + } + }, + + /* Update the settings for a date picker attached to an input field or division. + @param target element - the target input field or division or span + @param name object - the new settings to update or + string - the name of the setting to change or + @param value any - the new value for the setting (omit if above is an object) */ + _optionDatepicker: function(target, name, value) { + var settings = name || {}; + if (typeof name == 'string') { + settings = {}; + settings[name] = value; + } + var inst = this._getInst(target); + if (inst) { + if (this._curInst == inst) { + this._hideDatepicker(null); + } + extendRemove(inst.settings, settings); + var date = new Date(); + extendRemove(inst, {rangeStart: null, // start of range + endDay: null, endMonth: null, endYear: null, // end of range + selectedDay: date.getDate(), selectedMonth: date.getMonth(), + selectedYear: date.getFullYear(), // starting point + currentDay: date.getDate(), currentMonth: date.getMonth(), + currentYear: date.getFullYear(), // current selection + drawMonth: date.getMonth(), drawYear: date.getFullYear()}); // month being drawn + this._updateDatepicker(inst); + } + }, + + // change method deprecated + _changeDatepicker: function(target, name, value) { + this._optionDatepicker(target, name, value); + }, + + /* Redraw the date picker attached to an input field or division. + @param target element - the target input field or division or span */ + _refreshDatepicker: function(target) { + var inst = this._getInst(target); + if (inst) { + this._updateDatepicker(inst); + } + }, + + /* Set the dates for a jQuery selection. + @param target element - the target input field or division or span + @param date Date - the new date + @param endDate Date - the new end date for a range (optional) */ + _setDateDatepicker: function(target, date, endDate) { + var inst = this._getInst(target); + if (inst) { + this._setDate(inst, date, endDate); + this._updateDatepicker(inst); + this._updateAlternate(inst); + } + }, + + /* Get the date(s) for the first entry in a jQuery selection. + @param target element - the target input field or division or span + @return Date - the current date or + Date[2] - the current dates for a range */ + _getDateDatepicker: function(target) { + var inst = this._getInst(target); + if (inst && !inst.inline) + this._setDateFromField(inst); + return (inst ? this._getDate(inst) : null); + }, + + /* Handle keystrokes. */ + _doKeyDown: function(event) { + var inst = $.datepicker._getInst(event.target); + var handled = true; + var isRTL = inst.dpDiv.is('.ui-datepicker-rtl'); + inst._keyEvent = true; + if ($.datepicker._datepickerShowing) + switch (event.keyCode) { + case 9: $.datepicker._hideDatepicker(null, ''); + break; // hide on tab out + case 13: var sel = $('td.' + $.datepicker._dayOverClass + + ', td.' + $.datepicker._currentClass, inst.dpDiv); + if (sel[0]) + $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]); + else + $.datepicker._hideDatepicker(null, $.datepicker._get(inst, 'duration')); + return false; // don't submit the form + break; // select the value on enter + case 27: $.datepicker._hideDatepicker(null, $.datepicker._get(inst, 'duration')); + break; // hide on escape + case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ? + -$.datepicker._get(inst, 'stepBigMonths') : + -$.datepicker._get(inst, 'stepMonths')), 'M'); + break; // previous month/year on page up/+ ctrl + case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ? + +$.datepicker._get(inst, 'stepBigMonths') : + +$.datepicker._get(inst, 'stepMonths')), 'M'); + break; // next month/year on page down/+ ctrl + case 35: if (event.ctrlKey || event.metaKey) $.datepicker._clearDate(event.target); + handled = event.ctrlKey || event.metaKey; + break; // clear on ctrl or command +end + case 36: if (event.ctrlKey || event.metaKey) $.datepicker._gotoToday(event.target); + handled = event.ctrlKey || event.metaKey; + break; // current on ctrl or command +home + case 37: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), 'D'); + handled = event.ctrlKey || event.metaKey; + // -1 day on ctrl or command +left + if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ? + -$.datepicker._get(inst, 'stepBigMonths') : + -$.datepicker._get(inst, 'stepMonths')), 'M'); + // next month/year on alt +left on Mac + break; + case 38: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, -7, 'D'); + handled = event.ctrlKey || event.metaKey; + break; // -1 week on ctrl or command +up + case 39: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), 'D'); + handled = event.ctrlKey || event.metaKey; + // +1 day on ctrl or command +right + if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ? + +$.datepicker._get(inst, 'stepBigMonths') : + +$.datepicker._get(inst, 'stepMonths')), 'M'); + // next month/year on alt +right + break; + case 40: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, +7, 'D'); + handled = event.ctrlKey || event.metaKey; + break; // +1 week on ctrl or command +down + default: handled = false; + } + else if (event.keyCode == 36 && event.ctrlKey) // display the date picker on ctrl+home + $.datepicker._showDatepicker(this); + else { + handled = false; + } + if (handled) { + event.preventDefault(); + event.stopPropagation(); + } + }, + + /* Filter entered characters - based on date format. */ + _doKeyPress: function(event) { + var inst = $.datepicker._getInst(event.target); + if ($.datepicker._get(inst, 'constrainInput')) { + var chars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')); + var chr = String.fromCharCode(event.charCode == undefined ? event.keyCode : event.charCode); + return event.ctrlKey || (chr < ' ' || !chars || chars.indexOf(chr) > -1); + } + }, + + /* Pop-up the date picker for a given input field. + @param input element - the input field attached to the date picker or + event - if triggered by focus */ + _showDatepicker: function(input) { + input = input.target || input; + if (input.nodeName.toLowerCase() != 'input') // find from button/image trigger + input = $('input', input.parentNode)[0]; + if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput == input) // already here + return; + var inst = $.datepicker._getInst(input); + var beforeShow = $.datepicker._get(inst, 'beforeShow'); + extendRemove(inst.settings, (beforeShow ? beforeShow.apply(input, [input, inst]) : {})); + $.datepicker._hideDatepicker(null, ''); + $.datepicker._lastInput = input; + $.datepicker._setDateFromField(inst); + if ($.datepicker._inDialog) // hide cursor + input.value = ''; + if (!$.datepicker._pos) { // position below input + $.datepicker._pos = $.datepicker._findPos(input); + $.datepicker._pos[1] += input.offsetHeight; // add the height + } + var isFixed = false; + $(input).parents().each(function() { + isFixed |= $(this).css('position') == 'fixed'; + return !isFixed; + }); + if (isFixed && $.browser.opera) { // correction for Opera when fixed and scrolled + $.datepicker._pos[0] -= document.documentElement.scrollLeft; + $.datepicker._pos[1] -= document.documentElement.scrollTop; + } + var offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]}; + $.datepicker._pos = null; + inst.rangeStart = null; + // determine sizing offscreen + inst.dpDiv.css({position: 'absolute', display: 'block', top: '-1000px'}); + $.datepicker._updateDatepicker(inst); + // fix width for dynamic number of date pickers + // and adjust position before showing + offset = $.datepicker._checkOffset(inst, offset, isFixed); + inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ? + 'static' : (isFixed ? 'fixed' : 'absolute')), display: 'none', + left: offset.left + 'px', top: offset.top + 'px'}); + if (!inst.inline) { + var showAnim = $.datepicker._get(inst, 'showAnim') || 'show'; + var duration = $.datepicker._get(inst, 'duration'); + var postProcess = function() { + $.datepicker._datepickerShowing = true; + if ($.browser.msie && parseInt($.browser.version,10) < 7) // fix IE < 7 select problems + $('iframe.ui-datepicker-cover').css({width: inst.dpDiv.width() + 4, + height: inst.dpDiv.height() + 4}); + }; + if ($.effects && $.effects[showAnim]) + inst.dpDiv.show(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess); + else + inst.dpDiv[showAnim](duration, postProcess); + if (duration == '') + postProcess(); + if (inst.input[0].type != 'hidden') + inst.input[0].focus(); + $.datepicker._curInst = inst; + } + }, + + /* Generate the date picker content. */ + _updateDatepicker: function(inst) { + var dims = {width: inst.dpDiv.width() + 4, + height: inst.dpDiv.height() + 4}; + var self = this; + inst.dpDiv.empty().append(this._generateHTML(inst)) + .find('iframe.ui-datepicker-cover'). + css({width: dims.width, height: dims.height}) + .end() + .find('button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a') + .bind('mouseout', function(){ + $(this).removeClass('ui-state-hover'); + if(this.className.indexOf('ui-datepicker-prev') != -1) $(this).removeClass('ui-datepicker-prev-hover'); + if(this.className.indexOf('ui-datepicker-next') != -1) $(this).removeClass('ui-datepicker-next-hover'); + }) + .bind('mouseover', function(){ + if (!self._isDisabledDatepicker( inst.inline ? inst.dpDiv.parent()[0] : inst.input[0])) { + $(this).parents('.ui-datepicker-calendar').find('a').removeClass('ui-state-hover'); + $(this).addClass('ui-state-hover'); + if(this.className.indexOf('ui-datepicker-prev') != -1) $(this).addClass('ui-datepicker-prev-hover'); + if(this.className.indexOf('ui-datepicker-next') != -1) $(this).addClass('ui-datepicker-next-hover'); + } + }) + .end() + .find('.' + this._dayOverClass + ' a') + .trigger('mouseover') + .end(); + var numMonths = this._getNumberOfMonths(inst); + var cols = numMonths[1]; + var width = 17; + if (cols > 1) { + inst.dpDiv.addClass('ui-datepicker-multi-' + cols).css('width', (width * cols) + 'em'); + } else { + inst.dpDiv.removeClass('ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4').width(''); + } + inst.dpDiv[(numMonths[0] != 1 || numMonths[1] != 1 ? 'add' : 'remove') + + 'Class']('ui-datepicker-multi'); + inst.dpDiv[(this._get(inst, 'isRTL') ? 'add' : 'remove') + + 'Class']('ui-datepicker-rtl'); + if (inst.input && inst.input[0].type != 'hidden' && inst == $.datepicker._curInst) + $(inst.input[0]).focus(); + }, + + /* Check positioning to remain on screen. */ + _checkOffset: function(inst, offset, isFixed) { + var dpWidth = inst.dpDiv.outerWidth(); + var dpHeight = inst.dpDiv.outerHeight(); + var inputWidth = inst.input ? inst.input.outerWidth() : 0; + var inputHeight = inst.input ? inst.input.outerHeight() : 0; + var viewWidth = (window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth) + $(document).scrollLeft(); + var viewHeight = (window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight) + $(document).scrollTop(); + + offset.left -= (this._get(inst, 'isRTL') ? (dpWidth - inputWidth) : 0); + offset.left -= (isFixed && offset.left == inst.input.offset().left) ? $(document).scrollLeft() : 0; + offset.top -= (isFixed && offset.top == (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0; + + // now check if datepicker is showing outside window viewport - move to a better place if so. + offset.left -= (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ? Math.abs(offset.left + dpWidth - viewWidth) : 0; + offset.top -= (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ? Math.abs(offset.top + dpHeight + inputHeight*2 - viewHeight) : 0; + + return offset; + }, + + /* Find an object's position on the screen. */ + _findPos: function(obj) { + while (obj && (obj.type == 'hidden' || obj.nodeType != 1)) { + obj = obj.nextSibling; + } + var position = $(obj).offset(); + return [position.left, position.top]; + }, + + /* Hide the date picker from view. + @param input element - the input field attached to the date picker + @param duration string - the duration over which to close the date picker */ + _hideDatepicker: function(input, duration) { + var inst = this._curInst; + if (!inst || (input && inst != $.data(input, PROP_NAME))) + return; + if (inst.stayOpen) + this._selectDate('#' + inst.id, this._formatDate(inst, + inst.currentDay, inst.currentMonth, inst.currentYear)); + inst.stayOpen = false; + if (this._datepickerShowing) { + duration = (duration != null ? duration : this._get(inst, 'duration')); + var showAnim = this._get(inst, 'showAnim'); + var postProcess = function() { + $.datepicker._tidyDialog(inst); + }; + if (duration != '' && $.effects && $.effects[showAnim]) + inst.dpDiv.hide(showAnim, $.datepicker._get(inst, 'showOptions'), + duration, postProcess); + else + inst.dpDiv[(duration == '' ? 'hide' : (showAnim == 'slideDown' ? 'slideUp' : + (showAnim == 'fadeIn' ? 'fadeOut' : 'hide')))](duration, postProcess); + if (duration == '') + this._tidyDialog(inst); + var onClose = this._get(inst, 'onClose'); + if (onClose) + onClose.apply((inst.input ? inst.input[0] : null), + [(inst.input ? inst.input.val() : ''), inst]); // trigger custom callback + this._datepickerShowing = false; + this._lastInput = null; + if (this._inDialog) { + this._dialogInput.css({ position: 'absolute', left: '0', top: '-100px' }); + if ($.blockUI) { + $.unblockUI(); + $('body').append(this.dpDiv); + } + } + this._inDialog = false; + } + this._curInst = null; + }, + + /* Tidy up after a dialog display. */ + _tidyDialog: function(inst) { + inst.dpDiv.removeClass(this._dialogClass).unbind('.ui-datepicker-calendar'); + }, + + /* Close date picker if clicked elsewhere. */ + _checkExternalClick: function(event) { + if (!$.datepicker._curInst) + return; + var $target = $(event.target); + if (($target.parents('#' + $.datepicker._mainDivId).length == 0) && + !$target.hasClass($.datepicker.markerClassName) && + !$target.hasClass($.datepicker._triggerClass) && + $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI)) + $.datepicker._hideDatepicker(null, ''); + }, + + /* Adjust one of the date sub-fields. */ + _adjustDate: function(id, offset, period) { + var target = $(id); + var inst = this._getInst(target[0]); + if (this._isDisabledDatepicker(target[0])) { + return; + } + this._adjustInstDate(inst, offset + + (period == 'M' ? this._get(inst, 'showCurrentAtPos') : 0), // undo positioning + period); + this._updateDatepicker(inst); + }, + + /* Action for current link. */ + _gotoToday: function(id) { + var target = $(id); + var inst = this._getInst(target[0]); + if (this._get(inst, 'gotoCurrent') && inst.currentDay) { + inst.selectedDay = inst.currentDay; + inst.drawMonth = inst.selectedMonth = inst.currentMonth; + inst.drawYear = inst.selectedYear = inst.currentYear; + } + else { + var date = new Date(); + inst.selectedDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = date.getFullYear(); + } + this._notifyChange(inst); + this._adjustDate(target); + }, + + /* Action for selecting a new month/year. */ + _selectMonthYear: function(id, select, period) { + var target = $(id); + var inst = this._getInst(target[0]); + inst._selectingMonthYear = false; + inst['selected' + (period == 'M' ? 'Month' : 'Year')] = + inst['draw' + (period == 'M' ? 'Month' : 'Year')] = + parseInt(select.options[select.selectedIndex].value,10); + this._notifyChange(inst); + this._adjustDate(target); + }, + + /* Restore input focus after not changing month/year. */ + _clickMonthYear: function(id) { + var target = $(id); + var inst = this._getInst(target[0]); + if (inst.input && inst._selectingMonthYear && !$.browser.msie) + inst.input[0].focus(); + inst._selectingMonthYear = !inst._selectingMonthYear; + }, + + /* Action for selecting a day. */ + _selectDay: function(id, month, year, td) { + var target = $(id); + if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) { + return; + } + var inst = this._getInst(target[0]); + inst.selectedDay = inst.currentDay = $('a', td).html(); + inst.selectedMonth = inst.currentMonth = month; + inst.selectedYear = inst.currentYear = year; + if (inst.stayOpen) { + inst.endDay = inst.endMonth = inst.endYear = null; + } + this._selectDate(id, this._formatDate(inst, + inst.currentDay, inst.currentMonth, inst.currentYear)); + if (inst.stayOpen) { + inst.rangeStart = this._daylightSavingAdjust( + new Date(inst.currentYear, inst.currentMonth, inst.currentDay)); + this._updateDatepicker(inst); + } + }, + + /* Erase the input field and hide the date picker. */ + _clearDate: function(id) { + var target = $(id); + var inst = this._getInst(target[0]); + inst.stayOpen = false; + inst.endDay = inst.endMonth = inst.endYear = inst.rangeStart = null; + this._selectDate(target, ''); + }, + + /* Update the input field with the selected date. */ + _selectDate: function(id, dateStr) { + var target = $(id); + var inst = this._getInst(target[0]); + dateStr = (dateStr != null ? dateStr : this._formatDate(inst)); + if (inst.input) + inst.input.val(dateStr); + this._updateAlternate(inst); + var onSelect = this._get(inst, 'onSelect'); + if (onSelect) + onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback + else if (inst.input) + inst.input.trigger('change'); // fire the change event + if (inst.inline) + this._updateDatepicker(inst); + else if (!inst.stayOpen) { + this._hideDatepicker(null, this._get(inst, 'duration')); + this._lastInput = inst.input[0]; + if (typeof(inst.input[0]) != 'object') + inst.input[0].focus(); // restore focus + this._lastInput = null; + } + }, + + /* Update any alternate field to synchronise with the main field. */ + _updateAlternate: function(inst) { + var altField = this._get(inst, 'altField'); + if (altField) { // update alternate field too + var altFormat = this._get(inst, 'altFormat') || this._get(inst, 'dateFormat'); + var date = this._getDate(inst); + dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst)); + $(altField).each(function() { $(this).val(dateStr); }); + } + }, + + /* Set as beforeShowDay function to prevent selection of weekends. + @param date Date - the date to customise + @return [boolean, string] - is this date selectable?, what is its CSS class? */ + noWeekends: function(date) { + var day = date.getDay(); + return [(day > 0 && day < 6), '']; + }, + + /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition. + @param date Date - the date to get the week for + @return number - the number of the week within the year that contains this date */ + iso8601Week: function(date) { + var checkDate = new Date(date.getFullYear(), date.getMonth(), date.getDate()); + var firstMon = new Date(checkDate.getFullYear(), 1 - 1, 4); // First week always contains 4 Jan + var firstDay = firstMon.getDay() || 7; // Day of week: Mon = 1, ..., Sun = 7 + firstMon.setDate(firstMon.getDate() + 1 - firstDay); // Preceding Monday + if (firstDay < 4 && checkDate < firstMon) { // Adjust first three days in year if necessary + checkDate.setDate(checkDate.getDate() - 3); // Generate for previous year + return $.datepicker.iso8601Week(checkDate); + } else if (checkDate > new Date(checkDate.getFullYear(), 12 - 1, 28)) { // Check last three days in year + firstDay = new Date(checkDate.getFullYear() + 1, 1 - 1, 4).getDay() || 7; + if (firstDay > 4 && (checkDate.getDay() || 7) < firstDay - 3) { // Adjust if necessary + return 1; + } + } + return Math.floor(((checkDate - firstMon) / 86400000) / 7) + 1; // Weeks to given date + }, + + /* Parse a string value into a date object. + See formatDate below for the possible formats. + + @param format string - the expected format of the date + @param value string - the date in the above format + @param settings Object - attributes include: + shortYearCutoff number - the cutoff year for determining the century (optional) + dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) + dayNames string[7] - names of the days from Sunday (optional) + monthNamesShort string[12] - abbreviated names of the months (optional) + monthNames string[12] - names of the months (optional) + @return Date - the extracted date value or null if value is blank */ + parseDate: function (format, value, settings) { + if (format == null || value == null) + throw 'Invalid arguments'; + value = (typeof value == 'object' ? value.toString() : value + ''); + if (value == '') + return null; + var shortYearCutoff = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff; + var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort; + var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames; + var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort; + var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames; + var year = -1; + var month = -1; + var day = -1; + var doy = -1; + var literal = false; + // Check whether a format character is doubled + var lookAhead = function(match) { + var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match); + if (matches) + iFormat++; + return matches; + }; + // Extract a number from the string value + var getNumber = function(match) { + lookAhead(match); + var origSize = (match == '@' ? 14 : (match == 'y' ? 4 : (match == 'o' ? 3 : 2))); + var size = origSize; + var num = 0; + while (size > 0 && iValue < value.length && + value.charAt(iValue) >= '0' && value.charAt(iValue) <= '9') { + num = num * 10 + parseInt(value.charAt(iValue++),10); + size--; + } + if (size == origSize) + throw 'Missing number at position ' + iValue; + return num; + }; + // Extract a name from the string value and convert to an index + var getName = function(match, shortNames, longNames) { + var names = (lookAhead(match) ? longNames : shortNames); + var size = 0; + for (var j = 0; j < names.length; j++) + size = Math.max(size, names[j].length); + var name = ''; + var iInit = iValue; + while (size > 0 && iValue < value.length) { + name += value.charAt(iValue++); + for (var i = 0; i < names.length; i++) + if (name == names[i]) + return i + 1; + size--; + } + throw 'Unknown name at position ' + iInit; + }; + // Confirm that a literal character matches the string value + var checkLiteral = function() { + if (value.charAt(iValue) != format.charAt(iFormat)) + throw 'Unexpected literal at position ' + iValue; + iValue++; + }; + var iValue = 0; + for (var iFormat = 0; iFormat < format.length; iFormat++) { + if (literal) + if (format.charAt(iFormat) == "'" && !lookAhead("'")) + literal = false; + else + checkLiteral(); + else + switch (format.charAt(iFormat)) { + case 'd': + day = getNumber('d'); + break; + case 'D': + getName('D', dayNamesShort, dayNames); + break; + case 'o': + doy = getNumber('o'); + break; + case 'm': + month = getNumber('m'); + break; + case 'M': + month = getName('M', monthNamesShort, monthNames); + break; + case 'y': + year = getNumber('y'); + break; + case '@': + var date = new Date(getNumber('@')); + year = date.getFullYear(); + month = date.getMonth() + 1; + day = date.getDate(); + break; + case "'": + if (lookAhead("'")) + checkLiteral(); + else + literal = true; + break; + default: + checkLiteral(); + } + } + if (year == -1) + year = new Date().getFullYear(); + else if (year < 100) + year += new Date().getFullYear() - new Date().getFullYear() % 100 + + (year <= shortYearCutoff ? 0 : -100); + if (doy > -1) { + month = 1; + day = doy; + do { + var dim = this._getDaysInMonth(year, month - 1); + if (day <= dim) + break; + month++; + day -= dim; + } while (true); + } + var date = this._daylightSavingAdjust(new Date(year, month - 1, day)); + if (date.getFullYear() != year || date.getMonth() + 1 != month || date.getDate() != day) + throw 'Invalid date'; // E.g. 31/02/* + return date; + }, + + /* Standard date formats. */ + ATOM: 'yy-mm-dd', // RFC 3339 (ISO 8601) + COOKIE: 'D, dd M yy', + ISO_8601: 'yy-mm-dd', + RFC_822: 'D, d M y', + RFC_850: 'DD, dd-M-y', + RFC_1036: 'D, d M y', + RFC_1123: 'D, d M yy', + RFC_2822: 'D, d M yy', + RSS: 'D, d M y', // RFC 822 + TIMESTAMP: '@', + W3C: 'yy-mm-dd', // ISO 8601 + + /* Format a date object into a string value. + The format can be combinations of the following: + d - day of month (no leading zero) + dd - day of month (two digit) + o - day of year (no leading zeros) + oo - day of year (three digit) + D - day name short + DD - day name long + m - month of year (no leading zero) + mm - month of year (two digit) + M - month name short + MM - month name long + y - year (two digit) + yy - year (four digit) + @ - Unix timestamp (ms since 01/01/1970) + '...' - literal text + '' - single quote + + @param format string - the desired format of the date + @param date Date - the date value to format + @param settings Object - attributes include: + dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) + dayNames string[7] - names of the days from Sunday (optional) + monthNamesShort string[12] - abbreviated names of the months (optional) + monthNames string[12] - names of the months (optional) + @return string - the date in the above format */ + formatDate: function (format, date, settings) { + if (!date) + return ''; + var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort; + var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames; + var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort; + var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames; + // Check whether a format character is doubled + var lookAhead = function(match) { + var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match); + if (matches) + iFormat++; + return matches; + }; + // Format a number, with leading zero if necessary + var formatNumber = function(match, value, len) { + var num = '' + value; + if (lookAhead(match)) + while (num.length < len) + num = '0' + num; + return num; + }; + // Format a name, short or long as requested + var formatName = function(match, value, shortNames, longNames) { + return (lookAhead(match) ? longNames[value] : shortNames[value]); + }; + var output = ''; + var literal = false; + if (date) + for (var iFormat = 0; iFormat < format.length; iFormat++) { + if (literal) + if (format.charAt(iFormat) == "'" && !lookAhead("'")) + literal = false; + else + output += format.charAt(iFormat); + else + switch (format.charAt(iFormat)) { + case 'd': + output += formatNumber('d', date.getDate(), 2); + break; + case 'D': + output += formatName('D', date.getDay(), dayNamesShort, dayNames); + break; + case 'o': + var doy = date.getDate(); + for (var m = date.getMonth() - 1; m >= 0; m--) + doy += this._getDaysInMonth(date.getFullYear(), m); + output += formatNumber('o', doy, 3); + break; + case 'm': + output += formatNumber('m', date.getMonth() + 1, 2); + break; + case 'M': + output += formatName('M', date.getMonth(), monthNamesShort, monthNames); + break; + case 'y': + output += (lookAhead('y') ? date.getFullYear() : + (date.getYear() % 100 < 10 ? '0' : '') + date.getYear() % 100); + break; + case '@': + output += date.getTime(); + break; + case "'": + if (lookAhead("'")) + output += "'"; + else + literal = true; + break; + default: + output += format.charAt(iFormat); + } + } + return output; + }, + + /* Extract all possible characters from the date format. */ + _possibleChars: function (format) { + var chars = ''; + var literal = false; + for (var iFormat = 0; iFormat < format.length; iFormat++) + if (literal) + if (format.charAt(iFormat) == "'" && !lookAhead("'")) + literal = false; + else + chars += format.charAt(iFormat); + else + switch (format.charAt(iFormat)) { + case 'd': case 'm': case 'y': case '@': + chars += '0123456789'; + break; + case 'D': case 'M': + return null; // Accept anything + case "'": + if (lookAhead("'")) + chars += "'"; + else + literal = true; + break; + default: + chars += format.charAt(iFormat); + } + return chars; + }, + + /* Get a setting value, defaulting if necessary. */ + _get: function(inst, name) { + return inst.settings[name] !== undefined ? + inst.settings[name] : this._defaults[name]; + }, + + /* Parse existing date and initialise date picker. */ + _setDateFromField: function(inst) { + var dateFormat = this._get(inst, 'dateFormat'); + var dates = inst.input ? inst.input.val() : null; + inst.endDay = inst.endMonth = inst.endYear = null; + var date = defaultDate = this._getDefaultDate(inst); + var settings = this._getFormatConfig(inst); + try { + date = this.parseDate(dateFormat, dates, settings) || defaultDate; + } catch (event) { + this.log(event); + date = defaultDate; + } + inst.selectedDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = date.getFullYear(); + inst.currentDay = (dates ? date.getDate() : 0); + inst.currentMonth = (dates ? date.getMonth() : 0); + inst.currentYear = (dates ? date.getFullYear() : 0); + this._adjustInstDate(inst); + }, + + /* Retrieve the default date shown on opening. */ + _getDefaultDate: function(inst) { + var date = this._determineDate(this._get(inst, 'defaultDate'), new Date()); + var minDate = this._getMinMaxDate(inst, 'min', true); + var maxDate = this._getMinMaxDate(inst, 'max'); + date = (minDate && date < minDate ? minDate : date); + date = (maxDate && date > maxDate ? maxDate : date); + return date; + }, + + /* A date may be specified as an exact value or a relative one. */ + _determineDate: function(date, defaultDate) { + var offsetNumeric = function(offset) { + var date = new Date(); + date.setDate(date.getDate() + offset); + return date; + }; + var offsetString = function(offset, getDaysInMonth) { + var date = new Date(); + var year = date.getFullYear(); + var month = date.getMonth(); + var day = date.getDate(); + var pattern = /([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g; + var matches = pattern.exec(offset); + while (matches) { + switch (matches[2] || 'd') { + case 'd' : case 'D' : + day += parseInt(matches[1],10); break; + case 'w' : case 'W' : + day += parseInt(matches[1],10) * 7; break; + case 'm' : case 'M' : + month += parseInt(matches[1],10); + day = Math.min(day, getDaysInMonth(year, month)); + break; + case 'y': case 'Y' : + year += parseInt(matches[1],10); + day = Math.min(day, getDaysInMonth(year, month)); + break; + } + matches = pattern.exec(offset); + } + return new Date(year, month, day); + }; + date = (date == null ? defaultDate : + (typeof date == 'string' ? offsetString(date, this._getDaysInMonth) : + (typeof date == 'number' ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : date))); + date = (date && date.toString() == 'Invalid Date' ? defaultDate : date); + if (date) { + date.setHours(0); + date.setMinutes(0); + date.setSeconds(0); + date.setMilliseconds(0); + } + return this._daylightSavingAdjust(date); + }, + + /* Handle switch to/from daylight saving. + Hours may be non-zero on daylight saving cut-over: + > 12 when midnight changeover, but then cannot generate + midnight datetime, so jump to 1AM, otherwise reset. + @param date (Date) the date to check + @return (Date) the corrected date */ + _daylightSavingAdjust: function(date) { + if (!date) return null; + date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0); + return date; + }, + + /* Set the date(s) directly. */ + _setDate: function(inst, date, endDate) { + var clear = !(date); + var origMonth = inst.selectedMonth; + var origYear = inst.selectedYear; + date = this._determineDate(date, new Date()); + inst.selectedDay = inst.currentDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = inst.currentMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = inst.currentYear = date.getFullYear(); + if (origMonth != inst.selectedMonth || origYear != inst.selectedYear) + this._notifyChange(inst); + this._adjustInstDate(inst); + if (inst.input) { + inst.input.val(clear ? '' : this._formatDate(inst)); + } + }, + + /* Retrieve the date(s) directly. */ + _getDate: function(inst) { + var startDate = (!inst.currentYear || (inst.input && inst.input.val() == '') ? null : + this._daylightSavingAdjust(new Date( + inst.currentYear, inst.currentMonth, inst.currentDay))); + return startDate; + }, + + /* Generate the HTML for the current state of the date picker. */ + _generateHTML: function(inst) { + var today = new Date(); + today = this._daylightSavingAdjust( + new Date(today.getFullYear(), today.getMonth(), today.getDate())); // clear time + var isRTL = this._get(inst, 'isRTL'); + var showButtonPanel = this._get(inst, 'showButtonPanel'); + var hideIfNoPrevNext = this._get(inst, 'hideIfNoPrevNext'); + var navigationAsDateFormat = this._get(inst, 'navigationAsDateFormat'); + var numMonths = this._getNumberOfMonths(inst); + var showCurrentAtPos = this._get(inst, 'showCurrentAtPos'); + var stepMonths = this._get(inst, 'stepMonths'); + var stepBigMonths = this._get(inst, 'stepBigMonths'); + var isMultiMonth = (numMonths[0] != 1 || numMonths[1] != 1); + var currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) : + new Date(inst.currentYear, inst.currentMonth, inst.currentDay))); + var minDate = this._getMinMaxDate(inst, 'min', true); + var maxDate = this._getMinMaxDate(inst, 'max'); + var drawMonth = inst.drawMonth - showCurrentAtPos; + var drawYear = inst.drawYear; + if (drawMonth < 0) { + drawMonth += 12; + drawYear--; + } + if (maxDate) { + var maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(), + maxDate.getMonth() - numMonths[1] + 1, maxDate.getDate())); + maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw); + while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) { + drawMonth--; + if (drawMonth < 0) { + drawMonth = 11; + drawYear--; + } + } + } + inst.drawMonth = drawMonth; + inst.drawYear = drawYear; + var prevText = this._get(inst, 'prevText'); + prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText, + this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)), + this._getFormatConfig(inst))); + var prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ? + '' + prevText + '' : + (hideIfNoPrevNext ? '' : '' + prevText + '')); + var nextText = this._get(inst, 'nextText'); + nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText, + this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)), + this._getFormatConfig(inst))); + var next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ? + '' + nextText + '' : + (hideIfNoPrevNext ? '' : '' + nextText + '')); + var currentText = this._get(inst, 'currentText'); + var gotoDate = (this._get(inst, 'gotoCurrent') && inst.currentDay ? currentDate : today); + currentText = (!navigationAsDateFormat ? currentText : + this.formatDate(currentText, gotoDate, this._getFormatConfig(inst))); + var controls = (!inst.inline ? '' : ''); + var buttonPanel = (showButtonPanel) ? '
' + (isRTL ? controls : '') + + (this._isInRange(inst, gotoDate) ? '' : '') + (isRTL ? '' : controls) + '
' : ''; + var firstDay = parseInt(this._get(inst, 'firstDay'),10); + firstDay = (isNaN(firstDay) ? 0 : firstDay); + var dayNames = this._get(inst, 'dayNames'); + var dayNamesShort = this._get(inst, 'dayNamesShort'); + var dayNamesMin = this._get(inst, 'dayNamesMin'); + var monthNames = this._get(inst, 'monthNames'); + var monthNamesShort = this._get(inst, 'monthNamesShort'); + var beforeShowDay = this._get(inst, 'beforeShowDay'); + var showOtherMonths = this._get(inst, 'showOtherMonths'); + var calculateWeek = this._get(inst, 'calculateWeek') || this.iso8601Week; + var endDate = inst.endDay ? this._daylightSavingAdjust( + new Date(inst.endYear, inst.endMonth, inst.endDay)) : currentDate; + var defaultDate = this._getDefaultDate(inst); + var html = ''; + for (var row = 0; row < numMonths[0]; row++) { + var group = ''; + for (var col = 0; col < numMonths[1]; col++) { + var selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay)); + var cornerClass = ' ui-corner-all'; + var calender = ''; + if (isMultiMonth) { + calender += '
'; + } + calender += '
' + + (/all|left/.test(cornerClass) && row == 0 ? (isRTL ? next : prev) : '') + + (/all|right/.test(cornerClass) && row == 0 ? (isRTL ? prev : next) : '') + + this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate, + selectedDate, row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers + '
' + + ''; + var thead = ''; + for (var dow = 0; dow < 7; dow++) { // days of the week + var day = (dow + firstDay) % 7; + thead += '= 5 ? ' class="ui-datepicker-week-end"' : '') + '>' + + '' + dayNamesMin[day] + ''; + } + calender += thead + ''; + var daysInMonth = this._getDaysInMonth(drawYear, drawMonth); + if (drawYear == inst.selectedYear && drawMonth == inst.selectedMonth) + inst.selectedDay = Math.min(inst.selectedDay, daysInMonth); + var leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7; + var numRows = (isMultiMonth ? 6 : Math.ceil((leadDays + daysInMonth) / 7)); // calculate the number of rows to generate + var printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays)); + for (var dRow = 0; dRow < numRows; dRow++) { // create date picker rows + calender += ''; + var tbody = ''; + for (var dow = 0; dow < 7; dow++) { // create date picker days + var daySettings = (beforeShowDay ? + beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, '']); + var otherMonth = (printDate.getMonth() != drawMonth); + var unselectable = otherMonth || !daySettings[0] || + (minDate && printDate < minDate) || (maxDate && printDate > maxDate); + tbody += ''; // display for this month + printDate.setDate(printDate.getDate() + 1); + printDate = this._daylightSavingAdjust(printDate); + } + calender += tbody + ''; + } + drawMonth++; + if (drawMonth > 11) { + drawMonth = 0; + drawYear++; + } + calender += '
' + // actions + (otherMonth ? (showOtherMonths ? printDate.getDate() : ' ') : // display for other months + (unselectable ? '' + printDate.getDate() + '' : '' + printDate.getDate() + '')) + '
' + (isMultiMonth ? '
' + + ((numMonths[0] > 0 && col == numMonths[1]-1) ? '
' : '') : ''); + group += calender; + } + html += group; + } + html += buttonPanel + ($.browser.msie && parseInt($.browser.version,10) < 7 && !inst.inline ? + '' : ''); + inst._keyEvent = false; + return html; + }, + + /* Generate the month and year header. */ + _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate, + selectedDate, secondary, monthNames, monthNamesShort) { + minDate = (inst.rangeStart && minDate && selectedDate < minDate ? selectedDate : minDate); + var changeMonth = this._get(inst, 'changeMonth'); + var changeYear = this._get(inst, 'changeYear'); + var showMonthAfterYear = this._get(inst, 'showMonthAfterYear'); + var html = '
'; + var monthHtml = ''; + // month selection + if (secondary || !changeMonth) + monthHtml += '' + monthNames[drawMonth] + ' '; + else { + var inMinYear = (minDate && minDate.getFullYear() == drawYear); + var inMaxYear = (maxDate && maxDate.getFullYear() == drawYear); + monthHtml += ''; + } + if (!showMonthAfterYear) + html += monthHtml + ((secondary || changeMonth || changeYear) && (!(changeMonth && changeYear)) ? ' ' : ''); + // year selection + if (secondary || !changeYear) + html += '' + drawYear + ''; + else { + // determine range of years to display + var years = this._get(inst, 'yearRange').split(':'); + var year = 0; + var endYear = 0; + if (years.length != 2) { + year = drawYear - 10; + endYear = drawYear + 10; + } else if (years[0].charAt(0) == '+' || years[0].charAt(0) == '-') { + year = drawYear + parseInt(years[0], 10); + endYear = drawYear + parseInt(years[1], 10); + } else { + year = parseInt(years[0], 10); + endYear = parseInt(years[1], 10); + } + year = (minDate ? Math.max(year, minDate.getFullYear()) : year); + endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear); + html += ''; + } + if (showMonthAfterYear) + html += (secondary || changeMonth || changeYear ? ' ' : '') + monthHtml; + html += '
'; // Close datepicker_header + return html; + }, + + /* Adjust one of the date sub-fields. */ + _adjustInstDate: function(inst, offset, period) { + var year = inst.drawYear + (period == 'Y' ? offset : 0); + var month = inst.drawMonth + (period == 'M' ? offset : 0); + var day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + + (period == 'D' ? offset : 0); + var date = this._daylightSavingAdjust(new Date(year, month, day)); + // ensure it is within the bounds set + var minDate = this._getMinMaxDate(inst, 'min', true); + var maxDate = this._getMinMaxDate(inst, 'max'); + date = (minDate && date < minDate ? minDate : date); + date = (maxDate && date > maxDate ? maxDate : date); + inst.selectedDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = date.getFullYear(); + if (period == 'M' || period == 'Y') + this._notifyChange(inst); + }, + + /* Notify change of month/year. */ + _notifyChange: function(inst) { + var onChange = this._get(inst, 'onChangeMonthYear'); + if (onChange) + onChange.apply((inst.input ? inst.input[0] : null), + [inst.selectedYear, inst.selectedMonth + 1, inst]); + }, + + /* Determine the number of months to show. */ + _getNumberOfMonths: function(inst) { + var numMonths = this._get(inst, 'numberOfMonths'); + return (numMonths == null ? [1, 1] : (typeof numMonths == 'number' ? [1, numMonths] : numMonths)); + }, + + /* Determine the current maximum date - ensure no time components are set - may be overridden for a range. */ + _getMinMaxDate: function(inst, minMax, checkRange) { + var date = this._determineDate(this._get(inst, minMax + 'Date'), null); + return (!checkRange || !inst.rangeStart ? date : + (!date || inst.rangeStart > date ? inst.rangeStart : date)); + }, + + /* Find the number of days in a given month. */ + _getDaysInMonth: function(year, month) { + return 32 - new Date(year, month, 32).getDate(); + }, + + /* Find the day of the week of the first of a month. */ + _getFirstDayOfMonth: function(year, month) { + return new Date(year, month, 1).getDay(); + }, + + /* Determines if we should allow a "next/prev" month display change. */ + _canAdjustMonth: function(inst, offset, curYear, curMonth) { + var numMonths = this._getNumberOfMonths(inst); + var date = this._daylightSavingAdjust(new Date( + curYear, curMonth + (offset < 0 ? offset : numMonths[1]), 1)); + if (offset < 0) + date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth())); + return this._isInRange(inst, date); + }, + + /* Is the given date in the accepted range? */ + _isInRange: function(inst, date) { + // during range selection, use minimum of selected date and range start + var newMinDate = (!inst.rangeStart ? null : this._daylightSavingAdjust( + new Date(inst.selectedYear, inst.selectedMonth, inst.selectedDay))); + newMinDate = (newMinDate && inst.rangeStart < newMinDate ? inst.rangeStart : newMinDate); + var minDate = newMinDate || this._getMinMaxDate(inst, 'min'); + var maxDate = this._getMinMaxDate(inst, 'max'); + return ((!minDate || date >= minDate) && (!maxDate || date <= maxDate)); + }, + + /* Provide the configuration settings for formatting/parsing. */ + _getFormatConfig: function(inst) { + var shortYearCutoff = this._get(inst, 'shortYearCutoff'); + shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff : + new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10)); + return {shortYearCutoff: shortYearCutoff, + dayNamesShort: this._get(inst, 'dayNamesShort'), dayNames: this._get(inst, 'dayNames'), + monthNamesShort: this._get(inst, 'monthNamesShort'), monthNames: this._get(inst, 'monthNames')}; + }, + + /* Format the given date for display. */ + _formatDate: function(inst, day, month, year) { + if (!day) { + inst.currentDay = inst.selectedDay; + inst.currentMonth = inst.selectedMonth; + inst.currentYear = inst.selectedYear; + } + var date = (day ? (typeof day == 'object' ? day : + this._daylightSavingAdjust(new Date(year, month, day))) : + this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay))); + return this.formatDate(this._get(inst, 'dateFormat'), date, this._getFormatConfig(inst)); + } +}); + +/* jQuery extend now ignores nulls! */ +function extendRemove(target, props) { + $.extend(target, props); + for (var name in props) + if (props[name] == null || props[name] == undefined) + target[name] = props[name]; + return target; +}; + +/* Determine whether an object is an array. */ +function isArray(a) { + return (a && (($.browser.safari && typeof a == 'object' && a.length) || + (a.constructor && a.constructor.toString().match(/\Array\(\)/)))); +}; + +/* Invoke the datepicker functionality. + @param options string - a command, optionally followed by additional parameters or + Object - settings for attaching new datepicker functionality + @return jQuery object */ +$.fn.datepicker = function(options){ + + /* Initialise the date picker. */ + if (!$.datepicker.initialized) { + $(document).mousedown($.datepicker._checkExternalClick). + find('body').append($.datepicker.dpDiv); + $.datepicker.initialized = true; + } + + var otherArgs = Array.prototype.slice.call(arguments, 1); + if (typeof options == 'string' && (options == 'isDisabled' || options == 'getDate')) + return $.datepicker['_' + options + 'Datepicker']. + apply($.datepicker, [this[0]].concat(otherArgs)); + return this.each(function() { + typeof options == 'string' ? + $.datepicker['_' + options + 'Datepicker']. + apply($.datepicker, [this].concat(otherArgs)) : + $.datepicker._attachDatepicker(this, options); + }); +}; + +$.datepicker = new Datepicker(); // singleton instance +$.datepicker.initialized = false; +$.datepicker.uuid = new Date().getTime(); +$.datepicker.version = "1.7.1"; + +// Workaround for #4055 +// Add another global to avoid noConflict issues with inline event handlers +window.DP_jQuery = $; + +})(jQuery); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/ui.dialog.js b/js2/mwEmbed/jquery/jquery.ui/ui/ui.dialog.js new file mode 100644 index 0000000000..9f4f5e512b --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/ui.dialog.js @@ -0,0 +1,650 @@ +/* + * jQuery UI Dialog 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Dialog + * + * Depends: + * ui.core.js + * ui.draggable.js + * ui.resizable.js + */ +(function($) { + +var setDataSwitch = { + dragStart : "start.draggable", + drag : "drag.draggable", + dragStop : "stop.draggable", + maxHeight : "maxHeight.resizable", + minHeight : "minHeight.resizable", + maxWidth : "maxWidth.resizable", + minWidth : "minWidth.resizable", + resizeStart : "start.resizable", + resize : "drag.resizable", + resizeStop : "stop.resizable" + }, + + uiDialogClasses = + 'ui-dialog ' + + 'ui-widget ' + + 'ui-widget-content ' + + 'ui-corner-all '; + +$.widget("ui.dialog", { + + _init: function() { + this.originalTitle = this.element.attr('title'); + + var self = this, + options = this.options, + + title = options.title || this.originalTitle || ' ', + titleId = $.ui.dialog.getTitleId(this.element), + + uiDialog = (this.uiDialog = $('
')) + .appendTo(document.body) + .hide() + .addClass(uiDialogClasses + options.dialogClass) + .css({ + position: 'absolute', + overflow: 'hidden', + zIndex: options.zIndex + }) + // setting tabIndex makes the div focusable + // setting outline to 0 prevents a border on focus in Mozilla + .attr('tabIndex', -1).css('outline', 0).keydown(function(event) { + (options.closeOnEscape && event.keyCode + && event.keyCode == $.ui.keyCode.ESCAPE && self.close(event)); + }) + .attr({ + role: 'dialog', + 'aria-labelledby': titleId + }) + .mousedown(function(event) { + self.moveToTop(false, event); + }), + + uiDialogContent = this.element + .show() + .removeAttr('title') + .addClass( + 'ui-dialog-content ' + + 'ui-widget-content') + .appendTo(uiDialog), + + uiDialogTitlebar = (this.uiDialogTitlebar = $('
')) + .addClass( + 'ui-dialog-titlebar ' + + 'ui-widget-header ' + + 'ui-corner-all ' + + 'ui-helper-clearfix' + ) + .prependTo(uiDialog), + + uiDialogTitlebarClose = $('') + .addClass( + 'ui-dialog-titlebar-close ' + + 'ui-corner-all' + ) + .attr('role', 'button') + .hover( + function() { + uiDialogTitlebarClose.addClass('ui-state-hover'); + }, + function() { + uiDialogTitlebarClose.removeClass('ui-state-hover'); + } + ) + .focus(function() { + uiDialogTitlebarClose.addClass('ui-state-focus'); + }) + .blur(function() { + uiDialogTitlebarClose.removeClass('ui-state-focus'); + }) + .mousedown(function(ev) { + ev.stopPropagation(); + }) + .click(function(event) { + self.close(event); + return false; + }) + .appendTo(uiDialogTitlebar), + + uiDialogTitlebarCloseText = (this.uiDialogTitlebarCloseText = $('')) + .addClass( + 'ui-icon ' + + 'ui-icon-closethick' + ) + .text(options.closeText) + .appendTo(uiDialogTitlebarClose), + + uiDialogTitle = $('') + .addClass('ui-dialog-title') + .attr('id', titleId) + .html(title) + .prependTo(uiDialogTitlebar); + + uiDialogTitlebar.find("*").add(uiDialogTitlebar).disableSelection(); + + (options.draggable && $.fn.draggable && this._makeDraggable()); + (options.resizable && $.fn.resizable && this._makeResizable()); + + this._createButtons(options.buttons); + this._isOpen = false; + + (options.bgiframe && $.fn.bgiframe && uiDialog.bgiframe()); + (options.autoOpen && this.open()); + + }, + + destroy: function() { + (this.overlay && this.overlay.destroy()); + this.uiDialog.hide(); + this.element + .unbind('.dialog') + .removeData('dialog') + .removeClass('ui-dialog-content ui-widget-content') + .hide().appendTo('body'); + this.uiDialog.remove(); + + (this.originalTitle && this.element.attr('title', this.originalTitle)); + }, + + close: function(event) { + var self = this; + + if (false === self._trigger('beforeclose', event)) { + return; + } + + (self.overlay && self.overlay.destroy()); + self.uiDialog.unbind('keypress.ui-dialog'); + + (self.options.hide + ? self.uiDialog.hide(self.options.hide, function() { + self._trigger('close', event); + }) + : self.uiDialog.hide() && self._trigger('close', event)); + + $.ui.dialog.overlay.resize(); + + self._isOpen = false; + }, + + isOpen: function() { + return this._isOpen; + }, + + // the force parameter allows us to move modal dialogs to their correct + // position on open + moveToTop: function(force, event) { + + if ((this.options.modal && !force) + || (!this.options.stack && !this.options.modal)) { + return this._trigger('focus', event); + } + + if (this.options.zIndex > $.ui.dialog.maxZ) { + $.ui.dialog.maxZ = this.options.zIndex; + } + (this.overlay && this.overlay.$el.css('z-index', $.ui.dialog.overlay.maxZ = ++$.ui.dialog.maxZ)); + + //Save and then restore scroll since Opera 9.5+ resets when parent z-Index is changed. + // http://ui.jquery.com/bugs/ticket/3193 + var saveScroll = { scrollTop: this.element.attr('scrollTop'), scrollLeft: this.element.attr('scrollLeft') }; + this.uiDialog.css('z-index', ++$.ui.dialog.maxZ); + this.element.attr(saveScroll); + this._trigger('focus', event); + }, + + open: function() { + if (this._isOpen) { return; } + + var options = this.options, + uiDialog = this.uiDialog; + + this.overlay = options.modal ? new $.ui.dialog.overlay(this) : null; + (uiDialog.next().length && uiDialog.appendTo('body')); + this._size(); + this._position(options.position); + uiDialog.show(options.show); + this.moveToTop(true); + + // prevent tabbing out of modal dialogs + (options.modal && uiDialog.bind('keypress.ui-dialog', function(event) { + if (event.keyCode != $.ui.keyCode.TAB) { + return; + } + + var tabbables = $(':tabbable', this), + first = tabbables.filter(':first')[0], + last = tabbables.filter(':last')[0]; + + if (event.target == last && !event.shiftKey) { + setTimeout(function() { + first.focus(); + }, 1); + } else if (event.target == first && event.shiftKey) { + setTimeout(function() { + last.focus(); + }, 1); + } + })); + + // set focus to the first tabbable element in the content area or the first button + // if there are no tabbable elements, set focus on the dialog itself + $([]) + .add(uiDialog.find('.ui-dialog-content :tabbable:first')) + .add(uiDialog.find('.ui-dialog-buttonpane :tabbable:first')) + .add(uiDialog) + .filter(':first') + .focus(); + + this._trigger('open'); + this._isOpen = true; + }, + + _createButtons: function(buttons) { + var self = this, + hasButtons = false, + uiDialogButtonPane = $('
') + .addClass( + 'ui-dialog-buttonpane ' + + 'ui-widget-content ' + + 'ui-helper-clearfix' + ); + + // if we already have a button pane, remove it + this.uiDialog.find('.ui-dialog-buttonpane').remove(); + + (typeof buttons == 'object' && buttons !== null && + $.each(buttons, function() { return !(hasButtons = true); })); + if (hasButtons) { + $.each(buttons, function(name, fn) { + $('') + .addClass( + 'ui-state-default ' + + 'ui-corner-all' + ) + .text(name) + .click(function() { fn.apply(self.element[0], arguments); }) + .hover( + function() { + $(this).addClass('ui-state-hover'); + }, + function() { + $(this).removeClass('ui-state-hover'); + } + ) + .focus(function() { + $(this).addClass('ui-state-focus'); + }) + .blur(function() { + $(this).removeClass('ui-state-focus'); + }) + .appendTo(uiDialogButtonPane); + }); + uiDialogButtonPane.appendTo(this.uiDialog); + } + }, + + _makeDraggable: function() { + var self = this, + options = this.options, + heightBeforeDrag; + + this.uiDialog.draggable({ + cancel: '.ui-dialog-content', + handle: '.ui-dialog-titlebar', + containment: 'document', + start: function() { + heightBeforeDrag = options.height; + $(this).height($(this).height()).addClass("ui-dialog-dragging"); + (options.dragStart && options.dragStart.apply(self.element[0], arguments)); + }, + drag: function() { + (options.drag && options.drag.apply(self.element[0], arguments)); + }, + stop: function() { + $(this).removeClass("ui-dialog-dragging").height(heightBeforeDrag); + (options.dragStop && options.dragStop.apply(self.element[0], arguments)); + $.ui.dialog.overlay.resize(); + } + }); + }, + + _makeResizable: function(handles) { + handles = (handles === undefined ? this.options.resizable : handles); + var self = this, + options = this.options, + resizeHandles = typeof handles == 'string' + ? handles + : 'n,e,s,w,se,sw,ne,nw'; + + this.uiDialog.resizable({ + cancel: '.ui-dialog-content', + alsoResize: this.element, + maxWidth: options.maxWidth, + maxHeight: options.maxHeight, + minWidth: options.minWidth, + minHeight: options.minHeight, + start: function() { + $(this).addClass("ui-dialog-resizing"); + (options.resizeStart && options.resizeStart.apply(self.element[0], arguments)); + }, + resize: function() { + (options.resize && options.resize.apply(self.element[0], arguments)); + }, + handles: resizeHandles, + stop: function() { + $(this).removeClass("ui-dialog-resizing"); + options.height = $(this).height(); + options.width = $(this).width(); + (options.resizeStop && options.resizeStop.apply(self.element[0], arguments)); + $.ui.dialog.overlay.resize(); + } + }) + .find('.ui-resizable-se').addClass('ui-icon ui-icon-grip-diagonal-se'); + }, + + _position: function(pos) { + var wnd = $(window), doc = $(document), + pTop = doc.scrollTop(), pLeft = doc.scrollLeft(), + minTop = pTop; + + if ($.inArray(pos, ['center','top','right','bottom','left']) >= 0) { + pos = [ + pos == 'right' || pos == 'left' ? pos : 'center', + pos == 'top' || pos == 'bottom' ? pos : 'middle' + ]; + } + if (pos.constructor != Array) { + pos = ['center', 'middle']; + } + if (pos[0].constructor == Number) { + pLeft += pos[0]; + } else { + switch (pos[0]) { + case 'left': + pLeft += 0; + break; + case 'right': + pLeft += wnd.width() - this.uiDialog.outerWidth(); + break; + default: + case 'center': + pLeft += (wnd.width() - this.uiDialog.outerWidth()) / 2; + } + } + if (pos[1].constructor == Number) { + pTop += pos[1]; + } else { + switch (pos[1]) { + case 'top': + pTop += 0; + break; + case 'bottom': + pTop += wnd.height() - this.uiDialog.outerHeight(); + break; + default: + case 'middle': + pTop += (wnd.height() - this.uiDialog.outerHeight()) / 2; + } + } + + // prevent the dialog from being too high (make sure the titlebar + // is accessible) + pTop = Math.max(pTop, minTop); + this.uiDialog.css({top: pTop, left: pLeft}); + }, + + _setData: function(key, value){ + (setDataSwitch[key] && this.uiDialog.data(setDataSwitch[key], value)); + switch (key) { + case "buttons": + this._createButtons(value); + break; + case "closeText": + this.uiDialogTitlebarCloseText.text(value); + break; + case "dialogClass": + this.uiDialog + .removeClass(this.options.dialogClass) + .addClass(uiDialogClasses + value); + break; + case "draggable": + (value + ? this._makeDraggable() + : this.uiDialog.draggable('destroy')); + break; + case "height": + this.uiDialog.height(value); + break; + case "position": + this._position(value); + break; + case "resizable": + var uiDialog = this.uiDialog, + isResizable = this.uiDialog.is(':data(resizable)'); + + // currently resizable, becoming non-resizable + (isResizable && !value && uiDialog.resizable('destroy')); + + // currently resizable, changing handles + (isResizable && typeof value == 'string' && + uiDialog.resizable('option', 'handles', value)); + + // currently non-resizable, becoming resizable + (isResizable || this._makeResizable(value)); + break; + case "title": + $(".ui-dialog-title", this.uiDialogTitlebar).html(value || ' '); + break; + case "width": + this.uiDialog.width(value); + break; + } + + $.widget.prototype._setData.apply(this, arguments); + }, + + _size: function() { + /* If the user has resized the dialog, the .ui-dialog and .ui-dialog-content + * divs will both have width and height set, so we need to reset them + */ + var options = this.options; + + // reset content sizing + this.element.css({ + height: 0, + minHeight: 0, + width: 'auto' + }); + + // reset wrapper sizing + // determine the height of all the non-content elements + var nonContentHeight = this.uiDialog.css({ + height: 'auto', + width: options.width + }) + .height(); + + this.element + .css({ + minHeight: Math.max(options.minHeight - nonContentHeight, 0), + height: options.height == 'auto' + ? 'auto' + : Math.max(options.height - nonContentHeight, 0) + }); + } +}); + +$.extend($.ui.dialog, { + version: "1.7.1", + defaults: { + autoOpen: true, + bgiframe: false, + buttons: {}, + closeOnEscape: true, + closeText: 'close', + dialogClass: '', + draggable: true, + hide: null, + height: 'auto', + maxHeight: false, + maxWidth: false, + minHeight: 150, + minWidth: 150, + modal: false, + position: 'center', + resizable: true, + show: null, + stack: true, + title: '', + width: 300, + zIndex: 1000 + }, + + getter: 'isOpen', + + uuid: 0, + maxZ: 0, + + getTitleId: function($el) { + return 'ui-dialog-title-' + ($el.attr('id') || ++this.uuid); + }, + + overlay: function(dialog) { + this.$el = $.ui.dialog.overlay.create(dialog); + } +}); + +$.extend($.ui.dialog.overlay, { + instances: [], + maxZ: 0, + events: $.map('focus,mousedown,mouseup,keydown,keypress,click'.split(','), + function(event) { return event + '.dialog-overlay'; }).join(' '), + create: function(dialog) { + if (this.instances.length === 0) { + // prevent use of anchors and inputs + // we use a setTimeout in case the overlay is created from an + // event that we're going to be cancelling (see #2804) + setTimeout(function() { + $(document).bind($.ui.dialog.overlay.events, function(event) { + var dialogZ = $(event.target).parents('.ui-dialog').css('zIndex') || 0; + return (dialogZ > $.ui.dialog.overlay.maxZ); + }); + }, 1); + + // allow closing by pressing the escape key + $(document).bind('keydown.dialog-overlay', function(event) { + (dialog.options.closeOnEscape && event.keyCode + && event.keyCode == $.ui.keyCode.ESCAPE && dialog.close(event)); + }); + + // handle window resize + $(window).bind('resize.dialog-overlay', $.ui.dialog.overlay.resize); + } + + var $el = $('
').appendTo(document.body) + .addClass('ui-widget-overlay').css({ + width: this.width(), + height: this.height() + }); + + (dialog.options.bgiframe && $.fn.bgiframe && $el.bgiframe()); + + this.instances.push($el); + return $el; + }, + + destroy: function($el) { + this.instances.splice($.inArray(this.instances, $el), 1); + + if (this.instances.length === 0) { + $([document, window]).unbind('.dialog-overlay'); + } + + $el.remove(); + }, + + height: function() { + // handle IE 6 + if ($.browser.msie && $.browser.version < 7) { + var scrollHeight = Math.max( + document.documentElement.scrollHeight, + document.body.scrollHeight + ); + var offsetHeight = Math.max( + document.documentElement.offsetHeight, + document.body.offsetHeight + ); + + if (scrollHeight < offsetHeight) { + return $(window).height() + 'px'; + } else { + return scrollHeight + 'px'; + } + // handle "good" browsers + } else { + return $(document).height() + 'px'; + } + }, + + width: function() { + // handle IE 6 + if ($.browser.msie && $.browser.version < 7) { + var scrollWidth = Math.max( + document.documentElement.scrollWidth, + document.body.scrollWidth + ); + var offsetWidth = Math.max( + document.documentElement.offsetWidth, + document.body.offsetWidth + ); + + if (scrollWidth < offsetWidth) { + return $(window).width() + 'px'; + } else { + return scrollWidth + 'px'; + } + // handle "good" browsers + } else { + return $(document).width() + 'px'; + } + }, + + resize: function() { + /* If the dialog is draggable and the user drags it past the + * right edge of the window, the document becomes wider so we + * need to stretch the overlay. If the user then drags the + * dialog back to the left, the document will become narrower, + * so we need to shrink the overlay to the appropriate size. + * This is handled by shrinking the overlay before setting it + * to the full document size. + */ + var $overlays = $([]); + $.each($.ui.dialog.overlay.instances, function() { + $overlays = $overlays.add(this); + }); + + $overlays.css({ + width: 0, + height: 0 + }).css({ + width: $.ui.dialog.overlay.width(), + height: $.ui.dialog.overlay.height() + }); + } +}); + +$.extend($.ui.dialog.overlay.prototype, { + destroy: function() { + $.ui.dialog.overlay.destroy(this.$el); + } +}); + +})(jQuery); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/ui.draggable.js b/js2/mwEmbed/jquery/jquery.ui/ui/ui.draggable.js new file mode 100644 index 0000000000..e07d1c8a31 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/ui.draggable.js @@ -0,0 +1,766 @@ +/* + * jQuery UI Draggable 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Draggables + * + * Depends: + * ui.core.js + */ +(function($) { + +$.widget("ui.draggable", $.extend({}, $.ui.mouse, { + + _init: function() { + + if (this.options.helper == 'original' && !(/^(?:r|a|f)/).test(this.element.css("position"))) + this.element[0].style.position = 'relative'; + + (this.options.addClasses && this.element.addClass("ui-draggable")); + (this.options.disabled && this.element.addClass("ui-draggable-disabled")); + + this._mouseInit(); + + }, + + destroy: function() { + if(!this.element.data('draggable')) return; + this.element + .removeData("draggable") + .unbind(".draggable") + .removeClass("ui-draggable" + + " ui-draggable-dragging" + + " ui-draggable-disabled"); + this._mouseDestroy(); + }, + + _mouseCapture: function(event) { + + var o = this.options; + + if (this.helper || o.disabled || $(event.target).is('.ui-resizable-handle')) + return false; + + //Quit if we're not on a valid handle + this.handle = this._getHandle(event); + if (!this.handle) + return false; + + return true; + + }, + + _mouseStart: function(event) { + + var o = this.options; + + //Create and append the visible helper + this.helper = this._createHelper(event); + + //Cache the helper size + this._cacheHelperProportions(); + + //If ddmanager is used for droppables, set the global draggable + if($.ui.ddmanager) + $.ui.ddmanager.current = this; + + /* + * - Position generation - + * This block generates everything position related - it's the core of draggables. + */ + + //Cache the margins of the original element + this._cacheMargins(); + + //Store the helper's css position + this.cssPosition = this.helper.css("position"); + this.scrollParent = this.helper.scrollParent(); + + //The element's absolute position on the page minus margins + this.offset = this.element.offset(); + this.offset = { + top: this.offset.top - this.margins.top, + left: this.offset.left - this.margins.left + }; + + $.extend(this.offset, { + click: { //Where the click happened, relative to the element + left: event.pageX - this.offset.left, + top: event.pageY - this.offset.top + }, + parent: this._getParentOffset(), + relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper + }); + + //Generate the original position + this.originalPosition = this._generatePosition(event); + this.originalPageX = event.pageX; + this.originalPageY = event.pageY; + + //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied + if(o.cursorAt) + this._adjustOffsetFromHelper(o.cursorAt); + + //Set a containment if given in the options + if(o.containment) + this._setContainment(); + + //Call plugins and callbacks + this._trigger("start", event); + + //Recache the helper size + this._cacheHelperProportions(); + + //Prepare the droppable offsets + if ($.ui.ddmanager && !o.dropBehaviour) + $.ui.ddmanager.prepareOffsets(this, event); + + this.helper.addClass("ui-draggable-dragging"); + this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position + return true; + }, + + _mouseDrag: function(event, noPropagation) { + + //Compute the helpers position + this.position = this._generatePosition(event); + this.positionAbs = this._convertPositionTo("absolute"); + + //Call plugins and callbacks and use the resulting position if something is returned + if (!noPropagation) { + var ui = this._uiHash(); + this._trigger('drag', event, ui); + this.position = ui.position; + } + + if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px'; + if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px'; + if($.ui.ddmanager) $.ui.ddmanager.drag(this, event); + + return false; + }, + + _mouseStop: function(event) { + + //If we are using droppables, inform the manager about the drop + var dropped = false; + if ($.ui.ddmanager && !this.options.dropBehaviour) + dropped = $.ui.ddmanager.drop(this, event); + + //if a drop comes from outside (a sortable) + if(this.dropped) { + dropped = this.dropped; + this.dropped = false; + } + + if((this.options.revert == "invalid" && !dropped) || (this.options.revert == "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) { + var self = this; + $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() { + self._trigger("stop", event); + self._clear(); + }); + } else { + this._trigger("stop", event); + this._clear(); + } + + return false; + }, + + _getHandle: function(event) { + + var handle = !this.options.handle || !$(this.options.handle, this.element).length ? true : false; + $(this.options.handle, this.element) + .find("*") + .andSelf() + .each(function() { + if(this == event.target) handle = true; + }); + + return handle; + + }, + + _createHelper: function(event) { + + var o = this.options; + var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper == 'clone' ? this.element.clone() : this.element); + + if(!helper.parents('body').length) + helper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo)); + + if(helper[0] != this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) + helper.css("position", "absolute"); + + return helper; + + }, + + _adjustOffsetFromHelper: function(obj) { + if(obj.left != undefined) this.offset.click.left = obj.left + this.margins.left; + if(obj.right != undefined) this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; + if(obj.top != undefined) this.offset.click.top = obj.top + this.margins.top; + if(obj.bottom != undefined) this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; + }, + + _getParentOffset: function() { + + //Get the offsetParent and cache its position + this.offsetParent = this.helper.offsetParent(); + var po = this.offsetParent.offset(); + + // This is a special case where we need to modify a offset calculated on start, since the following happened: + // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent + // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that + // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag + if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) { + po.left += this.scrollParent.scrollLeft(); + po.top += this.scrollParent.scrollTop(); + } + + if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information + || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix + po = { top: 0, left: 0 }; + + return { + top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), + left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) + }; + + }, + + _getRelativeOffset: function() { + + if(this.cssPosition == "relative") { + var p = this.element.position(); + return { + top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), + left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() + }; + } else { + return { top: 0, left: 0 }; + } + + }, + + _cacheMargins: function() { + this.margins = { + left: (parseInt(this.element.css("marginLeft"),10) || 0), + top: (parseInt(this.element.css("marginTop"),10) || 0) + }; + }, + + _cacheHelperProportions: function() { + this.helperProportions = { + width: this.helper.outerWidth(), + height: this.helper.outerHeight() + }; + }, + + _setContainment: function() { + + var o = this.options; + if(o.containment == 'parent') o.containment = this.helper[0].parentNode; + if(o.containment == 'document' || o.containment == 'window') this.containment = [ + 0 - this.offset.relative.left - this.offset.parent.left, + 0 - this.offset.relative.top - this.offset.parent.top, + $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left, + ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top + ]; + + if(!(/^(document|window|parent)$/).test(o.containment) && o.containment.constructor != Array) { + var ce = $(o.containment)[0]; if(!ce) return; + var co = $(o.containment).offset(); + var over = ($(ce).css("overflow") != 'hidden'); + + this.containment = [ + co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left, + co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top, + co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left, + co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top + ]; + } else if(o.containment.constructor == Array) { + this.containment = o.containment; + } + + }, + + _convertPositionTo: function(d, pos) { + + if(!pos) pos = this.position; + var mod = d == "absolute" ? 1 : -1; + var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); + + return { + top: ( + pos.top // The absolute mouse position + + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent + + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border) + - ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) + ), + left: ( + pos.left // The absolute mouse position + + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent + + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border) + - ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) + ) + }; + + }, + + _generatePosition: function(event) { + + var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); + + // This is another very weird special case that only happens for relative elements: + // 1. If the css position is relative + // 2. and the scroll parent is the document or similar to the offset parent + // we have to refresh the relative offset during the scroll so there are no jumps + if(this.cssPosition == 'relative' && !(this.scrollParent[0] != document && this.scrollParent[0] != this.offsetParent[0])) { + this.offset.relative = this._getRelativeOffset(); + } + + var pageX = event.pageX; + var pageY = event.pageY; + + /* + * - Position constraining - + * Constrain the position to a mix of grid, containment. + */ + + if(this.originalPosition) { //If we are not dragging yet, we won't check for options + + if(this.containment) { + if(event.pageX - this.offset.click.left < this.containment[0]) pageX = this.containment[0] + this.offset.click.left; + if(event.pageY - this.offset.click.top < this.containment[1]) pageY = this.containment[1] + this.offset.click.top; + if(event.pageX - this.offset.click.left > this.containment[2]) pageX = this.containment[2] + this.offset.click.left; + if(event.pageY - this.offset.click.top > this.containment[3]) pageY = this.containment[3] + this.offset.click.top; + } + + if(o.grid) { + var top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1]; + pageY = this.containment ? (!(top - this.offset.click.top < this.containment[1] || top - this.offset.click.top > this.containment[3]) ? top : (!(top - this.offset.click.top < this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; + + var left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0]; + pageX = this.containment ? (!(left - this.offset.click.left < this.containment[0] || left - this.offset.click.left > this.containment[2]) ? left : (!(left - this.offset.click.left < this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; + } + + } + + return { + top: ( + pageY // The absolute mouse position + - this.offset.click.top // Click offset (relative to the element) + - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent + - this.offset.parent.top // The offsetParent's offset without borders (offset + border) + + ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) + ), + left: ( + pageX // The absolute mouse position + - this.offset.click.left // Click offset (relative to the element) + - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent + - this.offset.parent.left // The offsetParent's offset without borders (offset + border) + + ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) + ) + }; + + }, + + _clear: function() { + this.helper.removeClass("ui-draggable-dragging"); + if(this.helper[0] != this.element[0] && !this.cancelHelperRemoval) this.helper.remove(); + //if($.ui.ddmanager) $.ui.ddmanager.current = null; + this.helper = null; + this.cancelHelperRemoval = false; + }, + + // From now on bulk stuff - mainly helpers + + _trigger: function(type, event, ui) { + ui = ui || this._uiHash(); + $.ui.plugin.call(this, type, [event, ui]); + if(type == "drag") this.positionAbs = this._convertPositionTo("absolute"); //The absolute position has to be recalculated after plugins + return $.widget.prototype._trigger.call(this, type, event, ui); + }, + + plugins: {}, + + _uiHash: function(event) { + return { + helper: this.helper, + position: this.position, + absolutePosition: this.positionAbs, //deprecated + offset: this.positionAbs + }; + } + +})); + +$.extend($.ui.draggable, { + version: "1.7.1", + eventPrefix: "drag", + defaults: { + addClasses: true, + appendTo: "parent", + axis: false, + cancel: ":input,option", + connectToSortable: false, + containment: false, + cursor: "auto", + cursorAt: false, + delay: 0, + distance: 1, + grid: false, + handle: false, + helper: "original", + iframeFix: false, + opacity: false, + refreshPositions: false, + revert: false, + revertDuration: 500, + scope: "default", + scroll: true, + scrollSensitivity: 20, + scrollSpeed: 20, + snap: false, + snapMode: "both", + snapTolerance: 20, + stack: false, + zIndex: false + } +}); + +$.ui.plugin.add("draggable", "connectToSortable", { + start: function(event, ui) { + + var inst = $(this).data("draggable"), o = inst.options, + uiSortable = $.extend({}, ui, { item: inst.element }); + inst.sortables = []; + $(o.connectToSortable).each(function() { + var sortable = $.data(this, 'sortable'); + if (sortable && !sortable.options.disabled) { + inst.sortables.push({ + instance: sortable, + shouldRevert: sortable.options.revert + }); + sortable._refreshItems(); //Do a one-time refresh at start to refresh the containerCache + sortable._trigger("activate", event, uiSortable); + } + }); + + }, + stop: function(event, ui) { + + //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper + var inst = $(this).data("draggable"), + uiSortable = $.extend({}, ui, { item: inst.element }); + + $.each(inst.sortables, function() { + if(this.instance.isOver) { + + this.instance.isOver = 0; + + inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance + this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work) + + //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: 'valid/invalid' + if(this.shouldRevert) this.instance.options.revert = true; + + //Trigger the stop of the sortable + this.instance._mouseStop(event); + + this.instance.options.helper = this.instance.options._helper; + + //If the helper has been the original item, restore properties in the sortable + if(inst.options.helper == 'original') + this.instance.currentItem.css({ top: 'auto', left: 'auto' }); + + } else { + this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance + this.instance._trigger("deactivate", event, uiSortable); + } + + }); + + }, + drag: function(event, ui) { + + var inst = $(this).data("draggable"), self = this; + + var checkPos = function(o) { + var dyClick = this.offset.click.top, dxClick = this.offset.click.left; + var helperTop = this.positionAbs.top, helperLeft = this.positionAbs.left; + var itemHeight = o.height, itemWidth = o.width; + var itemTop = o.top, itemLeft = o.left; + + return $.ui.isOver(helperTop + dyClick, helperLeft + dxClick, itemTop, itemLeft, itemHeight, itemWidth); + }; + + $.each(inst.sortables, function(i) { + + //Copy over some variables to allow calling the sortable's native _intersectsWith + this.instance.positionAbs = inst.positionAbs; + this.instance.helperProportions = inst.helperProportions; + this.instance.offset.click = inst.offset.click; + + if(this.instance._intersectsWith(this.instance.containerCache)) { + + //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once + if(!this.instance.isOver) { + + this.instance.isOver = 1; + //Now we fake the start of dragging for the sortable instance, + //by cloning the list group item, appending it to the sortable and using it as inst.currentItem + //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one) + this.instance.currentItem = $(self).clone().appendTo(this.instance.element).data("sortable-item", true); + this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it + this.instance.options.helper = function() { return ui.helper[0]; }; + + event.target = this.instance.currentItem[0]; + this.instance._mouseCapture(event, true); + this.instance._mouseStart(event, true, true); + + //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes + this.instance.offset.click.top = inst.offset.click.top; + this.instance.offset.click.left = inst.offset.click.left; + this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left; + this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top; + + inst._trigger("toSortable", event); + inst.dropped = this.instance.element; //draggable revert needs that + //hack so receive/update callbacks work (mostly) + inst.currentItem = inst.element; + this.instance.fromOutside = inst; + + } + + //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable + if(this.instance.currentItem) this.instance._mouseDrag(event); + + } else { + + //If it doesn't intersect with the sortable, and it intersected before, + //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval + if(this.instance.isOver) { + + this.instance.isOver = 0; + this.instance.cancelHelperRemoval = true; + + //Prevent reverting on this forced stop + this.instance.options.revert = false; + + // The out event needs to be triggered independently + this.instance._trigger('out', event, this.instance._uiHash(this.instance)); + + this.instance._mouseStop(event, true); + this.instance.options.helper = this.instance.options._helper; + + //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size + this.instance.currentItem.remove(); + if(this.instance.placeholder) this.instance.placeholder.remove(); + + inst._trigger("fromSortable", event); + inst.dropped = false; //draggable revert needs that + } + + }; + + }); + + } +}); + +$.ui.plugin.add("draggable", "cursor", { + start: function(event, ui) { + var t = $('body'), o = $(this).data('draggable').options; + if (t.css("cursor")) o._cursor = t.css("cursor"); + t.css("cursor", o.cursor); + }, + stop: function(event, ui) { + var o = $(this).data('draggable').options; + if (o._cursor) $('body').css("cursor", o._cursor); + } +}); + +$.ui.plugin.add("draggable", "iframeFix", { + start: function(event, ui) { + var o = $(this).data('draggable').options; + $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() { + $('
') + .css({ + width: this.offsetWidth+"px", height: this.offsetHeight+"px", + position: "absolute", opacity: "0.001", zIndex: 1000 + }) + .css($(this).offset()) + .appendTo("body"); + }); + }, + stop: function(event, ui) { + $("div.ui-draggable-iframeFix").each(function() { this.parentNode.removeChild(this); }); //Remove frame helpers + } +}); + +$.ui.plugin.add("draggable", "opacity", { + start: function(event, ui) { + var t = $(ui.helper), o = $(this).data('draggable').options; + if(t.css("opacity")) o._opacity = t.css("opacity"); + t.css('opacity', o.opacity); + }, + stop: function(event, ui) { + var o = $(this).data('draggable').options; + if(o._opacity) $(ui.helper).css('opacity', o._opacity); + } +}); + +$.ui.plugin.add("draggable", "scroll", { + start: function(event, ui) { + var i = $(this).data("draggable"); + if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') i.overflowOffset = i.scrollParent.offset(); + }, + drag: function(event, ui) { + + var i = $(this).data("draggable"), o = i.options, scrolled = false; + + if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') { + + if(!o.axis || o.axis != 'x') { + if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) + i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed; + else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity) + i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed; + } + + if(!o.axis || o.axis != 'y') { + if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) + i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed; + else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity) + i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed; + } + + } else { + + if(!o.axis || o.axis != 'x') { + if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) + scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); + else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) + scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); + } + + if(!o.axis || o.axis != 'y') { + if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) + scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); + else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) + scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); + } + + } + + if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) + $.ui.ddmanager.prepareOffsets(i, event); + + } +}); + +$.ui.plugin.add("draggable", "snap", { + start: function(event, ui) { + + var i = $(this).data("draggable"), o = i.options; + i.snapElements = []; + + $(o.snap.constructor != String ? ( o.snap.items || ':data(draggable)' ) : o.snap).each(function() { + var $t = $(this); var $o = $t.offset(); + if(this != i.element[0]) i.snapElements.push({ + item: this, + width: $t.outerWidth(), height: $t.outerHeight(), + top: $o.top, left: $o.left + }); + }); + + }, + drag: function(event, ui) { + + var inst = $(this).data("draggable"), o = inst.options; + var d = o.snapTolerance; + + var x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width, + y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height; + + for (var i = inst.snapElements.length - 1; i >= 0; i--){ + + var l = inst.snapElements[i].left, r = l + inst.snapElements[i].width, + t = inst.snapElements[i].top, b = t + inst.snapElements[i].height; + + //Yes, I know, this is insane ;) + if(!((l-d < x1 && x1 < r+d && t-d < y1 && y1 < b+d) || (l-d < x1 && x1 < r+d && t-d < y2 && y2 < b+d) || (l-d < x2 && x2 < r+d && t-d < y1 && y1 < b+d) || (l-d < x2 && x2 < r+d && t-d < y2 && y2 < b+d))) { + if(inst.snapElements[i].snapping) (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); + inst.snapElements[i].snapping = false; + continue; + } + + if(o.snapMode != 'inner') { + var ts = Math.abs(t - y2) <= d; + var bs = Math.abs(b - y1) <= d; + var ls = Math.abs(l - x2) <= d; + var rs = Math.abs(r - x1) <= d; + if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top; + if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top; + if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left; + if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left; + } + + var first = (ts || bs || ls || rs); + + if(o.snapMode != 'outer') { + var ts = Math.abs(t - y1) <= d; + var bs = Math.abs(b - y2) <= d; + var ls = Math.abs(l - x1) <= d; + var rs = Math.abs(r - x2) <= d; + if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top; + if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top; + if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left; + if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left; + } + + if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) + (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); + inst.snapElements[i].snapping = (ts || bs || ls || rs || first); + + }; + + } +}); + +$.ui.plugin.add("draggable", "stack", { + start: function(event, ui) { + + var o = $(this).data("draggable").options; + + var group = $.makeArray($(o.stack.group)).sort(function(a,b) { + return (parseInt($(a).css("zIndex"),10) || o.stack.min) - (parseInt($(b).css("zIndex"),10) || o.stack.min); + }); + + $(group).each(function(i) { + this.style.zIndex = o.stack.min + i; + }); + + this[0].style.zIndex = o.stack.min + group.length; + + } +}); + +$.ui.plugin.add("draggable", "zIndex", { + start: function(event, ui) { + var t = $(ui.helper), o = $(this).data("draggable").options; + if(t.css("zIndex")) o._zIndex = t.css("zIndex"); + t.css('zIndex', o.zIndex); + }, + stop: function(event, ui) { + var o = $(this).data("draggable").options; + if(o._zIndex) $(ui.helper).css('zIndex', o._zIndex); + } +}); + +})(jQuery); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/ui.droppable.js b/js2/mwEmbed/jquery/jquery.ui/ui/ui.droppable.js new file mode 100644 index 0000000000..22fcbafa93 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/ui.droppable.js @@ -0,0 +1,282 @@ +/* + * jQuery UI Droppable 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Droppables + * + * Depends: + * ui.core.js + * ui.draggable.js + */ +(function($) { + +$.widget("ui.droppable", { + + _init: function() { + + var o = this.options, accept = o.accept; + this.isover = 0; this.isout = 1; + + this.options.accept = this.options.accept && $.isFunction(this.options.accept) ? this.options.accept : function(d) { + return d.is(accept); + }; + + //Store the droppable's proportions + this.proportions = { width: this.element[0].offsetWidth, height: this.element[0].offsetHeight }; + + // Add the reference and positions to the manager + $.ui.ddmanager.droppables[this.options.scope] = $.ui.ddmanager.droppables[this.options.scope] || []; + $.ui.ddmanager.droppables[this.options.scope].push(this); + + (this.options.addClasses && this.element.addClass("ui-droppable")); + + }, + + destroy: function() { + var drop = $.ui.ddmanager.droppables[this.options.scope]; + for ( var i = 0; i < drop.length; i++ ) + if ( drop[i] == this ) + drop.splice(i, 1); + + this.element + .removeClass("ui-droppable ui-droppable-disabled") + .removeData("droppable") + .unbind(".droppable"); + }, + + _setData: function(key, value) { + + if(key == 'accept') { + this.options.accept = value && $.isFunction(value) ? value : function(d) { + return d.is(value); + }; + } else { + $.widget.prototype._setData.apply(this, arguments); + } + + }, + + _activate: function(event) { + var draggable = $.ui.ddmanager.current; + if(this.options.activeClass) this.element.addClass(this.options.activeClass); + (draggable && this._trigger('activate', event, this.ui(draggable))); + }, + + _deactivate: function(event) { + var draggable = $.ui.ddmanager.current; + if(this.options.activeClass) this.element.removeClass(this.options.activeClass); + (draggable && this._trigger('deactivate', event, this.ui(draggable))); + }, + + _over: function(event) { + + var draggable = $.ui.ddmanager.current; + if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element + + if (this.options.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { + if(this.options.hoverClass) this.element.addClass(this.options.hoverClass); + this._trigger('over', event, this.ui(draggable)); + } + + }, + + _out: function(event) { + + var draggable = $.ui.ddmanager.current; + if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element + + if (this.options.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { + if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass); + this._trigger('out', event, this.ui(draggable)); + } + + }, + + _drop: function(event,custom) { + + var draggable = custom || $.ui.ddmanager.current; + if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return false; // Bail if draggable and droppable are same element + + var childrenIntersection = false; + this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function() { + var inst = $.data(this, 'droppable'); + if(inst.options.greedy && $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance)) { + childrenIntersection = true; return false; + } + }); + if(childrenIntersection) return false; + + if(this.options.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { + if(this.options.activeClass) this.element.removeClass(this.options.activeClass); + if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass); + this._trigger('drop', event, this.ui(draggable)); + return this.element; + } + + return false; + + }, + + ui: function(c) { + return { + draggable: (c.currentItem || c.element), + helper: c.helper, + position: c.position, + absolutePosition: c.positionAbs, //deprecated + offset: c.positionAbs + }; + } + +}); + +$.extend($.ui.droppable, { + version: "1.7.1", + eventPrefix: 'drop', + defaults: { + accept: '*', + activeClass: false, + addClasses: true, + greedy: false, + hoverClass: false, + scope: 'default', + tolerance: 'intersect' + } +}); + +$.ui.intersect = function(draggable, droppable, toleranceMode) { + + if (!droppable.offset) return false; + + var x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width, + y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height; + var l = droppable.offset.left, r = l + droppable.proportions.width, + t = droppable.offset.top, b = t + droppable.proportions.height; + + switch (toleranceMode) { + case 'fit': + return (l < x1 && x2 < r + && t < y1 && y2 < b); + break; + case 'intersect': + return (l < x1 + (draggable.helperProportions.width / 2) // Right Half + && x2 - (draggable.helperProportions.width / 2) < r // Left Half + && t < y1 + (draggable.helperProportions.height / 2) // Bottom Half + && y2 - (draggable.helperProportions.height / 2) < b ); // Top Half + break; + case 'pointer': + var draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left), + draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top), + isOver = $.ui.isOver(draggableTop, draggableLeft, t, l, droppable.proportions.height, droppable.proportions.width); + return isOver; + break; + case 'touch': + return ( + (y1 >= t && y1 <= b) || // Top edge touching + (y2 >= t && y2 <= b) || // Bottom edge touching + (y1 < t && y2 > b) // Surrounded vertically + ) && ( + (x1 >= l && x1 <= r) || // Left edge touching + (x2 >= l && x2 <= r) || // Right edge touching + (x1 < l && x2 > r) // Surrounded horizontally + ); + break; + default: + return false; + break; + } + +}; + +/* + This manager tracks offsets of draggables and droppables +*/ +$.ui.ddmanager = { + current: null, + droppables: { 'default': [] }, + prepareOffsets: function(t, event) { + + var m = $.ui.ddmanager.droppables[t.options.scope]; + var type = event ? event.type : null; // workaround for #2317 + var list = (t.currentItem || t.element).find(":data(droppable)").andSelf(); + + droppablesLoop: for (var i = 0; i < m.length; i++) { + + if(m[i].options.disabled || (t && !m[i].options.accept.call(m[i].element[0],(t.currentItem || t.element)))) continue; //No disabled and non-accepted + for (var j=0; j < list.length; j++) { if(list[j] == m[i].element[0]) { m[i].proportions.height = 0; continue droppablesLoop; } }; //Filter out elements in the current dragged item + m[i].visible = m[i].element.css("display") != "none"; if(!m[i].visible) continue; //If the element is not visible, continue + + m[i].offset = m[i].element.offset(); + m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight }; + + if(type == "mousedown") m[i]._activate.call(m[i], event); //Activate the droppable if used directly from draggables + + } + + }, + drop: function(draggable, event) { + + var dropped = false; + $.each($.ui.ddmanager.droppables[draggable.options.scope], function() { + + if(!this.options) return; + if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance)) + dropped = this._drop.call(this, event); + + if (!this.options.disabled && this.visible && this.options.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { + this.isout = 1; this.isover = 0; + this._deactivate.call(this, event); + } + + }); + return dropped; + + }, + drag: function(draggable, event) { + + //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse. + if(draggable.options.refreshPositions) $.ui.ddmanager.prepareOffsets(draggable, event); + + //Run through all droppables and check their positions based on specific tolerance options + + $.each($.ui.ddmanager.droppables[draggable.options.scope], function() { + + if(this.options.disabled || this.greedyChild || !this.visible) return; + var intersects = $.ui.intersect(draggable, this, this.options.tolerance); + + var c = !intersects && this.isover == 1 ? 'isout' : (intersects && this.isover == 0 ? 'isover' : null); + if(!c) return; + + var parentInstance; + if (this.options.greedy) { + var parent = this.element.parents(':data(droppable):eq(0)'); + if (parent.length) { + parentInstance = $.data(parent[0], 'droppable'); + parentInstance.greedyChild = (c == 'isover' ? 1 : 0); + } + } + + // we just moved into a greedy child + if (parentInstance && c == 'isover') { + parentInstance['isover'] = 0; + parentInstance['isout'] = 1; + parentInstance._out.call(parentInstance, event); + } + + this[c] = 1; this[c == 'isout' ? 'isover' : 'isout'] = 0; + this[c == "isover" ? "_over" : "_out"].call(this, event); + + // we just moved out of a greedy child + if (parentInstance && c == 'isout') { + parentInstance['isout'] = 0; + parentInstance['isover'] = 1; + parentInstance._over.call(parentInstance, event); + } + }); + + } +}; + +})(jQuery); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/ui.progressbar.js b/js2/mwEmbed/jquery/jquery.ui/ui/ui.progressbar.js new file mode 100644 index 0000000000..e69b2256e4 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/ui.progressbar.js @@ -0,0 +1,112 @@ +/* + * jQuery UI Progressbar 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Progressbar + * + * Depends: + * ui.core.js + */ +(function($) { + +$.widget("ui.progressbar", { + + _init: function() { + + this.element + .addClass("ui-progressbar" + + " ui-widget" + + " ui-widget-content" + + " ui-corner-all") + .attr({ + role: "progressbar", + "aria-valuemin": this._valueMin(), + "aria-valuemax": this._valueMax(), + "aria-valuenow": this._value() + }); + + this.valueDiv = $('
').appendTo(this.element); + + this._refreshValue(); + + }, + + destroy: function() { + + this.element + .removeClass("ui-progressbar" + + " ui-widget" + + " ui-widget-content" + + " ui-corner-all") + .removeAttr("role") + .removeAttr("aria-valuemin") + .removeAttr("aria-valuemax") + .removeAttr("aria-valuenow") + .removeData("progressbar") + .unbind(".progressbar"); + + this.valueDiv.remove(); + + $.widget.prototype.destroy.apply(this, arguments); + + }, + + value: function(newValue) { + arguments.length && this._setData("value", newValue); + return this._value(); + }, + + _setData: function(key, value) { + + switch (key) { + case 'value': + this.options.value = value; + this._refreshValue(); + this._trigger('change', null, {}); + break; + } + + $.widget.prototype._setData.apply(this, arguments); + + }, + + _value: function() { + + var val = this.options.value; + if (val < this._valueMin()) val = this._valueMin(); + if (val > this._valueMax()) val = this._valueMax(); + + return val; + + }, + + _valueMin: function() { + var valueMin = 0; + return valueMin; + }, + + _valueMax: function() { + var valueMax = 100; + return valueMax; + }, + + _refreshValue: function() { + var value = this.value(); + this.valueDiv[value == this._valueMax() ? 'addClass' : 'removeClass']("ui-corner-right"); + this.valueDiv.width(value + '%'); + this.element.attr("aria-valuenow", value); + } + +}); + +$.extend($.ui.progressbar, { + version: "1.7.1", + defaults: { + value: 0 + } +}); + +})(jQuery); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/ui.resizable.js b/js2/mwEmbed/jquery/jquery.ui/ui/ui.resizable.js new file mode 100644 index 0000000000..618102ffad --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/ui.resizable.js @@ -0,0 +1,800 @@ +/* + * jQuery UI Resizable 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Resizables + * + * Depends: + * ui.core.js + */ +(function($) { + +$.widget("ui.resizable", $.extend({}, $.ui.mouse, { + + _init: function() { + + var self = this, o = this.options; + this.element.addClass("ui-resizable"); + + $.extend(this, { + _aspectRatio: !!(o.aspectRatio), + aspectRatio: o.aspectRatio, + originalElement: this.element, + _proportionallyResizeElements: [], + _helper: o.helper || o.ghost || o.animate ? o.helper || 'ui-resizable-helper' : null + }); + + //Wrap the element if it cannot hold child nodes + if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) { + + //Opera fix for relative positioning + if (/relative/.test(this.element.css('position')) && $.browser.opera) + this.element.css({ position: 'relative', top: 'auto', left: 'auto' }); + + //Create a wrapper element and set the wrapper to the new current internal element + this.element.wrap( + $('
').css({ + position: this.element.css('position'), + width: this.element.outerWidth(), + height: this.element.outerHeight(), + top: this.element.css('top'), + left: this.element.css('left') + }) + ); + + //Overwrite the original this.element + this.element = this.element.parent().data( + "resizable", this.element.data('resizable') + ); + + this.elementIsWrapper = true; + + //Move margins to the wrapper + this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") }); + this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0}); + + //Prevent Safari textarea resize + this.originalResizeStyle = this.originalElement.css('resize'); + this.originalElement.css('resize', 'none'); + + //Push the actual element to our proportionallyResize internal array + this._proportionallyResizeElements.push(this.originalElement.css({ position: 'static', zoom: 1, display: 'block' })); + + // avoid IE jump (hard set the margin) + this.originalElement.css({ margin: this.originalElement.css('margin') }); + + // fix handlers offset + this._proportionallyResize(); + + } + + this.handles = o.handles || (!$('.ui-resizable-handle', this.element).length ? "e,s,se" : { n: '.ui-resizable-n', e: '.ui-resizable-e', s: '.ui-resizable-s', w: '.ui-resizable-w', se: '.ui-resizable-se', sw: '.ui-resizable-sw', ne: '.ui-resizable-ne', nw: '.ui-resizable-nw' }); + if(this.handles.constructor == String) { + + if(this.handles == 'all') this.handles = 'n,e,s,w,se,sw,ne,nw'; + var n = this.handles.split(","); this.handles = {}; + + for(var i = 0; i < n.length; i++) { + + var handle = $.trim(n[i]), hname = 'ui-resizable-'+handle; + var axis = $('
'); + + // increase zIndex of sw, se, ne, nw axis + //TODO : this modifies original option + if(/sw|se|ne|nw/.test(handle)) axis.css({ zIndex: ++o.zIndex }); + + //TODO : What's going on here? + if ('se' == handle) { + axis.addClass('ui-icon ui-icon-gripsmall-diagonal-se'); + }; + + //Insert into internal handles object and append to element + this.handles[handle] = '.ui-resizable-'+handle; + this.element.append(axis); + } + + } + + this._renderAxis = function(target) { + + target = target || this.element; + + for(var i in this.handles) { + + if(this.handles[i].constructor == String) + this.handles[i] = $(this.handles[i], this.element).show(); + + //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls) + if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) { + + var axis = $(this.handles[i], this.element), padWrapper = 0; + + //Checking the correct pad and border + padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth(); + + //The padding type i have to apply... + var padPos = [ 'padding', + /ne|nw|n/.test(i) ? 'Top' : + /se|sw|s/.test(i) ? 'Bottom' : + /^e$/.test(i) ? 'Right' : 'Left' ].join(""); + + target.css(padPos, padWrapper); + + this._proportionallyResize(); + + } + + //TODO: What's that good for? There's not anything to be executed left + if(!$(this.handles[i]).length) + continue; + + } + }; + + //TODO: make renderAxis a prototype function + this._renderAxis(this.element); + + this._handles = $('.ui-resizable-handle', this.element) + .disableSelection(); + + //Matching axis name + this._handles.mouseover(function() { + if (!self.resizing) { + if (this.className) + var axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i); + //Axis, default = se + self.axis = axis && axis[1] ? axis[1] : 'se'; + } + }); + + //If we want to auto hide the elements + if (o.autoHide) { + this._handles.hide(); + $(this.element) + .addClass("ui-resizable-autohide") + .hover(function() { + $(this).removeClass("ui-resizable-autohide"); + self._handles.show(); + }, + function(){ + if (!self.resizing) { + $(this).addClass("ui-resizable-autohide"); + self._handles.hide(); + } + }); + } + + //Initialize the mouse interaction + this._mouseInit(); + + }, + + destroy: function() { + + this._mouseDestroy(); + + var _destroy = function(exp) { + $(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing") + .removeData("resizable").unbind(".resizable").find('.ui-resizable-handle').remove(); + }; + + //TODO: Unwrap at same DOM position + if (this.elementIsWrapper) { + _destroy(this.element); + var wrapper = this.element; + wrapper.parent().append( + this.originalElement.css({ + position: wrapper.css('position'), + width: wrapper.outerWidth(), + height: wrapper.outerHeight(), + top: wrapper.css('top'), + left: wrapper.css('left') + }) + ).end().remove(); + } + + this.originalElement.css('resize', this.originalResizeStyle); + _destroy(this.originalElement); + + }, + + _mouseCapture: function(event) { + + var handle = false; + for(var i in this.handles) { + if($(this.handles[i])[0] == event.target) handle = true; + } + + return this.options.disabled || !!handle; + + }, + + _mouseStart: function(event) { + + var o = this.options, iniPos = this.element.position(), el = this.element; + + this.resizing = true; + this.documentScroll = { top: $(document).scrollTop(), left: $(document).scrollLeft() }; + + // bugfix for http://dev.jquery.com/ticket/1749 + if (el.is('.ui-draggable') || (/absolute/).test(el.css('position'))) { + el.css({ position: 'absolute', top: iniPos.top, left: iniPos.left }); + } + + //Opera fixing relative position + if ($.browser.opera && (/relative/).test(el.css('position'))) + el.css({ position: 'relative', top: 'auto', left: 'auto' }); + + this._renderProxy(); + + var curleft = num(this.helper.css('left')), curtop = num(this.helper.css('top')); + + if (o.containment) { + curleft += $(o.containment).scrollLeft() || 0; + curtop += $(o.containment).scrollTop() || 0; + } + + //Store needed variables + this.offset = this.helper.offset(); + this.position = { left: curleft, top: curtop }; + this.size = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; + this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; + this.originalPosition = { left: curleft, top: curtop }; + this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() }; + this.originalMousePosition = { left: event.pageX, top: event.pageY }; + + //Aspect Ratio + this.aspectRatio = (typeof o.aspectRatio == 'number') ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1); + + var cursor = $('.ui-resizable-' + this.axis).css('cursor'); + $('body').css('cursor', cursor == 'auto' ? this.axis + '-resize' : cursor); + + el.addClass("ui-resizable-resizing"); + this._propagate("start", event); + return true; + }, + + _mouseDrag: function(event) { + + //Increase performance, avoid regex + var el = this.helper, o = this.options, props = {}, + self = this, smp = this.originalMousePosition, a = this.axis; + + var dx = (event.pageX-smp.left)||0, dy = (event.pageY-smp.top)||0; + var trigger = this._change[a]; + if (!trigger) return false; + + // Calculate the attrs that will be change + var data = trigger.apply(this, [event, dx, dy]), ie6 = $.browser.msie && $.browser.version < 7, csdif = this.sizeDiff; + + if (this._aspectRatio || event.shiftKey) + data = this._updateRatio(data, event); + + data = this._respectSize(data, event); + + // plugins callbacks need to be called first + this._propagate("resize", event); + + el.css({ + top: this.position.top + "px", left: this.position.left + "px", + width: this.size.width + "px", height: this.size.height + "px" + }); + + if (!this._helper && this._proportionallyResizeElements.length) + this._proportionallyResize(); + + this._updateCache(data); + + // calling the user callback at the end + this._trigger('resize', event, this.ui()); + + return false; + }, + + _mouseStop: function(event) { + + this.resizing = false; + var o = this.options, self = this; + + if(this._helper) { + var pr = this._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName), + soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height, + soffsetw = ista ? 0 : self.sizeDiff.width; + + var s = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth) }, + left = (parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left)) || null, + top = (parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top)) || null; + + if (!o.animate) + this.element.css($.extend(s, { top: top, left: left })); + + self.helper.height(self.size.height); + self.helper.width(self.size.width); + + if (this._helper && !o.animate) this._proportionallyResize(); + } + + $('body').css('cursor', 'auto'); + + this.element.removeClass("ui-resizable-resizing"); + + this._propagate("stop", event); + + if (this._helper) this.helper.remove(); + return false; + + }, + + _updateCache: function(data) { + var o = this.options; + this.offset = this.helper.offset(); + if (isNumber(data.left)) this.position.left = data.left; + if (isNumber(data.top)) this.position.top = data.top; + if (isNumber(data.height)) this.size.height = data.height; + if (isNumber(data.width)) this.size.width = data.width; + }, + + _updateRatio: function(data, event) { + + var o = this.options, cpos = this.position, csize = this.size, a = this.axis; + + if (data.height) data.width = (csize.height * this.aspectRatio); + else if (data.width) data.height = (csize.width / this.aspectRatio); + + if (a == 'sw') { + data.left = cpos.left + (csize.width - data.width); + data.top = null; + } + if (a == 'nw') { + data.top = cpos.top + (csize.height - data.height); + data.left = cpos.left + (csize.width - data.width); + } + + return data; + }, + + _respectSize: function(data, event) { + + var el = this.helper, o = this.options, pRatio = this._aspectRatio || event.shiftKey, a = this.axis, + ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height), + isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height); + + if (isminw) data.width = o.minWidth; + if (isminh) data.height = o.minHeight; + if (ismaxw) data.width = o.maxWidth; + if (ismaxh) data.height = o.maxHeight; + + var dw = this.originalPosition.left + this.originalSize.width, dh = this.position.top + this.size.height; + var cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a); + + if (isminw && cw) data.left = dw - o.minWidth; + if (ismaxw && cw) data.left = dw - o.maxWidth; + if (isminh && ch) data.top = dh - o.minHeight; + if (ismaxh && ch) data.top = dh - o.maxHeight; + + // fixing jump error on top/left - bug #2330 + var isNotwh = !data.width && !data.height; + if (isNotwh && !data.left && data.top) data.top = null; + else if (isNotwh && !data.top && data.left) data.left = null; + + return data; + }, + + _proportionallyResize: function() { + + var o = this.options; + if (!this._proportionallyResizeElements.length) return; + var element = this.helper || this.element; + + for (var i=0; i < this._proportionallyResizeElements.length; i++) { + + var prel = this._proportionallyResizeElements[i]; + + if (!this.borderDif) { + var b = [prel.css('borderTopWidth'), prel.css('borderRightWidth'), prel.css('borderBottomWidth'), prel.css('borderLeftWidth')], + p = [prel.css('paddingTop'), prel.css('paddingRight'), prel.css('paddingBottom'), prel.css('paddingLeft')]; + + this.borderDif = $.map(b, function(v, i) { + var border = parseInt(v,10)||0, padding = parseInt(p[i],10)||0; + return border + padding; + }); + } + + if ($.browser.msie && !(!($(element).is(':hidden') || $(element).parents(':hidden').length))) + continue; + + prel.css({ + height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0, + width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0 + }); + + }; + + }, + + _renderProxy: function() { + + var el = this.element, o = this.options; + this.elementOffset = el.offset(); + + if(this._helper) { + + this.helper = this.helper || $('
'); + + // fix ie6 offset TODO: This seems broken + var ie6 = $.browser.msie && $.browser.version < 7, ie6offset = (ie6 ? 1 : 0), + pxyoffset = ( ie6 ? 2 : -1 ); + + this.helper.addClass(this._helper).css({ + width: this.element.outerWidth() + pxyoffset, + height: this.element.outerHeight() + pxyoffset, + position: 'absolute', + left: this.elementOffset.left - ie6offset +'px', + top: this.elementOffset.top - ie6offset +'px', + zIndex: ++o.zIndex //TODO: Don't modify option + }); + + this.helper + .appendTo("body") + .disableSelection(); + + } else { + this.helper = this.element; + } + + }, + + _change: { + e: function(event, dx, dy) { + return { width: this.originalSize.width + dx }; + }, + w: function(event, dx, dy) { + var o = this.options, cs = this.originalSize, sp = this.originalPosition; + return { left: sp.left + dx, width: cs.width - dx }; + }, + n: function(event, dx, dy) { + var o = this.options, cs = this.originalSize, sp = this.originalPosition; + return { top: sp.top + dy, height: cs.height - dy }; + }, + s: function(event, dx, dy) { + return { height: this.originalSize.height + dy }; + }, + se: function(event, dx, dy) { + return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy])); + }, + sw: function(event, dx, dy) { + return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy])); + }, + ne: function(event, dx, dy) { + return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy])); + }, + nw: function(event, dx, dy) { + return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy])); + } + }, + + _propagate: function(n, event) { + $.ui.plugin.call(this, n, [event, this.ui()]); + (n != "resize" && this._trigger(n, event, this.ui())); + }, + + plugins: {}, + + ui: function() { + return { + originalElement: this.originalElement, + element: this.element, + helper: this.helper, + position: this.position, + size: this.size, + originalSize: this.originalSize, + originalPosition: this.originalPosition + }; + } + +})); + +$.extend($.ui.resizable, { + version: "1.7.1", + eventPrefix: "resize", + defaults: { + alsoResize: false, + animate: false, + animateDuration: "slow", + animateEasing: "swing", + aspectRatio: false, + autoHide: false, + cancel: ":input,option", + containment: false, + delay: 0, + distance: 1, + ghost: false, + grid: false, + handles: "e,s,se", + helper: false, + maxHeight: null, + maxWidth: null, + minHeight: 10, + minWidth: 10, + zIndex: 1000 + } +}); + +/* + * Resizable Extensions + */ + +$.ui.plugin.add("resizable", "alsoResize", { + + start: function(event, ui) { + + var self = $(this).data("resizable"), o = self.options; + + _store = function(exp) { + $(exp).each(function() { + $(this).data("resizable-alsoresize", { + width: parseInt($(this).width(), 10), height: parseInt($(this).height(), 10), + left: parseInt($(this).css('left'), 10), top: parseInt($(this).css('top'), 10) + }); + }); + }; + + if (typeof(o.alsoResize) == 'object' && !o.alsoResize.parentNode) { + if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); } + else { $.each(o.alsoResize, function(exp, c) { _store(exp); }); } + }else{ + _store(o.alsoResize); + } + }, + + resize: function(event, ui){ + var self = $(this).data("resizable"), o = self.options, os = self.originalSize, op = self.originalPosition; + + var delta = { + height: (self.size.height - os.height) || 0, width: (self.size.width - os.width) || 0, + top: (self.position.top - op.top) || 0, left: (self.position.left - op.left) || 0 + }, + + _alsoResize = function(exp, c) { + $(exp).each(function() { + var el = $(this), start = $(this).data("resizable-alsoresize"), style = {}, css = c && c.length ? c : ['width', 'height', 'top', 'left']; + + $.each(css || ['width', 'height', 'top', 'left'], function(i, prop) { + var sum = (start[prop]||0) + (delta[prop]||0); + if (sum && sum >= 0) + style[prop] = sum || null; + }); + + //Opera fixing relative position + if (/relative/.test(el.css('position')) && $.browser.opera) { + self._revertToRelativePosition = true; + el.css({ position: 'absolute', top: 'auto', left: 'auto' }); + } + + el.css(style); + }); + }; + + if (typeof(o.alsoResize) == 'object' && !o.alsoResize.nodeType) { + $.each(o.alsoResize, function(exp, c) { _alsoResize(exp, c); }); + }else{ + _alsoResize(o.alsoResize); + } + }, + + stop: function(event, ui){ + var self = $(this).data("resizable"); + + //Opera fixing relative position + if (self._revertToRelativePosition && $.browser.opera) { + self._revertToRelativePosition = false; + el.css({ position: 'relative' }); + } + + $(this).removeData("resizable-alsoresize-start"); + } +}); + +$.ui.plugin.add("resizable", "animate", { + + stop: function(event, ui) { + var self = $(this).data("resizable"), o = self.options; + + var pr = self._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName), + soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height, + soffsetw = ista ? 0 : self.sizeDiff.width; + + var style = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth) }, + left = (parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left)) || null, + top = (parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top)) || null; + + self.element.animate( + $.extend(style, top && left ? { top: top, left: left } : {}), { + duration: o.animateDuration, + easing: o.animateEasing, + step: function() { + + var data = { + width: parseInt(self.element.css('width'), 10), + height: parseInt(self.element.css('height'), 10), + top: parseInt(self.element.css('top'), 10), + left: parseInt(self.element.css('left'), 10) + }; + + if (pr && pr.length) $(pr[0]).css({ width: data.width, height: data.height }); + + // propagating resize, and updating values for each animation step + self._updateCache(data); + self._propagate("resize", event); + + } + } + ); + } + +}); + +$.ui.plugin.add("resizable", "containment", { + + start: function(event, ui) { + var self = $(this).data("resizable"), o = self.options, el = self.element; + var oc = o.containment, ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc; + if (!ce) return; + + self.containerElement = $(ce); + + if (/document/.test(oc) || oc == document) { + self.containerOffset = { left: 0, top: 0 }; + self.containerPosition = { left: 0, top: 0 }; + + self.parentData = { + element: $(document), left: 0, top: 0, + width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight + }; + } + + // i'm a node, so compute top, left, right, bottom + else { + var element = $(ce), p = []; + $([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); }); + + self.containerOffset = element.offset(); + self.containerPosition = element.position(); + self.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) }; + + var co = self.containerOffset, ch = self.containerSize.height, cw = self.containerSize.width, + width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw ), height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch); + + self.parentData = { + element: ce, left: co.left, top: co.top, width: width, height: height + }; + } + }, + + resize: function(event, ui) { + var self = $(this).data("resizable"), o = self.options, + ps = self.containerSize, co = self.containerOffset, cs = self.size, cp = self.position, + pRatio = self._aspectRatio || event.shiftKey, cop = { top:0, left:0 }, ce = self.containerElement; + + if (ce[0] != document && (/static/).test(ce.css('position'))) cop = co; + + if (cp.left < (self._helper ? co.left : 0)) { + self.size.width = self.size.width + (self._helper ? (self.position.left - co.left) : (self.position.left - cop.left)); + if (pRatio) self.size.height = self.size.width / o.aspectRatio; + self.position.left = o.helper ? co.left : 0; + } + + if (cp.top < (self._helper ? co.top : 0)) { + self.size.height = self.size.height + (self._helper ? (self.position.top - co.top) : self.position.top); + if (pRatio) self.size.width = self.size.height * o.aspectRatio; + self.position.top = self._helper ? co.top : 0; + } + + self.offset.left = self.parentData.left+self.position.left; + self.offset.top = self.parentData.top+self.position.top; + + var woset = Math.abs( (self._helper ? self.offset.left - cop.left : (self.offset.left - cop.left)) + self.sizeDiff.width ), + hoset = Math.abs( (self._helper ? self.offset.top - cop.top : (self.offset.top - co.top)) + self.sizeDiff.height ); + + var isParent = self.containerElement.get(0) == self.element.parent().get(0), + isOffsetRelative = /relative|absolute/.test(self.containerElement.css('position')); + + if(isParent && isOffsetRelative) woset -= self.parentData.left; + + if (woset + self.size.width >= self.parentData.width) { + self.size.width = self.parentData.width - woset; + if (pRatio) self.size.height = self.size.width / self.aspectRatio; + } + + if (hoset + self.size.height >= self.parentData.height) { + self.size.height = self.parentData.height - hoset; + if (pRatio) self.size.width = self.size.height * self.aspectRatio; + } + }, + + stop: function(event, ui){ + var self = $(this).data("resizable"), o = self.options, cp = self.position, + co = self.containerOffset, cop = self.containerPosition, ce = self.containerElement; + + var helper = $(self.helper), ho = helper.offset(), w = helper.outerWidth() - self.sizeDiff.width, h = helper.outerHeight() - self.sizeDiff.height; + + if (self._helper && !o.animate && (/relative/).test(ce.css('position'))) + $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); + + if (self._helper && !o.animate && (/static/).test(ce.css('position'))) + $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); + + } +}); + +$.ui.plugin.add("resizable", "ghost", { + + start: function(event, ui) { + + var self = $(this).data("resizable"), o = self.options, cs = self.size; + + self.ghost = self.originalElement.clone(); + self.ghost + .css({ opacity: .25, display: 'block', position: 'relative', height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 }) + .addClass('ui-resizable-ghost') + .addClass(typeof o.ghost == 'string' ? o.ghost : ''); + + self.ghost.appendTo(self.helper); + + }, + + resize: function(event, ui){ + var self = $(this).data("resizable"), o = self.options; + if (self.ghost) self.ghost.css({ position: 'relative', height: self.size.height, width: self.size.width }); + }, + + stop: function(event, ui){ + var self = $(this).data("resizable"), o = self.options; + if (self.ghost && self.helper) self.helper.get(0).removeChild(self.ghost.get(0)); + } + +}); + +$.ui.plugin.add("resizable", "grid", { + + resize: function(event, ui) { + var self = $(this).data("resizable"), o = self.options, cs = self.size, os = self.originalSize, op = self.originalPosition, a = self.axis, ratio = o._aspectRatio || event.shiftKey; + o.grid = typeof o.grid == "number" ? [o.grid, o.grid] : o.grid; + var ox = Math.round((cs.width - os.width) / (o.grid[0]||1)) * (o.grid[0]||1), oy = Math.round((cs.height - os.height) / (o.grid[1]||1)) * (o.grid[1]||1); + + if (/^(se|s|e)$/.test(a)) { + self.size.width = os.width + ox; + self.size.height = os.height + oy; + } + else if (/^(ne)$/.test(a)) { + self.size.width = os.width + ox; + self.size.height = os.height + oy; + self.position.top = op.top - oy; + } + else if (/^(sw)$/.test(a)) { + self.size.width = os.width + ox; + self.size.height = os.height + oy; + self.position.left = op.left - ox; + } + else { + self.size.width = os.width + ox; + self.size.height = os.height + oy; + self.position.top = op.top - oy; + self.position.left = op.left - ox; + } + } + +}); + +var num = function(v) { + return parseInt(v, 10) || 0; +}; + +var isNumber = function(value) { + return !isNaN(parseInt(value, 10)); +}; + +})(jQuery); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/ui.selectable.js b/js2/mwEmbed/jquery/jquery.ui/ui/ui.selectable.js new file mode 100644 index 0000000000..32bc3d3a8a --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/ui.selectable.js @@ -0,0 +1,257 @@ +/* + * jQuery UI Selectable 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Selectables + * + * Depends: + * ui.core.js + */ +(function($) { + +$.widget("ui.selectable", $.extend({}, $.ui.mouse, { + + _init: function() { + var self = this; + + this.element.addClass("ui-selectable"); + + this.dragged = false; + + // cache selectee children based on filter + var selectees; + this.refresh = function() { + selectees = $(self.options.filter, self.element[0]); + selectees.each(function() { + var $this = $(this); + var pos = $this.offset(); + $.data(this, "selectable-item", { + element: this, + $element: $this, + left: pos.left, + top: pos.top, + right: pos.left + $this.outerWidth(), + bottom: pos.top + $this.outerHeight(), + startselected: false, + selected: $this.hasClass('ui-selected'), + selecting: $this.hasClass('ui-selecting'), + unselecting: $this.hasClass('ui-unselecting') + }); + }); + }; + this.refresh(); + + this.selectees = selectees.addClass("ui-selectee"); + + this._mouseInit(); + + this.helper = $(document.createElement('div')) + .css({border:'1px dotted black'}) + .addClass("ui-selectable-helper"); + }, + + destroy: function() { + this.element + .removeClass("ui-selectable ui-selectable-disabled") + .removeData("selectable") + .unbind(".selectable"); + this._mouseDestroy(); + }, + + _mouseStart: function(event) { + var self = this; + + this.opos = [event.pageX, event.pageY]; + + if (this.options.disabled) + return; + + var options = this.options; + + this.selectees = $(options.filter, this.element[0]); + + this._trigger("start", event); + + $(options.appendTo).append(this.helper); + // position helper (lasso) + this.helper.css({ + "z-index": 100, + "position": "absolute", + "left": event.clientX, + "top": event.clientY, + "width": 0, + "height": 0 + }); + + if (options.autoRefresh) { + this.refresh(); + } + + this.selectees.filter('.ui-selected').each(function() { + var selectee = $.data(this, "selectable-item"); + selectee.startselected = true; + if (!event.metaKey) { + selectee.$element.removeClass('ui-selected'); + selectee.selected = false; + selectee.$element.addClass('ui-unselecting'); + selectee.unselecting = true; + // selectable UNSELECTING callback + self._trigger("unselecting", event, { + unselecting: selectee.element + }); + } + }); + + $(event.target).parents().andSelf().each(function() { + var selectee = $.data(this, "selectable-item"); + if (selectee) { + selectee.$element.removeClass("ui-unselecting").addClass('ui-selecting'); + selectee.unselecting = false; + selectee.selecting = true; + selectee.selected = true; + // selectable SELECTING callback + self._trigger("selecting", event, { + selecting: selectee.element + }); + return false; + } + }); + + }, + + _mouseDrag: function(event) { + var self = this; + this.dragged = true; + + if (this.options.disabled) + return; + + var options = this.options; + + var x1 = this.opos[0], y1 = this.opos[1], x2 = event.pageX, y2 = event.pageY; + if (x1 > x2) { var tmp = x2; x2 = x1; x1 = tmp; } + if (y1 > y2) { var tmp = y2; y2 = y1; y1 = tmp; } + this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1}); + + this.selectees.each(function() { + var selectee = $.data(this, "selectable-item"); + //prevent helper from being selected if appendTo: selectable + if (!selectee || selectee.element == self.element[0]) + return; + var hit = false; + if (options.tolerance == 'touch') { + hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) ); + } else if (options.tolerance == 'fit') { + hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2); + } + + if (hit) { + // SELECT + if (selectee.selected) { + selectee.$element.removeClass('ui-selected'); + selectee.selected = false; + } + if (selectee.unselecting) { + selectee.$element.removeClass('ui-unselecting'); + selectee.unselecting = false; + } + if (!selectee.selecting) { + selectee.$element.addClass('ui-selecting'); + selectee.selecting = true; + // selectable SELECTING callback + self._trigger("selecting", event, { + selecting: selectee.element + }); + } + } else { + // UNSELECT + if (selectee.selecting) { + if (event.metaKey && selectee.startselected) { + selectee.$element.removeClass('ui-selecting'); + selectee.selecting = false; + selectee.$element.addClass('ui-selected'); + selectee.selected = true; + } else { + selectee.$element.removeClass('ui-selecting'); + selectee.selecting = false; + if (selectee.startselected) { + selectee.$element.addClass('ui-unselecting'); + selectee.unselecting = true; + } + // selectable UNSELECTING callback + self._trigger("unselecting", event, { + unselecting: selectee.element + }); + } + } + if (selectee.selected) { + if (!event.metaKey && !selectee.startselected) { + selectee.$element.removeClass('ui-selected'); + selectee.selected = false; + + selectee.$element.addClass('ui-unselecting'); + selectee.unselecting = true; + // selectable UNSELECTING callback + self._trigger("unselecting", event, { + unselecting: selectee.element + }); + } + } + } + }); + + return false; + }, + + _mouseStop: function(event) { + var self = this; + + this.dragged = false; + + var options = this.options; + + $('.ui-unselecting', this.element[0]).each(function() { + var selectee = $.data(this, "selectable-item"); + selectee.$element.removeClass('ui-unselecting'); + selectee.unselecting = false; + selectee.startselected = false; + self._trigger("unselected", event, { + unselected: selectee.element + }); + }); + $('.ui-selecting', this.element[0]).each(function() { + var selectee = $.data(this, "selectable-item"); + selectee.$element.removeClass('ui-selecting').addClass('ui-selected'); + selectee.selecting = false; + selectee.selected = true; + selectee.startselected = true; + self._trigger("selected", event, { + selected: selectee.element + }); + }); + this._trigger("stop", event); + + this.helper.remove(); + + return false; + } + +})); + +$.extend($.ui.selectable, { + version: "1.7.1", + defaults: { + appendTo: 'body', + autoRefresh: true, + cancel: ":input,option", + delay: 0, + distance: 0, + filter: '*', + tolerance: 'touch' + } +}); + +})(jQuery); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/ui.slider.js b/js2/mwEmbed/jquery/jquery.ui/ui/ui.slider.js new file mode 100644 index 0000000000..b1c1da666f --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/ui.slider.js @@ -0,0 +1,533 @@ +/* + * jQuery UI Slider 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Slider + * + * Depends: + * ui.core.js + */ + +(function($) { + +$.widget("ui.slider", $.extend({}, $.ui.mouse, { + + _init: function() { + + var self = this, o = this.options; + this._keySliding = false; + this._handleIndex = null; + this._detectOrientation(); + this._mouseInit(); + + this.element + .addClass("ui-slider" + + " ui-slider-" + this.orientation + + " ui-widget" + + " ui-widget-content" + + " ui-corner-all"); + + this.range = $([]); + + if (o.range) { + + if (o.range === true) { + this.range = $('
'); + if (!o.values) o.values = [this._valueMin(), this._valueMin()]; + if (o.values.length && o.values.length != 2) { + o.values = [o.values[0], o.values[0]]; + } + } else { + this.range = $('
'); + } + + this.range + .appendTo(this.element) + .addClass("ui-slider-range"); + + if (o.range == "min" || o.range == "max") { + this.range.addClass("ui-slider-range-" + o.range); + } + + // note: this isn't the most fittingly semantic framework class for this element, + // but worked best visually with a variety of themes + this.range.addClass("ui-widget-header"); + + } + + if ($(".ui-slider-handle", this.element).length == 0) + $('
') + .appendTo(this.element) + .addClass("ui-slider-handle"); + + if (o.values && o.values.length) { + while ($(".ui-slider-handle", this.element).length < o.values.length) + $('') + .appendTo(this.element) + .addClass("ui-slider-handle"); + } + + this.handles = $(".ui-slider-handle", this.element) + .addClass("ui-state-default" + + " ui-corner-all"); + + this.handle = this.handles.eq(0); + + this.handles.add(this.range).filter("a") + .click(function(event) { event.preventDefault(); }) + .hover(function() { $(this).addClass('ui-state-hover'); }, function() { $(this).removeClass('ui-state-hover'); }) + .focus(function() { $(".ui-slider .ui-state-focus").removeClass('ui-state-focus'); $(this).addClass('ui-state-focus'); }) + .blur(function() { $(this).removeClass('ui-state-focus'); }); + + this.handles.each(function(i) { + $(this).data("index.ui-slider-handle", i); + }); + + this.handles.keydown(function(event) { + + var ret = true; + + var index = $(this).data("index.ui-slider-handle"); + + if (self.options.disabled) + return; + + switch (event.keyCode) { + case $.ui.keyCode.HOME: + case $.ui.keyCode.END: + case $.ui.keyCode.UP: + case $.ui.keyCode.RIGHT: + case $.ui.keyCode.DOWN: + case $.ui.keyCode.LEFT: + ret = false; + if (!self._keySliding) { + self._keySliding = true; + $(this).addClass("ui-state-active"); + self._start(event, index); + } + break; + } + + var curVal, newVal, step = self._step(); + if (self.options.values && self.options.values.length) { + curVal = newVal = self.values(index); + } else { + curVal = newVal = self.value(); + } + + switch (event.keyCode) { + case $.ui.keyCode.HOME: + newVal = self._valueMin(); + break; + case $.ui.keyCode.END: + newVal = self._valueMax(); + break; + case $.ui.keyCode.UP: + case $.ui.keyCode.RIGHT: + if(curVal == self._valueMax()) return; + newVal = curVal + step; + break; + case $.ui.keyCode.DOWN: + case $.ui.keyCode.LEFT: + if(curVal == self._valueMin()) return; + newVal = curVal - step; + break; + } + + self._slide(event, index, newVal); + + return ret; + + }).keyup(function(event) { + + var index = $(this).data("index.ui-slider-handle"); + + if (self._keySliding) { + self._stop(event, index); + self._change(event, index); + self._keySliding = false; + $(this).removeClass("ui-state-active"); + } + + }); + + this._refreshValue(); + + }, + + destroy: function() { + + this.handles.remove(); + this.range.remove(); + + this.element + .removeClass("ui-slider" + + " ui-slider-horizontal" + + " ui-slider-vertical" + + " ui-slider-disabled" + + " ui-widget" + + " ui-widget-content" + + " ui-corner-all") + .removeData("slider") + .unbind(".slider"); + + this._mouseDestroy(); + + }, + + _mouseCapture: function(event) { + + var o = this.options; + + if (o.disabled) + return false; + + this.elementSize = { + width: this.element.outerWidth(), + height: this.element.outerHeight() + }; + this.elementOffset = this.element.offset(); + + var position = { x: event.pageX, y: event.pageY }; + var normValue = this._normValueFromMouse(position); + + var distance = this._valueMax() - this._valueMin() + 1, closestHandle; + var self = this, index; + this.handles.each(function(i) { + var thisDistance = Math.abs(normValue - self.values(i)); + if (distance > thisDistance) { + distance = thisDistance; + closestHandle = $(this); + index = i; + } + }); + + // workaround for bug #3736 (if both handles of a range are at 0, + // the first is always used as the one with least distance, + // and moving it is obviously prevented by preventing negative ranges) + if(o.range == true && this.values(1) == o.min) { + closestHandle = $(this.handles[++index]); + } + + this._start(event, index); + + self._handleIndex = index; + + closestHandle + .addClass("ui-state-active") + .focus(); + + var offset = closestHandle.offset(); + var mouseOverHandle = !$(event.target).parents().andSelf().is('.ui-slider-handle'); + this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : { + left: event.pageX - offset.left - (closestHandle.width() / 2), + top: event.pageY - offset.top + - (closestHandle.height() / 2) + - (parseInt(closestHandle.css('borderTopWidth'),10) || 0) + - (parseInt(closestHandle.css('borderBottomWidth'),10) || 0) + + (parseInt(closestHandle.css('marginTop'),10) || 0) + }; + + normValue = this._normValueFromMouse(position); + this._slide(event, index, normValue); + return true; + + }, + + _mouseStart: function(event) { + return true; + }, + + _mouseDrag: function(event) { + + var position = { x: event.pageX, y: event.pageY }; + var normValue = this._normValueFromMouse(position); + + this._slide(event, this._handleIndex, normValue); + + return false; + + }, + + _mouseStop: function(event) { + + this.handles.removeClass("ui-state-active"); + this._stop(event, this._handleIndex); + this._change(event, this._handleIndex); + this._handleIndex = null; + this._clickOffset = null; + + return false; + + }, + + _detectOrientation: function() { + this.orientation = this.options.orientation == 'vertical' ? 'vertical' : 'horizontal'; + }, + + _normValueFromMouse: function(position) { + + var pixelTotal, pixelMouse; + if ('horizontal' == this.orientation) { + pixelTotal = this.elementSize.width; + pixelMouse = position.x - this.elementOffset.left - (this._clickOffset ? this._clickOffset.left : 0); + } else { + pixelTotal = this.elementSize.height; + pixelMouse = position.y - this.elementOffset.top - (this._clickOffset ? this._clickOffset.top : 0); + } + + var percentMouse = (pixelMouse / pixelTotal); + if (percentMouse > 1) percentMouse = 1; + if (percentMouse < 0) percentMouse = 0; + if ('vertical' == this.orientation) + percentMouse = 1 - percentMouse; + + var valueTotal = this._valueMax() - this._valueMin(), + valueMouse = percentMouse * valueTotal, + valueMouseModStep = valueMouse % this.options.step, + normValue = this._valueMin() + valueMouse - valueMouseModStep; + + if (valueMouseModStep > (this.options.step / 2)) + normValue += this.options.step; + + // Since JavaScript has problems with large floats, round + // the final value to 5 digits after the decimal point (see #4124) + return parseFloat(normValue.toFixed(5)); + + }, + + _start: function(event, index) { + var uiHash = { + handle: this.handles[index], + value: this.value() + }; + if (this.options.values && this.options.values.length) { + uiHash.value = this.values(index) + uiHash.values = this.values() + } + this._trigger("start", event, uiHash); + }, + + _slide: function(event, index, newVal) { + + var handle = this.handles[index]; + + if (this.options.values && this.options.values.length) { + + var otherVal = this.values(index ? 0 : 1); + + if ((index == 0 && newVal >= otherVal) || (index == 1 && newVal <= otherVal)) + newVal = otherVal; + + if (newVal != this.values(index)) { + var newValues = this.values(); + newValues[index] = newVal; + // A slide can be canceled by returning false from the slide callback + var allowed = this._trigger("slide", event, { + handle: this.handles[index], + value: newVal, + values: newValues + }); + var otherVal = this.values(index ? 0 : 1); + if (allowed !== false) { + this.values(index, newVal, ( event.type == 'mousedown' && this.options.animate ), true); + } + } + + } else { + + if (newVal != this.value()) { + // A slide can be canceled by returning false from the slide callback + var allowed = this._trigger("slide", event, { + handle: this.handles[index], + value: newVal + }); + if (allowed !== false) { + this._setData('value', newVal, ( event.type == 'mousedown' && this.options.animate )); + } + + } + + } + + }, + + _stop: function(event, index) { + var uiHash = { + handle: this.handles[index], + value: this.value() + }; + if (this.options.values && this.options.values.length) { + uiHash.value = this.values(index) + uiHash.values = this.values() + } + this._trigger("stop", event, uiHash); + }, + + _change: function(event, index) { + var uiHash = { + handle: this.handles[index], + value: this.value() + }; + if (this.options.values && this.options.values.length) { + uiHash.value = this.values(index) + uiHash.values = this.values() + } + this._trigger("change", event, uiHash); + }, + + value: function(newValue) { + + if (arguments.length) { + this._setData("value", newValue); + this._change(null, 0); + } + + return this._value(); + + }, + + values: function(index, newValue, animated, noPropagation) { + + if (arguments.length > 1) { + this.options.values[index] = newValue; + this._refreshValue(animated); + if(!noPropagation) this._change(null, index); + } + + if (arguments.length) { + if (this.options.values && this.options.values.length) { + return this._values(index); + } else { + return this.value(); + } + } else { + return this._values(); + } + + }, + + _setData: function(key, value, animated) { + + $.widget.prototype._setData.apply(this, arguments); + + switch (key) { + case 'orientation': + + this._detectOrientation(); + + this.element + .removeClass("ui-slider-horizontal ui-slider-vertical") + .addClass("ui-slider-" + this.orientation); + this._refreshValue(animated); + break; + case 'value': + this._refreshValue(animated); + break; + } + + }, + + _step: function() { + var step = this.options.step; + return step; + }, + + _value: function() { + + var val = this.options.value; + if (val < this._valueMin()) val = this._valueMin(); + if (val > this._valueMax()) val = this._valueMax(); + + return val; + + }, + + _values: function(index) { + + if (arguments.length) { + var val = this.options.values[index]; + if (val < this._valueMin()) val = this._valueMin(); + if (val > this._valueMax()) val = this._valueMax(); + + return val; + } else { + return this.options.values; + } + + }, + + _valueMin: function() { + var valueMin = this.options.min; + return valueMin; + }, + + _valueMax: function() { + var valueMax = this.options.max; + return valueMax; + }, + + _refreshValue: function(animate) { + + var oRange = this.options.range, o = this.options, self = this; + + if (this.options.values && this.options.values.length) { + var vp0, vp1; + this.handles.each(function(i, j) { + var valPercent = (self.values(i) - self._valueMin()) / (self._valueMax() - self._valueMin()) * 100; + var _set = {}; _set[self.orientation == 'horizontal' ? 'left' : 'bottom'] = valPercent + '%'; + $(this).stop(1,1)[animate ? 'animate' : 'css'](_set, o.animate); + if (self.options.range === true) { + if (self.orientation == 'horizontal') { + (i == 0) && self.range.stop(1,1)[animate ? 'animate' : 'css']({ left: valPercent + '%' }, o.animate); + (i == 1) && self.range[animate ? 'animate' : 'css']({ width: (valPercent - lastValPercent) + '%' }, { queue: false, duration: o.animate }); + } else { + (i == 0) && self.range.stop(1,1)[animate ? 'animate' : 'css']({ bottom: (valPercent) + '%' }, o.animate); + (i == 1) && self.range[animate ? 'animate' : 'css']({ height: (valPercent - lastValPercent) + '%' }, { queue: false, duration: o.animate }); + } + } + lastValPercent = valPercent; + }); + } else { + var value = this.value(), + valueMin = this._valueMin(), + valueMax = this._valueMax(), + valPercent = valueMax != valueMin + ? (value - valueMin) / (valueMax - valueMin) * 100 + : 0; + var _set = {}; _set[self.orientation == 'horizontal' ? 'left' : 'bottom'] = valPercent + '%'; + this.handle.stop(1,1)[animate ? 'animate' : 'css'](_set, o.animate); + + (oRange == "min") && (this.orientation == "horizontal") && this.range.stop(1,1)[animate ? 'animate' : 'css']({ width: valPercent + '%' }, o.animate); + (oRange == "max") && (this.orientation == "horizontal") && this.range[animate ? 'animate' : 'css']({ width: (100 - valPercent) + '%' }, { queue: false, duration: o.animate }); + (oRange == "min") && (this.orientation == "vertical") && this.range.stop(1,1)[animate ? 'animate' : 'css']({ height: valPercent + '%' }, o.animate); + (oRange == "max") && (this.orientation == "vertical") && this.range[animate ? 'animate' : 'css']({ height: (100 - valPercent) + '%' }, { queue: false, duration: o.animate }); + } + + } + +})); + +$.extend($.ui.slider, { + getter: "value values", + version: "1.7.1", + eventPrefix: "slide", + defaults: { + animate: false, + delay: 0, + distance: 0, + max: 100, + min: 0, + orientation: 'horizontal', + range: false, + step: 1, + value: 0, + values: null + } +}); + +})(jQuery); + diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/ui.sortable.js b/js2/mwEmbed/jquery/jquery.ui/ui/ui.sortable.js new file mode 100644 index 0000000000..a119a6e9a9 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/ui.sortable.js @@ -0,0 +1,1019 @@ +/* + * jQuery UI Sortable 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Sortables + * + * Depends: + * ui.core.js + */ +(function($) { + +$.widget("ui.sortable", $.extend({}, $.ui.mouse, { + _init: function() { + + var o = this.options; + this.containerCache = {}; + this.element.addClass("ui-sortable"); + + //Get the items + this.refresh(); + + //Let's determine if the items are floating + this.floating = this.items.length ? (/left|right/).test(this.items[0].item.css('float')) : false; + + //Let's determine the parent's offset + this.offset = this.element.offset(); + + //Initialize mouse events for interaction + this._mouseInit(); + + }, + + destroy: function() { + this.element + .removeClass("ui-sortable ui-sortable-disabled") + .removeData("sortable") + .unbind(".sortable"); + this._mouseDestroy(); + + for ( var i = this.items.length - 1; i >= 0; i-- ) + this.items[i].item.removeData("sortable-item"); + }, + + _mouseCapture: function(event, overrideHandle) { + + if (this.reverting) { + return false; + } + + if(this.options.disabled || this.options.type == 'static') return false; + + //We have to refresh the items data once first + this._refreshItems(event); + + //Find out if the clicked node (or one of its parents) is a actual item in this.items + var currentItem = null, self = this, nodes = $(event.target).parents().each(function() { + if($.data(this, 'sortable-item') == self) { + currentItem = $(this); + return false; + } + }); + if($.data(event.target, 'sortable-item') == self) currentItem = $(event.target); + + if(!currentItem) return false; + if(this.options.handle && !overrideHandle) { + var validHandle = false; + + $(this.options.handle, currentItem).find("*").andSelf().each(function() { if(this == event.target) validHandle = true; }); + if(!validHandle) return false; + } + + this.currentItem = currentItem; + this._removeCurrentsFromItems(); + return true; + + }, + + _mouseStart: function(event, overrideHandle, noActivation) { + + var o = this.options, self = this; + this.currentContainer = this; + + //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture + this.refreshPositions(); + + //Create and append the visible helper + this.helper = this._createHelper(event); + + //Cache the helper size + this._cacheHelperProportions(); + + /* + * - Position generation - + * This block generates everything position related - it's the core of draggables. + */ + + //Cache the margins of the original element + this._cacheMargins(); + + //Get the next scrolling parent + this.scrollParent = this.helper.scrollParent(); + + //The element's absolute position on the page minus margins + this.offset = this.currentItem.offset(); + this.offset = { + top: this.offset.top - this.margins.top, + left: this.offset.left - this.margins.left + }; + + // Only after we got the offset, we can change the helper's position to absolute + // TODO: Still need to figure out a way to make relative sorting possible + this.helper.css("position", "absolute"); + this.cssPosition = this.helper.css("position"); + + $.extend(this.offset, { + click: { //Where the click happened, relative to the element + left: event.pageX - this.offset.left, + top: event.pageY - this.offset.top + }, + parent: this._getParentOffset(), + relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper + }); + + //Generate the original position + this.originalPosition = this._generatePosition(event); + this.originalPageX = event.pageX; + this.originalPageY = event.pageY; + + //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied + if(o.cursorAt) + this._adjustOffsetFromHelper(o.cursorAt); + + //Cache the former DOM position + this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] }; + + //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way + if(this.helper[0] != this.currentItem[0]) { + this.currentItem.hide(); + } + + //Create the placeholder + this._createPlaceholder(); + + //Set a containment if given in the options + if(o.containment) + this._setContainment(); + + if(o.cursor) { // cursor option + if ($('body').css("cursor")) this._storedCursor = $('body').css("cursor"); + $('body').css("cursor", o.cursor); + } + + if(o.opacity) { // opacity option + if (this.helper.css("opacity")) this._storedOpacity = this.helper.css("opacity"); + this.helper.css("opacity", o.opacity); + } + + if(o.zIndex) { // zIndex option + if (this.helper.css("zIndex")) this._storedZIndex = this.helper.css("zIndex"); + this.helper.css("zIndex", o.zIndex); + } + + //Prepare scrolling + if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') + this.overflowOffset = this.scrollParent.offset(); + + //Call callbacks + this._trigger("start", event, this._uiHash()); + + //Recache the helper size + if(!this._preserveHelperProportions) + this._cacheHelperProportions(); + + + //Post 'activate' events to possible containers + if(!noActivation) { + for (var i = this.containers.length - 1; i >= 0; i--) { this.containers[i]._trigger("activate", event, self._uiHash(this)); } + } + + //Prepare possible droppables + if($.ui.ddmanager) + $.ui.ddmanager.current = this; + + if ($.ui.ddmanager && !o.dropBehaviour) + $.ui.ddmanager.prepareOffsets(this, event); + + this.dragging = true; + + this.helper.addClass("ui-sortable-helper"); + this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position + return true; + + }, + + _mouseDrag: function(event) { + + //Compute the helpers position + this.position = this._generatePosition(event); + this.positionAbs = this._convertPositionTo("absolute"); + + if (!this.lastPositionAbs) { + this.lastPositionAbs = this.positionAbs; + } + + //Do scrolling + if(this.options.scroll) { + var o = this.options, scrolled = false; + if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') { + + if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) + this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed; + else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) + this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed; + + if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) + this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed; + else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) + this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed; + + } else { + + if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) + scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); + else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) + scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); + + if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) + scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); + else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) + scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); + + } + + if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) + $.ui.ddmanager.prepareOffsets(this, event); + } + + //Regenerate the absolute position used for position checks + this.positionAbs = this._convertPositionTo("absolute"); + + //Set the helper position + if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px'; + if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px'; + + //Rearrange + for (var i = this.items.length - 1; i >= 0; i--) { + + //Cache variables and intersection, continue if no intersection + var item = this.items[i], itemElement = item.item[0], intersection = this._intersectsWithPointer(item); + if (!intersection) continue; + + if(itemElement != this.currentItem[0] //cannot intersect with itself + && this.placeholder[intersection == 1 ? "next" : "prev"]()[0] != itemElement //no useless actions that have been done before + && !$.ui.contains(this.placeholder[0], itemElement) //no action if the item moved is the parent of the item checked + && (this.options.type == 'semi-dynamic' ? !$.ui.contains(this.element[0], itemElement) : true) + ) { + + this.direction = intersection == 1 ? "down" : "up"; + + if (this.options.tolerance == "pointer" || this._intersectsWithSides(item)) { + this._rearrange(event, item); + } else { + break; + } + + this._trigger("change", event, this._uiHash()); + break; + } + } + + //Post events to containers + this._contactContainers(event); + + //Interconnect with droppables + if($.ui.ddmanager) $.ui.ddmanager.drag(this, event); + + //Call callbacks + this._trigger('sort', event, this._uiHash()); + + this.lastPositionAbs = this.positionAbs; + return false; + + }, + + _mouseStop: function(event, noPropagation) { + + if(!event) return; + + //If we are using droppables, inform the manager about the drop + if ($.ui.ddmanager && !this.options.dropBehaviour) + $.ui.ddmanager.drop(this, event); + + if(this.options.revert) { + var self = this; + var cur = self.placeholder.offset(); + + self.reverting = true; + + $(this.helper).animate({ + left: cur.left - this.offset.parent.left - self.margins.left + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft), + top: cur.top - this.offset.parent.top - self.margins.top + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop) + }, parseInt(this.options.revert, 10) || 500, function() { + self._clear(event); + }); + } else { + this._clear(event, noPropagation); + } + + return false; + + }, + + cancel: function() { + + var self = this; + + if(this.dragging) { + + this._mouseUp(); + + if(this.options.helper == "original") + this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); + else + this.currentItem.show(); + + //Post deactivating events to containers + for (var i = this.containers.length - 1; i >= 0; i--){ + this.containers[i]._trigger("deactivate", null, self._uiHash(this)); + if(this.containers[i].containerCache.over) { + this.containers[i]._trigger("out", null, self._uiHash(this)); + this.containers[i].containerCache.over = 0; + } + } + + } + + //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! + if(this.placeholder[0].parentNode) this.placeholder[0].parentNode.removeChild(this.placeholder[0]); + if(this.options.helper != "original" && this.helper && this.helper[0].parentNode) this.helper.remove(); + + $.extend(this, { + helper: null, + dragging: false, + reverting: false, + _noFinalSort: null + }); + + if(this.domPosition.prev) { + $(this.domPosition.prev).after(this.currentItem); + } else { + $(this.domPosition.parent).prepend(this.currentItem); + } + + return true; + + }, + + serialize: function(o) { + + var items = this._getItemsAsjQuery(o && o.connected); + var str = []; o = o || {}; + + $(items).each(function() { + var res = ($(o.item || this).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/)); + if(res) str.push((o.key || res[1]+'[]')+'='+(o.key && o.expression ? res[1] : res[2])); + }); + + return str.join('&'); + + }, + + toArray: function(o) { + + var items = this._getItemsAsjQuery(o && o.connected); + var ret = []; o = o || {}; + + items.each(function() { ret.push($(o.item || this).attr(o.attribute || 'id') || ''); }); + return ret; + + }, + + /* Be careful with the following core functions */ + _intersectsWith: function(item) { + + var x1 = this.positionAbs.left, + x2 = x1 + this.helperProportions.width, + y1 = this.positionAbs.top, + y2 = y1 + this.helperProportions.height; + + var l = item.left, + r = l + item.width, + t = item.top, + b = t + item.height; + + var dyClick = this.offset.click.top, + dxClick = this.offset.click.left; + + var isOverElement = (y1 + dyClick) > t && (y1 + dyClick) < b && (x1 + dxClick) > l && (x1 + dxClick) < r; + + if( this.options.tolerance == "pointer" + || this.options.forcePointerForContainers + || (this.options.tolerance != "pointer" && this.helperProportions[this.floating ? 'width' : 'height'] > item[this.floating ? 'width' : 'height']) + ) { + return isOverElement; + } else { + + return (l < x1 + (this.helperProportions.width / 2) // Right Half + && x2 - (this.helperProportions.width / 2) < r // Left Half + && t < y1 + (this.helperProportions.height / 2) // Bottom Half + && y2 - (this.helperProportions.height / 2) < b ); // Top Half + + } + }, + + _intersectsWithPointer: function(item) { + + var isOverElementHeight = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height), + isOverElementWidth = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width), + isOverElement = isOverElementHeight && isOverElementWidth, + verticalDirection = this._getDragVerticalDirection(), + horizontalDirection = this._getDragHorizontalDirection(); + + if (!isOverElement) + return false; + + return this.floating ? + ( ((horizontalDirection && horizontalDirection == "right") || verticalDirection == "down") ? 2 : 1 ) + : ( verticalDirection && (verticalDirection == "down" ? 2 : 1) ); + + }, + + _intersectsWithSides: function(item) { + + var isOverBottomHalf = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height), + isOverRightHalf = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width), + verticalDirection = this._getDragVerticalDirection(), + horizontalDirection = this._getDragHorizontalDirection(); + + if (this.floating && horizontalDirection) { + return ((horizontalDirection == "right" && isOverRightHalf) || (horizontalDirection == "left" && !isOverRightHalf)); + } else { + return verticalDirection && ((verticalDirection == "down" && isOverBottomHalf) || (verticalDirection == "up" && !isOverBottomHalf)); + } + + }, + + _getDragVerticalDirection: function() { + var delta = this.positionAbs.top - this.lastPositionAbs.top; + return delta != 0 && (delta > 0 ? "down" : "up"); + }, + + _getDragHorizontalDirection: function() { + var delta = this.positionAbs.left - this.lastPositionAbs.left; + return delta != 0 && (delta > 0 ? "right" : "left"); + }, + + refresh: function(event) { + this._refreshItems(event); + this.refreshPositions(); + }, + + _connectWith: function() { + var options = this.options; + return options.connectWith.constructor == String + ? [options.connectWith] + : options.connectWith; + }, + + _getItemsAsjQuery: function(connected) { + + var self = this; + var items = []; + var queries = []; + var connectWith = this._connectWith(); + + if(connectWith && connected) { + for (var i = connectWith.length - 1; i >= 0; i--){ + var cur = $(connectWith[i]); + for (var j = cur.length - 1; j >= 0; j--){ + var inst = $.data(cur[j], 'sortable'); + if(inst && inst != this && !inst.options.disabled) { + queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper"), inst]); + } + }; + }; + } + + queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper"), this]); + + for (var i = queries.length - 1; i >= 0; i--){ + queries[i][0].each(function() { + items.push(this); + }); + }; + + return $(items); + + }, + + _removeCurrentsFromItems: function() { + + var list = this.currentItem.find(":data(sortable-item)"); + + for (var i=0; i < this.items.length; i++) { + + for (var j=0; j < list.length; j++) { + if(list[j] == this.items[i].item[0]) + this.items.splice(i,1); + }; + + }; + + }, + + _refreshItems: function(event) { + + this.items = []; + this.containers = [this]; + var items = this.items; + var self = this; + var queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]]; + var connectWith = this._connectWith(); + + if(connectWith) { + for (var i = connectWith.length - 1; i >= 0; i--){ + var cur = $(connectWith[i]); + for (var j = cur.length - 1; j >= 0; j--){ + var inst = $.data(cur[j], 'sortable'); + if(inst && inst != this && !inst.options.disabled) { + queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]); + this.containers.push(inst); + } + }; + }; + } + + for (var i = queries.length - 1; i >= 0; i--) { + var targetData = queries[i][1]; + var _queries = queries[i][0]; + + for (var j=0, queriesLength = _queries.length; j < queriesLength; j++) { + var item = $(_queries[j]); + + item.data('sortable-item', targetData); // Data for target checking (mouse manager) + + items.push({ + item: item, + instance: targetData, + width: 0, height: 0, + left: 0, top: 0 + }); + }; + }; + + }, + + refreshPositions: function(fast) { + + //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change + if(this.offsetParent && this.helper) { + this.offset.parent = this._getParentOffset(); + } + + for (var i = this.items.length - 1; i >= 0; i--){ + var item = this.items[i]; + + //We ignore calculating positions of all connected containers when we're not over them + if(item.instance != this.currentContainer && this.currentContainer && item.item[0] != this.currentItem[0]) + continue; + + var t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item; + + if (!fast) { + item.width = t.outerWidth(); + item.height = t.outerHeight(); + } + + var p = t.offset(); + item.left = p.left; + item.top = p.top; + }; + + if(this.options.custom && this.options.custom.refreshContainers) { + this.options.custom.refreshContainers.call(this); + } else { + for (var i = this.containers.length - 1; i >= 0; i--){ + var p = this.containers[i].element.offset(); + this.containers[i].containerCache.left = p.left; + this.containers[i].containerCache.top = p.top; + this.containers[i].containerCache.width = this.containers[i].element.outerWidth(); + this.containers[i].containerCache.height = this.containers[i].element.outerHeight(); + }; + } + + }, + + _createPlaceholder: function(that) { + + var self = that || this, o = self.options; + + if(!o.placeholder || o.placeholder.constructor == String) { + var className = o.placeholder; + o.placeholder = { + element: function() { + + var el = $(document.createElement(self.currentItem[0].nodeName)) + .addClass(className || self.currentItem[0].className+" ui-sortable-placeholder") + .removeClass("ui-sortable-helper")[0]; + + if(!className) + el.style.visibility = "hidden"; + + return el; + }, + update: function(container, p) { + + // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that + // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified + if(className && !o.forcePlaceholderSize) return; + + //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item + if(!p.height()) { p.height(self.currentItem.innerHeight() - parseInt(self.currentItem.css('paddingTop')||0, 10) - parseInt(self.currentItem.css('paddingBottom')||0, 10)); }; + if(!p.width()) { p.width(self.currentItem.innerWidth() - parseInt(self.currentItem.css('paddingLeft')||0, 10) - parseInt(self.currentItem.css('paddingRight')||0, 10)); }; + } + }; + } + + //Create the placeholder + self.placeholder = $(o.placeholder.element.call(self.element, self.currentItem)); + + //Append it after the actual current item + self.currentItem.after(self.placeholder); + + //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317) + o.placeholder.update(self, self.placeholder); + + }, + + _contactContainers: function(event) { + for (var i = this.containers.length - 1; i >= 0; i--){ + + if(this._intersectsWith(this.containers[i].containerCache)) { + if(!this.containers[i].containerCache.over) { + + if(this.currentContainer != this.containers[i]) { + + //When entering a new container, we will find the item with the least distance and append our item near it + var dist = 10000; var itemWithLeastDistance = null; var base = this.positionAbs[this.containers[i].floating ? 'left' : 'top']; + for (var j = this.items.length - 1; j >= 0; j--) { + if(!$.ui.contains(this.containers[i].element[0], this.items[j].item[0])) continue; + var cur = this.items[j][this.containers[i].floating ? 'left' : 'top']; + if(Math.abs(cur - base) < dist) { + dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j]; + } + } + + if(!itemWithLeastDistance && !this.options.dropOnEmpty) //Check if dropOnEmpty is enabled + continue; + + this.currentContainer = this.containers[i]; + itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[i].element, true); + this._trigger("change", event, this._uiHash()); + this.containers[i]._trigger("change", event, this._uiHash(this)); + + //Update the placeholder + this.options.placeholder.update(this.currentContainer, this.placeholder); + + } + + this.containers[i]._trigger("over", event, this._uiHash(this)); + this.containers[i].containerCache.over = 1; + } + } else { + if(this.containers[i].containerCache.over) { + this.containers[i]._trigger("out", event, this._uiHash(this)); + this.containers[i].containerCache.over = 0; + } + } + + }; + }, + + _createHelper: function(event) { + + var o = this.options; + var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper == 'clone' ? this.currentItem.clone() : this.currentItem); + + if(!helper.parents('body').length) //Add the helper to the DOM if that didn't happen already + $(o.appendTo != 'parent' ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]); + + if(helper[0] == this.currentItem[0]) + this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") }; + + if(helper[0].style.width == '' || o.forceHelperSize) helper.width(this.currentItem.width()); + if(helper[0].style.height == '' || o.forceHelperSize) helper.height(this.currentItem.height()); + + return helper; + + }, + + _adjustOffsetFromHelper: function(obj) { + if(obj.left != undefined) this.offset.click.left = obj.left + this.margins.left; + if(obj.right != undefined) this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; + if(obj.top != undefined) this.offset.click.top = obj.top + this.margins.top; + if(obj.bottom != undefined) this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; + }, + + _getParentOffset: function() { + + + //Get the offsetParent and cache its position + this.offsetParent = this.helper.offsetParent(); + var po = this.offsetParent.offset(); + + // This is a special case where we need to modify a offset calculated on start, since the following happened: + // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent + // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that + // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag + if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) { + po.left += this.scrollParent.scrollLeft(); + po.top += this.scrollParent.scrollTop(); + } + + if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information + || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix + po = { top: 0, left: 0 }; + + return { + top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), + left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) + }; + + }, + + _getRelativeOffset: function() { + + if(this.cssPosition == "relative") { + var p = this.currentItem.position(); + return { + top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), + left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() + }; + } else { + return { top: 0, left: 0 }; + } + + }, + + _cacheMargins: function() { + this.margins = { + left: (parseInt(this.currentItem.css("marginLeft"),10) || 0), + top: (parseInt(this.currentItem.css("marginTop"),10) || 0) + }; + }, + + _cacheHelperProportions: function() { + this.helperProportions = { + width: this.helper.outerWidth(), + height: this.helper.outerHeight() + }; + }, + + _setContainment: function() { + + var o = this.options; + if(o.containment == 'parent') o.containment = this.helper[0].parentNode; + if(o.containment == 'document' || o.containment == 'window') this.containment = [ + 0 - this.offset.relative.left - this.offset.parent.left, + 0 - this.offset.relative.top - this.offset.parent.top, + $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left, + ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top + ]; + + if(!(/^(document|window|parent)$/).test(o.containment)) { + var ce = $(o.containment)[0]; + var co = $(o.containment).offset(); + var over = ($(ce).css("overflow") != 'hidden'); + + this.containment = [ + co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left, + co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top, + co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left, + co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top + ]; + } + + }, + + _convertPositionTo: function(d, pos) { + + if(!pos) pos = this.position; + var mod = d == "absolute" ? 1 : -1; + var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); + + return { + top: ( + pos.top // The absolute mouse position + + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent + + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border) + - ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) + ), + left: ( + pos.left // The absolute mouse position + + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent + + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border) + - ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) + ) + }; + + }, + + _generatePosition: function(event) { + + var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); + + // This is another very weird special case that only happens for relative elements: + // 1. If the css position is relative + // 2. and the scroll parent is the document or similar to the offset parent + // we have to refresh the relative offset during the scroll so there are no jumps + if(this.cssPosition == 'relative' && !(this.scrollParent[0] != document && this.scrollParent[0] != this.offsetParent[0])) { + this.offset.relative = this._getRelativeOffset(); + } + + var pageX = event.pageX; + var pageY = event.pageY; + + /* + * - Position constraining - + * Constrain the position to a mix of grid, containment. + */ + + if(this.originalPosition) { //If we are not dragging yet, we won't check for options + + if(this.containment) { + if(event.pageX - this.offset.click.left < this.containment[0]) pageX = this.containment[0] + this.offset.click.left; + if(event.pageY - this.offset.click.top < this.containment[1]) pageY = this.containment[1] + this.offset.click.top; + if(event.pageX - this.offset.click.left > this.containment[2]) pageX = this.containment[2] + this.offset.click.left; + if(event.pageY - this.offset.click.top > this.containment[3]) pageY = this.containment[3] + this.offset.click.top; + } + + if(o.grid) { + var top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1]; + pageY = this.containment ? (!(top - this.offset.click.top < this.containment[1] || top - this.offset.click.top > this.containment[3]) ? top : (!(top - this.offset.click.top < this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; + + var left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0]; + pageX = this.containment ? (!(left - this.offset.click.left < this.containment[0] || left - this.offset.click.left > this.containment[2]) ? left : (!(left - this.offset.click.left < this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; + } + + } + + return { + top: ( + pageY // The absolute mouse position + - this.offset.click.top // Click offset (relative to the element) + - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent + - this.offset.parent.top // The offsetParent's offset without borders (offset + border) + + ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) + ), + left: ( + pageX // The absolute mouse position + - this.offset.click.left // Click offset (relative to the element) + - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent + - this.offset.parent.left // The offsetParent's offset without borders (offset + border) + + ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) + ) + }; + + }, + + _rearrange: function(event, i, a, hardRefresh) { + + a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction == 'down' ? i.item[0] : i.item[0].nextSibling)); + + //Various things done here to improve the performance: + // 1. we create a setTimeout, that calls refreshPositions + // 2. on the instance, we have a counter variable, that get's higher after every append + // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same + // 4. this lets only the last addition to the timeout stack through + this.counter = this.counter ? ++this.counter : 1; + var self = this, counter = this.counter; + + window.setTimeout(function() { + if(counter == self.counter) self.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove + },0); + + }, + + _clear: function(event, noPropagation) { + + this.reverting = false; + // We delay all events that have to be triggered to after the point where the placeholder has been removed and + // everything else normalized again + var delayedTriggers = [], self = this; + + // We first have to update the dom position of the actual currentItem + // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088) + if(!this._noFinalSort && this.currentItem[0].parentNode) this.placeholder.before(this.currentItem); + this._noFinalSort = null; + + if(this.helper[0] == this.currentItem[0]) { + for(var i in this._storedCSS) { + if(this._storedCSS[i] == 'auto' || this._storedCSS[i] == 'static') this._storedCSS[i] = ''; + } + this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); + } else { + this.currentItem.show(); + } + + if(this.fromOutside && !noPropagation) delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); }); + if((this.fromOutside || this.domPosition.prev != this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent != this.currentItem.parent()[0]) && !noPropagation) delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed + if(!$.ui.contains(this.element[0], this.currentItem[0])) { //Node was moved out of the current element + if(!noPropagation) delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); }); + for (var i = this.containers.length - 1; i >= 0; i--){ + if($.ui.contains(this.containers[i].element[0], this.currentItem[0]) && !noPropagation) { + delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.containers[i])); + delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.containers[i])); + } + }; + }; + + //Post events to containers + for (var i = this.containers.length - 1; i >= 0; i--){ + if(!noPropagation) delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i])); + if(this.containers[i].containerCache.over) { + delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); }; }).call(this, this.containers[i])); + this.containers[i].containerCache.over = 0; + } + } + + //Do what was originally in plugins + if(this._storedCursor) $('body').css("cursor", this._storedCursor); //Reset cursor + if(this._storedOpacity) this.helper.css("opacity", this._storedOpacity); //Reset cursor + if(this._storedZIndex) this.helper.css("zIndex", this._storedZIndex == 'auto' ? '' : this._storedZIndex); //Reset z-index + + this.dragging = false; + if(this.cancelHelperRemoval) { + if(!noPropagation) { + this._trigger("beforeStop", event, this._uiHash()); + for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events + this._trigger("stop", event, this._uiHash()); + } + return false; + } + + if(!noPropagation) this._trigger("beforeStop", event, this._uiHash()); + + //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! + this.placeholder[0].parentNode.removeChild(this.placeholder[0]); + + if(this.helper[0] != this.currentItem[0]) this.helper.remove(); this.helper = null; + + if(!noPropagation) { + for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events + this._trigger("stop", event, this._uiHash()); + } + + this.fromOutside = false; + return true; + + }, + + _trigger: function() { + if ($.widget.prototype._trigger.apply(this, arguments) === false) { + this.cancel(); + } + }, + + _uiHash: function(inst) { + var self = inst || this; + return { + helper: self.helper, + placeholder: self.placeholder || $([]), + position: self.position, + absolutePosition: self.positionAbs, //deprecated + offset: self.positionAbs, + item: self.currentItem, + sender: inst ? inst.element : null + }; + } + +})); + +$.extend($.ui.sortable, { + getter: "serialize toArray", + version: "1.7.1", + eventPrefix: "sort", + defaults: { + appendTo: "parent", + axis: false, + cancel: ":input,option", + connectWith: false, + containment: false, + cursor: 'auto', + cursorAt: false, + delay: 0, + distance: 1, + dropOnEmpty: true, + forcePlaceholderSize: false, + forceHelperSize: false, + grid: false, + handle: false, + helper: "original", + items: '> *', + opacity: false, + placeholder: false, + revert: false, + scroll: true, + scrollSensitivity: 20, + scrollSpeed: 20, + scope: "default", + tolerance: "intersect", + zIndex: 1000 + } +}); + +})(jQuery); diff --git a/js2/mwEmbed/jquery/jquery.ui/ui/ui.tabs.js b/js2/mwEmbed/jquery/jquery.ui/ui/ui.tabs.js new file mode 100644 index 0000000000..a73dbc9a45 --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/ui/ui.tabs.js @@ -0,0 +1,685 @@ +/* + * jQuery UI Tabs 1.7.1 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Tabs + * + * Depends: + * ui.core.js + */ +(function($) { + +$.widget("ui.tabs", { + + _init: function() { + if (this.options.deselectable !== undefined) { + this.options.collapsible = this.options.deselectable; + } + this._tabify(true); + }, + + _setData: function(key, value) { + if (key == 'selected') { + if (this.options.collapsible && value == this.options.selected) { + return; + } + this.select(value); + } + else { + this.options[key] = value; + if (key == 'deselectable') { + this.options.collapsible = value; + } + this._tabify(); + } + }, + + _tabId: function(a) { + return a.title && a.title.replace(/\s/g, '_').replace(/[^A-Za-z0-9\-_:\.]/g, '') || + this.options.idPrefix + $.data(a); + }, + + _sanitizeSelector: function(hash) { + return hash.replace(/:/g, '\\:'); // we need this because an id may contain a ":" + }, + + _cookie: function() { + var cookie = this.cookie || (this.cookie = this.options.cookie.name || 'ui-tabs-' + $.data(this.list[0])); + return $.cookie.apply(null, [cookie].concat($.makeArray(arguments))); + }, + + _ui: function(tab, panel) { + return { + tab: tab, + panel: panel, + index: this.anchors.index(tab) + }; + }, + + _cleanup: function() { + // restore all former loading tabs labels + this.lis.filter('.ui-state-processing').removeClass('ui-state-processing') + .find('span:data(label.tabs)') + .each(function() { + var el = $(this); + el.html(el.data('label.tabs')).removeData('label.tabs'); + }); + }, + + _tabify: function(init) { + + this.list = this.element.children('ul:first'); + this.lis = $('li:has(a[href])', this.list); + this.anchors = this.lis.map(function() { return $('a', this)[0]; }); + this.panels = $([]); + + var self = this, o = this.options; + + var fragmentId = /^#.+/; // Safari 2 reports '#' for an empty hash + this.anchors.each(function(i, a) { + var href = $(a).attr('href'); + + // For dynamically created HTML that contains a hash as href IE < 8 expands + // such href to the full page url with hash and then misinterprets tab as ajax. + // Same consideration applies for an added tab with a fragment identifier + // since a[href=#fragment-identifier] does unexpectedly not match. + // Thus normalize href attribute... + var hrefBase = href.split('#')[0], baseEl; + if (hrefBase && (hrefBase === location.toString().split('#')[0] || + (baseEl = $('base')[0]) && hrefBase === baseEl.href)) { + href = a.hash; + a.href = href; + } + + // inline tab + if (fragmentId.test(href)) { + self.panels = self.panels.add(self._sanitizeSelector(href)); + } + + // remote tab + else if (href != '#') { // prevent loading the page itself if href is just "#" + $.data(a, 'href.tabs', href); // required for restore on destroy + + // TODO until #3808 is fixed strip fragment identifier from url + // (IE fails to load from such url) + $.data(a, 'load.tabs', href.replace(/#.*$/, '')); // mutable data + + var id = self._tabId(a); + a.href = '#' + id; + var $panel = $('#' + id); + if (!$panel.length) { + $panel = $(o.panelTemplate).attr('id', id).addClass('ui-tabs-panel ui-widget-content ui-corner-bottom') + .insertAfter(self.panels[i - 1] || self.list); + $panel.data('destroy.tabs', true); + } + self.panels = self.panels.add($panel); + } + + // invalid tab href + else { + o.disabled.push(i); + } + }); + + // initialization from scratch + if (init) { + + // attach necessary classes for styling + this.element.addClass('ui-tabs ui-widget ui-widget-content ui-corner-all'); + this.list.addClass('ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all'); + this.lis.addClass('ui-state-default ui-corner-top'); + this.panels.addClass('ui-tabs-panel ui-widget-content ui-corner-bottom'); + + // Selected tab + // use "selected" option or try to retrieve: + // 1. from fragment identifier in url + // 2. from cookie + // 3. from selected class attribute on
  • + if (o.selected === undefined) { + if (location.hash) { + this.anchors.each(function(i, a) { + if (a.hash == location.hash) { + o.selected = i; + return false; // break + } + }); + } + if (typeof o.selected != 'number' && o.cookie) { + o.selected = parseInt(self._cookie(), 10); + } + if (typeof o.selected != 'number' && this.lis.filter('.ui-tabs-selected').length) { + o.selected = this.lis.index(this.lis.filter('.ui-tabs-selected')); + } + o.selected = o.selected || 0; + } + else if (o.selected === null) { // usage of null is deprecated, TODO remove in next release + o.selected = -1; + } + + // sanity check - default to first tab... + o.selected = ((o.selected >= 0 && this.anchors[o.selected]) || o.selected < 0) ? o.selected : 0; + + // Take disabling tabs via class attribute from HTML + // into account and update option properly. + // A selected tab cannot become disabled. + o.disabled = $.unique(o.disabled.concat( + $.map(this.lis.filter('.ui-state-disabled'), + function(n, i) { return self.lis.index(n); } ) + )).sort(); + + if ($.inArray(o.selected, o.disabled) != -1) { + o.disabled.splice($.inArray(o.selected, o.disabled), 1); + } + + // highlight selected tab + this.panels.addClass('ui-tabs-hide'); + this.lis.removeClass('ui-tabs-selected ui-state-active'); + if (o.selected >= 0 && this.anchors.length) { // check for length avoids error when initializing empty list + this.panels.eq(o.selected).removeClass('ui-tabs-hide'); + this.lis.eq(o.selected).addClass('ui-tabs-selected ui-state-active'); + + // seems to be expected behavior that the show callback is fired + self.element.queue("tabs", function() { + self._trigger('show', null, self._ui(self.anchors[o.selected], self.panels[o.selected])); + }); + + this.load(o.selected); + } + + // clean up to avoid memory leaks in certain versions of IE 6 + $(window).bind('unload', function() { + self.lis.add(self.anchors).unbind('.tabs'); + self.lis = self.anchors = self.panels = null; + }); + + } + // update selected after add/remove + else { + o.selected = this.lis.index(this.lis.filter('.ui-tabs-selected')); + } + + // update collapsible + this.element[o.collapsible ? 'addClass' : 'removeClass']('ui-tabs-collapsible'); + + // set or update cookie after init and add/remove respectively + if (o.cookie) { + this._cookie(o.selected, o.cookie); + } + + // disable tabs + for (var i = 0, li; (li = this.lis[i]); i++) { + $(li)[$.inArray(i, o.disabled) != -1 && + !$(li).hasClass('ui-tabs-selected') ? 'addClass' : 'removeClass']('ui-state-disabled'); + } + + // reset cache if switching from cached to not cached + if (o.cache === false) { + this.anchors.removeData('cache.tabs'); + } + + // remove all handlers before, tabify may run on existing tabs after add or option change + this.lis.add(this.anchors).unbind('.tabs'); + + if (o.event != 'mouseover') { + var addState = function(state, el) { + if (el.is(':not(.ui-state-disabled)')) { + el.addClass('ui-state-' + state); + } + }; + var removeState = function(state, el) { + el.removeClass('ui-state-' + state); + }; + this.lis.bind('mouseover.tabs', function() { + addState('hover', $(this)); + }); + this.lis.bind('mouseout.tabs', function() { + removeState('hover', $(this)); + }); + this.anchors.bind('focus.tabs', function() { + addState('focus', $(this).closest('li')); + }); + this.anchors.bind('blur.tabs', function() { + removeState('focus', $(this).closest('li')); + }); + } + + // set up animations + var hideFx, showFx; + if (o.fx) { + if ($.isArray(o.fx)) { + hideFx = o.fx[0]; + showFx = o.fx[1]; + } + else { + hideFx = showFx = o.fx; + } + } + + // Reset certain styles left over from animation + // and prevent IE's ClearType bug... + function resetStyle($el, fx) { + $el.css({ display: '' }); + if ($.browser.msie && fx.opacity) { + $el[0].style.removeAttribute('filter'); + } + } + + // Show a tab... + var showTab = showFx ? + function(clicked, $show) { + $(clicked).closest('li').removeClass('ui-state-default').addClass('ui-tabs-selected ui-state-active'); + $show.hide().removeClass('ui-tabs-hide') // avoid flicker that way + .animate(showFx, showFx.duration || 'normal', function() { + resetStyle($show, showFx); + self._trigger('show', null, self._ui(clicked, $show[0])); + }); + } : + function(clicked, $show) { + $(clicked).closest('li').removeClass('ui-state-default').addClass('ui-tabs-selected ui-state-active'); + $show.removeClass('ui-tabs-hide'); + self._trigger('show', null, self._ui(clicked, $show[0])); + }; + + // Hide a tab, $show is optional... + var hideTab = hideFx ? + function(clicked, $hide) { + $hide.animate(hideFx, hideFx.duration || 'normal', function() { + self.lis.removeClass('ui-tabs-selected ui-state-active').addClass('ui-state-default'); + $hide.addClass('ui-tabs-hide'); + resetStyle($hide, hideFx); + self.element.dequeue("tabs"); + }); + } : + function(clicked, $hide, $show) { + self.lis.removeClass('ui-tabs-selected ui-state-active').addClass('ui-state-default'); + $hide.addClass('ui-tabs-hide'); + self.element.dequeue("tabs"); + }; + + // attach tab event handler, unbind to avoid duplicates from former tabifying... + this.anchors.bind(o.event + '.tabs', function() { + var el = this, $li = $(this).closest('li'), $hide = self.panels.filter(':not(.ui-tabs-hide)'), + $show = $(self._sanitizeSelector(this.hash)); + + // If tab is already selected and not collapsible or tab disabled or + // or is already loading or click callback returns false stop here. + // Check if click handler returns false last so that it is not executed + // for a disabled or loading tab! + if (($li.hasClass('ui-tabs-selected') && !o.collapsible) || + $li.hasClass('ui-state-disabled') || + $li.hasClass('ui-state-processing') || + self._trigger('select', null, self._ui(this, $show[0])) === false) { + this.blur(); + return false; + } + + o.selected = self.anchors.index(this); + + self.abort(); + + // if tab may be closed + if (o.collapsible) { + if ($li.hasClass('ui-tabs-selected')) { + o.selected = -1; + + if (o.cookie) { + self._cookie(o.selected, o.cookie); + } + + self.element.queue("tabs", function() { + hideTab(el, $hide); + }).dequeue("tabs"); + + this.blur(); + return false; + } + else if (!$hide.length) { + if (o.cookie) { + self._cookie(o.selected, o.cookie); + } + + self.element.queue("tabs", function() { + showTab(el, $show); + }); + + self.load(self.anchors.index(this)); // TODO make passing in node possible, see also http://dev.jqueryui.com/ticket/3171 + + this.blur(); + return false; + } + } + + if (o.cookie) { + self._cookie(o.selected, o.cookie); + } + + // show new tab + if ($show.length) { + if ($hide.length) { + self.element.queue("tabs", function() { + hideTab(el, $hide); + }); + } + self.element.queue("tabs", function() { + showTab(el, $show); + }); + + self.load(self.anchors.index(this)); + } + else { + throw 'jQuery UI Tabs: Mismatching fragment identifier.'; + } + + // Prevent IE from keeping other link focussed when using the back button + // and remove dotted border from clicked link. This is controlled via CSS + // in modern browsers; blur() removes focus from address bar in Firefox + // which can become a usability and annoying problem with tabs('rotate'). + if ($.browser.msie) { + this.blur(); + } + + }); + + // disable click in any case + this.anchors.bind('click.tabs', function(){return false;}); + + }, + + destroy: function() { + var o = this.options; + + this.abort(); + + this.element.unbind('.tabs') + .removeClass('ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible') + .removeData('tabs'); + + this.list.removeClass('ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all'); + + this.anchors.each(function() { + var href = $.data(this, 'href.tabs'); + if (href) { + this.href = href; + } + var $this = $(this).unbind('.tabs'); + $.each(['href', 'load', 'cache'], function(i, prefix) { + $this.removeData(prefix + '.tabs'); + }); + }); + + this.lis.unbind('.tabs').add(this.panels).each(function() { + if ($.data(this, 'destroy.tabs')) { + $(this).remove(); + } + else { + $(this).removeClass([ + 'ui-state-default', + 'ui-corner-top', + 'ui-tabs-selected', + 'ui-state-active', + 'ui-state-hover', + 'ui-state-focus', + 'ui-state-disabled', + 'ui-tabs-panel', + 'ui-widget-content', + 'ui-corner-bottom', + 'ui-tabs-hide' + ].join(' ')); + } + }); + + if (o.cookie) { + this._cookie(null, o.cookie); + } + }, + + add: function(url, label, index) { + if (index === undefined) { + index = this.anchors.length; // append by default + } + + var self = this, o = this.options, + $li = $(o.tabTemplate.replace(/#\{href\}/g, url).replace(/#\{label\}/g, label)), + id = !url.indexOf('#') ? url.replace('#', '') : this._tabId($('a', $li)[0]); + + $li.addClass('ui-state-default ui-corner-top').data('destroy.tabs', true); + + // try to find an existing element before creating a new one + var $panel = $('#' + id); + if (!$panel.length) { + $panel = $(o.panelTemplate).attr('id', id).data('destroy.tabs', true); + } + $panel.addClass('ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide'); + + if (index >= this.lis.length) { + $li.appendTo(this.list); + $panel.appendTo(this.list[0].parentNode); + } + else { + $li.insertBefore(this.lis[index]); + $panel.insertBefore(this.panels[index]); + } + + o.disabled = $.map(o.disabled, + function(n, i) { return n >= index ? ++n : n; }); + + this._tabify(); + + if (this.anchors.length == 1) { // after tabify + $li.addClass('ui-tabs-selected ui-state-active'); + $panel.removeClass('ui-tabs-hide'); + this.element.queue("tabs", function() { + self._trigger('show', null, self._ui(self.anchors[0], self.panels[0])); + }); + + this.load(0); + } + + // callback + this._trigger('add', null, this._ui(this.anchors[index], this.panels[index])); + }, + + remove: function(index) { + var o = this.options, $li = this.lis.eq(index).remove(), + $panel = this.panels.eq(index).remove(); + + // If selected tab was removed focus tab to the right or + // in case the last tab was removed the tab to the left. + if ($li.hasClass('ui-tabs-selected') && this.anchors.length > 1) { + this.select(index + (index + 1 < this.anchors.length ? 1 : -1)); + } + + o.disabled = $.map($.grep(o.disabled, function(n, i) { return n != index; }), + function(n, i) { return n >= index ? --n : n; }); + + this._tabify(); + + // callback + this._trigger('remove', null, this._ui($li.find('a')[0], $panel[0])); + }, + + enable: function(index) { + var o = this.options; + if ($.inArray(index, o.disabled) == -1) { + return; + } + + this.lis.eq(index).removeClass('ui-state-disabled'); + o.disabled = $.grep(o.disabled, function(n, i) { return n != index; }); + + // callback + this._trigger('enable', null, this._ui(this.anchors[index], this.panels[index])); + }, + + disable: function(index) { + var self = this, o = this.options; + if (index != o.selected) { // cannot disable already selected tab + this.lis.eq(index).addClass('ui-state-disabled'); + + o.disabled.push(index); + o.disabled.sort(); + + // callback + this._trigger('disable', null, this._ui(this.anchors[index], this.panels[index])); + } + }, + + select: function(index) { + if (typeof index == 'string') { + index = this.anchors.index(this.anchors.filter('[href$=' + index + ']')); + } + else if (index === null) { // usage of null is deprecated, TODO remove in next release + index = -1; + } + if (index == -1 && this.options.collapsible) { + index = this.options.selected; + } + + this.anchors.eq(index).trigger(this.options.event + '.tabs'); + }, + + load: function(index) { + var self = this, o = this.options, a = this.anchors.eq(index)[0], url = $.data(a, 'load.tabs'); + + this.abort(); + + // not remote or from cache + if (!url || this.element.queue("tabs").length !== 0 && $.data(a, 'cache.tabs')) { + this.element.dequeue("tabs"); + return; + } + + // load remote from here on + this.lis.eq(index).addClass('ui-state-processing'); + + if (o.spinner) { + var span = $('span', a); + span.data('label.tabs', span.html()).html(o.spinner); + } + + this.xhr = $.ajax($.extend({}, o.ajaxOptions, { + url: url, + success: function(r, s) { + $(self._sanitizeSelector(a.hash)).html(r); + + // take care of tab labels + self._cleanup(); + + if (o.cache) { + $.data(a, 'cache.tabs', true); // if loaded once do not load them again + } + + // callbacks + self._trigger('load', null, self._ui(self.anchors[index], self.panels[index])); + try { + o.ajaxOptions.success(r, s); + } + catch (e) {} + + // last, so that load event is fired before show... + self.element.dequeue("tabs"); + } + })); + }, + + abort: function() { + // stop possibly running animations + this.element.queue([]); + this.panels.stop(false, true); + + // terminate pending requests from other tabs + if (this.xhr) { + this.xhr.abort(); + delete this.xhr; + } + + // take care of tab labels + this._cleanup(); + + }, + + url: function(index, url) { + this.anchors.eq(index).removeData('cache.tabs').data('load.tabs', url); + }, + + length: function() { + return this.anchors.length; + } + +}); + +$.extend($.ui.tabs, { + version: '1.7.1', + getter: 'length', + defaults: { + ajaxOptions: null, + cache: false, + cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true } + collapsible: false, + disabled: [], + event: 'click', + fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 } + idPrefix: 'ui-tabs-', + panelTemplate: '
    ', + spinner: 'Loading…', + tabTemplate: '
  • #{label}
  • ' + } +}); + +/* + * Tabs Extensions + */ + +/* + * Rotate + */ +$.extend($.ui.tabs.prototype, { + rotation: null, + rotate: function(ms, continuing) { + + var self = this, o = this.options; + + var rotate = self._rotate || (self._rotate = function(e) { + clearTimeout(self.rotation); + self.rotation = setTimeout(function() { + var t = o.selected; + self.select( ++t < self.anchors.length ? t : 0 ); + }, ms); + + if (e) { + e.stopPropagation(); + } + }); + + var stop = self._unrotate || (self._unrotate = !continuing ? + function(e) { + if (e.clientX) { // in case of a true click + self.rotate(null); + } + } : + function(e) { + t = o.selected; + rotate(); + }); + + // start rotation + if (ms) { + this.element.bind('tabsshow', rotate); + this.anchors.bind(o.event + '.tabs', stop); + rotate(); + } + // stop rotation + else { + clearTimeout(self.rotation); + this.element.unbind('tabsshow', rotate); + this.anchors.unbind(o.event + '.tabs', stop); + delete this._rotate; + delete this._unrotate; + } + } +}); + +})(jQuery); diff --git a/js2/mwEmbed/jquery/jquery.ui/version.txt b/js2/mwEmbed/jquery/jquery.ui/version.txt new file mode 100644 index 0000000000..081af9a10f --- /dev/null +++ b/js2/mwEmbed/jquery/jquery.ui/version.txt @@ -0,0 +1 @@ +1.7.1 \ No newline at end of file diff --git a/js2/mwEmbed/jquery/plugins/date.js b/js2/mwEmbed/jquery/plugins/date.js new file mode 100644 index 0000000000..86f802fc0d --- /dev/null +++ b/js2/mwEmbed/jquery/plugins/date.js @@ -0,0 +1,467 @@ +/* + * Date prototype extensions. Doesn't depend on any + * other code. Doens't overwrite existing methods. + * + * Adds dayNames, abbrDayNames, monthNames and abbrMonthNames static properties and isLeapYear, + * isWeekend, isWeekDay, getDaysInMonth, getDayName, getMonthName, getDayOfYear, getWeekOfYear, + * setDayOfYear, addYears, addMonths, addDays, addHours, addMinutes, addSeconds methods + * + * Copyright (c) 2006 Jörn Zaefferer and Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net) + * + * Additional methods and properties added by Kelvin Luck: firstDayOfWeek, dateFormat, zeroTime, asString, fromString - + * I've added my name to these methods so you know who to blame if they are broken! + * + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + */ + +/** + * An Array of day names starting with Sunday. + * + * @example dayNames[0] + * @result 'Sunday' + * + * @name dayNames + * @type Array + * @cat Plugins/Methods/Date + */ +Date.dayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; + +/** + * An Array of abbreviated day names starting with Sun. + * + * @example abbrDayNames[0] + * @result 'Sun' + * + * @name abbrDayNames + * @type Array + * @cat Plugins/Methods/Date + */ +Date.abbrDayNames = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; + +/** + * An Array of month names starting with Janurary. + * + * @example monthNames[0] + * @result 'January' + * + * @name monthNames + * @type Array + * @cat Plugins/Methods/Date + */ +Date.monthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; + +/** + * An Array of abbreviated month names starting with Jan. + * + * @example abbrMonthNames[0] + * @result 'Jan' + * + * @name monthNames + * @type Array + * @cat Plugins/Methods/Date + */ +Date.abbrMonthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; + +/** + * The first day of the week for this locale. + * + * @name firstDayOfWeek + * @type Number + * @cat Plugins/Methods/Date + * @author Kelvin Luck + */ +Date.firstDayOfWeek = 1; + +/** + * The format that string dates should be represented as (e.g. 'dd/mm/yyyy' for UK, 'mm/dd/yyyy' for US, 'yyyy-mm-dd' for Unicode etc). + * + * @name format + * @type String + * @cat Plugins/Methods/Date + * @author Kelvin Luck + */ +Date.format = 'dd/mm/yyyy'; +//Date.format = 'mm/dd/yyyy'; +//Date.format = 'yyyy-mm-dd'; +//Date.format = 'dd mmm yy'; + +/** + * The first two numbers in the century to be used when decoding a two digit year. Since a two digit year is ambiguous (and date.setYear + * only works with numbers < 99 and so doesn't allow you to set years after 2000) we need to use this to disambiguate the two digit year codes. + * + * @name format + * @type String + * @cat Plugins/Methods/Date + * @author Kelvin Luck + */ +Date.fullYearStart = '20'; + +(function() { + + /** + * Adds a given method under the given name + * to the Date prototype if it doesn't + * currently exist. + * + * @private + */ + function add(name, method) { + if( !Date.prototype[name] ) { + Date.prototype[name] = method; + } + }; + + /** + * Checks if the year is a leap year. + * + * @example var dtm = new Date("01/12/2008"); + * dtm.isLeapYear(); + * @result true + * + * @name isLeapYear + * @type Boolean + * @cat Plugins/Methods/Date + */ + add("isLeapYear", function() { + var y = this.getFullYear(); + return (y%4==0 && y%100!=0) || y%400==0; + }); + + /** + * Checks if the day is a weekend day (Sat or Sun). + * + * @example var dtm = new Date("01/12/2008"); + * dtm.isWeekend(); + * @result false + * + * @name isWeekend + * @type Boolean + * @cat Plugins/Methods/Date + */ + add("isWeekend", function() { + return this.getDay()==0 || this.getDay()==6; + }); + + /** + * Check if the day is a day of the week (Mon-Fri) + * + * @example var dtm = new Date("01/12/2008"); + * dtm.isWeekDay(); + * @result false + * + * @name isWeekDay + * @type Boolean + * @cat Plugins/Methods/Date + */ + add("isWeekDay", function() { + return !this.isWeekend(); + }); + + /** + * Gets the number of days in the month. + * + * @example var dtm = new Date("01/12/2008"); + * dtm.getDaysInMonth(); + * @result 31 + * + * @name getDaysInMonth + * @type Number + * @cat Plugins/Methods/Date + */ + add("getDaysInMonth", function() { + return [31,(this.isLeapYear() ? 29:28),31,30,31,30,31,31,30,31,30,31][this.getMonth()]; + }); + + /** + * Gets the name of the day. + * + * @example var dtm = new Date("01/12/2008"); + * dtm.getDayName(); + * @result 'Saturday' + * + * @example var dtm = new Date("01/12/2008"); + * dtm.getDayName(true); + * @result 'Sat' + * + * @param abbreviated Boolean When set to true the name will be abbreviated. + * @name getDayName + * @type String + * @cat Plugins/Methods/Date + */ + add("getDayName", function(abbreviated) { + return abbreviated ? Date.abbrDayNames[this.getDay()] : Date.dayNames[this.getDay()]; + }); + + /** + * Gets the name of the month. + * + * @example var dtm = new Date("01/12/2008"); + * dtm.getMonthName(); + * @result 'Janurary' + * + * @example var dtm = new Date("01/12/2008"); + * dtm.getMonthName(true); + * @result 'Jan' + * + * @param abbreviated Boolean When set to true the name will be abbreviated. + * @name getDayName + * @type String + * @cat Plugins/Methods/Date + */ + add("getMonthName", function(abbreviated) { + return abbreviated ? Date.abbrMonthNames[this.getMonth()] : Date.monthNames[this.getMonth()]; + }); + + /** + * Get the number of the day of the year. + * + * @example var dtm = new Date("01/12/2008"); + * dtm.getDayOfYear(); + * @result 11 + * + * @name getDayOfYear + * @type Number + * @cat Plugins/Methods/Date + */ + add("getDayOfYear", function() { + var tmpdtm = new Date("1/1/" + this.getFullYear()); + return Math.floor((this.getTime() - tmpdtm.getTime()) / 86400000); + }); + + /** + * Get the number of the week of the year. + * + * @example var dtm = new Date("01/12/2008"); + * dtm.getWeekOfYear(); + * @result 2 + * + * @name getWeekOfYear + * @type Number + * @cat Plugins/Methods/Date + */ + add("getWeekOfYear", function() { + return Math.ceil(this.getDayOfYear() / 7); + }); + + /** + * Set the day of the year. + * + * @example var dtm = new Date("01/12/2008"); + * dtm.setDayOfYear(1); + * dtm.toString(); + * @result 'Tue Jan 01 2008 00:00:00' + * + * @name setDayOfYear + * @type Date + * @cat Plugins/Methods/Date + */ + add("setDayOfYear", function(day) { + this.setMonth(0); + this.setDate(day); + return this; + }); + + /** + * Add a number of years to the date object. + * + * @example var dtm = new Date("01/12/2008"); + * dtm.addYears(1); + * dtm.toString(); + * @result 'Mon Jan 12 2009 00:00:00' + * + * @name addYears + * @type Date + * @cat Plugins/Methods/Date + */ + add("addYears", function(num) { + this.setFullYear(this.getFullYear() + num); + return this; + }); + + /** + * Add a number of months to the date object. + * + * @example var dtm = new Date("01/12/2008"); + * dtm.addMonths(1); + * dtm.toString(); + * @result 'Tue Feb 12 2008 00:00:00' + * + * @name addMonths + * @type Date + * @cat Plugins/Methods/Date + */ + add("addMonths", function(num) { + var tmpdtm = this.getDate(); + + this.setMonth(this.getMonth() + num); + + if (tmpdtm > this.getDate()) + this.addDays(-this.getDate()); + + return this; + }); + + /** + * Add a number of days to the date object. + * + * @example var dtm = new Date("01/12/2008"); + * dtm.addDays(1); + * dtm.toString(); + * @result 'Sun Jan 13 2008 00:00:00' + * + * @name addDays + * @type Date + * @cat Plugins/Methods/Date + */ + add("addDays", function(num) { + this.setDate(this.getDate() + num); + return this; + }); + + /** + * Add a number of hours to the date object. + * + * @example var dtm = new Date("01/12/2008"); + * dtm.addHours(24); + * dtm.toString(); + * @result 'Sun Jan 13 2008 00:00:00' + * + * @name addHours + * @type Date + * @cat Plugins/Methods/Date + */ + add("addHours", function(num) { + this.setHours(this.getHours() + num); + return this; + }); + + /** + * Add a number of minutes to the date object. + * + * @example var dtm = new Date("01/12/2008"); + * dtm.addMinutes(60); + * dtm.toString(); + * @result 'Sat Jan 12 2008 01:00:00' + * + * @name addMinutes + * @type Date + * @cat Plugins/Methods/Date + */ + add("addMinutes", function(num) { + this.setMinutes(this.getMinutes() + num); + return this; + }); + + /** + * Add a number of seconds to the date object. + * + * @example var dtm = new Date("01/12/2008"); + * dtm.addSeconds(60); + * dtm.toString(); + * @result 'Sat Jan 12 2008 00:01:00' + * + * @name addSeconds + * @type Date + * @cat Plugins/Methods/Date + */ + add("addSeconds", function(num) { + this.setSeconds(this.getSeconds() + num); + return this; + }); + + /** + * Sets the time component of this Date to zero for cleaner, easier comparison of dates where time is not relevant. + * + * @example var dtm = new Date(); + * dtm.zeroTime(); + * dtm.toString(); + * @result 'Sat Jan 12 2008 00:01:00' + * + * @name zeroTime + * @type Date + * @cat Plugins/Methods/Date + * @author Kelvin Luck + */ + add("zeroTime", function() { + this.setMilliseconds(0); + this.setSeconds(0); + this.setMinutes(0); + this.setHours(0); + return this; + }); + + /** + * Returns a string representation of the date object according to Date.format. + * (Date.toString may be used in other places so I purposefully didn't overwrite it) + * + * @example var dtm = new Date("01/12/2008"); + * dtm.asString(); + * @result '12/01/2008' // (where Date.format == 'dd/mm/yyyy' + * + * @name asString + * @type Date + * @cat Plugins/Methods/Date + * @author Kelvin Luck + */ + add("asString", function() { + var r = Date.format; + return r + .split('yyyy').join(this.getFullYear()) + .split('yy').join((this.getFullYear() + '').substring(2)) + .split('mmm').join(this.getMonthName(true)) + .split('mm').join(_zeroPad(this.getMonth()+1)) + .split('dd').join(_zeroPad(this.getDate())); + }); + + /** + * Returns a new date object created from the passed String according to Date.format or false if the attempt to do this results in an invalid date object + * (We can't simple use Date.parse as it's not aware of locale and I chose not to overwrite it incase it's functionality is being relied on elsewhere) + * + * @example var dtm = Date.fromString("12/01/2008"); + * dtm.toString(); + * @result 'Sat Jan 12 2008 00:00:00' // (where Date.format == 'dd/mm/yyyy' + * + * @name fromString + * @type Date + * @cat Plugins/Methods/Date + * @author Kelvin Luck + */ + Date.fromString = function(s) + { + var f = Date.format; + var d = new Date('01/01/1977'); + var iY = f.indexOf('yyyy'); + if (iY > -1) { + d.setFullYear(Number(s.substr(iY, 4))); + } else { + // TODO - this doesn't work very well - are there any rules for what is meant by a two digit year? + d.setFullYear(Number(Date.fullYearStart + s.substr(f.indexOf('yy'), 2))); + } + var iM = f.indexOf('mmm'); + if (iM > -1) { + var mStr = s.substr(iM, 3); + for (var i=0; i 0 ) $results.css("width", options.width); + }else{ + var results = $j(options.resultElem).get(0); + var $results = $j(options.resultElem); + $results.hide(); + } + + + input.autocompleter = me; + + var timeout = null; + var prev = ""; + var active = -1; + var cache = {}; + var keyb = false; + var hasFocus = false; + var lastKeyPressCode = null; + + // flush cache + function flushCache(){ + cache = {}; + cache.data = {}; + cache.length = 0; + }; + + // flush cache + flushCache(); + + // if there is a data array supplied + if( options.data != null ){ + var sFirstChar = "", stMatchSets = {}, row = []; + + // no url was specified, we need to adjust the cache length to make sure it fits the local data store + if( typeof options.url != "string" ) options.cacheLength = 1; + + // loop through the array and create a lookup structure + for( var i=0; i < options.data.length; i++ ){ + // if row is a string, make an array otherwise just reference the array + row = ((typeof options.data[i] == "string") ? [options.data[i]] : options.data[i]); + + // if the length is zero, don't add to list + if( row[0].length > 0 ){ + // get the first character + sFirstChar = row[0].substring(0, 1).toLowerCase(); + // if no lookup array for this character exists, look it up now + if( !stMatchSets[sFirstChar] ) stMatchSets[sFirstChar] = []; + // if the match is a string + stMatchSets[sFirstChar].push(row); + } + } + + // add the data items to the cache + for( var k in stMatchSets ){ + // increase the cache size + options.cacheLength++; + // add to the cache + addToCache(k, stMatchSets[k]); + } + } + + $input + .keydown(function(e) { + // track last key pressed + lastKeyPressCode = e.keyCode; + switch(e.keyCode) { + case 38: // up + e.preventDefault(); + moveSelect(-1); + break; + case 40: // down + e.preventDefault(); + moveSelect(1); + break; + case 9: // tab + case 13: // return + if( selectCurrent() ){ + // make sure to blur off the current field + $input.get(0).blur(); + e.preventDefault(); + } + break; + default: + active = -1; + if (timeout) clearTimeout(timeout); + timeout = setTimeout(function(){onChange();}, options.delay); + break; + } + }) + .focus(function(){ + // track whether the field has focus, we shouldn't process any results if the field no longer has focus + hasFocus = true; + }) + .blur(function() { + // track whether the field has focus + hasFocus = false; + hideResults(); + }); + + hideResultsNow(); + + function onChange() { + // ignore if the following keys are pressed: [del] [shift] [capslock] + if( lastKeyPressCode == 46 || (lastKeyPressCode > 8 && lastKeyPressCode < 32) ) return $results.hide(); + var v = $input.val(); + if (v == prev) return; + prev = v; + if (v.length >= options.minChars) { + $input.addClass(options.loadingClass); + requestData(v); + } else { + $input.removeClass(options.loadingClass); + $results.hide(); + } + }; + + function moveSelect(step) { + var lis = $("li", results); + if (!lis) return; + + active += step; + + if (active < 0) { + active = 0; + } else if (active >= lis.size()) { + active = lis.size() - 1; + } + + lis.removeClass("ac_over"); + + $(lis[active]).addClass("ac_over"); + + // Weird behaviour in IE + // if (lis[active] && lis[active].scrollIntoView) { + // lis[active].scrollIntoView(false); + // } + + }; + function selectCurrent() { + var li = $("li.ac_over", results)[0]; + if (!li) { + var $li = $("li", results); + if (options.selectOnly) { + if ($li.length == 1) li = $li[0]; + } else if (options.selectFirst) { + li = $li[0]; + } + } + if (li) { + selectItem(li); + return true; + } else { + return false; + } + }; + + function selectItem(li) { + if (!li) { + li = document.createElement("li"); + li.extra = []; + li.selectValue = ""; + } + var v = $.trim(li.selectValue ? li.selectValue : li.innerHTML); + input.lastSelected = v; + prev = v; + $results.html(""); + $input.val(v); + hideResultsNow(); + if (options.onItemSelect) setTimeout(function() { options.onItemSelect(li) }, 1); + }; + + // selects a portion of the input string + function createSelection(start, end){ + // get a reference to the input element + var field = $input.get(0); + if( field.createTextRange ){ + var selRange = field.createTextRange(); + selRange.collapse(true); + selRange.moveStart("character", start); + selRange.moveEnd("character", end); + selRange.select(); + } else if( field.setSelectionRange ){ + field.setSelectionRange(start, end); + } else { + if( field.selectionStart ){ + field.selectionStart = start; + field.selectionEnd = end; + } + } + field.focus(); + }; + + // fills in the input box w/the first match (assumed to be the best match) + function autoFill(sValue){ + // if the last user key pressed was backspace, don't autofill + if( lastKeyPressCode != 8 ){ + // fill in the value (keep the case the user has typed) + $input.val($input.val() + sValue.substring(prev.length)); + // select the portion of the value not typed by the user (so the next character will erase) + createSelection(prev.length, sValue.length); + } + }; + + function showResults() { + // get the position of the input field right now (in case the DOM is shifted) + var pos = findPos(input); + // either use the specified width, or autocalculate based on form element + var iWidth = (options.width > 0) ? options.width : $input.width(); + // reposition + if(!options.resultElem){ + $results.css({ + width: parseInt(iWidth) + "px", + top: (pos.y + input.offsetHeight) + "px", + left: pos.x + "px" + }).show(); + }else{ + $results.show(); + } + if(options.resultContainer){ + $(options.resultContainer).css({top: (pos.y + input.offsetHeight) + "px", + left: (pos.x- parseInt(iWidth)) + "px"}).show(); + } + }; + + function hideResults() { + if (timeout) clearTimeout(timeout); + timeout = setTimeout(hideResultsNow, 200); + }; + + function hideResultsNow() { + if (timeout) clearTimeout(timeout); + $input.removeClass(options.loadingClass); + if ($results.is(":visible")) { + $results.hide(); + } + if(options.resultContainer){ + $(options.resultContainer).hide(); + } + if (options.mustMatch) { + var v = $input.val(); + if (v != input.lastSelected) { + selectItem(null); + } + } + }; + + function receiveData(q, data) { + if (data) { + $input.removeClass(options.loadingClass); + results.innerHTML = ""; + + // if the field no longer has focus or if there are no matches, do not display the drop down + if( !hasFocus || data.length == 0 ) return hideResultsNow(); + + //messes with layout & ie7 does not have this problem + /*if ($.browser.msie) { + // we put a styled iframe behind the calendar so HTML SELECT elements don't show through + $results.append(document.createElement('iframe')); + }*/ + results.appendChild(dataToDom(data)); + // autofill in the complete box w/the first match as long as the user hasn't entered in more data + if( options.autoFill && ($input.val().toLowerCase() == q.toLowerCase()) ) autoFill(data[0][0]); + showResults(); + } else { + hideResultsNow(); + } + }; + + function parseData(data) { + if (!data) return null; + var parsed = []; + var rows = data.split(options.lineSeparator); + for (var i=0; i < rows.length; i++) { + var row = $.trim(rows[i]); + if (row) { + parsed[parsed.length] = row.split(options.cellSeparator); + } + } + return parsed; + }; + + function dataToDom(data) { + var ul = document.createElement("ul"); + if(options.ul_class)$(ul).addClass(options.ul_class); + + var num = data.length; + + // limited results to a max number + if( (options.maxItemsToShow > 0) && (options.maxItemsToShow < num) ) num = options.maxItemsToShow; + + for (var i=0; i < num; i++) { + var row = data[i]; + if (!row) continue; + var li = document.createElement("li"); + if (options.formatItem) { + li.innerHTML = options.formatItem(row, i, num); + li.selectValue = row[0]; + } else { + li.innerHTML = row[0]; + li.selectValue = row[0]; + } + var extra = null; + if (row.length > 1) { + extra = []; + for (var j=1; j < row.length; j++) { + extra[extra.length] = row[j]; + } + } + li.extra = extra; + ul.appendChild(li); + $(li).hover( + function() { $("li", ul).removeClass("ac_over"); $(this).addClass("ac_over"); active = $("li", ul).indexOf($(this).get(0)); }, + function() { $(this).removeClass("ac_over"); } + ).click(function(e) { e.preventDefault(); e.stopPropagation(); selectItem(this) }); + } + return ul; + }; + + function requestData(q) { + if (!options.matchCase) q = q.toLowerCase(); + //var data = options.cacheLength ? loadFromCache(q) : null; + var data=null; + // recieve the cached data + if (data) { + receiveData(q, data); + // if an AJAX url has been supplied, try loading the data now + } else if( (typeof options.url == "string") && (options.url.length > 0) ){ + $.get(makeUrl(q), function(data) { + data = parseData(data); + addToCache(q, data); + receiveData(q, data); + }); + // if there's been no data found, remove the loading class + } else { + $input.removeClass(options.loadingClass); + } + }; + + function makeUrl(q) { + var url = options.url + "?"+options.paramName+'='+ encodeURI(q); + for (var i in options.extraParams) { + url += "&" + i + "=" + encodeURI(options.extraParams[i]); + } + return url; + }; + + function loadFromCache(q) { + if (!q) return null; + if (typeof cache.data[q]!='undefined'){ + return cache.data[q]; + } + if (options.matchSubset) { + for (var i = q.length - 1; i >= options.minChars; i--) { + var qs = q.substr(0, i); + var c = cache.data[qs]; + if (c) { + var csub = []; + for (var j = 0; j < c.length; j++) { + var x = c[j]; + var x0 = x[0]; + if (matchSubset(x0, q)) { + csub[csub.length] = x; + } + } + return csub; + } + } + } + return null; + }; + + function matchSubset(s, sub) { + if (!options.matchCase) s = s.toLowerCase(); + var i = s.indexOf(sub); + if (i == -1) return false; + return i == 0 || options.matchContains; + }; + + this.flushCache = function() { + flushCache(); + }; + + this.setExtraParams = function(p) { + options.extraParams = p; + }; + + this.findValue = function(){ + var q = $input.val(); + + if (!options.matchCase) q = q.toLowerCase(); + var data = options.cacheLength ? loadFromCache(q) : null; + if (data) { + findValueCallback(q, data); + } else if( (typeof options.url == "string") && (options.url.length > 0) ){ + $.get(makeUrl(q), function(data) { + data = parseData(data) + addToCache(q, data); + findValueCallback(q, data); + }); + } else { + // no matches + findValueCallback(q, null); + } + } + + function findValueCallback(q, data){ + if (data) $input.removeClass(options.loadingClass); + + var num = (data) ? data.length : 0; + var li = null; + + for (var i=0; i < num; i++) { + var row = data[i]; + + if( row[0].toLowerCase() == q.toLowerCase() ){ + li = document.createElement("li"); + if (options.formatItem) { + li.innerHTML = options.formatItem(row, i, num); + li.selectValue = row[0]; + } else { + li.innerHTML = row[0]; + li.selectValue = row[0]; + } + var extra = null; + if( row.length > 1 ){ + extra = []; + for (var j=1; j < row.length; j++) { + extra[extra.length] = row[j]; + } + } + li.extra = extra; + } + } + + if( options.onFindValue ) setTimeout(function() { options.onFindValue(li) }, 1); + } + + function addToCache(q, data) { + if (!data || !q || !options.cacheLength) return; + if (!cache.length || cache.length > options.cacheLength) { + flushCache(); + cache.length++; + } else if (!cache[q]) { + cache.length++; + } + cache.data[q] = data; + }; + + function findPos(obj) { + var curleft = obj.offsetLeft || 0; + var curtop = obj.offsetTop || 0; + while (obj = obj.offsetParent) { + curleft += obj.offsetLeft + curtop += obj.offsetTop + } + return {x:curleft,y:curtop}; + } +} +})(jQuery); + +jQuery.fn.autocomplete = function(url, options, data) { + // Make sure options exists + options = options || {}; + // Set url as option + options.url = url; + // set some bulk local data + options.data = ((typeof data == "object") && (data.constructor == Array)) ? data : null; + + // Set default values for required options + options.resultElem = options.resultElem || null; + options.paramName = options.paramName || 'q'; + + options.inputClass = options.inputClass || "ac_input"; + options.resultsClass = options.resultsClass || "ac_results"; + options.lineSeparator = options.lineSeparator || "\n"; + options.cellSeparator = options.cellSeparator || "|"; + options.minChars = options.minChars || 1; + options.delay = options.delay || 400; + options.matchCase = options.matchCase || 0; + options.matchSubset = options.matchSubset || 1; + options.matchContains = options.matchContains || 0; + options.cacheLength = options.cacheLength || 1; + options.mustMatch = options.mustMatch || 0; + options.extraParams = options.extraParams || {}; + options.loadingClass = options.loadingClass || "ac_loading"; + options.selectFirst = options.selectFirst || false; + options.selectOnly = options.selectOnly || false; + options.maxItemsToShow = options.maxItemsToShow || -1; + options.autoFill = options.autoFill || false; + options.width = parseInt(options.width, 10) || 0; + + this.each(function() { + var input = this; + new jQuery.autocomplete(input, options); + }); + + // Don't break the chain + return this; +} + +jQuery.fn.autocompleteArray = function(data, options) { + return this.autocomplete(null, options, data); +} + +jQuery.fn.indexOf = function(e){ + for( var i=0; i

    Paragraph

    + * @result
    ' ); + + // Set the form target to the iframe + form.attr( 'target', _this.iframeId ); + + // Set up the completion callback + $j( '#' + _this.iframeId ).load( function() { + _this.processIframeResult( $j( this ).get( 0 ) ); + }); + + // Set the action to the API URL: + form.attr( 'action', _this.api_url ); + + js_log( 'Do iframe form submit to: ' + form.attr( 'target' ) ); + js_log( ' destName:' + form.find( "[name='filename']" ).val() ); + + // Do post override + _this.form_post_override = true; + // Reset the done with action flag + _this.action_done = false; + + form.submit(); + }, + + /** + * Do an upload by submitting an API request + */ + doApiCopyUpload: function() { + js_log( 'mvBaseUploadInterface.doApiCopyUpload' ); + js_log( 'doHttpUpload (no form submit) ' ); + var httpUpConf = { + 'url' : $j( '#wpUploadFileURL' ).val(), + 'filename' : $j( '#wpDestFile' ).val(), + 'comment' : $j( '#wpUploadDescription' ).val(), + 'watch' : ( $j( '#wpWatchthis' ).is( ':checked' ) ) ? 'true' : 'false', + 'ignorewarnings': ($j('#wpIgnoreWarning' ).is( ':checked' ) ) ? 'true' : 'false' + } + //check for editToken + this.editToken = $j( "#wpEditToken" ).val(); + this.doHttpUpload( httpUpConf ); + }, + + /** + * Process the result of the form submission, returned to an iframe. + * This is the iframe's onload event. + */ + processIframeResult: function( iframe ) { + var _this = this; + var doc = iframe.contentDocument ? iframe.contentDocument : frames[iframe.id].document; + // Fix for Opera 9.26 + if ( doc.readyState && doc.readyState != 'complete' ) { + return; + } + // Fix for Opera 9.64 + if ( doc.body && doc.body.innerHTML == "false" ) { + return; + } + var response; + if ( doc.XMLDocument ) { + // The response is a document property in IE + response = doc.XMLDocument; + } else if ( doc.body ) { + // Get the json string + json = $j( doc.body ).find( 'pre' ).text(); + //js_log( 'iframe:json::' + json_str + "\nbody:" + $j( doc.body ).html() ); + if ( json ) { + response = window["eval"]( "(" + json + ")" ); + } else { + response = {}; + } + } else { + // response is a xml document + response = doc; + } + // Process the API result + _this.processApiResult( response ); + }, + + /** + * Do a generic action=upload API request and monitor its progress + */ + doHttpUpload: function( params ) { + var _this = this; + // Display the progress overlay (again) + _this.displayProgressOverlay(); + + // Set the HTTP box to "loading", in case we don't get an update for some time + $j( '#dlbox-centered' ).html( '
    ' + _this.getProgressTitle() + '
    ' + + mv_get_loading_img( 'left:40%;top:20%' ) + ); + + // Set up the request + var request = { + 'action' : 'upload', + 'asyncdownload' : true // Do async download + }; + + // Add any parameters specified by the caller + for ( key in params ) { + if ( !request[key] ) { + request[key] = params[key]; + } + } + + // Add the edit token (if available) + if( !_this.editToken && _this.api_url ) { + js_log( 'Error:doHttpUpload: missing token' ); + } else { + request['token'] =_this.editToken; + } + + // Reset the done with action flag + _this.action_done = false; + + //do the api request + do_api_req({ + 'data': request, + 'url' : _this.api_url + }, function( data ) { + _this.processApiResult( data ); + }); + }, + + /** + * Start periodic checks of the upload status using XHR + */ + doAjaxUploadStatus: function() { + var _this = this; + + //set up the progress display for status updates: + this.displayProgressOverlay(); + this.upload_status_request = { + 'action' : 'upload', + 'httpstatus' : 'true', + 'sessionkey' : _this.upload_session_key + }; + // Add token if present + if ( this.editToken ) + this.upload_status_request['token'] = this.editToken; + + // Trigger an initial request (subsequent ones will be done by a timer) + this.onAjaxUploadStatusTimer(); + }, + + /** + * This is called when the timer which separates XHR requests elapses. + * It starts a new request. + */ + onAjaxUploadStatusTimer: function() { + var _this = this; + //do the api request: + do_api_req( + { + 'data': this.upload_status_request, + 'url' : this.api_url + }, + function ( data ) { + _this.onAjaxUploadStatusResponse( data ); + } + ); + }, + + /** + * Called when a response to an upload status query is available. + * Starts the timer for the next upload status check. + */ + onAjaxUploadStatusResponse: function( data ) { + var _this = this; + //@@check if we are done + if ( data.upload['apiUploadResult'] ) { + //update status to 100% + _this.updateProgress( 1 ); + //see if we need JSON + mvJsLoader.doLoad( [ + 'JSON' + ], function() { + var apiResult = {}; + try { + apiResult = JSON.parse( data.upload['apiUploadResult'] ) ; + } catch ( e ) { + //could not parse api result + js_log( 'errro: could not parse apiUploadResult' ) + } + _this.processApiResult( apiResult ); + }); + return ; + } + + //@@ else update status: + if ( data.upload['content_length'] && data.upload['loaded'] ) { + //we have content length we can show percentage done: + var fraction = data.upload['loaded'] / data.upload['content_length']; + //update the status: + _this.updateProgress( fraction ); + //special case update the file progress where we have data size: + $j( '#up-status-container' ).html( + gM( 'mwe-upload-stats-fileprogress', + [ + mw.lang.formatSize( data.upload['loaded'] ), + mw.lang.formatSize( data.upload['content_length'] ) + ] + ) + ); + } else if( data.upload['loaded'] ) { + _this.updateProgress( 1 ); + js_log( 'just have loaded (no cotent length: ' + data.upload['loaded'] ); + //for lack of content-length requests: + $j( '#up-status-container' ).html( + gM( 'mwe-upload-stats-fileprogress', + [ + mw.lang.formatSize( data.upload['loaded'] ), + gM( 'mwe-upload-unknown-size' ) + ] + ) + ); + } + if ( _this.api_url == 'proxy' ) { + // Do the updates a bit less often: every 4.2 seconds + var timeout = 4200; + } else { + // We got a result: set timeout to 100ms + your server update + // interval (in our case 2s) + var timeout = 2100; + } + setTimeout( + function() { + _this.onAjaxUploadStatusTimer(); + }, + timeout ); + }, + + /** + * Returns true if an action=upload API result was successful, false otherwise + */ + isApiSuccess: function( apiRes ) { + if ( apiRes.error || ( apiRes.upload && apiRes.upload.result == "Failure" ) ) { + return false; + } + if ( apiRes.upload && apiRes.upload.error ) { + return false; + } + if ( apiRes.upload && apiRes.upload.warnings ) { + return false; + } + return true; + }, + + /** + * Given the result of an action=upload API request, display the error message + * to the user. + */ + showApiError: function( apiRes ) { + var _this = this; + if ( apiRes.error || ( apiRes.upload && apiRes.upload.result == "Failure" ) ) { + // Generate the error button + var buttons = {}; + buttons[ gM( 'mwe-return-to-form' ) ] = function() { + _this.form_post_override = false; + $j( this ).dialog( 'close' ); + }; + + //@@TODO should be refactored to more specialUpload page type error handling + + // Check a few places for the error code + var error_code = 0; + var errorReplaceArg = ''; + if ( apiRes.error && apiRes.error.code ) { + error_code = apiRes.error.code; + } else if ( apiRes.upload.code ) { + if ( typeof apiRes.upload.code == 'object' ) { + if ( apiRes.upload.code[0] ) { + error_code = apiRes.upload.code[0]; + } + if ( apiRes.upload.code['status'] ) { + error_code = apiRes.upload.code['status']; + if ( apiRes.upload.code['filtered'] ) + errorReplaceArg = apiRes.upload.code['filtered']; + } + } else { + apiRes.upload.code; + } + } + + var error_msg = ''; + if ( typeof apiRes.error == 'string' ) + error_msg = apiRes.error; + + // There are many possible error messages here, so we don't load all + // message text in advance, instead we use gMsgLoadRemote() for some. + // + // This code is similar to the error handling code formerly in + // SpecialUpload::processUpload() + var error_msg_key = { + '2' : 'largefileserver', + '3' : 'emptyfile', + '4' : 'minlength1', + '5' : 'illegalfilename' + }; + + //@@todo: handle these error types + var error_onlykey = { + '1': 'BEFORE_PROCESSING', + '6': 'PROTECTED_PAGE', + '7': 'OVERWRITE_EXISTING_FILE', + '8': 'FILETYPE_MISSING', + '9': 'FILETYPE_BADTYPE', + '10': 'VERIFICATION_ERROR', + '11': 'UPLOAD_VERIFICATION_ERROR', + '12': 'UPLOAD_WARNING', + '13': 'INTERNAL_ERROR', + '14': 'MIN_LENGTH_PARTNAME' + } + + if ( !error_code || error_code == 'unknown-error' ) { + if ( typeof JSON != 'undefined' ) { + js_log( 'Error: apiRes: ' + JSON.stringify( apiRes ) ); + } + if ( apiRes.upload.error == 'internal-error' ) { + // Do a remote message load + errorKey = apiRes.upload.details[0]; + gMsgLoadRemote( errorKey, function() { + _this.updateProgressWin( gM( 'mwe-uploaderror' ), gM( errorKey ), buttons ); + + }); + return false; + } + + _this.updateProgressWin( + gM('mwe-uploaderror'), + gM('mwe-unknown-error') + '
    ' + error_msg, + buttons ); + return false; + } + + if ( apiRes.error && apiRes.error.info ) { + _this.updateProgressWin( gM( 'mwe-uploaderror' ), apiRes.error.info, buttons ); + return false; + } + + if ( typeof error_code == 'number' + && typeof error_msg_key[error_code] == 'undefined' ) + { + if ( apiRes.upload.code.finalExt ) { + _this.updateProgressWin( + gM( 'mwe-uploaderror' ), + gM( 'mwe-wgfogg_warning_bad_extension', apiRes.upload.code.finalExt ), + buttons ); + } else { + _this.updateProgressWin( + gM( 'mwe-uploaderror' ), + gM( 'mwe-unknown-error' ) + ' : ' + error_code, + buttons ); + } + return false; + } + + js_log( 'get key: ' + error_msg_key[ error_code ] ) + gMsgLoadRemote( error_msg_key[ error_code ], function() { + _this.updateProgressWin( + gM( 'mwe-uploaderror' ), + gM( error_msg_key[ error_code ], errorReplaceArg ), + buttons ); + }); + js_log( "api.error" ); + return false; + } + + // Check upload.error + if ( apiRes.upload && apiRes.upload.error ) { + js_log( ' apiRes.upload.error: ' + apiRes.upload.error ); + _this.updateProgressWin( + gM( 'mwe-uploaderror' ), + gM( 'mwe-unknown-error' ) + '
    ', + buttons ); + return false; + } + + // Check for warnings: + if ( apiRes.upload && apiRes.upload.warnings ) { + var wmsg = '
      '; + for ( var wtype in apiRes.upload.warnings ) { + var winfo = apiRes.upload.warnings[wtype] + wmsg += '
    • '; + switch ( wtype ) { + case 'duplicate': + case 'exists': + if ( winfo[1] && winfo[1].title && winfo[1].title.mTextform ) { + wmsg += gM( 'mwe-file-exists-duplicate' ) + ' ' + + '' + winfo[1].title.mTextform + ''; + } else { + //misc error (weird that winfo[1] not present + wmsg += gM( 'mwe-upload-misc-error' ) + ' ' + wtype; + } + break; + case 'file-thumbnail-no': + wmsg += gM( 'mwe-file-thumbnail-no', winfo ); + break; + default: + wmsg += gM( 'mwe-upload-misc-error' ) + ' ' + wtype; + break; + } + wmsg += '
    • '; + } + wmsg += '
    '; + if ( apiRes.upload.sessionkey ) + _this.warnings_sessionkey = apiRes.upload.sessionkey; + + // Create the "ignore warning" button + var buttons = {}; + buttons[ gM( 'mwe-ignorewarning' ) ] = function() { + //check if we have a stashed key: + if ( _this.warnings_sessionkey ) { + //set to "loading" + $j( '#upProgressDialog' ).html( mv_get_loading_img() ); + //setup loading: + var req = { + 'action': 'upload', + 'sessionkey': _this.warnings_sessionkey, + 'ignorewarnings': 1, + 'filename': $j( '#wpDestFile' ).val(), + 'token' : _this.editToken + }; + //run the upload from stash request + do_api_req( + { + 'data': req, + 'url' : _this.api_url + }, + function( data ) { + _this.processApiResult( data ); + } + ); + } else { + js_log( 'No session key re-sending upload' ) + //do a stashed upload + $j( '#wpIgnoreWarning' ).attr( 'checked', true ); + $j( _this.editForm ).submit(); + } + }; + // Create the "return to form" button + buttons[ gM( 'mwe-return-to-form' ) ] = function() { + $j( this ).dialog( 'close' ); + _this.form_post_override = false; + } + // Show warning + _this.updateProgressWin( + gM( 'mwe-uploadwarning' ), + '

    ' + gM( 'mwe-uploadwarning' ) + '

    ' + wmsg + '

    ', + buttons ); + return false; + } + // No error! + return true; + }, + + /** + * Process the result of an action=upload API request. Display the result + * to the user. + */ + processApiResult: function( apiRes ) { + var _this = this; + js_log( 'processApiResult::' ); + if ( !_this.isApiSuccess( apiRes ) ) { + // Error detected, show it to the user + _this.showApiError( apiRes ); + return false; + } + if ( apiRes.upload && apiRes.upload.upload_session_key ) { + // Async upload, do AJAX status polling + _this.upload_session_key = apiRes.upload.upload_session_key; + _this.doAjaxUploadStatus(); + js_log( "set upload_session_key: " + _this.upload_session_key ); + return; + } + + if ( apiRes.upload.imageinfo && apiRes.upload.imageinfo.descriptionurl ) { + var url = apiRes.upload.imageinfo.descriptionurl; + + // Upload complete. + // Call the completion callback if available. + if ( _this.done_upload_cb && typeof _this.done_upload_cb == 'function' ) { + js_log( "call done_upload_cb" ); + // This overrides our normal completion handling so we close the + // dialog immediately. + $j( '#upProgressDialog' ).dialog( 'destroy' ).remove(); + _this.done_upload_cb( apiRes.upload ); + return false; + } + + var buttons = {}; + // "Return" button + buttons[ gM( 'mwe-return-to-form' ) ] = function() { + $j( this ).dialog( 'destroy' ).remove(); + _this.form_post_override = false; + } + // "Go to resource" button + buttons[ gM('mwe-go-to-resource') ] = function() { + window.location = url; + }; + _this.action_done = true; + _this.updateProgressWin( + gM( 'mwe-successfulupload' ), + gM( 'mwe-upload_done', url), + buttons ); + js_log( 'apiRes.upload.imageinfo::' + url ); + return true; + } + }, + + /** + * Update the progress window to display a given message, with a given + * list of buttons below it. + * @param title_txt Plain text + * @param msg HTML + * @param buttons See http://docs.jquery.com/UI/Dialog#option-buttons + */ + updateProgressWin: function( title_txt, msg, buttons ) { + var _this = this; + + if ( !title_txt ) + title_txt = _this.getProgressTitle(); + + if ( !msg ) + msg = mv_get_loading_img( 'left:40%;top:40px;' ); + + if ( !buttons ) { + // If no buttons are specified, add a close button + buttons = {}; + buttons[ gM( 'mwe-ok' ) ] = function() { + $j( this ).dialog( 'close' ); + }; + } + + $j( '#upProgressDialog' ).dialog( 'option', 'title', title_txt ); + $j( '#upProgressDialog' ).html( msg ); + $j( '#upProgressDialog' ).dialog( 'option', 'buttons', buttons ); + }, + + /** + * Get the default title of the progress window + */ + getProgressTitle: function() { + return gM( 'mwe-upload-in-progress' ); + }, + + /** + * Get the DOMNode of the form element we are rewriting. + * Returns false if it can't be found. + */ + getForm: function() { + if ( this.form_selector && $j( this.form_selector ).length != 0 ) { + return $j( this.form_selector ).get( 0 ); + } else { + js_log( "mvBaseUploadInterface.getForm(): no form_selector" ); + return false; + } + }, + + /** + * Update the progress bar to a given completion fraction (between 0 and 1) + */ + updateProgress: function( fraction ) { + //js_log('update progress: ' + fraction); + $j( '#up-progressbar' ).progressbar( 'value', parseInt( fraction * 100 ) ); + $j( '#up-pstatus' ).html( parseInt( fraction * 100 ) + '% - ' ); + }, + + /** + * Show a dialog box reporting upload progress and status + */ + displayProgressOverlay: function() { + var _this = this; + // Remove the old instance if present + if( $j( '#upProgressDialog' ).length != 0 ) { + $j( '#upProgressDialog' ).dialog( 'destroy' ).remove(); + } + // Add a new one + $j( 'body' ).append( '

    ' ); + + $j( '#upProgressDialog' ).dialog( { + title: _this.getProgressTitle(), + bgiframe: true, + modal: true, + draggable: true, + width: 400, + heigh: 200, + beforeclose: function( event, ui ) { + // If the upload is not complete, ask the user if they want to cancel + if ( event.button == 0 && _this.action_done === false ) { + _this.onCancel(); + return false; + } else { + // Complete already, allow close + return true; + } + }, + buttons: _this.getCancelButton() + } ); + $j( '#upProgressDialog' ).html( + '
    ' + + '
    ' + + '
    ' + + '0% - ' + + '' + gM( 'mwe-uploaded-status' ) + ' ' + + '
    '+ + '
    ' + ); + // Open the empty progress window + $j( '#upProgressDialog' ).dialog( 'open' ); + + // Create progress bar + $j( '#up-progressbar' ).progressbar({ + value: 0 + }); + }, + + /** + * Get a standard cancel button in the jQuery.ui dialog format + */ + getCancelButton: function() { + var _this = this; + var cancelBtn = new Array(); + cancelBtn[ gM( 'mwe-cancel' ) ] = function() { + return _this.onCancel( this ) + }; + return cancelBtn; + }, + + /** + * UI cancel button handler. + * Show a dialog box asking the user whether they want to cancel an upload. + * FIXME: doesn't work at all. + */ + onCancel: function( dlElm ) { + //confirm: + if ( confirm( gM( 'mwe-cancel-confim' ) ) ) { + //@@todo (cancel the encode / upload) + $j( this ).dialog( 'close' ); + } + } +}; + +// jQuery plugins + +( function( $ ) { + /** + * Check the upload destination filename for conflicts and show a conflict + * error message if there is one + */ + $.fn.doDestCheck = function( opt ) { + var _this = this; + js_log( 'doDestCheck::' + _this.selector ); + + // Set up option defaults + if ( !opt.warn_target ) + opt.warn_target = '#wpDestFile-warning'; + + // Add the wpDestFile-warning row + if ( $j( '#wpDestFile-warning' ).length == 0 ) { + $j( '#mw-htmlform-options tr:last' ) + .after( '' ); + } + + // Remove any existing warning + $j( opt.warn_target ).empty(); + + // Show the AJAX spinner + $j( _this.selector ) + .append( '' ); + + // Do the destination check + do_api_req( + { + 'data': { + //@@todo we may need a more clever way to get a the filename + 'titles': 'File:' + $j( _this.selector ).val(), + 'prop': 'imageinfo', + 'iiprop': 'url|mime|size', + 'iiurlwidth': 150 + } + }, + function( data ) { + // Remove spinner + $j( '#mw-spinner-wpDestFile' ).remove(); + + if ( !data || !data.query || !data.query.pages ) { + // Ignore a null result + return; + } + + if ( data.query.pages[-1] ) { + // No conflict found + return; + } + for ( var page_id in data.query.pages ) { + if ( !data.query.pages[ page_id ].imageinfo ) { + continue; + } + + // Conflict found, show warning + if ( data.query.normalized ) { + var ntitle = data.query.normalized[0].to; + } else { + var ntitle = data.query.pages[ page_id ].title + } + var img = data.query.pages[ page_id ].imageinfo[0]; + $j( '#wpDestFile-warning' ).html( + gM( 'mwe-fileexists', ntitle ) + + '
    ' + + '
    ' + + '' + + '' + + '' + + '
    ' + + '
    ' + + '' + + '" + + '' + + '
    ' + + gM( 'mwe-fileexists-thumb' ) + + '
    ' + + '
    ' + + '
    ' + ); + } + } + ); + } +})( jQuery ); diff --git a/js2/mwEmbed/libAddMedia/mvFirefogg.js b/js2/mwEmbed/libAddMedia/mvFirefogg.js new file mode 100644 index 0000000000..1add58bbeb --- /dev/null +++ b/js2/mwEmbed/libAddMedia/mvFirefogg.js @@ -0,0 +1,1080 @@ +/* Firefogg support. + * autodetects: new upload api or old http POST. + */ + +loadGM({ + "fogg-select_file" : "Select file", + "fogg-select_new_file" : "Select new file", + "fogg-select_url" : "Select URL", + "fogg-save_local_file" : "Save Ogg", + "fogg-check_for_firefogg" : "Checking for Firefogg...", + "fogg-installed" : "Firefogg is installed", + "fogg-for_improved_uploads" : "For improved uploads:", + "fogg-please_install" : "Install Firefogg<\/a>. More about Firefogg<\/a>.", + "fogg-use_latest_firefox" : "Please first install Firefox 3.5<\/a> (or later). Then revisit this page to install the Firefogg<\/b> extension.<\/i>", + "fogg-passthrough_mode" : "Your selected file is already Ogg or not a video file", + "fogg-transcoding" : "Encoding video to Ogg...", + "fogg-encoding-done" : "Encoding complete", + "fogg-badtoken" : "Token is not valid", + "fogg-preview" : "Preview video", + "fogg-hidepreview" : "Hide preview" +}); + +var firefogg_install_links = { + 'macosx': 'http://firefogg.org/macosx/Firefogg.xpi', + 'win32': 'http://firefogg.org/win32/Firefogg.xpi', + 'linux': 'http://firefogg.org/linux/Firefogg.xpi' +}; + +var default_firefogg_options = { + // Callback for upload completion + 'done_upload_cb': false, + + // The API URL to upload to + 'api_url': null, + + // True when a file is uploaded without re-encoding + 'passthrough': false, + + // True if we will be showing the encoder interface + 'encoder_interface': false, + + // True if we want to limit the library functionality to "only firefogg" + // (no upload or progress bars) + 'only_firefogg': false, + + // Callback which is called when the source name changes + 'new_source_cb': false, + + // CSS selector identifying the target control container or form (can't be left null) + 'selector': '', + + // May be "upload" to if we are rewriting an upload form, or "local" if we are encoding a local file + 'form_type': 'local', + + // CSS selector for the select file button + 'target_btn_select_file': false, + + // CSS selector for the select new file button + 'target_btn_select_new_file': false, + + // CSS selector for the save local file button + 'target_btn_save_local_file': false, + + // CSS selector for the input file name button + 'target_input_file_name': false, + + // CSS selector for the "checking for firefogg..." message div + 'target_check_for_firefogg': false, + + // CSS selector for the "firefogg is installed" message div + 'target_installed': false, + + // CSS selector for the "please install firefogg" message div + 'target_please_install': false, + + // CSS selector for the "please use Firefox 3.5" message div + 'target_use_latest_firefox': false, + + // CSS selector for the message div warning that passthrough mode is enabled + 'target_passthrough_mode': false, + + // True if firefogg should take over the form submit action + 'firefogg_form_action': true, + + // True if we should show a preview of the encoding progress + 'show_preview': true, + + //If we should enable chunk uploads ( mediaWiki api supports chunk uploads) + 'enable_chunks' : false +}; + + +var mvFirefogg = function( options ) { + return this.init( options ); +}; + +mvFirefogg.prototype = { // extends mvBaseUploadInterface + min_firefogg_version: '0.9.9.5', + default_encoder_settings: { // @@todo allow the server to set these + 'maxSize' : '400', + 'videoBitrate' : '544', + 'audioBitrate' : '96', + 'noUpscaling' : true + }, + have_firefogg: null, // lazy initialised, use getFirefogg() + current_encoder_settings: null, // lazy initialised, use getEncoderSettings() + sourceFileInfo: null, // lazy initialised, use getSourceFileInfo() + ogg_extensions: [ 'ogg', 'ogv', 'oga' ], + video_extensions: [ 'avi', 'mov', 'mp4', 'mp2', 'mpeg', 'mpeg2', 'mpeg4', 'dv', 'wmv' ], + + passthrough: false, + sourceMode: 'file', + + /** + * Object initialisation + */ + init: function( options ) { + if ( !options ) + options = {}; + + // If we have no api_url, set upload mode to "post" + if ( !options.api_url ) + options.upload_mode = 'post'; + + // Set options + for ( var i in default_firefogg_options ) { + if ( options[i] ) { + this[i] = options[i]; + } else { + this[i] = default_firefogg_options[i]; + } + } + + // Inherit from mvBaseUploadInterface (unless we're in only_firefogg mode) + if ( !this.only_firefogg ) { + var myBUI = new mvBaseUploadInterface( options ); + + // Prefix conflicting members with pe_ + for ( var i in myBUI ) { + if ( this[i] ) { + this['pe_'+ i] = myBUI[i]; + } else { + this[i] = myBUI[i]; + } + } + } + + if ( !this.selector ) { + js_log('firefogg: missing selector '); + } + }, + + /** + * Rewrite the upload form, or create our own upload controls for local transcoding. + * Called from $j.firefogg(), in mv_embed.js. + */ + doRewrite: function( callback ) { + var _this = this; + js_log( 'sel len: ' + this.selector + '::' + $j( this.selector ).length + + ' tag:' + $j( this.selector ).get( 0 ).tagName ); + if ( $j( this.selector ).length >= 0 ) { + if ( $j( this.selector ).get( 0 ).tagName.toLowerCase() == 'input' ) { + _this.form_type = 'upload'; + } + } + if ( this.form_type == 'upload' ) { + // Initialise existing upload form + this.setupForm(); + } else { + // Create our own form controls + this.createControls(); + this.bindControls(); + } + + if ( callback ) + callback(); + }, + + /** + * Create controls for local transcoding and add them to the page + */ + createControls: function() { + var _this = this; + var out = ''; + $j.each( default_firefogg_options, function( target, na ) { + if ( /^target/.test( target ) ) { + // Create the control if it doesn't already exist + if( _this[target] === false ) { + out += _this.getControlHtml(target) + ' '; + // Update the target selector + _this[target] = _this.selector + ' .' + target; + } + } + }); + $j( this.selector ).append( out ).hide(); + }, + + /** + * Get the HTML for the control with a particular name + */ + getControlHtml: function( target ) { + if ( /^target_btn_/.test( target ) ) { + // Button + var msg = gM( target.replace( /^target_btn_/, 'fogg-' ) ); + return ' '; + } else if ( /^target_input_/.test( target ) ) { + // Text input + var msg = gM( target.replace( /^target_input_/, 'fogg-' ) ); + return ' '; + } else if ( /^target_/.test( target ) ) { + // Message + var msg = gM( target.replace( '/^target_/', 'fogg-' ) ); + return '
    ' + msg + '
    '; + } else { + js_error( 'Invalid target: ' + target ); + return ''; + } + }, + + /** + * Set up events for the controls which were created with createControls() + */ + bindControls: function() { + var _this = this; + + // Hide all controls + var hide_target_list = ''; + var comma = ''; + $j.each( default_firefogg_options, function( target, na ) { + if ( /^target/.test( target ) ) { + hide_target_list += comma + _this[target]; + comma = ','; + } + }); + $j( hide_target_list ).hide(); + + // Now show the form + $j( _this.selector ).show(); + if ( _this.getFirefogg() ) { + // Firefogg enabled + // If we're in upload mode, show the input filename + if ( _this.form_type == 'upload' ) + $j( _this.target_input_file_name ).show(); + + // Show the select file button + $j( this.target_btn_select_file ) + .unbind() + .attr( 'disabled', false ) + .css( { 'display': 'inline' } ) + .click( function() { + _this.selectSourceFile(); + } ); + + // Set up the click handler for the filename box + $j( this.target_input_file_name ) + .unbind() + .attr( 'readonly', 'readonly' ) + .click( function() { + _this.selectSourceFile(); + }); + } else { + // Firefogg disabled + // FIXME: move this elsewhere. None of this is related to binding. + + // Show the "use latest Firefox" message if necessary + if ( !( $j.browser.mozilla && $j.browser.version >= '1.9.1' ) ) { + js_log( 'show use latest::' + _this.target_use_latest_firefox ); + if ( _this.target_use_latest_firefox ) { + if ( _this.form_type == 'upload' ) + $j( _this.target_use_latest_firefox ) + .prepend( gM( 'fogg-for_improved_uploads' ) ); + + $j( _this.target_use_latest_firefox ).show(); + } + return; + } + + // Otherwise show the "install Firefogg" message + var upMsg = ( _this.form_type == 'upload' ) ? gM( 'fogg-for_improved_uploads' ) : ''; + var firefoggUrl = _this.getFirefoggInstallUrl(); + if( firefoggUrl ){ + $j( _this.target_please_install ) + .html( upMsg + gM( 'fogg-please_install', firefoggUrl ) ) + .css( 'padding', '10px' ) + .show(); + } + } + + // Set up the click handler for the "save local file" button + if( _this.target_btn_save_local_file ){ + $j( _this.target_btn_save_local_file ) + .unbind() + .click( function() { + _this.doLocalEncodeAndSave(); + } ); + } + }, + + /* + * Get the URL for installing firefogg on the client OS + */ + getFirefoggInstallUrl: function() { + var os_link = false; + if ( navigator.oscpu ) { + if ( navigator.oscpu.search( 'Linux' ) >= 0 ) + os_link = firefogg_install_links['linux']; + else if ( navigator.oscpu.search( 'Mac' ) >= 0 ) + os_link = firefogg_install_links['macosx']; + else if (navigator.oscpu.search( 'Win' ) >= 0 ) + os_link = firefogg_install_links['win32']; + } + return os_link; + }, + + /** + * Get the Firefogg instance (or false if firefogg is unavailable) + */ + getFirefogg: function() { + if ( this.have_firefogg == null ) { + if ( typeof( Firefogg ) != 'undefined' + && Firefogg().version >= this.min_firefogg_version ) + { + this.have_firefogg = true; + this.fogg = new Firefogg(); + } else { + this.have_firefogg = false; + this.fogg = false; + } + } + return this.fogg; + }, + + /** + * Set up the upload form + */ + setupForm: function() { + js_log( 'firefogg::setupForm::' ); + + // Set up the parent if we are in upload mode + if ( this.form_type == 'upload' ) { + this.pe_setupForm(); + } + + // If Firefogg is not available, just show a "please install" message + if ( !this.getFirefogg() ) { + if ( !this.target_please_install ) { + $j( this.selector ).after( this.getControlHtml( 'target_please_install' ) ); + this.target_please_install = this.selector + ' ~ .target_please_install'; + } + if ( !this.target_use_latest_firefox ) { + $j( this.selector ).after( this.getControlHtml( 'target_use_latest_firefox' ) ); + this.target_use_latest_firefox = this.selector + ' ~ .target_use_latest_firefox'; + } + // Show download link + this.bindControls(); + return; + } + + // Change the file browser to type text. We can't simply change the attribute so + // we have to delete and recreate. + var inputTag = ''; + + js_log( 'set input: ' + inputTag ); + $j( this.selector ).replaceWith( inputTag ); + + this.target_input_file_name = 'input[name=' + $j( this.selector ).attr( 'name' ) + ']'; + + // Point the selector at the span we just created + this.selector = '#' + id; + + // Create controls for local transcoding + this.createControls(); + this.bindControls(); + }, + + /** + * Display an upload progress overlay. Overrides the function in mvBaseUploadInterface. + */ + displayProgressOverlay: function() { + this.pe_displayProgressOverlay(); + // If we are uploading video (not in passthrough mode), show preview button + if( this.getFirefogg() + && !this.isCopyUpload() + && !this.getEncoderSettings()['passthrough'] ) + { + this.createPreviewControls(); + } + }, + + /** + * Create controls for showing a transcode/crop/resize preview + */ + createPreviewControls: function() { + var _this = this; + + // Set the initial button html: + var buttonHtml = ''; + if( _this.show_preview == true ){ + buttonHtml = $j.btnHtml( gM( 'fogg-hidepreview' ), 'fogg_preview', 'triangle-1-s' ); + } else { + buttonHtml = $j.btnHtml( gM( 'fogg-preview' ), 'fogg_preview', 'triangle-1-e' ); + } + + // Add the preview button and canvas + $j( '#upProgressDialog' ).append( + '
    ' + + buttonHtml + + '
    ' + + '' + + '
    ' + ); + + // Set the initial state + if ( _this.show_preview == true ) { + $j( '#fogg_preview_canvas' ).show(); + } + + // Bind the preview button + $j( '#upProgressDialog .fogg_preview' ).btnBind().click( function() { + return _this.onPreviewClick( this ); + }); + }, + + /** + * onclick handler for the hide/show preview button + */ + onPreviewClick: function( sourceNode ) { + var button = $j( sourceNode ); + var icon = button.children( '.ui-icon' ); + js_log( "click .fogg_preview" + icon.attr( 'class' ) ); + + if ( icon.hasClass( 'ui-icon-triangle-1-e' ) ) { + // Show preview + // Toggle button class and set button text to "hide". + this.show_preview = true; + icon.removeClass( 'ui-icon-triangle-1-e' ).addClass( 'ui-icon-triangle-1-s' ); + button.children( '.btnText' ).text( gM( 'fogg-hidepreview' ) ); + $j( '#fogg_preview_canvas' ).show( 'fast' ); + } else { + // Hide preview + // Toggle button class and set button text to "show". + this.show_preview = false; + icon.removeClass( 'ui-icon-triangle-1-s' ).addClass( 'ui-icon-triangle-1-e' ); + button.children( '.btnText' ).text( gM( 'fogg-preview' ) ); + $j( '#fogg_preview_canvas' ).hide( 'slow' ); + } + // Don't follow the # link + return false; + }, + + /** + * Render the preview frame (asynchronously) + */ + renderPreview: function() { + var _this = this; + // Set up the hidden video to pull frames from + if( $j( '#fogg_preview_vid' ).length == 0 ) + $j( 'body' ).append( '' ); + var v = $j( '#fogg_preview_vid' ).get( 0 ); + + function seekToEnd() { + var v = $j( '#fogg_preview_vid' ).get( 0 ); + // TODO: document arbitrary 0.4s constant + v.currentTime = v.duration - 0.4; + } + function renderFrame() { + var v = $j( '#fogg_preview_vid' ).get( 0 ); + var canvas = $j( '#fogg_preview_canvas' ).get( 0 ); + if ( canvas ) { + canvas.width = 160; + canvas.height = canvas.width * v.videoHeight / v.videoWidth; + var ctx = canvas.getContext( "2d" ); + ctx.drawImage( v, 0, 0, canvas.width, canvas.height ); + } + } + function preview() { + // Initialize the video if it is not set up already + var v = $j( '#fogg_preview_vid' ).get( 0 ); + if ( v.src != _this.fogg.previewUrl ) { + js_log( 'init preview with url:' + _this.fogg.previewUrl ); + v.src = _this.fogg.previewUrl; + + // Once it's loaded, seek to the end + v.removeEventListener( "loadedmetadata", seekToEnd, true ); + v.addEventListener( "loadedmetadata", seekToEnd, true ); + + // When the seek is done, render a frame + v.removeEventListener( "seeked", renderFrame, true ); + v.addEventListener( "seeked", renderFrame, true ); + + // Refresh the video duration and metadata + var previewTimer = setInterval( function() { + if ( _this.fogg.status() != "encoding" ) { + clearInterval( previewTimer ); + _this.show_preview == false; + } + if ( _this.show_preview == true ) { + v.load(); + } + }, 1000 ); + } + } + preview(); + }, + + /** + * Get the DOMNode of the form element we are rewriting. + * Returns false if it can't be found. + * Overrides mvBaseUploadInterface.getForm(). + */ + getForm: function() { + if ( this.form_selector ) { + return this.pe_getForm(); + } else { + // No configured form selector + // Use the first form descendant of the current container + return $j( this.selector ).parents( 'form:first' ).get( 0 ); + } + }, + + /** + * Show a dialog box allowing the user to select the source file of the + * encode/upload operation. The filename is stored by Firefogg until the + * next encode/upload call. + * + * After a successful select, the UI is updated accordingly. + */ + selectSourceFile: function() { + var _this = this; + if( !_this.fogg.selectVideo() ) { + // User clicked "cancel" + return; + } + _this.clearSourceInfoCache(); + _this.updateSourceFileUI(); + }, + + /** + * Update the UI due to the source file changing + */ + updateSourceFileUI: function() { + js_log( 'videoSelectReady' ); + var _this = this; + if ( !_this.fogg.sourceInfo || !_this.fogg.sourceFilename ) { + // Something wrong with the source file? + js_log( 'selectSourceFile: sourceInfo/sourceFilename missing' ); + return; + } + + // Hide the "select file" button and show "select new" + $j( _this.target_btn_select_file ).hide(); + $j( _this.target_btn_select_new_file) + .show() + .unbind() + .click( function() { + _this.fogg = new Firefogg(); + _this.selectSourceFile(); + } ); + + var settings = this.getEncoderSettings(); + + // If we're in passthrough mode, update the interface (if not a form) + if ( settings['passthrough'] == true && _this.form_type == 'local' ) { + $j( _this.target_passthrough_mode ).show(); + } else { + $j( _this.target_passthrough_mode ).hide(); + // Show the "save file" button if this is a local form + if ( _this.form_type == 'local' ) { + $j( _this.target_btn_save_local_file ).show(); + } // else the upload will be done on form submit + } + + // Update the input file name box and show it + js_log( " should update: " + _this.target_input_file_name + + ' to: ' + _this.fogg.sourceFilename ); + $j( _this.target_input_file_name ) + .val( _this.fogg.sourceFilename ) + .show(); + + + // Notify callback new_source_cb + if ( _this.new_source_cb ) { + if ( settings['passthrough'] ) { + var fName = _this.fogg.sourceFilename; + } else { + var oggExt = _this.isSourceAudio() ? 'oga' : 'ogg'; + oggExt = _this.isSourceVideo() ? 'ogv' : oggExt; + oggExt = _this.isUnknown() ? 'ogg' : oggExt; + oggName = _this.fogg.sourceFilename.substr( 0, + _this.fogg.sourceFilename.lastIndexOf( '.' ) ); + var fName = oggName + '.' + oggExt; + } + _this.new_source_cb( _this.fogg.sourceFilename, fName ); + } + }, + + /** + * Get the source file info for the current file selected into this.fogg + */ + getSourceFileInfo: function() { + if ( this.sourceFileInfo == null ) { + if ( !this.fogg.sourceInfo ) { + js_error( 'No firefogg source info is available' ); + return false; + } + try { + this.sourceFileInfo = JSON.parse( this.fogg.sourceInfo ); + } catch ( e ) { + js_error( 'error could not parse fogg sourceInfo' ); + return false; + } + } + return this.sourceFileInfo; + }, + + /** + * Clear the cache of the source file info, presumably due to a new file + * being selected into this.fogg + */ + clearSourceInfoCache: function() { + this.sourceFileInfo = null; + this.current_encoder_settings = null; + }, + + /** + * Save the result of the transcode as a local file + */ + doLocalEncodeAndSave: function() { + var _this = this; + if ( !this.fogg ) { + js_error( 'doLocalEncodeAndSave: no Firefogg object!' ); + return false; + } + + // Set up the target location + // Firefogg shows the "save as" dialog box, and sets the path chosen as + // the destination for a later encode() call. + if ( !this.fogg.saveVideoAs() ) { + // User clicked "cancel" + return false; + } + + // We have a source file, now do the encode + this.doEncode( + function /* onProgress */ ( progress ) { + _this.updateProgress( progress ); + }, + function /* onDone */ () { + js_log( "done with encoding (no upload) " ); + // Set status to 100% for one second + // FIXME: this is either a hack or a waste of time, not sure which + _this.updateProgress( 1 ); + setTimeout( function() { + _this.onLocalEncodeDone(); + }); + } + ); + }, + + /** + * This is called when a local encode operation has completed. It updates the UI. + */ + onLocalEncodeDone: function() { + var _this = this; + _this.updateProgressWin( gM( 'fogg-encoding-done' ), + gM( 'fogg-encoding-done' ) + '
    ' + + //show the video at full resolution upto 720px wide + '' + ); + //load the video and set a callback: + var v = $j( '#fogg_final_vid' ).get( 0 ); + function resizeVid() { + var v = $j( '#fogg_final_vid' ).get(0); + if ( v.videoWidth > 720 ) { + var vW = 720; + var vH = 720 * v.videoHeight / v.videoWidth; + } else { + var vW = v.videoWidth; + var vH = v.videoHeight; + } + //reize the video: + $j( v ).css({ + 'width': vW, + 'height': vH + }); + //if large video resize the dialog box: + if( vW + 5 > 400 ) { + //also resize the dialog box + $j( '#upProgressDialog' ).dialog( 'option', 'width', vW + 20 ); + $j( '#upProgressDialog' ).dialog( 'option', 'height', vH + 120 ); + + //also position the dialog container + $j( '#upProgressDialog') .dialog( 'option', 'position', 'center' ); + } + } + v.removeEventListener( "loadedmetadata", resizeVid, true ); + v.addEventListener( "loadedmetadata", resizeVid, true ); + v.load(); + }, + + /** + * Get the appropriate encoder settings for the current Firefogg object, + * into which a video has already been selected. + */ + getEncoderSettings: function() { + if ( this.current_encoder_settings == null ) { + // Clone the default settings + var defaults = function () { }; + defaults.prototype = this.default_encoder_settings; + var settings = new defaults(); + + // Grab the extension + var sf = this.fogg.sourceFilename; + if ( !sf ) { + js_error( 'getEncoderSettings(): No Firefogg source filename is available!' ); + return false; + } + var ext = ''; + if ( sf.lastIndexOf('.') != -1 ) + ext = sf.substring( sf.lastIndexOf( '.' ) + 1 ).toLowerCase(); + + // Determine passthrough mode + if ( this.isOggFormat() ) { + // Already Ogg, no need to encode + settings['passthrough'] = true; + } else if ( this.isSourceAudio() || this.isSourceVideo() ) { + // OK to encode + settings['passthrough'] = false; + } else { + // Not audio or video, can't encode + settings['passthrough'] = true; + } + + js_log( 'base setupAutoEncoder::' + this.getSourceFileInfo().contentType + + ' passthrough:' + settings['passthrough'] ); + this.current_encoder_settings = settings; + } + return this.current_encoder_settings; + }, + + isUnknown: function() { + return ( this.getSourceFileInfo().contentType.indexOf("unknown") != -1 ); + }, + + isSourceAudio: function() { + return ( this.getSourceFileInfo().contentType.indexOf("audio/") != -1 ); + }, + + isSourceVideo: function() { + return ( this.getSourceFileInfo().contentType.indexOf("video/") != -1 ); + }, + + isOggFormat: function() { + var contentType = this.getSourceFileInfo().contentType; + return ( contentType.indexOf("video/ogg") != -1 + || contentType.indexOf("application/ogg") != -1 ); + }, + + /** + * Get the default title of the progress window + */ + getProgressTitle: function() { + js_log( "fogg:getProgressTitle f:" + ( this.getFirefogg() ? 'on' : 'off' ) + + ' mode:' + this.form_type ); + // Return the parent's title if we don't have Firefogg turned on + if ( !this.getFirefogg() || !this.firefogg_form_action ) { + return this.pe_getProgressTitle(); + } else if ( this.form_type == 'local' ) { + return gM( 'fogg-transcoding' ); + } else { + return gM( 'mwe-upload-transcode-in-progress' ); + } + }, + + /** + * Do an upload, with the mode given by this.upload_mode + */ + doUpload: function() { + var _this = this; + js_log( "firefogg: doUpload:: " + + ( this.getFirefogg() ? 'on' : 'off' ) + + ' up mode:' + _this.upload_mode ); + + // If Firefogg is disabled or doing an copyByUrl upload, just invoke the parent method + if( !this.getFirefogg() || this.isCopyUpload() ) { + _this.pe_doUpload(); + return; + } + // We can do a chunk upload + if( _this.upload_mode == 'post' && _this.enable_chunks ){ + _this.doChunkUpload(); + } else if ( _this.upload_mode == 'post' ) { + // Encode and then do a post upload + _this.doEncode( + function /* onProgress */ ( progress ) { + _this.updateProgress( progress ); + }, + function /* onDone */ () { + js_log( 'done with encoding do POST upload:' + _this.form.action ); + // ignore warnings & set source type + //_this.formData[ 'wpIgnoreWarning' ]='true'; + _this.formData['wpSourceType'] = 'upload'; + _this.formData['action'] = 'submit'; + + // wpUploadFile is set by firefogg + delete _this.formData['file']; + + _this.fogg.post( _this.editForm.action, 'wpUploadFile', + JSON.stringify( _this.formData ) ); + _this.doUploadStatus(); + } + ); + } else { + js_error( 'Error: unrecongized upload mode: ' + _this.upload_mode ); + } + }, + + /** + * Do both uploading and encoding at the same time. Uploads 1MB chunks as + * they become ready. + */ + doChunkUpload : function() { + js_log( 'firefogg::doChunkUpload' ); + var _this = this; + _this.action_done = false; + + if ( !_this.getEncoderSettings()['passthrough'] ) { + // We are transcoding to Ogg. Fix the destination extension, it + // must be ogg/ogv/oga. + var fileName = _this.formData['filename']; + var ext = ''; + var dotPos = fileName.lastIndexOf( '.' ); + if ( dotPos != -1 ) { + ext = fileName.substring( dotPos ).toLowerCase(); + } + if ( $j.inArray( ext.substr( 1 ), _this.ogg_extensions ) == -1 ) { + var extreg = new RegExp( ext + '$', 'i' ); + _this.formData['filename'] = fileName.replace( extreg, '.ogg' ); + } + } + + // Get the edit token from formData if it's not set already + if ( !_this.editToken && _this.formData['token'] ) { + _this.editToken = _this.formData['token']; + } + + if( _this.editToken ) { + js_log( 'we already have an edit token: ' + _this.editToken ); + _this.doChunkUploadWithFormData(); + return; + } + + // No edit token. Fetch it asynchronously and then do the upload. + get_mw_token( + 'File:'+ _this.formData['filename'], + _this.api_url, + function( editToken ) { + if( !editToken || editToken == '+\\' ) { + _this.updateProgressWin( gM( 'fogg-badtoken' ), gM( 'fogg-badtoken' ) ); + return false; + } + _this.editToken = editToken; + _this.doChunkUploadWithFormData(); + } + ); + }, + + /** + * Internal function called from doChunkUpload() when the edit token is available + */ + doChunkUploadWithFormData: function() { + var _this = this; + js_log( "firefogg::doChunkUploadWithFormData" + _this.editToken ); + // Build the API URL + var aReq = { + 'action': 'upload', + 'format': 'json', + 'filename': _this.formData['filename'], + 'comment': _this.formData['comment'], + 'enablechunks': 'true' + }; + + if ( _this.editToken ) + aReq['token'] = this.editToken; + + if ( _this.formData['watch'] ) + aReq['watch'] = _this.formData['watch']; + + if ( _this.formData['ignorewarnings'] ) + aReq['ignorewarnings'] = _this.formData['ignorewarnings']; + + var encoderSettings = this.getEncoderSettings(); + js_log( 'do fogg upload/encode call: ' + _this.api_url + ' :: ' + JSON.stringify( aReq ) ); + js_log( 'foggEncode: ' + JSON.stringify( encoderSettings ) ); + _this.fogg.upload( JSON.stringify( encoderSettings ), _this.api_url, + JSON.stringify( aReq ) ); + + // Start polling the upload status + _this.doUploadStatus(); + }, + + /** + * Encode the video and monitor progress. + * + * Calls progressCallback() regularly with a number between 0 and 1 indicating progress. + * Calls doneCallback() when the encode is finished. + * + * Asynchronous, returns immediately. + */ + doEncode : function( progressCallback, doneCallback ) { + var _this = this; + _this.action_done = false; + _this.displayProgressOverlay(); + var encoderSettings = this.getEncoderSettings(); + js_log( 'doEncode: with: ' + JSON.stringify( encoderSettings ) ); + _this.fogg.encode( JSON.stringify( encoderSettings ) ); + + //show transcode status: + $j( '#up-status-state' ).html( gM( 'mwe-upload-transcoded-status' ) ); + + //setup a local function for timed callback: + var encodingStatus = function() { + var status = _this.fogg.status(); + + if ( _this.show_preview == true && _this.fogg.state == 'encoding' ) { + _this.renderPreview(); + } + + // Update progress + progressCallback( _this.fogg.progress() ); + + //loop to get new status if still encoding + if ( _this.fogg.state == 'encoding' ) { + setTimeout( encodingStatus, 500 ); + } else if ( _this.fogg.state == 'encoding done' ) { + _this.action_done = true; + progressCallback( 1 ); + doneCallback(); + } else if ( _this.fogg.state == 'encoding fail' ) { + //@@todo error handling: + js_error( 'encoding failed' ); + } + } + encodingStatus(); + }, + + /** + * Poll the upload progress and update the UI regularly until the upload is complete. + * + * Asynchronous, returns immediately. + */ + doUploadStatus: function() { + var _this = this; + $j( '#up-status-state' ).html( gM( 'mwe-uploaded-status' ) ); + + _this.oldResponseText = ''; + + // Create a local function for timed callback + var uploadStatus = function() { + var response_text = _this.fogg.responseText; + if ( !response_text ) { + try { + var pstatus = JSON.parse( _this.fogg.uploadstatus() ); + response_text = pstatus["responseText"]; + } catch( e ) { + js_log( "could not parse uploadstatus / could not get responseText" ); + } + } + + if ( _this.oldResponseText != response_text ) { + js_log( 'new result text:' + response_text + ' state:' + _this.fogg.state ); + _this.oldResponseText = response_text; + // Parse the response text and check for errors + try { + var apiResult = JSON.parse( response_text ); + } catch( e ) { + js_log( "could not parse response_text::" + response_text + + ' ...for now try with eval...' ); + try { + var apiResult = eval( response_text ); + } catch( e ) { + var apiResult = null; + } + } + if ( apiResult && !_this.isApiSuccess( apiResult ) ) { + // Show the error and stop the upload + _this.showApiError( apiResult ); + _this.action_done = true; + _this.fogg.cancel(); + return false; + } + } + if ( _this.show_preview == true ) { + if ( _this.fogg.state == 'encoding' ) { + _this.renderPreview(); + } + } + + // Update the progress bar + _this.updateProgress( _this.fogg.progress() ); + + // If we're still uploading or encoding, continue to poll the status + if ( _this.fogg.state == 'encoding' || _this.fogg.state == 'uploading' ) { + setTimeout( uploadStatus, 100 ); + return; + } + + // Upload done? + if ( -1 == $j.inArray( _this.fogg.state, [ 'upload done', 'done', 'encoding done' ] ) ) { + js_log( 'Error:firefogg upload error: ' + _this.fogg.state ); + return; + } + if ( apiResult && apiResult.resultUrl ) { + var buttons = {}; + buttons[ gM( 'mwe-go-to-resource' ) ] = function() { + window.location = apiResult.resultUrl; + } + var go_to_url_txt = gM( 'mwe-go-to-resource' ); + var showMessage = true; + if ( typeof _this.done_upload_cb == 'function' ) { + // Call the callback + // It will return false if it doesn't want us to show our own "done" message + showMessage = _this.done_upload_cb( _this.formData ); + } + if ( showMessage ) { + _this.updateProgressWin( gM( 'mwe-successfulupload' ), + gM( 'mwe-upload_done', apiResult.resultUrl ), buttons ); + } else { + this.action_done = true; + $j( '#upProgressDialog' ).empty().dialog( 'close' ); + } + } else { + // Done state with error? Not really possible given how firefogg works... + js_log( " Upload done in chunks mode, but no resultUrl!" ); + } + + } + uploadStatus(); + }, + + /** + * This is the cancel button handler, referenced by getCancelButton() in the parent. + */ + onCancel: function( dlElm ) { + if ( !this.have_firefogg ) { + return this.pe_cancel_action(); + } + js_log( 'firefogg:cancel' ) + if ( confirm( gM( 'mwe-cancel-confim' ) ) ) { + // FIXME: sillyness ( upstream firefogg cancel fix needed ) + if ( navigator.oscpu && navigator.oscpu.search( 'Win' ) >= 0 ) { + alert( 'sorry we do not yet support cancel on windows' ); + } else { + this.action_done = true; + this.fogg.cancel(); + $j( dlElm ).empty().dialog( 'close' ); + } + } + // Don't follow the # link: + return false; + } +}; diff --git a/js2/mwEmbed/libAddMedia/remoteSearchDriver.js b/js2/mwEmbed/libAddMedia/remoteSearchDriver.js new file mode 100644 index 0000000000..c0d4cc759d --- /dev/null +++ b/js2/mwEmbed/libAddMedia/remoteSearchDriver.js @@ -0,0 +1,2196 @@ +/* + * remoteSearchDriver + * Provides a base interface for the Add-Media-Wizard + * supporting remote searching of http archives for free images/audio/video assets + */ + +loadGM( { + "mwe-add_media_wizard" : "Add media wizard", + "mwe-media_search" : "Media search", + "rsd_box_layout" : "Box layout", + "rsd_list_layout" : "List layout", + "rsd_results_desc" : "Results $1 to $2", + "rsd_results_desc_total" : "Results $1 to $2 of $3", + "rsd_results_next" : "next", + "rsd_results_prev" : "previous", + "rsd_no_results" : "No search results for $1<\/b>", + "mwe-upload_tab" : "Upload", + "rsd_layout" : "Layout:", + "rsd_resource_edit" : "Edit resource: $1", + "mwe-resource_description_page" : "Resource description page", + "mwe-link" : "link", + "rsd_local_resource_title" : "Local resource title", + "rsd_do_insert" : "Do insert", + "mwe-cc_title" : "Creative Commons", + "mwe-cc_by_title" : "Attribution", + "mwe-cc_nc_title" : "Noncommercial", + "mwe-cc_nd_title" : "No Derivative Works", + "mwe-cc_sa_title" : "Share Alike", + "mwe-cc_pd_title" : "Public Domain", + "mwe-unknown_license" : "Unknown license", + "mwe-no_import_by_url" : "This user or wiki cannot<\/b> import assets from remote URLs.

    Do you need to login?<\/p>

    Is upload_by_url permission set for you?
    Does the wiki have
    $wgAllowCopyUploads<\/a> enabled?<\/p>", + "mwe-results_from" : "Results from $2<\/a>", + "mwe-missing_desc_see_source" : "This asset is missing a description. Please see the [$1 original source] and help describe it.", + "rsd_config_error" : "Add media wizard configuration error: $1", + "mwe-your_recent_uploads" : "Your recent uploads to $1", + "mwe-upload_a_file" : "Upload a new file to $1", + "mwe-resource_page_desc" : "Resource page description:", + "mwe-edit_resource_desc" : "Edit wiki text resource description:", + "mwe-local_resource_title" : "Local resource title:", + "mwe-watch_this_page" : "Watch this page", + "mwe-do_import_resource" : "Import resource", + "mwe-update_preview" : "Update resource page preview", + "mwe-cancel_import" : "Cancel import", + "mwe-importing_asset" : "Importing asset", + "mwe-preview_insert_resource" : "Preview insert of resource: $1", + "mwe-checking-resource" : "Checking for resource", + "mwe-resource-needs-import" : "Resource $1 needs to be imported to $2", + "mwe-ftype-svg" : "SVG vector file", + "mwe-ftype-jpg" : "JPEG image file", + "mwe-ftype-png" : "PNG image file", + "mwe-ftype-oga" : "Ogg audio file", + "mwe-ftype-ogg" : "Ogg video file", + "mwe-ftype-unk" : "Unknown file format", + + "rsd-wiki_commons-title": "Wikimedia Commons", + "rsd-wiki_commons": "Wikimedia Commons, an archive of freely-licensed educational media content (images, sound and video clips)", + + "rsd-this_wiki-title" : "This wiki", + "rsd-this_wiki-desc" : "The local wiki install", + + "rsd-archive_org-title": "Archive.org", + "rsd-archive_org-desc" : "The Internet Archive, a digital library of cultural artifacts", + + "rsd-flickr-title" : "Flickr.com", + "rsd-flickr-desc" : "Flickr.com, a online photo sharing site", + "rsd-metavid-title" : "Metavid.org", + "rsd-metavid-desc" : "Metavid.org, a community archive of US House and Senate floor proceedings" + +} ); + +var default_remote_search_options = { + 'profile': 'mediawiki_edit', + 'target_container': null, // the div that will hold the search interface + + 'target_invoke_button': null, // the button or link that will invoke the search interface + + 'default_provider_id': 'all', // all or one of the content_providers ids + + 'local_wiki_api_url': null, + + // Can be 'api', 'autodetect', 'remote_link' + 'import_url_mode': 'api', + + 'target_title': null, + + // Edit tools (can be an array of tools or keyword 'all') + 'enabled_tools': 'all', + + + 'target_textbox': null, + 'target_render_area': null, // where output render should go: + 'instance_name': null, // a globally accessible callback instance name + 'default_query': null, // default search query + + // Specific to sequence profile + 'p_seq': null, + 'cFileNS': 'File', // What is the canonical namespace prefix for images + // @@todo (should get that from the api or in-page vars) + + 'upload_api_target': 'local', // can be local or the url or remote + 'upload_api_name': null, + 'upload_api_proxy_frame': null, // a page that will request mw.proxy.server + + 'enabled_providers': 'all', // can be keyword 'all' or an array of enabled content provider keys + + 'currentProvider': null // sets the default display item: +} + +if ( typeof wgServer == 'undefined' ) + wgServer = ''; +if ( typeof wgScriptPath == 'undefined' ) + wgScriptPath = ''; +if ( typeof stylepath == 'undefined' ) + stylepath = ''; + +/* + * Base remoteSearch Driver interface + */ +var remoteSearchDriver = function( iObj ) { + return this.init( iObj ); +} + +remoteSearchDriver.prototype = { + results_cleared: false, + + caretPos: null, // lazy initialised + textboxValue: null, // lazy initialised + + // here we define the set of possible media content providers: + // FIXME: unused + main_search_options: { + 'selprovider': { + 'title': 'Select Providers' + }, + 'advanced_search': { + 'title': 'Advanced Options' + } + }, + + /** the default content providers list. + * + * (should be note that special tabs like "upload" and "combined" don't go into the content providers list: + * @note do not use double underscore in content providers names (used for id lookup) + * + * @@todo we will want to load more per user-preference and per category lookup + */ + content_providers: { + /*content_providers documentation: + * @@todo we should move the bulk of the configuration to each file + * + + @enabled: whether the search provider can be selected + @checked: whether the search provider will show up as selectable tab + @default: default: if the current cp should be displayed (only one should be the default) + @title: the title of the search provider + @desc: can use html + @api_url: the url to query against given the library type: + @lib: the search library to use corresponding to the + search object ie: 'mediaWiki' = new mediaWikiSearchSearch() + @tab_img: the tab image (if set to false use title text) + if === "true" use standard location skin/images/{cp_id}_tab.png + if === string use as url for image + + @linkback_icon default is: /wiki/skins/common/images/magnify-clip.png + + //domain insert: two modes: simple config or domain list: + @local : if the content provider assets need to be imported or not. + @local_domains : sets of domains for which the content is local + //@@todo should query wgForeignFileRepos setting maybe interwikimap from the api + */ + + 'this_wiki': { + 'enabled': 1, + 'checked': 1, + 'api_url': ( wgServer && wgScriptPath ) ? + wgServer + wgScriptPath + '/api.php' : null, + 'lib': 'mediaWiki', + 'local': true, + 'tab_img': false + }, + 'wiki_commons': { + 'enabled': 1, + 'checked': 1, + 'homepage': 'http://commons.wikimedia.org/wiki/Main_Page', + 'api_url': 'http://commons.wikimedia.org/w/api.php', + 'lib': 'mediaWiki', + 'resource_prefix': 'WC_', // prefix on imported resources (not applicable if the repository is local) + + // if we should check for shared repository asset ( generally only applicable to commons ) + 'check_shared': true, + + // list all the domains where commons is local? + // probably should set this some other way by doing an api query + // or by seeding this config when calling the remote search? + 'local_domains': [ 'wikimedia', 'wikipedia', 'wikibooks' ], + // specific to wiki commons config: + 'search_title': false, // disable title search + 'tab_img': true + }, + 'archive_org': { + 'enabled': 1, + 'checked': 1, + 'homepage': 'http://www.archive.org/about/about.php', + + 'api_url': 'http://homeserver7.us.archive.org:8983/solr/select', + 'lib': 'archiveOrg', + 'local': false, + 'resource_prefix': 'AO_', + 'tab_img': true + }, + 'flickr': { + 'enabled': 1, + 'checked': 1, + 'homepage': 'http://www.flickr.com/about/', + + 'api_url': 'http://www.flickr.com/services/rest/', + 'lib': 'flickr', + 'local': false, + // Just prefix with Flickr_ for now. + 'resource_prefix': 'Flickr_', + 'tab_img': true + }, + 'metavid': { + 'enabled': 1, + 'checked': 1, + 'homepage': 'http://metavid.org/wiki/Metavid_Overview', + 'api_url': 'http://metavid.org/w/index.php?title=Special:MvExportSearch', + 'lib': 'metavid', + 'local': false, // if local set to true we can use local + 'resource_prefix': 'MV_', // what prefix to use on imported resources + + 'local_domains': ['metavid'], // if the domain name contains metavid + // no need to import metavid content to metavid sites + + 'stream_import_key': 'mv_ogg_low_quality', // which stream to import, could be mv_ogg_high_quality + // or flash stream, see ROE xml for keys + + 'remote_embed_ext': false, // if running the remoteEmbed extension no need to copy local + // syntax will be [remoteEmbed:roe_url link title] + 'tab_img': true + }, + // special cp "upload" + 'upload': { + 'enabled': 1, + 'checked': 1, + 'title': 'Upload' + } + }, + + // define the licenses + // ... this will get complicated quick... + // (just look at complexity for creative commons without excessive "duplicate data") + // ie cc_by could be "by/3.0/us/" or "by/2.1/jp/" to infinitum... + // some complexity should be negated by license equivalences. + + // but we will have to abstract into another class let content providers provide license urls + // and we have to clone the license object and allow local overrides + + licenses: { + // for now only support creative commons type licenses + // used page: http://creativecommons.org/licenses/ + 'cc': { + 'base_img_url':'http://upload.wikimedia.org/wikipedia/commons/thumb/', + 'base_license_url': 'http://creativecommons.org/licenses/', + 'licenses': [ + 'by', + 'by-sa', + 'by-nc-nd', + 'by-nc', + 'by-nd', + 'by-nc-sa', + 'by-sa', + 'pd' + ], + 'license_images': { + 'by': { + 'image_url': '1/11/Cc-by_new_white.svg/20px-Cc-by_new_white.svg.png' + }, + 'nc': { + 'image_url': '2/2f/Cc-nc_white.svg/20px-Cc-nc_white.svg.png' + }, + 'nd': { + 'image_url': 'b/b3/Cc-nd_white.svg/20px-Cc-nd_white.svg.png' + }, + 'sa': { + 'image_url': 'd/df/Cc-sa_white.svg/20px-Cc-sa_white.svg.png' + }, + 'pd': { + 'image_url': '5/51/Cc-pd-new_white.svg/20px-Cc-pd-new_white.svg.png' + } + } + } + }, + + // some default layout values: + thumb_width: 80, + image_edit_width: 400, + video_edit_width: 400, + insert_text_pos: 0, // insert at the start (will be overwritten by the user cursor pos) + displayMode : 'box', // box or list + + cUpLoader: null, + clipEdit: null, + proxySetupDone: null, + dmodalCss: {}, + + init: function( options ) { + var _this = this; + js_log( 'remoteSearchDriver:init' ); + // Add in a local "id" reference to each provider + for ( var cp_id in this.content_providers ) { + this.content_providers[ cp_id ].id = cp_id; + } + + // Merge in the options + // @@todo for cleaner config we should set _this.opt to the provided options + $j.extend( _this, default_remote_search_options, options ); + + // Quick fix for cases where people put ['all'] instead of 'all' for enabled_providers + if ( _this.enabled_providers.length == 1 && _this.enabled_providers[0] == 'all' ) + _this.enabled_providers = 'all'; + + // Set up content_providers + for ( var provider in this.content_providers ) { + if ( _this.enabled_providers == 'all' && !this.currentProvider ) { + this.currentProvider = provider; + break; + } else { + if ( $j.inArray( provider, _this.enabled_providers ) != -1 ) { + // This provider is enabled + this.content_providers[provider].enabled = true; + // Set the current provider to the first enabled one + if ( !this.currentProvider ) { + this.currentProvider = provider; + } + } else { + // This provider is disabled + if ( _this.enabled_providers != 'all' ) { + this.content_providers[provider].enabled = false; + } + } + } + } + + // Set the upload target name if unset + if ( _this.upload_api_target == 'local' + && ! _this.upload_api_name + && typeof wgSiteName != 'undefined' ) + { + _this.upload_api_name = wgSiteName; + } + + // Set the target to "proxy" if a proxy frame is configured + if ( _this.upload_api_proxy_frame ) + _this.upload_api_target = 'proxy'; + + // Set up the local API upload URL + if ( _this.upload_api_target == 'local' ) { + if ( ! _this.local_wiki_api_url ) { + $j( '#tab-upload' ).html( gM( 'rsd_config_error', 'missing_local_api_url' ) ); + return false; + } else { + _this.upload_api_target = _this.local_wiki_api_url; + } + } + + // Set up the "add media wizard" button, which invokes this object + if ( $j( this.target_invoke_button ).length == 0 ) { + js_log( "RemoteSearchDriver:: no target invocation provided " + + "(will have to run your own createUI() )" ); + } else { + if ( this.target_invoke_button ) { + $j( this.target_invoke_button ) + .css( 'cursor', 'pointer' ) + .attr( 'title', gM( 'mwe-add_media_wizard' ) ) + .click( function() { + _this.createUI(); + } ); + } + } + }, + + /* + * getLicenseIconHtml + * @param license_key the license key (ie "by-sa" or "by-nc-sa" etc) + */ + getLicenseIconHtml: function( licenseObj ) { + // js_log('output images: '+ imgs); + return '

    '; + }, + + /* + * getLicenseKeyFromKey + * @param license_key the key of the license (must be defined in: this.licenses.cc.licenses) + */ + getLicenseFromKey: function( license_key, force_url ) { + // set the current license pointer: + var cl = this.licenses.cc; + var title = gM( 'mwe-cc_title' ); + var imgs = ''; + var license_set = license_key.split( '-' ); + for ( var i = 0; i < license_set.length; i++ ) { + var lkey = license_set[i]; + if ( !cl.license_images[ lkey ] ) { + js_log( "MISSING::" + lkey ); + } + + title += ' ' + gM( 'mwe-cc_' + lkey + '_title' ); + imgs += ''; + } + var url = ( force_url ) ? force_url : cl.base_license_url + cl.licenses[ license_key ]; + return { + 'title': title, + 'img_html': imgs, + 'key': license_key, + 'lurl': url + }; + }, + + /* + * getLicenseKeyFromUrl + * @param license_url the url of the license + */ + getLicenseFromUrl: function( license_url ) { + // check for some pre-defined url types: + if ( license_url == 'http://www.usa.gov/copyright.shtml' || + license_url == 'http://creativecommons.org/licenses/publicdomain' ) + return this.getLicenseFromKey( 'pd' , license_url ); + + + // js_log("getLicenseFromUrl::" + license_url); + // first do a direct lookup check: + for ( var j = 0; j < this.licenses.cc.licenses.length; j++ ) { + var jL = this.licenses.cc.licenses[ j ]; + // special 'pd' case: + if ( jL == 'pd' ) { + var keyCheck = 'publicdomain'; + } else { + var keyCheck = jL; + } + if ( mw.parseUri( license_url ).path.indexOf( '/' + keyCheck + '/' ) != -1 ) { + return this.getLicenseFromKey( jL , license_url ); + } + } + // Could not find it return mwe-unknown_license + return { + 'title': gM( 'mwe-unknown_license' ), + 'img_html': '' + gM( 'mwe-unknown_license' ) + '', + 'lurl': license_url + }; + }, + + /** + * getTypeIcon + * @param str mime type of the requested file + */ + getTypeIcon: function( mimetype ) { + var typestr = 'unk'; + switch ( mimetype ) { + case 'image/svg+xml': + typestr = 'svg'; + break; + case 'image/jpeg': + typestr = 'jpg' + break; + case 'image/png': + typestr = 'png'; + break; + case 'audio/ogg': + typestr = 'oga'; + case 'video/ogg': + case 'application/ogg': + typestr = 'ogg'; + break; + } + + if ( typestr == 'unk' ) { + js_log( "unkown ftype: " + mimetype ); + return ''; + } + + return '
    ' + + typestr + + '
    '; + }, + + createUI: function() { + var _this = this; + + this.clearTextboxCache(); + // setup the parent container: + this.createDialogContainer(); + // fill in the html: + this.initDialog(); + // bind actions: + this.add_interface_bindings(); + + // update the target binding to just un-hide the dialog: + if ( this.target_invoke_button ) { + $j( this.target_invoke_button ) + .unbind() + .click( function() { + js_log( "createUI:target_invoke_button: click showDialog" ); + _this.showDialog(); + } ); + } + }, + + showDialog: function() { + var _this = this; + js_log( "showDialog::" ); + _this.clearTextboxCache(); + var query = _this.getDefaultQuery(); + if ( query != $j( '#rsd_q' ).val() ) { + $j( '#rsd_q' ).val( query ); + _this.showCurrentTab(); + } + // $j(_this.target_container).dialog("open"); + $j( _this.target_container ).parents( '.ui-dialog' ).fadeIn( 'slow' ); + // re-center the dialog: + $j( _this.target_container ).dialog( 'option', 'position', 'center' ); + }, + + clearTextboxCache: function() { + this.caretPos = null; + this.textboxValue = null; + this.default_query = null; + }, + + getCaretPos: function() { + if ( this.caretPos == null ) { + if ( this.target_textbox ) { + this.caretPos = $j( this.target_textbox ).getCaretPosition(); + } else { + this.caretPos = false; + } + } + return this.caretPos; + }, + + getTextboxValue: function() { + if ( this.textboxValue == null ) { + if ( this.target_textbox ) { + this.textboxValue = $j( this.target_textbox ).val(); + } else { + this.textboxValue = ''; + } + } + return this.textboxValue; + }, + + getDefaultQuery: function() { + if ( this.default_query == null ) { + if ( this.target_textbox ) { + var ts = $j( this.target_textbox ).textSelection(); + if ( ts != '' ) { + this.default_query = ts; + } else { + this.default_query = ''; + } + } + } + return this.default_query; + }, + + createDialogContainer: function() { + js_log( "createDialogContainer" ); + var _this = this; + // add the parent target_container if not provided or missing + if ( _this.target_container && $j( _this.target_container ).length != 0 ) { + js_log( 'dialog already exists' ); + return; + } + + _this.target_container = '#rsd_modal_target'; + $j( 'body' ).append( + '
    ' + + '
    ' ); + // js_log('appended: #rsd_modal_target' + $j(_this.target_container).attr('id')); + // js_log('added target id:' + $j(_this.target_container).attr('id')); + // get layout + js_log( 'width: ' + $j( window ).width() + ' height: ' + $j( window ).height() ); + var cBtn = {}; + cBtn[ gM( 'mwe-cancel' ) ] = function() { + _this.onCancelClipEdit(); + } + + $j( _this.target_container ).dialog( { + bgiframe: true, + autoOpen: true, + modal: true, + draggable: false, + resizable: false, + buttons: cBtn, + close: function() { + // if we are 'editing' a item close that + // @@todo maybe prompt the user? + _this.onCancelClipEdit(); + $j( this ).parents( '.ui-dialog' ).fadeOut( 'slow' ); + } + } ); + $j( _this.target_container ).dialogFitWindow(); + $j( window ).resize( function() { + $j( _this.target_container ).dialogFitWindow(); + } ); + + // add cancel callback and updated button with icon + _this.onCancelClipEdit(); + }, + + // sets up the initial html interface + initDialog: function() { + js_log( 'initDialog' ); + var _this = this; + js_log( 'f::initDialog' ); + + var o = '
    ' + + '
    ' + + '' + + $j.btnHtml( gM( 'mwe-media_search' ), 'rms_search_button', 'search' ) + + '
    '; + // close up the control container: + o += '
    '; + + // search provider tabs based on "checked" and "enabled" and "combined tab" + o += '
    ' + + '
    '; + $j( this.target_container ).html( o ); + // add simple styles: + $j( this.target_container + ' .rms_search_button' ).btnBind().click( function() { + _this.showCurrentTab(); + } ); + + // draw the tabs: + this.createTabs(); + // run the default search: + if ( this.getDefaultQuery() ) + this.showCurrentTab(); + + // Add bindings + $j( '#mso_selprovider,#mso_selprovider_close' ) + .unbind() + .click( function() { + if ( $j( '#rsd_options_bar:hidden' ).length != 0 ) { + $j( '#rsd_options_bar' ).animate( { + 'height': '110px', + 'opacity': 1 + }, "normal" ); + } else { + $j( '#rsd_options_bar' ).animate( { + 'height': '0px', + 'opacity': 0 + }, "normal", function() { + $j( this ).hide(); + } ); + } + } ); + // set form bindings + $j( '#rsd_form' ) + .unbind() + .submit( function() { + _this.showCurrentTab(); + // don't submit the form + return false; + } ); + }, + + showUploadTab: function() { + js_log( "showUploadTab::" ); + var _this = this; + // set it to loading: + mv_set_loading( '#tab-upload' ); + // do things async to keep interface snappy + setTimeout( + function() { + // check if we need to setup the proxy:: + if ( _this.upload_api_target == 'proxy' ) { + _this.setupProxy( function() { + _this.showUploadForm(); + } ); + } else { + _this.showUploadForm(); + } + }, + 1 ); + }, + + showUploadForm: function() { + var _this = this; + mvJsLoader.doLoad( ['$j.fn.simpleUploadForm'], function() { + // get extends info about the file + var provider = _this.content_providers['this_wiki']; + + // check for "this_wiki" enabled + /*if(!provider.enabled){ + $j('#tab-upload') + .html('error this_wiki not enabled (can\'t get uploaded file info)'); + return false; + }*/ + + // load this_wiki search system to grab the resource + _this.loadSearchLib( provider, function() { + _this.showUploadForm_internal( provider ); + } ); + } ); + }, + + showUploadForm_internal: function( provider ) { + var _this = this; + var uploadMsg = gM( 'mwe-upload_a_file', _this.upload_api_name ); + var recentUploadsMsg = gM( 'mwe-your_recent_uploads', _this.upload_api_name ); + // do basic layout form on left upload "bin" on right + $j( '#tab-upload' ).html( + '' + + '' + + '' + + '' + + '' + + '
    ' + + '

    ' + uploadMsg + '

    ' + + '
    ' + + mv_get_loading_img() + + '
    ' + + '
    ' + + '

    ' + recentUploadsMsg + '

    ' + + '
    ' + + mv_get_loading_img() + + '
    ' + + '
    ' ); + + + // fill in the user page: + if ( typeof wgUserName != 'undefined' && wgUserName ) { + // load the upload bin with anything the current user has uploaded + provider.sObj.getUserRecentUploads( wgUserName, function() { + _this.showResults(); + } ); + } else { + $j( '#upload_bin_cnt' ).empty(); + } + + // deal with the api form upload form directly: + $j( '#upload_form' ).simpleUploadForm( { + "api_target" : _this.upload_api_target, + "ondone_cb": function( resultData ) { + var wTitle = resultData['filename']; + // add a loading div + _this.addResourceEditLoader(); + // @@note: we have most of what we need in resultData imageinfo + provider.sObj.addByTitle( wTitle, function( resource ) { + // Redraw ( with added result if new ) + _this.showResults(); + // Pull up resource editor: + _this.showResourceEditor( resource, $j( '#res_upload__' + resource.id ).get( 0 ) ); + } ); + // Return false to close progress window: + return false; + } + } ); + }, + + showCurrentTab: function() { + if ( this.currentProvider == 'upload' ) { + this.showUploadTab(); + } else { + this.showSearchTab( this.currentProvider, false ); + } + } + + showSearchTab: function( providerName, resetPaging ) { + js_log( "f:showSearchTab::" + providerName ); + + var draw_direct_flag = true; + + // else do showSearchTab + var provider = this.content_providers[providerName]; + + // check if we need to update: + if ( typeof provider.sObj != 'undefined' ) { + if ( provider.sObj.last_query == $j( '#rsd_q' ).val() + && provider.sObj.last_offset == provider.offset ) + { + js_log( 'last query is: ' + provider.sObj.last_query + + ' matches: ' + $j( '#rsd_q' ).val() ); + } else { + js_log( 'last query is: ' + provider.sObj.last_query + + ' not match: ' + $j( '#rsd_q' ).val() ); + draw_direct_flag = false; + } + } else { + draw_direct_flag = false; + } + if ( !draw_direct_flag ) { + // see if we should reset the paging + if ( resetPaging ) { + provider.sObj.offset = provider.offset = 0; + } + + // set the content to loading while we do the search: + $j( '#tab-' + providerName ).html( mv_get_loading_img() ); + + // Make sure the search library is loaded and issue the search request + this.getLibSearchResults( provider ); + } + }, + + // Issue a api request & cache the result + // this check can be avoided by setting the + // this.import_url_mode = 'api' | 'form' | instead of 'autodetect' or 'none' + checkForCopyURLSupport: function ( callback ) { + var _this = this; + js_log( 'checkForCopyURLSupport:: ' ); + + // See if we already have the import mode: + if ( this.import_url_mode != 'autodetect' ) { + js_log( 'import mode: ' + _this.import_url_mode ); + callback(); + } + // If we don't have the local wiki api defined we can't auto-detect use "link" + if ( ! _this.upload_api_target ) { + js_log( 'import mode: remote link (no import_wiki_api_url)' ); + _this.import_url_mode = 'remote_link'; + callback(); + } + if ( this.import_url_mode == 'autodetect' ) { + do_api_req( + { + 'url': _this.upload_api_target, + 'data': { + 'action': 'paraminfo', + 'modules': 'upload' + } + }, function( data ) { + // jump right into api checks: + for ( var i in data.paraminfo.modules[0].parameters ) { + var pname = data.paraminfo.modules[0].parameters[i].name; + if ( pname == 'url' ) { + js_log( 'Autodetect Upload Mode: api: copy by url:: ' ); + // check permission too: + _this.checkForCopyURLPermission( function( canCopyUrl ) { + if ( canCopyUrl ) { + _this.import_url_mode = 'api'; + js_log( 'import mode: ' + _this.import_url_mode ); + callback(); + } else { + _this.import_url_mode = 'none'; + js_log( 'import mode: ' + _this.import_url_mode ); + callback(); + } + } ); + break; + } + } + } + ); + } + }, + + /* + * checkForCopyURLPermission: + * not really necessary the api request to upload will return appropriate error + * if the user lacks permission. or $wgAllowCopyUploads is set to false + * (use this function if we want to issue a warning up front) + */ + checkForCopyURLPermission: function( callback ) { + var _this = this; + // do api check: + do_api_req( + { + 'data': { 'action' : 'query', 'meta' : 'userinfo', 'uiprop' : 'rights' }, + 'url': _this.upload_api_target, + 'userinfo' : true + }, function( data ) { + for ( var i in data.query.userinfo.rights ) { + var right = data.query.userinfo.rights[i]; + // js_log('checking: ' + right ) ; + if ( right == 'upload_by_url' ) { + callback( true ); + return true; // break out of the function + } + } + callback( false ); + } + ); + }, + + getLibSearchResults: function( provider ) { + var _this = this; + + // first check if we should even run the search at all (can we import / insert + // into the page? ) + if ( !this.isProviderLocal( provider ) && this.import_url_mode == 'autodetect' ) { + // provider is not local check if we can support the import mode: + this.checkForCopyURLSupport( function() { + _this.getLibSearchResults( provider ); + } ); + return false; + } else if ( !this.isProviderLocal( provider ) && this.import_url_mode == 'none' ) { + if ( this.currentProvider == 'combined' ) { + // combined results are harder to error handle just ignore that repo + provider.sObj.loading = false; + } else { + $j( '#tab-' + this.currentProvider ).html( + '
    ' + + gM( 'mwe-no_import_by_url' ) + + '
    ' ); + } + return false; + } + _this.loadSearchLib( provider, function() { + // Do the search + provider.sObj.getSearchResults(); + _this.waitForResults( function() { + this.showResults(); + } ); + } ); + }, + + loadSearchLib: function( provider, callback ) { + var _this = this; + // set up the library req: + mvJsLoader.doLoad( [ + 'baseRemoteSearch', + provider.lib + 'Search' + ], function() { + js_log( "loaded lib:: " + provider.lib ); + // else we need to run the search: + var options = { + 'provider': provider, + 'rsd': _this + }; + eval( 'provider.sObj = new ' + provider.lib + 'Search( options );' ); + if ( !provider.sObj ) { + js_log( 'Error: could not find search lib for ' + cp_id ); + return false; + } + + // inherit defaults if not set: + provider.limit = provider.limit ? provider.limit : provider.sObj.limit; + provider.offset = provider.offset ? provider.offset : provider.sObj.offset; + callback(); + } ); + }, + + /* check for all the results to finish */ + waitForResults: function( callback ) { + // js_log('rsd:waitForResults'); + var _this = this; + var loading_done = true; + + for ( var cp_id in this.content_providers ) { + var cp = this.content_providers[ cp_id ]; + if ( typeof cp['sObj'] != 'undefined' ) { + if ( cp.sObj.loading ) + loading_done = false; + } + } + if ( loading_done ) { + callback(); + } else { + setTimeout( + function() { + _this.waitForResults( callback ); + }, + 50 + ); + } + }, + + createTabs: function() { + var _this = this; + // add the tabs to the rsd_results container: + var s = '
    '; + var selected_tab = 0; + var index = 0; + s += '
      '; + var content = ''; + for ( var providerName in this.content_providers ) { + var provider = this.content_providers[providerName]; + var tabImage = mv_embed_path + '/skins/common/remote_cp/' + providerName + '_tab.png'; + if ( provider.enabled && provider.checked && provider.api_url ) { + // add selected default if set + if ( this.currentProvider == providerName ) + selected_tab = index; + + s += '
    • '; + s += ''; + if ( provider.tab_img === true ) { + s += '' + gM( 'rsd-' + providerName + '-title' ) + ''; + } else { + s += gM( 'rsd-' + providerName + '-title' ); + } + s += ''; + s += '
    • '; + index++; + } + content += '
      '; + } + // Do an upload tab if enabled: + if ( this.content_providers['upload'].enabled ) { + s += '
    • ' + + '' + + gM( 'mwe-upload_tab' ) + + '
    • '; + content += '
      '; + if ( this.currentProvider == 'upload' ) + selected_tab = index++; + } + s += '
    '; + // Output the tab content containers: + s += content; + s += '
    '; // close tab container + + // Output the respective results holders + $j( '#rsd_results_container' ).html( s ); + // Setup bindings for tabs make them sortable: (@@todo remember order) + js_log( 'selected tab is: ' + selected_tab ); + $j( "#rsd_tabs_container" ) + .tabs( { + selected: selected_tab, + select: function( event, ui ) { + _this.selectTab( $j( ui.tab ).attr( 'id' ).replace( 'rsd_tab_', '' ) ); + } + }) + // Add sorting + .find( ".ui-tabs-nav" ).sortable( { axis: 'x' } ); + // @@todo store sorted repo + }, + + // Resource title + getResourceFromTitle: function( title, callback ) { + var _this = this; + reqObj = { + 'action': 'query', + 'titles': _this.cFileNS + ':' + title + }; + do_api_req( { + 'data': reqObj, + 'url': this.local_wiki_api_url + }, function( data ) { + // @@todo propagate the resource + var resource = {}; + } + ); + }, + + // @@todo we could load the id with the content provider id to find the object faster... + getResourceFromId: function( id ) { + var parts = id.replace( /^res_/, '' ).split( '__' ); + var providerName = parts[0]; + var resIndex = parts[1]; + + // Set the upload helper providerName (to render recent uploads by this user) + if ( providerName == 'upload' ) + providerName = 'this_wiki'; + + var provider = this.content_providers[providerName]; + if ( provider && provider['sObj'] && provider.sObj.resultsObj[resIndex] ) { + return provider.sObj.resultsObj[resIndex]; + } + js_log( "ERROR: could not find " + resIndex ); + return false; + }, + + showResults: function() { + js_log( 'f:showResults::' + this.currentProvider ); + var _this = this; + var o = ''; + var tabSelector = ''; + + if ( this.currentProvider == 'upload' ) { + tabSelector = '#upload_bin'; + var provider = _this.content_providers['this_wiki']; + } else { + var provider = this.content_providers[this.currentProvider]; + tabSelector = '#tab-' + this.currentProvider; + // Output the results bar / controls + } + // Empty the existing results: + $j( tabSelector ).empty(); + // @@todo give the user upload control love + if ( this.currentProvider != 'upload' ) { + _this.showResultsHeader(); + } + + var numResults = 0; + + // Output all the results for the current currentProvider + if ( typeof provider['sObj'] != 'undefined' ) { + $j.each( provider.sObj.resultsObj, function( resIndex, resource ) { + o += _this.getResultHtml( provider, resIndex, resource ); + numResults++; + } ); + js_log( 'append to: ' + '#tab-' + cp_id ); + // Put in the tab output (plus clear the output) + $j( tabSelector ).append( o + '
    ' ); + } + + js_log( 'did numResults :: ' + numResults + + ' append: ' + $j( '#rsd_q' ).val() ); + + // Remove any old search res + $j( '#rsd_no_search_res' ).remove(); + if ( numResults == 0 ) { + $j( '#tab-' + cp_id ).append( + '' + + gM( 'rsd_no_results', $j( '#rsd_q' ).val() ) + + '' ); + } + this.addResultBindings(); + }, + + getResultHtml: function( provider, resIndex, resource ) { + var o = ''; + if ( this.displayMode == 'box' ) { + o += '
    '; + // Check for missing poster types for audio + if ( resource.mime == 'audio/ogg' && !resource.poster ) { + resource.poster = mv_skin_img_path + 'sound_music_icon-80.png'; + } + // Get a thumb with proper resolution transform if possible: + var thumbUrl = provider.sObj.getImageTransform( resource, + { 'width' : this.thumb_width } ); + + o += ''; + // Add a linkback to resource page in upper right: + if ( resource.link ) { + o += ''; + } + + // Add file type icon if known + if ( resource.mime ) { + o += this.getTypeIcon( resource.mime ); + } + + // Add license icons if present + if ( resource.license ) + o += this.getLicenseIconHtml( resource.license ); + + o += '
    '; + } else if ( this.displayMode == 'list' ) { + o += '
    '; + o += + ''; + // Add license icons if present + if ( resource.license ) + o += this.getLicenseIconHtml( resource.license ); + + o += resource.desc ; + o += '
    '; + o += '
    '; + } + return o; + } + + addResultBindings: function() { + var _this = this; + $j( '.mv_clip_' + _this.displayMode + '_result' ).hover( + function() { + $j( this ).addClass( 'mv_clip_' + _this.displayMode + '_result_over' ); + // Also set the animated image if available + var res_id = $j( this ).children( '.rsd_res_item' ).attr( 'id' ); + var resource = _this.getResourceFromId( res_id ); + if ( resource.poster_ani ) + $j( '#' + res_id ).attr( 'src', resource.poster_ani ); + }, function() { + $j( this ).removeClass( + 'mv_clip_' + _this.displayMode + '_result_over' ); + var res_id = $j( this ).children( '.rsd_res_item' ).attr( 'id' ); + var resource = _this.getResourceFromId( res_id ); + // Restore the original (non animated) + if ( resource.poster_ani ) + $j( '#' + res_id ).attr( 'src', resource.poster ); + } + ); + // Resource click action: (bring up the resource editor) + $j( '.rsd_res_item' ).unbind().click( function() { + var resource = _this.getResourceFromId( $j( this ).attr( "id" ) ); + _this.showResourceEditor( resource, this ); + } ); + }, + + addResourceEditLoader: function( maxWidth, overflowStyle ) { + var _this = this; + if ( !maxWidth ) maxWidth = 400; + if ( !overflowStyle ) overflowStyle = 'overflow:auto;'; + // Remove any old instance: + $j( _this.target_container ).find( '#rsd_resource_edit' ).remove(); + + // Hide the results container + $j( '#rsd_results_container' ).hide(); + + var pt = $j( _this.target_container ).html(); + // Add the edit layout window with loading place holders + $j( _this.target_container ).append( + '
    ' + + '
    ' + + '
    ' + + '
    ' + + mv_get_loading_img( 'position:absolute;top:30px;left:30px' ) + + '
    ' + + '
    ' ); + }, + + getEditWidth: function( resource ) { + var mediaType = this.getMediaType( resource ); + if ( mediaType == 'image' ) { + return resource.image_edit_width; + } else { + return resource.video_edit_width; + } + }, + + getMediaType: function( resource ) { + if ( resource.mime.indexOf( 'image' ) != -1 ) { + return 'image'; + } else if ( resource.mime.indexOf( 'audio' ) != -1 ) { + return 'audio'; + } else { + return 'video'; + } + }, + + removeResourceEditor: function() { + $j( '#rsd_resource_edit' ).remove(); + $j( '#rsd_resource_edit' ).css( 'opacity', 0 ); + $j( '#rsd_edit_img' ).remove(); + } + + showResourceEditor: function( resource, rsdElement ) { + js_log( 'f:showResourceEditor:' + resource.title ); + var _this = this; + + // Remove any existing resource edit interface + _this.removeResourceEditor(); + + var mediaType = _this.getMediaType( resource ); + var maxWidth = _this.getEditWidth( resource ); + + // So that transcripts show on top + var overflow_style = ( mediaType == 'video' ) ? '' : 'overflow:auto;'; + // Append to the top level of model window: + _this.addResourceEditLoader( maxWidth, overflow_style ); + // update add media wizard title: + var dialogTitle = gM( 'mwe-add_media_wizard' ) + ': ' + + gM( 'rsd_resource_edit', resource.title ); + $j( _this.target_container ).dialog( 'option', 'title', dialogTitle ); + js_log( 'did append to: ' + _this.target_container ); + + // Left side holds the image right size the controls / + $j( rsdElement ) + .clone() + .attr( 'id', 'rsd_edit_img' ) + .appendTo( '#clip_edit_disp' ) + .css( { + 'position':'absolute', + 'top':'40%', + 'left':'20%', + 'cursor':'default', + 'opacity':0 + } ); + + // Try and keep aspect ratio for the thumbnail that we clicked: + var tRatio = $j( rsdElement ).height() / $j( rsdElement ).width(); + + if ( !tRatio ) { + var tRatio = 1; // set ratio to 1 if tRatio did not work. + } + js_log( 'Set from ' + tRatio + ' to init thumbimage to ' + + maxWidth + ' x ' + parseInt( tRatio * maxWidth ) ); + // Scale up image and to swap with high res version + $j( '#rsd_edit_img' ).animate( + { + 'opacity': 1, + 'top': '5px', + 'left': '5px', + 'width': maxWidth + 'px', + 'height': parseInt( tRatio * maxWidth ) + 'px' + }, + "slow" ); // Do it slow to give it a chance to finish loading the high quality version + + if ( mediaType == 'image' ) { + _this.loadHighQualityImage( + resource, + { 'width': maxWidth }, + 'rsd_edit_img', + function() { + $j( '.mv_loading_img' ).remove(); + } + ); + } + // Also fade in the container: + $j( '#rsd_resource_edit' ).animate( { + 'opacity': 1, + 'background-color': '#FFF', + 'z-index': 99 + } ); + + // Show the editor itself + if ( mediaType == 'image' ) { + _this.showImageEditor( resource ); + } else if ( mediaType == 'video' || mediaType == 'audio' ) { + _this.showVideoEditor( resource ); + } + }, + + loadHighQualityImage: function( resource, size, target_img_id, callback ) { + // Get the high quality image url: + resource.pSobj.getImageObj( resource, size, function( imObj ) { + resource['edit_url'] = imObj.url; + + js_log( "edit url: " + resource.edit_url ); + // Update the resource + resource['width'] = imObj.width; + resource['height'] = imObj.height; + + // See if we need to animate some transition + if ( size.width != imObj.width ) { + js_log( 'loadHighQualityImage:size mismatch: ' + size.width + ' != ' + imObj.width ); + // Set the target id to the new size: + $j( '#' + target_img_id ).animate( { + 'width': imObj.width + 'px', + 'height': imObj.height + 'px' + }); + } else { + js_log( 'using req size: ' + imObj.width + 'x' + imObj.height ); + $j( '#' + target_img_id ).animate( { + 'width': imObj.width + 'px', + 'height': imObj.height + 'px' + }); + } + // Don't swap it in until its loaded: + var img = new Image(); + // Load the image image: + $j( img ).load( function () { + $j( '#' + target_img_id ).attr( 'src', resource.edit_url ); + // Let the caller know we are done and what size we ended up with: + callback(); + } ).error( function () { + js_log( "Error with: " + resource.edit_url ); + } ).attr( 'src', resource.edit_url ); + } ); + }, + + onCancelClipEdit: function() { + var _this = this; + js_log( 'onCancelClipEdit' ); + var b_target = _this.target_container + '~ .ui-dialog-buttonpane'; + $j( '#rsd_resource_edit' ).remove(); + // Remove preview if its 'on' + $j( '#rsd_preview_display' ).remove(); + // Restore the resource container: + $j( '#rsd_results_container' ).show(); + + // Restore the title: + $j( _this.target_container ).dialog( 'option', 'title', gM( 'mwe-add_media_wizard' ) ); + js_log( "should update: " + b_target + ' with: cancel' ); + // Restore the buttons: + $j( b_target ) + .html( $j.btnHtml( gM( 'mwe-cancel' ) , 'mv_cancel_rsd', 'close' ) ) + .children( '.mv_cancel_rsd' ) + .btnBind() + .click( function() { + $j( _this.target_container ).dialog( 'close' ); + } ); + }, + + /** + * Get the control actions for clipEdit with relevant callbacks + */ + getClipEditControlActions: function( provider ) { + var _this = this; + var actions = { }; + + actions['insert'] = function( resource ) { + _this.insertResource( resource ); + } + // If not directly inserting the resource is support a preview option: + if ( _this.import_url_mode != 'remote_link' ) { + actions['preview'] = function( resource ) { + _this.showPreview( resource ) + }; + } + actions['cancel'] = function() { + _this.onCancelClipEdit() + } + return actions; + }, + + getClipEditOptions: function( resource ) { + return { + 'rObj': resource, + 'parent_ct': 'rsd_modal_target', + 'clip_disp_ct': 'clip_edit_disp', + 'control_ct': 'clip_edit_ctrl', + 'media_type': this.getMediaType( resource ), + 'p_rsdObj': this, + 'controlActionsCb': this.getClipEditControlActions( resource.pSobj.cp ), + 'enabled_tools': this.enabled_tools + }; + }, + + /** + * Internal function called by showResourceEditor() to show an image editor + */ + showImageEditor: function( resource ) { + var _this = this; + var options = _this.getClipEditOptions( resource ); + // Display the mvClipEdit obj once we are done loading: + mvJsLoader.doLoad( clibs, function() { + // Run the image clip tools + _this.clipEdit = new mvClipEdit( options ); + } ); + }, + + /** + * Internal function called by showResourceEditor() to show a video or audio + * editor. + */ + showVideoEditor: function( resource ) { + var _this = this; + var options = _this.getClipEditOptions( resource ); + var mediaType = this.getMediaType( resource ); + + js_log( 'media type:: ' + mediaType ); + // Get any additional embedding helper meta data prior to doing the actual embed + // normally this meta should be provided in the search result + // (but archive.org has another query for more media meta) + resource.pSobj.addResourceInfoCallback( resource, function() { + // Make sure we have the embedVideo libs: + var runFlag = false; + mvJsLoader.embedVideoCheck( function() { + // Strange concurrency issue with callbacks + // @@todo try and figure out why this callback is fired twice + if ( !runFlag ) { + runFlag = true; + } else { + js_log( 'Error: embedVideoCheck run twice' ); + return false; + } + var embedHtml = resource.pSobj.getEmbedHTML( resource, + { id : 'embed_vid' } ); + js_log( 'append html: ' + embedHtml ); + $j( '#clip_edit_disp' ).html( embedHtml ); + js_log( "about to call rewrite_by_id::embed_vid" ); + // Rewrite by id + rewrite_by_id( 'embed_vid', function() { + // Grab information avaliable from the embed instance + resource.pSobj.addResourceInfoFromEmbedInstance( resource, 'embed_vid' ); + + // Add the re-sizable to the doLoad request: + clibs.push( '$j.ui.resizable' ); + clibs.push( '$j.fn.hoverIntent' ); + mvJsLoader.doLoad( clibs, function() { + // Make sure the rsd_edit_img is removed: + $j( '#rsd_edit_img' ).remove(); + // Run the image clip tools + _this.clipEdit = new mvClipEdit( options ); + } ); + } ); + } ); + } ); + }, + + isProviderLocal: function( provider ) { + if ( provider.local ) { + return true; + } else { + // Check if we can embed the content locally per a domain name check: + var localHost = mw.parseUri( this.local_wiki_api_url ).host; + if ( provider.local_domains ) { + for ( var i = 0; i < provider.local_domains.length; i++ ) { + var domain = provider.local_domains[i]; + if ( localHost.indexOf( domain ) != -1 ) + return true; + } + } + return false; + } + }, + + /** + * Check if the file is either a local upload, or if it has already been + * imported under the standard filename scheme. + * + * Calls the callback with two parameters: + * callback( resource, status ) + * + * resource: a resource object pointing to the local file if there is one, + * or false if not + * + * status: may be 'local', 'shared', 'imported' or 'missing' + */ + isFileLocallyAvailable: function( resource, callback ) { + var _this = this; + // Add a loader on top + $j.addLoaderDialog( gM( 'mwe-checking-resource' ) ); + + // Extend the callback, closing the loader dialog before chaining + myCallback = function( newRes, status ) { + $j.closeLoaderDialog(); + if ( typeof callback == 'function' ) { + callback( newRes, status ); + } + } + + // @@todo get the localized File/Image namespace name or do a general {NS}:Title + var provider = resource.pSobj.cp; + var _this = this; + + // Clone the resource + var proto = {}; + proto.prototype = resource; + var myRes = new proto; + + // Update base target_resource_title: + myRes.target_resource_title = myRes.titleKey.replace( /^(File:|Image:)/ , '' ) + + // check if local repository + // or if import mode if just "linking" (we should already have the 'url' + + if ( this.isProviderLocal( provider ) || this.import_url_mode == 'remote_link' ) { + // Local repo, jump directly to the callback: + myCallback( myRes, 'local' ); + } else { + // Check if the file is local (can be shared repo) + if ( provider.check_shared ) { + _this.findFileInLocalWiki( myRes.target_resource_title, function( imagePage ) { + if ( imagePage && imagePage['imagerepository'] == 'shared' ) { + myCallback( myRes, 'shared' ); + } else { + _this.isFileAlreadyImported( myRes, myCallback ); + } + } ); + } else { + _this.isFileAlreadyImported( myRes, myCallback ); + } + } + }, + + /** + * Check if the file is already imported with this extension's filename scheme + * + * Calls the callback with two parameters: + * callback( resource, status ) + * + * If the image is found, the status will be 'imported' and the resource + * will be the new local resource. + * + * If the image is not found, the status will be 'missing' and the resource + * will be false. + */ + isFileAlreadyImported: function( resource, callback ) { + js_log( '::isFileAlreadyImported:: ' ); + var _this = this; + + // Clone the resource + var proto = {}; + proto.prototype = resource; + var myRes = new proto; + + var provider = myRes.pSobj.cp; + + // update target_resource_title with resource repository prefix: + myRes.target_resource_title = provider.resource_prefix + myRes.target_resource_title; + // check if the file exists: + _this.findFileInLocalWiki( myRes.target_resource_title, function( imagePage ) { + if ( imagePage ) { + // update to local src + myRes.local_src = imagePage['imageinfo'][0].url; + // @@todo maybe update poster too? + myRes.local_poster = imagePage['imageinfo'][0].thumburl; + // update the title: + myRes.target_resource_title = imagePage.title.replace(/^(File:|Image:)/ , '' ); + callback( myRes, 'imported' ); + } else { + callback( false, 'missing' ); + } + } ); + }, + + showImportUI: function( resource, callback ) { + var _this = this; + js_log( "showImportUI:: update:" + _this.cFileNS + ':' + + resource.target_resource_title ); + + // setup the resource description from resource description: + // FIXME: i18n, namespace + var desc = '{{Information ' + "\n"; + + if ( resource.desc ) { + desc += '|Description= ' + resource.desc + "\n"; + } else { + desc += '|Description= ' + gM( 'mwe-missing_desc_see_source', resource.link ) + "\n"; + } + + // output search specific info + desc += '|Source=' + resource.pSobj.getImportResourceDescWiki( resource ) + "\n"; + + if ( resource.author ) + desc += '|Author=' + resource.author + "\n"; + + if ( resource.date ) + desc += '|Date=' + resource.date + "\n"; + + // add the Permision info: + desc += '|Permission=' + resource.pSobj.getPermissionWikiTag( resource ) + "\n"; + + if ( resource.other_versions ) + desc += '|other_versions=' + resource.other_versions + "\n"; + + desc += '}}'; + + // get any extra categories or helpful links + desc += resource.pSobj.getExtraResourceDescWiki( resource ); + + + $j( '#rsd_resource_import' ).remove();// remove any old resource imports + + // @@ show user dialog to import the resource + $j( _this.target_container ).append( + '
    ' + + '

    ' + + gM( 'mwe-resource-needs-import', [resource.title, _this.upload_api_name] ) + + '

    ' + + '
    ' + + resource.pSobj.getEmbedHTML( resource, { + 'id': _this.target_container + '_rsd_pv_vid', + 'max_height': '220', + 'only_poster': true + } ) + // get embedHTML with small thumb: + '
    ' + + '' + gM( 'mwe-resource_page_desc' ) + '' + + '
    ' + + mv_get_loading_img( 'position:absolute;top:5px;left:5px' ) + + '
    ' + + '
    ' + + '
    ' + + '' + gM( 'mwe-local_resource_title' ) + '' + + // FIXME: invalid HTML,
    must be empty + '
    ' + + '' + + '
    ' + + '' + gM( 'mwe-edit_resource_desc' ) + '' + + // FIXME: invalid HTML, two id attributes + '' + + '
    ' + + '' + + ' ' + + '


    ' + + $j.btnHtml( gM( 'mwe-update_preview' ), 'rsd_import_apreview', 'refresh' ) + + ' ' + + '
    ' + + // output the rendered and non-rendered version of description for easy switching: + '
    ' ); + var buttonPaneSelector = _this.target_container + '~ .ui-dialog-buttonpane'; + $j( buttonPaneSelector ).html ( + // add the btns to the bottom: + $j.btnHtml( gM( 'mwe-do_import_resource' ), 'rsd_import_doimport', 'check' ) + + ' ' + + $j.btnHtml( gM( 'mwe-cancel_import' ), 'rsd_import_acancel', 'close' ) + ' ' + ); + + // add hover: + + // update video tag (if a video) + if ( resource.mime.indexOf( 'video/' ) !== -1 ) + rewrite_by_id( $j( _this.target_container ).attr( 'id' ) + '_rsd_pv_vid' ); + + // load the preview text: + _this.parse( + desc, _this.cFileNS + ':' + resource.target_resource_title, + function( descHtml ) { + $j( '#rsd_import_desc' ).html( descHtml ); + } + ); + // add bindings: + $j( _this.target_container + ' .rsd_import_apreview' ) + .btnBind() + .click( function() { + js_log( " Do preview asset update" ); + $j( '#rsd_import_desc' ).html( mv_get_loading_img() ); + // load the preview text: + _this.parse( + $j( '#rsd_import_ta' ).val(), + _this.cFileNS + ':' + resource.target_resource_title, + function( o ) { + js_log( 'got updated preview: ' ); + $j( '#rsd_import_desc' ).html( o ); + } + ); + } ); + + $j( buttonPaneSelector + ' .rsd_import_doimport' ) + .btnBind() + .click( function() { + js_log( "do import asset:" + _this.import_url_mode ); + // check import mode: + if ( _this.import_url_mode == 'api' ) { + if ( _this.upload_api_target == 'proxy' ) { + _this.setupProxy( function() { + _this.doApiImport( resource, callback ); + } ); + } else { + _this.doApiImport( resource, callback ); + } + } else { + js_log( "Error: import mode is not form or API (can not copy asset)" ); + } + } ); + $j( buttonPaneSelector + ' .rsd_import_acancel' ) + .btnBind() + .click( function() { + $j( '#rsd_resource_import' ).fadeOut( "fast", function() { + $j( this ).remove(); + // restore buttons (from the clipEdit object::) + _this.clipEdit.updateInsertControlActions(); + $j( buttonPaneSelector ).removeClass( 'ui-state-error' ); + } ); + } ); + }, + + /** + * Sets up the proxy for the remote inserts + */ + setupProxy: function( callback ) { + var _this = this; + + if ( _this.proxySetupDone ) { + if ( callback ) + callback(); + return; + } + // setup the the proxy via $j.apiProxy loader: + if ( !_this.upload_api_proxy_frame ) { + js_log( "Error:: remote api but no proxy frame target" ); + return false; + } else { + $j.apiProxy( + 'client', + { + 'server_frame': _this.upload_api_proxy_frame + }, function() { + _this.proxySetupDone = true + if ( callback ) + callback(); + } + ); + } + }, + + findFileInLocalWiki: function( fName, callback ) { + js_log( "findFileInLocalWiki::" + fName ); + var _this = this; + reqObj = { + 'action': 'query', + 'titles': _this.cFileNS + ':' + fName, + 'prop': 'imageinfo', + 'iiprop': 'url', + 'iiurlwidth': '400' + }; + // first check the api for imagerepository + do_api_req( + { + 'data': reqObj, + 'url': this.local_wiki_api_url + }, function( data ) { + if ( data.query.pages ) { + for ( var i in data.query.pages ) { + for ( var j in data.query.pages[i] ) { + if ( j == 'missing' + && data.query.pages[i].imagerepository != 'shared' ) + { + js_log( fName + " not found" ); + callback( false ); + return; + } + } + // else page is found: + js_log( fName + " found" ); + callback( data.query.pages[i] ); + } + } + } + ); + }, + + doApiImport: function( resource, callback ) { + var _this = this; + js_log( ":doApiImport:" ); + $j.addLoaderDialog( gM( 'mwe-importing_asset' ) ); + // baseUploadInterface + mvJsLoader.doLoad( + [ + 'mvBaseUploadInterface', + '$j.ui.progressbar' + ], + function() { + js_log( 'mvBaseUploadInterface ready' ); + // initiate a upload object ( similar to url copy ): + var uploader = new mvBaseUploadInterface( { + 'api_url' : _this.upload_api_target, + 'done_upload_cb':function() { + js_log( 'doApiImport:: run callback::' ); + // we have finished the upload: + + // close up the rsd_resource_import + $j( '#rsd_resource_import' ).remove(); + // return the parent callback: + return callback(); + } + } ); + // get the edit token if we have it handy + _this.getEditToken( function( token ) { + uploader.editToken = token; + + // close the loader now that we are ready to present the progress dialog:: + $j.closeLoaderDialog(); + + uploader.doHttpUpload( { + 'url': resource.src, + 'filename': resource.target_resource_title, + 'comment': $j( '#rsd_import_ta' ).val() + } ); + } ) + } + ); + }, + + getEditToken: function( callback ) { + var _this = this; + if ( _this.upload_api_target != 'proxy' ) { + // (if not a proxy) first try to get the token from the page: + var editToken = $j( "input[name='wpEditToken']" ).val(); + if ( editToken ) { + callback( editToken ); + return; + } + } + // @@todo try to load over ajax if( _this.local_wiki_api_url ) is set + // (your on the api domain but are inserting from a normal page view) + get_mw_token( null, _this.upload_api_target, function( token ) { + callback( token ); + } ); + }, + + showPreview: function( resource ) { + var _this = this; + this.isFileLocallyAvailable( resource, function( newRes, status ) { + if ( status === 'missing' ) { + _this.showImportUI( resource, callback ); + return; + } + + // put another window ontop: + $j( _this.target_container ).append( + '
    ' + + mv_get_loading_img( 'top:30px;left:30px' ) + + '
    ' ); + + var buttonPaneSelector = _this.target_container + '~ .ui-dialog-buttonpane'; + var origTitle = $j( _this.target_container ).dialog( 'option', 'title' ); + + // update title: + $j( _this.target_container ).dialog( 'option', 'title', + gM( 'mwe-preview_insert_resource', newRes.title ) ); + + // update buttons preview: + $j( buttonPaneSelector ) + .html( + $j.btnHtml( gM( 'rsd_do_insert' ), 'preview_do_insert', 'check' ) + ' ' ) + .children( '.preview_do_insert' ) + .click( function() { + _this.insertResource( newRes ); + } ); + // update cancel button + $j( buttonPaneSelector ) + .append( 'Do More Modification' ) + .children( '.preview_close' ) + .click( function() { + $j( '#rsd_preview_display' ).remove(); + // restore title: + $j( _this.target_container ).dialog( 'option', 'title', origTitle ); + // restore buttons (from the clipEdit object::) + _this.clipEdit.updateInsertControlActions(); + } ); + + // Get the preview wikitext + _this.parse( + _this.getPreviewText( newRes ), + _this.target_title, + function( phtml ) { + $j( '#rsd_preview_display' ).html( phtml ); + // update the display of video tag items (if any) + mwdomReady( true ); + } + ); + } ); + }, + + getEmbedCode: function( resource ) { + if ( this.import_url_mode == 'remote_link' ) { + return resource.pSobj.getEmbedHTML( resource ); + } else { + return resource.pSobj.getEmbedWikiCode( resource ); + } + }, + + getPreviewText: function( resource ) { + var _this = this; + var text; + + // insert at start if textInput cursor has not been set (ie == length) + var insertPos = _this.getCaretPos(); + var originalText = _this.getTextboxValue(); + var embedCode = _this.getEmbedCode( resource ); + if ( insertPos !== false && originalText ) { + if ( originalText.length == insertPos ) { + insertPos = 0; + } + text = originalText.substring( 0, insertPos ) + + embedCode + originalText.substring( insertPos ); + } else { + text = $j( _this.target_textbox ).val() + embedCode; + } + // check for missing + if ( text.indexOf( '' ) == -1 && text.indexOf( '' ) != -1 ) { + text = text + ''; + } + return text; + }, + + parse: function( wikitext, title, callback ) { + do_api_req( + { + 'data': { + 'action': 'parse', + 'text': wikitext + }, + 'url': this.local_wiki_api_url + }, function( data ) { + callback( data.parse.text['*'] ); + } + ); + }, + + insertResource: function( resource ) { + js_log( 'insertResource: ' + resource.title ); + + var _this = this; + // double check that the resource is present: + this.isFileLocallyAvailable( resource, function( newRes, status ) { + if ( status === 'missing' ) { + _this.showImportUI( resource, callback ); + return; + } + + $j( _this.target_textbox ).val( _this.getPreviewText( newRes ) ); + _this.clearTextboxCache(); + + // update the render area (if present) + var embedCode = _this.getEmbedCode( newRes ); + if ( _this.target_render_area && embedCode ) { + // output with some padding: + $j( _this.target_render_area ) + .append( embedCode + '
    ' ) + + // update the player if video or audio: + if ( newRes.mime.indexOf( 'audio' ) != -1 || + newRes.mime.indexOf( 'video' ) != -1 || + newRes.mime.indexOf( '/ogg' ) != -1 ) + { + mvJsLoader.embedVideoCheck( function() { + mv_video_embed(); + } ); + } + } + _this.closeAll(); + } ); + }, + + closeAll: function() { + var _this = this; + js_log( "close all:: " + _this.target_container ); + _this.onCancelClipEdit(); + // Give a chance for the events to complete + // (somehow at least in firefox a rare condition occurs where + // the modal of the edit-box stick around even after the + // close request has been issued. ) + setTimeout( + function() { + $j( _this.target_container ).dialog( 'close' ); + }, 10 + ); + }, + + showResultsHeader: function() { + var _this = this; + var darkBoxUrl = mv_skin_img_path + 'box_layout_icon_dark.png'; + var lightBoxUrl = mv_skin_img_path + 'box_layout_icon.png'; + var darkListUrl = mv_skin_img_path + 'list_layout_icon_dark.png'; + var lightListUrl = mv_skin_img_path + 'list_layout_icon.png'; + + if ( !this.content_providers[ this.currentProvider ] ) { + return; + } + var cp = this.content_providers[this.currentProvider]; + var resultsFromMsg = gM( 'mwe-results_from', + [ cp.homepage, gM( 'rsd-' + this.currentProvider + '-title' ) ] ); + var defaultBoxUrl, defaultListUrl; + if ( _this.displayMode == 'box' ) { + defaultBoxUrl = darkBoxUrl; + defaultListUrl = lightListUrl; + } else { + defaultBoxUrl = lightBoxUrl; + defaultListUrl = darkListUrl; + } + + var about_desc = '' + + '' + resultsFromMsg + ''; + + $j( '#tab-' + this.currentProvider ).append( '
    ' + + '' + + gM( 'rsd_layout' ) + ' ' + + ' ' + + '' + + about_desc + + '' + + '' + + '
    ' + ); + + // Get paging with bindings: + this.showPagingHeader( '#rsd_paging_ctrl' ); + + $j( '#msc_box_layout' ) + .hover( + function() { + $j( this ).attr( "src", darkBoxUrl ); + }, + function() { + $j( this ).attr( "src", defaultBoxUrl ); + } ) + .click( function() { + $j( this ).attr( "src", darkBoxUrl ); + $j( '#msc_list_layout' ).attr( "src", lightListUrl ); + _this.setDisplayMode( 'box' ); + } ); + + $j( '#msc_list_layout' ) + .hover( + function() { + $j( this ).attr( "src", darkListUrl ); + }, + function() { + $j( this ).attr( "src", defaultListUrl ); + } ) + .click( function() { + $j( this ).attr( "src", darkListUrl ); + $j( '#msc_box_layout' ).attr( "src", lightBoxUrl ); + _this.setDisplayMode( 'list' ); + } ); + }, + + showPagingHeader: function( target ) { + var _this = this; + if ( _this.currentProvider == 'upload' ) { + var provider = _this.content_providers['this_wiki']; + } else { + var provider = _this.content_providers[ _this.currentProvider ]; + } + var search = provider.sObj; + js_log( 'showPagingHeader:' + _this.currentProvider + ' len: ' + search.num_results ); + var to_num = ( provider.limit > search.num_results ) ? + ( parseInt( provider.offset ) + parseInt( search.num_results ) ) : + ( parseInt( provider.offset ) + parseInt( provider.limit ) ); + var out = ''; + + // @@todo we should instead support the wiki number format template system instead of inline calls + if ( search.num_results != 0 ) { + if ( search.num_results > provider.limit ) { + out += gM( 'rsd_results_desc_total', [( provider.offset + 1 ), to_num, + mw.lang.formatNumber( search.num_results )] ); + } else { + out += gM( 'rsd_results_desc', [( provider.offset + 1 ), to_num] ); + } + } + // check if we have more results (next prev link) + if ( provider.offset >= provider.limit ) { + out += ' ' + gM( 'rsd_results_prev' ) + ' ' + provider.limit + ''; + } + + if ( search.more_results ) { + out += ' ' + gM( 'rsd_results_next' ) + ' ' + provider.limit + ''; + } + + $j( target ).html( out ); + + // set bindings + $j( '#rsd_pnext' ).click( function() { + provider.offset += provider.limit; + _this.showCurrentTab(); + } ); + + $j( '#rsd_pprev' ).click( function() { + provider.offset -= provider.limit; + if ( provider.offset < 0 ) + provider.offset = 0; + _this.showCurrentTab(); + } ); + }, + + selectTab: function( provider ) { + js_log( 'select tab: ' + provider ); + this.currentProvider = provider; + if ( this.currentProvider == 'upload' ) { + this.showUploadTab(); + } else { + // update the search results: + this.showCurrentTab(); + } + }, + + setDisplayMode: function( mode ) { + js_log( 'setDisplayMode:' + mode ); + this.displayMode = mode; + // run /update search display: + this.showResults(); + } +}; diff --git a/js2/mwEmbed/libAddMedia/searchLibs/archiveOrgSearch.js b/js2/mwEmbed/libAddMedia/searchLibs/archiveOrgSearch.js new file mode 100644 index 0000000000..b0d7e7b526 --- /dev/null +++ b/js2/mwEmbed/libAddMedia/searchLibs/archiveOrgSearch.js @@ -0,0 +1,130 @@ +/* +* Archive.org Search +* +* archive.org uses the solr engine: +* more about solr here: +* http://lucene.apache.org/solr/ +*/ + +var archiveOrgSearch = function ( iObj ) { + return this.init( iObj ); +} +archiveOrgSearch.prototype = { + // Archive.org constants: + downloadUrl : 'http://www.archive.org/download/', + detailsUrl : 'http://www.archive.org/details/', + /* + * Inititalize the archiveOrgSearch class. + * archiveOrgSearch inherits the baseSearch class + */ + init:function( options ) { + var baseSearch = new baseRemoteSearch( options ); + for ( var i in baseSearch ) { + if ( typeof this[i] == 'undefined' ) { + this[i] = baseSearch[i]; + } else { + this['parent_' + i] = baseSearch[i]; + } + } + }, + /** + * Gets the search results from the api query + */ + getSearchResults:function() { + // call parent: + this.parent_getSearchResults(); + var _this = this; + js_log( 'f:getSearchResults for:' + $j( '#rsd_q' ).val() ); + // build the query var + var q = $j( '#rsd_q' ).val(); + // @@todo check advanced options: include audio and images media types + // for now force (Ogg video) & url based license + q += ' format:(Ogg video)'; + q += ' licenseurl:(http\\:\\/\\/*)'; + var reqObj = { + 'q': q, // just search for video atm + 'fl':"description,title,identifier,licenseurl,format,license,thumbnail", + 'wt':'json', + 'rows' : this.cp.limit, + 'start' : this.cp.offset + } + do_api_req( { + 'data':reqObj, + 'url':this.cp.api_url, + 'jsonCB':'json.wrf' + }, function( data ) { + _this.addResults( data ); + _this.loading = false; + } + ); + }, + /** + * Adds the search results to the local resultsObj + */ + addResults:function( data ) { + var _this = this; + if ( data.response && data.response.docs ) { + // Set result info: + this.num_results = data.response.numFound; + + for ( var resource_id in data.response.docs ) { + var resource = data.response.docs[resource_id]; + var rObj = { + // @@todo we should add .ogv or oga if video or audio: + 'titleKey' : resource.identifier + '.ogg', + 'resourceKey': resource.identifier, + 'link' : _this.detailsUrl + resource.identifier, + 'title' : resource.title, + 'poster' : _this.downloadUrl + resource.identifier + '/format=thumbnail', + 'poster_ani' : _this.downloadUrl + resource.identifier + '/format=Animated+Gif', + 'thumbwidth' : 160, + 'thumbheight': 110, + 'desc' : resource.description, + 'src' : _this.downloadUrl + resource.identifier + '/format=Ogg+video', + 'mime' : 'application/ogg', + // Set the license: (rsd is a pointer to the parent remoteSearchDriver ) + 'license' : this.rsd.getLicenseFromUrl( resource.licenseurl ), + 'pSobj' :_this + + }; + this.resultsObj[ resource_id ] = rObj; + } + } + }, + /** + * Gets some media metadata via a archive.org special entry point "avinfo" + */ + addResourceInfoCallback:function( rObj, callback ) { + var _this = this; + do_api_req( { + 'data': { 'avinfo' : 1 }, + 'url':_this.downloadUrl + rObj.resourceKey + '/format=Ogg+video' + }, function( data ) { + if ( data['length'] ) + rObj.duration = data['length']; + if ( data['width'] ) + rObj.width = data['width']; + if ( data['height'] ) + rObj.height = data['height']; + + callback(); + } ); + }, + /* + * Returns html to embed a given result Object ( rObj ) + */ + getEmbedHTML: function( rObj , options ) { + js_log( 'getEmbedHTML:: ' + rObj.poster ); + if ( !options ) + options = { }; + var id_attr = ( options['id'] ) ? ' id = "' + options['id'] + '" ': ''; + if ( rObj.duration ) { + var src = rObj.src + '?t=0:0:0/' + seconds2npt( rObj.duration ); + } else { + var src = rObj.src; + } + if ( rObj.mime == 'application/ogg' || rObj.mime == 'audio/ogg' || rObj.mime == 'video/ogg' ) { + return ''; + } + } +} diff --git a/js2/mwEmbed/libAddMedia/searchLibs/baseRemoteSearch.js b/js2/mwEmbed/libAddMedia/searchLibs/baseRemoteSearch.js new file mode 100644 index 0000000000..7065d17903 --- /dev/null +++ b/js2/mwEmbed/libAddMedia/searchLibs/baseRemoteSearch.js @@ -0,0 +1,380 @@ +/* +* Base remote search Object. +* provides the base class for the other search system to extend. +*/ +loadGM( { + "mwe-imported_from" : "$1 imported from [$2 $3]. See the original [$4 resource page] for more information.", + "mwe-import-description" : "$1, imported from $2" +} ); + +/* +* rsd_default_rss_item_mapping +* +* @key is name of rObj variable +* @value is where to find the value in the item xml +* +* *value format:* +* . indicates multiple tags +* @ separates the tag from attribute list +* {.}tag_name@{attribute1|attribute2} +* +* Also see mapAttributeToResource function bellow +* +* FIXME should switch this over to something like Xpath if we end up parsing a lot of rss formats +*/ +var rsd_default_rss_item_mapping = { + 'poster' : 'media:thumbnail@url', + 'roe_url' : 'media:roe_embed@url', + 'person' : 'media:person@label|url', + 'parent_clip':'media:parent_clip@url', + 'bill' : 'media:bill@label|url', + 'title' : 'title', + 'link' : 'link', + 'desc' : 'description', + // multiple items + 'category' : '.media:category@label|url' +}; + +var baseRemoteSearch = function( iObj ) { + return this.init( iObj ); +}; +baseRemoteSearch.prototype = { + + completed_req:0, + num_req:0, + + // ResultsObj holds the array of results + resultsObj: { }, + + // Default search result values for paging: + offset :0, + limit : 30, + more_results : false, + num_results : 0, + + /** + * Initialise the baseRemoteSearch + * @param {Object} options The set of options for the remote search class + */ + init: function( options ) { + js_log( 'mvBaseRemoteSearch:init' ); + for ( var i in options ) { + this[i] = options[i]; + } + return this; + }, + getSearchResults:function() { + // Empty out the current results before issuing a request + this.resultsObj = { }; + + // Do global getSearchResults bindings + this.last_query = $j( '#rsd_q' ).val(); + this.last_offset = this.cp.offset; + + // Set the loading flag: + this.loading = true; + }, + /* + * Parses and adds video rss based input format + * @param {XML Nodes} data the data to be parsed + * @param {String} provider_url the source url (used to generate absolute links) + */ + addRSSData:function( data , provider_url ) { + js_log( 'f:addRSSData' ); + var _this = this; + var http_host = ''; + var http_path = ''; + if ( provider_url ) { + pUrl = mw.parseUri( provider_url ); + http_host = pUrl.protocol + '://' + pUrl.authority; + http_path = pUrl.directory; + } + var items = data.getElementsByTagName( 'item' ); + // js_log('found ' + items.length ); + $j.each( items, function( inx, item ) { + var rObj = { }; + for ( var attr in rsd_default_rss_item_mapping ) { + _this.mapAttributeToResource( rObj, item, attr ); + } + // make relative urls absolute: + var url_param = new Array( 'src', 'poster' ); + for ( var j = 0; j < url_param.length; j++ ) { + var p = url_param[j]; + if ( typeof rObj[p] != 'undefined' ) { + if ( rObj[p].substr( 0, 1 ) == '/' ) { + rObj[p] = http_host + rObj[p]; + } + if ( mw.parseUri( rObj[i] ).host == rObj[p] ) { + rObj[p] = http_host + http_path + rObj[p]; + } + } + } + // Force a mime type. In the future generalize for other RSS feeds + rObj['mime'] = 'video/ogg'; + // Add pointer to parent search obj:( this.cp.limit )? this.cp.limit : this.limit, + + rObj['pSobj'] = _this; + + // Set target_resource_title + _this.updateTargetResourceTitle( rObj ); + + // add the result to the result set: + _this.resultsObj[ inx ] = rObj; + _this.num_results++; + } ); + }, + /* + * Maps a given attribute to a resource object per mapping defined in + * rsd_default_rss_item_mapping + * + * @param {Object} rObj the resource object + * @param {XML Node} the xml result node + * @param {attr} the name attribute we are maping to the resource object + */ + mapAttributeToResource: function( rObj, item, attr ){ + var selector = rsd_default_rss_item_mapping[ attr ].split( '@' ); + var flag_multiple = ( selector[0].substr( 0, 1 ) == '.' ) ? true : false; + if ( flag_multiple ) { + rObj[ attr ] = new Array(); + var tag_name = selector[0].substr( 1 ); + } else { + var tag_name = selector[0]; + } + + var attr_name = null; + if ( typeof selector[1] != 'undefined' ) { + attr_name = selector[1]; + if ( attr_name.indexOf( '|' ) != -1 ) + attr_name = attr_name.split( '|' ); + } + + $j.each( item.getElementsByTagName( tag_name ), function ( inx, node ) { + var tag_val = ''; + if ( node != null && attr_name == null ) { + if ( node.childNodes[0] != null ) { + // trim and strip html: + tag_val = $j.trim( node.firstChild.nodeValue ).replace(/(<([^>]+)>)/ig,""); + } + } + if ( node != null && attr_name != null ) { + if ( typeof attr_name == 'string' ) { + tag_val = $j.trim( $j( node ).attr( attr_name ) ); + } else { + var attr_vals = { }; + for ( var j in attr_name ) { + if ( $j( node ).attr( attr_name[j] ).length != 0 ) + attr_vals[ attr_name[j] ] = $j.trim( $j(node).attr( attr_name[j]) ).replace(/(<([^>]+)>)/ig,""); + } + tag_val = attr_vals ; + } + } + if ( flag_multiple ) { + rObj[ attr ].push( tag_val ) + } else { + rObj[ attr ] = tag_val; + } + } ); + // Nothing to return we update the "rObj" directly + }, + + /** + * Get the html representation of the resource Object parameter + */ + getEmbedHTML: function( rObj , options ) { + if ( !options ) + options = { }; + // Set up the output var with the default values: + if(! options.width ) + options.width = rObj.width; + if(! options.height ) + options.height = rObj.height + + var outHtml = ''; + if ( options['max_height'] ) { + options.height = ( options.max_height > rObj.height ) ? rObj.height : options.max_height; + options.width = ( rObj.width / rObj.height ) * options.height; + } + options.style = ''; + if( options.height ) + options.style += 'height:' + options.height + 'px;'; + + if( options.width ) + options.style += 'width:' + options.width + 'px;'; + + if ( rObj.mime.indexOf( 'image' ) != -1 ) + outHtml = this.getImageEmbedHTML( rObj, options ); + + if ( rObj.mime == 'application/ogg' || rObj.mime == 'video/ogg' || rObj.mime == 'audio/ogg' ) { + // Setup the attribute html: + var ahtml = ( options['id'] ) ? ' id = "' + options['id'] + '" ': ''; + ahtml+= 'src="' + rObj.src + '" ' + + 'style="' + options.style + '" ' + + 'poster="' + rObj.poster + '" '; + + if ( rObj.mime == 'application/ogg' || rObj.mime == 'video/ogg' ) { + outHtml = ''; + } + + if ( rObj.mime == 'audio/ogg' ) { + outHtml = ''; + } + } + + // Return the output. Wrap with a description div if remote_insert_description is on. + if( outHtml != '') + return ( this.rsd['remote_insert_description'] ) ? + this.wrapHtmlDesc(rObj, options, outHtml) : + outHtml; + + // No output give error: + js_log( "ERROR:: no embed code for mime type: " + rObj.mime ); + return 'Error missing embed code for: ' + escape( rObj.mime ); + }, + wrapHtmlDesc: function( rObj, options, outHtml ) { + var stripedTitle = rObj.title.replace( /File:|Image:|.jpg|.png|.ogg|.ogv|.oga|.svg/ig, ''); + + var titleLink = '' + + stripedTitle + ''; + var cpTitle = gM('rsd-' + this.cp.id + '-title'); + var remoteProviderLink = '' + + cpTitle + ''; + return '
    ' + + outHtml + + gM( 'mwe-import-description', [titleLink, remoteProviderLink]) + + '
    '; + }, + /** + * Get the embed html specifically for an image type resource Object. + */ + getImageEmbedHTML:function( rObj, options ) { + // if crop is null do base output: + var imgHtml = ''; + if ( rObj.crop == null ) + return imgHtml; + // Else do crop output: + return '
    ' + + '
    ' + + imgHtml + + '
    ' + + '
    '; + }, + /** + * Gets an image object from a requested transformation via callback + * ( letting api search implementations query the remote server for a + * given transformation ) + * + * By default just return the existing image. + */ + getImageObj:function( rObj, size, callback ) { + callback( { + 'url' : rObj.poster + } ); + }, + /** + * Gets the inline wikiText description of the resource Object + */ + getInlineDescWiki:function( rObj ) { + // return striped html & trim white space + if ( rObj.desc ) + return $j.trim( rObj.desc.replace(/(<([^>]+)>)/ig,"") ); + // No Description available: + return ''; + }, + /** + * Get the license wikiText tag for a given resource Object. + * + * By default license permission wiki text is cc based template mapping + * (does not confirm the templates actually exist) + */ + getPermissionWikiTag: function( rObj ) { + if ( !rObj.license ) + return '';// no license info + + // First check if we have a special license template tag already set: + if( rObj.license_template_tag ) + return '{{' + rObj.license_template_tag + '}}'; + + // Check that its a defined creative commons license key: + if ( this.rsd.licenses.cc.licenses[ rObj.license.key ] != 'undefined' ) { + return '{{Cc-' + rObj.license.key + '}}'; + } else if ( rObj.license.lurl ) { + return '{{Template:External_License|' + rObj.license.lurl + '}}'; + } + + }, + /** + * Gets the resource import description text + */ + getImportResourceDescWiki:function( rObj ) { + return gM( 'mwe-imported_from', [rObj.title, this.cp.homepage, gM('rsd-' + this.cp.id + '-title'), rObj.link] ); + }, + /** + * Get any extra wikitext description for the given resource object. + * For content outside of the main template description, + * like categories or additional wikitext notes. + * + * By default its an empty string. + */ + getExtraResourceDescWiki:function( rObj ) { + return ''; + }, + + /** + * Gets a image transformation + * by default it just return the poster + */ + getImageTransform:function( rObj, opt ) { + return rObj.poster; + }, + + /** + * Adds additional resource information post clip embedding. + */ + addResourceInfoFromEmbedInstance : function( rObj, eb_id ) { + return rObj; + }, + + /** + * Adds resource info with a callback function + * + * Use full for grabbing extra info that is not available in the initial + * search results api request. + */ + addResourceInfoCallback:function( rObj, callback ) { + callback(); + }, + + /** + * Get the wiki embed code for a given resource object + */ + getEmbedWikiCode:function( rObj ) { + var layout = ( rObj.layout ) ? rObj.layout:"right" + var o = '[[' + this.rsd.fileNS + ':' + rObj.target_resource_title + '|thumb|' + layout; + + if ( !rObj.target_width && rObj.width ) { + rObj.target_width = ( rObj.width < 640 ) ? rObj.width: '640'; + } + + if ( rObj.target_width ) + o += '|' + rObj.target_width + 'px'; + + if ( rObj.inlineDesc ) + o += '|' + rObj.inlineDesc; + + o += ']]'; + return o; + }, + /** + * Updates / normalizes the target_resource_title + */ + updateTargetResourceTitle:function( rObj ) { + rObj.target_resource_title = rObj.titleKey.replace( /^(File:|Image:)/ , '' ); + rObj.target_resource_title = this.cp.resource_prefix + rObj.target_resource_title; + } +} diff --git a/js2/mwEmbed/libAddMedia/searchLibs/flickrSearch.js b/js2/mwEmbed/libAddMedia/searchLibs/flickrSearch.js new file mode 100644 index 0000000000..c96bb2c19e --- /dev/null +++ b/js2/mwEmbed/libAddMedia/searchLibs/flickrSearch.js @@ -0,0 +1,172 @@ +/* + * Basic flickr search uses flickr jsonp api + * http://www.flickr.com/services/api/ + * + * + * we look for licenses from method=flickr.photos.licenses.getInfo + * per http://commons.wikimedia.org/wiki/Special:Upload?uselang=fromflickr + * we are interested in: + * (4) Attribution License + * (5) Attribution-ShareAlike License, + * (7) No known copyright restrictions, + * (8) United States Government Work + */ + +var flickrSearch = function ( iObj ) { + return this.init( iObj ); +} +flickrSearch.prototype = { + dtUrl : 'http://www.flickr.com/photos/', + // @@todo probably would be good to read the api-key from configuration + apikey : '2867787a545cc66c0bce6f2e57aca1d1', + // What license we are interested in + _license_keys: '4,5,7,8', + _srctypes: ['t', 'sq', 's', 'm', 'o'], + licenseMap: { + '4' : 'http://creativecommons.org/licenses/by/3.0/', + '5' : 'http://creativecommons.org/licenses/by-sa/3.0/', + '7' : 'http://www.flickr.com/commons/usage/', + '8' : 'http://www.usa.gov/copyright.shtml' + }, + /** + * Initialize the flickr Search with provided options + */ + init:function( options ) { + var baseSearch = new baseRemoteSearch( options ); + for ( var i in baseSearch ) { + if ( typeof this[i] == 'undefined' ) { + this[i] = baseSearch[i]; + } else { + this['parent_' + i] = baseSearch[i]; + } + } + }, + /** + * Gets the Search results setting _loading flag to false once results have been added + */ + getSearchResults:function() { + var _this = this; + js_log( "flickr::getSearchResults" ); + // call parent (sets loading sate and other setup stuff) + this.parent_getSearchResults(); + // setup the flickr request: + var reqObj = { + 'method':'flickr.photos.search', + 'format':'json', + 'license':this._license_keys, + 'api_key':this.apikey, + 'per_page': this.cp.limit, + 'page' : this.cp.offset, + 'text': $j( '#rsd_q' ).val(), + 'extras' : 'license, date_upload, date_taken, owner_name, icon_server, original_format, last_update, geo, tags, machine_tags, o_dims, views, media, path_alias, url_sq, url_t, url_s, url_m, url_o' + } + do_api_req( { + 'data': reqObj, + 'url':this.cp.api_url, + 'jsonCB':'jsoncallback', + }, function( data ) { + _this.addResults( data ); + _this.loading = false; + } ); + }, + /** + * Adds Results for a given data response from api query + */ + addResults:function( data ) { + var _this = this; + if ( data.photos && data.photos.photo ) { + // set result info: + this.num_results = data.photos.total; + if ( this.num_results > this.cp.offset + this.cp.limit ) { + this.more_results = true; + } + for ( var resource_id in data.photos.photo ) { + var sourceResource = data.photos.photo[ resource_id ]; + var rObj = _this.getResourceObject( sourceResource ); + _this.resultsObj[ resource_id ] = rObj; + } + } + }, + /** + * Gets an individual resource object from a given source Resource + */ + getResourceObject: function( resource ){ + var _this = this; + var rObj = { + 'titleKey' : resource.title + '.jpg', + 'resourceKey': resource.id, + 'link' : _this.dtUrl + resource.pathalias + '/' + resource.id, + 'title' : resource.title, + 'thumbwidth' : resource.width_t, + 'thumbheight': resource.height_t, + 'desc' : resource.title, + // Set the license + 'license' : this.rsd.getLicenceFromUrl( _this.licenseMap[ resource.license ] ), + 'pSobj' : _this, + // Assume image/jpeg for flickr response + 'mime' : 'image/jpeg' + }; + // Add all the provided src types that are avaliable + rObj['srcSet'] = { }; + for ( var i in _this._srctypes ) { + var st = _this._srctypes[i]; + // if resource has a url add it to the srcSet: + if ( resource['url_' + st] ) { + rObj['srcSet'][st] = { + 'h': resource['height_' + st], + 'w': resource['width_' + st], + 'src': resource['url_' + st] + } + // Set src to the largest + rObj['src'] = resource['url_' + st]; + } + } + return rObj; + }, + /** + * return image transform via callback + */ + getImageObj:function( rObj, size, callback ) { + if ( size.width ) { + var skey = this.getSrcTypeKey( rObj, size.width ) + callback ( { + 'url' : rObj.srcSet[ skey ].src, + 'width' : rObj.srcSet[ skey ].w, + 'height' : rObj.srcSet[ skey ].h + } ); + } + }, + /** + * Gets an image transformation based a SrcTypeKey gennerated by the requested options + */ + getImageTransform:function( rObj, options ) { + if ( options.width ) { + return rObj.srcSet[ this.getSrcTypeKey( rObj, options.width ) ].src; + } + return rObj.srcSet[ _srctypes[_srctypes.length-1] ]; + }, + getSrcTypeKey:function( rObj, width ) { + if ( width <= 75 ) { + if ( rObj.srcSet['sq'] ) + return 'sq'; + } else if ( width <= 100 ) { + if ( rObj.srcSet['t'] ) + return 't'; + } else if ( width <= 240 ) { + if ( rObj.srcSet['s'] ) + return 's'; + } else if ( width <= 500 ) { + if ( rObj.srcSet['m'] ) + return 'm'; + } else { + if ( rObj.srcSet['o'] ) + return 'o'; + } + // original was missing return medium or small + if ( rObj.srcSet['m'] ) + return 'm'; + if ( rObj.srcSet['s'] ) + return 's'; + + } +} diff --git a/js2/mwEmbed/libAddMedia/searchLibs/mediaWikiSearch.js b/js2/mwEmbed/libAddMedia/searchLibs/mediaWikiSearch.js new file mode 100644 index 0000000000..583fbc82c1 --- /dev/null +++ b/js2/mwEmbed/libAddMedia/searchLibs/mediaWikiSearch.js @@ -0,0 +1,357 @@ +var mediaWikiSearch = function( iObj ) { + return this.init( iObj ); +}; +mediaWikiSearch.prototype = { + init:function( iObj ) { + // init base class and inherit: + var baseSearch = new baseRemoteSearch( iObj ); + for ( var i in baseSearch ) { + if ( typeof this[i] == 'undefined' ) { + this[i] = baseSearch[i]; + } else { + this['parent_' + i] = baseSearch[i]; + } + } + // inherit the cp settings for + }, + // returns a rObj by title + addByTitle:function( title , callback, redirect_count ) { + js_log( "AddByTitle::" + title ); + var _this = this; + if ( !redirect_count ) + redirect_count = 0; + if ( redirect_count > 5 ) { + js_log( 'Error: addByTitle too many redirects' ); + callback( false ); + return false; + } + var reqObj = { + 'action':'query', + 'titles':'File:' + title, + 'prop':'imageinfo|revisions|categories', + 'iiprop':'url|mime|size', + 'iiurlwidth': parseInt( this.rsd.thumb_width ), + 'rvprop':'content' + } + do_api_req( { + 'data':reqObj, + 'url':this.cp.api_url + }, function( data ) { + // check for redirect + for ( var i in data.query.pages ) { + var page = data.query.pages[i]; + if ( page.revisions[0]['*'] && page.revisions[0]['*'].indexOf( '#REDIRECT' ) === 0 ) { + var re = new RegExp( /[^\[]*\[\[([^\]]*)/ ); + var pt = page.revisions[0]['*'].match( re ); + if ( pt[1] ) { + _this.addByTitle( pt[1], callback, redirect_count++ ); + return ; + } else { + js_log( 'Error: addByTitle could not proccess redirect' ); + callback( false ); + return false; + } + } + } + // if not a redirect do the callback directly: + callback( _this.addSingleResult( data ) ); + } + ); + }, + clearResults:function() { + this.resultsObj = { }; + this.last_query = ''; + }, + // update the resultObj with recently uploaded items by current User: + getUserRecentUploads:function( wgUser, callback ) { + var _this = this; + do_api_req( { + 'url':this.cp.api_url, + 'data': { + 'action':'query', + 'list':'recentchanges', + 'rcnamespace':6, // only files + 'rcuser': wgUser, + 'rclimit':15 // get last 15 uploaded files + } + }, function( data ) { + var titleSet = { }; + var titleStr = '' + var pound = ''; + // loop over the data and group by title + if ( data.query && data.query.recentchanges ) { + for ( var i in data.query.recentchanges ) { + var rc = data.query.recentchanges[i]; + if ( !titleSet[ rc.title ] ) { + titleSet[ rc.title ] = true; + titleStr += pound + rc.title; + pound = '|'; + } + } + } + // now run the actual query ( too bad we can't use recentchanges as a generator ) + // bug 20563 + do_api_req( { + 'data' : { + 'action' : 'query', + 'titles' : titleStr, + 'prop' : 'imageinfo|revisions|categories', + 'iiprop' : 'url|mime|size', + 'iiurlwidth': parseInt( _this.rsd.thumb_width ), + 'rvprop':'content' + }, + 'url':_this.cp.api_url + }, function( data ) { + _this.clearResults(); + _this.addResults( data ); + if ( callback ) + callback(); + } ); + } ); + }, + getSearchResults:function() { + // Call parent: + this.parent_getSearchResults(); + // Set local ref: + var _this = this; + + js_log( 'f:getSearchResults for:' + $j( '#rsd_q' ).val() ); + // Do two queries against the Image / File / MVD namespace: + + // Build the image request object: + var reqObj = { + 'action':'query', + 'generator':'search', + 'gsrsearch': $j( '#rsd_q' ).val(), + 'gsrnamespace':6, // (only search the "file" namespace (audio, video, images) + 'gsrwhat':'title', + 'gsrlimit': this.cp.limit, + 'gsroffset': this.cp.offset, + 'prop':'imageinfo|revisions|categories', + 'iiprop':'url|mime|size', + 'iiurlwidth': parseInt( this.rsd.thumb_width ), + 'rvprop':'content' + }; + // Set up the number of request: + this.completed_req = 0; + this.num_req = 1; + // Setup the number of requests result flag: + // Also do a request for page titles (would be nice if api could query both at the same time) + reqObj['gsrwhat'] = 'text'; + do_api_req( { + 'data':reqObj, + 'url':this.cp.api_url + }, function( data ) { + js_log( 'mediaWikiSearch: got data response' ); + // parse the return data + _this.addResults( data ); + // _this.checkRequestDone(); //only need if we do two queries one for title one for text + _this.loading = false; + } ); + }, + // same as below but returns your rObj for convenience + addSingleResult:function( data ) { + return this.addResults( data, true ); + }, + addResults:function( data, returnFirst ) { + js_log( "f:addResults" ); + var _this = this + // check if we have + if ( typeof data['query-continue'] != 'undefined' ) { + if ( typeof data['query-continue'].search != 'undefined' ) + this.more_results = true; + } + // Make sure we have pages to idorate: + if ( data.query && data.query.pages ) { + for ( var page_id in data.query.pages ) { + var page = data.query.pages[ page_id ]; + + // Make sure the reop is shared (don't show for now it confusing things) + // @@todo support remote repository better + if ( page.imagerepository == 'shared' ) { + continue; + } + + // Make sure the page is not a redirect + if ( page.revisions && page.revisions[0] && + page.revisions[0]['*'] && page.revisions[0]['*'].indexOf( '#REDIRECT' ) === 0 ) { + // skip page is redirect + continue; + } + // Skip if its an empty or missing imageinfo: + if ( !page.imageinfo ) + continue; + var rObj = { + 'id' : page_id, + 'titleKey' : page.title, + 'link' : page.imageinfo[0].descriptionurl, + 'title' : page.title.replace(/File:.jpg|.png|.svg|.ogg|.ogv|.oga/ig, ''), + 'poster' : page.imageinfo[0].thumburl, + 'thumbwidth' : page.imageinfo[0].thumbwidth, + 'thumbheight': page.imageinfo[0].thumbheight, + 'orgwidth' : page.imageinfo[0].width, + 'orgheight' : page.imageinfo[0].height, + 'mime' : page.imageinfo[0].mime, + 'src' : page.imageinfo[0].url, + 'desc' : page.revisions[0]['*'], + // add pointer to parent search obj: + 'pSobj' :_this, + 'meta': { + 'categories':page.categories + } + }; + /* + //to use once we get the wiki-text parser in shape + var pObj = mw.parser.pNew( rObj.desc ); + //structured data on commons is based on the "information" template: + var tmplInfo = pObj.templates( 'information' ); + rObj.desc = tmplInfo.description + */ + + // Attempt to parse out the description current user desc from the commons template: + // @@todo these could be combined to a single regEx + // or better improve the wiki-text parsing and use above + var desc = rObj.desc.match( /\|\s*description\s*=\s*(([^\n]*\n)*)\|\s*source=/i ); + if ( desc && desc[1] ) { + rObj.desc = $j.trim( desc[1] ); + // attempt to get the user language if set: + if ( typeof wgUserLanguage != 'undefined' && wgUserLanguage ) { + // for some reason the RegExp object is not happy: + var reg = new RegExp( '\{\{\s*' + wgUserLanguage + '([^=]*)=([^\}]*)\}\}', 'gim' ); + var langMatch = reg.exec( rObj.desc ); + if ( langMatch && langMatch[2] ) { + rObj.desc = langMatch[2]; + } else { + // try simple lang template form: + var reg = new RegExp( '\{\{\s*' + wgUserLanguage + '\\|([^\}]*)\}\}', 'gim' ); + var langMatch = reg.exec( rObj.desc ); + if ( langMatch && langMatch[1] ) { + rObj.desc = langMatch[1]; + } + } + } + } + + // Likely a audio clip if no poster and type application/ogg + // @@todo we should return audio/ogg for the mime type or some other way to specify its "audio" + if ( ! rObj.poster && rObj.mime == 'application/ogg' ) { + rObj.mime = 'audio/ogg'; + } + // Add to the resultObj + this.resultsObj[page_id] = rObj; + + // If returnFirst flag: + if ( returnFirst ) + return this.resultsObj[page_id]; + + + this.num_results++; + // for(var i in this.resultsObj[page_id]){ + // js_log('added: '+ i +' '+ this.resultsObj[page_id][i]); + // } + } + } else { + js_log( 'no results:' + data ); + } + }, + // Check request done used for when we have multiple requests to check before formating results. + checkRequestDone:function() { + // Display output if done: + this.completed_req++; + if ( this.completed_req == this.num_req ) { + this.loading = 0; + } + }, + getImageObj:function( rObj, size, callback ) { + if ( rObj.mime == 'application/ogg' ) + return callback( { 'url':rObj.src, 'poster' : rObj.url } ); + + // This could be depreciated if thumb.php support is standard + var reqObj = { + 'action':'query', + 'format':'json', + 'titles':rObj.titleKey, + 'prop':'imageinfo', + 'iiprop':'url|size|mime' + } + // Set the width: + if ( size.width ) + reqObj['iiurlwidth'] = size.width; + js_log( 'going to do req: ' + this.cp.api_url + ' ' + reqObj ); + do_api_req( { + 'data':reqObj, + 'url' : this.cp.api_url + }, function( data ) { + var imObj = { }; + for ( var page_id in data.query.pages ) { + var iminfo = data.query.pages[ page_id ].imageinfo[0]; + // store the orginal width: + imObj['org_width'] = iminfo.width; + // check if thumb size > than image size and is jpeg or png (it will not scale well above its max res) + if ( ( iminfo.mime == 'image/jpeg' || iminfo == 'image/png' ) && + iminfo.thumbwidth > iminfo.width ) { + imObj['url'] = iminfo.url; + imObj['width'] = iminfo.width; + imObj['height'] = iminfo.height; + } else { + imObj['url'] = iminfo.thumburl; + imObj['width'] = iminfo.thumbwidth; + imObj['height'] = iminfo.thumbheight; + } + } + js_log( 'getImageObj: get: ' + size.width + ' got url:' + imObj.url ); + callback( imObj ); + } ); + }, + // the insert image function + insertImage:function( cEdit ) { + if ( !cEdit ) + var cEdit = _this.cEdit; + }, + getInlineDescWiki:function( rObj ) { + var desc = this.parent_getInlineDescWiki( rObj ); + + // Strip categories for inline Desc: (should strip license tags too but not as easy) + desc = desc.replace( /\[\[Category\:[^\]]*\]\]/gi, '' ); + + // Just grab the description tag for inline desc: + var descMatch = new RegExp( /Description=(\{\{en\|)?([^|]*|)/ ); + var dparts = desc.match( descMatch ); + + if ( dparts && dparts.length > 1 ) { + desc = ( dparts.length == 2 ) ? dparts[1] : dparts[2].replace( '}}', '' ); + desc = ( desc.substr( 0, 2 ) == '1=' ) ? desc.substr( 2 ): desc; + return desc; + } + // Hackish attempt to strip templates + desc = desc.replace( /\{\{[^\}]*\}\}/gi, '' ); + // strip any nexted template closures + desc = desc.replace( /\}\}/gi, '' ); + // strip titles + desc = desc.replace( /\=\=[^\=]*\=\=/gi, '' ); + + // else return the title since we could not find the desc: + js_log( 'Error: No Description Tag, Using::' + desc ); + return desc; + }, + // Returns the inline wikitext for insertion (template based crops for now) + getEmbedWikiCode: function( rObj ) { + // Set default layout to right justified + var layout = ( rObj.layout ) ? rObj.layout:"right" + // if crop is null do base output: + if ( rObj.crop == null ) + return this.parent_getEmbedWikiCode( rObj ); + // Using the preview crop template: http://en.wikipedia.org/wiki/Template:Preview_Crop + // @@todo should be replaced with server side cropping + return '{{Preview Crop ' + "\n" + + '|Image = ' + rObj.target_resource_title + "\n" + + '|bSize = ' + rObj.width + "\n" + + '|cWidth = ' + rObj.crop.w + "\n" + + '|cHeight = ' + rObj.crop.h + "\n" + + '|oTop = ' + rObj.crop.y + "\n" + + '|oLeft = ' + rObj.crop.x + "\n" + + '|Location =' + layout + "\n" + + '|Description =' + rObj.inlineDesc + "\n" + + '}}'; + } +} \ No newline at end of file diff --git a/js2/mwEmbed/libAddMedia/searchLibs/metavidSearch.js b/js2/mwEmbed/libAddMedia/searchLibs/metavidSearch.js new file mode 100644 index 0000000000..0d7ddb92cf --- /dev/null +++ b/js2/mwEmbed/libAddMedia/searchLibs/metavidSearch.js @@ -0,0 +1,208 @@ +/* +* API modes (implementations should call these objects which inherit the mvBaseRemoteSearch +*/ +loadGM( { + "mwe-stream_title" : "$1 $2 to $3" +} ); +var metavidSearch = function( iObj ) { + return this.init( iObj ); +}; +metavidSearch.prototype = { + defaultReq: { // set up the default request paramaters + 'order':'recent', + 'feed_format':'json_rss', + 'cb_inx': 1 // Not really used (we should update the metavid json retrun system) + }, + init:function( iObj ) { + // init base class and inherit: + var baseSearch = new baseRemoteSearch( iObj ); + for ( var i in baseSearch ) { + if ( typeof this[i] == 'undefined' ) { + this[i] = baseSearch[i]; + } else { + this['parent_' + i] = baseSearch[i]; + } + } + }, + getSearchResults:function() { + // call parent: + this.parent_getSearchResults(); + // set local ref: + var _this = this; + js_log( 'metavidSearch::getSearchResults()' ); + // Proccess all options + var url = this.cp.api_url; + var reqObj = $j.extend({}, this.defaultReq); + reqObj[ 'f[0][t]' ] = 'match'; + reqObj[ 'f[0][v]' ] = $j( '#rsd_q' ).val(); + + // add offset limit: + reqObj[ 'limit' ] = this.cp.limit; + reqObj[ 'offset' ] = this.cp.offset; + + do_api_req({ + 'url' : url, + 'jsonCB' : 'cb', + 'data' : reqObj + }, function( data ) { + js_log( 'mvSearch: got data response::' ); + var xmldata = ( data && data['pay_load'] ) ? mw.parseXML( data['pay_load'] ) : false; + if( !xmldata ){ + // XML Error or No results: + _this.resultsObj = {}; + _this.loading = 0; + return ; + } + + // Add the data xml payload with context url: + _this.addRSSData( xmldata , url ); + + // Do some metavid specific pos processing on the rObj data: + for ( var i in _this.resultsObj ) { + var rObj = _this.resultsObj[i]; + var proe = mw.parseUri( rObj['roe_url'] ); + rObj['start_time'] = proe.queryKey['t'].split( '/' )[0]; + rObj['end_time'] = proe.queryKey['t'].split( '/' )[1]; + rObj['stream_name'] = proe.queryKey['stream_name']; + + // All metavid content is public domain: + rObj['license'] = _this.rsd.getLicenseFromKey( 'pd' ); + + // Transform the title into a wiki_safe title: + rObj['titleKey'] = _this.getTitleKey( rObj ); + + // Default width of metavid clips: + rObj['target_width'] = 400; + + rObj['author'] = 'US Government'; + + // Add in the date as UTC "toDateString" : + var d = _this.getDateFromLink( rObj.link ); + rObj['date'] = d.toDateString(); + + // Set the license_template_tag ( all metavid content is PD-USGov ) + rObj['license_template_tag'] = 'PD-USGov'; + } + // done loading: + _this.loading = 0; + } ); + }, + /** + * Get a Title key for the assset name inside the mediaWiki system + */ + getTitleKey:function( rObj ) { + return rObj['stream_name'] + '_part_' + rObj['start_time'].replace(/:/g, '.' ) + '_to_' + rObj['end_time'].replace(/:/g, '.' ) + '.ogv'; + }, + getTitle:function( rObj ) { + var sn = rObj['stream_name'].replace( /_/g, ' ' ); + sn = sn.charAt( 0 ).toUpperCase() + sn.substr( 1 ); + return gM( 'mwe-stream_title', [ sn, rObj.start_time, rObj.end_time ] ); + }, + getExtraResourceDescWiki:function( rObj ) { + var o = "\n"; + // check for person + if ( rObj.person && rObj.person['label'] ) + o += '* featuring [[' + rObj.person['label'] + ']]' + "\n"; + + if ( rObj.parent_clip ) + o += '* part of longer [' + rObj.parent_clip + ' video clip]' + "\n"; + + if ( rObj.person && rObj.person['url'] && rObj.person['label'] ) + o += '* also see speeches by [' + $j.trim( rObj.person.url ) + ' ' + rObj.person['label'] + ']' + "\n"; + + // check for bill: + if ( rObj.bill && rObj.bill['label'] && rObj.bill['url'] ) + o += '* related to bill: [[' + rObj.bill['label'] + ']] more bill [' + rObj.bill['url'] + ' video clips]' + "\n"; + return o; + }, + // format is "quote" followed by [[name of person]] + getInlineDescWiki:function( rObj ) { + var o = this.parent_getInlineDescWiki( rObj ); + // add in person if found + if ( rObj.person && rObj.person['label'] ) { + o = $j.trim( o.replace( rObj.person['label'], '' ) ); + // trim leading : + if ( o.substr( 0, 1 ) == ':' ) + o = o.substr( 1 ); + // add quotes and person at the end: + var d = this.getDateFromLink( rObj.link ); + o = '"' + o + '" [[' + rObj.person['label'] + ']] on ' + d.toDateString(); + } + // could do ref or direct link: + o += ' \'\'[' + $j.trim( rObj.link ) + ' source clip]\'\' '; + + // var o= '"' + o + '" by [[' + rObj.person['label'] + ']] '+ + // '[' + rObj.link + ' Metavid Source Page] for ' + rObj.title +''; + return o; + }, + // give an updated start and end time updates the title and url + applyVideoAdj: function( rObj ) { + js_log( 'mv ApplyVideoAdj::' ); + // update the titleKey: + rObj['titleKey'] = this.getTitleKey( rObj ); + + // update the title: + rObj['title'] = this.getTitle( rObj ); + + // update the interface: + js_log( 'update title to: ' + rObj['title'] ); + $j( '#rsd_resource_title' ).html( gM( 'rsd_resource_edit', rObj['title'] ) ); + + // if the video is "roe" based select the ogg stream + if ( rObj.roe_url && rObj.pSobj.cp.stream_import_key ) { + var source = $j( '#embed_vid' ).get( 0 ).media_element.getSourceById( rObj.pSobj.cp.stream_import_key ); + if ( !source ) { + js_error( 'Error::could not find source: ' + rObj.pSobj.cp.stream_import_key ); + } else { + rObj['src'] = source.getURI(); + js_log( "g src_key: " + rObj.pSobj.cp.stream_import_key + ' src:' + rObj['src'] ) ; + return true; + } + } + }, + getEmbedHTML:function( rObj , options ) { + if ( !options ) + options = { }; + var id_attr = ( options['id'] ) ? ' id = "' + options['id'] + '" ': ''; + var style_attr = ( options['max_width'] ) ? ' style="width:' + options['max_width'] + 'px;"':''; + // @@maybe check type here ? + if ( options['only_poster'] ) { + return ''; + } else { + return ''; + } + }, + getImageTransform:function( rObj, opt ) { + if ( opt.width <= 80 ) { + return getURLParamReplace( rObj.poster, { 'size' : "icon" } ) + } else if ( opt.width <= 160 ) { + return getURLParamReplace( rObj.poster, { 'size' : "small" } ) + } else if ( opt.width <= 320 ) { + return getURLParamReplace( rObj.poster, { 'size' : 'medium' } ) + } else if ( opt.width <= 512 ) { + return getURLParamReplace( rObj.poster, { 'size' : 'large' } ) + } else { + return getURLParamReplace( rObj.poster, { 'size' : 'full' } ) + } + }, + addResourceInfoFromEmbedInstance : function( rObj, embed_id ) { + var sources = $j( '#' + embed_id ).get( 0 ).media_element.getSources(); + rObj.other_versions = '*[' + rObj['roe_url'] + ' XML of all Video Formats and Timed Text]' + "\n"; + for ( var i in sources ) { + var cur_source = sources[i]; + // rObj.other_versions += '*['+cur_source.getURI() +' ' + cur_source.title +']' + "\n"; + if ( cur_source.id == this.cp.target_source_id ) + rObj['url'] = cur_source.getURI(); + } + // js_log('set url to: ' + rObj['url']); + return rObj; + }, + getDateFromLink:function( link ) { + var dateExp = new RegExp( /_([0-9]+)\-([0-9]+)\-([0-9]+)/ ); + var dParts = link.match ( dateExp ); + var d = new Date(); + var year_full = ( dParts[3].length == 2 ) ? '20' + dParts[3].toString():dParts[3]; + d.setFullYear( year_full, dParts[1] - 1, dParts[2] ); + return d; + } +} diff --git a/js2/mwEmbed/libAddMedia/simpleUploadForm.js b/js2/mwEmbed/libAddMedia/simpleUploadForm.js new file mode 100644 index 0000000000..e2e76e1533 --- /dev/null +++ b/js2/mwEmbed/libAddMedia/simpleUploadForm.js @@ -0,0 +1,156 @@ +/* + * simple form output jquery binding + * enables dynamic form output to a given target + * + */ + +loadGM( { + "mwe-select_file" : "Select file", + "mwe-more_license_options" : "For more license options, view the normal upload page<\/a>", + "mwe-select_ownwork" : "I am uploading entirely my own work, and licencing it under:", + "mwe-license_cc-by-sa" : "Creative Commons Share Alike (3.0)", + "mwe-upload" : "Upload file", + "mwe-destfilename" : "Destination filename:", + "mwe-summary" : "Summary", + "mwe-error_not_loggedin" : "You do not appear to be logged in or do not have upload privileges.", + "mwe-watch-this-file" : "Watch this file", + "mwe-ignore-any-warnings" : "Ignore any warnings" +} ); + +var default_form_options = { + 'enable_fogg' : true, + 'license_options': ['cc-by-sa'], + 'api_target' : false, + 'ondone_cb' : null +}; + +( function( $ ) { + $.fn.simpleUploadForm = function( opt , callback ) { + var _this = this; + // set the options: + for ( var i in default_form_options ) { + if ( !opt[i] ) + opt[i] = default_form_options[i]; + } + + // first do a reality check on the options: + if ( !opt.api_target ) { + $( this.selector ).html( 'Error: Missing api target' ); + return false; + } + + // @@todo this is just a proof of concept + // much todo to improved this web form + get_mw_token( 'File:MyRandomFileTokenCheck', opt.api_target, function( eToken ) { + if ( !eToken || eToken == '+\\' ) { + $( this.selector ).html( gM( 'mwe-error_not_loggedin' ) ); + return false; + } + + // build an upload form: + var o = '
    ' + + '
    ' + + // hidden input: + '' + + '' + + '' + + + // form name set: + '
    ' + + '
    ' + + + '
    ' + + '
    ' + + + '
    ' + + '
    '; + // js_log('getInsertDescHtml: ' + o ); + return o; + }, + updateInsertControlActions:function() { + var _this = this; + var b_target = _this.p_rsdObj.target_container + '~ .ui-dialog-buttonpane'; + // empty the ui-dialog-buttonpane bar: + $j( b_target ).empty(); + for ( var cbType in _this.controlActionsCb ) { + switch( cbType ) { + case 'insert_seq': + $j( b_target ).append( $j.btnHtml( gM( 'mwe-insert_into_sequence' ), 'mv_insert_sequence', 'check' ) + ' ' ) + .children( '.mv_insert_sequence' ) + .btnBind() + .click( function() { + _this.applyEdit(); + _this.controlActionsCb['insert_seq']( _this.rObj ); + } ); + break; + case 'insert': + $j( b_target ).append( $j.btnHtml( gM( 'mwe-insert_image_page' ), 'mv_insert_image_page', 'check' ) + ' ' ) + .children( '.mv_insert_image_page' ) + .btnBind() + .click( function() { + _this.applyEdit(); + _this.controlActionsCb['insert']( _this.rObj ); + } ).show( 'slow' ); + break; + case 'preview': + $j( b_target ).append( $j.btnHtml( gM( 'mwe-preview_insert' ), 'mv_preview_insert', 'refresh' ) + ' ' ) + .children( '.mv_preview_insert' ) + .btnBind() + .click( function() { + _this.applyEdit(); + _this.controlActionsCb['preview']( _this.rObj ); + } ).show( 'slow' ); + break; + case 'cancel': + $j( b_target ).append( $j.btnHtml( gM( 'mwe-cancel_image_insert' ), 'mv_cancel_img_edit', 'close' ) + ' ' ) + .children( '.mv_cancel_img_edit' ) + .btnBind() + .click( function() { + // no cancel action; + _this.controlActionsCb['cancel']( _this.rObj ); + } ).show( 'slow' ); + break; + } + } + }, + applyEdit:function() { + var _this = this; + js_log( 'applyEdit::' + this.media_type ); + if ( this.media_type == 'image' ) { + this.applyCrop(); + } else if ( this.media_type == 'video' ) { + this.applyVideoAdj(); + } + // copy over the desc text to the resource object + _this.rObj['inlineDesc'] = $j( '#mv_inline_img_desc' ).val(); + }, + appendTool: function( $target, tool_id ) { + var _this = this; + switch( tool_id ) { + case 'layout': + $target.append( '' + + 'Layout:' + + ''+ + '
    ' + + ''+ + '
    ' + + '

    ' + ); + // make sure the default is reflected: + if ( ! _this.rObj.layout ) + _this.rObj.layout = 'right'; + $j( '#mv_layout_' + _this.rObj.layout )[0].checked = true; + + // left radio click + $j( '#mv_layout_left,#mv_layout_left_img' ).click( function() { + $j( '#mv_layout_right' )[0].checked = false; + $j( '#mv_layout_left' )[0].checked = true; + _this.rObj.layout = 'left'; + } ); + // right radio click + $j( '#mv_layout_right,#mv_layout_right_img' ).click( function() { + $j( '#mv_layout_left' )[0].checked = false; + $j( '#mv_layout_right' )[0].checked = true; + _this.rObj.layout = 'right'; + } ); + break; + case 'crop': + $target.append( '' + + '
    ' + + '' + gM( 'mwe-crop' ) + ' ' + + ' ' + + ' ' + + ' ' + + '

    ' + ); + // add binding: + $j( '#mv_crop_button,.mv_crop_msg,.mv_apply_crop' ).click( function() { + js_log( 'click:mv_crop_button: base width: ' + _this.rObj.width + ' bh: ' + _this.rObj.height ); + if ( $j( '#mv_crop_button' ).hasClass( 'mv_crop_button_selected' ) ) { + _this.applyCrop(); + } else { + js_log( 'click:turn on' ); + _this.enableCrop(); + } + } ); + $j( '.mv_reset_crop' ).click( function() { + $j( '.mv_apply_crop,.mv_reset_crop' ).hide(); + $j( '.mv_crop_msg' ).show(); + $j( '#mv_crop_button' ).removeClass( 'mv_crop_button_selected' ).addClass( 'mv_crop_button_base' ).attr( 'title', gM( 'mwe-crop' ) ); + _this.rObj.crop = null; + $j( '#' + _this.clip_disp_ct ).empty().html( + '' + ); + } ); + break; + case 'scale': + /*scale: + '
    '+ + '' + gM('mwe-scale') + '
    '+ + ' '+ + '
    '+ + + */ + break; + } + }, + setUpImageCtrl:function() { + var _this = this; + var $tool_target = $j( '#' + this.control_ct ); + // by default apply Crop tool + if ( _this.enabled_tools == 'all' || _this.enabled_tools.length > 0 ) { + $tool_target.append( '

    ' + gM( 'mwe-edit-tools' ) + '

    ' ); + for ( var i in _this.toolset ) { + var toolid = _this.toolset[i]; + if ( $j.inArray( toolid, _this.enabled_tools ) != -1 || _this.enabled_tools == 'all' ) + _this.appendTool( $tool_target, toolid ); + } + } + // add the insert description text field: + $tool_target.append( _this.getInsertDescHtml() ); + // add the actions to the 'button bar' + _this.updateInsertControlActions(); + }, + applyVideoAdj:function() { + js_log( 'applyVideoAdj::' ); + $tp = $j( '#' + this.control_ct ); + + // be sure to "stop the video (some plugins can't have DOM elements on top of them) + $j( '#embed_vid' ).get( 0 ).stop(); + + // update video related keys + this.rObj['start_time'] = $tp.find( '.startInOut' ).val(); + this.rObj['end_time'] = $tp.find( '.endInOut' ).val() ; + + // do the local video adjust + if ( typeof this.rObj.pSobj['applyVideoAdj'] != 'undefined' ) { + this.rObj.pSobj.applyVideoAdj( this.rObj ); + } + }, + applyCrop:function() { + var _this = this; + $j( '.mv_apply_crop' ).hide(); + $j( '.mv_crop_msg' ).show(); + $j( '#mv_crop_button' ).removeClass( 'mv_crop_button_selected' ).addClass( 'mv_crop_button_base' ).attr( 'title', gM( 'mwe-crop' ) ); + js_log( 'click:turn off' ); + var cat = _this.rObj; + if ( _this.rObj.crop ) { + // empty out and display cropped: + $j( '#' + _this.clip_disp_ct ).empty().html( + '
    ' + + '
    ' + + '' + + '
    ' + + '
    ' + ); + } + return true; + }, + // right now enableCrop loads "just in time" + // @@todo we really need an "auto loader" type system. + enableCrop:function() { + var _this = this; + $j( '.mv_crop_msg' ).hide(); + $j( '.mv_crop_msg_load' ).show(); + var doEnableCrop = function() { + $j( '.mv_crop_msg_load' ).hide(); + $j( '.mv_reset_crop,.mv_apply_crop' ).show(); + $j( '#mv_crop_button' ).removeClass( 'mv_crop_button_base' ).addClass( 'mv_crop_button_selected' ).attr( 'title', gM( 'mwe-crop_done' ) ); + $j( '#' + _this.clip_disp_ct + ' img' ).Jcrop( { + onSelect: function( c ) { + js_log( 'on select:' + c.x + ',' + c.y + ',' + c.x2 + ',' + c.y2 + ',' + c.w + ',' + c.h ); + _this.rObj.crop = c; + }, + onChange: function( c ) { + } + } ); + // temporary hack (@@todo need to debug why rsd_res_item gets moved ) + $j( '#clip_edit_disp .rsd_res_item' ).css( { + 'top':'0px', + 'left':'0px' + } ); + } + // load the jcrop library if needed: + mvJsLoader.doLoad( [ + '$j.Jcrop' + ], function() { + doEnableCrop(); + } ); + } +} + +// mv_lock_vid_updates defined in mv_stream.js (we need to do some more refactoring ) +if ( typeof mv_lock_vid_updates == 'undefined' ) + mv_lock_vid_updates = false; + +function add_adjust_hooks( mvd_id, adj_callback ) { + + var start_sec = npt2seconds( $j( '#mv_start_hr_' + mvd_id ).val() ); + var end_sec = npt2seconds( $j( '#mv_end_hr_' + mvd_id ).val() ); + + // if we don't have 0 as start then assume we are in a range request and give some buffer area: + var min_slider = ( start_sec - 60 < 0 ) ? 0 : start_sec - 60; + if ( min_slider != 0 ) { + var max_slider = end_sec + 60; + } else { + max_slider = end_sec; + } + // pre-destroy just in case: + $j( '#mvd_form_' + mvd_id + ' .inOutSlider' ).slider( 'destroy' ).slider( { + range: true, + min: min_slider, + max: max_slider, + values: [start_sec, end_sec], + slide: function( event, ui ) { + js_log( " vals:" + seconds2npt( ui.values[0] ) + ' : ' + seconds2npt( ui.values[1] ) ); + $j( '#mv_start_hr_' + mvd_id ).val( seconds2npt( ui.values[0] ) ); + $j( '#mv_end_hr_' + mvd_id ).val( seconds2npt( ui.values[1] ) ); + }, + change:function( event, ui ) { + do_video_time_update( seconds2npt( ui.values[0] ), seconds2npt( ui.values[1] ) ); + } + } ); + $j( '.mv_adj_hr' ).change( function() { + // preserve track duration for nav and seq: + // ie seems to crash so no interface updates for IE for the time being + if ( !$j.browser.msie ) { + if ( mvd_id == 'nav' || mvd_id == 'seq' ) { + add_adjust_hooks( mvd_id ); // (no adj_callback) + } else { + add_adjust_hooks( mvd_id ) + } + } + // update the video time for onChange + do_video_time_update( $j( '#mv_start_hr_' + mvd_id ).val(), $j( '#mv_end_hr_' + mvd_id ).val() ); + } ); +} + +function do_video_time_update( start_time, end_time, mvd_id ) { + js_log( 'do_video_time_update: ' + start_time + ' ' + end_time ); + if ( mv_lock_vid_updates == false ) { + // update the vid title: + $j( '#mv_videoPlayerTime' ).html( start_time + ' to ' + end_time ); + var ebvid = $j( '#embed_vid' ).get( 0 ); + if ( ebvid ) { + if ( ebvid.isPaused() ) + ebvid.stop(); + ebvid.updateVideoTime( start_time, end_time ); + js_log( 'update thumb: ' + start_time ); + ebvid.updateThumbTimeNTP( start_time ); + } + } +} + +// some custom jquery bindings: +( function( $ ) { + $.fn.upDownTimeInputBind = function( inputCB ) { + $( this.selector ).unbind( 'focus' ).focus( function() { + var doDelayCall = true; + $( this ).addClass( 'ui-state-focus' ); + // bind up down keys + $( this ).unbind( 'keydown' ).keydown( function ( e ) { + var sec = npt2seconds( $j( this ).val() ); + var k = e.which; + if ( k == 38 ) {// up + $( this ).val( seconds2npt( sec + 1 ) ); + } else if ( k == 40 ) { // down + var sval = ( ( sec - 1 ) < 0 ) ? 0 : ( sec - 1 ) + $( this ).val( seconds2npt( sval ) ); + } + // set the delay updates: + if ( k == 38 || k == 40 ) { + var _inputElm = this; + if ( doDelayCall ) { + setTimeout( function() { + inputCB( _inputElm ); + doDelayCall = true; + }, 500 ); + doDelayCall = false; + } + } + } ); + } ).unbind( 'blur' ).blur( function() { + $( this ).removeClass( 'ui-state-focus' ); + } ); + } +} )( jQuery ); diff --git a/js2/mwEmbed/libClipEdit/pixastic-editor/editor.js b/js2/mwEmbed/libClipEdit/pixastic-editor/editor.js new file mode 100644 index 0000000000..6789531dd0 --- /dev/null +++ b/js2/mwEmbed/libClipEdit/pixastic-editor/editor.js @@ -0,0 +1,968 @@ + +var PixasticEditor = (function () { + + var $frame; // iframe container element + var $editor; // editor container element + + // various UI structures + var accordionElements = {}; + var tabElements = {}; + var activeTabId; + var $activeTabContent; + + var isRunning = false; + + var $loadingScreen; + + var $imageCanvas; // the canvas holding the current state of the image + var $displayCanvas; // the canvas element displayed on the screen, also the working canvas (where preview operations are performed) + var imageCtx; + + var imageWidth = 0; // dimensions of the current image state + var imageHeight = 0; + + var undoImages = []; // canvas elements holding previous image states + var undoLevels = 10; + + var doc; + + var $; + + // test for valid file formats for toDataURL() + // we do that by calling it with each of the mime types in testFormats + // and then doing string checking on the resulting data: URI to see if it succeeded + var saveFormats = []; + var testFormats = [["image/jpeg", "JPEG"], ["image/png", "PNG"]]; + var testCanvas = document.createElement("canvas"); + if (testCanvas.toDataURL) { + testCanvas.width = testCanvas.height = 1; + for (var i=0;i
    ", doc) + .addClass("error-dialog") + .attr("title", "Oops!") + .html(errTxt) + .dialog(); + // the dialog is added outside the Pixastic container, so get it back in. + var dialogParent = $j(dialog.get(0).parentNode); + dialogParent.appendTo($editor); + + return errTxt; + } + + function enableTab(id, refresh) { + if (id == activeTabId && !refresh) + return; + + activeTabId = id; + + var activeIndex = 0; + + if ($activeTabContent) { + if ($activeTabContent.get(0)) { + var $parent = $j($activeTabContent.get(0).parentNode); + activeIndex = $parent.data("accordionindex"); + if ($parent.data("ondeactivate")) { + $parent.data("ondeactivate")(); + } + if ($parent.data("previewCheckbox")) + $parent.data("previewCheckbox").attr("checked", false); + $parent.data("uidesc").previewEnabled = false; + if ($parent.data("uidesc").forcePreview) + $parent.data("uidesc").previewEnabled = true; + } + } + + + for (var a in accordionElements) { + if (accordionElements.hasOwnProperty(a)) { + accordionElements[a].accordion("option", "animated", false); + accordionElements[a].accordion("activate", -1); + accordionElements[a].hide(); + tabElements[a].removeClass("active"); + + } + } + + accordionElements[id].accordion("option", "animated", false); + accordionElements[id].accordion("activate", refresh ? activeIndex : 0); + tabElements[id].addClass("active"); + accordionElements[id].show(); + accordionElements[id].accordion("option", "animated", "slide"); + resetDisplayCanvas(); + } + + // revert to a previous image state + function undo(idx) { + var undoImage = undoImages[idx]; + + if (!undoImage) + throw new Error(errorDialog("Invalid undo state")); + if (!($imageCanvas && $imageCanvas.get && $imageCanvas.get(0))) + throw new Error(errorDialog("$imageCanvas doesn't exist")); + + var canvas = $imageCanvas.get(0); + addUndo(canvas); + canvas.width = imageWidth = undoImage.width; + canvas.height = imageHeight = undoImage.height; + canvas.getContext("2d").drawImage(undoImage,0,0); + + enableTab(activeTabId, true); + resetDisplayCanvas(); + } + + function addUndo(canvasElement) { + if (!canvasElement) + throw new Error(errorDialog("No undo image state provided")); + + if (undoImages.length == undoLevels) { + undoImages.shift(); + } + var undoCanvas = document.createElement("canvas"); + undoCanvas.width = canvasElement.width; + undoCanvas.height = canvasElement.height; + undoCanvas.getContext("2d").drawImage(canvasElement,0,0); + $j(undoCanvas).addClass("undo-canvas"); + undoImages.push(undoCanvas); + updateUndoList(); + } + + function updateUndoList() { + var $listCtr = $j("#undo-bar", doc) + .html(""); + + var ctrHeight = $listCtr.height(); + + var $testCanvas = $j("", doc) + .addClass("undo-canvas-small") + .addClass("far-far-away") + .appendTo("body"); + + var canvasHeight = $testCanvas.height(); + var canvasWidth = $testCanvas.width(); + var canvasCSSHeight = canvasHeight + parseInt($testCanvas.css("margin-top"),10) + parseInt($testCanvas.css("margin-bottom"),10); + + $testCanvas.remove(); + + var undoRatio = canvasWidth / canvasHeight; + + for (var i=undoImages.length-1;i>=0;i--) { + (function(){ + var canvas = document.createElement("canvas"); + $j(canvas) + .addClass("undo-canvas-small") + .attr("width", canvasWidth) + .attr("height", canvasHeight); + + var image = undoImages[i]; + $j(image).show(); + + var undoWidth, undoHeight; + var imageRatio = image.width / image.height; + + if (imageRatio > undoRatio) { // image too wide + undoWidth = canvasWidth; + undoHeight = canvasWidth / imageRatio; + } else { + undoWidth = canvasHeight * imageRatio; + undoHeight = canvasHeight; + } + + var restWidth = canvasWidth - undoWidth; + var restHeight = canvasHeight - undoHeight; + + canvas.getContext("2d").drawImage( + image, + 0,0,image.width,image.height, + restWidth*0.5, restHeight*0.5, + undoWidth, undoHeight + ); + + + $link = $j("", doc) + .addClass("undo-link") + .appendTo($listCtr) + .mouseover(function(){ $j(this).addClass("hover") }) + .mouseout(function(){ $j(this).removeClass("hover") }); + $j(canvas).appendTo($link); + + var displayShowing; + var undoIndex = i; + $link.click(function() { + $j(image).hide(); + $j(image).remove(); + undo(undoIndex); + if (displayShowing) + $displayCanvas.show(); + $j(".jcrop-holder", doc).show(); + }); + + $link.mouseover(function() { + displayShowing = $displayCanvas.css("display") != "none"; + var $imagectr = $j("#image-container", doc); + + $j(".jcrop-holder", doc).hide(); + $displayCanvas.hide(); + $j(image).appendTo($imagectr); + + var h1 = $j("#image-area", doc).height(); + var h2 = image.height; + var m = Math.max(0, (h1 - h2) / 2); + $imagectr.css("marginTop", m); + + $imagectr.height(image.height); + }); + + $link.mouseout(function() { + $j(image).remove(); + if (displayShowing) + $displayCanvas.show(); + $j(".jcrop-holder", doc).show(); + updateDisplayCanvas(); + }); + + + $j(canvas).attr("title", "Click to revert to this previous image"); + + })(); + } + } + + + function applyAction(id, options, afteraction) { + if (!Pixastic.Actions[id]) + throw new Error("applyAction(): unknown action [" + id + "]"); + + $j("#action-bar-overlay", doc).show(); + + setTimeout(function() { + options.leaveDOM = true; + var canvasElement = $imageCanvas.get(0); + addUndo(canvasElement) + + var res = Pixastic.process( + canvasElement, id, options, + function(resCanvas) { + canvasElement.width = imageWidth = resCanvas.width; + canvasElement.height = imageHeight = resCanvas.height; + + var ctx = canvasElement.getContext("2d"); + ctx.clearRect(0,0,imageWidth,imageHeight); + ctx.drawImage(resCanvas,0,0); + $imageCanvas = $j(canvasElement); + resetDisplayCanvas(); + + $j("#action-bar-overlay", doc).hide(); + + if (afteraction) + afteraction(); + } + ); + if (!res) + throw new Error("applyAction(): Pixastic.process() failed for action [" + id + "]"); + },1); + } + + + function previewAction(id, options, afteraction) { + if (!Pixastic.Actions[id]) + throw new Error("applyAction(): unknown action [" + id + "]"); + + $j("#action-bar-overlay", doc).show(); + + resetDisplayCanvas(); + + options.leaveDOM = true; + var canvasElement = $displayCanvas.get(0); + + var res = Pixastic.process( + canvasElement, id, options, + function(resCanvas) { + + canvasElement.width = resCanvas.width; + canvasElement.height = resCanvas.height; + + var ctx = canvasElement.getContext("2d"); + ctx.clearRect(0,0,canvasElement.width,canvasElement.height); + ctx.drawImage(resCanvas,0,0); + updateDisplayCanvas(); + updateOverlay(); + + $j("#action-bar-overlay", doc).hide(); + + if (afteraction) + afteraction(); + } + ); + } + + var onwindowresize = function() { + updateDisplayCanvas(); + updateOverlay(); + } + + var baseUrl = "" + + function buildEditor() { + var styles = [ + "jquery-ui-1.7.1.custom.css", + "jquery.Jcrop.css", + "pixastic.css" + ]; + + for (var i=0;i", doc) + .attr("id", "pixastic-editor") + .appendTo($j(doc.body)); + + $editor.append( + $j("
    ", doc), + $j("
    ", doc).append( + $j("
    ", doc).append( + $j("
    ", doc).append( + $j("
    ", doc).append( + $j("
    ", doc) + ), + $j("
    ", doc) + ), + $j("
    ", doc).append( + $j("
    ", doc).append( + $j("
    ", doc), + $j("
    ", doc).append( + $j("
    ", doc) + ) + ) + ) + ) + ), + $j("
    ", doc), + $j("", doc) + ); + + $j("#image-container", doc).append( + $displayCanvas = $j("", doc) + .addClass("display-canvas") + ); + + // loop through all defined UI action controls + var tabs = PixasticEditor.UI.data.tabs; + + for (var i=0;i" + tab.title + "", doc) + .attr("id", "main-tab-button-" + tab.id) + .addClass("main-tab") + .click(function() { + enableTab(tab.id); + }) + .mouseover(function(){ $j(this).addClass("hover") }) + .mouseout(function(){ $j(this).removeClass("hover") }); + + $j("#main-bar", doc).append($tabElement); + + tabElements[tab.id] = $tabElement; + + var $menu = $j("
    ", doc); + accordionElements[tab.id] = $menu; + + for (var j=0;j

    " + action.title + "

    ", doc) + + $menu.append($actionElement); + + var $content = $j("
    ", doc) + .attr("id", "pixastic-action-tab-content-" + action.id) + .appendTo($actionElement); + + var controlOptions = []; + + action.previewEnabled = false; + if (action.forcePreview) + action.previewEnabled = true; + + function togglePreview(enable, doAction) { + if (enable && !action.previewEnabled && doAction) + doAction(true); + if (!enable && action.previewEnabled) + resetDisplayCanvas(); + + action.previewEnabled = enable; + } + + var reset = function() { + for (var i in controlOptions) { + if (controlOptions.hasOwnProperty(i)) { + controlOptions[i].reset(); + } + } + if (action.previewEnabled) + doAction(true); + } + var doAction = function(isPreview) { + var options = {}; + for (var i in controlOptions) { + if (controlOptions.hasOwnProperty(i)) { + options[i] = controlOptions[i].valueField.val(); + } + } + + var afteraction = function() { + if (action.onafteraction) + action.onafteraction(action, isPreview); + if (!isPreview) + resetDisplayCanvas(); + + if (!isPreview && !action.forcePreview) { + $j("#pixastic-input-preview-" + action.id, doc).attr("checked", false); + togglePreview(false); + reset(); + } + } + + if (isPreview) { + previewAction(action.id, options, afteraction); + } else { + applyAction(action.id, options, afteraction); + } + + } + + var hadInputs = false; + + if (action.controls) { + var onChange = function() {}; + if (action.isAction && action.preview) { + onChange = function() { + if (action.previewEnabled) + doAction(true) + }; + } + + for (var k=0;k
    ", doc) + .addClass("ui-action-output") + .html(control.content) + .appendTo($content); + break; + } + } + } + + if (action.isAction) { + + var $applyButton = PixasticEditor.UI.makeButton("Apply") + .addClass("pixastic-option-button-apply") + .click(function() {doAction();}); + + $content.append($applyButton); + + if (hadInputs) { + var $resetButton = PixasticEditor.UI.makeButton("Reset") + .addClass("pixastic-option-button-reset") + .click(reset); + + $content.append($resetButton) + } + + if (action.preview && !action.forcePreview) { + var $checkctr = $j("
    ", doc) + .addClass("ui-checkbox-container") + .addClass("ui-preview-checkbox-container"); + + var $label = $j("", doc) + .addClass("ui-checkbox-label") + .attr("for", "pixastic-input-preview-" + action.id) + .html("Preview:") + .appendTo($checkctr); + + var $checkbox = $j("", doc) + .addClass("ui-checkbox") + .attr("id", "pixastic-input-preview-" + action.id) + .appendTo($checkctr) + .change(function() { + togglePreview(this.checked, doAction) + }); + + $content.append($checkctr); + + $content.data("previewCheckbox", $checkbox); + } + + } + + + if (typeof action.content == "function") { + action.content($content); + } + + // stupid hack to make it possible to get $content in change event (below) + $j("", doc).appendTo($content); + + $content.data("controlOptions", controlOptions); + $content.data("onactivate", action.onactivate); + $content.data("ondeactivate", action.ondeactivate); + $content.data("onoverlayupdate", action.onoverlayupdate); + $content.data("accordionindex", j); + $content.data("uidesc", action); + + })(); + } + + $j("#action-bar", doc).append($menu); + + $menu.hide().accordion({ + header: "h3", + autoHeight : false, + collapsible : true, + active: -1 + }) + .bind("accordionchange", + function(event, ui) { + resetDisplayCanvas(); + + // oldContent / newContent are arrays of whatever elements are present in the content area + // We need the parent element (the one holding the content) but if there is no content, how do we get it? + // fixed above by always appending a but that's ugly and needs to be done in some other way + if (ui.oldContent.get(0)) { + var $parent = $j(ui.oldContent.get(0).parentNode); + if ($parent.data("ondeactivate")) { + $parent.data("ondeactivate")(); + } + } + $activeTabContent = ui.newContent; + + if (ui.newContent.get(0)) { + var $parent = $j(ui.newContent.get(0).parentNode); + if ($parent.data("previewCheckbox")) + $parent.data("previewCheckbox").attr("checked", false); + $parent.data("uidesc").previewEnabled = false; + if ($parent.data("uidesc").forcePreview) + $parent.data("uidesc").previewEnabled = true; + + var controlOptions = $parent.data("controlOptions"); + for (var i in controlOptions) { + if (controlOptions.hasOwnProperty(i)) { + controlOptions[i].reset(); + } + } + if ($parent.data("onactivate")) { + $parent.data("onactivate")(); + } + } + updateDisplayCanvas(); + + } + ); + + + })(); + } + + $j(window).bind("resize", onwindowresize); + } + + function showLoadingScreen() { + if ($loadingScreen) { + $loadingScreen.show(); + return; + } + $loadingScreen = $j("
    ") + var $ctr = $j("
    "); + $j("
    ") + .addClass("spinner") + .appendTo($ctr); + $loadingScreen.append($ctr); + $loadingScreen.appendTo("body"); + } + + function hideLoadingScreen() { + setTimeout(function() { + $loadingScreen.hide(); + }, 1); + } + + var oldScrollLeft; + var oldScrollTop; + var oldOverflow; + + // fire it up + function init(callback) { + isRunning = true; + + showLoadingScreen(); + + oldScrollLeft = document.body.scrollLeft; + oldScrollTop = document.body.scrollTop; + oldOverflow = document.body.style.overflow; + + document.body.scrollLeft = 0; + document.body.scrollTop = 0; + document.body.style.overflow = "hidden"; + + $frame = $j("' ); + + // add an onLoad hook: + $j( '#frame_proxy' ).get( 0 ).onload = function() { + // add a 5 second timeout for setting up the nested child callback (after page load) + setTimeout( function() { + if ( !frameProxyOk ) { + // we timmed out no api proxy (should make sure the user is "logged in") + js_log( "Error:: api proxy timeout are we logged in? mwEmbed is on?" ); + $.proxy.proxyNotReadyDialog(); + } + }, 5000 ); + } + } + var lastApiReq = { }; + $.proxy.proxyNotReadyDialog = function() { + var buttons = { }; + buttons[ gM( 'mwe-re-try' ) ] = function() { + $j.addLoaderDialog( gM( 'mwe-re-trying' ) ); + $.proxy.doFrameProxy( lastApiReq ); + } + buttons[ gM( 'mwe-cancel' ) ] = function() { + $j.closeLoaderDialog(); + } + var pUri = mw.parseUri( $.proxy.server_frame ); + + // FIXME we should have a Hosted iframe once we deploy mwEmbed on the servers. + // A hosted iframe would be much faster since than a normal page view + + var login_url = pUri.protocol + '://' + pUri.host; + login_url += pUri.path.replace( 'MediaWiki:ApiProxy', 'Special:UserLogin' ); + + $j.addDialog( + gM( 'mwe-proxy-not-ready' ), + gM( 'mwe-please-login', [ login_url, pUri.host] ) + + '

    ' + + gM( 'mwe-remember-loging' ) + + '

    ', + buttons + ) + } + /* + * doRequest + * Takes a requestQuery, executes the query and then calls the callback + */ + $.proxy.doRequest = function( requestQuery, callback ) { + js_log( "doRequest:: " + JSON.stringify( reqObj ) ); + lastApiReq = reqObj; + // setup the callback: + $.proxy.callback = callback; + // do the proxy req: + $.proxy.doFrameProxy( requestQuery ); + } + /** + * The nested iframe action that passes its result back up to the top frame instance + */ + $.proxy.nested = function( hashResult ) { + // Close the loader if present: + $j.closeLoaderDialog(); + js_log( '$.proxy.nested callback :: ' + unescape( hashResult ) ); + frameProxyOk = true; + + // Try to parse the hash result: + try { + var rObj = JSON.parse( unescape( hashResult ) ); + } catch ( e ) { + js_log( "Error could not parse hashResult" ); + } + + // Special callback to frameProxyOk flag + // (only used to test the proxy connection) + if ( rObj.state == 'ok' ) + return ; + + // Pass the callback: + $.proxy.callback( rObj ); + } + /** + * The server handles the actual proxy + * it adds child frames pointing to the parent "blank" frames + * + * This is (Domain B) in the above described setup + */ + $.proxy.server = function( pConf, callback ) { + /* clear the body of any html */ + $j( 'body' ).html( 'proxy setup' ); + + // read the anchor action from the requesting url + var jmsg = unescape( mw.parseUri( document.URL ).anchor ); + try { + var aObj = JSON.parse( jmsg ); + } catch ( e ) { + js_log( "ProxyServer:: could not parse anchor" ); + } + if ( !aObj.cd ) { + js_log( "Error: no client domain provided " ); + return false; + } + + js_log( "Setup server on: " + mw.parseUri( document.URL ).host + + ' client from: ' + aObj.cd + + ' to nested target: ' + aObj.cfp ); + + // Make sure we are logged in + // (its a normal mediaWiki page so all site vars should be defined) + if ( !wgUserName ) { + js_log( 'Error Not logged in' ); + return false; + } + + var domain = aObj.cd; + var nested_frame_src = 'http://' + aObj.cd + aObj.cfp; + // Check the master whitelist + for ( var i in pConf.master_whitelist ) { + if ( domain == pConf.master_whitelist[ i ] ) { + // Do the request: + return doNestedProxy( aObj.req ); + } + } + // Check master blacklist + for ( var i in pConf.master_blacklist ) { + if ( domain == pConf.master_blacklist ) { + js_log( 'domain: ' + domain + ' is blacklisted' ); + return false; + } + } + // FIXME grab the users whitelist for our current domain + /*var local_api = wgScriptPath + '/index' + wgScriptExtension + '?title=' + + 'User:' + wgUserName + '/apiProxyDomainList.js' + + '&action=raw&smaxage=0&gen=js'; + $j.get( local_api, function( data ){ + debugger; + });*/ + + // if still not found: + js_log( "domain " + domain + " not approved" ); + + // FIXME :: offer the user the ability to "approve" requested domain save to + // their user/ apiProxyDomainList.js page + + function doNestedProxy( reqObj ) { + js_log( "doNestedProxy to: " + nested_frame_src ); + + // Do a quick response to establish the proxy is working + // ( before we actually run the api-request ) + doNestedFrame ( 'nested_ok' , { 'state':'ok' } ); + + var outputhash = escape( JSON.stringify( reqObj ) ); + + // Add some api stuff: + reqObj[ 'format' ] = 'json'; + + // Process the api request + $j.post( wgScriptPath + '/api' + wgScriptExtension, + reqObj, + function( data ) { + // Put it into the nested frame hash string: + doNestedFrame( 'nested_push', JSON.parse( data ) ); + } + ); + } + // Add the doNestedFrame iframe: + function doNestedFrame( nestname, resultObj ) { + $j( '#nested_push' ).remove(); + // Setup the nested proxy that points back to top domain: + $j( 'body' ).append( '' ); + } + } + +} )( window.mw ); diff --git a/js2/mwEmbed/libSequencer/mvFirefoggRender.js b/js2/mwEmbed/libSequencer/mvFirefoggRender.js new file mode 100644 index 0000000000..0c00040a73 --- /dev/null +++ b/js2/mwEmbed/libSequencer/mvFirefoggRender.js @@ -0,0 +1,146 @@ +/* + * Handles driving the firefogg render system +*/ +var mvFirefoggRender = function( options ) { + return this.init( options ); +}; +var default_render_options = { + "videoQuality" : 10, + "framerate" : 30 +} +var default_FirefoggRender_options = { + start_time:0, + // if we should save to disk (if false setup upload stuff below) + save_to_disk:true +} +// set up the mvPlaylist object +mvFirefoggRender.prototype = { + // default empty render options: + renderOptions: { }, + continue_rendering:false, + init:function( options ) { + var _this = this; + + // grab the mvFirefogg object to do basic tests + this.myFogg = new mvFirefogg( { + 'only_fogg':true + } ); + + // check for firefogg: + if ( this.myFogg.getFirefogg() ) { + this.enabled = true; + } else { + this.enabled = false; + return this; + } + + // set up local fogg pointer: + this.fogg = this.myFogg.fogg; + + // setup player instance + this.player = $j( options.player_target ).get( 0 ); + this.player_target = options.player_target; + + // Extend the render options with any provided details + if( options['render_options'] ) + $j.extend(this.renderOptions, options['render_options']); + + // If no height width provided use target DOM width/height + if( !this.renderOptions.width && !this.renderOptions.height ){ + this.renderOptions.width = $j(this.player_target).width(); + this.renderOptions.height = $j(this.player_target).height(); + } + + + // Setup the application options (with defaults) + for ( var i in default_FirefoggRender_options ) { + if ( options[ i ] ) { + this[ i ] = options[ i ]; + } else { + this[ i ] = default_FirefoggRender_options[i]; + } + } + // Should be externally controlled + if ( options.target_startRender ) { + $j( options.target_startRender ).click( function() { + js_log( "Start render" ); + _this.startRender(); + } ) + this.target_startRender = options.target_startRender; + } + if ( options.target_stopRender ) { + $j( options.target_stopRender ).click( function() { + _this.stopRender(); + } ) + this.target_stopRender = options.target_stopRender; + } + if ( options.target_timeStatus ) { + this.target_timeStatus = options.target_timeStatus; + } + }, + startRender:function() { + var _this = this; + var t = this.start_time; + // get the interval from renderOptions framerate + var interval = 1 / this.renderOptions.framerate + + // issue a load request on the player: + //this.player.load(); + + // init the Render + this.fogg.initRender( JSON.stringify( _this.renderOptions ), 'foggRender' ); + + // add audio if we had any: + + // request a target (should support rendering to temp location too) + //this.fogg.saveVideoAs(); + + // set the continue rendering flag to true: + this.continue_rendering = true; + + // internal function to hanndle updates: + var doNextFrame = function() { + $j( _this.target_timeStatus ).val( " on " + ( Math.round( t * 10 ) / 10 ) + " of " + + ( Math.round( _this.player.getDuration() * 10 ) / 10 ) ); + _this.player.setCurrentTime( t, function() { + //_this.fogg.addFrame( $j( _this.player_target ).attr( 'id' ) ); + t += interval; + if ( t >= _this.player.getDuration() ) { + _this.doFinalRender(); + } else { + if ( _this.continue_rendering ) { + doNextFrame(); + } else { + js_log('done with render'); + // else quit: + //_this.doFinalRender(); + } + } + } ); + } + doNextFrame(); + }, + stopRender:function() { + this.continue_rendering = false; + }, + doFinalRender:function() { + $j( this.target_timeStatus ).val( "doing final render" ); + this.fogg.render(); + this.updateStatus(); + }, + updateStatus:function() { + var _this = this; + var doUpdateStatus = function() { + var rstatus = _this.fogg.renderstatus() + $j( _this.target_timeStatus ).val( rstatus ); + if ( rstatus != 'done' && rstatus != 'rendering failed' ) { + setTimeout( doUpdateStatus, 100 ); + } else { + $j( _this.target_startRender ).attr( "disabled", false ); + } + } + doUpdateStatus(); + } + + +} \ No newline at end of file diff --git a/js2/mwEmbed/libSequencer/mvPlayList.js b/js2/mwEmbed/libSequencer/mvPlayList.js new file mode 100644 index 0000000000..e0d9be42ac --- /dev/null +++ b/js2/mwEmbed/libSequencer/mvPlayList.js @@ -0,0 +1,2300 @@ +/* + * the mvPlayList object code + * only included if playlist object found + * + * part of mwEmbed media projects see: + * http://www.mediawiki.org/wiki/Media_Projects_Overview + * + * @author: Michael Dale mdale@wikimedia.org + * @license GPL2 + */ +var mv_default_playlist_attributes = { + // playlist attributes : + "id":null, + "title":null, + "width":400, + "height":300, + "desc":'', + "controls":true, + // playlist user controlled features + "linkback":null, + "src":null, + "embed_link":true, + + // enable sequencer? (only display top frame no navigation or accompanying text + "sequencer":false +} +// The call back rate for animations and internal timers in ms: 33 is about 30 frames a second: +var MV_ANIMATION_CB_RATE = 33; + +// globals: +// 10 possible colors for clips: (can be in hexadecimal) +var mv_clip_colors = new Array( 'aqua', 'blue', 'fuchsia', 'green', 'lime', 'maroon', 'navy', 'olive', 'purple', 'red' ); + +// The base url for requesting stream metadata +if ( typeof wgServer == 'undefined' ) { + var defaultMetaDataProvider = 'http://metavid.org/overlay/archive_browser/export_cmml?stream_name='; +} else { + var defaultMetaDataProvider = wgServer + wgScript + '?title=Special:MvExportStream&feed_format=roe&stream_name='; +} +/* + * The playlist Object implements ~most~ of embedVideo but we don't inherit (other than to use the control builder) + * because pretty much every function has to be changed for the playlist context + */ +var mvPlayList = function( element ) { + return this.init( element ); +}; +// set up the mvPlaylist object +mvPlayList.prototype = { + instanceOf:'mvPlayList', + pl_duration:null, + update_tl_hook:null, + clip_ready_count:0, + cur_clip:null, + start_clip:null, + start_clip_src:null, + disp_play_head:null, + userSlide:false, + loading:true, + loading_external_data:true, // if we are loading external data (set to loading by default) + //set initial state to "paused" + paused:true, + + activeClipList:null, + playlist_buffer_time: 20, // how many seconds of future clips we should buffer + + interface_url:null, // the interface url + tracks: { }, + default_track:null, // the default track to add clips to. + // the layout for the playlist object + pl_layout : { + seq_title:.1, + clip_desc:.63, // displays the clip description + clip_aspect:1.33, // 4/3 video aspect ratio + seq:.25, // display clip thumbnails + seq_thumb:.25, // size for thumbnails (same as seq by default) + seq_nav:0, // for a nav bar at the base (currently disabled) + // some pl_layout info: + title_bar_height:17, + control_height:29 + }, + // embed object type support system; + supports: { + 'play_head':true, + 'pause':true, + 'fullscreen':false, + 'time_display':true, + 'volume_control':true, + + 'overlays':true, + 'playlist_swap_loader':true // if the object supports playlist functions + }, + init : function( element ) { + js_log( 'mvPlayList:init:' ); + this.tracks = { }; + this.default_track = null; + + this.activeClipList = new activeClipList(); + // add default track & default track pointer: + this.tracks[0] = new trackObj( { 'inx':0 } ); + this.default_track = this.tracks[0]; + + // get all the attributes: + for ( var attr in mv_default_playlist_attributes ) { + if ( element.getAttribute( attr ) ) { + this[attr] = element.getAttribute( attr ); + // js_log('attr:' + attr + ' val: ' + video_attributes[attr] +" "+'elm_val:' + element.getAttribute(attr) + "\n (set by elm)"); + } else { + this[attr] = mv_default_playlist_attributes[attr]; + // js_log('attr:' + attr + ' val: ' + video_attributes[attr] +" "+ 'elm_val:' + element.getAttribute(attr) + "\n (set by attr)"); + } + } + // make sure height and width are int: + this.width = parseInt( this.width ); + this.height = parseInt( this.height ); + + // if style is set override width and height + if ( element.style.width )this.width = parseInt( element.style.width.replace( 'px', '' ) ); + if ( element.style.height )this.height = parseInt( element.style.height.replace( 'px', '' ) ); + + // if controls=false hide the title and the controls: + if ( this.controls === false ) { + this.pl_layout.control_height = 0; + this.pl_layout.title_bar_height = 0; + } else { + // setup the controlBuilder object: + this.ctrlBuilder = new ctrlBuilder( this ); + } + }, + // the element has now been swapped into the dom: + on_dom_swap:function() { + js_log( 'pl: dom swap' ); + // get and load the html: + this.getHTML(); + }, + // run inheritEmbedObj on every clip (we have changed the playback method) + inheritEmbedObj:function() { + $j.each( this.tracks, function( i, track ) { + track.inheritEmbedObj(); + } ); + }, + doOptionsHTML:function() { + // grab "options" use current clip: + this.cur_clip.embed.doOptionsHTML(); + }, + // pulls up the video editor inline + doEditor:function() { + // black out the page: + // $j('body').append('
    ' ); + if ( this.controls == true ) { + var cpos = _this.height + _this.pl_layout.title_bar_height; + // give more space if not in sequence: + cpos += ( this.sequencer ) ? 2:5; + // append title: + $j( '#dc_' + _this.id ).append( + '
    ' + + '
    ' + + '
    ' + + _this.getControlsHTML() + + '
    ' + + '
    ' + ); + + // once the controls are in the DOM add hooks: + this.ctrlBuilder.addControlHooks( ); + } else { + // just append the video: + $j( '#dc_' + _this.id ).append( + '
    ' + ); + } + this.setupClipDisplay(); + + // update the title and status bar + this.updateBaseStatus(); + this.doSmilActions(); + }, + setupClipDisplay:function() { + js_log( 'mvPlaylist:setupClipDisplay:: clip len:' + this.default_track.clips.length ); + var _this = this; + $j.each( this.default_track.clips, function( i, clip ) { + var cout = '
    '; + $j( '#dc_' + _this.id ).append( cout ); + // update the embed html: + clip.embed.height = _this.height; + clip.embed.width = _this.width; + clip.embed.play_button = false; + clip.embed.controls = false; + + clip.embed.getHTML();// get the thubnails for everything + + $j( clip.embed ).css( { + 'position':"absolute", + 'top':"0px", + 'left':"0px" + } ); + if ( $j( '#clipDesc_' + clip.id ).length != 0 ) { + js_log( "should set: #clipDesc_" + clip.id + ' to: ' + $j( clip.embed ).html() ) + $j( '#clipDesc_' + clip.id ).append( clip.embed ); + } else { + js_log( 'cound not find: clipDesc_' + clip.id ); + } + } ); + if ( this.cur_clip ) + $j( '#clipDesc_' + this.cur_clip.id ).css( { display:'inline' } ); + }, + updateThumbPerc:function( perc ) { + // get float seconds: + var float_sec = ( this.getDuration() * perc ); + this.updateThumbTime( float_sec ); + }, + updateThumbTime:function( float_sec ) { + // update display & cur_clip: + var pl_sum_time = 0; + var clip_float_sec = 0; + // js_log('seeking clip: '); + for ( var i in this.default_track.clips ) { + var clip = this.default_track.clips[i]; + if ( ( clip.getDuration() + pl_sum_time ) >= float_sec ) { + if ( this.cur_clip.id != clip.id ) { + $j( '#clipDesc_' + this.cur_clip.id ).hide(); + this.cur_clip = clip; + $j( '#clipDesc_' + this.cur_clip.id ).show(); + } + break; + } + pl_sum_time += clip.getDuration(); + } + + // issue thumbnail update request: (if plugin supports it will render out frame + // if not then we do a call to the server to get a new jpeg thumbnail + this.cur_clip.embed.updateThumbTime( float_sec - pl_sum_time ); + + this.cur_clip.embed.currentTime = ( float_sec - pl_sum_time ) + this.cur_clip.embed.start_offset ; + this.cur_clip.embed.seek_time_sec = ( float_sec - pl_sum_time ); + + // render effects ontop: (handled by doSmilActions) + this.doSmilActions(); + }, + updateBaseStatus:function() { + var _this = this; + js_log( 'Playlist:updateBaseStatus' ); + + $j( '#ptitle_' + this.id ).html( '' + + '' + this.title + ' ' + + this.getClipCount() + ' clips, ' + + seconds2npt( this.getDuration() ) + '' ); + + // should probably be based on if we have a provider api url + if ( typeof wgEnableWriteAPI != 'undefined' && !this.sequencer ) { + $j( $j.btnHtml( 'edit', 'editBtn_' + this.id, 'pencil', + { 'style':'position:absolute;right:0;;font-size:x-small;height:10px;margin-bottom:0;padding-bottom:7px;padding-top:0;' } ) + ).click( function() { + _this.stop(); + _this.doEditor(); + return false; + } ).appendTo( '#ptitle_' + this.id ); + $j( '.editBtn_' + this.id ).btnBind(); + } + // render out the dividers on the timeline: + this.colorPlayHead(); + // update status: + this.setStatus( '0:0:00/' + seconds2npt( this.getDuration() ) ); + }, + /*setStatus override (could call the jquery directly) */ + setStatus:function( value ) { + $j( '#' + this.id + ' .time-disp' ).text( value ); + }, + setSliderValue:function( value ) { + // slider is on 1000 scale: + var val = parseInt( value * 1000 ); + //js_log( 'update slider: #' + this.id + ' .play_head to ' + val ); + $j( '#' + this.id + ' .play_head' ).slider( 'value', val ); + }, + getPlayHeadPos: function( prec_done ) { + var _this = this; + if ( $j( '#mv_seeker_' + this.id ).length == 0 ) { + js_log( 'no playhead so we can\'t get playhead pos' ); + return 0; + } + var track_len = $j( '#mv_seeker_' + this.id ).css( 'width' ).replace( /px/ , '' ); + // assume the duration is static and present at .duration during playback + var clip_perc = this.cur_clip.embed.duration / this.getDuration(); + var perc_offset = time_offset = 0; + for ( var i in this.default_track.clips ) { + var clip = this.default_track.clips[i]; + if ( this.cur_clip.id == clip.id )break; + perc_offset += ( clip.embed.duration / _this.getDuration() ); + time_offset += clip.embed.duration; + } + // run any update time line hooks: + if ( this.update_tl_hook ) { + var cur_time_ms = time_offset + Math.round( this.cur_clip.embed.duration * prec_done ); + if ( typeof update_tl_hook == 'function' ) { + this.update_tl_hook( cur_time_ms ); + } else { + // string type passed use eval: + eval( this.update_tl_hook + '(' + cur_time_ms + ');' ); + } + } + + // handle offset hack @@todo fix so this is not needed: + if ( perc_offset > .66 ) + perc_offset += ( 8 / track_len ); + // js_log('perc:'+ perc_offset +' c:'+ clip_perc + '*' + prec_done + ' v:'+(clip_perc*prec_done)); + return perc_offset + ( clip_perc * prec_done ); + }, + // attempts to load the embed object with the playlist + loadEmbedPlaylist: function() { + // js_log('load playlist'); + }, + /** mannages the loading of future clips + * called regurally while we are playing clips + * + * load works like so: + * if the current clip is full loaded + * load clips untill buffredEndTime < playlist_buffer_time load next + * + * this won't work so well with time range loading for smil (need to work on that) + */ + loadFutureClips:function() { + /*if( this.cur_clip.embed.bufferedPercent == 1){ + //set the buffer to the currentTime - duration + var curBuffredTime = this.cur_clip.getDuration() - this.cur_clip.embed.currentTime; + + if(curBuffredTime < 0) + curBuffredTime = 0; + + js_log( "curBuffredTime:: " + curBuffredTime ); + if( curBuffredTime < this.playlist_buffer_time ){ + js_log(" we only have " + curBuffredTime + ' buffed but we need: ' + this.playlist_buffer_time); + + for(var inx = this.cur_clip.order + 1; inx < this.default_track.clips.length; inx++ ){ + var cClip = this.default_track.getClip( inx ); + + //check if the clip is already loaded (add its duration) + if( cClip.embed.bufferedPercent == 1){ + curBuffredTime += cClip.embed.getDuration(); + } + //check if we still have to load a resource: + if( curBuffredTime < this.playlist_buffer_time ){ + //issue the load request + if( cClip.embed.networkState==0 ){ + cClip.embed.load(); + } + break; //check back next time + } + } + } + }*/ + }, + // called to play the next clip if done call onClipDone + playNext: function() { + // advance the playhead to the next clip + var next_clip = this.getNextClip(); + + if ( !next_clip ) { + js_log( 'play next with no next clip... must be done:' ); + this.onClipDone(); + return ; + } + // @@todo where the plugin supports pre_loading future clips and manage that in javascript + // stop current clip + this.cur_clip.embed.stop(); + + this.updateCurrentClip( next_clip ); + //if part of a transition should continue playing where it left off + this.cur_clip.embed.play(); + }, + onClipDone:function() { + js_log( "pl onClipDone" ); + this.cur_clip.embed.stop(); + }, + updateCurrentClip : function( new_clip , into_perc) { + js_log( 'f:updateCurrentClip:' + new_clip.id ); + + // keep the active play clip in sync (stop the other clip) + if ( this.cur_clip ) { + // make sure we are not switching to the current + if ( this.cur_clip.id == new_clip.id ) { + js_log( 'trying to updateCurrentClip to same clip' ); + return false; + } + + if ( !this.cur_clip.embed.isStoped() ) + this.cur_clip.embed.stop(); + this.activeClipList.remove( this.cur_clip ) + + //hide the current clip + $j( '#clipDesc_' + this.cur_clip.id ).hide(); + } + this.activeClipList.add( new_clip ); + // do swap: + this.cur_clip = new_clip; + $j( '#clipDesc_' + this.cur_clip.id ).show(); + + // Update the playhead: + if( this.controls ){ + // Check if we have into_perc + if( into_perc ){ + var clip_time = this.cur_clip.dur_offset + ( into_perc * this.cur_clip.getDuration() ); + }else{ + var clip_time = this.cur_clip.dur_offset; + } + + this.setSliderValue( clip_time / this.getDuration() ); + } + }, + playPrev: function() { + // advance the playhead to the previous clip + var prev_clip = this.getPrevClip(); + if ( !prev_clip ) { + js_log( "tried to play PrevClip with no prev Clip.. setting prev_clip to start clip" ); + prev_clip = this.start_clip; + } + // @@todo we could do something fancy like use playlist for sets of clips where supported. + // or in cases where the player nativly supports the playlist format we can just pass it in (ie m3u or xspf) + if ( this.cur_clip.embed.supports['playlist_swap_loader'] ) { + // where the plugin supports pre_loading future clips and manage that in javascript + // pause current clip + this.cur_clip.embed.pause(); + // do swap: + this.updateCurrentClip( prev_clip ); + this.cur_clip.embed.play(); + } else { + js_log( 'do prev hard embed swap' ); + this.switchPlayingClip( prev_clip ); + } + }, + switchPlayingClip:function( new_clip ) { + // swap out the existing embed code for next clip embed code + $j( '#mv_ebct_' + this.id ).empty(); + new_clip.embed.width = this.width; + new_clip.embed.height = this.height; + // js_log('set embed to: '+ new_clip.embed.getEmbedObj()); + $j( '#mv_ebct_' + this.id ).html( new_clip.embed.getEmbedObj() ); + this.cur_clip = new_clip; + // run js code: + this.cur_clip.embed.pe_postEmbedJS(); + }, + // playlist play + play: function() { + var _this = this; + js_log( 'pl play' ); + // hide the playlist play button: + $j( this.id + ' .play-btn-large' ).hide(); + + // un-pause if paused: + if ( this.paused ) + this.paused = false; + + // update the control: + this.start_clip = this.cur_clip; + this.start_clip_src = this.cur_clip.src; + + if ( this.cur_clip.embed.supports['playlist_swap_loader'] ) { + // set the cur_clip to active + this.activeClipList.add( this.cur_clip ); + + // navtive support: + // * pre-loads clips + // * mv_playlist smil extension, manages transitions animations overlays etc. + // js_log('clip obj supports playlist swap_loader (ie playlist controlled playback)'); + // @@todo pre-load each clip: + // play all active clips (playlist_swap_loader can have more than one clip active) + $j.each( this.activeClipList.getClipList(), function( inx, clip ) { + clip.embed.play(); + } ); + } else if ( this.cur_clip.embed.supports['playlist_driver'] ) { + // js_log('playlist_driver'); + // embedObject is feed the playlist info directly and manages next/prev + this.cur_clip.embed.playMovieAt( this.cur_clip.order ); + } else { + // not much playlist support just play the first clip: + // js_log('basic play'); + // play cur_clip + this.cur_clip.embed.play(); + } + // start up the playlist monitor + this.monitor(); + }, + /* + * the load function loads all the clips in order + */ + load:function() { + // do nothing right now) + alert('load pl'); + }, + toggleMute:function() { + this.cur_clip.embed.toggleMute(); + }, + pause:function() { + // js_log('f:pause: playlist'); + var ct = new Date(); + this.pauseTime = this.currentTime; + this.paused = true; + // js_log('pause time: '+ this.pauseTime + ' call embed pause:'); + + // pause all the active clips: + $j.each( this.activeClipList.getClipList(), function( inx, clip ) { + clip.embed.pause(); + } ); + }, + // @@todo mute across all child clips: + toggleMute:function() { + var this_id = ( this.pc != null ) ? this.pc.pp.id:this.id; + if ( this.muted ) { + this.muted = false; + $j( '#volume_control_' + this_id + ' span' ).removeClass( 'ui-icon-volume-off' ).addClass( 'ui-icon-volume-on' ); + $j( '#volume_bar_' + this_id ).slider( 'value', 100 ); + this.updateVolumen( 1 ); + } else { + this.muted = true; + $j( '#volume_control_' + this_id + ' span' ).removeClass( 'ui-icon-volume-on' ).addClass( 'ui-icon-volume-off' ); + $j( '#volume_bar_' + this_id ).slider( 'value', 0 ); + this.updateVolumen( 0 ); + } + js_log( 'f:toggleMute::' + this.muted ); + }, + updateVolumen:function( perc ) { + js_log( 'update volume not supported with current playback type' ); + }, + fullscreen:function() { + this.cur_clip.embed.fullscreen(); + }, + // playlist stops playback for the current clip (and resets state for start clips) + stop:function() { + var _this = this; + /*js_log("pl stop:"+ this.start_clip.id + ' c:'+this.cur_clip.id); + //if start clip + if(this.start_clip.id!=this.cur_clip.id){ + //restore clipDesc visibility & hide desc for start clip: + $j('#clipDesc_'+this.start_clip.id).html(''); + this.start_clip.getDetail(); + $j('#clipDesc_'+this.start_clip.id).css({display:'none'}); + this.start_clip.setBaseEmbedDim(this.start_clip.embed); + //equivalent of base stop + $j('#'+this.start_clip.embed.id).html(this.start_clip.embed.getThumbnailHTML()); + this.start_clip.embed.thumbnail_disp=true; + } + //empty the play-back container + $j('#mv_ebct_'+this.id).empty();*/ + + // stop all the clips: monitor: + window.clearInterval( this.smil_monitorTimerId ); + /*for (var i=0;i pt ) { + // js_log('seek:'+ pt +' - '+perc_offset + ') / (' + next_perc_offset +' - '+ perc_offset); + var relative_perc = ( pt - perc_offset ) / ( next_perc_offset - perc_offset ); + // update the current clip: + _this.updateCurrentClip( clip, relative_perc ); + return relative_perc; + } + perc_offset = next_perc_offset; + } + return 0; + }, + // gets playlist controls large control height for sporting + // next prev button and more status display + getControlsHTML:function() { + // get controls from current clip (add some playlist specific controls: + return this.ctrlBuilder.getControls( this ); + }, + // ads colors/dividers between tracks + colorPlayHead: function() { + var _this = this; + + if ( !_this.mv_seeker_width ) + _this.mv_seeker_width = $j( '#' + _this.id + ' .play_head' ).width(); + + if ( !_this.track_len ) + _this.track_len = $j( '#' + _this.id + ' .play_head' ).width(); + + // total duration: + var pl_duration = _this.getDuration(); + + var cur_pixle = 0; + // set up _this + + // js_log("do play head total dur: "+pl_duration ); + $j.each( this.default_track.clips, function( i, clip ) { + // (use getSoloDuration to not include transitions and such) + var perc = ( clip.getSoloDuration() / pl_duration ); + var pwidth = Math.round( perc * _this.track_len ); + // js_log('pstatus:c:'+ clip.getDuration() + ' of '+ pl_duration+' %:' + perc + ' width: '+ pwidth + ' of total: ' + _this.track_len); + // var pwidth = Math.round( perc * _this.track_len - (_this.mv_seeker_width*perc) ); + + // add the buffer child indicator: + var barHtml = '
    '; + + barHtml += _this.ctrlBuilder.getMvBufferHtml(); + + barHtml += '
    '; + + // background:#DDD +clip.getColor(); + + $j( '#' + _this.id + ' .play_head' ).append( barHtml ); + + // js_log('offset:' + cur_pixle +' width:'+pwidth+' add clip'+ clip.id + ' is '+clip.embed.getDuration() +' = ' + perc +' of ' + _this.track_len); + cur_pixle += pwidth; + } ); + }, + // @@todo currently not really in use + setUpHover:function() { + js_log( 'Setup Hover' ); + // set up hover for prev,next + var th = 50; + var tw = th * this.pl_layout.clip_aspect; + var _this = this; + $j( '#mv_prev_link_' + _this.id + ',#mv_next_link_' + _this.id ).hover( function() { + var clip = ( this.id == 'mv_prev_link_' + _this.id ) ? _this.getPrevClip() : _this.getNextClip(); + if ( !clip ) + return js_log( 'missing clip for Hover' ); + // get the position of #mv_perv|next_link: + var loc = getAbsolutePos( this.id ); + // js_log('Hover: x:'+loc.x + ' y:' + loc.y + ' :'+clip.img); + $j( "body" ).append( '
    ' + + '' + + '
    ' ); + }, function() { + $j( '#mv_Athub' ).remove(); + } ); + }, + // @@todo we need to move a lot of this track logic like "cur_clip" to the track Obj + // and have the playlist just drive the tracks. + getNextClip:function( track ) { + if ( !track ) + track = this.default_track; + var tc = parseInt( this.cur_clip.order ) + 1; + var cat = track; + if ( tc > track.getClipCount() - 1 ) + return false; // out of range + + return track.getClip( tc ); + }, + getPrevClip:function( track ) { + if ( !track ) + track = this.default_track; + var tc = parseInt( this.cur_clip.order ) - 1; + if ( tc < 0 ) + return false; + return track.getClip( tc ); + }, + /* + * generic add Clip to ~default~ track + */ + addCliptoTrack: function( clipObj, pos ) { + if ( typeof clipObj['track_id'] == 'undefined' ) { + var track = this.default_track; + } else { + var track = this.tracks[ clipObj.track_id ] + } + js_log( 'add clip:' + clipObj.id + ' to track: at:' + pos ); + // set the first clip to current (maybe deprecated ) + if ( clipObj.order == 0 ) { + if ( !this.cur_clip )this.cur_clip = clipObj; + } + track.addClip( clipObj, pos ); + }, + swapClipDesc: function( req_clipID, callback ) { + // hide all but the requested + var _this = this; + js_log( 'r:' + req_clipID + ' cur:' + _this.id ); + if ( req_clipID == _this.cur_clip.id ) { + js_log( 'no swap to same clip' ); + } else { + // fade out clips + req_clip = null; + $j.each( this.default_track.clips, function( i, clip ) { + if ( clip.id != req_clipID ) { + // fade out if display!=none already + if ( $j( '#clipDesc_' + clip.id ).css( 'display' ) != 'none' ) { + $j( '#clipDesc_' + clip.id ).fadeOut( "slow" ); + } + } else { + req_clip = clip; + } + } ); + // fade in requested clip *and set req_clip to current + $j( '#clipDesc_' + req_clipID ).fadeIn( "slow", function() { + _this.cur_clip = req_clip; + if ( callback ) + callback(); + } ); + } + }, + // this is pretty outdated: + getPLControls: function() { + js_log( 'getPL cont' ); + return '' + + getTransparentPng( { id:'mv_prev_btn_' + this.id, style:'float:left', width:'27', height:'27', border:"0", + src:mv_skin_img_path + 'vid_prev_sm.png' } ) + + '' + + '' + + getTransparentPng( { id:'mv_next_btn_' + this.id, style:'float:left', width:'27', height:'27', border:"0", + src:mv_skin_img_path + 'vid_next_sm.png' } ) + + ''; + }, + run_transition: function( clip_inx, trans_type ) { + if ( typeof this.default_track.clips[ clip_inx ][ trans_type ] == 'undefined' ) + clearInterval( this.default_track.clips[ clip_inx ].timerId ); + else + this.default_track.clips[ clip_inx ][ trans_type ].run_transition(); + }, + playerPixelWidth : function() + { + var player = $j( '#dc_' + this.id ).get( 0 ); + if ( typeof player != 'undefined' && player['offsetWidth'] ) + return player.offsetWidth; + else + return parseInt( this.width ); + }, + playerPixelHeight : function() + { + var player = $j( '#dc_' + this.id ).get( 0 ); + if ( typeof player != 'undefined' && player['offsetHeight'] ) + return player.offsetHeight; + else + return parseInt( this.height ); + } +} + +/* Object Stubs: + * + * @videoTrack ... stores clips and layer info + * + * @clip... each clip segment is a clip object. + * */ +var mvClip = function( o ) { + if ( o ) + this.init( o ); + return this; +}; +// set up the mvPlaylist object +mvClip.prototype = { + id:null, // clip id + pp:null, // parent playlist + order:null, // the order/array key for the current clip + src:null, + info:null, + title:null, + mvclip:null, + type:null, + img:null, + duration:null, + loading:false, + isAnimating:false, + init:function( o ) { + // init object including pointer to parent + for ( var i in o ) { + this[i] = o[i]; + }; + js_log( 'id is: ' + this.id ); + }, + // setup the embed object: + setUpEmbedObj:function() { + js_log( 'mvClip:setUpEmbedObj()' ); + + this.embed = null; + // js_log('setup embed for clip '+ this.id + ':id is a function?'); + // set up the pl_mv_embed object: + var init_pl_embed = { id:'e_' + this.id, + pc:this, // parent clip + src:this.src + }; + + this.setBaseEmbedDim( init_pl_embed ); + + + // if in sequence mode hide controls / embed links + // init_pl_embed.play_button=false; + // init_pl_embed.controls=true; + // if(this.pp.sequencer=='true'){ + init_pl_embed.embed_link = null; + init_pl_embed.linkback = null; + + if( this.durationHint ) + init_pl_embed.durationHint = this.durationHint; + + if ( this.poster )init_pl_embed['thumbnail'] = this.poster; + + if ( this.type )init_pl_embed['type'] = this.type; + + this.embed = new PlMvEmbed( init_pl_embed ); + + // js_log('media Duration:' + this.embed.getDuration() ); + // js_log('media element:'+ this.embed.media_element.length); + // js_log('type of embed:' + typeof(this.embed) + ' seq:' + this.pp.sequencer+' pb:'+ this.embed.play_button); + }, + doAdjust:function( side, delta ) { + js_log( "f:doAdjust: " + side + ' , ' + delta ); + if ( this.embed ) { + if ( side == 'start' ) { + var start_offset = parseInt( this.embed.start_offset ) + parseInt( delta * -1 ); + this.embed.updateVideoTime( seconds2npt( start_offset ), seconds2npt ( this.embed.start_offset + this.embed.getDuration() ) ); + } else if ( side == 'end' ) { + var end_offset = parseInt( this.embed.start_offset ) + parseInt( this.embed.getDuration() ) + parseInt( delta ); + this.embed.updateVideoTime( seconds2npt( this.embed.start_offset ), seconds2npt( end_offset ) ); + } + // update everything: + this.pp.refresh(); + /*var base_src = this.src.substr(0,this.src.indexOf('?')); + js_log("delta:"+ delta); + if(side=='start'){ + //since we adjust start invert the delta: + var start_offset =parseInt(this.embed.start_offset/1000)+parseInt(delta*-1); + this.src = base_src +'?t='+ seconds2npt(start_offset) +'/'+ this.embed.end_ntp; + }else if(side=='end'){ + //put back into seconds for adjustment: + var end_offset = parseInt(this.embed.start_offset/1000) + parseInt(this.embed.duration/1000) + parseInt(delta); + this.src = base_src +'?t='+ this.embed.start_ntp +'/'+ seconds2npt(end_offset); + } + this.embed.updateVideoTime( this.src ); + //update values + this.duration = this.embed.getDuration(); + this.pp.pl_duration=null; + //update playlist stuff: + this.pp.updateTitle();*/ + } + }, + getDuration:function() { + if ( !this.embed )this.setUpEmbedObj(); + return this.embed.getDuration(); + }, + setBaseEmbedDim:function( o ) { + if ( !o )o = this; + // o.height=Math.round(pl_layout.clip_desc*this.pp.height)-2;//give it some padding: + // o.width=Math.round(o.height*pl_layout.clip_aspect)-2; + o.height = this.pp.height; + o.width = this.pp.width; + }, + // output the detail view: + // @@todo + /*getDetail:function(){ + //js_log('get detail:' + this.pp.title); + var th=Math.round( this.pl_layout.clip_desc * this.pp.height ); + var tw=Math.round( th * this.pl_layout.clip_aspect ); + + var twDesc = (this.pp.width-tw)-2; + + if(this.title==null) + this.title='clip ' + this.order + ' ' +this.pp.title; + if(this.desc==null) + this.desc=this.pp.desc; + //update the embed html: + this.embed.getHTML(); + + $j(this.embed).css({ 'position':"absolute",'top':"0px", 'left':"0px"}); + + //js_log('append child to:#clipDesc_'+this.id); + if($j('#clipDesc_'+this.id).get(0)){ + $j('#clipDesc_'+this.id).get(0).appendChild(this.embed); + + $j('#clipDesc_'+this.id).append(''+ + '
    '+ + ''+this.title+'
    '+ + this.desc + '
    ' + + 'clip length: '+ seconds2npt( this.embed.getDuration() ); + '
    '); + } + },*/ + getTitle:function() { + if ( typeof this.title == 'string' ) + return this.title + + return 'untitled clip ' + this.order; + }, + getClipImg:function( start_offset, size ) { + js_log( 'f:getClipImg ' + start_offset + ' s:' + size ); + if ( !this.img ) { + return mv_default_thumb_url; + } else { + if ( !size && !start_offset ) { + return this.img; + } else { + // if a metavid image (has request parameters) use size and time args + if ( this.img.indexOf( '?' ) != -1 ) { + js_log( 'get with offset: ' + start_offset ); + var time = seconds2npt( start_offset + ( this.embed.start_offset / 1000 ) ); + js_log( "time is: " + time ); + this.img = this.img.replace( /t\=[^&]*/gi, "t=" + time ); + if ( this.img.indexOf( '&size=' ) != -1 ) { + this.img = this.img.replace( /size=[^&]*/gi, "size=" + size ); + } else { + this.img += '&size=' + size; + } + } + return this.img; + } + } + }, + getColor: function() { + // js_log('get color:'+ num +' : '+ num.toString().substr(num.length-1, 1) + ' : '+colors[ num.toString().substr(num.length-1, 1)] ); + var num = this.id.substr( this.id.length - 1, 1 ); + if ( !isNaN( num ) ) { + num = num.charCodeAt( 0 ); + } + if ( num >= 10 )num = num % 10; + return mv_clip_colors[num]; + } +} +/* mv_embed extensions for playlists */ +var PlMvEmbed = function( vid_init ) { + // js_log('PlMvEmbed: '+ vid_init.id); + // create the div container + var ve = document.createElement( 'div' ); + // extend ve with all this + this.init( vid_init ); + for ( method in this ) { + if ( method != 'readyState' ) { + ve[method] = this[method]; + } + } + js_log( 've src len:' + ve.media_element.sources.length ); + return ve; +} +// all the overwritten and new methods for playlist extension of baseEmbed +PlMvEmbed.prototype = { + init:function( vid_init ) { + // send embed_video a created video element: + ve = document.createElement( 'div' ); + for ( var i in vid_init ) { + // set the parent clip pointer: + if ( i == 'pc' ) { + this['pc'] = vid_init['pc']; + } else { + ve.setAttribute( i, vid_init[i] ); + } + } + var videoInterface = new embedVideo( ve ); + // inherit the videoInterface + for ( method in videoInterface ) { + if ( method != 'style' ) { + if ( this[ method ] ) { + // parent embed method preservation: + this['pe_' + method] = videoInterface[method]; + } else { + this[method] = videoInterface[method]; + } + } + // string -> boolean: + if ( this[method] == "false" )this[method] = false; + if ( this[method] == "true" )this[method] = true; + } + }, + onClipDone:function() { + js_log( 'pl onClipDone (should go to next)' ); + // go to next in playlist: + this.pc.pp.playNext(); + }, + stop:function() { + js_log( 'pl:do stop' ); + // set up convenience pointer to parent playlist + var _this = this.pc.pp; + + var th = Math.round( _this.pl_layout.clip_desc * _this.height ); + var tw = Math.round( th * _this.pl_layout.clip_aspect ); + + // run the parent stop: + this.pe_stop(); + var pl_height = ( _this.sequencer == 'true' ) ? _this.height + 27:_this.height; + + this.getHTML(); + }, + play:function() { + // js_log('pl eb play'); + var _this = this.pc.pp; + // check if we are already playing + if ( !this.thumbnail_disp ) { + this.pe_play(); + return ''; + } + mv_lock_vid_updates = true; + this.pe_play(); + }, + // do post interface operations + postEmbedJS:function() { + // add playlist clips (if plugin supports it) + if ( this.pc.pp.cur_clip.embed.playlistSupport() ) + this.pc.pp.loadEmbedPlaylist(); + // color playlist points (if play_head present) + if ( this.pc.pp.disp_play_head ) + this.pc.pp.colorPlayHead(); + // setup hover images (for playhead and next/prev buttons) + this.pc.pp.setUpHover(); + // call the parent postEmbedJS + this.pe_postEmbedJS(); + mv_lock_vid_updates = false; + }, + getPlayButton:function() { + return this.pe_getPlayButton( this.pc.pp.id ); + }, + setStatus:function( value ) { + // status updates handled by playlist obj + }, + setSliderValue:function( value ) { + //js_log( 'PlMvEmbed:setSliderValue:' + value ); + // setSlider value handled by playlist obj + } +} + +/* + * m3u parse + */ +var m3uPlaylist = { + doParse:function() { + // for each line not # add as clip + var inx = 0; + var this_pl = this; + // js_log('data:'+ this.data.toString()); + $j.each( this.data.split( "\n" ), function( i, n ) { + // js_log('on line '+i+' val:'+n+' len:'+n.length); + if ( n.charAt( 0 ) != '#' ) { + if ( n.length > 3 ) { + // @@todo make sure its a valid url + // js_log('add url: '+i + ' '+ n); + var cur_clip = new mvClip( { type:'srcClip', id:'p_' + this_pl.id + '_c_' + inx, pp:this_pl, src:n, order:inx } ); + // setup the embed object + cur_clip.setUpEmbedObj(); + js_log( 'm3uPlaylist len:' + thisClip.embed.media_element.sources.length ); + this_pl.addCliptoTrack( cur_clip ); + inx++; + } + } + } ); + return true; + } +} + +var itunesPlaylist = { + doParse:function() { + var properties = { title:'title', linkback:'link', + author:'itunes:author', desc:'description', + date:'pubDate' }; + var tmpElm = null; + for ( i in properties ) { + tmpElm = this.data.getElementsByTagName( properties[i] )[0]; + if ( tmpElm ) { + this[i] = tmpElm.childNodes[0].nodeValue; + // js_log('set '+i+' to '+this[i]); + } + } + // image src is nested in itunes rss: + tmpElm = this.data.getElementsByTagName( 'image' )[0]; + if ( tmpElm ) { + imgElm = tmpElm.getElementsByTagName( 'url' )[0]; + if ( imgElm ) { + this.img = imgElm.childNodes[0].nodeValue; + } + } + // get the clips: + var clips = this.data.getElementsByTagName( "item" ); + properties.src = 'guid'; + for ( var i = 0; i < clips.length; i++ ) { + var cur_clip = new mvClip( { type:'srcClip', id:'p_' + this.id + '_c_' + i, pp:this, order:i } ); + for ( var j in properties ) { + tmpElm = clips[i].getElementsByTagName( properties[j] )[0]; + if ( tmpElm != null ) { + cur_clip[j] = tmpElm.childNodes[0].nodeValue; + // js_log('set clip property: ' + j+' to '+cur_clip[j]); + } + } + // image is nested + tmpElm = clips[i].getElementsByTagName( 'image' )[0]; + if ( tmpElm ) { + imgElm = tmpElm.getElementsByTagName( 'url' )[0]; + if ( imgElm ) { + cur_clip.img = imgElm.childNodes[0].nodeValue; + } + } + // set up the embed object now that all the values have been set + cur_clip.setUpEmbedObj(); + + // add the current clip to the clip list + this.addCliptoTrack( cur_clip ); + } + return true; + } +} + +/* + * parse xsfp: + * http://www.xspf.org/xspf-v1.html + */ +var xspfPlaylist = { + doParse:function() { + // js_log('do xsfp parse: '+ this.data.innerHTML); + var properties = { title:'title', linkback:'info', + author:'creator', desc:'annotation', + poster:'image', date:'date' }; + var tmpElm = null; + // get the first instance of any of the meta tags (ok that may be the meta on the first clip) + // js_log('do loop on properties:' + properties); + for ( i in properties ) { + js_log( 'on property: ' + i ); + tmpElm = this.data.getElementsByTagName( properties[i] )[0]; + if ( tmpElm ) { + if ( tmpElm.childNodes[0] ) { + this[i] = tmpElm.childNodes[0].nodeValue; + js_log( 'set pl property: ' + i + ' to ' + this[i] ); + } + } + } + var clips = this.data.getElementsByTagName( "track" ); + js_log( 'found clips:' + clips.length ); + // add any clip specific properties + properties.src = 'location'; + for ( var i = 0; i < clips.length; i++ ) { + var cur_clip = new mvClip( { id:'p_' + this.id + '_c_' + i, pp:this, order:i } ); + // js_log('cur clip:'+ cur_clip.id); + for ( var j in properties ) { + tmpElm = clips[i].getElementsByTagName( properties[j] )[0]; + if ( tmpElm != null ) { + if ( tmpElm.childNodes.length != 0 ) { + cur_clip[j] = tmpElm.childNodes[0].nodeValue; + js_log( 'set clip property: ' + j + ' to ' + cur_clip[j] ); + } + } + } + // add mvClip ref from info link: + if ( cur_clip.linkback ) { + // if mv linkback + mvInx = 'Stream:'; + mvclippos = cur_clip.linkback.indexOf( mvInx ); + if ( mvclippos !== false ) { + cur_clip.mvclip = cur_clip.linkback.substr( mvclippos + mvInx.length ); + } + } + // set up the embed object now that all the values have been set + cur_clip.setUpEmbedObj(); + // add the current clip to the clip list + this.addCliptoTrack( cur_clip ); + } + // js_log('done with parse'); + return true; + } +} +/***************************** + * SMIL CODE (could be put into another js file / lazy_loaded for improved basic playlist performance / modularity) + *****************************/ +/*playlist driver extensions to the playlist object*/ +mvPlayList.prototype.monitor = function() { + // js_log('pl:monitor'); + // if paused stop updates + if ( this.paused ) { + // clearInterval( this.smil_monitorTimerId ); + return ; + } + // js_log("pl check: " + this.currentTime + ' > '+this.getDuration()); + // check if we should be done: + if ( this.currentTime > this.getDuration() ) + this.stop(); + + // update the playlist current time: + // check for a trsnOut from the previus clip to subtract + this.currentTime = this.cur_clip.dur_offset + this.cur_clip.embed.relativeCurrentTime(); + + // update slider: + if ( !this.userSlide ) { + this.setStatus( seconds2npt( this.currentTime ) + '/' + seconds2npt( this.getDuration() ) ); + this.setSliderValue( this.currentTime / this.getDuration() ); + } + // pre-load any future clips: + this.loadFutureClips(); + + + // status updates are handled by children clips ... playlist mostly manages smil actions + this.doSmilActions(); + + if ( ! this.smil_monitorTimerId ) { + if ( document.getElementById( this.id ) ) { + this.smil_monitorTimerId = setInterval( '$j(\'#' + this.id + '\').get(0).monitor()', 250 ); + } + } +} + +// handles the rendering of overlays load of future clips (if necessary) +// @@todo could be lazy loaded if necessary +mvPlayList.prototype.doSmilActions = function( callback ) { + var _this = this; + // js_log('f:doSmilActions: ' + this.cur_clip.id + ' tid: ' + this.cur_clip.transOut ); + var offSetTime = 0; // offset time should let us start a transition later on if we have to. + var _clip = this.cur_clip; // setup a local pointer to cur_clip + + + // do any smil time actions that may change the current clip + if ( this.userSlide ) { + // current clip set is updated mannually outside the scope of smil Actions + } else { + // Assume playing and go to next: + if ( _clip.dur <= _clip.embed.currentTime + && _clip.order != _clip.pp.getClipCount() - 1 ) { + // force next clip + js_log( 'order:' + _clip.order + ' != count:' + ( _clip.pp.getClipCount() - 1 ) + + ' smil dur: ' + _clip.dur + ' <= curTime: ' + _clip.embed.currentTime + ' go to next clip..' ); + // do a _play next: + _clip.pp.playNext(); + } + } + // @@todo could maybe generalize transIn with trasOut into one "flow" with a few scattered if statements + // update/setup all transitions (will render current transition state) + + // process actions per transition types: + _this.procTranType( 'transIn', callback); + _this.procTranType( 'transOut', callback); +} + +/* +* procTranType +* @param {string} tid the transition type [transIn|transOut] +* @param {function} callback the callback function passed onto doUPdate +*/ +mvPlayList.prototype.procTranType = function( tid, callback){ + // Setup local clip pointer: + var _clip = this.cur_clip; + + eval( 'var tObj = _clip.' + tid ); + if ( !tObj ) + return; + // js_log('f:doSmilActions: ' + _clip.id + ' tid:'+tObj.id + ' tclip_id:'+ tObj.pClip.id); + // Check if we are in range: + if ( tid == 'transIn' ) + in_range = ( _clip.embed.currentTime <= tObj.dur ) ? true : false; + + if ( tid == 'transOut' ) + in_range = ( _clip.embed.currentTime >= ( _clip.dur - tObj.dur ) ) ? true : false; + + if ( in_range ) { + if ( this.userSlide || this.paused ) { + if ( tid == 'transIn' ){ + mvTransLib.doUpdate( tObj, + ( _clip.embed.currentTime / tObj.dur ), + callback ); + } + if ( tid == 'transOut' ){ + mvTransLib.doUpdate( tObj, + ( ( _clip.embed.currentTime - ( _clip.dur - tObj.dur ) ) / tObj.dur ), + callback ); + } + } else if ( tObj.animation_state == 0 ) { + js_log( 'init/run_transition ' ); + tObj.run_transition(); + } + } else { + // Close up transition if done & still onDispaly + if ( tObj.overlay_selector_id ) { + js_log( 'close up transition :' + tObj.overlay_selector_id ); + mvTransLib.doCloseTransition( tObj ); + } + } + // Run the callback:: + if( callback ) + callback(); +} + +/* + * mvTransLib library of transitions + * a single object called to initiate transition effects can easily be extended in separate js file + * /mvTransLib is a all static object no instances of mvTransLib/ + * (that way a limited feature set "sequence" need not include a _lot_ of js unless necessary ) + * + * Smil Transition Effects see: + * http://www.w3.org/TR/SMIL3/smil-transitions.html#TransitionEffects-TransitionAttribute + */ +var mvTransLib = { + /* + * function doTransition lookups up the transition in the mvTransLib obj + * and init the transition if its available + * @param tObj transition attribute object + * @param offSetTime default value 0 if we need to start rendering from a given time + */ + doInitTransition:function( tObj ) { + js_log( 'mvTransLib:f:doInitTransition' ); + if ( !tObj.type ) { + js_log( 'transition is missing type attribute' ); + return false; + } + + if ( !tObj.subtype ) { + js_log( 'transition is missing subtype attribute' ); + return false; + } + + if ( !this['type'][tObj.type] ) { + js_log( 'mvTransLib does not support type: ' + tObj.type ); + return false; + } + + if ( !this['type'][tObj.type][tObj.subtype] ) { + js_log( 'mvTransLib does not support subType: ' + tObj.subtype ); + return false; + } + + // setup overlay_selector_id + if ( tObj.subtype == 'crossfade' ) { + if ( tObj.transAttrType == 'transIn' ) + var other_pClip = tObj.pClip.pp.getPrevClip(); + if ( tObj.transAttrType == 'transOut' ) + var other_pClip = tObj.pClip.pp.getNextClip(); + + if ( typeof( other_pClip ) == 'undefined' || other_pClip === false || other_pClip.id == tObj.pClip.pp.cur_clip.id ) + js_log( 'Error: crossfade without target media asset' ); + // if not sliding start playback: + if ( !tObj.pClip.pp.userSlide && !tObj.pClip.pp.paused) { + other_pClip.embed.play(); + }else{ + //issue a load request: + other_pClip.embed.load(); + } + // manualy ad the extra layer to the activeClipList + tObj.pClip.pp.activeClipList.add( other_pClip ); + tObj.overlay_selector_id = 'clipDesc_' + other_pClip.id; + } else { + tObj.overlay_selector_id = this.getOverlaySelector( tObj ); + } + + // all good call function with tObj param + js_log( 'should call: ' + tObj.type + ' ' + tObj.subtype ); + this['type'][tObj.type][tObj.subtype].init( tObj ); + }, + doCloseTransition:function( tObj ) { + if ( tObj.subtype == 'crossfade' ) { + // close up crossfade + js_log( "close up crossfade" ); + } else { + $j( '#' + tObj.overlay_selector_id ).remove(); + } + // null selector: + tObj.overlay_selector_id = null; + }, + getOverlaySelector:function( tObj ) { + var overlay_selector_id = tObj.transAttrType + tObj.pClip.id; + js_log( 'f:getOverlaySelector: ' + overlay_selector_id + ' append to: ' + '#videoPlayer_' + tObj.pClip.embed.id ); + // make sure overlay_selector_id not already here: + if ( $j( '#' + overlay_selector_id ).length == 0 ) { + $j( '#videoPlayer_' + tObj.pClip.embed.id ).prepend( '' + + '
    ' + + '
    ' ); + } + return overlay_selector_id; + }, + doUpdate:function( tObj, percent, callback ) { + // init the transition if necessary: + if ( !tObj.overlay_selector_id ) + this.doInitTransition( tObj ); + + // @@todo we should ensure viability outside of doUpate loop + if ( !$j( '#' + tObj.overlay_selector_id ).is( ':visible' ) ) + $j( '#' + tObj.overlay_selector_id ).show(); + + // do update: + /* js_log('doing update for: '+ tObj.pClip.id + + ' type:' + tObj.transAttrType + + ' t_type:'+ tObj.type + + ' subypte:'+ tObj.subtype + + ' percent:' + percent);*/ + + this[ 'type' ][ tObj.type ][ tObj.subtype ].u( tObj, percent, callback); + }, + getTransitionIcon:function( type, subtype ) { + return mv_embed_path + '/skins/common/transition_images/' + type + '_' + subtype + '.png'; + }, + /* + * mvTransLib: functional library mapping: + */ + type: { + // Types: + fade: { + fadeFromColor: { + 'attr' : ['fadeColor'], + 'init' : function( tObj ) { + // js_log('f:fadeFromColor: '+tObj.overlay_selector_id +' to color: '+ tObj.fadeColor); + if ( !tObj.fadeColor ) + js_log( 'missing fadeColor' ); + if ( $j( '#' + tObj.overlay_selector_id ).length == 0 ) { + js_log( "ERROR can't find: " + tObj.overlay_selector_id ); + } + // set the initial state + $j( '#' + tObj.overlay_selector_id ).css( { + 'background-color':tObj.fadeColor, + 'opacity':"1" + } ); + }, + 'u' : function( tObj, percent ) { + // js_log(':fadeFromColor:update: '+ percent); + // fade from color (invert the percent) + var percent = 1 - percent; + $j( '#' + tObj.overlay_selector_id ).css( { + "opacity" : percent + } ); + } + }, + // corssFade + crossfade: { + "attr" : [], + "init" : function( tObj ) { + js_log( 'f:crossfade: ' + tObj.overlay_selector_id ); + if ( $j( '#' + tObj.overlay_selector_id ).length == 0 ) + js_log( "ERROR overlay selector not found: " + tObj.overlay_selector_id ); + + // set the initial state show the zero opacity animation + $j( '#' + tObj.overlay_selector_id ).css( { 'opacity':0 } ).show(); + }, + 'u':function( tObj, percent ) { + // Do the relative seek: + $j( '#' + tObj.overlay_selector_id ).css( { + "opacity" : percent + } ); + } + } + } + } +} + +/* object to manage embedding html with smil timings + * grabs settings from parent clip + */ +var transitionObj = function( element ) { + this.init( element ); +}; +transitionObj.prototype = { + supported_attributes : new Array( + 'id', + 'type', + 'subtype', + 'fadeColor', + 'dur' + ), + transAttrType:null, // transIn or transOut + overlay_selector_id:null, + pClip:null, + timerId:null, + animation_state:0, // can be 0=unset, 1=running, 2=done + interValCount:0, // inter-intervalCount for animating between time updates + dur:2, // default duration of 2 + init:function( element ) { + // load supported attributes: + var _this = this; + $j.each( this.supported_attributes, function( i, attr ) { + if ( element.getAttribute( attr ) ) + _this[attr] = element.getAttribute( attr ); + } ); + // @@todo process duration (for now just strip s) per: + // http://www.w3.org/TR/SMIL3/smil-timing.html#Timing-ClockValueSyntax + if ( _this.dur ) + _this.dur = smilParseTime( _this.dur ); + }, + /* + * returns a visual representation of the transition + */ + getIconSrc:function( opt ) { + // @@todo support some arguments + return mvTransLib.getTransitionIcon( this.type, this.subtype ); + }, + getDuration:function() { + return this.dur; + }, + // returns the values of supported_attributes: + getAttributeObj:function() { + var elmObj = { }; + for ( var i in this.supported_attributes ) { + var attr = this.supported_attributes[i]; + if ( this[ attr ] ) + elmObj[ attr ] = this[ attr ]; + } + return elmObj; + }, + /* + * the main animation loop called every MV_ANIMATION_CB_RATE or 34ms ~around 30frames per second~ + */ + run_transition:function() { + // js_log('f:run_transition:' + this.interValCount); + + // update the time from the video if native: + if ( typeof this.pClip.embed.vid != 'undefined' ) { + this.interValCount = 0; + this.pClip.embed.currentTime = this.pClip.embed.vid.currentTime; + } + + // }else{ + // relay on currentTime update grabs (every 250ms or so) (ie for images) + // if(this.prev_curtime!=this.pClip.embed.currentTime){ + // this.prev_curtime = this.pClip.embed.currentTime; + // this.interValCount=0; + // } + // } + + // start_time =assigned by doSmilActions + // base_cur_time = pClip.embed.currentTime; + // dur = assigned by attribute + if ( this.animation_state == 0 ) { + mvTransLib.doInitTransition( this ); + this.animation_state = 1; + } + // set percentage include diffrence of currentTime to prev_curTime + // ie updated in-between currentTime updates) + + if ( this.transAttrType == 'transIn' ) + var percentage = ( this.pClip.embed.currentTime + + ( ( this.interValCount * MV_ANIMATION_CB_RATE ) / 1000 ) + ) / this.dur ; + + if ( this.transAttrType == 'transOut' ) + var percentage = ( this.pClip.embed.currentTime + + ( ( this.interValCount * MV_ANIMATION_CB_RATE ) / 1000 ) + - ( this.pClip.dur - this.dur ) + ) / this.dur ; + + /*js_log('percentage = ct:'+this.pClip.embed.currentTime + ' + ic:'+this.interValCount +' * cb:'+MV_ANIMATION_CB_RATE + + ' / ' + this.dur + ' = ' + percentage ); + */ + + // js_log('cur percentage of transition: '+percentage); + // update state based on current time + cur_time_offset (for now just use pClip.embed.currentTime) + mvTransLib.doUpdate( this, percentage ); + + if ( percentage >= 1 ) { + js_log( "transition done update with percentage " + percentage ); + this.animation_state = 2; + clearInterval( this.timerId ); + mvTransLib.doCloseTransition( this ) + return true; + } + + this.interValCount++; + // setInterval in we are still in running state and user is not using the playhead + if ( this.animation_state == 1 ) { + if ( !this.timerId ) { + this.timerId = setInterval( 'document.getElementById(\'' + this.pClip.pp.id + '\').' + + 'run_transition(\'' + this.pClip.pp.cur_clip.order + '\',' + + '\'' + this.transAttrType + '\')', + MV_ANIMATION_CB_RATE ); + } + } else { + clearInterval( this.timerId ); + } + return true; + }, + clone :function() { + var cObj = new this.constructor(); + for ( var i in this ) + cObj[i] = this[i]; + return cObj; + } +} + +// very limited smile feature set more details soon: +// region="video_region" transIn="fromGreen" begin="2s" +// http://www.w3.org/TR/2007/WD-SMIL3-20070713/smil-extended-media-object.html#edef-ref +var smilPlaylist = { + transitions: { }, + doParse:function() { + var _this = this; + js_log( 'f:doParse smilPlaylist' ); + // @@todo get/parse meta that we are interested in: + var meta_tags = this.data.getElementsByTagName( 'meta' ); + var metaNames = { + 'title':'', + 'interface_url':"", + 'linkback':"", + 'mTitle':"", + 'mTalk':"", + 'mTouchedTime':"" + }; + $j.each( meta_tags, function( i, meta_elm ) { + // js_log( "on META tag: "+ $j(meta_elm).attr('name') ); + if ( $j( meta_elm ).attr( 'name' ) in metaNames ) { + _this[ $j( meta_elm ).attr( 'name' ) ] = $j( meta_elm ).attr( 'content' ); + } + // Special check for wikiDesc + if ( $j( meta_elm ).attr( 'name' ) == 'wikiDesc' ) { + if ( meta_elm.firstChild ) + _this.wikiDesc = meta_elm.firstChild.nodeValue; + } + } ); + // Add transition objects: + var transition_tags = this.data.getElementsByTagName( 'transition' ); + $j.each( transition_tags, function( i, trans_elm ) { + if ( $j( trans_elm ).attr( "id" ) ) { + _this.transitions[ $j( trans_elm ).attr( "id" )] = new transitionObj( trans_elm ); + } else { + js_log( 'skipping transition: (missing id) ' + trans_elm ); + } + } ); + js_log( 'loaded transitions:' + _this.transitions.length ); + + // Add seq (latter we will have support more than one seq tag) / more than one "track" + var seq_tags = this.data.getElementsByTagName( 'seq' ); + $j.each( seq_tags, function( i, seq_elm ) { + var inx = 0; + // get all the clips for the given seq: + $j.each( seq_elm.childNodes, function( i, mediaElement ) { + // ~complex~ @@todo to handle a lot like "switch" "region" etc + // js_log('process: ' + mediaElemnt.tagName); + if ( typeof mediaElement.tagName != 'undefined' ) { + if ( _this.tryAddMedia( mediaElement, inx ) ) { + inx++; + } + } + } ); + } ); + js_log( "done proc seq tags" ); + return true; + }, + tryAddMediaObj:function( mConfig, order, track_id ) { + js_log( 'tryAddMediaObj::' ); + var mediaElement = document.createElement( 'div' ); + for ( var i = 0; i < mv_smil_ref_supported_attributes.length; i++ ) { + var attr = mv_smil_ref_supported_attributes[i]; + if ( mConfig[attr] ) + $j( mediaElement ).attr( attr, mConfig[attr] ); + } + this.tryAddMedia( mediaElement, order, track_id ); + }, + tryAddMedia:function( mediaElement, order, track_id ) { + js_log( 'SMIL:tryAddMedia:' + mediaElement ); + + var _this = this; + // Set up basic mvSMILClip send it the mediaElemnt & mvClip init: + var clipObj = { }; + var cConfig = { + "id" : 'p_' + _this.id + '_c_' + order, + "pp" : this, // set the parent playlist object pointer + "order" : order + }; + var clipObj = new mvSMILClip( mediaElement, cConfig ); + + // set optional params track + if ( typeof track_id != 'undefined' ) + clipObj["track_id"] = track_id; + + + if ( clipObj ) { + // set up embed: + clipObj.setUpEmbedObj(); + // inhreit embedObject (only called on "new media" + clipObj.embed.init_with_sources_loaded(); + // add clip to track: + this.addCliptoTrack( clipObj , order ); + + return true; + } + return false; + } +} +// http://www.w3.org/TR/2007/WD-SMIL3-20070713/smil-extended-media-object.html#smilMediaNS-BasicMedia +// and added resource description elements +// @@ supporting the "ID" attribute turns out to be kind of tricky since we use it internally +// (for now don't include) +var mv_smil_ref_supported_attributes = new Array( + 'src', + 'type', + 'region', + 'transIn', + 'transOut', + 'fill', + 'dur', + 'title', + // some custom attributes: + 'uri', + 'durationHint', + 'poster' +); +/* extension to mvClip to support smil properties */ +var mvSMILClip = function( sClipElm, mvClipInit ) { + return this.init( sClipElm, mvClipInit ); +} +// all the overwritten and new methods for SMIL extension of mv_embed +mvSMILClip.prototype = { + instanceOf:'mvSMILClip', + params : { }, // support param as child of ref clips per SMIL spec + init:function( sClipElm, mvClipInit ) { + _this = this; + this.params = { }; + // make new mvCLip with ClipInit vals + var myMvClip = new mvClip( mvClipInit ); + // inherit mvClip + for ( var method in myMvClip ) { + if ( typeof this[method] != 'undefined' ) { + this['parent_' + method] = myMvClip[method]; + } else { + this[method] = myMvClip[method]; + } + } + + // get supported media attr init non-set + for ( var i = 0; i < mv_smil_ref_supported_attributes.length; i++ ) { + var attr = mv_smil_ref_supported_attributes[i]; + if ( $j( sClipElm ).attr( attr ) ) { + _this[attr] = $j( sClipElm ).attr( attr ); + } + } + this['tagName'] = sClipElm.tagName; + + // Fix url paths (if needed) + if( _this['src'] && _this.src.indexOf('/') != 0 && _this.src.indexOf('://') === -1) + _this['src'] = mw.absoluteUrl( _this['src'], mvClipInit.pp.getSrc() ); + + if ( sClipElm.firstChild ) { + this['wholeText'] = sClipElm.firstChild.nodeValue; + js_log( "SET wholeText for: " + this['tagName'] + ' ' + this['wholeText'] ); + } + // debugger; + // mv_embed specific property: + if ( $j( sClipElm ).attr( 'poster' ) ) + this['img'] = $j( sClipElm ).attr( 'poster' ); + + // lookup and assign copies of transitions + // (since transition needs to hold some per-instance state info) + if ( this.transIn && this.pp.transitions[ this.transIn ] ) { + this.transIn = this.pp.transitions[ this.transIn ]. clone (); + this.transIn.pClip = _this; + this.transIn.transAttrType = 'transIn'; + } + + if ( this.transOut && this.pp.transitions[ this.transOut ] ) { + this.transOut = this.pp.transitions[ this.transOut ]. clone (); + this.transOut.pClip = _this; + this.transOut.transAttrType = 'transOut'; + } + // parse duration / begin times: + if ( this.dur ) + this.dur = smilParseTime( this.dur ); + + // parse the media duration hint ( the source media length) + if ( this.durationHint ) + this.durationHint = smilParseTime( this.durationHint ); + + // conform type to vido/ogg: + if ( this.type == 'application/ogg' ) + this.type = 'video/ogg'; // conform to 'video/ogg' type + + // if unset type and we have innerHTML assume text/html type + if ( !this.type && this.wholeText ) { + this.type = 'text/html'; + } + // Also grab any child param elements if present: + if ( sClipElm.getElementsByTagName( 'param' )[0] ) { + for ( var i = 0; i < sClipElm.getElementsByTagName( 'param' ).length; i++ ) { + this.params[ sClipElm.getElementsByTagName( 'param' )[i].getAttribute( "name" ) ] = + sClipElm.getElementsByTagName( 'param' )[i].firstChild.nodeValue; + } + } + return this; + }, + /** + * Returns the values of supported_attributes: + */ + getAttributeObj:function() { + var elmObj = { }; + for ( var i = 0; i < mv_smil_ref_supported_attributes.length; i++ ) { + var attr = mv_smil_ref_supported_attributes[i]; + if ( this[attr] ) + elmObj[ attr ] = this[attr]; + } + return elmObj; + }, + /* + * getDuration + * @returns duration in int + */ + getDuration:function() { + // check for smil dur: + if ( this.dur ) + return this.dur; + return this.embed.getDuration(); + }, + // gets the duration of the clip subracting transitions + getSoloDuration:function() { + var fulldur = this.getDuration(); + // see if we need to subtract from time eating transitions (transOut) + if ( this.transOut ) + fulldur -= this.transOut.getDuration(); + + // js_log("getSoloDuration:: td: " + this.getDuration() + ' sd:' + fulldur); + return fulldur; + }, + // gets the duration of the original media asset (usefull for bounding setting of in-out-points) + getSourceDuration:function() { + if ( this.durationHint ) + return this.durationHint; + // if we have no source duration just return the media dur: + return this.getDuration(); + } +} +/* + * takes an input + * @time_str input time string + * returns time in seconds + * + * @@todo process duration (for now just srip s) per: + * http://www.w3.org/TR/SMIL3/smil-timing.html#Timing-ClockValueSyntax + * (probably have to use a Time object to fully support the smil spec + */ +function smilParseTime( time_str ) { + time_str = time_str + ''; + // first check for hh:mm:ss time: + if ( time_str.split( ':' ).length == 3 ) { + return npt2seconds( time_str ); + } else { + // assume 34s secconds representation + return parseInt( time_str.replace( 's', '' ) ); + } +} +// stores a list pointers to active clips (maybe this should just be a property of clips (but results in lots of seeks) +var activeClipList = function() { + return this.init(); +} +activeClipList.prototype = { + init:function() { + this.clipList = new Array(); + }, + add:function( clip ) { + // make sure the clip is not already active: + for ( var i = 0; i < this.clipList.lenght; i++ ) { + var active_clip = this.clipList[i]; + if ( clip.id == active_clip.id ) // clip already active: + return false; + } + this.clipList.push( clip ); + return true; + }, + remove:function( clip ) { + for ( var i = 0; i < this.clipList.length; i++ ) { + var active_clip = this.clipList[i]; + if ( clip.id == active_clip.id ) { + this.clipList.splice( i, 1 ); + return true; + } + } + return false; + }, + getClipList:function() { + return this.clipList; + } +} + var trackObj = function( iObj ) { + return this.init( iObj ); + } + var supported_track_attr = +trackObj.prototype = { + // should be something like "seq" per SMIL spec + // http://www.w3.org/TR/SMIL3/smil-timing.html#edef-seq + // but we don't really support anywhere near the full concept of seq containers yet either + supported_attributes: new Array( + 'title', + 'desc', + 'inx' + ), + disp_mode:'timeline_thumb', + init : function( iObj ) { + if ( !iObj ) + iObj = { }; + // make sure clips is new: + this.clips = new Array(); + + var _this = this; + $j.each( this.supported_attributes, function( i, attr ) { + if ( iObj[attr] ) + _this[attr] = iObj[attr]; + } ); + }, + // returns the values of supported_attributes: + getAttributeObj:function() { + var elmObj = { }; + for ( var i in this.supported_attributes ) { + var attr = this.supported_attributes[i]; + if ( this[attr] ) + elmObj[ attr ] = this[attr]; + } + return elmObj; + }, + addClip:function( clipObj, pos ) { + js_log( 'pl_Track: AddClip at:' + pos + ' clen: ' + this.clips.length ); + if ( typeof pos == 'undefined' ) + pos = this.clips.length; + // get everything after pos + this.clips.splice( pos, 0, clipObj ); + // keep the clip order values accurate: + this.reOrderClips(); + js_log( "did add now cLen: " + this.clips.length ); + }, + getClip:function( inx ) { + if ( !this.clips[inx] ) + return false; + return this.clips[inx]; + }, + reOrderClips:function() { + for ( var k in this.clips ) { + this.clips[k].order = k; + } + }, + getClipCount:function() { + return this.clips.length; + }, + inheritEmbedObj: function() { + $j.each( this.clips, function( i, clip ) { + clip.embed.inheritEmbedObj(); + } ); + } +}; + +/* utility functions + * (could be combined with other stuff) +*/ +function getAbsolutePos( objectId ) { + // Get an object left position from the upper left viewport corner + o = document.getElementById( objectId ); + oLeft = o.offsetLeft; // Get left position from the parent object + while ( o.offsetParent != null ) { // Parse the parent hierarchy up to the document element + oParent = o.offsetParent // Get parent object reference + oLeft += oParent.offsetLeft // Add parent left position + o = oParent + } + o = document.getElementById( objectId ); + oTop = o.offsetTop; + while ( o.offsetParent != null ) { // Parse the parent hierarchy up to the document element + oParent = o.offsetParent // Get parent object reference + oTop += oParent.offsetTop // Add parent top position + o = oParent + } + return { x:oLeft, y:oTop }; +} diff --git a/js2/mwEmbed/libSequencer/mvSequencer.js b/js2/mwEmbed/libSequencer/mvSequencer.js new file mode 100644 index 0000000000..4f6efdec77 --- /dev/null +++ b/js2/mwEmbed/libSequencer/mvSequencer.js @@ -0,0 +1,1648 @@ +/* + * mvSequencer.js Created on Oct 17, 2007 + * + * All Metavid Wiki code is Released under the GPL2 + * for more info visit http://metavid.org/wiki/Code + * + * @author Michael Dale + * @email mdale@wikimedia.org + * + * Further developed in open source development partnership with kaltura. + * more info at http://kaltura.com & http://kaltura.org + * + * mv_sequencer.js + * is a basic embeddeble sequencer. + * extends the playlist with drag/drop/sortable/add/remove functionality + * editing of annotative content (mostly for wiki) + * enables more dynamic layouts + * exports back out to json or inline format + */ + +loadGM( { + "mwe-menu_clipedit" : "Edit media", + "mwe-menu_transition" : "Transitions and effects", + "mwe-menu_cliplib" : "Add media", + "mwe-menu_resource_overview" : "Resource overview", + "mwe-menu_options" : "Options", + "mwe-loading_timeline" : "Loading timeline ...", + "mwe-loading_user_rights" : "Loading user rights ...", + "mwe-no_edit_permissions" : "You do not have permissions to save changes to this sequence", + "mwe-edit_clip" : "Edit clip", + "mwe-edit_save" : "Save sequence changes", + "mwe-saving_wait" : "Save in progress (please wait)", + "mwe-save_done" : "Save complete", + "mwe-edit_cancel" : "Cancel sequence edit", + "mwe-edit_cancel_confirm" : "Are you sure you want to cancel your edit? Changes will be lost.", + "mwe-zoom_in" : "Zoom in", + "mwe-zoom_out" : "Zoom out", + "mwe-cut_clip" : "Cut clips", + "mwe-expand_track" : "Expand track", + "mwe-collapse_track" : "Collapse track", + "mwe-play_from_position" : "Play from playline position", + "mwe-pixle2sec" : "pixels to seconds", + "mwe-rmclip" : "Remove clip", + "mwe-clip_in" : "clip in", + "mwe-clip_out" : "clip out", + "mwe-welcome_to_sequencer" : "

    Welcome to the sequencer demo<\/h3> Very limited<\/b> functionality right now. Not much documentation yet either.", + "mwe-no_selected_resource" : "

    No resource selected<\/h3> Select a clip to enable editing.", + "mwe-error_edit_multiple" : "

    Multiple resources selected<\/h3> Select a single clip to edit it.", + "mwe-editor_options" : "Editor options", + "mwe-editor_mode" : "Editor mode", + "mwe-simple_editor_desc" : "simple editor (iMovie style)", + "mwe-advanced_editor_desc" : "advanced editor (Final Cut style)", + "mwe-other_options" : "Other options", + "mwe-contextmenu_opt" : "Enable context menus", + "mwe-sequencer_credit_line" : "Developed by Kaltura, Inc.<\/a> in partnership with the Wikimedia Foundation<\/a> (more information<\/a>)." +} ); + // used to set default values and validate the passed init object +var sequencerDefaultValues = { + + instance_name:'mvSeq', // for now only one instance by name mvSeq is allowed + + target_sequence_container:null,// text value (so that its a valid property) + target_form_text: null, + + // what is our save mode: + // can save to 'api' url or 'form' + saveMode : 'api', + + video_container_id:'mv_video_container', + + video_width : 400, + video_height: 300, + + sequence_tools_id:'mv_sequence_tools', + timeline_id:'mv_timeline', + plObj_id:'seq_pl', + plObj:'null', + + // In pixel to second ratio ie 100pixles for every ~30seconds + timeline_scale:.06, + + // Default timeline duration in seconds + timeline_duration:500, + + playline_time:0, + track_thumb_height:60, + track_text_height:20, + + // Default timeline mode: "story" (i-movie like) or "time" (finalCut like) + timeline_mode:'storyboard', + + // How large are the i-movie type clips + track_clipThumb_height:80, + + // Default time to subtract or add when adjusting clips. + base_adj_duration:.5, + + // Default clipboard is empty: + clipboard:new Array(), + + // Stores the clipboard edit token (if user has rights to edit their User page) + clipboardEditToken:null, + + // Stores the sequence edit token (if user has rights to edit the current sequence) + sequenceEditToken:null, + + // The time the sequence was last touched (grabbed at time of startup) + sequenceTouchedTime:null, + + // the default config for the add media wizard + amw_conf: { }, + + + inline_playlist:'null', + inline_playlist_id:'null', + mv_pl_src:'null', + + // The edit stack (so that you can "undo" edits) + edit_stack:new Array(), + disp_menu_item:null, + + // Track Object + tracks: { } +} +var mvSequencer = function( iObj ) { + return this.init( iObj ); +}; +// Set up the mvSequencer object +mvSequencer.prototype = { + // The menu_items Object contains: default html, js setup/loader functions + menu_items : { + 'clipedit': { + 'default':0, + 'html':'', + 'js': function( this_seq ) { + this_seq.doEditSelectedClip(); + }, + 'click_js':function( this_seq ) { + this_seq.doEditSelectedClip(); + } + }, + 'transition': { + 'default':0, + 'html' : '

    ' + gM( 'mwe-menu_transition' ) + '

    ', + 'js':function( this_seq ) { + this_seq.doEditTransitionSelectedClip(); + }, + 'click_js':function( this_seq ) { + // Highlight the transition of the selected clip: + this_seq.doEditTransitionSelectedClip(); + } + }, + 'cliplib': { + 'default':0, + 'html': gM( 'mwe-loading_txt' ), + 'js':function( this_seq ) { + // Load the search interface with sequence tool targets + mvJsLoader.doLoad( [ + 'remoteSearchDriver', + 'seqRemoteSearchDriver' + ], function() { + this_seq.mySearch = new seqRemoteSearchDriver( this_seq ); + this_seq.mySearch.createUI(); + } ); + } + }, + 'options': { + 'default':0, + 'html' : '

    ' + gM( 'mwe-menu_options' ) + '

    ' + + gM( 'mwe-editor_mode' ) + '
    ' + + '
    ' + + gM( 'mwe-simple_editor_desc' ) + '
    ' + + '
    ' + + gM( 'mwe-advanced_editor_desc' ) + '
    ' + + gM( 'mwe-other_options' ) + '
    ' + + '
    ' + + gM( 'mwe-contextmenu_opt' ) + '
    ', + 'js':function( this_seq ) { + $j( '#options_ic input[value=\'simple_editor\']' ).attr( { + 'checked':( this_seq.timeline_mode == 'storyboard' ) ? true:false + } ).click( function() { + this_seq.doSimpleTl(); + } ); + $j( '#options_ic input[value=\'advanced_editor\']' ).attr( { + 'checked':( this_seq.timeline_mode == 'time' ) ? true:false + } ).click( function() { + this_seq.doAdvancedTl(); + } ); + // set up the options for context menus + } + } + }, + + // set up initial key states: + key_shift_down:false, + key_ctrl_down:false, + inputFocus:false, + + init:function( iObj ) { + // set up pointer to this_seq for current scope: + var this_seq = this; + // set the default values: + for ( var i in sequencerDefaultValues ) { + this[ i ] = sequencerDefaultValues[i]; + } + for ( var i in iObj ) { + // js_log('on '+ i + ' :' + iObj[i]); + if ( typeof sequencerDefaultValues[i] != 'undefined' ) { // make sure its a valid property + this[i] = iObj[i]; + } + } + + // check for sequence_container + if ( $j( this.target_sequence_container ).length === 0 ) { + js_log( "Error: missing target_sequence_container" ); + return false; + } + + // $j(this.target_sequence_container).css('position', 'relative'); + this['base_width'] = $j( this.target_sequence_container ).width(); + this['base_height'] = $j( this.target_sequence_container ).height(); + + // add the container divs (with basic layout ~universal~ + $j( this.target_sequence_container ).html( '' + + '
    ' + + '
    ' + + gM( 'mwe-loading_timeline' ) + '
    ' + + '
    ' + + '
    ' + + gM( 'mwe-loading_user_rights' ) + + '
    ' + + '
    ' + + gM( 'mwe-sequencer_credit_line' ) + + '
    ' + + '
    ' + ).css( { + 'min-width':'850px' + } ); + + /*js_log('set: '+this.target_sequence_container + ' html to:'+ "\n"+ + $j(this.target_sequence_container).html() + );*/ + + // first check if we got a cloned PL object: + // (when the editor is invoked with the plalylist already on the page) + /*if( this.plObj != 'null' ){ + js_log('found plObj clone'); + //extend with mvSeqPlayList object: + this.plObj = new mvSeqPlayList(this.plObj); + js_log('mvSeqPlayList added: ' + this.plObj.org_control_height ); + $j('#'+this.video_container_id).get(0).attachNode( this.plObj ); + this.plObj.getHTML(); + this.checkReadyPlObj(); + return ; + }*/ + + // else check for source based sequence editor (a clean page load of the editor) + if ( this.mv_pl_src != 'null' ) { + js_log( ' pl src:: ' + this.mv_pl_src ); + var src_attr = ' src="' + this.mv_pl_src + '" '; + } else { + js_log( ' null playlist src .. (start empty) ' ); + var src_attr = ''; + } + $j( '#' + this.video_container_id ).html( '' ); + rewrite_by_id( this.plObj_id ); + setTimeout( this.instance_name + '.checkReadyPlObj()', 25 ); + }, + updateSeqSaveButtons:function() { + var _this = this; + if ( this.sequenceEditToken ) { + $j( this.target_sequence_container + ' .seq_save_cancel' ).html( + $j.btnHtml( gM( 'mwe-edit_save' ), 'seq_edit_save', 'close' ) + ' ' + + $j.btnHtml( gM( 'mwe-edit_cancel' ), 'seq_edit_cancel', 'close' ) + ); + } else { + $j( this.target_sequence_container + ' .seq_save_cancel' ).html( cancel_button + gM( 'mwe-no_edit_permissions' ) ); + } + // assing bindings + $j( this.target_sequence_container + ' .seq_edit_cancel' ).unbind().click( function() { + var x = window.confirm( gM( 'mwe-edit_cancel_confirm' ) ); + if ( x ) { + _this.closeModEditor(); + } else { + // close request canceled. + } + } ); + $j( this.target_sequence_container + ' .seq_edit_save' ).unbind().click( function() { + // pop up progress dialog ~requesting edit line summary~ + // remove any other save dialog + $j( '#seq_save_dialog' ).remove(); + $j( 'body' ).append( '
    ' + + '' + + '' + + '' + + '' + + '
    ' ); + var bConf = { }; + bConf[ gM( 'mwe-cancel' ) ] = function() { + $j( this ).dialog( 'close' ); + }; + bConf[ gM( 'mwe-edit_save' ) ] = function() { + var saveReq = { + 'action' : 'edit', + 'title' : _this.plObj.mTitle, + // the text is the sequence XML + the description + 'text' : _this.getSeqOutputHLRDXML() + "\n" + + _this.plObj.wikiDesc, + 'token' : _this.sequenceEditToken, + 'summary' : $j( '#seq_save_summary' ).val() + }; + // change to progress bar and save: + $j( '#seq_save_dialog' ).html( '

    ' + + gM( 'mwe-saving_wait' ) + ) + $j( '#seq_save_dialog .progress' ).progressbar( { + value: 100 + } ); + // run the Seq Save Request: + do_api_req( { + 'data': saveReq, + 'url' : _this.getLocalApiUrl() + }, function( data ) { + $j( '#seq_save_dialog' ).html( gM( 'mwe-save_done' ) ); + $j( '#seq_save_dialog' ).dialog( 'option', + 'buttons', { + "Done":function() { + // refresh the page? + window.location.reload(); + }, + "Do More Edits": function() { + $j( this ).dialog( "close" ); + } + } ); + } ); + }; + // dialog: + $j( '#seq_save_dialog' ).dialog( { + bgiframe: true, + autoOpen: true, + modal: true, + buttons: bConf + } ); + } ) + }, + // display a menu item (hide the rest) + disp:function( item, dispCall ) { + js_log( 'menu_item disp: ' + item ); + this.disp_menu_item = item; + // update the display and item state: + if ( this.menu_items[item] ) { + // update the tabs display: + if ( !dispCall ) + $j( "#seq_menu" ).tabs( 'select', this.menu_items[item].inx ); + + this.menu_items[item].default = 1; + // do any click_js actions:getInsertControl + if ( this.menu_items[item].click_js ) + this.menu_items[item].click_js( this ); + } + }, + // setup the menu items: + setupMenuItems:function() { + js_log( 'loadInitMenuItems' ); + var this_seq = this; + // do all the menu_items setup: @@we could defer this to once the menu item is requested + for ( var i in this.menu_items ) { + if ( this.menu_items[i].js ) + this.menu_items[i].js( this ); + } + }, + renderTimeLine:function() { + // empty out the top level html: + $j( '#' + this.timeline_id ).html( '' ); + // add html general for timeline + if ( this.timeline_mode == 'time' ) { + $j( '#' + this.timeline_id ).html( '' + + '
    ' + + '
    ' + + '
    ' + + '
    ' + + '
    ' + ); + // add playlist hook to update timeline + this.plObj.update_tl_hook = this.instance_name + '.update_tl_hook'; + var this_sq = this; + var top_pos = 25; + // add tracks: + for ( var i in this.plObj.tracks ) { + var track = this.plObj.tracks[i]; + // js_log("on track: "+ i + ' t:'+ $j('#'+this.timeline_id+'_left_cnt').html() ); + // set up track based on disp type + switch( track.disp_mode ) { + case 'timeline_thumb': + var track_height = 60; + var exc_img = 'opened'; + var exc_action = 'close'; + var exc_msg = gM( 'mwe-collapse_track' ); + break; + case 'text': + var track_height = 20; + var exc_img = 'closed'; + var exc_action = 'open'; + var exc_msg = gM( 'mwe-expand_track' ); + break; + } + // add track name: + $j( '#' + this.timeline_id + '_left_cnt' ).append( + '
    ' + + '' + + '' + + '' + + track.title + '
    ' + ); + // also render the clips in the trackset container: (thumb or text view) + $j( '#' + this.timeline_id + '_tracks' ).append( + '
    ' + ); + top_pos += track_height + 20; + } + } + if ( this.timeline_mode == 'storyboard' ) { + var top_pos = this.plObj.org_control_height; + // debugger; + for ( var i in this.plObj.tracks ) { + var track_height = this.track_clipThumb_height; + var timeline_id = this.timeline_id + // add in play box and container tracks + $j( '#' + timeline_id ).append( '' + + '
    ' + + '
    ' + + '
    ' + + '
    ' + + '
    ' + + '
    ' + + '
    ' + ); + top_pos += track_height + 20; + } + } + }, + // once playlist is ready continue + checkReadyPlObj:function() { + // set up pointers from sequencer to pl obj + this.plObj = $j( '#' + this.plObj_id ).get( 0 ); + // & from seq obj to sequencer + this.plObj.pSeq = this; + + if ( this.plObj ) + if ( ! this.plObj.loading ) + this.plReadyInit(); + + // else keep checking for the playlist to be ready + if ( this.plObj.loading ) { + if ( this.plReadyTimeout == 200 ) { + js_error( 'error playlist never ready' ); + } else { + this.plReadyTimeout++; + setTimeout( this.instance_name + '.checkReadyPlObj()', 25 ); + } + } + }, + getLocalApiUrl:function() { + return this.plObj.interface_url; + }, + plReadyInit:function() { + var _this = this; + js_log( 'plReadyInit' ); + js_log( this.plObj ); + // give the playlist a pointer to its parent seq: + this.plObj['seqObj'] = this; + + // update playlist (if its empty right now) + if ( this.plObj.getClipCount() == 0 ) { + $j( '#' + this.plObj_id ).html( 'empty playlist' ); + } + + // propagate the edit tokens + // if on an edit page just grab from the form: + this.sequenceEditToken = $j( 'input[wpEditToken]' ).val(); + + if ( typeof this.sequenceEditToken == 'undefined' && this.getLocalApiUrl() != null ) { + get_mw_token( _this.plObj.mTitle, _this.getLocalApiUrl(), + function( token ) { + if ( token ) { + _this.sequenceEditToken = token; + _this.updateSeqSaveButtons(); + } + } + ); + get_mw_token( _this.plObj.mTalk, _this.getLocalApiUrl(), + function( token ) { + _this.clipboardEditToken = token; + } + ); + // also grab permissions for sending clipboard commands to the server + + // (calling the sequencer inline) try and get edit token via api call: + // (somewhat fragile way to get at the api... should move to config + /*var token_url = this.plObj.interface_url.replace(/index\.php/, 'api.php'); + token_url += '?action=query&format=xml&prop=info&intoken=edit&titles='; + $j.ajax({ + type: "GET", + url: token_url + this_seq.plObj.mTitle, + success:function(data){ + var pageElm = data.getElementsByTagName('page')[0]; + if( $j(pageElm).attr('edittoken') ){ + this_seq.sequenceEditToken = $j(pageElm).attr('edittoken'); + } + + } + });*/ + // also grab permissions for sending clipboard commands to the server + /*$j.ajax({ + type:"GET", + url: token_url + this_seq.plObj.mTalk, + success:function(data){ + var pageElm = data.getElementsByTagName('page')[0]; + if( $j(pageElm).attr('edittoken') ){ + this_seq.clipboardEditToken = $j(pageElm).attr('edittoken'); + } + } + });*/ + } + + + // Render the menu tabs:: + var item_containers = ''; + var inx = 0; + var selected_tab = 0; + var tabc = ''; + var o = '
    '; + o += '
      '; + for ( var tab_id in this.menu_items ) { + menu_item = this.menu_items[tab_id]; + menu_item.inx = inx; + if ( menu_item.default ) { + selected_tab = inx; + _this.disp_menu_item = tab_id; + } + + o += '
    • ' + + '' + gM( 'mwe-menu_' + tab_id ) + '' + + '
    • '; + + tabc += '
      '; + tabc += ( menu_item.html ) ? menu_item.html : '

      ' + gM( 'mwe-menu_' + tab_id ) + '

      '; + tabc += '
      '; + inx++; + }; + o += '
    '; + o += tabc; + $j( '#' + this.sequence_tools_id ).html( o ); + + + $j( "#seq_menu" ).tabs( { + selected:selected_tab, + select: function( event, ui ) { + _this.disp( $j( ui.tab ).attr( 'id' ).replace( 'mv_menu_item_', '' ), true ); + } + // Add sorting + } ).find( ".ui-tabs-nav" ).sortable( { axis : 'x' } ); + + + // Render the timeline + this.renderTimeLine(); + this.do_refresh_timeline(); + + // Load initial content into containers + this.setupMenuItems(); + + this.doFocusBindings(); + + // Set up key bidnings + $j( window ).keydown( function( e ) { + js_log( 'pushed down on:' + e.which ); + if ( e.which == 16 ) + _this.key_shift_down = true; + + if ( e.which == 17 ) + _this.key_ctrl_down = true; + + if ( ( e.which == 67 && _this.key_ctrl_down ) && !_this.inputFocus ) + _this.copySelectedClips(); + + if ( ( e.which == 88 && _this.key_ctrl_down ) && !_this.inputFocus ) + _this.cutSelectedClips(); + + // Paste cips on v + ctrl while not focused on a text area: + if ( ( e.which == 86 && _this.key_ctrl_down ) && !_this.inputFocus ) + _this.pasteClipBoardClips(); + + } ); + $j( window ).keyup( function( e ) { + js_log( 'key up on ' + e.which ); + // User let go of "shift" turn off multi-select + if ( e.which == 16 ) + _this.key_shift_down = false; + + if ( e.which == 17 ) + _this.key_ctrl_down = false; + + // Escape key ( deselect ) + if ( e.which == 27 ) + _this.deselectClip(); + + + // Backspace or Delete key while not focused on a text area: + if ( ( e.which == 8 || e.which == 46 ) && !_this.inputFocus ) + _this.removeSelectedClips(); + } ); + }, + /** + * Check all text nodes for focus + */ + doFocusBindings:function() { + var _this = this; + // if an input or text area has focus disable delete key binding + $j( "input,textarea" ).focus( function () { + js_log( "inputFocus:true" ); + _this.inputFocus = true; + } ); + $j( "input,textarea" ).blur( function () { + js_log( "inputFocus:blur" ); + _this.inputFocus = false; + } ) + }, + /* + * Update the timeline hook + */ + update_tl_hook:function( jh_time_ms ) { + // Put into seconds scale: + var jh_time_sec_float = jh_time_ms / 1000; + // Render playline at given time + $j( '#' + this.timeline_id + '_playline' ) + .css( + 'left', + Math.round( jh_time_sec_float / this.timeline_scale ) + 'px' + ); + // js_log('at time:'+ jh_time_sec + ' px:'+ Math.round(jh_time_sec_float/this.timeline_scale)); + }, + /* + * Returns a xml or json representation of the current sequence + */ + getSeqOutputJSON:function() { + js_log( 'json output:' ); + }, + /* + * Gets the Sequence as a formated high level resource description xml string + * @returns {xml} + */ + getSeqOutputHLRDXML:function() { + var o = '' + "\n"; + o += "\t\n"; + // Get transitions + for ( var i in this.plObj.transitions ) { + if ( this.plObj.transitions[i] ) { + var tObj = this.plObj.transitions[i].getAttributeObj(); + o += "\t\t' + pVal + '' + "\n"; + } + o += "\t\t\n\n"; + } + o += "\n\n"; + } + o += "\t\n"; + // Close the tag + o += ''; + + return o; + }, + /** + * Takes a track index and a clip index, to get a clip Object. + * It then calls doEditClip with that clip Object. + */ + editClip:function( track_inx, clip_inx ) { + var cObj = this.plObj.tracks[ track_inx ].clips[ clip_inx ]; + this.doEditClip( cObj ); + }, + /** + * Calls the doEditClip interface on the selected clip + * Handles cases where no clips are selected or multiple clips are selected. + */ + doEditSelectedClip:function() { + js_log( "f:doEditSelectedClip:" ); + // And only one clip selected + if ( $j( '.mv_selected_clip' ).length == 1 ) { + this.doEditClip( this.getClipFromSeqID( $j( '.mv_selected_clip' ).parent().attr( 'id' ) ) ); + } else if ( $j( '.mv_selected_clip' ).length === 0 ) { + // No clip selected warning: + $j( '#clipedit_ic' ).html( gM( 'mwe-no_selected_resource' ) ); + } else { + // Multiple clip selected warning: + $j( '#clipedit_ic' ).html( gM( 'mwe-error_edit_multiple' ) ); + } + }, + /** + * Pulls up the edit transition interface for the selected clip + */ + doEditTransitionSelectedClip:function() { + var _this = this; + js_log( "f:doEditTransitionSelectedClip:" + $j( '.mv_selected_clip' ).length ); + if ( $j( '.mv_selected_clip' ).length == 1 ) { + _this.doEditTransition( _this.getClipFromSeqID( $j( '.mv_selected_clip' ).parent().attr( 'id' ) ) ); + } else if ( $j( '.mv_selected_clip' ).length === 0 ) { + // no clip selected warning: + $j( '#transition_ic' ).html( gM( 'mwe-no_selected_resource' ) ); + } else { + // multiple clip selected warning: + $j( '#transition_ic' ).html( gM( 'mwe-error_edit_multiple' ) ); + } + }, + /** + * Loads the transition edit javascript libs and + * displays the transition edit interface. + */ + doEditTransition:function( cObj ) { + js_log( "sequence:doEditTransition" ); + var _this = this; + // Add a loading image + mv_get_loading_img( '#transitions_ic' ); + mvJsLoader.doLoad( [ + '$j.fn.ColorPicker', + 'mvTimedEffectsEdit' + ], function() { + // For some reason we lose scope in the options passed to mvTimedEffectsEdit + // so we re refrence the sequence here: + var localSeqRef = _this; + _this.myEffectEdit = new mvTimedEffectsEdit( { + 'rObj' : cObj, + 'control_ct' : 'transition_ic', + 'pSeq' : localSeqRef + } ); + } ) + }, + /* + * Updates the clip details div if edit resource is set + */ + doEditClip:function( cObj ) { + js_log( 'seq:doEditClip' ); + var _this = this; + + // Set default edit action + var edit_action = 'fileopts'; + + mv_get_loading_img( '#clipedit_ic' ); + + // Load the clipEdit library if not already loaded: + mvJsLoader.doLoad( [ + 'mvClipEdit' + ], function() { + // Zero out the current editor: + _this.myClipEditor = { }; + // Setup the cliploader options + _this.myClipEditor = new mvClipEdit( { + 'rObj' : cObj, + 'control_ct' : 'clipedit_ic', + 'clip_disp_ct' : cObj.id, + 'edit_action' : edit_action, + 'p_seqObj' : _this, + 'profile' : 'sequence' + } ); + } ); + }, + + /* + * Save new clip segment + * FIXME this is just a stub + */ + saveClipEdit:function() { + // saves the clip updates + }, + + /** + * Closes the sequence and dereferences the global instance. + */ + closeModEditor:function() { + // unset the sequencer + _global['mvSeq'] = null; + $j( this.target_sequence_container + ',.ui-widget-overlay' ).remove(); + }, + + /** + * Copies the selected clips to the server hosted "clipboard" + * + * FIXME need to support local clipboard for stand alone editing. + * FIXME this does not really work at all right now + */ + copySelectedClips:function() { + var this_seq = this; + // set all the selected clips + this.clipboard = new Array(); + $j( '.mv_selected_clip' ).each( function() { + + // Add each clip to the clip board: + var cur_clip = this_seq.getClipFromSeqID( $j( this ).parent().attr( 'id' ) ); + this_seq.clipboard.push( cur_clip.getAttributeObj() ); + + } ); + + // Upload clipboard to the server (if possible) + if ( mw.parseUri( document.URL ).host != mw.parseUri( this_seq.plObj.interface_url ).host ) { + js_log( 'error: presently we can\'t copy clips across domains' ); + } else { + // FIXME we need to add an api entry point to store a "clipboard" + // right now this is dependent on a custom hook: + if ( this_seq.clipboardEditToken && this_seq.plObj.interface_url ) { + var req_url = this_seq.plObj.interface_url.replace( /api.php/, 'index.php' ) + '?action=ajax&rs=mv_seqtool_clipboard&rsargs[]=copy'; + $j.ajax( { + type: "POST", + url : req_url, + data: $j.param( { + "clipboard_data": $j.toJSON( this_seq.clipboard ), + "clipboardEditToken": this_seq.clipboardEditToken + } ), + success:function( data ) { + js_log( 'did clipboard push ' + $j.toJSON( this_seq.clipboard ) ); + } + } ); + } else { + js_log( 'error: no clipboardEditToken to uplaod clipboard to server' ); + } + } + }, + /* + * Paste the clipboard clips into the sequence + */ + pasteClipBoardClips:function() { + js_log( 'f:pasteClipBoardClips' ); + // @@todo query the server for updated clipboard + // paste before the "current clip" + this.addClips( this.clipboard, this.plObj.cur_clip.order ); + }, + + /** + * Cut selected clips from the timeline + */ + cutSelectedClips:function() { + this.copySelectedClips(); + this.removeSelectedClips(); + }, + + /** + * Remove selected clips from the timeline + */ + removeSelectedClips:function() { + var remove_clip_ary = new Array(); + // Remove selected clips from display + $j( '.container_track .mv_selected_clip' ).each( function() { + // grab the track index from the id (assumes track_#_clip_# + remove_clip_ary.push ( $j( this ).parent().attr( 'id' ).replace( 'track_', '' ).replace( 'clip_', '' ).split( '_' ) ); + } ); + if ( remove_clip_ary.length != 0 ) + this.removeClips( remove_clip_ary ); + + // doEdit selected clips (updated selected resource) + // @@todo refresh menu of current + this.doEditSelectedClip(); + }, + /* + * Add a clip to the timeline + */ + addClip:function( clip, before_clip_pos, track_inx ) { + this.addClips( [clip], before_clip_pos, track_inx ) + }, + /** + * add a single or set of clips + * to a given position and track_inx + */ + addClips:function( clipSet, before_clip_pos, track_inx ) { + this_seq = this; + + if ( !track_inx ) + track_inx = this.plObj.default_track.inx; + + if ( !before_clip_pos ) + before_clip_pos = this.plObj.default_track.getClipCount(); + + js_log( "seq: add clip: at: " + before_clip_pos + ' in track: ' + track_inx ); + var cur_pos = before_clip_pos; + + $j.each( clipSet, function( inx, clipInitDom ) { + var mediaElement = document.createElement( 'ref' ); + for ( var i in clipInitDom ) { + js_log( "set: " + i + ' to ' + clipInitDom[i] ); + if ( i != 'id' ) + $j( mediaElement ).attr( i, clipInitDom[i] ); + } + if ( this_seq.plObj.tryAddMedia( mediaElement, cur_pos, track_inx ) ) + cur_pos++; + } ); + // debugger; + this.do_refresh_timeline(); + }, + + /** + * Removes Clips listed in the remove_clip_ary paramater + */ + removeClips:function( remove_clip_ary ) { + var this_seq = this; + var jselect = coma = ''; + js_log( 'clip count before removal : ' + this_seq.plObj.default_track.clips.length + ' should remove ' + remove_clip_ary.length ); + var afected_tracks = new Array(); + // add order to track_clip before we start removing: + $j.each( remove_clip_ary, function( inx, track_clip ) { + remove_clip_ary[inx]['order'] = this_seq.plObj.tracks[ track_clip[0] ].clips[ track_clip[1] ].order; + } ); + $j.each( remove_clip_ary, function( inx, track_clip ) { + var track_inx = track_clip[0]; + var clip_inx = track_clip[1]; + var clip_rm_order = track_clip['order']; + js_log( 'remove t:' + track_inx + ' c:' + clip_inx + ' id:' + ' #track_' + track_inx + '_clip_' + clip_inx + ' order:' + clip_rm_order ); + // remove the clips from the base tracks + for ( var i in this_seq.plObj.tracks[ track_inx ].clips ) { + cur_clip = this_seq.plObj.tracks[ track_inx ].clips[i] + if ( cur_clip.order == clip_rm_order ) { + this_seq.plObj.tracks[ track_clip[0] ].clips.splice( i, 1 ); + } + } + // add track to affected track list: + afected_tracks[ track_inx ] = true; + jselect += coma + '#track_' + track_inx + '_clip_' + clip_inx; + coma = ','; + } ); + // update/ reorder: + $j.each( afected_tracks, function( track_inx, affected ) { + this_seq.plObj.tracks[track_inx].reOrderClips(); + } ); + + js_log( 'clip count after removal : ' + this_seq.plObj.default_track.clips.length ); + // animate the removal (@@todo should be able to call the resulting fadeOut only once without a flag) + var done_with_refresh = false; + $j( jselect ).fadeOut( "slow", function() { + if ( !done_with_refresh ) + this_seq.do_refresh_timeline(); + done_with_refresh = true; + } ).empty(); // empty to remove any persistent bindings + }, + doEdit:function( editObj ) { + // add the current editObj to the edit stack (should allow for "undo") + this.edit_stack.push( editObj ); + // make the adjustments + this.makeAdjustment( editObj ); + }, + /* + * takes adjust ment object with options: + * track_inx, clip_inx, start, end delta + */ + makeAdjustment:function( e ) { + switch( e.type ) { + case 'resize_start': + this.plObj.tracks[e.track_inx].clips[e.clip_inx].doAdjust( 'start', e.delta ); + break; + case 'resize_end': + this.plObj.tracks[e.track_inx].clips[e.clip_inx].doAdjust( 'end', e.delta ); + break; + } + js_log( 're render: ' + e.track_inx ); + // refresh the playlist after adjustment + this.do_refresh_timeline(); + }, + // @@todo set up key bindings for undo + undoEdit:function() { + var editObj = this.edit_stack.pop(); + // invert the delta + + }, + exc_track:function( inx, req ) { + this_seq = this; + if ( req == 'close' ) { + $j( '#mv_exc_' + inx ).attr( 'href', 'javascript:' + this.instance_name + '.exc_track(' + inx + ',\'open\')' ); + $j( '#mv_exc_' + inx + ' > img' ).attr( 'src', mv_embed_path + 'images/closed.png' ); + $j( '#track_cnt_' + inx + ',#container_track_' + inx ).animate( { height:this.track_text_height }, "slow", '', + function() { + this_seq.plObj.tracks[inx].disp_mode = 'text'; + this_seq.render_tracks( inx ); + } ); + } else if ( req == 'open' ) { + $j( '#mv_exc_' + inx ).attr( 'href', 'javascript:' + this.instance_name + '.exc_track(' + inx + ',\'close\')' ); + $j( '#mv_exc_' + inx + ' > img' ).attr( 'src', mv_embed_path + 'images/opened.png' ); + $j( '#track_cnt_' + inx + ',#container_track_' + inx ).animate( { height:this.track_thumb_height }, "slow", '', + function() { + this_seq.plObj.tracks[inx].disp_mode = 'timeline_thumb'; + this_seq.render_tracks( inx ); + } ); + + } + }, + // adds tracks + add_track:function( inx, track ) { + + }, + // toggle cut mode (change icon to cut) + cut_mode:function() { + js_log( 'do cut mode' ); + // add cut layer ontop of clips + }, + doAdvancedTl:function() { + this.timeline_mode = 'time'; + this.renderTimeLine(); + this.do_refresh_timeline(); + return false; + }, + doSimpleTl:function() { + this.timeline_mode = 'storyboard'; + this.renderTimeLine(); + this.do_refresh_timeline(); + return false; + }, + // renders updates the timeline based on the current scale + render_tracks:function( track_inx ) { + js_log( "f::render track: " + track_inx ); + var this_seq = this; + // inject the tracks into the timeline (if not already there) + for ( var track_id in this.plObj.tracks ) { + if ( track_inx == track_id || typeof track_inx == 'undefined' ) { + // empty out the track container: + // $j('#container_track_'+track_id).empty(); + var track_html = droppable_html = ''; + // set up per track vars: + var track = this.plObj.tracks[track_id]; + var cur_clip_time = 0; + + // set up some constants for timeline_mode == storyboard: + if ( this.timeline_mode == 'storyboard' ) { + var frame_width = Math.round( this.track_clipThumb_height * 1.3333333 ); + var container_width = frame_width + 60; + } + + // for each clip: + for ( var j in track.clips ) { + clip = track.clips[j]; + // var img = clip.getClipImg('icon'); + if ( this.timeline_mode == 'storyboard' ) { + clip.left_px = j * container_width; + clip.width_px = container_width; + var base_id = 'track_' + track_id + '_clip_' + j; + track_html += ''; + track_html += clip.embed.renderTimelineThumbnail( { + 'width' : frame_width, + 'thumb_class' : 'mv_clip_thumb', + 'height':this.track_clipThumb_height, + 'time':0 + } ); + // render out edit button + /*track_html+='
    ';*/ + + // check if the clip has transitions + var imgHtml = ''; + var imsrc = ''; + var cat = clip; + if ( clip.transIn || clip.transOut ) { + if ( clip.transIn && clip.transIn.getIconSrc ) + imsrc = clip.transIn.getIconSrc(); + // @@todo put transOut somewhere else + if ( clip.transOut && clip.transOut.getIconSrc ) + imsrc = clip.transOut.getIconSrc(); + if ( imsrc != '' ) + imgHtml = ''; + } + // render out transition edit box + track_html += '
    ' + + imgHtml + + '
    ' + + // render out adjustment text + /*track_html+='
    '+ + ' - '+ + ( (clip.getDuration() > 60 )? seconds2npt(clip.getDuration()): clip.getDuration() ) + + ' + '+ + '
    '; + */ + track_html += ''; + + } + // do timeline_mode rendering: + if ( this.timeline_mode == 'time' ) { + clip.left_px = Math.round( cur_clip_time / this.timeline_scale ); + clip.width_px = Math.round( Math.round( clip.getDuration() ) / this.timeline_scale ); + clip.height_px = 60; + js_log( 'at time:' + cur_clip_time + ' left: ' + clip.left_px + ' clip dur: ' + Math.round( clip.getDuration() ) + ' clip width:' + clip.width_px ); + + // for every clip_width pixle output image + if ( track.disp_mode == 'timeline_thumb' ) { + track_html += ''; + track_html += this.render_clip_frames( clip ); + } else if ( track.disp_mode == 'text' ) { + // '+left_px+ + track_html += '' + clip.title; + } + // add in per clip controls + track_html += '
    ' + "\n"; + track_html += '
    ' + "\n"; + track_html += '
    ' + "\n"; + track_html += ''; + + track_html += '
    '; + // droppable_html+='
    '; + // droppable_html+='
    '; + cur_clip_time += Math.round( clip.getDuration() ); // increment cur_clip_time + } + + } + + // js_log("new htmL for track i: "+track_id + ' html:'+track_html); + $j( '#container_track_' + track_id ).html( track_html ); + + // apply transition click action + $j( '.clip_trans_box' ).click( function() { + if ( $j( this ).hasClass( 'mv_selected_transition' ) ) { + $j( this ).removeClass( 'mv_selected_transition' ); + this_seq.deselectClip( $j( this ).siblings( '.mv_clip_thumb' ).get( 0 ) ); + } else { + // deselect others + this_seq.deselectClip(); + $j( '.clip_trans_box' ).removeClass( 'mv_selected_transition' ); + $j( this ).addClass( "mv_selected_transition" ); + $j( this ).siblings( '.mv_clip_thumb' ).addClass( "mv_selected_clip" ); + var sClipObj = this_seq.getClipFromSeqID( $j( this ).parent().attr( 'id' ) ); + // jump to the current clip + this_seq.plObj.updateCurrentClip( sClipObj ); + // display the transition edit tab: + this_seq.disp( 'transition' ); + } + } ); + + // apply edit button mouse over effect: + $j( '.clip_edit_button' ).hover( function() { + $j( this ).removeClass( "clip_edit_base" ).addClass( "clip_edit_over" ); + }, function() { + $j( this ).removeClass( "clip_edit_over" ).addClass( "clip_edit_base" ); + } ).click( function() { + // deselect everything else: + $j( '.mv_selected_clip' ).each( function( inx, selected_clip ) { + this_seq.deselectClip( this ); + } ); + + var sClipObj = this_seq.getClipFromSeqID( $j( this ).parent().attr( 'id' ) ); + this_seq.plObj.updateCurrentClip( sClipObj ); + // get the clip (siblings with mv_clip_thumb class) + var cur_clip_elm = $j( this ).siblings( '.mv_clip_thumb' ); + // select the clip (add mv_selected_clip if not already selected) + if ( ! $j( cur_clip_elm ).hasClass( "mv_selected_clip" ) ) { + $j( cur_clip_elm ).addClass( 'mv_selected_clip' ); + $j( '#' + $j( cur_clip_elm ).parent().attr( "id" ) + '_adj' ).fadeIn( "fast" ); + } + // display the edit tab: + this_seq.disp( 'clipedit' ); + // display edit dialog: + this_seq.doEditClip( sClipObj ); + } ); + + // apply onClick edit controls: + $j( '.mv_clip_thumb' ).click( function() { + var cur_clip_click = this; + // if not in multi select mode remove all existing selections + // (except for the current click which is handled down below) + js_log( ' ks: ' + this_seq.key_shift_down + ' ctrl_down:' + this_seq.key_ctrl_down ); + if ( ! this_seq.key_shift_down && ! this_seq.key_ctrl_down ) { + $j( '.mv_selected_clip' ).each( function( inx, selected_clip ) { + if ( $j( this ).parent().attr( 'id' ) != $j( cur_clip_click ).parent().attr( 'id' ) + || ( $j( '.mv_selected_clip' ).length > 1 ) ) { + this_seq.deselectClip( this ); + } + } ); + } + + // jump to clip time + var sClipObj = this_seq.getClipFromSeqID( $j( this ).parent().attr( 'id' ) ); + this_seq.plObj.updateCurrentClip( sClipObj ); + if ( $j( this ).hasClass( "mv_selected_clip" ) ) { + $j( this ).removeClass( "mv_selected_clip" ); + $j( '#' + $j( this ).parent().attr( "id" ) + '_adj' ).fadeOut( "fast" ); + } else { + $j( this ).addClass( 'mv_selected_clip' ); + $j( '#' + $j( this ).parent().attr( "id" ) + '_adj' ).fadeIn( "fast" ); + } + // if shift select is down select the in-between clips + if ( this_seq.key_shift_down ) { + // get the min max of current selection (within the current track) + var max_order = 0; + var min_order = 999999999; + $j( '.mv_selected_clip' ).each( function() { + var cur_clip = this_seq.getClipFromSeqID( $j( this ).parent().attr( 'id' ) ); + // get min max + if ( cur_clip.order < min_order ) + min_order = cur_clip.order; + if ( cur_clip.order > max_order ) + max_order = cur_clip.order; + } ); + // select all non-selected between max or min + js_log( 'sOrder: ' + sClipObj.order + ' min:' + min_order + ' max:' + max_order ); + if ( sClipObj.order <= min_order ) { + for ( var i = sClipObj.order; i <= max_order; i++ ) { + $j( '#track_' + track_id + '_clip_' + i + ' > .mv_clip_thumb' ).addClass( 'mv_selected_clip' ); + } + } + if ( sClipObj.order >= max_order ) { + for ( var i = min_order; i <= max_order; i++ ) { + $j( '#track_' + track_id + '_clip_' + i + ' > .mv_clip_thumb' ).addClass( 'mv_selected_clip' ); + } + } + } + this_seq.doEditSelectedClip(); + } ); + // add in control for time based display + // debugger; + if ( this.timeline_mode == 'time' ) { + $j( '.ui-resizable-handle' ).mousedown( function() { + js_log( 'hid: ' + $j( this ).attr( 'class' ) ); + this_seq.resize_mode = ( $j( this ).attr( 'class' ).indexOf( 'ui-resizable-e' ) != -1 ) ? + 'resize_end':'resize_start'; + } ); + } + var insert_key = 'na'; + // drag hooks: + // @@todo support multiple clips + for ( var j in track.clips ) { + $j( '#track_' + track_id + '_clip_' + j ).draggable( { + axis:'x', + containment:'#container_track_' + track_id, + opacity:50, + handle: ":not(.clip_control)", + scroll:true, + drag:function( e, ui ) { + // debugger; + insert_key = this_seq.clipDragUpdate( ui, this ); + }, + start:function( e, ui ) { + js_log( 'start drag:' + this.id ); + // make sure we are ontop + $j( this ).css( { top:'0px', zindex:10 } ); + }, + stop:function( e, ui ) { + $j( this ).css( { top:'0px', zindex:0 } ); + + var id_parts = this.id.split( '_' ); + var track_inx = id_parts[1]; + var clip_inx = id_parts[3]; + var clips = this_seq.plObj.tracks[track_inx].clips; + var cur_drag_clip = clips[clip_inx]; + + if ( insert_key != 'na' && insert_key != 'end' ) { + cur_drag_clip.order = insert_key - .5; + } else if ( insert_key == 'end' ) { + cur_drag_clip.order = clips.length; + } + // reorder array based on new order + clips.sort( sort_func ); + function sort_func( a, b ) { + return a.order - b.order; + } + // assign keys back to order: + this_seq.plObj.tracks[track_inx].reOrderClips(); + // redraw: + this_seq.do_refresh_timeline(); + } + } ); + // add in resize hook if in time mode: + if ( this.timeline_mode == 'time' ) { + $j( '#track_' + track_id + '_clip_' + j ).resizable( { + minWidth:10, + maxWidth:6000, + start: function( e, ui ) { + // set border to red + $j( this ).css( { 'border':'solid thin red' } ); + // fade In Time stats (end or start based on handle) + // dragging east (adjusting end time) + js_log( 'append to: ' + this.id ); + $j( '#' + this.id + ' > .mv_clip_stats' ).fadeIn( "fast" ); + }, + stop: function( e, ui ) { + js_log( 'stop resize' ); + // restore border + $j( this ).css( 'border', 'solid thin white' ); + // remove stats + var clip_drag = this; + $j( '#' + this.id + ' > .mv_clip_stats' ).fadeOut( "fast", function() { + var id_parts = clip_drag.id.split( '_' ); + var track_inx = id_parts[1]; + var clip_inx = id_parts[3]; + // update clip + this_seq.doEdit( { + type:this_seq.resize_mode, + delta:this_seq.edit_delta, + track_inx:track_inx, + clip_inx:clip_inx } ) + } ); + }, + resize: function( e, ui ) { + // update time stats & render images: + this_seq.update_clip_resize( this ); + } + } ); + } + } + $j( '#container_track_' + track_id ).width( Math.round( this.timeline_duration / this.timeline_scale ) ); + } + // debugger; + } + }, + clipDragUpdate:function( ui, clipElm ) { + var this_seq = this; + + var insert_key = 'na'; + // animate re-arrange by left position: + // js_log('left: '+ui.position.left); + // locate clip (based on clip duration not animate) + var id_parts = clipElm.id.split( '_' ); + var track_inx = id_parts[1]; + var clip_inx = id_parts[3]; + var clips = this_seq.plObj.tracks[track_inx].clips; + var cur_drag_clip = clips[clip_inx]; + var return_org = true; + $j( clipElm ).css( 'zindex', 10 ); + // find out where we are inserting and set left border to solid red thick + for ( var k in clips ) { + if ( ui.position.left > clips[k].left_px && + ui.position.left < ( clips[k].left_px + clips[k].width_px ) ) { + if ( clip_inx != k ) { + // also make sure we are not where we started + if ( k - 1 != clip_inx ) { + $j( '#track_' + track_inx + '_clip_' + k ).css( 'border-left', 'solid thick red' ); + insert_key = k; + } else { + insert_key = 'na'; + } + } else { + insert_key = 'na'; + } + } else { + $j( '#track_' + track_inx + '_clip_' + k ).css( 'border-left', 'solid thin white' ); + } + } + // if greater than the last k insert after + if ( ui.position.left > ( clips[k].left_px + clips[k].width_px ) && + k != clip_inx ) { + $j( '#track_' + track_inx + '_clip_' + k ).css( 'border-right', 'solid thick red' ); + insert_key = 'end'; + } else { + $j( '#track_' + track_inx + '_clip_' + k ).css( 'border-right', 'solid thin white' ); + } + return insert_key; + }, + deselectClip:function( clipElm ) { + if ( !clipElm ) { + $j( '.mv_selected_clip' ).removeClass( "mv_selected_clip" ); + } else { + $j( clipElm ).removeClass( "mv_selected_clip" ); + // make sure the transition sibling is removed: + $j( clipElm ).siblings( '.clip_trans_box' ).removeClass( 'mv_selected_transition' ); + $j( '#' + $j( clipElm ).parent().attr( "id" ) + '_adj' ).fadeOut( "fast" ); + } + }, + getClipFromSeqID:function( clip_seq_id ) { + js_log( 'get id from: ' + clip_seq_id ); + var ct = clip_seq_id.replace( 'track_', '' ).replace( 'clip_', '' ).split( '_' ); + return this.plObj.tracks[ ct[0] ].clips[ ct[1] ]; + }, + // renders clip frames + render_clip_frames:function( clip, frame_offset_count ) { + js_log( 'f:render_clip_frames: ' + clip.id + ' foc:' + frame_offset_count ); + var clip_frames_html = ''; + var frame_width = Math.round( this.track_thumb_height * 1.3333333 ); + + var pint = ( frame_offset_count == null ) ? 0:frame_offset_count * frame_width; + + // js_log("pinit: "+ pint+ ' < '+clip.width_px+' ++'+frame_width); + for ( var p = pint; p < clip.width_px; p += frame_width ) { + var clip_time = ( p == 0 ) ? 0:Math.round( p * this.timeline_scale ); + js_log( 'rendering clip frames: p:' + p + ' pts:' + ( p * this.timeline_scale ) + ' time:' + clip_time + ' height:' + this.track_thumb_height ); + clip_frames_html += clip.embed.renderTimelineThumbnail( { + 'width': frame_width, + 'thumb_class':'mv_tl_thumb', + 'height': this.track_thumb_height, + 'size' : "icon", // set size to "icon" preset + 'time': clip_time + } ); + } + js_log( 'render_clip_frames:' + clip_frames_html ); + return clip_frames_html; + }, + update_clip_resize:function( clip_element ) { + // js_log('update_clip_resize'); + var this_seq = this; + var id_parts = clip_element.id.split( '_' ); + track_inx = id_parts[1]; + clip_inx = id_parts[3]; + // set clip: + var clip = this.plObj.tracks[ track_inx ].clips[ clip_inx ]; + var clip_desc = ''; + // would be nice if getting the width did not flicker the border + // @@todo do a work around e in resize function has some screen based offset values + clip.width_px = $j( clip_element ).width(); + var width_dif = clip.width_px - Math.round( Math.round( clip.getDuration() ) / this.timeline_scale ); + // var left_px = $j(clip_element).css('left'); + + var new_clip_dur = Math.round( clip.width_px * this.timeline_scale ); + var clip_dif = ( new_clip_dur - clip.getDuration() ); + var clip_dif_str = ( clip_dif > 0 ) ? '+' + clip_dif:clip_dif; + // set the edit global delta + this.edit_delta = clip_dif; + + // get new length: + clip_desc += 'length: ' + seconds2npt( new_clip_dur ) + '(' + clip_dif_str + ')'; + if ( this_seq.resize_mode == 'resize_end' ) { + // expanding right + var new_end = seconds2npt( npt2seconds( clip.embed.end_ntp ) + clip_dif ); + clip_desc += '
    end time: ' + new_end; + // also shift all the other clips (after the current) + // js_log("track_inx: " + track_inx + ' clip inx:'+clip_inx); + // $j('#container_track_'+track_inx+' > .mv_clip_drag :gt('+clip_inx+')').each(function(){ + $j( '#container_track_' + track_inx + ' > :gt(' + clip_inx + ')' ).each( function() { + var move_id_parts = this.id.split( '_' ); + var move_clip = this_seq.plObj.tracks[move_id_parts[1]].clips[move_id_parts[3]]; + // js_log('should move:'+ this.id); + $j( this ).css( 'left', move_clip.left_px + width_dif ); + } ); + } else { + // expanding left (resize_start) + var new_start = seconds2npt( npt2seconds( clip.embed.start_ntp ) + clip_dif ); + clip_desc += '
    start time: ' + new_start; + } + + // update clip stats: + $j( '#' + clip_element.id + ' > .mv_clip_stats' ).html( clip_desc ); + var frame_width = Math.round( this.track_thumb_height * 1.3333333 ); + // check if we need to append some images: + var frame_count = $j( '#' + clip_element.id + ' > img' ).length; + if ( clip.width_px > ( frame_count * frame_width ) ) { + // if dragging left append + js_log( 'width_px:' + clip.width_px + ' framecount:' + frame_count + ' Xcw=' + ( frame_count * frame_width ) ); + $j( '#' + clip_element.id ).append( this.render_clip_frames( clip, frame_count ) ); + } + }, + // renders cnt_time + render_playheadhead_seeker:function() { + js_log( 'render_playheadhead_seeker' ); + // render out time stamps and time "jump" links + // first get total width + + // remove the old one if its still there + $j( '#' + this.timeline_id + '_pl_control' ).remove(); + // render out a playlist clip wide and all the way to the right (only playhead and play button) (outside of timeline) + $j( this.target_sequence_container ).append( '
    ' + + this.plObj.getControlsHTML() + + '
    ' + + '
    ' ); + // update time and render out clip dividers .. should be used to show load progress + this.plObj.updateBaseStatus(); + + // once the controls are in the DOM add hooks: + this.plObj.ctrlBuilder.addControlHooks( $j( '#' + this.timeline_id + '_pl_control' ) ); + + // render out the "jump" div + if ( this.timeline_mode == 'time' ) { + /*$j('#'+this.timeline_id+'_head_jump').width(pixle_length); + //output times every 50pixles + var out=''; + //output time-desc every 50pixles and jump links every 10 pixles + var n=0; + for(i=0;i
    '; + if(n==0) + out+='|'+seconds2npt(Math.round(i*this.timeline_scale))+''; + n++; + if(n==10)n=0; + }*/ + + } + }, + jt:function( jh_time ) { + js_log( 'jt:' + jh_time ); + var this_seq = this; + this.playline_time = jh_time; + js_log( 'time: ' + seconds2npt( jh_time ) + ' ' + Math.round( jh_time / this.timeline_scale ) ); + // render playline at given time + $j( '#' + this.timeline_id + '_playline' ).css( 'left', Math.round( jh_time / this.timeline_scale ) + 'px' ); + cur_pl_time = 0; + // update the thumb with the requested time: + this.plObj.updateThumbTime( jh_time ); + }, + // adjusts the current scale + zoom_in:function() { + this.timeline_scale = this.timeline_scale * .75; + this.do_refresh_timeline(); + js_log( 'zoomed in:' + this.timeline_scale ); + }, + zoom_out:function() { + this.timeline_scale = this.timeline_scale * ( 1 + ( 1 / 3 ) ); + this.do_refresh_timeline(); + js_log( 'zoom out: ' + this.timeline_scale ); + }, + do_refresh_timeline:function( preserve_selection ) { + js_log( 'Sequencer:do_refresh_timeline()' ); + // @@todo should "lock" interface while refreshing timeline + var pSelClips = []; + if ( preserve_selection ) { + $j( '.mv_selected_clip' ).each( function() { + pSelClips.push( $j( this ).parent().attr( 'id' ) ); + } ); + } + // regen duration + this.plObj.getDuration( true ); + // refresh player: + this.plObj.getHTML(); + + // this.render_playheadhead_seeker(); + this.render_tracks(); + this.jt( this.playline_time ); + + if ( preserve_selection ) { + for ( var i = 0; i < pSelClips.length; i++ ) { + $j( '#' + pSelClips[i] + ' .mv_clip_thumb' ).addClass( 'mv_selected_clip' ); + } + } + } + +} +/* extension to mvPlayList to support sequencer features properties */ +var mvSeqPlayList = function( element ) { + return this.init( element ); +} +mvSeqPlayList.prototype = { + init:function( element ) { + var myPlObj = new mvPlayList( element ); + + // inherit mvClip + for ( var method in myPlObj ) { + if ( typeof this[method] != 'undefined' ) { + this[ 'parent_' + method ] = myPlObj[method]; + } else { + this[method] = myPlObj[method]; + } + } + + this.org_control_height = this.pl_layout.control_height; + // do specific mods:(controls and title are managed by the sequencer) + this.pl_layout.title_bar_height = 0; + this.pl_layout.control_height = 0; + }, + setSliderValue:function( perc ) { + js_log( 'setSliderValue::' + perc ); + // get the track_clipThumb_height from parent mvSequencer + var frame_width = Math.round( this.pSeq.track_clipThumb_height * 1.3333333 ); + var container_width = frame_width + 60; + + var perc_clip = this.cur_clip.embed.currentTime / this.cur_clip.getDuration(); + + var left_px = parseInt( ( this.cur_clip.order * container_width ) + ( frame_width * perc_clip ) ) + 'px'; + js_log( "set " + perc + ' of cur_clip: ' + this.cur_clip.order + ' lp:' + left_px ); + + + // update the timeline playhead and + $j( '#' + this.seqObj.timeline_id + '_playline' ).css( 'left', left_px ); + + // pass update request to parent: + this.parent_setSliderValue( perc ); + }, + getControlsHTML:function() { + // get controls from current clip add some playlist specific controls: + this.cur_clip.embed.supports['prev_next'] = true; + this.cur_clip.embed.supports['options'] = false; + return ctrlBuilder.getControls( this.cur_clip.embed ); + }, + // override renderDisplay + renderDisplay:function() { + js_log( 'mvSequence:renderDisplay' ); + // setup layout for title and dc_ clip container + $j( this ).html( '
    ' ); + + this.setupClipDisplay(); + } +}; diff --git a/js2/mwEmbed/libSequencer/mvTimedEffectsEdit.js b/js2/mwEmbed/libSequencer/mvTimedEffectsEdit.js new file mode 100644 index 0000000000..0edb7529f8 --- /dev/null +++ b/js2/mwEmbed/libSequencer/mvTimedEffectsEdit.js @@ -0,0 +1,267 @@ +/* +* mvTimedEffectsEdit +* +* for now just simple single stack transition control +* +*/ + +// add our local msgs +loadGM( { + "mwe-transition_in" : "Transition in", + "mwe-transition_out" : "Transition out", + "mwe-effects" : "Effects stack", + "mwe-remove_transition" : "Remove transition", + "mwe-edit_transin" : "Edit transition into clip", + "mwe-edit_transout" : "Edit transition out of clip", + "mwe-add-transition" : "Add a transition" +} ); + +var default_timed_effect_values = { + 'rObj': null, // the resource object + 'clip_disp_ct':null, // target clip disp + 'control_ct':null, // control container + + 'parent_ct': null, // parent container + 'pSeq': null, // parent sequence Object + + 'edit_action': null, // the requested edit action +}; + +var mvTimedEffectsEdit = function( iObj ) { + return this.init( iObj ); +}; +// set up the mvSequencer object +mvTimedEffectsEdit.prototype = { + // the menu_items Object contains: default html, js setup/loader functions + menu_items : { + 'transin': { + 'title':gM( 'mwe-transition_in' ), + 'clip_attr':'transIn', + 'doEdit':function( _this ) { + _this.doTransitionDisplayEdit( 'transin' ); + } + }, + 'transout': { + 'title':gM( 'mwe-transition_out' ), + 'clip_attr':'transOut', + 'doEdit':function( _this ) { + _this.doTransitionDisplayEdit( 'transout' ); + } + }, + 'effects': { + 'title':gM( 'mwe-effects' ), + 'clip_attr':'Effects', + 'doEdit':function( _this ) { + // display + _this.doEditEffectDisplayEdit(); + } + } + }, + init:function( iObj ) { + // init object: + for ( var i in default_timed_effect_values ) { + if ( iObj[i] ) { + this[i] = iObj[i]; + } + } + this.doEditMenu(); + }, + doEditMenu:function() { + js_log( 'mvTimedEffects : doEditMenu::' ); + var _this = this; + // add in subMenus if set + // check for submenu and add to item container + + // update the default edit display (if we have a target) + var tTarget = 'transin'; + if ( this.rObj.transOut ) + tTarget = 'transout'; + if ( this.rObj.effects ) + tTarget = 'effects'; + + var o = ''; + var tabc = ''; + o += '
    '; + o += '
      '; + var inx = 0; + var selected_tab = 0; + $j.each( this.menu_items, function( sInx, mItem ) { + if ( sInx == tTarget ) { + selected_tab = inx; + } + // check if the given editType is valid for our given media type + o += '
    • ' + + '' + mItem.title + '' + + '
    • '; + tabc += '
      '; + inx++; + } ); + o += '
    ' + tabc; + o += '
    '; + // add sub menu container with menu html: + $j( '#' + this.control_ct ).html( o ) ; + js_log( 'should have set: #' + this.control_ct + ' to: ' + o ); + // set up bindins: + $j( '#mv_submenu_timedeffect' ).tabs( { + selected: selected_tab, + select: function( event, ui ) { + _this.doDisplayEdit( $j( ui.tab ).attr( 'id' ).replace( 'mv_te_', '' ) ); + } + } ).addClass( 'ui-tabs-vertical ui-helper-clearfix' ); + // close left: + $j( "#mv_submenu_clipedit li" ).removeClass( 'ui-corner-top' ).addClass( 'ui-corner-left' ); + _this.doDisplayEdit( tTarget ); + }, + doDisplayEdit:function( tab_id ) { + // @@todo fix the double display of doDisplayEdit + js_log( "doDisplayEdit::" ); + if ( !this.menu_items[ tab_id ] ) { + js_log( 'error: doDisplayEdit missing item:' + tab_id ); + } else { + // use the menu_item config to map to function display + this.menu_items[tab_id].doEdit( this ); + } + }, + doEditEffectDisplayEdit:function() { + var _this = this; + var appendTarget = '#te_effects'; + js_log( 'type:' + _this.rObj['type'] ); + $j( appendTarget ).html( gM( 'mwe-loading_txt' ) ); + // @@todo integrate into core and loading system: + loadExternalJs( mv_embed_path + 'libClipEdit/pixastic-editor/editor.js?' + getMwReqParam() ); + loadExternalJs( mv_embed_path + 'libClipEdit/pixastic-editor/pixastic.all.js?' + getMwReqParam() ); + loadExternalJs( mv_embed_path + 'libClipEdit/pixastic-editor/ui.js?' + getMwReqParam() ); + loadExternalJs( mv_embed_path + 'libClipEdit/pixastic-editor/uidata.js?' + getMwReqParam() ); + loadExternalCss( mv_embed_path + 'libClipEdit/pixastic-editor/pixastic.all.js?' + getMwReqParam() ); + + var isPixasticReady = function() { + if ( typeof PixasticEditor != 'undefined' ) { + $j( appendTarget ).html( 'Run Pixastic Editor Demo (not yet fully integrated/ super alpha)
    best to view stand alone' ); + $j( appendTarget + ' .run_effect_demo' ).click( function() { + var cat = _this; + var imgElm = $j( '.clip_container:visible img' ).get( 0 ); + PixasticEditor.load( imgElm ); + } ); + } else { + setTimeout( isPixasticReady, 100 ) + } + } + isPixasticReady(); + }, + doTransitionDisplayEdit:function( target_item ) { + var _this = this; + js_log( "doTransitionDisplayEdit: " + target_item ); + var apendTarget = '#te_' + target_item; + // check if we have a transition of type clip_attr + if ( !this.rObj[ this.menu_items[ target_item ].clip_attr ] ) { + // empty append the transition list: + this.getTransitionListControl( apendTarget ); + return ; + } + var cTran = this.rObj[ this.menu_items[ target_item ].clip_attr ]; + var o = '

    ' + gM( 'mwe-edit_' + target_item ) + '

    '; + o += 'Type: ' + + '
    '; + o += ''; + + // add html and select bindings + $j( apendTarget ).html( o ).children( '.te_select_type' ) + .change( function() { + var selectedType = $j( this ).val(); + // update subtype listing: + _this.getSubTypeControl( target_item, selectedType, apendTarget + ' .te_subtype_container' ); + } ); + // add subtype control + _this.getSubTypeControl( target_item, cTran.type, apendTarget + ' .te_subtype_container' ); + + // add remove transition button: + $j( apendTarget ).append( '

    ' + $j.btnHtml( gM( 'mwe-remove_transition' ), 'te_remove_transition', 'close' ) ) + .children( '.te_remove_transition' ) + .click( function() { + // remove the transtion from the playlist + _this.pSeq.plObj.transitions[cTran.id] = null; + // remove the transtion from the clip: + _this.rObj[ _this.menu_items[ target_item ].clip_attr ] = null; + // update the interface: + _this.doTransitionDisplayEdit( target_item ); + // update the sequence + _this.pSeq.do_refresh_timeline(); + } ); + }, + getSubTypeControl:function( target_item, transition_type, htmlTarget ) { + var _this = this; + var cTran = this.rObj[ this.menu_items[ target_item ].clip_attr ]; + var o = 'Sub Type:
    '; + $j( htmlTarget ).html( o ) + .children( '.te_subtype_select' ) + .change( function() { + // update the property + cTran.subtype = $j( this ).val(); + // re-gen timeline / playlist + _this.pSeq.do_refresh_timeline(); + // (re-select self?) + _this.getSubTypeControl( target_item, transition_type, htmlTarget ); + } ); + var o = ''; + // check for extra properties control: + for ( var i = 0; i < mvTransLib.type[ transition_type ][ cTran.subtype ].attr.length; i++ ) { + var tAttr = mvTransLib.type[ transition_type ][ cTran.subtype ].attr[i] + switch( tAttr ) { + case 'fadeColor': + var cColor = ( cTran['fadeColor'] ) ? cTran['fadeColor']:''; + $j( htmlTarget ).append( 'Select Color:
    ' ); + js_log( 'cs target: ' + htmlTarget + ' .colorSelector' ); + + + $j( htmlTarget + ' .colorSelector' ).ColorPicker( { + color: cColor, + onShow: function ( colpkr ) { + // make sure its ontop: + $j( colpkr ).css( "zIndex", "12" ); + $j( colpkr ).fadeIn( 500 ); + return false; + }, + onHide: function ( colpkr ) { + $j( colpkr ).fadeOut( 500 ); + _this.pSeq.plObj.setCurrentTime( 0, function() { + js_log( "render ready" ); + } ); + return false; + }, + onChange: function ( hsb, hex, rgb ) { + $j( htmlTarget + ' .colorIndicator' ).css( 'backgroundColor', '#' + hex ); + // update the transition + cTran['fadeColor'] = '#' + hex; + } + } ) + break; + } + } + // and finally add effect timeline scruber (for timed effects this also stores keyframes) + + }, + getTransitionListControl : function( target_out ) { + js_log( "getTransitionListControl" ); + var o = '

    ' + gM( 'mwe-add-transition' ) + '

    '; + for ( var type in mvTransLib['type'] ) { + js_log( 'on tran type: ' + i ); + var base_trans_name = i; + var tLibSet = mvTransLib['type'][ type ]; + for ( var subtype in tLibSet ) { + o += ''; + } + } + $j( target_out ).html( o ); + } +}; diff --git a/js2/mwEmbed/libSequencer/seqRemoteSearchDriver.js b/js2/mwEmbed/libSequencer/seqRemoteSearchDriver.js new file mode 100644 index 0000000000..25aa0c2ddf --- /dev/null +++ b/js2/mwEmbed/libSequencer/seqRemoteSearchDriver.js @@ -0,0 +1,184 @@ +/*the sequence remote search driver + extends the base remote search driver with sequence specific stuff +*/ + +var seqRemoteSearchDriver = function( iObj ) { + return this.init( iObj ) +} +seqRemoteSearchDriver.prototype = { + sequence_add_target:false, + init:function( this_seq ) { + var _this = this; + js_log( "init:seqRemoteSearchDriver" ); + // setup remote search driver with a seq parent: + this.pSeq = this_seq; + var iObj = { + 'target_container' : '#cliplib_ic', + 'local_wiki_api_url': this_seq.getLocalApiUrl(), + 'instance_name' : this_seq.instance_name + '.mySearch', + 'default_query' : this.pSeq.plObj.title + } + if ( typeof this_seq.amw_conf != 'undefined' ) + $j.extend( iObj, this_seq.amw_conf ); + + + // inherit the remoteSearchDriver properties:n + var tmpRSD = new remoteSearchDriver( iObj ); + for ( var i in tmpRSD ) { + if ( this[i] ) { + this['parent_' + i] = tmpRSD[i]; + } else { + this[i] = tmpRSD[i]; + } + } + // extend parent_do_refresh_timeline actions: + if ( !this.pSeq.parent_do_refresh_timeline ) { + this.pSeq.parent_do_refresh_timeline = this.pSeq.do_refresh_timeline; + this.pSeq.do_refresh_timeline = function() { + js_log( "seqRemoteSearchDriver::" + _this.pSeq.disp_menu_item ); + // call the parent + _this.pSeq.parent_do_refresh_timeline(); + // add our local bindings + _this.addResultBindings(); + return true; + } + } + }, + resourceEdit:function() { + var _this = this; + + }, + addResultBindings:function() { + // set up seq: + var _this = this; + // setup parent bindings: + this.parent_addResultBindings(); + + // Add an additional click binding + $j( '.rsd_res_item' ).click( function() { + js_log( 'SeqRemoteSearch: rsd_res_item: click (remove sequence_add_target)' ); + _this.sequence_add_target = false; + } ); + + // Add an additional drag binding + $j( '.rsd_res_item' ).draggable( 'destroy' ).draggable( { + helper:function() { + return $j( this ). clone ().appendTo( 'body' ).css( { 'z-index':9999 } ).get( 0 ); + }, + revert:'invalid', + start:function() { + js_log( 'start drag' ); + } + } ); + $j( ".mv_clip_drag" ).droppable( 'destroy' ).droppable( { + accept: '.rsd_res_item', + over:function( event, ui ) { + // js_log("over : mv_clip_drag: " + $j(this).attr('id') ); + $j( this ).css( 'border-right', 'solid thick red' ); + }, + out:function( event, ui ) { + $j( this ).css( 'border-right', 'solid thin white' ); + }, + drop: function( event, ui ) { + $j( this ).css( 'border-right', 'solid thin white' ); + js_log( "Droped: " + $j( ui.draggable ).attr( 'id' ) + ' on ' + $j( this ).attr( 'id' ) ); + _this.sequence_add_target = $j( this ).attr( 'id' ); + // load the orginal draged item + var rObj = _this.getResourceFromId( $j( ui.draggable ).attr( 'id' ) ); + _this.resourceEdit( rObj, ui.draggable ); + } + } ); + + }, + insertResource:function( rObj ) { + var _this = this; + js_log( "SEQ insert resource after:" + _this.sequence_add_target + ' of type: ' + rObj.mime ); + if ( _this.sequence_add_target ) { + var tClip = _this.pSeq.getClipFromSeqID( _this.sequence_add_target ); + var target_order = false; + if ( tClip ) + var target_order = tClip.order; + } + // @@todo show watting of sorts. + + // get target order: + var cat = rObj; + // check for target insert path + this.checkImportResource( rObj, function() { + + var clipConfig = { + 'type' : rObj.mime, + 'uri' : _this.fileNS + ':' + rObj.target_resource_title, + 'title' : rObj.title + }; + // Set via local properties if available + clipConfig['src'] = ( rObj.local_src ) ? rObj.local_src : rObj.src; + clipConfig['poster'] = ( rObj.local_poster ) ? rObj.local_poster : rObj.poster; + + if ( rObj.start_time && rObj.end_time ) { + clipConfig['dur'] = npt2seconds( rObj.end_time ) - npt2seconds( rObj.start_time ); + } else { + // Provide a default duration if none set + clipConfig['dur'] = 4; + } + + // Create the media element (target order+1 (since we insert (after) + _this.pSeq.plObj.tryAddMediaObj( clipConfig, ( parseInt( target_order ) + 1 ) ); + + // Refresh the timeline: + _this.pSeq.do_refresh_timeline(); + js_log( "run close all: " ); + _this.closeAll(); + } ); + }, + getClipEditControlActions:function() { + var _this = this; + return { + 'insert_seq':function( rObj ) { + _this.insertResource( rObj ) + }, + 'cancel':function( rObj ) { + _this.cancelClipEditCB( rObj ) + } + }; + }, + resourceEdit:function( rObj, rsdElement ) { + var _this = this; + // don't resize to default (full screen behavior) + _this.dmodalCss = { }; + // open up a new target_contaienr: + if ( $j( '#seq_resource_import' ).length == 0 ) + $j( 'body' ).append( '
    ' ); + var bConf = { }; + bConf[ gM( 'mwe-cancel' ) ] = function() { + $j( this ).dialog( "close" ); + } + $j( '#seq_resource_import' ).dialog( 'destroy' ).dialog( { + bgiframe: true, + width:750, + height:480, + modal: true, + buttons: bConf + } ); + _this.target_container = '#seq_resource_import'; + // do parent resource edit (with updated target) + this.parent_resourceEdit( rObj, rsdElement ); + }, + closeAll:function() { + js_log( 'should close: seq_resource_import' ); + $j( '#seq_resource_import' ).dialog( 'close' ).dialog( 'destroy' ).remove(); + this.parent_closeAll(); + }, + getEditToken:function( callback ) { + if ( this.pSeq.sequenceEditToken ) { + callback( this.pSeq.sequenceEditToken ) + } else { + this.parent_getEditToken( callback ); + } + }, + cancelClipEditCB:function() { + js_log( 'seqRSD:cancelClipEditCB' ); + $j( '#seq_resource_import' ).dialog( 'close' ).dialog( 'destroy' ).remove(); + } +}; + diff --git a/js2/mwEmbed/libTimedText/mvTextInterface.js b/js2/mwEmbed/libTimedText/mvTextInterface.js new file mode 100644 index 0000000000..7326c477ff --- /dev/null +++ b/js2/mwEmbed/libTimedText/mvTextInterface.js @@ -0,0 +1,695 @@ +loadGM( { + "mwe-select_transcript_set" : "Select subtitles", + "mwe-auto_scroll" : "auto scroll", + "mwe-close" : "close", + "mwe-improve_transcript" : "Improve", + "mwe-no_text_tracks_found" : "No text subtitles found", + "mwe-add-edit-subs" : "Add/edit subtitles" +} ) +// text interface object (for inline display captions) +var mvTextInterface = function( parentEmbed ) { + return this.init( parentEmbed ); +} +mvTextInterface.prototype = { + text_lookahead_time:0, + body_ready:false, + default_time_range: "source", // by default just use the source don't get a time-range + transcript_set:null, + autoscroll:true, + add_to_end_on_this_pass:false, + scrollTimerId:0, + editlink: '', + suportedMime: { + 'srt': 'text/x-srt', + 'cmml': 'text/cmml' + }, + init:function( parentEmbed ) { + // init a new availableTracks obj: + this.availableTracks = new Array(); + // set the parent embed object: + this.pe = parentEmbed; + // parse roe if not already done: + this.getTextTracks(); + }, + // @@todo separate out data loader & data display + getTextTracks:function() { + // js_log("load timed text from roe: "+ this.pe.roe); + var _this = this; + // if roe not yet loaded do load it: + if ( this.pe.roe || _this.pe.wikiTitleKey ) { + if ( !this.pe.media_element.addedROEData ) { + $j( '#mv_txt_load_' + _this.pe.id ).show(); // show the loading icon + if ( _this.pe.roe ) { + do_request( _this.pe.roe, function( data ) + { + _this.pe.media_element.addROE( data ); + _this.getParseTimedText_rowReady(); + } ); + } else if ( _this.pe.wikiTitleKey ) { + // check for a clear namespace key: + _this.getTextTracksWikiTitle() + } + } else { + js_log( 'row data ready (no roe request)' ); + _this.getParseTimedText_rowReady(); + } + } else { + if ( this.pe.media_element.timedTextSources() ) { + _this.getParseTimedText_rowReady(); + } else { + js_log( 'no roe data or timed text sources' ); + } + } + }, + getTextTracksWikiTitle:function() { + var apiUrl = mw.getLocalApiUrl(); + var _this = this; + + var timedtext_ns = 102; + if ( typeof wgNamespaceIds != 'undefined' && wgNamespaceIds['timedtext'] ) { + timedtext_ns = wgNamespaceIds['timedtext']; + } + do_api_req( { + 'url' : apiUrl, + 'data': { + 'list' : 'allpages', + 'apprefix' : _this.pe.wikiTitleKey, + 'apnamespace' : timedtext_ns, + 'prop':'revisions' + } + }, function( subData ) { + if ( subData.error && subData.error.code == 'apunknown_apnamespace' ) { + do_api_req( { + 'url' : apiUrl, + 'data': { + 'list' : 'allpages', + 'apprefix' : 'TimedText:' + _this.pe.wikiTitleKey, + } + }, function( subData ) { + _this.doProcSubPages( subData, wgServer + wgScriptPath ); + } ); + } else { + _this.doProcSubPages( subData, wgServer + wgScriptPath ); + } + } ); + }, + doProcSubPages: function( subData, hostPath ) { + var _this = this; + // look for text tracks: + var foundTextTracks = false; + + // get all the known languages: + do_api_req( { + 'url': hostPath + '/api.php', + 'data': { + 'meta' : 'siteinfo', + 'siprop' : 'languages' + } + }, function( langDataRaw ) { + var langData = { }; + var lagRaw = langDataRaw.query.languages; + for ( var j in lagRaw ) { + langData[ lagRaw[j].code ] = lagRaw[j]['*']; + } + for ( var i in subData.query.allpages ) { + var subPage = subData.query.allpages[i]; + var langKey = subPage.title.split( '.' ); + var extension = langKey.pop(); + langKey = langKey.pop(); + if ( ! _this.suportedMime[ extension ] ) { + js_log( 'Error: unknown extension:' + extension ); + continue; + } + + if ( !langData[ langKey] ) { + js_log( 'Error: langkey:' + langKey + ' not found' ); + } else { + var textElm = document.createElement( 'text' ); + $j( textElm ).attr( { + 'category' : 'SUB', + 'lang' : langKey, + 'type' : _this.suportedMime[ extension ], + 'title' : langData[ langKey] + } ); + // We use the api since ?action raw on the real title has cache issues + $j( textElm ).attr( { + 'apisrc' : hostPath + '/api.php', + 'titleKey' : subPage.title + } ); + _this.pe.media_element.tryAddSource( textElm ); + foundTextTracks = true; + } + } + // after all text loaded (or we have allready checked commons + if ( foundTextTracks || hostPath.indexOf( 'commons.wikimedia' ) !== -1 ) { + // alert('calling getParseTimedText_rowReady '); + _this.getParseTimedText_rowReady(); + } else { + _this.checkSharedRepo(); + } + } ); // do_api_req({ + }, + checkSharedRepo:function() { + var _this = this; + js_log( 'checking for shared value of image' ); + // check if its a shared repo + do_api_req( { + 'data': { + 'action':'query', + 'titles': 'File:' + _this.pe.wikiTitleKey, + 'prop' : 'imageinfo' + } + }, function( data ) { + if ( data.query.pages && data.query.pages['-1'] && data.query.pages['-1'].imagerepository == 'shared' ) { + js_log( 'image is shared checking commons for subtitles' ); + // found shared repo assume commons: + do_api_req( { + 'url': mw.commons_api_url, + 'data': { + 'list' : 'allpages', + 'apprefix' : _this.pe.wikiTitleKey, + 'apnamespace' : 102 + } + }, function( data ) { + _this.editlink = 'http://commons.wikimedia.org/wiki/TimedText:' + _this.pe.wikiTitleKey + '.' + wgUserLanguage + '.srt'; + _this.doProcSubPages( data, 'http://commons.wikimedia.org/w/' ); + } ); + } else { + // no shared repo do normal proc + _this.getParseTimedText_rowReady(); + } + } ); + }, + getParseTimedText_rowReady: function () { + var _this = this; + var found_tracks = false; + // create timedTextObj + js_log( "mv_txt_load_:SHOW mv_txt_load_" ); + $j( '#mv_txt_load_' + _this.pe.id ).show(); // show the loading icon + + // setup edit link: + if ( _this.editlink == '' ) { + if ( this.pe.media_element.linkback ) { + _this.editlink = this.pe.media_element.linkback; + } else if ( this.pe.wikiTitleKey && wgServer && wgScript ) { // check for wikiTitleKey (for edit linkback) + // only local: + _this.editlink = wgServer + wgScript + '?title=TimedText:' + this.pe.wikiTitleKey + '.' + wgUserLanguage + '.srt&action=edit'; + } + } + $j.each( this.pe.media_element.sources, function( inx, source ) { + if ( typeof source.id == 'undefined' || source.id == null ) { + source.id = 'text_' + inx; + } + var tObj = new timedTextObj( source ); + // make sure its a valid timed text format (we have not loaded or parsed yet) : ( + if ( tObj.lib != null ) { + _this.availableTracks.push( tObj ); + // display requested language if we can know that: + if ( ( typeof wgUserLanguage != 'undefined' && source['lang'] == wgUserLanguage ) || source['default'] == "true" ) { + // we did set at least one track by default tag + found_tracks = true; + _this.loadAndDisplay( _this.availableTracks.length - 1 ); + } else { + // don't load the track and don't display + } + } + } ); + + // no default clip found take the userLanguage key if set: + if ( !found_tracks ) { + $j.each( _this.availableTracks, function( inx, source ) { + _this.loadAndDisplay( inx ); + found_tracks = true; + // return after loading first available + return false; + } ); + } + + // if nothing found anywhere give the not found msg: + if ( !found_tracks ) { + $j( '#metaBox_' + _this.pe.id ).html( '' + + '

    ' + gM( 'mwe-no_text_tracks_found' ) + '

    ' + + '' + gM( 'mwe-add-edit-subs' ) + '' + ); + } + }, + loadAndDisplay: function ( track_id ) { + var _this = this; + $j( '#mv_txt_load_' + _this.pe.id ).show();// show the loading icon + _this.availableTracks[ track_id ].load( _this.default_time_range, function() { + $j( '#mv_txt_load_' + _this.pe.id ).hide(); + _this.addTrack( track_id ); + } ); + }, + addTrack: function( track_id ) { + js_log( 'f:displayTrack:' + track_id ); + var _this = this; + // set the display flag to true: + _this.availableTracks[ track_id ].display = true; + // setup the layout: + this.setup_layout(); + js_log( "SHOULD ADD: track:" + track_id + ' count:' + _this.availableTracks[ track_id ].textNodes.length ); + + // a flag to avoid checking all clips if we know we are adding to the end: + _this.add_to_end_on_this_pass = false; + + // run clip adding on a timed interval to not lock the browser on large srt file merges (should use worker threads) + var i = 0; + var track_id = track_id; + var addNextClip = function() { + var text_clip = _this.availableTracks[ track_id ].textNodes[i]; + if ( text_clip ) { + _this.add_merge_text_clip( text_clip, track_id ); + i++; + if ( i < _this.availableTracks[ track_id ].textNodes.length ) { + setTimeout( addNextClip, 1 ); + } + } + } + addNextClip(); + }, + add_merge_text_clip: function( text_clip, track_id ) { + var _this = this; + // make sure the clip does not already exist: + if ( $j( '#tc_' + text_clip.id ).length == 0 ) { + var inserted = false; + var text_clip_start_time = npt2seconds( text_clip.start ); + + var insertHTML = '
    ' + + '
    ' + + text_clip.start + ' to ' + text_clip.end + + '
    ' + + text_clip.body + + '
    '; + if ( !_this.add_to_end_on_this_pass ) { + $j( '#mmbody_' + this.pe.id + ' .mvtt' ).each( function() { + if ( !inserted ) { + if ( $j( this ).attr( 'start_sec' ) > text_clip_start_time ) { + inserted = true; + $j( this ).before( insertHTML ); + } + } else { + _this.add_to_end = true; + } + } ); + } + // js_log('should just add to end: '+insertHTML); + if ( !inserted ) { + $j( '#mmbody_' + this.pe.id ).append( insertHTML ); + } + + // apply the mouse over transcript seek/click functions: + $j( ".mvttseek" ).click( function() { + _this.pe.doSeek( $j( this ).parent().attr( "start_sec" ) / _this.pe.getDuration() ); + } ); + $j( ".mvttseek" ).hoverIntent( { + interval:200, // polling interval + timeout:200, // delay before onMouseOut + over:function () { + js_log( 'mvttseek: over' ); + $j( this ).parent().addClass( 'tt_highlight' ); + // do section highlight + _this.pe.highlightPlaySection( { + 'start' : $j( this ).parent().attr( "start" ), + 'end' : $j( this ).parent().attr( "end" ) + } ); + }, + out:function () { + js_log( 'mvttseek: out' ); + $j( this ).parent().removeClass( 'tt_highlight' ); + // de highlight section + _this.pe.hideHighlight(); + } + } + ); + } + }, + setup_layout:function() { + var _this = this; + // check if we have already loaded the menu/body: + if ( $j( '#tt_mmenu_' + this.pe.id ).length == 0 ) { + // alert( this.availableTracks.length ); + if ( this.availableTracks.length != 0 ) { + $j( '#metaBox_' + this.pe.id ).html( + this.getMenu() + + this.getBody() + ); + this.doMenuBindings(); + } + } + }, + show:function() { + // setup layout if not already done: + this.setup_layout(); + // display the interface if not already displayed: + $j( '#metaBox_' + this.pe.id ).fadeIn( "fast" ); + // start the autoscroll timer: + if ( this.autoscroll ) + this.setAutoScroll(); + }, + close:function() { + // the meta box: + $j( '#metaBox_' + this.pe.id ).fadeOut( 'fast' ); + // the icon link: + $j( '#metaButton_' + this.pe.id ).fadeIn( 'fast' ); + }, + getBody:function() { + return '
    ' + + '
    '; + }, + getTsSelect:function() { + var _this = this; + js_log( 'getTsSelect' ); + var selHTML = '
    '; + selHTML += '' + gM( 'mwe-select_transcript_set' ) + '
      '; + // debugger; + for ( var i in _this.availableTracks ) { // for in loop ok on object + var checked = ( _this.availableTracks[i].display ) ? 'checked' : ''; + selHTML += '
    • ' + + _this.availableTracks[i].getTitle() + '
    • '; + } + selHTML += '
    ' + + '
    '; + $j( '#metaBox_' + _this.pe.id ).append( selHTML ); + $j( '.mvTsSelect' ).click( function() { + _this.applyTsSelect(); + } ); + }, + applyTsSelect:function() { + var _this = this; + // update availableTracks + $j( '#mvtsel_' + this.pe.id + ' .mvTsSelect' ).each( function() { + var track_id = $j( this ).val(); + if ( this.checked ) { + // if not yet loaded now would be a good time + if ( ! _this.availableTracks[ track_id ].loaded ) { + _this.loadAndDisplay( track_id ); + } else { + _this.availableTracks[track_id].display = true; + // display the named class: + $j( '#mmbody_' + _this.pe.id + ' .track_' + track_id ).show(); + } + } else { + if ( _this.availableTracks[track_id].display ) { + _this.availableTracks[track_id].display = false; + // hide unchecked + $j( '#mmbody_' + _this.pe.id + ' .track_' + track_id ).hide(); + } + } + } ); + $j( '#mvtsel_' + _this.pe.id ).fadeOut( "fast" ).remove(); + }, + monitor:function() { + _this = this; + // grab the time from the video object + var cur_time = this.pe.currentTime ; + if ( cur_time != 0 ) { + var search_for_range = true; + // check if the current transcript is already where we want: + if ( $j( '#mmbody_' + this.pe.id + ' .tt_scroll_highlight' ).length != 0 ) { + var curhl = $j( '#mmbody_' + this.pe.id + ' .tt_scroll_highlight' ).get( 0 ); + if ( npt2seconds( $j( curhl ).attr( 'start' ) ) < cur_time && + npt2seconds( $j( curhl ).attr( 'end' ) ) > cur_time ) { + /*js_log('in range of current hl: ' + + npt2seconds($j(curhl).attr('start')) + ' to ' + npt2seconds($j(curhl).attr('end'))); + */ + search_for_range = false; + } else { + search_for_range = true; + // remove the highlight from all: + $j( '#mmbody_' + this.pe.id + ' .tt_scroll_highlight' ).removeClass( 'tt_scroll_highlight' ); + } + }; + /*js_log('search_for_range:'+search_for_range + ' for: '+ cur_time);*/ + if ( search_for_range ) { + // search for current time: add tt_scroll_highlight to clip + // optimize: + // should do binnary search not iterative + // avoid jquery function calls do native loops + $j( '#mmbody_' + this.pe.id + ' .mvtt' ).each( function() { + if ( npt2seconds( $j( this ).attr( 'start' ) ) < cur_time && + npt2seconds( $j( this ).attr( 'end' ) ) > cur_time ) { + _this.prevTimeScroll = cur_time; + $j( '#mmbody_' + _this.pe.id ).animate( { + scrollTop: $j( this ).get( 0 ).offsetTop + }, 'slow' ); + $j( this ).addClass( 'tt_scroll_highlight' ); + // js_log('should add class to: ' + $j(this).attr('id')); + // done with loop + return false; + } + } ); + } + } + }, + setAutoScroll:function( timer ) { + var _this = this; + this.autoscroll = ( typeof timer == 'undefined' ) ? this.autoscroll:timer; + if ( this.autoscroll ) { + // start the timer if its not already running + if ( !this.scrollTimerId ) { + var mvElm = $j('#' + _this.id ).get(0); + if( mvElm ) + this.scrollTimerId = setInterval( mvElm.textInterface.monitor(), 500 ); + } + // jump to the current position: + var cur_time = parseInt ( this.pe.currentTime ); + js_log( 'cur time: ' + cur_time ); + + _this = this; + var scroll_to_id = ''; + $j( '#mmbody_' + this.pe.id + ' .mvtt' ).each( function() { + if ( cur_time > npt2seconds( $j( this ).attr( 'start' ) ) ) { + _this.prevTimeScroll = cur_time; + if ( $j( this ).attr( 'id' ) ) + scroll_to_id = $j( this ).attr( 'id' ); + } + } ); + if ( scroll_to_id != '' ) + $j( '#mmbody_' + _this.pe.id ).animate( { scrollTop: $j( '#' + scroll_to_id ).position().top } , 'slow' ); + } else { + // stop the timer + clearInterval( this.scrollTimerId ); + this.scrollTimerId = 0; + } + }, + getMenu:function() { + var out = ''; + var _this = this; + // add in loading icon: + var as_checked = ( this.autoscroll ) ? 'checked':''; + out += '
    '; + out += $j.btnHtml( gM( 'mwe-select_transcript_set' ), 'tt-select', 'shuffle' ); + + if ( _this.editlink != '' ) + out += ' ' + $j.btnHtml( gM( 'mwe-improve_transcript' ), 'tt-improve' ); + + out += '' + gM( 'mwe-auto_scroll' ); + + out += ' ' + $j.btnHtml( gM( 'mwe-close' ), 'tt-close', 'circle-close' ); + + out += '
    '; + return out; + }, + doMenuBindings:function() { + var _this = this; + var mt = '#tt_mmenu_' + _this.pe.id; + $j( mt + ' .tt-close' ).unbind().btnBind().click( function() { + $j( '#' + _this.pe.id ).get( 0 ).closeTextInterface(); + return false; + } ); + $j( mt + ' .tt-select' ).unbind().btnBind().click( function() { + $j( '#' + _this.pe.id ).get( 0 ).textInterface.getTsSelect(); + return false; + } ); + $j( mt + ' .tt-scroll' ).click( function() { + _this.setAutoScroll( this.checked ); + } ); + $j( mt + ' .tt-improve' ).unbind().btnBind().click( function() { + document.location.href = _this.editlink; + } ); + } +} + +/* text format objects +* @@todo allow loading from external lib set +*/ +var timedTextObj = function( source ) { + // @@todo in the future we could support timed text in oggs if they can be accessed via javascript + // we should be able to do a HEAD request to see if we can read transcripts from the file. + switch( source.mime_type ) { + case 'text/cmml': + this.lib = 'CMML'; + break; + case 'text/srt': + case 'text/x-srt': + this.lib = 'SRT'; + break; + default: + js_log( source.mime_type + ' is not suported timed text fromat' ); + return ; + break; + } + // extend with the per-mime type lib: + eval( 'var tObj = timedText' + this.lib + ';' ); + for ( var i in tObj ) { + this[ i ] = tObj[i]; + } + return this.init( source ); +} + +// base timedText object +timedTextObj.prototype = { + loaded: false, + lib:null, + display: false, + textNodes:new Array(), + init: function( source ) { + // copy source properties + this.source = source; + this.id = source.id; + }, + getTitle:function() { + return this.source.title; + }, + getSRC:function() { + return this.source.src; + } +} + +// Specific Timed Text formats: + +timedTextCMML = { + load: function( range, callback ) { + var _this = this; + js_log( 'textCMML: loading track: ' + this.src ); + + // :: Load transcript range :: + var pcurl = mw.parseUri( _this.getSRC() ); + // check for urls without time keys: + if ( typeof pcurl.queryKey['t'] == 'undefined' ) { + // in which case just get the full time req: + do_request( this.getSRC(), function( data ) { + _this.doParse( data ); + _this.loaded = true; + callback(); + } ); + return ; + } + // temporal urls: + var req_time = pcurl.queryKey['t'].split( '/' ); + req_time[0] = npt2seconds( req_time[0] ); + req_time[1] = npt2seconds( req_time[1] ); + if ( req_time[1] - req_time[0] > _this.request_length ) { + // longer than 5 min will only issue a (request 5 min) + req_time[1] = req_time[0] + _this.request_length; + } + // set up request url: + url = pcurl.protocol + '://' + pcurl.authority + pcurl.path + '?'; + $j.each( pcurl.queryKey, function( key, val ) { + if ( key != 't' ) { + url += key + '=' + val + '&'; + } else { + url += 't=' + seconds2npt( req_time[0] ) + '/' + seconds2npt( req_time[1] ) + '&'; + } + } ); + do_request( url, function( data ) { + js_log( "load track clip count:" + data.getElementsByTagName( 'clip' ).length ); + _this.doParse( data ); + _this.loaded = true; + callback(); + } ); + }, + doParse: function( data ) { + var _this = this; + $j.each( data.getElementsByTagName( 'clip' ), function( inx, clip ) { + // js_log(' on clip ' + clip.id); + var text_clip = { + start: $j( clip ).attr( 'start' ).replace( 'npt:', '' ), + end: $j( clip ).attr( 'end' ).replace( 'npt:', '' ), + type_id: _this.id, + id: $j( clip ).attr( 'id' ) + } + $j.each( clip.getElementsByTagName( 'body' ), function( binx, bn ) { + if ( bn.textContent ) { + text_clip.body = bn.textContent; + } else if ( bn.text ) { + text_clip.body = bn.text; + } + } ); + _this.textNodes.push( text_clip ); + } ); + } +} +timedTextSRT = { + load: function( range, callback ) { + var _this = this; + js_log( 'textSRT: loading : ' + _this.getSRC() ); + if ( _this.getSRC() ) { + do_request( _this.getSRC() , function( data ) { + _this.doParse( data ); + _this.loaded = true; + callback(); + } ); + } else if ( _this.source.apisrc ) { + do_api_req( { + 'url' : _this.source.apisrc, + 'data': { + 'titles': _this.source.titleKey, + 'prop':'revisions', + 'rvprop':'content' + } + }, function( data ) { + if ( data && data.query && data.query.pages ) { + for ( var i in data.query.pages ) { + var page = data.query.pages[i]; + if ( page.revisions ) { + for ( var j in page.revisions ) { + if ( page.revisions[j]['*'] ) { + _this.doParse( page.revisions[j]['*'] ); + _this.loaded = true; + callback(); + } + } + } + } + } + } ); + } + }, + doParse:function( data ) { + // split up the transcript chunks: + // strip any \r's + var tc = data.split( /[\r]?\n[\r]?\n/ ); + // pushing can take time + for ( var s = 0; s < tc.length ; s++ ) { + var st = tc[s].split( '\n' ); + if ( st.length >= 2 ) { + var n = st[0]; + var i = st[1].split( ' --> ' )[0].replace( /^\s+|\s+$/g, "" ); + var o = st[1].split( ' --> ' )[1].replace( /^\s+|\s+$/g, "" ); + var t = st[2]; + if ( st.length > 2 ) { + for ( j = 3; j < st.length; j++ ) + t += '\n' + st[j]; + } + var text_clip = { + "start": i, + "end": o, + "type_id": this.id, + "id": this.id + '_' + n, + "body": t + } + this.textNodes.push( text_clip ); + } + } + } +}; diff --git a/js2/mwEmbed/libTimedText/mvTimeTextEdit.js b/js2/mwEmbed/libTimedText/mvTimeTextEdit.js new file mode 100644 index 0000000000..8916bfe1af --- /dev/null +++ b/js2/mwEmbed/libTimedText/mvTimeTextEdit.js @@ -0,0 +1,162 @@ +/* + * JS2-style mvTimedTextEdit.js + */ + +// Setup configuration vars (if not set already) +if ( !mwAddMediaConfig ) + var mwAddMediaConfig = { }; + +var mvTimeTextEdit = { }; + +loadGM( { + "mwe-upload-subs-file" : "Upload subtitle", + "mwe-add-subs-file-title" : "Select subtitle to upload", + "mwe-error-only-srt" : "You can only upload srt files.", + "mwe-watch-video" : "Watch video", + "mwe-select-other-language" : "Select another language", + "mwe-saving" : "saving..." +} ) + + +js2AddOnloadHook( function() { + function getSubtitle( f ) { + var name = f.files[0].name; + var srtData = f.files[0].getAsBinary(); + srtData = srtData.replace( '\r\n', '\n' ); + return srtData; + } + function getVideoTitle() { + var videoTitle = wgPageName.split( '.' ); + videoTitle.pop(); + videoTitle.pop(); + videoTitle = videoTitle.join( '.' ).replace( 'TimedText:', 'File:' ); + return videoTitle; + } + function uploadSubtitles() { + do_api_req( { + 'data': { + 'meta' : 'siteinfo', + 'siprop' : 'languages' + } + }, function( langDataRaw ) { + var apprefix = wgTitle.split( '.' ); + apprefix.pop(); + apprefix.pop(); + apprefix = apprefix.join( '.' ); + do_api_req( { + 'data': { + 'list' : 'allpages', + 'apprefix' : apprefix + } + }, function( subData ) { + var availableSubtitles = { }; + for ( var i in subData.query.allpages ) { + var subPage = subData.query.allpages[i]; + var langKey = subPage.title.split( '.' ); + var extension = langKey.pop(); + langKey = langKey.pop(); + availableSubtitles[langKey] = subPage.title; + } + var langData = { }; + var languageSelect = ''; + var cBtn = { }; + cBtn[ gM( 'mwe-cancel' ) ] = function() { + $j( this ).dialog( 'close' ); + } + cBtn[ gM( 'mwe-ok' ) ] = function() { + // get language from form + langKey = $j( '#timed_text_language' ).val(); + var title = wgPageName.split( '.' ); + title.pop(); + title.pop(); + title = title.join( '.' ) + '.' + langKey + '.srt'; + + var file = $j( '#timed_text_file_upload' ); + if ( !file[0].files[0] ) { + // no file to upload just jump to the lang key: + document.location.href = wgArticlePath.replace( '/$1', '?title=' + title + '&action=edit' ); + return ; + } + var langKey = file[0].files[0].name.split( '.' ); + var extension = langKey.pop(); + langKey = langKey.pop(); + var mimeTypes = { + 'srt': 'text/x-srt', + 'cmml': 'text/cmml' + } + if ( !mimeTypes[ extension ] ) { + js_log( 'Error: unknown extension:' + extension ); + } + + + if ( extension == "srt" ) { + var srt = getSubtitle( file[0] ); + $j( this ).text( gM( 'mwe-saving' ) ); + $j( '.ui-dialog-buttonpane' ).remove(); + + var editToken = $j( 'input[name=wpEditToken]' ).val(); + + do_api_req( { + 'data': { + 'action' : 'edit', + 'title' : title, + 'text' : srt, + 'token': editToken + } + }, function( dialog ) { + return function( result ) { + document.location.href = wgArticlePath.replace( '/$1', '?title=' + title + '&action=edit' ); + $j( dialog ).dialog( 'close' ); + } }( this ) + ); + } else { + $j( this ).html( gM( "mwe-error-only-srt" ) ); + } + } + $j.addDialog( gM( "mwe-add-subs-file-title" ), + '
    ' + languageSelect, + cBtn ); + $j( '#timed_text_file_upload' ).change( function( ev ) { + if ( this.files[0] ) { + var langKey = this.files[0].name.split( '.' ); + var extension = langKey.pop(); + langKey = langKey.pop(); + $j( '#timed_text_language' ).val( langKey ); + } + } ); + } ); + } ); + } + var tselect = ( $j( '#wikiEditor-ui-top' ).length != 0 ) ? '#wikiEditor-ui-top':'#toolbar'; + $j( tselect ).hide(); + var ttoolbar = $j( '
    ' ); + $j( tselect ).after( ttoolbar ); + + var button = $j( '