1
|
(function(window, $, undefined) {
|
2
|
|
3
|
var JSSOCIALS = "JSSocials",
|
4
|
JSSOCIALS_DATA_KEY = JSSOCIALS;
|
5
|
|
6
|
var getOrApply = function(value, context) {
|
7
|
if($.isFunction(value)) {
|
8
|
return value.apply(context, $.makeArray(arguments).slice(2));
|
9
|
}
|
10
|
return value;
|
11
|
};
|
12
|
|
13
|
var IMG_SRC_REGEX = /(\.(jpeg|png|gif|bmp|svg)$|^data:image\/(jpeg|png|gif|bmp|svg\+xml);base64)/i;
|
14
|
var URL_PARAMS_REGEX = /(&?[a-zA-Z0-9]+=)?\{([a-zA-Z0-9]+)\}/g;
|
15
|
|
16
|
var MEASURES = {
|
17
|
"G": 1000000000,
|
18
|
"M": 1000000,
|
19
|
"K": 1000
|
20
|
};
|
21
|
|
22
|
var shares = {};
|
23
|
|
24
|
function Socials(element, config) {
|
25
|
var $element = $(element);
|
26
|
|
27
|
$element.data(JSSOCIALS_DATA_KEY, this);
|
28
|
|
29
|
this._$element = $element;
|
30
|
|
31
|
this.shares = [];
|
32
|
|
33
|
this._init(config);
|
34
|
this._render();
|
35
|
}
|
36
|
|
37
|
Socials.prototype = {
|
38
|
url: "",
|
39
|
text: "",
|
40
|
shareIn: "blank",
|
41
|
|
42
|
showLabel: function(screenWidth) {
|
43
|
return (this.showCount === false) ?
|
44
|
(screenWidth > this.smallScreenWidth) :
|
45
|
(screenWidth >= this.largeScreenWidth);
|
46
|
},
|
47
|
|
48
|
showCount: function(screenWidth) {
|
49
|
return (screenWidth <= this.smallScreenWidth) ? "inside" : true;
|
50
|
},
|
51
|
|
52
|
smallScreenWidth: 640,
|
53
|
largeScreenWidth: 1024,
|
54
|
|
55
|
resizeTimeout: 200,
|
56
|
|
57
|
elementClass: "jssocials",
|
58
|
sharesClass: "jssocials-shares",
|
59
|
shareClass: "jssocials-share",
|
60
|
shareButtonClass: "jssocials-share-button",
|
61
|
shareLinkClass: "jssocials-share-link",
|
62
|
shareLogoClass: "jssocials-share-logo",
|
63
|
shareLabelClass: "jssocials-share-label",
|
64
|
shareLinkCountClass: "jssocials-share-link-count",
|
65
|
shareCountBoxClass: "jssocials-share-count-box",
|
66
|
shareCountClass: "jssocials-share-count",
|
67
|
shareZeroCountClass: "jssocials-share-no-count",
|
68
|
|
69
|
_init: function(config) {
|
70
|
this._initDefaults();
|
71
|
$.extend(this, config);
|
72
|
this._initShares();
|
73
|
this._attachWindowResizeCallback();
|
74
|
},
|
75
|
|
76
|
_initDefaults: function() {
|
77
|
this.url = window.location.href;
|
78
|
this.text = $.trim($("meta[name=description]").attr("content") || $("title").text());
|
79
|
},
|
80
|
|
81
|
_initShares: function() {
|
82
|
this.shares = $.map(this.shares, $.proxy(function(shareConfig) {
|
83
|
if(typeof shareConfig === "string") {
|
84
|
shareConfig = { share: shareConfig };
|
85
|
}
|
86
|
|
87
|
var share = (shareConfig.share && shares[shareConfig.share]);
|
88
|
|
89
|
if(!share && !shareConfig.renderer) {
|
90
|
throw Error("Share '" + shareConfig.share + "' is not found");
|
91
|
}
|
92
|
|
93
|
return $.extend({ url: this.url, text: this.text }, share, shareConfig);
|
94
|
}, this));
|
95
|
},
|
96
|
|
97
|
_attachWindowResizeCallback: function() {
|
98
|
$(window).on("resize", $.proxy(this._windowResizeHandler, this));
|
99
|
},
|
100
|
|
101
|
_detachWindowResizeCallback: function() {
|
102
|
$(window).off("resize", this._windowResizeHandler);
|
103
|
},
|
104
|
|
105
|
_windowResizeHandler: function() {
|
106
|
if($.isFunction(this.showLabel) || $.isFunction(this.showCount)) {
|
107
|
window.clearTimeout(this._resizeTimer);
|
108
|
this._resizeTimer = setTimeout($.proxy(this.refresh, this), this.resizeTimeout);
|
109
|
}
|
110
|
},
|
111
|
|
112
|
_render: function() {
|
113
|
this._clear();
|
114
|
|
115
|
this._defineOptionsByScreen();
|
116
|
|
117
|
this._$element.addClass(this.elementClass);
|
118
|
|
119
|
this._$shares = $("<div>").addClass(this.sharesClass)
|
120
|
.appendTo(this._$element);
|
121
|
|
122
|
this._renderShares();
|
123
|
},
|
124
|
|
125
|
_defineOptionsByScreen: function() {
|
126
|
this._screenWidth = $(window).width();
|
127
|
this._showLabel = getOrApply(this.showLabel, this, this._screenWidth);
|
128
|
this._showCount = getOrApply(this.showCount, this, this._screenWidth);
|
129
|
},
|
130
|
|
131
|
_renderShares: function() {
|
132
|
$.each(this.shares, $.proxy(function(_, share) {
|
133
|
this._renderShare(share);
|
134
|
}, this));
|
135
|
},
|
136
|
|
137
|
_renderShare: function(share) {
|
138
|
var $share;
|
139
|
|
140
|
if($.isFunction(share.renderer)) {
|
141
|
$share = $(share.renderer());
|
142
|
} else {
|
143
|
$share = this._createShare(share);
|
144
|
}
|
145
|
|
146
|
$share.addClass(this.shareClass)
|
147
|
.addClass(share.share ? "jssocials-share-" + share.share : "")
|
148
|
.addClass(share.css)
|
149
|
.appendTo(this._$shares);
|
150
|
},
|
151
|
|
152
|
_createShare: function(share) {
|
153
|
var $result = $("<div>");
|
154
|
var $shareLink = this._createShareLink(share).appendTo($result);
|
155
|
|
156
|
if(this._showCount) {
|
157
|
var isInsideCount = (this._showCount === "inside");
|
158
|
var $countContainer = isInsideCount ? $shareLink : $("<div>").addClass(this.shareCountBoxClass).appendTo($result);
|
159
|
$countContainer.addClass(isInsideCount ? this.shareLinkCountClass : this.shareCountBoxClass);
|
160
|
this._renderShareCount(share, $countContainer);
|
161
|
}
|
162
|
|
163
|
return $result;
|
164
|
},
|
165
|
|
166
|
_createShareLink: function(share) {
|
167
|
var shareStrategy = this._getShareStrategy(share);
|
168
|
|
169
|
var $result = shareStrategy.call(share, {
|
170
|
shareUrl: this._getShareUrl(share)
|
171
|
});
|
172
|
|
173
|
$result.addClass(this.shareLinkClass)
|
174
|
.append(this._createShareLogo(share));
|
175
|
|
176
|
if(this._showLabel) {
|
177
|
$result.append(this._createShareLabel(share));
|
178
|
}
|
179
|
|
180
|
$.each(this.on || {}, function(event, handler) {
|
181
|
if($.isFunction(handler)) {
|
182
|
$result.on(event, $.proxy(handler, share));
|
183
|
}
|
184
|
});
|
185
|
|
186
|
return $result;
|
187
|
},
|
188
|
|
189
|
_getShareStrategy: function(share) {
|
190
|
var result = shareStrategies[share.shareIn || this.shareIn];
|
191
|
|
192
|
if(!result)
|
193
|
throw Error("Share strategy '" + this.shareIn + "' not found");
|
194
|
|
195
|
return result;
|
196
|
},
|
197
|
|
198
|
_getShareUrl: function(share) {
|
199
|
var shareUrl = getOrApply(share.shareUrl, share);
|
200
|
return this._formatShareUrl(shareUrl, share);
|
201
|
},
|
202
|
|
203
|
_createShareLogo: function(share) {
|
204
|
var logo = share.logo;
|
205
|
|
206
|
var $result = IMG_SRC_REGEX.test(logo) ?
|
207
|
$("<img>").attr("src", share.logo) :
|
208
|
$("<i>").addClass(logo);
|
209
|
|
210
|
$result.addClass(this.shareLogoClass);
|
211
|
|
212
|
return $result;
|
213
|
},
|
214
|
|
215
|
_createShareLabel: function(share) {
|
216
|
return $("<span>").addClass(this.shareLabelClass)
|
217
|
.text(share.label);
|
218
|
},
|
219
|
|
220
|
_renderShareCount: function(share, $container) {
|
221
|
var $count = $("<span>").addClass(this.shareCountClass);
|
222
|
|
223
|
$container.addClass(this.shareZeroCountClass)
|
224
|
.append($count);
|
225
|
|
226
|
this._loadCount(share).done($.proxy(function(count) {
|
227
|
if(count) {
|
228
|
$container.removeClass(this.shareZeroCountClass);
|
229
|
$count.text(count);
|
230
|
}
|
231
|
}, this));
|
232
|
},
|
233
|
|
234
|
_loadCount: function(share) {
|
235
|
var deferred = $.Deferred();
|
236
|
var countUrl = this._getCountUrl(share);
|
237
|
|
238
|
if(!countUrl) {
|
239
|
return deferred.resolve(0).promise();
|
240
|
}
|
241
|
|
242
|
var handleSuccess = $.proxy(function(response) {
|
243
|
deferred.resolve(this._getCountValue(response, share));
|
244
|
}, this);
|
245
|
|
246
|
$.getJSON(countUrl).done(handleSuccess)
|
247
|
.fail(function() {
|
248
|
$.get(countUrl).done(handleSuccess)
|
249
|
.fail(function() {
|
250
|
deferred.resolve(0);
|
251
|
});
|
252
|
});
|
253
|
|
254
|
return deferred.promise();
|
255
|
},
|
256
|
|
257
|
_getCountUrl: function(share) {
|
258
|
var countUrl = getOrApply(share.countUrl, share);
|
259
|
return this._formatShareUrl(countUrl, share);
|
260
|
},
|
261
|
|
262
|
_getCountValue: function(response, share) {
|
263
|
var count = ($.isFunction(share.getCount) ? share.getCount(response) : response) || 0;
|
264
|
return (typeof count === "string") ? count : this._formatNumber(count);
|
265
|
},
|
266
|
|
267
|
_formatNumber: function(number) {
|
268
|
$.each(MEASURES, function(letter, value) {
|
269
|
if(number >= value) {
|
270
|
number = parseFloat((number / value).toFixed(2)) + letter;
|
271
|
return false;
|
272
|
}
|
273
|
});
|
274
|
|
275
|
return number;
|
276
|
},
|
277
|
|
278
|
_formatShareUrl: function(url, share) {
|
279
|
return url.replace(URL_PARAMS_REGEX, function(match, key, field) {
|
280
|
var value = share[field] || "";
|
281
|
return value ? (key || "") + window.encodeURIComponent(value) : "";
|
282
|
});
|
283
|
},
|
284
|
|
285
|
_clear: function() {
|
286
|
window.clearTimeout(this._resizeTimer);
|
287
|
this._$element.empty();
|
288
|
},
|
289
|
|
290
|
_passOptionToShares: function(key, value) {
|
291
|
var shares = this.shares;
|
292
|
|
293
|
$.each(["url", "text"], function(_, optionName) {
|
294
|
if(optionName !== key)
|
295
|
return;
|
296
|
|
297
|
$.each(shares, function(_, share) {
|
298
|
share[key] = value;
|
299
|
});
|
300
|
});
|
301
|
},
|
302
|
|
303
|
_normalizeShare: function(share) {
|
304
|
if($.isNumeric(share)) {
|
305
|
return this.shares[share];
|
306
|
}
|
307
|
|
308
|
if(typeof share === "string") {
|
309
|
return $.grep(this.shares, function(s) {
|
310
|
return s.share === share;
|
311
|
})[0];
|
312
|
}
|
313
|
|
314
|
return share;
|
315
|
},
|
316
|
|
317
|
refresh: function() {
|
318
|
this._render();
|
319
|
},
|
320
|
|
321
|
destroy: function() {
|
322
|
this._clear();
|
323
|
this._detachWindowResizeCallback();
|
324
|
|
325
|
this._$element
|
326
|
.removeClass(this.elementClass)
|
327
|
.removeData(JSSOCIALS_DATA_KEY);
|
328
|
},
|
329
|
|
330
|
option: function(key, value) {
|
331
|
if(arguments.length === 1) {
|
332
|
return this[key];
|
333
|
}
|
334
|
|
335
|
this[key] = value;
|
336
|
|
337
|
this._passOptionToShares(key, value);
|
338
|
|
339
|
this.refresh();
|
340
|
},
|
341
|
|
342
|
shareOption: function(share, key, value) {
|
343
|
share = this._normalizeShare(share);
|
344
|
|
345
|
if(arguments.length === 2) {
|
346
|
return share[key];
|
347
|
}
|
348
|
|
349
|
share[key] = value;
|
350
|
this.refresh();
|
351
|
}
|
352
|
};
|
353
|
|
354
|
|
355
|
$.fn.jsSocials = function(config) {
|
356
|
var args = $.makeArray(arguments),
|
357
|
methodArgs = args.slice(1),
|
358
|
result = this;
|
359
|
|
360
|
this.each(function() {
|
361
|
var $element = $(this),
|
362
|
instance = $element.data(JSSOCIALS_DATA_KEY),
|
363
|
methodResult;
|
364
|
|
365
|
if(instance) {
|
366
|
if(typeof config === "string") {
|
367
|
methodResult = instance[config].apply(instance, methodArgs);
|
368
|
if(methodResult !== undefined && methodResult !== instance) {
|
369
|
result = methodResult;
|
370
|
return false;
|
371
|
}
|
372
|
} else {
|
373
|
instance._detachWindowResizeCallback();
|
374
|
instance._init(config);
|
375
|
instance._render();
|
376
|
}
|
377
|
} else {
|
378
|
new Socials($element, config);
|
379
|
}
|
380
|
});
|
381
|
|
382
|
return result;
|
383
|
};
|
384
|
|
385
|
var setDefaults = function(config) {
|
386
|
var component;
|
387
|
|
388
|
if($.isPlainObject(config)) {
|
389
|
component = Socials.prototype;
|
390
|
} else {
|
391
|
component = shares[config];
|
392
|
config = arguments[1] || {};
|
393
|
}
|
394
|
|
395
|
$.extend(component, config);
|
396
|
};
|
397
|
|
398
|
var shareStrategies = {
|
399
|
popup: function(args) {
|
400
|
return $("<a>").attr("href", "#")
|
401
|
.on("click", function() {
|
402
|
window.open(args.shareUrl, null, "width=600, height=400, location=0, menubar=0, resizeable=0, scrollbars=0, status=0, titlebar=0, toolbar=0");
|
403
|
return false;
|
404
|
});
|
405
|
},
|
406
|
|
407
|
blank: function(args) {
|
408
|
return $("<a>").attr({ target: "_blank", href: args.shareUrl });
|
409
|
},
|
410
|
|
411
|
self: function(args) {
|
412
|
return $("<a>").attr({ target: "_self", href: args.shareUrl });
|
413
|
}
|
414
|
};
|
415
|
|
416
|
window.jsSocials = {
|
417
|
Socials: Socials,
|
418
|
shares: shares,
|
419
|
shareStrategies: shareStrategies,
|
420
|
setDefaults: setDefaults
|
421
|
};
|
422
|
|
423
|
}(window, jQuery));
|
424
|
|