259 lines
6.7 KiB
JavaScript
259 lines
6.7 KiB
JavaScript
|
/* Author: Artem Sapegin, http://sapegin.me, 2012 */
|
||
|
|
||
|
/*global tamia:false, doT:true, htmlhl:false, JSZip:false, store:false */
|
||
|
;(function ($) {
|
||
|
'use strict';
|
||
|
|
||
|
$.extend(doT.templateSettings, {
|
||
|
strip: false,
|
||
|
varname: '$'
|
||
|
});
|
||
|
|
||
|
var lang = $('html').attr('lang'),
|
||
|
skins = ['flat', 'classic', 'birman'],
|
||
|
skin = 'classic',
|
||
|
downloadData = {
|
||
|
lang: lang,
|
||
|
jquery_ver: jQuery.fn.jquery,
|
||
|
footer: $('#index_footer_tmpl').html(),
|
||
|
html: '',
|
||
|
skin: skin
|
||
|
},
|
||
|
prefix = location.hostname === '127.0.0.1' ? '' : '/social-likes/',
|
||
|
sourceFiles = {
|
||
|
'social-likes.min.js': {url: prefix + 'src/social-likes.min.js'},
|
||
|
'social-likes_{skin}.css': {url: prefix + 'src/social-likes_{skin}.css'}
|
||
|
},
|
||
|
templateIndex = doT.template($('#index_tmpl').html().replace(/\\\//g, '/')),
|
||
|
experimental = location.hash === '#ponies',
|
||
|
// simple = !('download' in document.createElement('a'));
|
||
|
simple = true; // Because of bug in Chrome 35: https://code.google.com/p/chromium/issues/detail?id=377860
|
||
|
|
||
|
// stackoverflow.com/questions/1184624/convert-form-data-to-js-object-with-jquery
|
||
|
$.fn.serializeObject = function() {
|
||
|
var o = {};
|
||
|
var a = this.serializeArray();
|
||
|
$.each(a, function() {
|
||
|
if (o[this.name] !== undefined) {
|
||
|
if (!o[this.name].push) {
|
||
|
o[this.name] = [o[this.name]];
|
||
|
}
|
||
|
o[this.name].push(this.value || '');
|
||
|
} else {
|
||
|
o[this.name] = this.value || '';
|
||
|
}
|
||
|
});
|
||
|
return o;
|
||
|
};
|
||
|
|
||
|
|
||
|
// jasonwyatt.tumblr.com/post/10481498815/how-to-correctly-debounce-a-javascript-function
|
||
|
function debounce(fn, debounceDuration){
|
||
|
// summary:
|
||
|
// Returns a debounced function that will make sure the given
|
||
|
// function is not triggered too much.
|
||
|
// fn: Function
|
||
|
// Function to debounce.
|
||
|
// debounceDuration: Number
|
||
|
// OPTIONAL. The amount of time in milliseconds for which we
|
||
|
// will debounce the function. (defaults to 100ms)
|
||
|
|
||
|
debounceDuration = debounceDuration || 100;
|
||
|
|
||
|
return function(){
|
||
|
if (!fn.debouncing) {
|
||
|
fn.debouncing = true;
|
||
|
}
|
||
|
clearTimeout(fn.debounceTimeout);
|
||
|
var args = Array.prototype.slice.apply(arguments);
|
||
|
fn.debounceTimeout = setTimeout(function() {
|
||
|
fn.lastReturnVal = fn.apply(window, args);
|
||
|
fn.debouncing = false;
|
||
|
}, debounceDuration);
|
||
|
|
||
|
return fn.lastReturnVal;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function escapeValue(value) {
|
||
|
return value
|
||
|
.replace(/&/g, '&')
|
||
|
.replace(/</g, '<')
|
||
|
.replace(/>/g, '>')
|
||
|
.replace(/"/g, '"')
|
||
|
;
|
||
|
}
|
||
|
|
||
|
function escapeFormData(data) {
|
||
|
var fields = ['url', 'title', 'twitter_via', 'twitter_related', 'pinterest_media'];
|
||
|
for (var fieldIdx = 0; fieldIdx < fields.length; fieldIdx++) {
|
||
|
var field = fields[fieldIdx];
|
||
|
data[field] = escapeValue(data[field]);
|
||
|
}
|
||
|
return data;
|
||
|
}
|
||
|
|
||
|
function fillForm(form, data) {
|
||
|
jQuery.each(data, function(name, value) {
|
||
|
var field = form.find('[name="' + name + '"]'),
|
||
|
type = field.attr('type');
|
||
|
switch (type) {
|
||
|
case 'checkbox':
|
||
|
field.prop('checked', !!value);
|
||
|
break;
|
||
|
case 'radio':
|
||
|
field.filter('[value="' + value + '"]').prop('checked', true);
|
||
|
break;
|
||
|
default:
|
||
|
field.val(value);
|
||
|
break;
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function cleanHtml(code) {
|
||
|
return code
|
||
|
.replace(/\n[\n\t]*\n/g, '\n') // Remove empty lines
|
||
|
.replace(/ {2,}/g, ' ') // Remove extra spaces
|
||
|
;
|
||
|
}
|
||
|
|
||
|
function highlight(code) {
|
||
|
return htmlhl(code.replace(/\\\//g, '/'));
|
||
|
}
|
||
|
|
||
|
function download(e) {
|
||
|
var files = getFiles();
|
||
|
|
||
|
var zip = new JSZip();
|
||
|
zip.file('index.html', templateIndex(downloadData));
|
||
|
|
||
|
for (var fileName in files) {
|
||
|
zip.file(fileName, files[fileName]);
|
||
|
}
|
||
|
|
||
|
var content = zip.generate();
|
||
|
|
||
|
if (simple) {
|
||
|
var form = $('#download-proxy'),
|
||
|
field = form.find('[name="content"]');
|
||
|
field.val(content);
|
||
|
form.submit();
|
||
|
return false;
|
||
|
}
|
||
|
else {
|
||
|
$(e.target).attr('href', 'data:application/zip;base64,' + content);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function getFiles() {
|
||
|
var files = {};
|
||
|
for (var fileName in sourceFiles) {
|
||
|
files[getFilenameForSkin(fileName)] = getFile(fileName);
|
||
|
}
|
||
|
return files;
|
||
|
}
|
||
|
|
||
|
function getFile(fileName) {
|
||
|
var file = sourceFiles[fileName];
|
||
|
var url = getFilenameForSkin(file.url);
|
||
|
if (!file.files) file.files = {};
|
||
|
if (!file.files[url]) {
|
||
|
$.ajax(url, { async: false, dataType: 'html' }).then(function(data) {
|
||
|
file.files[url] = data;
|
||
|
});
|
||
|
}
|
||
|
return file.files[url];
|
||
|
}
|
||
|
|
||
|
function getFilenameForSkin(fileName) {
|
||
|
return fileName.replace('{skin}', skin);
|
||
|
}
|
||
|
|
||
|
tamia.initComponents({
|
||
|
builder: function(elem) {
|
||
|
var form = $(elem),
|
||
|
preview = $('.js-preview'),
|
||
|
code = $('.js-code'),
|
||
|
twitterExtra = form.find('.js-twitter-extra'),
|
||
|
pinterestExtra = form.find('.js-pinterest-extra'),
|
||
|
lightStyle = form.find('.js-light'),
|
||
|
prepend = doT.template($('#prepend_tmpl').html()),
|
||
|
template = doT.template($('#build_tmpl').html()),
|
||
|
previous;
|
||
|
|
||
|
var delayedUpdate = debounce(function(html, data) {
|
||
|
// Switch skin
|
||
|
skin = data.skin;
|
||
|
|
||
|
$.each(skins, function(i, s) {
|
||
|
$('#styles_' + s).prop('disabled', s !== skin);
|
||
|
});
|
||
|
|
||
|
// Render preview
|
||
|
preview.attr('class', preview.attr('class').replace(/(preview_)\w+/, '$1' + data.type));
|
||
|
preview.html(html);
|
||
|
preview.find('.social-likes').socialLikes();
|
||
|
|
||
|
form.find('.js-experimental').toggleClass('is-hidden', !experimental);
|
||
|
|
||
|
store.set(lang, {
|
||
|
skin: skin,
|
||
|
type: data.type,
|
||
|
counters: !!data.counters,
|
||
|
light: !!data.light,
|
||
|
title: data.title,
|
||
|
url: data.url,
|
||
|
site_facebook: !!data.site_facebook,
|
||
|
site_mailru: !!data.site_mailru,
|
||
|
site_odnoklassniki: !!data.site_odnoklassniki,
|
||
|
site_plusone: !!data.site_plusone,
|
||
|
site_twitter: !!data.site_twitter,
|
||
|
site_pinterest: !!data.site_pinterest,
|
||
|
site_vkontakte: !!data.site_vkontakte,
|
||
|
twitter_related: data.twitter_related,
|
||
|
twitter_via: data.twitter_via,
|
||
|
pinterest_media: data.pinterest_media
|
||
|
});
|
||
|
});
|
||
|
|
||
|
var loadOptions = function() {
|
||
|
var data = store.get(lang);
|
||
|
if (data) fillForm(form, data);
|
||
|
};
|
||
|
|
||
|
function update() {
|
||
|
var dataString = form.serialize();
|
||
|
if (dataString !== previous) {
|
||
|
var data = escapeFormData(form.serializeObject());
|
||
|
data.experimental = experimental;
|
||
|
|
||
|
twitterExtra.toggleClass('is-hidden', data.site_twitter !== '1');
|
||
|
pinterestExtra.toggleClass('is-hidden', data.site_pinterest !== '1');
|
||
|
lightStyle.toggleClass('is-hidden', data.skin !== 'flat');
|
||
|
|
||
|
var html = cleanHtml(template(data));
|
||
|
code.html(highlight(prepend(data) + html));
|
||
|
delayedUpdate(html, data);
|
||
|
downloadData.html = html;
|
||
|
downloadData.skin = data.skin;
|
||
|
|
||
|
previous = dataString;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
loadOptions();
|
||
|
|
||
|
form.on('change input', 'input', update);
|
||
|
update();
|
||
|
|
||
|
form.submit(function() {
|
||
|
return false;
|
||
|
});
|
||
|
|
||
|
$('.js-download').click(download);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
}(jQuery));
|