Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Twitter widget generator: This script makes it easy to generate Twitter widget. It works at https://twitter.com/settings/widgets .
(function(doc, win){
if(!(
doc.URL.replace(/\/$/, "") === "https://twitter.com/settings/widgets" &&
!doc.getElementById("widgetGenerator")
)){
return;
}
var head = (doc.head || doc.getElementsByTagName("head")[0]),
loadScript = function(source, callback){
var script = doc.createElement("script");
script.setAttribute("src", source);
script.addEventListener("load", callback, false);
head.appendChild(script);
};
(function(callback, requires){
requires = requires || [];
(function(){
if(requires.length){
loadScript(requires.shift(), arguments.callee);
}
else{
callback();
}
}());
}(function(){
(function(_, $){
$.fn.extend({
populate: function(values){
return this.each(function(i, form){
var $form = $(this);
for(var key in values){
var input = (
$form.find(":input#" + key)[0] ||
$form.find(":input[name='$name']".replace("$name", key))[0] ||
$form.find(":input[name*='[$key]']".replace("$key", key))[0]
),
value = values[key];
if(!input){
continue;
}
switch(input.tagName.toLowerCase()){
case "input":
switch(input.type){
case "checkbox":
input.checked = !!value;
break;
case "hidden":
case "number":
case "password":
case "text":
input.value = value.toString();
break;
case "radio":
$form.find(
"input[type='radio'][name='$name'][value='$value']"
.replace("$name", input.name)
.replace("$value", value)
)
.prop("checked", true);
break;
case "button":
case "file":
case "image":
case "reset":
case "submit":
default:
}
break;
case "select":
switch(input.type){
case "select-multiple":
var _values = _.invoke($.makeArray(value), "toString");
_.each(input.options, function(option, i, options){
option.selected = _.contains(_values, option.value);
});
break;
case "select-one":
var option = _.findWhere(input.options, {value: value.toString()});
if(option){
option.selected = true;
}
break;
default:
}
break;
case "textarea":
input.value = value.toString();
break;
case "button":
default:
}
}
});
},
_serializedObject: function(){
var values = {};
_.each(this.serializeArray(), function(nameValuePair, i, nameValuePairs){
var name = nameValuePair.name;
if(name in values){
if(!_.isArray(values[name])){
values[name] = [values[name]];
}
values[name].push(nameValuePair.value);
}
else{
values[name] = nameValuePair.value;
}
});
return values;
},
serializedObject: function(){
var values = this._serializedObject();
this.first().find("input[type='checkbox'][name]:enabled").each(function(i, checkbox){
values[this.name] = this.checked;
});
return values;
},
submitForm: function(settings){
settings = $.extend({
type: this.attr("method"),
url: this.attr("action"),
data: this.serialize(),
dataType: "html"
}, settings);
return $.ajax(settings);
}
});
var formatWidgetSettings = (function(){
var unnecessaries = ["_method", "authenticity_token"],
keyExtractor = /^\w+\[(\w+)\]$/;
return function(settings){
var formattedSettings = {};
for(var name in settings){
if(_.contains(unnecessaries, name)){
continue;
}
var key = (keyExtractor.test(name) ? name.replace(keyExtractor, "$1") : name);
formattedSettings[key] = settings[name];
}
return formattedSettings;
};
}());
function setUpImporter(){
var $section = $("#widgetSettingsImporter"),
sampleSettings = {
user: {
settings: [
{
widget: "user",
screen_name: "twitter"
}
]
},
favorites: {
settings: [
{
widget: "favorites",
screen_name: "twitter"
}
]
},
list: {
settings: [
{
widget: "list",
list_id: "5157981"
}
]
},
search: {
settings: [
{
widget: "search",
query: "#corgi",
safe_mode: "on"
}
]
},
user_detailed: {
settings: [
{
widget: "user",
screen_name: "twitter",
hide_at_replies: false,
expand_media: false,
height: "500",
theme: "dark",
link_color: "#4aed05",
do_not_track: true
}
]
},
user_multiple: {
settings: [
{
widget: "user",
screen_name: "twitter"
},
{
widget: "user",
screen_name: "twittermobile"
},
{
widget: "user",
screen_name: "Support"
}
]
},
user_multiple_with_defaults: {
defaults: {
widget: "user",
hide_at_replies: true,
expand_media: true,
height: "500",
theme: "dark",
link_color: "#4aed05",
do_not_track: true
},
settings: [
{screen_name: "twitter"},
{screen_name: "twittermobile"},
{screen_name: "Support"}
]
}
},
isValidSettingsJson = function(json){
var settings;
try{
settings = JSON.parse(json);
}
catch(error){
return false;
}
return (
settings &&
_.isArray(settings.settings) &&
settings.settings.length &&
(
(settings.defaults && settings.defaults.widget) ||
settings.settings.every(function(settings, i, settingsArray){
return !!settings.widget;
})
)
);
},
validateSettings = function(event){
var $textarea = $section.find("textarea"),
settingsJson = $textarea.val(),
$button = $section.find("button");
if(settingsJson){
if(isValidSettingsJson(settingsJson)){
$textarea.css({backgroundColor: "rgba(50, 205, 50, 0.2)"});
$button.removeAttr("disabled");
}
else{
$textarea.css({backgroundColor: "rgba(255, 69, 0, 0.2)"});
$button.attr("disabled", true);
}
}
else{
$textarea.css({backgroundColor: "white"});
$button.attr("disabled", true);
}
},
rejecters = $.Callbacks("unique"),
registerRejecter = function(dfd){
rejecters.add(dfd.reject);
return dfd;
},
widgetIdExtractor = /^\/settings\/widgets\/(\w+)$/,
importWidgetSettings = function(settings){
rejecters.empty();
var widgetSettingsArray = settings.settings,
defaultSettings = settings.defaults,
newWidgetSettingsArray = [];
if(defaultSettings){
widgetSettingsArray = widgetSettingsArray.map(function(widgetSettings, i, widgetSettingsArray){
return $.extend({}, defaultSettings, widgetSettings);
});
}
return $.Deferred(function(settingsImporting){
(function(){
if(widgetSettingsArray.length){
settingsImporting.notify(newWidgetSettingsArray.length);
registerRejecter($.Deferred(function(widgetGenerating){
var widgetSettings = widgetSettingsArray.shift();
$.ajax({
type: "GET",
url: "/settings/widgets/new/" + widgetSettings.widget,
dataType: "html"
})
.then(function(html, textStatus, jqXhr){
var $html = $(html),
$widgetForm = $html.find("#widget-form");
return $widgetForm
.populate(_.omit(widgetSettings, "widget"))
.submitForm();
})
.done(function(html, textStatus, jqXhr){
var $html = $(html),
$widgetForm = $html.find("#widget-form"),
action = $widgetForm.attr("action");
if(widgetIdExtractor.test(action)){
var widgetId = action.replace(widgetIdExtractor, "$1"),
newWidgetSettings = $widgetForm.serializedObject(),
code = $html.find("#code").val();
newWidgetSettings = $.extend(
{widget_id: widgetId},
formatWidgetSettings(newWidgetSettings),
{code: code}
);
newWidgetSettingsArray.push(newWidgetSettings);
}
else{
var message = $html.find(".message .message-text").text();
newWidgetSettingsArray.push($.extend({}, widgetSettings, {error: message}));
}
})
.fail(function(jqXhr, textStatus, errorMessage){
newWidgetSettingsArray.push($.extend({}, widgetSettings, {error: errorMessage}));
})
.always(widgetGenerating.resolve);
}))
.done(arguments.callee)
.fail(settingsImporting.reject);
}
else{
settingsImporting.resolve({
settings: newWidgetSettingsArray
});
}
}());
})
.promise();
},
startImport = function(event){
var settingsJson = $section.find("textarea").val();
if(!isValidSettingsJson(settingsJson)){
return false;
}
$section
.find("textarea").attr({readonly: true}).end()
.find("button")
.text("Abort")
.off("click")
.on("click", rejecters.fire);
var settings = JSON.parse(settingsJson),
progressMessageTemplate = "Importing... ($i / $n)".replace("$n", settings.settings.length),
$messageField = $section.find("p.messageField").text("");
importWidgetSettings(settings)
.progress(function(i){
$messageField.text(progressMessageTemplate.replace("$i", i + 1));
})
.done(function(newSettings){
if(win.console && _.isFunction(console.dir)){
console.dir(newSettings);
}
var counts = _.countBy(newSettings.settings, function(settings, i, settingsArray){
return ("error" in settings ? "error" : "success");
}),
messages = [];
if(counts.success){
messages.push(counts.success + " new widget" + (counts.success === 1 ? " has" : "s have") + " been generated successfully.");
if(counts.error){
messages.push("While " + counts.error + " widget generation" + (counts.error === 1 ? " has" : "s have") + " failed.");
}
}
else{
messages.push("All widget generations have failed.");
}
if(counts.error){
messages.push("Please check \"error\" property in settings where the error occurred.");
}
$section
.find("select").attr("disabled", true).end()
.find("textarea")
.val(JSON.stringify(newSettings))
.on("click", function(event){
this.select();
})
.end()
.find("p.messageField").text(messages.join(" ")).end()
.find("button")
.attr({title: "Reload the page to display generated widgets."})
.text("Reload")
.off("click")
.on("click", function(event){
location.reload(true);
});
})
.fail(function(){
var messages = [
"Import was aborted.",
"However several new widgets may have been generated.",
"Please reload the page to check if unnecessary widgets are generated."
];
$section
.find("textarea").removeAttr("readonly").end()
.find("p.messageField").text(messages.join(" ")).end()
.find("button")
.text("Start")
.off("click")
.on("click", startImport);
});
};
var $select = $("<select/>", {
id: "sampleSelector",
css: {
marginTop: "0.5em",
width: "100%"
},
on: {
change: function(event){
var value = $(this).find("option:selected").val();
if(value in sampleSettings){
$section.find("textarea").val(JSON.stringify(sampleSettings[value]));
}
}
}
});
_.each([
["You could view sample settings.", "none"],
["User widget", "user"],
["Favorites widget", "favorites"],
["List widget", "list"],
["Search widget", "search"],
["Detailed user widget", "user_detailed"],
["Multiple user widgets", "user_multiple"],
["Multiple user widgets with defaults", "user_multiple_with_defaults"]
], function(keyValuePair, i, keyValuePairs){
$select.append($("<option/>", {
text: keyValuePair[0],
val: keyValuePair[1],
selected: (i === 0)
}));
});
$section
.find("div.direction")
.text("")
.css({
color: "limegreen",
textShadow: "0 0 2px limegreen"
})
.end()
.find("textarea")
.attr({placeholder: "Please input widget settings."})
.css({cursor: "text"})
.before($select)
.end()
.find("button")
.attr({disabled: true})
.on("click", startImport);
setInterval(validateSettings, 500);
}
function setUpExporter(){
var $section = $("#widgetSettingsExporter").css({marginTop: "0.5em"}),
rejecters = $.Callbacks("unique"),
registerRejecter = function(dfd){
rejecters.add(dfd.reject);
return dfd;
},
widgetIdExtractor = /^\/settings\/widgets\/(\w+)\/edit$/,
exportWidgetSettings = function(widgetEditorPaths){
rejecters.empty();
var widgetSettingsArray = [];
return $.Deferred(function(settingsExporting){
(function(){
if(widgetEditorPaths.length){
settingsExporting.notify(widgetSettingsArray.length);
registerRejecter($.Deferred(function(settingsRetrieving){
var widgetEditorPath = widgetEditorPaths.shift(),
widgetId = widgetEditorPath.replace(widgetIdExtractor, "$1");
$.ajax({
type: "GET",
url: widgetEditorPath,
dataType: "html"
})
.done(function(html, textStatus, jqXhr){
var $html = $(html),
widgetSettings = $html.find("#widget-form").serializedObject(),
code = $html.find("#code").val();
widgetSettings = $.extend(
{widget_id: widgetId},
formatWidgetSettings(widgetSettings),
{code: code}
);
widgetSettingsArray.push(widgetSettings);
})
.fail(function(jqXhr, textStatus, errorMessage){
widgetSettingsArray.push({
widget_id: widgetId,
error: errorMessage
});
})
.always(settingsRetrieving.resolve);
}))
.done(arguments.callee)
.fail(settingsExporting.reject);
}
else{
settingsExporting.resolve({
settings: widgetSettingsArray
});
}
}());
})
.promise();
},
startExport = function(event){
$section
.find("textarea").val("").end()
.find("button")
.text("Abort")
.off("click")
.on("click", rejecters.fire);
var widgetEditorPaths = $("#page-container li.widgets-list-item a.btn-widgets-edit")
.map(function(i, a){
return $(this).attr("href");
})
.toArray(),
progressMessageTemplate = "Exporting... ($i / $n)".replace("$n", widgetEditorPaths.length),
$messageField = $section.find("p.messageField").text("");
exportWidgetSettings(widgetEditorPaths)
.progress(function(i){
$messageField.text(progressMessageTemplate.replace("$i", i + 1));
})
.done(function(settings){
if(win.console && _.isFunction(console.dir)){
console.dir(settings);
}
var counts = _.countBy(settings.settings, function(settings, i, settingsArray){
return ("error" in settings ? "error" : "success");
}),
messages = [];
if(counts.success){
messages.push(counts.success + " widget settings" + (counts.success === 1 ? " has" : " have") + " been retrieved successfully.");
if(counts.error){
messages.push("While " + counts.error + " settings retrieval" + (counts.error === 1 ? " has" : "s have") + " failed.");
}
}
else if(counts.error){
messages.push("All widget settings retrievals have failed.");
}
else{
messages.push("You currently have no widgets.");
}
if(counts.error){
messages.push("Please check \"error\" property in settings where the error occurred.");
}
$section
.find("textarea").val(JSON.stringify(settings)).end()
.find("p.messageField").text(messages.join(" "));
})
.fail(function(){
var messages = ["Export was aborted."];
$section.find("p.messageField").text(messages.join(" "));
})
.always(function(){
$section.find("button")
.text("Start")
.off("click")
.on("click", startExport);
});
};
$section
.find("div.direction")
.text("")
.css({
color: "orangered",
textShadow: "0 0 2px orangered"
})
.end()
.find("textarea")
.attr({readonly: true})
.css({cursor: "text"})
.on("click", function(event){
this.select();
})
.before(function(i){
return $("<label/>", {
"for": this.id,
text: "Exported widget settings:",
css: {
color: "gray",
margin: "0.2em 0 0"
}
});
})
.end()
.find("button")
.on("click", startExport);
}
$(function(){
var $widgetGenerator = $("<section/>", {
"class": "module",
id: "widgetGenerator",
css: {
backgroundColor: "white",
padding: "0.8em"
}
})
.append($("<h1/>", {
text: "Widget generator",
css: {
fontSize: "1.8em",
marginBottom: "0.5em"
}
}))
.insertAfter("#page-container .dashboard .module:eq(1)");
_.each([
{
id: "widgetSettingsImporter",
headingText: "Widget settings import",
textAreaId: "widgetSettings"
},
{
id: "widgetSettingsExporter",
headingText: "Widget settings export",
textAreaId: "exportedWidgetSettings"
}
], function(data, i, dataArray){
$("<section/>", {
id: data.id,
css: {
border: "solid 1px rgba(0, 0, 0, 0.5)",
borderRadius: "0.5em",
overflow: "hidden",
padding: "0.5em",
position: "relative"
}
})
.append($("<div/>", {
"class": "direction",
css: {
fontSize: "1.6em",
position: "absolute",
right: "0.2em",
top: "0.4em"
}
}))
.append($("<h1/>", {
text: data.headingText,
css: {fontSize: "1.2em"}
}))
.append($("<textarea/>", {
id: data.textAreaId,
css: {
backgroundColor: "white",
height: "15em",
margin: "0.2em 0 0.5em",
padding: "2%",
width: "96%"
}
}))
.append($("<button/>", {
"class": "btn",
text: "Start",
css: {
"float": "right",
width: "5em"
}
}))
.append($("<p/>", {
"class": "messageField",
css: {
lineHeight: "1.4",
marginRight: "5em"
}
}))
.appendTo($widgetGenerator);
});
setUpImporter();
setUpExporter();
});
}(_.noConflict(), jQuery.noConflict(true)));
}, [
"//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min.js",
"//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"
]));
}(document, window));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment