/*! Embedly jQuery - v3.1.1 - 2013-06-05
* https://github.com/embedly/embedly-jquery
* Copyright (c) 2013 Sean Creeley
* Licensed BSD
*/
(function($) {
/*
* Util Functions
*/
// Defaults for Embedly.
var defaults = {
key: null,
endpoint: 'oembed', // default endpoint is oembed (preview and objectify available too)
secure: null, // use https endpoint vs http
query: {},
method: 'replace', // embed handling option for standard callback
addImageStyles: true, // add style="" attribute to images for query.maxwidth and query.maxhidth
wrapElement: 'div', // standard wrapper around all returned embeds
className: 'embed', // class on the wrapper element
batch: 20, // Default Batch Size.
urlRe: null
};
var urlRe = /(http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/;
var none = function(obj){
return obj === null || obj === undefined;
};
// Split a list into a bunch of batchs.
var batch = function(list, split){
var batches = [], current = [];
$.each(list, function(i, obj){
current.push(obj);
if (current.length === split){
batches.push(current);
current = [];
}
});
if (current.length !== 0){
batches.push(current);
}
return batches;
};
// Make an argument a list
var listify = function(obj){
if (none(obj)){
return [];
} else if (!$.isArray(obj)){
return [obj];
}
return obj;
};
// From: http://bit.ly/T9SjVv
var zip = function(arrays) {
return $.map(arrays[0], function(_,i){
return [$.map(arrays, function(array){return array[i];})];
});
};
/* Keeper
*
* alittle wrapper around Deferred that lets us keep track of
* all the callbacks that we have.
*/
var Keeper = function (len, each, after) {
this.init(len, each, after);
};
Keeper.prototype = {
init: function(urls){
this.urls = urls;
this.count = 0;
this.results = {};
this._deferred = $.Deferred();
},
// Only 2 methods we really care about.
notify : function(result) {
// Store the result.
this.results[result.original_url] = result;
// Increase the count.
this.count++;
// Notify the success functions
this._deferred.notify.apply(this._deferred, [result]);
// If all the callbacks have completed, do your thing.
if (this.count === this.urls.length){
// This sorts the results in the manner in which they were added.
var self = this;
var results = $.map(this.urls, function(url){ return self.results[url];});
this._deferred.resolve(results);
}
return this;
},
state: function() {
return this._deferred.state.apply(this._deferred, arguments);
}
};
window.Keeper = Keeper;
// direct API for dealing with the
var API = function () {};
API.prototype = {
/*
For dealing directly with Embedly's API.
options: {
key: 'Your API key'
secure: false,
query: {
maxwidth: 500,
colors: true,
}
}
*/
defaults: {},
log: function(level, message){
if (!none(window.console) && !none(window.console[level])){
window.console[level].apply(window.console, [message]);
}
},
// Based on the method and options, build the url,
build: function(method, urls, options){
// Technically, not great.
options = none(options) ? {}: options;
// Base method.
var secure = options.secure;
if (none(secure)){
// If the secure param was not see, use the protocol instead.
secure = window.location.protocol === 'https:'? true:false;
}
var base = (secure ? 'https': 'http') +
'://api.embed.ly/' + (method === 'objectify' ? '2/' : '1/') + method;
// Base Query;
var query = none(options.query) ? {} : options.query;
query.key = options.key;
base += '?'+$.param(query);
// Add the urls the way we like.
base += '&urls='+ $.map(urls, encodeURIComponent).join(',');
return base;
},
// Batch a bunch of URLS up for processing. Will split longer lists out
// into many batches and return the callback on each and after on done.
ajax: function(method, urls, options){
// Use the defaults.
options = $.extend({}, defaults, $.embedly.defaults, typeof options === 'object' && options);
if (none(options.key)){
this.log('error', 'Embedly jQuery requires an API Key. Please sign up for one at http://embed.ly');
return null;
}
// Everything is dealt with in lists.
urls = listify(urls);
// add a keeper that holds everything till we are good to go.
var keeper = new Keeper(urls);
var valid_urls = [], rejects = [], valid;
// Debunk the invalid urls right now.
$.each(urls, function(i, url){
valid = false;
// Make sure it's a URL
if (urlRe.test(url)){
valid = true;
// If the urlRe has been defined make sure it works.
if (options.urlRe !== null && options.urlRe.test && !options.urlRe.test(url)){
valid = false;
}
}
// deal with the valid urls
if(valid === true){
valid_urls.push(url);
} else {
// Notify the keeper that we have a bad url.
rejects.push({
url: url,
original_url: url,
error: true,
invalid: true,
type: 'error',
error_message: 'Invalid URL "'+ url+'"'
});
}
});
// Put everything into batches, even if these is only one.
var batches = batch(valid_urls, options.batch), self = this;
// Actually make those calls.
$.each(batches, function(i, batch){
$.ajax({
url: self.build(method, batch, options),
dataType: 'jsonp',
success: function(data){
// We zip together the urls and the data so we have the original_url
$.each(zip([batch, data]), function(i, obj){
var result = obj[1];
result.original_url = obj[0];
result.invalid = false;
keeper.notify(result);
});
}
});
});
if (rejects.length){
// set a short timeout so we can set up progress and done, otherwise
// the progress notifier will not get all the events.
setTimeout(function(){
$.each(rejects, function(i, reject){
keeper.notify(reject);
});
}, 1);
}
return keeper._deferred;
},
// Wrappers around ajax.
oembed: function(urls, options){
return this.ajax('oembed', urls, options);
},
preview: function(urls, options){
return this.ajax('preview', urls, options);
},
objectify: function(urls, options){
return this.ajax('objectify', urls, options);
},
extract: function(urls, options){
return this.ajax('extract', urls, options);
}
};
// direct API dealing directly with Embedly's Display API.
var ImageAPI = function () {};
ImageAPI.prototype = {
// Based on the method and options, build the image url,
build: function(method, url, options){
options = $.extend({}, $.embedly.defaults, typeof options === 'object' && options);
var secure = options.secure;
if (none(secure)){
// If the secure param was not seen, use the protocol instead.
secure = window.location.protocol === 'https:'? true:false;
}
var base = (secure ? 'https': 'http') +
'://i.embed.ly/' + (method === 'display' ? '1/' : '1/display/') + method;
// Base Query
var query = none(options.query) ? {} : options.query;
query.key = options.key;
base += '?'+$.param(query);
// Add the image url
base += '&url='+ encodeURIComponent(url);
return base;
},
// Wrappers around build image url function.
display: function(url, options){
return this.build('display', url, options);
},
resize: function(url, options){
return this.build('resize', url, options);
},
fill: function(url, options){
return this.build('fill', url, options);
},
crop: function(url, options){
return this.build('crop', url, options);
}
};
var Embedly = function (element, url, options) {
this.init(element, url, options);
};
Embedly.prototype = {
init: function(elem, original_url, options){
this.elem = elem;
this.$elem = $(elem);
this.original_url = original_url;
this.options = options;
this.loaded = $.Deferred();
// Sets up some triggers.
var self = this;
this.loaded.done(function(){
self.$elem.trigger('loaded', [self]);
});
// So you can listen when the tag has been initialized;
this.$elem.trigger('initialized', [this]);
},
progress: function(obj){
$.extend(this, obj);
// if there is a custom display method, use it.
if (this.options.display){
this.options.display.apply(this.elem, [this, this.elem]);
}
// We only have a simple case for oEmbed. Everything else should be a custom
// success method.
else if(this.options.endpoint === 'oembed'){
this.display();
}
// Notifies all listeners that the data has been loaded.
this.loaded.resolve(this);
},
imageStyle: function(){
var style = [], units;
if (this.options.addImageStyles) {
if (this.options.query.maxwidth) {
units = isNaN(parseInt(this.options.query.maxwidth, 10)) ? '' : 'px';
style.push("max-width: " + (this.options.query.maxwidth)+units);
}
if (this.options.query.maxheight) {
units = isNaN(parseInt(this.options.query.maxheight,10)) ? '' : 'px';
style.push("max-height: " + (this.options.query.maxheight)+units);
}
}
return style.join(';');
},
display: function(){
// Ignore errors
if (this.type === 'error'){
return false;
}
// Image Style.
this.style = this.imageStyle();
var html;
if (this.type === 'photo'){
html = "";
html += "";
} else if (this.type === 'video' || this.type === 'rich'){
html = this.html;
} else {
this.title = this.title || this.url;
html = this.thumbnail_url ? "
" : "";
html += "" + this.title + "";
html += this.provider_name ? "" + this.provider_name + "" : "";
html += this.description ? '
$.fn.display = function (endpoint, options) {
// default to display
if (none(endpoint)) {
endpoint = 'display';
}
if (options === undefined || typeof options === 'object') {
// Use the defaults
options = $.extend({}, defaults, $.embedly.defaults, typeof options === 'object' && options);
// Key Check.
if (none(options.key)){
$.embedly.log('error', 'Embedly jQuery requires an API Key. Please sign up for one at http://embed.ly/display');
return this.each($.noop);
}
// Create the node for all elements
var create = function (elem){
var $elem = $(elem);
if (!$elem.data('display')) {
var url = $elem.data('src') || $elem.attr('href');
var data = {
original_url : url,
url : $.embedly.display.build(endpoint, url, options)
};
$elem.data('display', data);
$elem.trigger('initialized', [elem]);
var html = "