; // for better merging // Init style shamelessly stolen from jQuery http://jquery.com var Froogaloop = (function(){ // Define a local copy of Froogaloop function Froogaloop(iframe) { // The Froogaloop object is actually just the init constructor return new Froogaloop.fn.init(iframe); } var eventCallbacks = {}, hasWindowEvent = false, isReady = false, slice = Array.prototype.slice, playerDomain = ''; Froogaloop.fn = Froogaloop.prototype = { element: null, init: function(iframe) { if (typeof iframe === "string") { iframe = document.getElementById(iframe); } this.element = iframe; // Register message event listeners playerDomain = getDomainFromUrl(this.element.getAttribute('src')); return this; }, /* * Calls a function to act upon the player. * * @param {string} method The name of the Javascript API method to call. Eg: 'play'. * @param {Array|Function} valueOrCallback params Array of parameters to pass when calling an API method * or callback function when the method returns a value. */ api: function(method, valueOrCallback) { if (!this.element || !method) { return false; } var self = this, element = self.element, target_id = element.id !== '' ? element.id : null, params = !isFunction(valueOrCallback) ? valueOrCallback : null, callback = isFunction(valueOrCallback) ? valueOrCallback : null; // Store the callback for get functions if (callback) { storeCallback(method, callback, target_id); } postMessage(method, params, element); return self; }, /* * Registers an event listener and a callback function that gets called when the event fires. * * @param eventName (String): Name of the event to listen for. * @param callback (Function): Function that should be called when the event fires. */ addEvent: function(eventName, callback) { if (!this.element) { return false; } var self = this, element = self.element, target_id = element.id !== '' ? element.id : null; storeCallback(eventName, callback, target_id); // The ready event is not registered via postMessage. It fires regardless. if (eventName != 'ready') { postMessage('addEventListener', eventName, element); } else if (eventName == 'ready' && isReady) { callback.call(null, target_id); } return self; }, /* * Unregisters an event listener that gets called when the event fires. * * @param eventName (String): Name of the event to stop listening for. */ removeEvent: function(eventName) { if (!this.element) { return false; } var self = this, element = self.element, target_id = element.id !== '' ? element.id : null, removed = removeCallback(eventName, target_id); // The ready event is not registered if (eventName != 'ready' && removed) { postMessage('removeEventListener', eventName, element); } } }; /** * Handles posting a message to the parent window. * * @param method (String): name of the method to call inside the player. For api calls * this is the name of the api method (api_play or api_pause) while for events this method * is api_addEventListener. * @param params (Object or Array): List of parameters to submit to the method. Can be either * a single param or an array list of parameters. * @param target (HTMLElement): Target iframe to post the message to. */ function postMessage(method, params, target) { if (!target.contentWindow.postMessage) { return false; } var url = target.getAttribute('src').split('?')[0], data = JSON.stringify({ method: method, value: params }); if (url.substr(0, 2) === '//') { url = window.location.protocol + url; } target.contentWindow.postMessage(data, url); } /** * Event that fires whenever the window receives a message from its parent * via window.postMessage. */ function onMessageReceived(event) { var data, method; try { data = JSON.parse(event.data); method = data.event || data.method; } catch(e) { //fail silently... like a ninja! } if (method == 'ready' && !isReady) { isReady = true; } // Handles messages from moogaloop only if (event.origin != playerDomain) { return false; } var value = data.value, eventData = data.data, target_id = target_id === '' ? null : data.player_id, callback = getCallback(method, target_id), params = []; if (!callback) { return false; } if (value !== undefined) { params.push(value); } if (eventData) { params.push(eventData); } if (target_id) { params.push(target_id); } return params.length > 0 ? callback.apply(null, params) : callback.call(); } /** * Stores submitted callbacks for each iframe being tracked and each * event for that iframe. * * @param eventName (String): Name of the event. Eg. api_onPlay * @param callback (Function): Function that should get executed when the * event is fired. * @param target_id (String) [Optional]: If handling more than one iframe then * it stores the different callbacks for different iframes based on the iframe's * id. */ function storeCallback(eventName, callback, target_id) { if (target_id) { if (!eventCallbacks[target_id]) { eventCallbacks[target_id] = {}; } eventCallbacks[target_id][eventName] = callback; } else { eventCallbacks[eventName] = callback; } } /** * Retrieves stored callbacks. */ function getCallback(eventName, target_id) { if (target_id) { return eventCallbacks[target_id][eventName]; } else { return eventCallbacks[eventName]; } } function removeCallback(eventName, target_id) { if (target_id && eventCallbacks[target_id]) { if (!eventCallbacks[target_id][eventName]) { return false; } eventCallbacks[target_id][eventName] = null; } else { if (!eventCallbacks[eventName]) { return false; } eventCallbacks[eventName] = null; } return true; } /** * Returns a domain's root domain. * Eg. returns http://vimeo.com when http://vimeo.com/channels is sbumitted * * @param url (String): Url to test against. * @return url (String): Root domain of submitted url */ function getDomainFromUrl(url) { if (url.substr(0, 2) === '//') { url = window.location.protocol + url; } var url_pieces = url.split('/'), domain_str = ''; for(var i = 0, length = url_pieces.length; i < length; i++) { if(i<3) {domain_str += url_pieces[i];} else {break;} if(i<2) {domain_str += '/';} } return domain_str; } function isFunction(obj) { return !!(obj && obj.constructor && obj.call && obj.apply); } function isArray(obj) { return toString.call(obj) === '[object Array]'; } // Give the init function the Froogaloop prototype for later instantiation Froogaloop.fn.init.prototype = Froogaloop.fn; // Listens for the message event. // W3C if (window.addEventListener) { window.addEventListener('message', onMessageReceived, false); } // IE else { window.attachEvent('onmessage', onMessageReceived); } // Expose froogaloop to the global object return (window.Froogaloop = window.$f = Froogaloop); })();