Skip to content

Instantly share code, notes, and snippets.

@CatoTH
Forked from LouisStAmour/plugin.js
Created March 13, 2012 14:48
Show Gist options
  • Save CatoTH/2029227 to your computer and use it in GitHub Desktop.
Save CatoTH/2029227 to your computer and use it in GitHub Desktop.
Proof-of-concept alpha of jQuery-oembed integrated with CKeditor on paste or when space is pressed.
/*
* CKEditor plugin to automatically embed oEmbed-Content
* CKEditor/jquery.oembed-integration proof of concept by Tobias Hößl
*
* Inspired by:
* Auto-Insertion plugin
* Copyright (c) 2010 Louis St-Amour, but multi-licensed as GPL/LGPL/MPL
*
* Embeds:
* jquery oembed plugin v1.1
* Copyright (c) 2009 Richard Chamorro
* Licensed under the MIT license
*
*
*
*/
(function ($) {
$.fn.oembed = function (url, options, embedAction) {
settings = $.extend(true, $.fn.oembed.defaults, options);
initializeProviders();
return this.each(function () {
var container = $(this),
resourceURL = (url != null) ? url : container.attr("href"),
provider;
if (embedAction) {
settings.onEmbed = embedAction;
} else {
settings.onEmbed = function (oembedData) {
$.fn.oembed.insertCode(this, settings.embedMethod, oembedData);
};
}
if (resourceURL != null) {
provider = $.fn.oembed.getOEmbedProvider(resourceURL);
if (provider != null) {
provider.params = getNormalizedParams(settings[provider.name]) || {};
provider.maxWidth = settings.maxWidth;
provider.maxHeight = settings.maxHeight;
embedCode(container, resourceURL, provider);
} else {
settings.onProviderNotFound.call(container, resourceURL);
}
}
return container;
});
};
var settings, activeProviders = [];
// Plugin defaults
$.fn.oembed.defaults = {
maxWidth: null,
maxHeight: null,
embedMethod: "replace", // "auto", "append", "fill"
defaultOEmbedProvider: "oohembed", // "oohembed", "embed.ly", "none"
allowedProviders: null,
disallowedProviders: null,
customProviders: null, // [ new $.fn.oembed.OEmbedProvider("customprovider", null, ["customprovider\\.com/watch.+v=[\\w-]+&?"]) ]
defaultProvider: null,
greedy: true,
preferThumbnails: true,
onProviderNotFound: function () { },
beforeEmbed: function () { },
afterEmbed: function () { },
onEmbed: function () { },
onError: function() {},
ajaxOptions: {}
};
/* Private functions */
function getRequestUrl(provider, externalUrl) {
var url = provider.apiendpoint, qs = "", callbackparameter = provider.callbackparameter || "callback", i;
if (url.indexOf("?") <= 0)
url = url + "?";
else
url = url + "&";
if (provider.maxWidth != null && provider.params["maxwidth"] == null)
provider.params["maxwidth"] = provider.maxWidth;
if (provider.maxHeight != null && provider.params["maxheight"] == null)
provider.params["maxheight"] = provider.maxHeight;
for (i in provider.params) {
// We don't want them to jack everything up by changing the callback parameter
if (i == provider.callbackparameter)
continue;
// allows the options to be set to null, don't send null values to the server as parameters
if (provider.params[i] != null)
qs += "&" + escape(i) + "=" + provider.params[i];
}
if (url.search("\\?format=") == -1) url += "format=json&";
url += provider.getUrlParameter(externalUrl) + qs + "&" + callbackparameter + "=?";
return url;
};
function embedCode(container, externalUrl, embedProvider) {
var requestUrl = getRequestUrl(embedProvider, externalUrl),
ajaxopts = $.extend({
url: requestUrl,
type: 'get',
dataType: 'json',
// error: jsonp request doesnt' support error handling
success: function (data) {
var oembedData = $.extend({}, data);
switch (oembedData.type) {
case "photo":
oembedData.code = $.fn.oembed.getPhotoCode(externalUrl, oembedData);
break;
case "video":
oembedData.code = $.fn.oembed.getVideoCode(externalUrl, oembedData);
break;
case "rich":
oembedData.code = $.fn.oembed.getRichCode(externalUrl, oembedData);
break;
default:
if (oembedData.thumbnail_url) oembedData.code = $.fn.oembed.getPhotoCode(externalUrl, oembedData);
else oembedData.code = $.fn.oembed.getGenericCode(externalUrl, oembedData);
break;
}
settings.beforeEmbed.call(container, oembedData);
settings.onEmbed.call(container, oembedData);
settings.afterEmbed.call(container, oembedData);
},
error: settings.onError.call(container, externalUrl, embedProvider)
}, settings.ajaxOptions || { } );
$.ajax( ajaxopts );
};
function initializeProviders() {
activeProviders = [];
var defaultProvider, restrictedProviders = [], i, provider;
if (!isNullOrEmpty(settings.allowedProviders)) {
for (i = 0; i < $.fn.oembed.providers.length; i++) {
if ($.inArray($.fn.oembed.providers[i].name, settings.allowedProviders) >= 0)
activeProviders.push($.fn.oembed.providers[i]);
}
// If there are allowed providers, jquery-oembed cannot be greedy
settings.greedy = false;
} else {
activeProviders = $.fn.oembed.providers;
}
if (!isNullOrEmpty(settings.disallowedProviders)) {
for (i = 0; i < activeProviders.length; i++) {
if ($.inArray(activeProviders[i].name, settings.disallowedProviders) < 0)
restrictedProviders.push(activeProviders[i]);
}
activeProviders = restrictedProviders;
// If there are allowed providers, jquery-oembed cannot be greedy
settings.greedy = false;
}
if (!isNullOrEmpty(settings.customProviders)) {
$.each(settings.customProviders, function (n, customProvider) {
if (customProvider instanceof $.fn.oembed.OEmbedProvider) {
activeProviders.push(provider);
} else {
provider = new $.fn.oembed.OEmbedProvider();
if (provider.fromJSON(customProvider))
activeProviders.push(provider);
}
});
}
// If in greedy mode, we add the default provider
defaultProvider = getDefaultOEmbedProvider(settings.defaultOEmbedProvider);
if (settings.greedy == true) {
activeProviders.push(defaultProvider);
}
// If any provider has no apiendpoint, we use the default provider endpoint
for (i = 0; i < activeProviders.length; i++) {
if (activeProviders[i].apiendpoint == null)
activeProviders[i].apiendpoint = defaultProvider.apiendpoint;
}
}
function getDefaultOEmbedProvider(defaultOEmbedProvider) {
var url = "http://oohembed.com/oohembed/";
if (defaultOEmbedProvider == "embed.ly")
url = "http://api.embed.ly/v1/api/oembed?";
return new $.fn.oembed.OEmbedProvider(defaultOEmbedProvider, null, null, url, "callback");
}
function getNormalizedParams(params) {
if (params == null)
return null;
var key, normalizedParams = {};
for (key in params) {
if (key != null)
normalizedParams[key.toLowerCase()] = params[key];
}
return normalizedParams;
}
function isNullOrEmpty(object) {
if (typeof object == "undefined")
return true;
if (object == null)
return true;
if ($.isArray(object) && object.length == 0)
return true;
return false;
}
/* Public functions */
$.fn.oembed.insertCode = function (container, embedMethod, oembedData) {
if (oembedData == null)
return;
switch (embedMethod) {
case "auto":
if (container.attr("href") != null) {
$.fn.oembed.insertCode(container, "append", oembedData);
}
else {
$.fn.oembed.insertCode(container, "replace", oembedData);
};
break;
case "replace":
container.replaceWith(oembedData.code);
break;
case "fill":
container.html(oembedData.code);
break;
case "append":
var oembedContainer = container.next();
if (oembedContainer == null || !oembedContainer.hasClass("oembed-container")) {
oembedContainer = container
.after('<div class="oembed-container"></div>')
.next(".oembed-container");
if (oembedData != null && oembedData.provider_name != null)
oembedContainer.toggleClass("oembed-container-" + oembedData.provider_name);
}
oembedContainer.html(oembedData.code);
break;
}
};
$.fn.oembed.getPhotoCode = function (url, oembedData) {
var code, alt = oembedData.title ? oembedData.title : '';
alt += oembedData.author_name ? ' - ' + oembedData.author_name : '';
alt += oembedData.provider_name ? ' - ' + oembedData.provider_name : '';
var url = oembedData.url;
if (settings.preferThumbnails) {
if (oembedData.thumbnail_url_150) url = oembedData.thumbnail_url_150;
else if (oembedData.thumbnail_url) url = oembedData.thumbnail_url;
}
code = '<div><a href="' + url + '" target=\'_blank\'><img src="' + url + '" alt="' + alt + '"/></a></div>';
if (oembedData.html)
code += "<div>" + oembedData.html + "</div>";
return code;
};
$.fn.oembed.getVideoCode = function (url, oembedData) {
var code = oembedData.html;
return code;
};
$.fn.oembed.getRichCode = function (url, oembedData) {
var code = oembedData.html;
return code;
};
$.fn.oembed.getGenericCode = function (url, oembedData) {
var title = (oembedData.title != null) ? oembedData.title : url,
code = '<a href="' + url + '">' + title + '</a>';
if (oembedData.html)
code += "<div>" + oembedData.html + "</div>";
return code;
};
$.fn.oembed.isProviderAvailable = function (url) {
var provider = getOEmbedProvider(url);
return (provider != null);
};
$.fn.oembed.getOEmbedProvider = function (url) {
for (var i = 0; i < activeProviders.length; i++) {
if (activeProviders[i].matches(url)) {
return activeProviders[i];
}
}
return null;
};
$.fn.oembed.OEmbedProvider = function (name, type, urlschemesarray, apiendpoint, callbackparameter, urlparameterfunction) {
this.name = name;
this.type = type; // "photo", "video", "link", "rich", null
this.urlschemes = getUrlSchemes(urlschemesarray);
this.apiendpoint = apiendpoint;
this.callbackparameter = callbackparameter;
this.maxWidth = 500;
this.maxHeight = 400;
this.urlparameterfunction = urlparameterfunction;
var i, property, regExp;
this.matches = function (externalUrl) {
for (i = 0; i < this.urlschemes.length; i++) {
regExp = new RegExp(this.urlschemes[i], "i");
if (externalUrl.match(regExp) != null)
return true;
}
return false;
};
this.fromJSON = function (json) {
for (property in json) {
if (property != "urlschemes")
this[property] = json[property];
else
this[property] = getUrlSchemes(json[property]);
}
return true;
};
this.getUrlParameter = function (externalUrl) {
if (this.urlparameterfunction) return this.urlparameterfunction(externalUrl);
else return "url=" + escape(externalUrl);
}
function getUrlSchemes(urls) {
if (isNullOrEmpty(urls))
return ["."];
if ($.isArray(urls))
return urls;
return urls.split(";");
}
};
/* Native & common providers */
$.fn.oembed.providers = [
new $.fn.oembed.OEmbedProvider("youtube", "video", ["youtube\\.com/watch.+v=[\\w-]+&?"]), // "http://www.youtube.com/oembed" (no jsonp)
new $.fn.oembed.OEmbedProvider("flickr", "photo", ["flickr\\.com/photos/[-.\\w@]+/\\d+/?"], "http://flickr.com/services/oembed", "jsoncallback"),
new $.fn.oembed.OEmbedProvider("viddler", "video", ["viddler\.com"]), // "http://lab.viddler.com/services/oembed/" (no jsonp)
new $.fn.oembed.OEmbedProvider("blip", "video", ["blip\\.tv/.+"], "http://blip.tv/oembed/"),
new $.fn.oembed.OEmbedProvider("hulu", "video", ["hulu\\.com/watch/.*"], "http://www.hulu.com/api/oembed.json"),
new $.fn.oembed.OEmbedProvider("vimeo", "video", ["http:\/\/www\.vimeo\.com\/groups\/.*\/videos\/.*", "http:\/\/www\.vimeo\.com\/.*", "http:\/\/vimeo\.com\/groups\/.*\/videos\/.*", "http:\/\/vimeo\.com\/.*"], "http://vimeo.com/api/oembed.json"),
new $.fn.oembed.OEmbedProvider("dailymotion", "video", ["dailymotion\\.com/.+"]), // "http://www.dailymotion.com/api/oembed/" (callback parameter does not return jsonp)
new $.fn.oembed.OEmbedProvider("scribd", "rich", ["scribd\\.com/.+"]), // ", "http://www.scribd.com/services/oembed"" (no jsonp)
new $.fn.oembed.OEmbedProvider("slideshare", "rich", ["slideshare\.net"], "http://www.slideshare.net/api/oembed/1"),
new $.fn.oembed.OEmbedProvider("photobucket", "photo", ["photobucket\\.com/(albums|groups)/.*"], "http://photobucket.com/oembed/"),
new $.fn.oembed.OEmbedProvider("animexx", "rich", ["https?:\/\/([a-z0-9_-]+\\.animexx\\.de|animexx\\.onlinewelten\\.com)/.*"], "http://www.animexx.de/services/oembed.php"),
new $.fn.oembed.OEmbedProvider("deviantart", "photo", ["https?:\/\/[a-z0-9_-]+\\.deviantart\\.com/.*"], "http://backend.deviantart.com/oembed?format=jsonp"),
new $.fn.oembed.OEmbedProvider("soundcloud", "rich", ["https?:\/\/soundcloud\\.com/.*"], "http://soundcloud.com/oembed?format=js"),
new $.fn.oembed.OEmbedProvider("twitter", "photo", ["https?:\/\/twitter\\.com/.*"], "https://api.twitter.com/1/statuses/oembed.json", null, function(externalUrl) {
var id = externalUrl.match(/[0-9]{18}/);
return "id=" + id;
})
// new $.fn.oembed.OEmbedProvider("vids.myspace.com", "video", ["vids\.myspace\.com"]), // "http://vids.myspace.com/index.cfm?fuseaction=oembed" (not working)
// new $.fn.oembed.OEmbedProvider("screenr", "rich", ["screenr\.com"], "http://screenr.com/api/oembed.json") (error)
// new $.fn.oembed.OEmbedProvider("qik", "video", ["qik\\.com/\\w+"], "http://qik.com/api/oembed.json"),
// new $.fn.oembed.OEmbedProvider("revision3", "video", ["revision3\.com"], "http://revision3.com/api/oembed/")
];
})(jQuery);
(function()
{
var autolinkCommand =
{
exec : function( editor )
{
var d = editor.getData();
var match;
while (match = CKEDITOR.plugins.registered.autoinsert.urlpattern.exec(d)) {
var url = match[1];
console.log(url);
var cb = (match.index > 0 ? d[match.index - 1] : "");
if (match.index == 0 || (cb != "\"" && cb != "'")) {
var $holder = $("<div><a></a></div>");
$holder.find("a").attr("href", url).oembed(null, { afterEmbed: function() {
console.log(cb + url);
console.log(cb + $holder.html() + "&nbsp;");
editor.setData(d.replace(cb + url, cb + $holder.html() + "&nbsp;"));
} });
}
}
}
};
CKEDITOR.plugins.add( 'autoinsert',
{
requires : [ 'keystrokes' ],
idcounter : 0,
urlpattern : /(https?:\/\/[-a-zäöü0-9\_]+[-a-zäöü0-9\_\$\.\:;\/\\?=\+\~@,&%#!\'\[\]]+[-a-zäöü0-9\_\$\:\/=\+\~@%#])/gi,
init : function( editor ) {
editor.on( 'key', function( ev ) {
if ( ev.data.keyCode == 32 ) // SPACE
{
editor.execCommand( 'autolink' );
}
});
editor.on( 'paste', function( ev ) {
setTimeout(function() {
editor.execCommand( 'autolink' );
}, 0);
});
editor.addCommand( 'autolink', CKEDITOR.tools.extend( autolinkCommand ) );
}
});
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment