', {'class': prefix + '__single-container'}));
var wrapper = container.parent();
// Widget
var widget = $('
', {
'class': getElementClassNames('widget', 'single')
});
var button = $(template(
'
' +
'
' +
'
',
{
buttonCls: getElementClassNames('button', 'single'),
iconCls: getElementClassNames('icon', 'single'),
title: this.options.singleTitle
}
));
widget.append(button);
wrapper.append(widget);
widget.click(function() {
var activeClass = prefix + '__widget_active';
widget.toggleClass(activeClass);
if (widget.hasClass(activeClass)) {
container.css({left: 70, top: 10});
showInViewport(container);
closeOnClick(container, function() {
widget.removeClass(activeClass);
});
}
else {
container.removeClass(openClass);
}
return false;
});
this.widget = widget;
},
update: function(options) {
if (!options.forceUpdate && options.url === this.options.url) return;
// Reset counters
this.number = 0;
this.countersLeft = this.buttons.length;
if (this.widget) this.widget.find('.' + prefix + '__counter').remove();
// Update options
$.extend(this.options, options);
for (var buttonIdx = 0; buttonIdx < this.buttons.length; buttonIdx++) {
this.buttons[buttonIdx].update(options);
}
},
updateCounter: function(e, service, number) {
if (number) {
this.number += number;
if (this.single) {
this.getCounterElem().text(this.number);
}
}
this.countersLeft--;
if (this.countersLeft === 0) {
this.appear();
this.container.addClass(prefix + '_ready');
this.container.trigger('ready.' + prefix, this.number);
}
},
appear: function() {
this.container.addClass(prefix + '_visible');
},
getCounterElem: function() {
var counterElem = this.widget.find('.' + classPrefix + 'counter_single');
if (!counterElem.length) {
counterElem = $('
', {
'class': getElementClassNames('counter', 'single')
});
this.widget.append(counterElem);
}
return counterElem;
}
};
function Button(widget, options) {
this.widget = widget;
this.options = $.extend({}, options);
this.detectService();
if (this.service) {
this.init();
}
}
Button.prototype = {
init: function() {
this.detectParams();
this.initHtml();
this.initCounter();
},
update: function(options) {
$.extend(this.options, {forceUpdate: false}, options);
this.widget.find('.' + prefix + '__counter').remove(); // Remove old counter
this.initCounter();
},
detectService: function() {
var service = this.widget.data('service');
if (!service) {
// class="facebook"
var node = this.widget[0];
var classes = node.classList || node.className.split(' ');
for (var classIdx = 0; classIdx < classes.length; classIdx++) {
var cls = classes[classIdx];
if (services[cls]) {
service = cls;
break;
}
}
if (!service) return;
}
this.service = service;
$.extend(this.options, services[service]);
},
detectParams: function() {
var data = this.widget.data();
// Custom page counter URL or number
if (data.counter) {
var number = parseInt(data.counter, 10);
if (isNaN(number)) {
this.options.counterUrl = data.counter;
}
else {
this.options.counterNumber = number;
}
}
// Custom page title
if (data.title) {
this.options.title = data.title;
}
// Custom page URL
if (data.url) {
this.options.url = data.url;
}
},
initHtml: function() {
var options = this.options;
var widget = this.widget;
// Old initialization HTML
var a = widget.find('a');
if (a.length) {
this.cloneDataAttrs(a, widget);
}
// Button
var button = $('', {
'class': this.getElementClassNames('button'),
'text': widget.text()
});
if (options.clickUrl) {
var url = makeUrl(options.clickUrl, {
url: options.url,
title: options.title
});
var link = $('', {
href: url
});
this.cloneDataAttrs(widget, link);
widget.replaceWith(link);
this.widget = widget = link;
}
else {
widget.click($.proxy(this.click, this));
}
widget.removeClass(this.service);
widget.addClass(this.getElementClassNames('widget'));
// Icon
button.prepend($('', {'class': this.getElementClassNames('icon')}));
widget.empty().append(button);
this.button = button;
},
initCounter: function() {
if (this.options.counters) {
if (this.options.counterNumber) {
this.updateCounter(this.options.counterNumber);
}
else {
var extraOptions = {
counterUrl: this.options.counterUrl,
forceUpdate: this.options.forceUpdate
};
counters.fetch(this.service, this.options.url, extraOptions)
.always($.proxy(this.updateCounter, this));
}
}
},
cloneDataAttrs: function(source, destination) {
var data = source.data();
for (var key in data) {
if (data.hasOwnProperty(key)) {
destination.data(key, data[key]);
}
}
},
getElementClassNames: function(elem) {
return getElementClassNames(elem, this.service);
},
updateCounter: function(number) {
number = parseInt(number, 10) || 0;
var params = {
'class': this.getElementClassNames('counter'),
'text': number
};
if (!number && !this.options.zeroes) {
params['class'] += ' ' + prefix + '__counter_empty';
params.text = '';
}
var counterElem = $('', params);
this.widget.append(counterElem);
this.widget.trigger('counter.' + prefix, [this.service, number]);
},
click: function(e) {
var options = this.options;
var process = true;
if ($.isFunction(options.click)) {
process = options.click.call(this, e);
}
if (process) {
var url = makeUrl(options.popupUrl, {
url: options.url,
title: options.title
});
url = this.addAdditionalParamsToUrl(url);
this.openPopup(url, {
width: options.popupWidth,
height: options.popupHeight
});
}
return false;
},
addAdditionalParamsToUrl: function(url) {
var params = $.param($.extend(this.widget.data(), this.options.data));
if ($.isEmptyObject(params)) return url;
var glue = url.indexOf('?') === -1 ? '?' : '&';
return url + glue + params;
},
openPopup: function(url, params) {
var left = Math.round(screen.width/2 - params.width/2);
var top = 0;
if (screen.height > params.height) {
top = Math.round(screen.height/3 - params.height/2);
}
var win = window.open(url, 'sl_' + this.service, 'left=' + left + ',top=' + top + ',' +
'width=' + params.width + ',height=' + params.height + ',personalbar=0,toolbar=0,scrollbars=1,resizable=1');
if (win) {
win.focus();
this.widget.trigger('popup_opened.' + prefix, [this.service, win]);
var timer = setInterval($.proxy(function() {
if (!win.closed) return;
clearInterval(timer);
this.widget.trigger('popup_closed.' + prefix, this.service);
}, this), this.options.popupCheckInterval);
}
else {
location.href = url;
}
}
};
/**
* Helpers
*/
// Camelize data-attributes
function dataToOptions(elem) {
function upper(m, l) {
return l.toUpper();
}
var options = {};
var data = elem.data();
for (var key in data) {
var value = data[key];
if (value === 'yes') value = true;
else if (value === 'no') value = false;
options[key.replace(/-(\w)/g, upper)] = value;
}
return options;
}
function makeUrl(url, context) {
return template(url, context, encodeURIComponent);
}
function template(tmpl, context, filter) {
return tmpl.replace(/\{([^\}]+)\}/g, function(m, key) {
// If key doesn't exists in the context we should keep template tag as is
return key in context ? (filter ? filter(context[key]) : context[key]) : m;
});
}
function getElementClassNames(elem, mod) {
var cls = classPrefix + elem;
return cls + ' ' + cls + '_' + mod;
}
function closeOnClick(elem, callback) {
function handler(e) {
if ((e.type === 'keydown' && e.which !== 27) || $(e.target).closest(elem).length) return;
elem.removeClass(openClass);
doc.off(events, handler);
if ($.isFunction(callback)) callback();
}
var doc = $(document);
var events = 'click touchstart keydown';
doc.on(events, handler);
}
function showInViewport(elem) {
var offset = 10;
if (document.documentElement.getBoundingClientRect) {
var left = parseInt(elem.css('left'), 10);
var top = parseInt(elem.css('top'), 10);
var rect = elem[0].getBoundingClientRect();
if (rect.left < offset)
elem.css('left', offset - rect.left + left);
else if (rect.right > window.innerWidth - offset)
elem.css('left', window.innerWidth - rect.right - offset + left);
if (rect.top < offset)
elem.css('top', offset - rect.top + top);
else if (rect.bottom > window.innerHeight - offset)
elem.css('top', window.innerHeight - rect.bottom - offset + top);
}
elem.addClass(openClass);
}
/**
* Auto initialization
*/
$(function() {
$('.' + prefix).socialLikes();
});
}));