/*!

 * jQuery postMessage - v0.5 - 9/11/2009

 * http://benalman.com/projects/jquery-postmessage-plugin/

 * 

 * Copyright (c) 2009 "Cowboy" Ben Alman

 * Dual licensed under the MIT and GPL licenses.

 * http://benalman.com/about/license/

 */



// Script: jQuery postMessage: Cross-domain scripting goodness

//

// *Version: 0.5, Last updated: 9/11/2009*

// 

// Project Home - http://benalman.com/projects/jquery-postmessage-plugin/

// GitHub       - http://github.com/cowboy/jquery-postmessage/

// Source       - http://github.com/cowboy/jquery-postmessage/raw/master/jquery.ba-postmessage.js

// (Minified)   - http://github.com/cowboy/jquery-postmessage/raw/master/jquery.ba-postmessage.min.js (0.9kb)

// 

// About: License

// 

// Copyright (c) 2009 "Cowboy" Ben Alman,

// Dual licensed under the MIT and GPL licenses.

// http://benalman.com/about/license/

// 

// About: Examples

// 

// This working example, complete with fully commented code, illustrates one

// way in which this plugin can be used.

// 

// Iframe resizing - http://benalman.com/code/projects/jquery-postmessage/examples/iframe/

// 

// About: Support and Testing

// 

// Information about what version or versions of jQuery this plugin has been

// tested with and what browsers it has been tested in.

// 

// jQuery Versions - 1.3.2

// Browsers Tested - Internet Explorer 6-8, Firefox 3, Safari 3-4, Chrome, Opera 9.

// 

// About: Release History

// 

// 0.5 - (9/11/2009) Improved cache-busting

// 0.4 - (8/25/2009) Initial release



(function($){

  '$:nomunge'; // Used by YUI compressor.

  

  // A few vars used in non-awesome browsers.

  var interval_id,

    last_hash,

    cache_bust = 1,

    

    // A var used in awesome browsers.

    rm_callback,

    

    // A few convenient shortcuts.

    window = this,

    FALSE = !1,

    

    // Reused internal strings.

    postMessage = 'postMessage',

    addEventListener = 'addEventListener',

    

    p_receiveMessage,

    

    // I couldn't get window.postMessage to actually work in Opera 9.64!

    has_postMessage = window[postMessage] && !$.browser.opera;

  

  // Method: jQuery.postMessage

  // 

  // This method will call window.postMessage if available, setting the

  // targetOrigin parameter to the base of the target_url parameter for maximum

  // security in browsers that support it. If window.postMessage is not available,

  // the target window's location.hash will be used to pass the message. If an

  // object is passed as the message param, it will be serialized into a string

  // using the jQuery.param method.

  // 

  // Usage:

  // 

  // > jQuery.postMessage( message, target_url [, target ] );

  // 

  // Arguments:

  // 

  //  message - (String) A message to be passed to the other frame.

  //  message - (Object) An object to be serialized into a params string, using

  //    the jQuery.param method.

  //  target_url - (String) The URL of the other frame this window is

  //    attempting to communicate with. This must be the exact URL (including

  //    any query string) of the other window for this script to work in

  //    browsers that don't support window.postMessage.

  //  target - (Object) A reference to the other frame this window is

  //    attempting to communicate with. If omitted, defaults to `parent`.

  // 

  // Returns:

  // 

  //  Nothing.

  

  $[postMessage] = function( message, target_url, target ) {

    if ( !target_url ) { return; }

    

    // Serialize the message if not a string. Note that this is the only real

    // jQuery dependency for this script. If removed, this script could be

    // written as very basic JavaScript.

    message = typeof message === 'string' ? message : $.param( message );

    

    // Default to parent if unspecified.

    target = target || parent;

    

    if ( has_postMessage ) {

      // The browser supports window.postMessage, so call it with a targetOrigin

      // set appropriately, based on the target_url parameter.

      target[postMessage]( message, target_url.replace( /([^:]+:\/\/[^\/]+).*/, '$1' ) );

      

    } else if ( target_url ) {

      // The browser does not support window.postMessage, so set the location

      // of the target to target_url#message. A bit ugly, but it works! A cache

      // bust parameter is added to ensure that repeat messages trigger the

      // callback.

      target.location = target_url.replace( /#.*$/, '' ) + '#' + (+new Date) + (cache_bust++) + '&' + message;

    }

  };

  

  // Method: jQuery.receiveMessage

  // 

  // Register a single callback for either a window.postMessage call, if

  // supported, or if unsupported, for any change in the current window

  // location.hash. If window.postMessage is supported and source_origin is

  // specified, the source window will be checked against this for maximum

  // security. If window.postMessage is unsupported, a polling loop will be

  // started to watch for changes to the location.hash.

  // 

  // Note that for simplicity's sake, only a single callback can be registered

  // at one time. Passing no params will unbind this event (or stop the polling

  // loop), and calling this method a second time with another callback will

  // unbind the event (or stop the polling loop) first, before binding the new

  // callback.

  // 

  // Also note that if window.postMessage is available, the optional

  // source_origin param will be used to test the event.origin property. From

  // the MDC window.postMessage docs: This string is the concatenation of the

  // protocol and "://", the host name if one exists, and ":" followed by a port

  // number if a port is present and differs from the default port for the given

  // protocol. Examples of typical origins are https://example.org (implying

  // port 443), http://example.net (implying port 80), and http://example.com:8080.

  // 

  // Usage:

  // 

  // > jQuery.receiveMessage( callback [, source_origin ] [, delay ] );

  // 

  // Arguments:

  // 

  //  callback - (Function) This callback will execute whenever a <jQuery.postMessage>

  //    message is received, provided the source_origin matches. If callback is

  //    omitted, any existing receiveMessage event bind or polling loop will be

  //    canceled.

  //  source_origin - (String) If window.postMessage is available and this value

  //    is not equal to the event.origin property, the callback will not be

  //    called.

  //  source_origin - (Function) If window.postMessage is available and this

  //    function returns false when passed the event.origin property, the

  //    callback will not be called.

  //  delay - (Number) An optional zero-or-greater delay in milliseconds at

  //    which the polling loop will execute (for browser that don't support

  //    window.postMessage). If omitted, defaults to 100.

  // 

  // Returns:

  // 

  //  Nothing!

  

  $.receiveMessage = p_receiveMessage = function( callback, source_origin, delay ) {

    if ( has_postMessage ) {

      // Since the browser supports window.postMessage, the callback will be

      // bound to the actual event associated with window.postMessage.

      

      if ( callback ) {

        // Unbind an existing callback if it exists.

        rm_callback && p_receiveMessage();

        

        // Bind the callback. A reference to the callback is stored for ease of

        // unbinding.

        rm_callback = function(e) {

          if ( ( typeof source_origin === 'string' && e.origin !== source_origin )

            || ( $.isFunction( source_origin ) && source_origin( e.origin ) === FALSE ) ) {

            return FALSE;

          }

          callback( e );

        };

      }

      

      if ( window[addEventListener] ) {

        window[ callback ? addEventListener : 'removeEventListener' ]( 'message', rm_callback, FALSE );

      } else {

        window[ callback ? 'attachEvent' : 'detachEvent' ]( 'onmessage', rm_callback );

      }

      

    } else {

      // Since the browser sucks, a polling loop will be started, and the

      // callback will be called whenever the location.hash changes.

      

      interval_id && clearInterval( interval_id );

      interval_id = null;

      

      if ( callback ) {

        delay = typeof source_origin === 'number'

          ? source_origin

          : typeof delay === 'number'

            ? delay

            : 100;

        

        interval_id = setInterval(function(){

          var hash = document.location.hash,

            re = /^#?\d+&/;

          if ( hash !== last_hash && re.test( hash ) ) {

            last_hash = hash;

            callback({ data: hash.replace( re, '' ) });

          }

        }, delay );

      }

    }

  };

  

})(jQuery);

