web/wp-includes/js/customize-base.js
changeset 204 09a1c134465b
parent 194 32102edaa81b
equal deleted inserted replaced
203:f507feede89a 204:09a1c134465b
     1 if(typeof wp==="undefined"){var wp={}}(function(a,d){var b,g,c,f,e=Array.prototype.slice;g=function(h,i){var j=f(this,h,i);j.extend=this.extend;return j};c=function(){};f=function(i,h,j){var k;if(h&&h.hasOwnProperty("constructor")){k=h.constructor}else{k=function(){var l=i.apply(this,arguments);return l}}d.extend(k,i);c.prototype=i.prototype;k.prototype=new c();if(h){d.extend(k.prototype,h)}if(j){d.extend(k,j)}k.prototype.constructor=k;k.__super__=i.prototype;return k};b={};b.Class=function(l,k,i){var j,h=arguments;if(l&&k&&b.Class.applicator===l){h=k;d.extend(this,i||{})}j=this;if(this.instance){j=function(){return j.instance.apply(j,arguments)};d.extend(j,this)}j.initialize.apply(j,h);return j};b.Class.applicator={};b.Class.prototype.initialize=function(){};b.Class.prototype.extended=function(h){var i=this;while(typeof i.constructor!=="undefined"){if(i.constructor===h){return true}if(typeof i.constructor.__super__==="undefined"){return false}i=i.constructor.__super__}return false};b.Class.extend=g;b.Events={trigger:function(h){if(this.topics&&this.topics[h]){this.topics[h].fireWith(this,e.call(arguments,1))}return this},bind:function(i,h){this.topics=this.topics||{};this.topics[i]=this.topics[i]||d.Callbacks();this.topics[i].add.apply(this.topics[i],e.call(arguments,1));return this},unbind:function(i,h){if(this.topics&&this.topics[i]){this.topics[i].remove.apply(this.topics[i],e.call(arguments,1))}return this}};b.Value=b.Class.extend({initialize:function(i,h){this._value=i;this.callbacks=d.Callbacks();d.extend(this,h||{});this.set=d.proxy(this.set,this)},instance:function(){return arguments.length?this.set.apply(this,arguments):this.get()},get:function(){return this._value},set:function(i){var h=this._value;i=this._setter.apply(this,arguments);i=this.validate(i);if(null===i||this._value===i){return this}this._value=i;this.callbacks.fireWith(this,[i,h]);return this},_setter:function(h){return h},setter:function(i){var h=this.get();this._setter=i;this._value=null;this.set(h);return this},resetSetter:function(){this._setter=this.constructor.prototype._setter;this.set(this.get());return this},validate:function(h){return h},bind:function(h){this.callbacks.add.apply(this.callbacks,arguments);return this},unbind:function(h){this.callbacks.remove.apply(this.callbacks,arguments);return this},link:function(){var h=this.set;d.each(arguments,function(){this.bind(h)});return this},unlink:function(){var h=this.set;d.each(arguments,function(){this.unbind(h)});return this},sync:function(){var h=this;d.each(arguments,function(){h.link(this);this.link(h)});return this},unsync:function(){var h=this;d.each(arguments,function(){h.unlink(this);this.unlink(h)});return this}});b.Values=b.Class.extend({defaultConstructor:b.Value,initialize:function(h){d.extend(this,h||{});this._value={};this._deferreds={}},instance:function(h){if(arguments.length===1){return this.value(h)}return this.when.apply(this,arguments)},value:function(h){return this._value[h]},has:function(h){return typeof this._value[h]!=="undefined"},add:function(i,h){if(this.has(i)){return this.value(i)}this._value[i]=h;h.parent=this;if(h.extended(b.Value)){h.bind(this._change)}this.trigger("add",h);if(this._deferreds[i]){this._deferreds[i].resolve()}return this._value[i]},create:function(h){return this.add(h,new this.defaultConstructor(b.Class.applicator,e.call(arguments,1)))},each:function(i,h){h=typeof h==="undefined"?this:h;d.each(this._value,function(j,k){i.call(h,k,j)})},remove:function(i){var h;if(this.has(i)){h=this.value(i);this.trigger("remove",h);if(h.extended(b.Value)){h.unbind(this._change)}delete h.parent}delete this._value[i];delete this._deferreds[i]},when:function(){var i=this,j=e.call(arguments),h=d.Deferred();if(d.isFunction(j[j.length-1])){h.done(j.pop())}d.when.apply(d,d.map(j,function(k){if(i.has(k)){return}return i._deferreds[k]=i._deferreds[k]||d.Deferred()})).done(function(){var k=d.map(j,function(l){return i(l)});if(k.length!==j.length){i.when.apply(i,j).done(function(){h.resolveWith(i,k)});return}h.resolveWith(i,k)});return h.promise()},_change:function(){this.parent.trigger("change",this)}});d.extend(b.Values.prototype,b.Events);b.ensure=function(h){return typeof h=="string"?d(h):h};b.Element=b.Value.extend({initialize:function(j,i){var h=this,m=b.Element.synchronizer.html,l,n,k;this.element=b.ensure(j);this.events="";if(this.element.is("input, select, textarea")){this.events+="change";m=b.Element.synchronizer.val;if(this.element.is("input")){l=this.element.prop("type");if(b.Element.synchronizer[l]){m=b.Element.synchronizer[l]}if("text"===l||"password"===l){this.events+=" keyup"}}else{if(this.element.is("textarea")){this.events+=" keyup"}}}b.Value.prototype.initialize.call(this,null,d.extend(i||{},m));this._value=this.get();n=this.update;k=this.refresh;this.update=function(o){if(o!==k.call(h)){n.apply(this,arguments)}};this.refresh=function(){h.set(k.call(h))};this.bind(this.update);this.element.bind(this.events,this.refresh)},find:function(h){return d(h,this.element)},refresh:function(){},update:function(){}});b.Element.synchronizer={};d.each(["html","val"],function(h,j){b.Element.synchronizer[j]={update:function(i){this.element[j](i)},refresh:function(){return this.element[j]()}}});b.Element.synchronizer.checkbox={update:function(h){this.element.prop("checked",h)},refresh:function(){return this.element.prop("checked")}};b.Element.synchronizer.radio={update:function(h){this.element.filter(function(){return this.value===h}).prop("checked",true)},refresh:function(){return this.element.filter(":checked").val()}};d.support.postMessage=!!window.postMessage;b.Messenger=b.Class.extend({add:function(j,i,h){return this[j]=new b.Value(i,h)},initialize:function(j,h){var i=window.parent==window?null:window.parent;d.extend(this,h||{});this.add("channel",j.channel);this.add("url",j.url||"");this.add("targetWindow",j.targetWindow||i);this.add("origin",this.url()).link(this.url).setter(function(k){return k.replace(/([^:]+:\/\/[^\/]+).*/,"$1")});this.receive=d.proxy(this.receive,this);this.receive.guid=d.guid++;d(window).on("message",this.receive)},destroy:function(){d(window).off("message",this.receive)},receive:function(i){var h;i=i.originalEvent;if(!this.targetWindow()){return}if(this.origin()&&i.origin!==this.origin()){return}h=JSON.parse(i.data);if(!h||!h.id||typeof h.data==="undefined"){return}if((h.channel||this.channel())&&this.channel()!==h.channel){return}this.trigger(h.id,h.data)},send:function(j,i){var h;i=typeof i==="undefined"?null:i;if(!this.url()||!this.targetWindow()){return}h={id:j,data:i};if(this.channel()){h.channel=this.channel()}this.targetWindow().postMessage(JSON.stringify(h),this.origin())}});d.extend(b.Messenger.prototype,b.Events);b=d.extend(new b.Values(),b);b.get=function(){var h={};this.each(function(j,i){h[i]=j.get()});return h};a.customize=b})(wp,jQuery);
     1 window.wp = window.wp || {};
       
     2 
       
     3 (function( exports, $ ){
       
     4 	var api, extend, ctor, inherits,
       
     5 		slice = Array.prototype.slice;
       
     6 
       
     7 	/* =====================================================================
       
     8 	 * Micro-inheritance - thank you, backbone.js.
       
     9 	 * ===================================================================== */
       
    10 
       
    11 	extend = function( protoProps, classProps ) {
       
    12 		var child = inherits( this, protoProps, classProps );
       
    13 		child.extend = this.extend;
       
    14 		return child;
       
    15 	};
       
    16 
       
    17 	// Shared empty constructor function to aid in prototype-chain creation.
       
    18 	ctor = function() {};
       
    19 
       
    20 	// Helper function to correctly set up the prototype chain, for subclasses.
       
    21 	// Similar to `goog.inherits`, but uses a hash of prototype properties and
       
    22 	// class properties to be extended.
       
    23 	inherits = function( parent, protoProps, staticProps ) {
       
    24 		var child;
       
    25 
       
    26 		// The constructor function for the new subclass is either defined by you
       
    27 		// (the "constructor" property in your `extend` definition), or defaulted
       
    28 		// by us to simply call `super()`.
       
    29 		if ( protoProps && protoProps.hasOwnProperty( 'constructor' ) ) {
       
    30 			child = protoProps.constructor;
       
    31 		} else {
       
    32 			child = function() {
       
    33 				// Storing the result `super()` before returning the value
       
    34 				// prevents a bug in Opera where, if the constructor returns
       
    35 				// a function, Opera will reject the return value in favor of
       
    36 				// the original object. This causes all sorts of trouble.
       
    37 				var result = parent.apply( this, arguments );
       
    38 				return result;
       
    39 			};
       
    40 		}
       
    41 
       
    42 		// Inherit class (static) properties from parent.
       
    43 		$.extend( child, parent );
       
    44 
       
    45 		// Set the prototype chain to inherit from `parent`, without calling
       
    46 		// `parent`'s constructor function.
       
    47 		ctor.prototype  = parent.prototype;
       
    48 		child.prototype = new ctor();
       
    49 
       
    50 		// Add prototype properties (instance properties) to the subclass,
       
    51 		// if supplied.
       
    52 		if ( protoProps )
       
    53 			$.extend( child.prototype, protoProps );
       
    54 
       
    55 		// Add static properties to the constructor function, if supplied.
       
    56 		if ( staticProps )
       
    57 			$.extend( child, staticProps );
       
    58 
       
    59 		// Correctly set child's `prototype.constructor`.
       
    60 		child.prototype.constructor = child;
       
    61 
       
    62 		// Set a convenience property in case the parent's prototype is needed later.
       
    63 		child.__super__ = parent.prototype;
       
    64 
       
    65 		return child;
       
    66 	};
       
    67 
       
    68 	api = {};
       
    69 
       
    70 	/* =====================================================================
       
    71 	 * Base class.
       
    72 	 * ===================================================================== */
       
    73 
       
    74 	api.Class = function( applicator, argsArray, options ) {
       
    75 		var magic, args = arguments;
       
    76 
       
    77 		if ( applicator && argsArray && api.Class.applicator === applicator ) {
       
    78 			args = argsArray;
       
    79 			$.extend( this, options || {} );
       
    80 		}
       
    81 
       
    82 		magic = this;
       
    83 		if ( this.instance ) {
       
    84 			magic = function() {
       
    85 				return magic.instance.apply( magic, arguments );
       
    86 			};
       
    87 
       
    88 			$.extend( magic, this );
       
    89 		}
       
    90 
       
    91 		magic.initialize.apply( magic, args );
       
    92 		return magic;
       
    93 	};
       
    94 
       
    95 	api.Class.applicator = {};
       
    96 
       
    97 	api.Class.prototype.initialize = function() {};
       
    98 
       
    99 	/*
       
   100 	 * Checks whether a given instance extended a constructor.
       
   101 	 *
       
   102 	 * The magic surrounding the instance parameter causes the instanceof
       
   103 	 * keyword to return inaccurate results; it defaults to the function's
       
   104 	 * prototype instead of the constructor chain. Hence this function.
       
   105 	 */
       
   106 	api.Class.prototype.extended = function( constructor ) {
       
   107 		var proto = this;
       
   108 
       
   109 		while ( typeof proto.constructor !== 'undefined' ) {
       
   110 			if ( proto.constructor === constructor )
       
   111 				return true;
       
   112 			if ( typeof proto.constructor.__super__ === 'undefined' )
       
   113 				return false;
       
   114 			proto = proto.constructor.__super__;
       
   115 		}
       
   116 		return false;
       
   117 	};
       
   118 
       
   119 	api.Class.extend = extend;
       
   120 
       
   121 	/* =====================================================================
       
   122 	 * Events mixin.
       
   123 	 * ===================================================================== */
       
   124 
       
   125 	api.Events = {
       
   126 		trigger: function( id ) {
       
   127 			if ( this.topics && this.topics[ id ] )
       
   128 				this.topics[ id ].fireWith( this, slice.call( arguments, 1 ) );
       
   129 			return this;
       
   130 		},
       
   131 
       
   132 		bind: function( id, callback ) {
       
   133 			this.topics = this.topics || {};
       
   134 			this.topics[ id ] = this.topics[ id ] || $.Callbacks();
       
   135 			this.topics[ id ].add.apply( this.topics[ id ], slice.call( arguments, 1 ) );
       
   136 			return this;
       
   137 		},
       
   138 
       
   139 		unbind: function( id, callback ) {
       
   140 			if ( this.topics && this.topics[ id ] )
       
   141 				this.topics[ id ].remove.apply( this.topics[ id ], slice.call( arguments, 1 ) );
       
   142 			return this;
       
   143 		}
       
   144 	};
       
   145 
       
   146 	/* =====================================================================
       
   147 	 * Observable values that support two-way binding.
       
   148 	 * ===================================================================== */
       
   149 
       
   150 	api.Value = api.Class.extend({
       
   151 		initialize: function( initial, options ) {
       
   152 			this._value = initial; // @todo: potentially change this to a this.set() call.
       
   153 			this.callbacks = $.Callbacks();
       
   154 
       
   155 			$.extend( this, options || {} );
       
   156 
       
   157 			this.set = $.proxy( this.set, this );
       
   158 		},
       
   159 
       
   160 		/*
       
   161 		 * Magic. Returns a function that will become the instance.
       
   162 		 * Set to null to prevent the instance from extending a function.
       
   163 		 */
       
   164 		instance: function() {
       
   165 			return arguments.length ? this.set.apply( this, arguments ) : this.get();
       
   166 		},
       
   167 
       
   168 		get: function() {
       
   169 			return this._value;
       
   170 		},
       
   171 
       
   172 		set: function( to ) {
       
   173 			var from = this._value;
       
   174 
       
   175 			to = this._setter.apply( this, arguments );
       
   176 			to = this.validate( to );
       
   177 
       
   178 			// Bail if the sanitized value is null or unchanged.
       
   179 			if ( null === to || this._value === to )
       
   180 				return this;
       
   181 
       
   182 			this._value = to;
       
   183 
       
   184 			this.callbacks.fireWith( this, [ to, from ] );
       
   185 
       
   186 			return this;
       
   187 		},
       
   188 
       
   189 		_setter: function( to ) {
       
   190 			return to;
       
   191 		},
       
   192 
       
   193 		setter: function( callback ) {
       
   194 			var from = this.get();
       
   195 			this._setter = callback;
       
   196 			// Temporarily clear value so setter can decide if it's valid.
       
   197 			this._value = null;
       
   198 			this.set( from );
       
   199 			return this;
       
   200 		},
       
   201 
       
   202 		resetSetter: function() {
       
   203 			this._setter = this.constructor.prototype._setter;
       
   204 			this.set( this.get() );
       
   205 			return this;
       
   206 		},
       
   207 
       
   208 		validate: function( value ) {
       
   209 			return value;
       
   210 		},
       
   211 
       
   212 		bind: function( callback ) {
       
   213 			this.callbacks.add.apply( this.callbacks, arguments );
       
   214 			return this;
       
   215 		},
       
   216 
       
   217 		unbind: function( callback ) {
       
   218 			this.callbacks.remove.apply( this.callbacks, arguments );
       
   219 			return this;
       
   220 		},
       
   221 
       
   222 		link: function() { // values*
       
   223 			var set = this.set;
       
   224 			$.each( arguments, function() {
       
   225 				this.bind( set );
       
   226 			});
       
   227 			return this;
       
   228 		},
       
   229 
       
   230 		unlink: function() { // values*
       
   231 			var set = this.set;
       
   232 			$.each( arguments, function() {
       
   233 				this.unbind( set );
       
   234 			});
       
   235 			return this;
       
   236 		},
       
   237 
       
   238 		sync: function() { // values*
       
   239 			var that = this;
       
   240 			$.each( arguments, function() {
       
   241 				that.link( this );
       
   242 				this.link( that );
       
   243 			});
       
   244 			return this;
       
   245 		},
       
   246 
       
   247 		unsync: function() { // values*
       
   248 			var that = this;
       
   249 			$.each( arguments, function() {
       
   250 				that.unlink( this );
       
   251 				this.unlink( that );
       
   252 			});
       
   253 			return this;
       
   254 		}
       
   255 	});
       
   256 
       
   257 	/* =====================================================================
       
   258 	 * A collection of observable values.
       
   259 	 * ===================================================================== */
       
   260 
       
   261 	api.Values = api.Class.extend({
       
   262 		defaultConstructor: api.Value,
       
   263 
       
   264 		initialize: function( options ) {
       
   265 			$.extend( this, options || {} );
       
   266 
       
   267 			this._value = {};
       
   268 			this._deferreds = {};
       
   269 		},
       
   270 
       
   271 		instance: function( id ) {
       
   272 			if ( arguments.length === 1 )
       
   273 				return this.value( id );
       
   274 
       
   275 			return this.when.apply( this, arguments );
       
   276 		},
       
   277 
       
   278 		value: function( id ) {
       
   279 			return this._value[ id ];
       
   280 		},
       
   281 
       
   282 		has: function( id ) {
       
   283 			return typeof this._value[ id ] !== 'undefined';
       
   284 		},
       
   285 
       
   286 		add: function( id, value ) {
       
   287 			if ( this.has( id ) )
       
   288 				return this.value( id );
       
   289 
       
   290 			this._value[ id ] = value;
       
   291 			value.parent = this;
       
   292 			if ( value.extended( api.Value ) )
       
   293 				value.bind( this._change );
       
   294 
       
   295 			this.trigger( 'add', value );
       
   296 
       
   297 			if ( this._deferreds[ id ] )
       
   298 				this._deferreds[ id ].resolve();
       
   299 
       
   300 			return this._value[ id ];
       
   301 		},
       
   302 
       
   303 		create: function( id ) {
       
   304 			return this.add( id, new this.defaultConstructor( api.Class.applicator, slice.call( arguments, 1 ) ) );
       
   305 		},
       
   306 
       
   307 		each: function( callback, context ) {
       
   308 			context = typeof context === 'undefined' ? this : context;
       
   309 
       
   310 			$.each( this._value, function( key, obj ) {
       
   311 				callback.call( context, obj, key );
       
   312 			});
       
   313 		},
       
   314 
       
   315 		remove: function( id ) {
       
   316 			var value;
       
   317 
       
   318 			if ( this.has( id ) ) {
       
   319 				value = this.value( id );
       
   320 				this.trigger( 'remove', value );
       
   321 				if ( value.extended( api.Value ) )
       
   322 					value.unbind( this._change );
       
   323 				delete value.parent;
       
   324 			}
       
   325 
       
   326 			delete this._value[ id ];
       
   327 			delete this._deferreds[ id ];
       
   328 		},
       
   329 
       
   330 		/**
       
   331 		 * Runs a callback once all requested values exist.
       
   332 		 *
       
   333 		 * when( ids*, [callback] );
       
   334 		 *
       
   335 		 * For example:
       
   336 		 *     when( id1, id2, id3, function( value1, value2, value3 ) {} );
       
   337 		 *
       
   338 		 * @returns $.Deferred.promise();
       
   339 		 */
       
   340 		when: function() {
       
   341 			var self = this,
       
   342 				ids  = slice.call( arguments ),
       
   343 				dfd  = $.Deferred();
       
   344 
       
   345 			// If the last argument is a callback, bind it to .done()
       
   346 			if ( $.isFunction( ids[ ids.length - 1 ] ) )
       
   347 				dfd.done( ids.pop() );
       
   348 
       
   349 			$.when.apply( $, $.map( ids, function( id ) {
       
   350 				if ( self.has( id ) )
       
   351 					return;
       
   352 
       
   353 				return self._deferreds[ id ] = self._deferreds[ id ] || $.Deferred();
       
   354 			})).done( function() {
       
   355 				var values = $.map( ids, function( id ) {
       
   356 						return self( id );
       
   357 					});
       
   358 
       
   359 				// If a value is missing, we've used at least one expired deferred.
       
   360 				// Call Values.when again to generate a new deferred.
       
   361 				if ( values.length !== ids.length ) {
       
   362 					// ids.push( callback );
       
   363 					self.when.apply( self, ids ).done( function() {
       
   364 						dfd.resolveWith( self, values );
       
   365 					});
       
   366 					return;
       
   367 				}
       
   368 
       
   369 				dfd.resolveWith( self, values );
       
   370 			});
       
   371 
       
   372 			return dfd.promise();
       
   373 		},
       
   374 
       
   375 		_change: function() {
       
   376 			this.parent.trigger( 'change', this );
       
   377 		}
       
   378 	});
       
   379 
       
   380 	$.extend( api.Values.prototype, api.Events );
       
   381 
       
   382 	/* =====================================================================
       
   383 	 * An observable value that syncs with an element.
       
   384 	 *
       
   385 	 * Handles inputs, selects, and textareas by default.
       
   386 	 * ===================================================================== */
       
   387 
       
   388 	api.ensure = function( element ) {
       
   389 		return typeof element == 'string' ? $( element ) : element;
       
   390 	};
       
   391 
       
   392 	api.Element = api.Value.extend({
       
   393 		initialize: function( element, options ) {
       
   394 			var self = this,
       
   395 				synchronizer = api.Element.synchronizer.html,
       
   396 				type, update, refresh;
       
   397 
       
   398 			this.element = api.ensure( element );
       
   399 			this.events = '';
       
   400 
       
   401 			if ( this.element.is('input, select, textarea') ) {
       
   402 				this.events += 'change';
       
   403 				synchronizer = api.Element.synchronizer.val;
       
   404 
       
   405 				if ( this.element.is('input') ) {
       
   406 					type = this.element.prop('type');
       
   407 					if ( api.Element.synchronizer[ type ] )
       
   408 						synchronizer = api.Element.synchronizer[ type ];
       
   409 					if ( 'text' === type || 'password' === type )
       
   410 						this.events += ' keyup';
       
   411 				} else if ( this.element.is('textarea') ) {
       
   412 					this.events += ' keyup';
       
   413 				}
       
   414 			}
       
   415 
       
   416 			api.Value.prototype.initialize.call( this, null, $.extend( options || {}, synchronizer ) );
       
   417 			this._value = this.get();
       
   418 
       
   419 			update  = this.update;
       
   420 			refresh = this.refresh;
       
   421 
       
   422 			this.update = function( to ) {
       
   423 				if ( to !== refresh.call( self ) )
       
   424 					update.apply( this, arguments );
       
   425 			};
       
   426 			this.refresh = function() {
       
   427 				self.set( refresh.call( self ) );
       
   428 			};
       
   429 
       
   430 			this.bind( this.update );
       
   431 			this.element.bind( this.events, this.refresh );
       
   432 		},
       
   433 
       
   434 		find: function( selector ) {
       
   435 			return $( selector, this.element );
       
   436 		},
       
   437 
       
   438 		refresh: function() {},
       
   439 
       
   440 		update: function() {}
       
   441 	});
       
   442 
       
   443 	api.Element.synchronizer = {};
       
   444 
       
   445 	$.each( [ 'html', 'val' ], function( i, method ) {
       
   446 		api.Element.synchronizer[ method ] = {
       
   447 			update: function( to ) {
       
   448 				this.element[ method ]( to );
       
   449 			},
       
   450 			refresh: function() {
       
   451 				return this.element[ method ]();
       
   452 			}
       
   453 		};
       
   454 	});
       
   455 
       
   456 	api.Element.synchronizer.checkbox = {
       
   457 		update: function( to ) {
       
   458 			this.element.prop( 'checked', to );
       
   459 		},
       
   460 		refresh: function() {
       
   461 			return this.element.prop( 'checked' );
       
   462 		}
       
   463 	};
       
   464 
       
   465 	api.Element.synchronizer.radio = {
       
   466 		update: function( to ) {
       
   467 			this.element.filter( function() {
       
   468 				return this.value === to;
       
   469 			}).prop( 'checked', true );
       
   470 		},
       
   471 		refresh: function() {
       
   472 			return this.element.filter( ':checked' ).val();
       
   473 		}
       
   474 	};
       
   475 
       
   476 	/* =====================================================================
       
   477 	 * Messenger for postMessage.
       
   478 	 * ===================================================================== */
       
   479 
       
   480 	$.support.postMessage = !! window.postMessage;
       
   481 
       
   482 	api.Messenger = api.Class.extend({
       
   483 		add: function( key, initial, options ) {
       
   484 			return this[ key ] = new api.Value( initial, options );
       
   485 		},
       
   486 
       
   487 		/**
       
   488 		 * Initialize Messenger.
       
   489 		 *
       
   490 		 * @param  {object} params        Parameters to configure the messenger.
       
   491 		 *         {string} .url          The URL to communicate with.
       
   492 		 *         {window} .targetWindow The window instance to communicate with. Default window.parent.
       
   493 		 *         {string} .channel      If provided, will send the channel with each message and only accept messages a matching channel.
       
   494 		 * @param  {object} options       Extend any instance parameter or method with this object.
       
   495 		 */
       
   496 		initialize: function( params, options ) {
       
   497 			// Target the parent frame by default, but only if a parent frame exists.
       
   498 			var defaultTarget = window.parent == window ? null : window.parent;
       
   499 
       
   500 			$.extend( this, options || {} );
       
   501 
       
   502 			this.add( 'channel', params.channel );
       
   503 			this.add( 'url', params.url || '' );
       
   504 			this.add( 'targetWindow', params.targetWindow || defaultTarget );
       
   505 			this.add( 'origin', this.url() ).link( this.url ).setter( function( to ) {
       
   506 				return to.replace( /([^:]+:\/\/[^\/]+).*/, '$1' );
       
   507 			});
       
   508 
       
   509 			// Since we want jQuery to treat the receive function as unique
       
   510 			// to this instance, we give the function a new guid.
       
   511 			//
       
   512 			// This will prevent every Messenger's receive function from being
       
   513 			// unbound when calling $.off( 'message', this.receive );
       
   514 			this.receive = $.proxy( this.receive, this );
       
   515 			this.receive.guid = $.guid++;
       
   516 
       
   517 			$( window ).on( 'message', this.receive );
       
   518 		},
       
   519 
       
   520 		destroy: function() {
       
   521 			$( window ).off( 'message', this.receive );
       
   522 		},
       
   523 
       
   524 		receive: function( event ) {
       
   525 			var message;
       
   526 
       
   527 			event = event.originalEvent;
       
   528 
       
   529 			if ( ! this.targetWindow() )
       
   530 				return;
       
   531 
       
   532 			// Check to make sure the origin is valid.
       
   533 			if ( this.origin() && event.origin !== this.origin() )
       
   534 				return;
       
   535 
       
   536 			message = JSON.parse( event.data );
       
   537 
       
   538 			// Check required message properties.
       
   539 			if ( ! message || ! message.id || typeof message.data === 'undefined' )
       
   540 				return;
       
   541 
       
   542 			// Check if channel names match.
       
   543 			if ( ( message.channel || this.channel() ) && this.channel() !== message.channel )
       
   544 				return;
       
   545 
       
   546 			this.trigger( message.id, message.data );
       
   547 		},
       
   548 
       
   549 		send: function( id, data ) {
       
   550 			var message;
       
   551 
       
   552 			data = typeof data === 'undefined' ? null : data;
       
   553 
       
   554 			if ( ! this.url() || ! this.targetWindow() )
       
   555 				return;
       
   556 
       
   557 			message = { id: id, data: data };
       
   558 			if ( this.channel() )
       
   559 				message.channel = this.channel();
       
   560 
       
   561 			this.targetWindow().postMessage( JSON.stringify( message ), this.origin() );
       
   562 		}
       
   563 	});
       
   564 
       
   565 	// Add the Events mixin to api.Messenger.
       
   566 	$.extend( api.Messenger.prototype, api.Events );
       
   567 
       
   568 	/* =====================================================================
       
   569 	 * Core customize object.
       
   570 	 * ===================================================================== */
       
   571 
       
   572 	api = $.extend( new api.Values(), api );
       
   573 	api.get = function() {
       
   574 		var result = {};
       
   575 
       
   576 		this.each( function( obj, key ) {
       
   577 			result[ key ] = obj.get();
       
   578 		});
       
   579 
       
   580 		return result;
       
   581 	};
       
   582 
       
   583 	// Expose the API to the world.
       
   584 	exports.customize = api;
       
   585 })( wp, jQuery );