Last active
December 14, 2015 21:59
-
-
Save kwixilvr/5154674 to your computer and use it in GitHub Desktop.
Twitter widget generator: This script makes it easy to generate Twitter widget. It works at https://twitter.com/settings/widgets .
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(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