PageRenderTime 49ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/files/socialite/2.1.0/socialite.js

https://gitlab.com/Mirros/jsdelivr
JavaScript | 711 lines | 492 code | 67 blank | 152 comment | 90 complexity | 414a32b80bb5bcac52cc119f34dcdfa9 MD5 | raw file
  1. /*!
  2. * Socialite v2.0
  3. * http://socialitejs.com
  4. * Copyright (c) 2011 David Bushell
  5. * Dual-licensed under the BSD or MIT licenses: http://socialitejs.com/license.txt
  6. */
  7. window.Socialite = (function(window, document, undefined)
  8. {
  9. 'use strict';
  10. var uid = 0,
  11. instances = [ ],
  12. networks = { },
  13. widgets = { },
  14. rstate = /^($|loaded|complete)/,
  15. euc = window.encodeURIComponent;
  16. var socialite = {
  17. settings: { },
  18. trim: function(str)
  19. {
  20. return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g,'');
  21. },
  22. hasClass: function(el, cn)
  23. {
  24. return (' ' + el.className + ' ').indexOf(' ' + cn + ' ') !== -1;
  25. },
  26. addClass: function(el, cn)
  27. {
  28. if (!socialite.hasClass(el, cn)) {
  29. el.className = (el.className === '') ? cn : el.className + ' ' + cn;
  30. }
  31. },
  32. removeClass: function(el, cn)
  33. {
  34. el.className = socialite.trim(' ' + el.className + ' '.replace(' ' + cn + ' ', ' '));
  35. },
  36. /**
  37. * Copy properties of one object to another
  38. */
  39. extendObject: function(to, from, overwrite)
  40. {
  41. for (var prop in from) {
  42. var hasProp = to[prop] !== undefined;
  43. if (hasProp && typeof from[prop] === 'object') {
  44. socialite.extendObject(to[prop], from[prop], overwrite);
  45. } else if (overwrite || !hasProp) {
  46. to[prop] = from[prop];
  47. }
  48. }
  49. },
  50. /**
  51. * Return elements with a specific class
  52. *
  53. * @param context - containing element to search within
  54. * @param cn - class name to search for
  55. *
  56. */
  57. getElements: function(context, cn)
  58. {
  59. // copy to a new array to avoid a live NodeList
  60. var i = 0,
  61. el = [ ],
  62. gcn = !!context.getElementsByClassName,
  63. all = gcn ? context.getElementsByClassName(cn) : context.getElementsByTagName('*');
  64. for (; i < all.length; i++) {
  65. if (gcn || socialite.hasClass(all[i], cn)) {
  66. el.push(all[i]);
  67. }
  68. }
  69. return el;
  70. },
  71. /**
  72. * Return data-* attributes of element as a query string (or object)
  73. *
  74. * @param el - the element
  75. * @param noprefix - (optional) if true, remove "data-" from attribute names
  76. * @param nostr - (optional) if true, return attributes in an object
  77. *
  78. */
  79. getDataAttributes: function(el, noprefix, nostr)
  80. {
  81. var i = 0,
  82. str = '',
  83. obj = { },
  84. attr = el.attributes;
  85. for (; i < attr.length; i++) {
  86. var key = attr[i].name,
  87. val = attr[i].value;
  88. if (val.length && key.indexOf('data-') === 0) {
  89. if (noprefix) {
  90. key = key.substring(5);
  91. }
  92. if (nostr) {
  93. obj[key] = val;
  94. } else {
  95. str += euc(key) + '=' + euc(val) + '&';
  96. }
  97. }
  98. }
  99. return nostr ? obj : str;
  100. },
  101. /**
  102. * Copy data-* attributes from one element to another
  103. *
  104. * @param from - element to copy from
  105. * @param to - element to copy to
  106. * @param noprefix - (optional) if true, remove "data-" from attribute names
  107. * @param nohyphen - (optional) if true, convert hyphens to underscores in the attribute names
  108. *
  109. */
  110. copyDataAttributes: function(from, to, noprefix, nohyphen)
  111. {
  112. // `nohyphen` was needed for Facebook's <fb:like> elements - remove as no longer used?
  113. var attr = socialite.getDataAttributes(from, noprefix, true);
  114. for (var i in attr) {
  115. to.setAttribute(nohyphen ? i.replace(/-/g, '_') : i, attr[i]);
  116. }
  117. },
  118. /**
  119. * Create iframe element
  120. *
  121. * @param src - iframe URL (src attribute)
  122. * @param instance - (optional) socialite instance to activate on iframe load
  123. *
  124. */
  125. createIframe: function(src, instance)
  126. {
  127. // Socialite v2 has slashed the amount of manual iframe creation, we should aim to avoid this entirely
  128. var iframe = document.createElement('iframe');
  129. iframe.style.cssText = 'overflow: hidden; border: none;';
  130. socialite.extendObject(iframe, { src: src, allowtransparency: 'true', frameborder: '0', scrolling: 'no' }, true);
  131. if (instance) {
  132. iframe.onload = iframe.onreadystatechange = function ()
  133. {
  134. if (rstate.test(iframe.readyState || '')) {
  135. iframe.onload = iframe.onreadystatechange = null;
  136. socialite.activateInstance(instance);
  137. }
  138. };
  139. }
  140. return iframe;
  141. },
  142. /**
  143. * Returns true if network script has loaded
  144. */
  145. networkReady: function(name)
  146. {
  147. return networks[name] ? networks[name].loaded : undefined;
  148. },
  149. /**
  150. * Append network script to the document
  151. */
  152. appendNetwork: function(network)
  153. {
  154. // the activation process is getting a little confusing for some networks
  155. // it would appear a script load event does not mean its global object exists yet
  156. // therefore the first call to `activateAll` may have no effect whereas the second call does, e.g. via `window.twttr.ready`
  157. if (!network || network.appended) {
  158. return;
  159. }
  160. // `network.append` and `network.onload` can cancel progress
  161. if (typeof network.append === 'function' && network.append(network) === false) {
  162. network.appended = network.loaded = true;
  163. socialite.activateAll(network);
  164. return;
  165. }
  166. if (network.script) {
  167. network.el = document.createElement('script');
  168. socialite.extendObject(network.el, network.script, true);
  169. network.el.async = true;
  170. network.el.onload = network.el.onreadystatechange = function()
  171. {
  172. if (rstate.test(network.el.readyState || '')) {
  173. network.el.onload = network.el.onreadystatechange = null;
  174. network.loaded = true;
  175. if (typeof network.onload === 'function' && network.onload(network) === false) {
  176. return;
  177. }
  178. socialite.activateAll(network);
  179. }
  180. };
  181. document.body.appendChild(network.el);
  182. }
  183. network.appended = true;
  184. },
  185. /**
  186. * Remove network script from the document
  187. */
  188. removeNetwork: function(network)
  189. {
  190. if (!socialite.networkReady(network.name)) {
  191. return false;
  192. }
  193. if (network.el.parentNode) {
  194. network.el.parentNode.removeChild(network.el);
  195. }
  196. return !(network.appended = network.loaded = false);
  197. },
  198. /**
  199. * Remove and re-append network script to the document
  200. */
  201. reloadNetwork: function(name)
  202. {
  203. // This is a last-ditch effort for half-baked scripts
  204. var network = networks[name];
  205. if (network && socialite.removeNetwork(network)) {
  206. socialite.appendNetwork(network);
  207. }
  208. },
  209. /**
  210. * Create new Socialite instance
  211. *
  212. * @param el - parent element that will hold the new instance
  213. * @param widget - widget the instance belongs to
  214. *
  215. */
  216. createInstance: function(el, widget)
  217. {
  218. var proceed = true,
  219. instance = {
  220. el : el,
  221. uid : uid++,
  222. widget : widget
  223. };
  224. instances.push(instance);
  225. if (widget.process !== undefined) {
  226. proceed = (typeof widget.process === 'function') ? widget.process(instance) : false;
  227. }
  228. if (proceed) {
  229. socialite.processInstance(instance);
  230. }
  231. instance.el.setAttribute('data-socialite', instance.uid);
  232. instance.el.className = 'socialite ' + widget.name + ' socialite-instance';
  233. return instance;
  234. },
  235. /**
  236. * Process a socialite instance to an intermediate state prior to load
  237. */
  238. processInstance: function(instance)
  239. {
  240. var el = instance.el;
  241. instance.el = document.createElement('div');
  242. instance.el.className = el.className;
  243. socialite.copyDataAttributes(el, instance.el);
  244. // stop over-zealous scripts from activating all instances
  245. if (el.nodeName.toLowerCase() === 'a' && !el.getAttribute('data-default-href')) {
  246. instance.el.setAttribute('data-default-href', el.getAttribute('href'));
  247. }
  248. var parent = el.parentNode;
  249. parent.insertBefore(instance.el, el);
  250. parent.removeChild(el);
  251. },
  252. /**
  253. * Activate a socialite instance
  254. */
  255. activateInstance: function(instance)
  256. {
  257. if (instance && !instance.loaded) {
  258. instance.loaded = true;
  259. if (typeof instance.widget.activate === 'function') {
  260. instance.widget.activate(instance);
  261. }
  262. socialite.addClass(instance.el, 'socialite-loaded');
  263. return instance.onload ? instance.onload(instance.el) : null;
  264. }
  265. },
  266. /**
  267. * Activate all socialite instances belonging to a network
  268. */
  269. activateAll: function(network)
  270. {
  271. if (typeof network === 'string') {
  272. network = networks[network];
  273. }
  274. for (var i = 0; i < instances.length; i++) {
  275. var instance = instances[i];
  276. if (instance.init && instance.widget.network === network) {
  277. socialite.activateInstance(instance);
  278. }
  279. }
  280. },
  281. /**
  282. * Load socialite instances
  283. *
  284. * @param context - (optional) containing element to search within
  285. * @param el - (optional) individual or an array of elements to load
  286. * @param w - (optional) widget name
  287. * @param onload - (optional) function to call after each socialite instance has loaded
  288. * @param process - (optional) process but don't load network (if true)
  289. *
  290. */
  291. load: function(context, el, w, onload, process)
  292. {
  293. // use document as context if unspecified
  294. context = (context && typeof context === 'object' && context.nodeType === 1) ? context : document;
  295. // if no elements search within the context and recurse
  296. if (!el || typeof el !== 'object') {
  297. socialite.load(context, socialite.getElements(context, 'socialite'), w, onload, process);
  298. return;
  299. }
  300. var i;
  301. // if array of elements load each one individually
  302. if (/Array/.test(Object.prototype.toString.call(el))) {
  303. for (i = 0; i < el.length; i++) {
  304. socialite.load(context, el[i], w, onload, process);
  305. }
  306. return;
  307. }
  308. // nothing was found...
  309. if (el.nodeType !== 1) {
  310. return;
  311. }
  312. // if widget name not specified search within the element classes
  313. if (!w || !widgets[w]) {
  314. w = null;
  315. var classes = el.className.split(' ');
  316. for (i = 0; i < classes.length; i++) {
  317. if (widgets[classes[i]]) {
  318. w = classes[i];
  319. break;
  320. }
  321. }
  322. if (!w) {
  323. return;
  324. }
  325. }
  326. // find or create the Socialite instance
  327. var instance,
  328. widget = widgets[w],
  329. sid = parseInt(el.getAttribute('data-socialite'), 10);
  330. if (!isNaN(sid)) {
  331. for (i = 0; i < instances.length; i++) {
  332. if (instances[i].uid === sid) {
  333. instance = instances[i];
  334. break;
  335. }
  336. }
  337. } else {
  338. instance = socialite.createInstance(el, widget);
  339. }
  340. // return if just processing (or no instance found)
  341. if (process || !instance) {
  342. return;
  343. }
  344. // initialise the instance
  345. if (!instance.init) {
  346. instance.init = true;
  347. instance.onload = (typeof onload === 'function') ? onload : null;
  348. widget.init(instance);
  349. }
  350. // append the parent network (all instances will be activated onload)
  351. // or activate immediately if network has already loaded
  352. if (!widget.network.appended) {
  353. socialite.appendNetwork(widget.network);
  354. } else {
  355. if (socialite.networkReady(widget.network.name)) {
  356. socialite.activateInstance(instance);
  357. }
  358. }
  359. },
  360. /**
  361. * Load a single element
  362. *
  363. * @param el - an individual element
  364. * @param w - (optional) widget for this socialite instance
  365. * @param onload - (optional) function to call once each instance has loaded
  366. *
  367. */
  368. activate: function(el, w, onload)
  369. {
  370. // skip the first few steps
  371. window.Socialite.load(null, el, w, onload);
  372. },
  373. /**
  374. * Process elements to an intermediate state prior to load
  375. *
  376. * @param context - containing element to search within
  377. * @param el - (optional) individual or an array of elements to load
  378. * @param w - (optional) widget name
  379. *
  380. */
  381. process: function(context, el, w)
  382. {
  383. // stop before widget initialises instance
  384. window.Socialite.load(context, el, w, null, true);
  385. },
  386. /**
  387. * Add a new social network
  388. *
  389. * @param name - unique name for network
  390. * @param params - additional data and callbacks
  391. *
  392. */
  393. network: function(n, params)
  394. {
  395. networks[n] = {
  396. name : n,
  397. el : null,
  398. appended : false,
  399. loaded : false,
  400. widgets : { }
  401. };
  402. if (params) {
  403. socialite.extendObject(networks[n], params);
  404. }
  405. },
  406. /**
  407. * Add a new social widget
  408. *
  409. * @param name - name of owner network
  410. * @param w - unique name for widget
  411. * @param params - additional data and callbacks
  412. *
  413. */
  414. widget: function(n, w, params)
  415. {
  416. params.name = n + '-' + w;
  417. if (!networks[n] || widgets[params.name]) {
  418. return;
  419. }
  420. params.network = networks[n];
  421. networks[n].widgets[w] = widgets[params.name] = params;
  422. },
  423. /**
  424. * Change the default Socialite settings for each network
  425. */
  426. setup: function(params)
  427. {
  428. socialite.extendObject(socialite.settings, params, true);
  429. }
  430. };
  431. return socialite;
  432. })(window, window.document);
  433. /**
  434. * Socialite Extensions - Pick 'n' Mix!
  435. */
  436. (function(window, document, Socialite, undefined)
  437. {
  438. // default to the Queen's English
  439. Socialite.setup({
  440. facebook: {
  441. lang: 'en_GB',
  442. appId: null
  443. },
  444. twitter: {
  445. lang: 'en'
  446. },
  447. googleplus: {
  448. lang: 'en-GB'
  449. }
  450. });
  451. // Facebook
  452. // http://developers.facebook.com/docs/reference/plugins/like/
  453. // http://developers.facebook.com/docs/reference/javascript/FB.init/
  454. Socialite.network('facebook', {
  455. script: {
  456. src : '//connect.facebook.net/{{language}}/all.js',
  457. id : 'facebook-jssdk'
  458. },
  459. append: function(network)
  460. {
  461. var fb = document.createElement('div'),
  462. settings = Socialite.settings.facebook,
  463. events = { onlike: 'edge.create', onunlike: 'edge.remove', onsend: 'message.send' };
  464. fb.id = 'fb-root';
  465. document.body.appendChild(fb);
  466. network.script.src = network.script.src.replace('{{language}}', settings.lang);
  467. window.fbAsyncInit = function() {
  468. window.FB.init({
  469. appId: settings.appId,
  470. xfbml: true
  471. });
  472. for (var e in events) {
  473. if (typeof settings[e] === 'function') {
  474. window.FB.Event.subscribe(events[e], settings[e]);
  475. }
  476. }
  477. };
  478. }
  479. });
  480. var facebookInit = function(instance)
  481. {
  482. var el = document.createElement('div');
  483. el.className = instance.widget.fbtype;
  484. Socialite.copyDataAttributes(instance.el, el);
  485. instance.el.appendChild(el);
  486. if (window.FB && window.FB.XFBML) {
  487. window.FB.XFBML.parse(instance.el);
  488. }
  489. };
  490. Socialite.widget('facebook', 'like', { init: facebookInit, fbtype: 'fb-like' });
  491. Socialite.widget('facebook', 'share', { init: facebookInit, fbtype: 'fb-share-button' });
  492. // Twitter
  493. // https://dev.twitter.com/docs/tweet-button/
  494. // https://dev.twitter.com/docs/intents/events/
  495. // https://developers.google.com/analytics/devguides/collection/gajs/gaTrackingSocial#twitter
  496. Socialite.network('twitter', {
  497. script: {
  498. src : '//platform.twitter.com/widgets.js',
  499. id : 'twitter-wjs',
  500. charset : 'utf-8'
  501. },
  502. append: function()
  503. {
  504. var notwttr = (typeof window.twttr !== 'object'),
  505. settings = Socialite.settings.twitter,
  506. events = ['click', 'tweet', 'retweet', 'favorite', 'follow'];
  507. if (notwttr) {
  508. window.twttr = (t = { _e: [], ready: function(f) { t._e.push(f); } });
  509. }
  510. window.twttr.ready(function(twttr)
  511. {
  512. for (var i = 0; i < events.length; i++) {
  513. var e = events[i];
  514. if (typeof settings['on' + e] === 'function') {
  515. twttr.events.bind(e, settings['on' + e]);
  516. }
  517. }
  518. Socialite.activateAll('twitter');
  519. });
  520. return notwttr;
  521. }
  522. });
  523. var twitterInit = function(instance)
  524. {
  525. var el = document.createElement('a');
  526. el.className = instance.widget.name + '-button';
  527. Socialite.copyDataAttributes(instance.el, el);
  528. el.setAttribute('href', instance.el.getAttribute('data-default-href'));
  529. el.setAttribute('data-lang', instance.el.getAttribute('data-lang') || Socialite.settings.twitter.lang);
  530. instance.el.appendChild(el);
  531. };
  532. var twitterActivate = function(instance)
  533. {
  534. if (window.twttr && typeof window.twttr.widgets === 'object' && typeof window.twttr.widgets.load === 'function') {
  535. window.twttr.widgets.load();
  536. }
  537. };
  538. Socialite.widget('twitter', 'share', { init: twitterInit, activate: twitterActivate });
  539. Socialite.widget('twitter', 'follow', { init: twitterInit, activate: twitterActivate });
  540. Socialite.widget('twitter', 'hashtag', { init: twitterInit, activate: twitterActivate });
  541. Socialite.widget('twitter', 'mention', { init: twitterInit, activate: twitterActivate });
  542. Socialite.widget('twitter', 'timeline', { init: twitterInit, activate: twitterActivate });
  543. Socialite.widget('twitter', 'embed', {
  544. process: function(instance)
  545. {
  546. instance.innerEl = instance.el;
  547. if (!instance.innerEl.getAttribute('data-lang')) {
  548. instance.innerEl.setAttribute('data-lang', Socialite.settings.twitter.lang);
  549. }
  550. instance.el = document.createElement('div');
  551. instance.el.className = instance.innerEl.className;
  552. instance.innerEl.className = '';
  553. instance.innerEl.parentNode.insertBefore(instance.el, instance.innerEl);
  554. instance.el.appendChild(instance.innerEl);
  555. },
  556. init: function(instance)
  557. {
  558. instance.innerEl.className = 'twitter-tweet';
  559. },
  560. activate: twitterActivate
  561. });
  562. // Google+
  563. // https://developers.google.com/+/plugins/+1button/
  564. // Google does not support IE7
  565. Socialite.network('googleplus', {
  566. script: {
  567. src: '//apis.google.com/js/plusone.js'
  568. },
  569. append: function(network)
  570. {
  571. if (window.gapi) {
  572. return false;
  573. }
  574. window.___gcfg = {
  575. lang: Socialite.settings.googleplus.lang,
  576. parsetags: 'explicit'
  577. };
  578. }
  579. });
  580. var googleplusInit = function(instance)
  581. {
  582. var el = document.createElement('div');
  583. el.className = 'g-' + instance.widget.gtype;
  584. Socialite.copyDataAttributes(instance.el, el);
  585. instance.el.appendChild(el);
  586. instance.gplusEl = el;
  587. };
  588. var googleplusEvent = function(instance, callback) {
  589. return (typeof callback !== 'function') ? null : function(data) {
  590. callback(instance.el, data);
  591. };
  592. };
  593. var googleplusActivate = function(instance)
  594. {
  595. var type = instance.widget.gtype;
  596. if (window.gapi && window.gapi[type]) {
  597. var settings = Socialite.settings.googleplus,
  598. params = Socialite.getDataAttributes(instance.el, true, true),
  599. events = ['onstartinteraction', 'onendinteraction', 'callback'];
  600. for (var i = 0; i < events.length; i++) {
  601. params[events[i]] = googleplusEvent(instance, settings[events[i]]);
  602. }
  603. window.gapi[type].render(instance.gplusEl, params);
  604. }
  605. };
  606. Socialite.widget('googleplus', 'one', { init: googleplusInit, activate: googleplusActivate, gtype: 'plusone' });
  607. Socialite.widget('googleplus', 'share', { init: googleplusInit, activate: googleplusActivate, gtype: 'plus' });
  608. Socialite.widget('googleplus', 'badge', { init: googleplusInit, activate: googleplusActivate, gtype: 'plus' });
  609. Socialite.widget('googleplus', 'follow', { init: googleplusInit, activate: googleplusActivate, gtype: 'follow' });
  610. // LinkedIn
  611. // http://developer.linkedin.com/plugins/share-button/
  612. Socialite.network('linkedin', {
  613. script: {
  614. src: '//platform.linkedin.com/in.js'
  615. }
  616. });
  617. var linkedinInit = function(instance)
  618. {
  619. var el = document.createElement('script');
  620. el.type = 'IN/' + instance.widget.intype;
  621. Socialite.copyDataAttributes(instance.el, el);
  622. instance.el.appendChild(el);
  623. if (typeof window.IN === 'object' && typeof window.IN.parse === 'function') {
  624. window.IN.parse(instance.el);
  625. Socialite.activateInstance(instance);
  626. }
  627. };
  628. Socialite.widget('linkedin', 'share', { init: linkedinInit, intype: 'Share' });
  629. Socialite.widget('linkedin', 'recommend', { init: linkedinInit, intype: 'RecommendProduct' });
  630. Socialite.widget('linkedin', 'follow', { init: linkedinInit, intype: 'FollowCompany' });
  631. })(window, window.document, window.Socialite);
  632. /**
  633. * Execute any queued functions (don't enqueue before the document has loaded!)
  634. */
  635. (function() {
  636. var s = window._socialite;
  637. if (/Array/.test(Object.prototype.toString.call(s))) {
  638. for (var i = 0, len = s.length; i < len; i++) {
  639. if (typeof s[i] === 'function') {
  640. s[i]();
  641. }
  642. }
  643. }
  644. })();