diff -r 000000000000 -r d970ebf37754 wp/wp-admin/js/customize-controls.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/wp/wp-admin/js/customize-controls.js Wed Nov 06 03:21:17 2013 +0000
@@ -0,0 +1,1009 @@
+(function( exports, $ ){
+ var api = wp.customize;
+
+ /*
+ * @param options
+ * - previewer - The Previewer instance to sync with.
+ * - transport - The transport to use for previewing. Supports 'refresh' and 'postMessage'.
+ */
+ api.Setting = api.Value.extend({
+ initialize: function( id, value, options ) {
+ var element;
+
+ api.Value.prototype.initialize.call( this, value, options );
+
+ this.id = id;
+ this.transport = this.transport || 'refresh';
+
+ this.bind( this.preview );
+ },
+ preview: function() {
+ switch ( this.transport ) {
+ case 'refresh':
+ return this.previewer.refresh();
+ case 'postMessage':
+ return this.previewer.send( 'setting', [ this.id, this() ] );
+ }
+ }
+ });
+
+ api.Control = api.Class.extend({
+ initialize: function( id, options ) {
+ var control = this,
+ nodes, radios, settings;
+
+ this.params = {};
+ $.extend( this, options || {} );
+
+ this.id = id;
+ this.selector = '#customize-control-' + id.replace( /\]/g, '' ).replace( /\[/g, '-' );
+ this.container = $( this.selector );
+
+ settings = $.map( this.params.settings, function( value ) {
+ return value;
+ });
+
+ api.apply( api, settings.concat( function() {
+ var key;
+
+ control.settings = {};
+ for ( key in control.params.settings ) {
+ control.settings[ key ] = api( control.params.settings[ key ] );
+ }
+
+ control.setting = control.settings['default'] || null;
+ control.ready();
+ }) );
+
+ control.elements = [];
+
+ nodes = this.container.find('[data-customize-setting-link]');
+ radios = {};
+
+ nodes.each( function() {
+ var node = $(this),
+ name;
+
+ if ( node.is(':radio') ) {
+ name = node.prop('name');
+ if ( radios[ name ] )
+ return;
+
+ radios[ name ] = true;
+ node = nodes.filter( '[name="' + name + '"]' );
+ }
+
+ api( node.data('customizeSettingLink'), function( setting ) {
+ var element = new api.Element( node );
+ control.elements.push( element );
+ element.sync( setting );
+ element.set( setting() );
+ });
+ });
+ },
+
+ ready: function() {},
+
+ dropdownInit: function() {
+ var control = this,
+ statuses = this.container.find('.dropdown-status'),
+ params = this.params,
+ update = function( to ) {
+ if ( typeof to === 'string' && params.statuses && params.statuses[ to ] )
+ statuses.html( params.statuses[ to ] ).show();
+ else
+ statuses.hide();
+ };
+
+ var toggleFreeze = false;
+
+ // Support the .dropdown class to open/close complex elements
+ this.container.on( 'click keydown', '.dropdown', function( event ) {
+ if ( event.type === 'keydown' && 13 !== event.which ) // enter
+ return;
+
+ event.preventDefault();
+
+ if (!toggleFreeze)
+ control.container.toggleClass('open');
+
+ if ( control.container.hasClass('open') )
+ control.container.parent().parent().find('li.library-selected').focus();
+
+ // Don't want to fire focus and click at same time
+ toggleFreeze = true;
+ setTimeout(function () {
+ toggleFreeze = false;
+ }, 400);
+ });
+
+ this.setting.bind( update );
+ update( this.setting() );
+ }
+ });
+
+ api.ColorControl = api.Control.extend({
+ ready: function() {
+ var control = this,
+ picker = this.container.find('.color-picker-hex');
+
+ picker.val( control.setting() ).wpColorPicker({
+ change: function( event, options ) {
+ control.setting.set( picker.wpColorPicker('color') );
+ },
+ clear: function() {
+ control.setting.set( false );
+ }
+ });
+ }
+ });
+
+ api.UploadControl = api.Control.extend({
+ ready: function() {
+ var control = this;
+
+ this.params.removed = this.params.removed || '';
+
+ this.success = $.proxy( this.success, this );
+
+ this.uploader = $.extend({
+ container: this.container,
+ browser: this.container.find('.upload'),
+ dropzone: this.container.find('.upload-dropzone'),
+ success: this.success,
+ plupload: {},
+ params: {}
+ }, this.uploader || {} );
+
+ if ( control.params.extensions ) {
+ control.uploader.plupload.filters = [{
+ title: api.l10n.allowedFiles,
+ extensions: control.params.extensions
+ }];
+ }
+
+ if ( control.params.context )
+ control.uploader.params['post_data[context]'] = this.params.context;
+
+ if ( api.settings.theme.stylesheet )
+ control.uploader.params['post_data[theme]'] = api.settings.theme.stylesheet;
+
+ this.uploader = new wp.Uploader( this.uploader );
+
+ this.remover = this.container.find('.remove');
+ this.remover.on( 'click keydown', function( event ) {
+ if ( event.type === 'keydown' && 13 !== event.which ) // enter
+ return;
+
+ control.setting.set( control.params.removed );
+ event.preventDefault();
+ });
+
+ this.removerVisibility = $.proxy( this.removerVisibility, this );
+ this.setting.bind( this.removerVisibility );
+ this.removerVisibility( this.setting.get() );
+ },
+ success: function( attachment ) {
+ this.setting.set( attachment.get('url') );
+ },
+ removerVisibility: function( to ) {
+ this.remover.toggle( to != this.params.removed );
+ }
+ });
+
+ api.ImageControl = api.UploadControl.extend({
+ ready: function() {
+ var control = this,
+ panels;
+
+ this.uploader = {
+ init: function( up ) {
+ var fallback, button;
+
+ if ( this.supports.dragdrop )
+ return;
+
+ // Maintain references while wrapping the fallback button.
+ fallback = control.container.find( '.upload-fallback' );
+ button = fallback.children().detach();
+
+ this.browser.detach().empty().append( button );
+ fallback.append( this.browser ).show();
+ }
+ };
+
+ api.UploadControl.prototype.ready.call( this );
+
+ this.thumbnail = this.container.find('.preview-thumbnail img');
+ this.thumbnailSrc = $.proxy( this.thumbnailSrc, this );
+ this.setting.bind( this.thumbnailSrc );
+
+ this.library = this.container.find('.library');
+
+ // Generate tab objects
+ this.tabs = {};
+ panels = this.library.find('.library-content');
+
+ this.library.children('ul').children('li').each( function() {
+ var link = $(this),
+ id = link.data('customizeTab'),
+ panel = panels.filter('[data-customize-tab="' + id + '"]');
+
+ control.tabs[ id ] = {
+ both: link.add( panel ),
+ link: link,
+ panel: panel
+ };
+ });
+
+ // Bind tab switch events
+ this.library.children('ul').on( 'click keydown', 'li', function( event ) {
+ if ( event.type === 'keydown' && 13 !== event.which ) // enter
+ return;
+
+ var id = $(this).data('customizeTab'),
+ tab = control.tabs[ id ];
+
+ event.preventDefault();
+
+ if ( tab.link.hasClass('library-selected') )
+ return;
+
+ control.selected.both.removeClass('library-selected');
+ control.selected = tab;
+ control.selected.both.addClass('library-selected');
+ });
+
+ // Bind events to switch image urls.
+ this.library.on( 'click keydown', 'a', function( event ) {
+ if ( event.type === 'keydown' && 13 !== event.which ) // enter
+ return;
+
+ var value = $(this).data('customizeImageValue');
+
+ if ( value ) {
+ control.setting.set( value );
+ event.preventDefault();
+ }
+ });
+
+ if ( this.tabs.uploaded ) {
+ this.tabs.uploaded.target = this.library.find('.uploaded-target');
+ if ( ! this.tabs.uploaded.panel.find('.thumbnail').length )
+ this.tabs.uploaded.both.addClass('hidden');
+ }
+
+ // Select a tab
+ panels.each( function() {
+ var tab = control.tabs[ $(this).data('customizeTab') ];
+
+ // Select the first visible tab.
+ if ( ! tab.link.hasClass('hidden') ) {
+ control.selected = tab;
+ tab.both.addClass('library-selected');
+ return false;
+ }
+ });
+
+ this.dropdownInit();
+ },
+ success: function( attachment ) {
+ api.UploadControl.prototype.success.call( this, attachment );
+
+ // Add the uploaded image to the uploaded tab.
+ if ( this.tabs.uploaded && this.tabs.uploaded.target.length ) {
+ this.tabs.uploaded.both.removeClass('hidden');
+
+ // @todo: Do NOT store this on the attachment model. That is bad.
+ attachment.element = $( '' )
+ .data( 'customizeImageValue', attachment.get('url') )
+ .append( '
' )
+ .appendTo( this.tabs.uploaded.target );
+ }
+ },
+ thumbnailSrc: function( to ) {
+ if ( /^(https?:)?\/\//.test( to ) )
+ this.thumbnail.prop( 'src', to ).show();
+ else
+ this.thumbnail.hide();
+ }
+ });
+
+ // Change objects contained within the main customize object to Settings.
+ api.defaultConstructor = api.Setting;
+
+ // Create the collection of Control objects.
+ api.control = new api.Values({ defaultConstructor: api.Control });
+
+ api.PreviewFrame = api.Messenger.extend({
+ sensitivity: 2000,
+
+ initialize: function( params, options ) {
+ var deferred = $.Deferred(),
+ self = this;
+
+ // This is the promise object.
+ deferred.promise( this );
+
+ this.container = params.container;
+ this.signature = params.signature;
+
+ $.extend( params, { channel: api.PreviewFrame.uuid() });
+
+ api.Messenger.prototype.initialize.call( this, params, options );
+
+ this.add( 'previewUrl', params.previewUrl );
+
+ this.query = $.extend( params.query || {}, { customize_messenger_channel: this.channel() });
+
+ this.run( deferred );
+ },
+
+ run: function( deferred ) {
+ var self = this,
+ loaded = false,
+ ready = false;
+
+ if ( this._ready )
+ this.unbind( 'ready', this._ready );
+
+ this._ready = function() {
+ ready = true;
+
+ if ( loaded )
+ deferred.resolveWith( self );
+ };
+
+ this.bind( 'ready', this._ready );
+
+ this.request = $.ajax( this.previewUrl(), {
+ type: 'POST',
+ data: this.query,
+ xhrFields: {
+ withCredentials: true
+ }
+ } );
+
+ this.request.fail( function() {
+ deferred.rejectWith( self, [ 'request failure' ] );
+ });
+
+ this.request.done( function( response ) {
+ var location = self.request.getResponseHeader('Location'),
+ signature = self.signature,
+ index;
+
+ // Check if the location response header differs from the current URL.
+ // If so, the request was redirected; try loading the requested page.
+ if ( location && location != self.previewUrl() ) {
+ deferred.rejectWith( self, [ 'redirect', location ] );
+ return;
+ }
+
+ // Check if the user is not logged in.
+ if ( '0' === response ) {
+ self.login( deferred );
+ return;
+ }
+
+ // Check for cheaters.
+ if ( '-1' === response ) {
+ deferred.rejectWith( self, [ 'cheatin' ] );
+ return;
+ }
+
+ // Check for a signature in the request.
+ index = response.lastIndexOf( signature );
+ if ( -1 === index || index < response.lastIndexOf('