social-share.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. /**
  2. * social-share.js
  3. *
  4. * @author 52cik <fe.52cik@gmail.com>
  5. * @license MIT
  6. *
  7. * @example
  8. * <pre>
  9. * socialShare('.share-components');
  10. *
  11. * // or
  12. *
  13. * socialShare('.share-bar', {
  14. * sites: ['qzone', 'qq', 'weibo','wechat'],
  15. * // ...
  16. * });
  17. * </pre>
  18. */
  19. ;(function (window, document, undefined) {
  20. // Initialize a variables.
  21. var Array$indexOf = Array.prototype.indexOf;
  22. var Object$assign = Object.assign;
  23. var runningInWeChat = /MicroMessenger/i.test(navigator.userAgent);
  24. var isMobileScreen = document.documentElement.clientWidth <= 768;
  25. var image = (document.images[0] || 0).src || '';
  26. var site = getMetaContentByName('site') || getMetaContentByName('Site') || document.title;
  27. var title = getMetaContentByName('title') || getMetaContentByName('Title') || document.title;
  28. var description = getMetaContentByName('description') || getMetaContentByName('Description') || '';
  29. var defaults = {
  30. url: location.href,
  31. origin: location.origin,
  32. source: site,
  33. title: title,
  34. description: description,
  35. image: image,
  36. imageSelector: undefined,
  37. weiboKey: '',
  38. // wechatQrcodeTitle: '微信扫一扫:分享',
  39. // wechatQrcodeHelper: '<p>微信里点“发现”,扫一下</p><p>二维码便可将本文分享至朋友圈。</p>',
  40. // wechatQrcodeSize: 100,
  41. sites: ['weibo', 'qq', 'wechat', 'tencent', 'douban', 'qzone', 'linkedin', 'diandian', 'facebook', 'twitter', 'google'],
  42. mobileSites: [],
  43. disabled: [],
  44. initialized: false
  45. };
  46. var templates = {
  47. qzone: 'http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url={{URL}}&title={{TITLE}}&desc={{DESCRIPTION}}&summary={{SUMMARY}}&site={{SOURCE}}',
  48. qq: 'http://connect.qq.com/widget/shareqq/index.html?url={{URL}}&title={{TITLE}}&source={{SOURCE}}&desc={{DESCRIPTION}}&pics={{IMAGE}}&summary="{{SUMMARY}}"',
  49. tencent: 'http://share.v.t.qq.com/index.php?c=share&a=index&title={{TITLE}}&url={{URL}}&pic={{IMAGE}}',
  50. weibo: 'https://service.weibo.com/share/share.php?url={{URL}}&title={{TITLE}}&pic={{IMAGE}}&appkey={{WEIBOKEY}}',
  51. wechat: '#',//'javascript:',
  52. douban: 'http://shuo.douban.com/!service/share?href={{URL}}&name={{TITLE}}&text={{DESCRIPTION}}&image={{IMAGE}}&starid=0&aid=0&style=11',
  53. diandian: 'http://www.diandian.com/share?lo={{URL}}&ti={{TITLE}}&type=link',
  54. linkedin: 'http://www.linkedin.com/shareArticle?mini=true&ro=true&title={{TITLE}}&url={{URL}}&summary={{SUMMARY}}&source={{SOURCE}}&armin=armin',
  55. facebook: 'https://www.facebook.com/sharer/sharer.php?u={{URL}}',
  56. twitter: 'https://twitter.com/intent/tweet?text={{TITLE}}&url={{URL}}&via={{ORIGIN}}',
  57. google: 'https://plus.google.com/share?url={{URL}}'
  58. };
  59. /**
  60. * Expose API to the global
  61. *
  62. * @param {String|Element} elem
  63. * @param {Object} options
  64. */
  65. window.socialShare = function (elem, options) {
  66. elem = typeof elem === 'string' ? querySelectorAlls(elem) : elem;
  67. if (elem.length === undefined) {
  68. elem = [elem];
  69. }
  70. each(elem, function (el) {
  71. if (!el.initialized) {
  72. share(el, options);
  73. }
  74. });
  75. };
  76. // Domready after initialization
  77. alReady(function () {
  78. socialShare('.social-share, .share-component');
  79. });
  80. /**
  81. * Initialize a share bar.
  82. *
  83. * @param {Object} $options globals (optional).
  84. *
  85. * @return {Void}
  86. */
  87. function share(elem, options) {
  88. var data = mixin({}, defaults, options || {}, dataset(elem));
  89. if (data.imageSelector) {
  90. data.image = querySelectorAlls(data.imageSelector).map(function(item) {
  91. return item.src;
  92. }).join('||');
  93. }
  94. addClass(elem, 'share-component social-share');
  95. createIcons(elem, data);
  96. createWechat(elem, data);
  97. elem.initialized = true;
  98. }
  99. /**
  100. * Create site icons
  101. *
  102. * @param {Element} elem
  103. * @param {Object} data
  104. */
  105. function createIcons(elem, data) {
  106. var sites = getSites(data);
  107. var isPrepend = data.mode == 'prepend';
  108. each(isPrepend ? sites.reverse() : sites, function (name) {
  109. var url = makeUrl(name, data);
  110. var link = data.initialized ? getElementsByClassName(elem, 'icon-' + name) : createElementByString('<a class="social-share-icon icon-' + name + '"></a>');
  111. if (!link.length) {
  112. return true;
  113. }
  114. link[0].href = url;
  115. if (name === 'wechat') {
  116. link[0].tabindex = -1;
  117. } else {
  118. link[0].target = '_blank';
  119. }
  120. if (!data.initialized) {
  121. isPrepend ? elem.insertBefore(link[0], elem.firstChild) : elem.appendChild(link[0]);
  122. }
  123. });
  124. }
  125. /**
  126. * Create the wechat icon and QRCode.
  127. *
  128. * @param {Element} elem
  129. * @param {Object} data
  130. */
  131. function createWechat (elem, data) {
  132. var wechat = getElementsByClassName(elem, 'icon-wechat', 'a');
  133. if (wechat.length === 0) {
  134. return false;
  135. }
  136. /* var elems = createElementByString('<div class="wechat-qrcode"><h4>' + data.wechatQrcodeTitle + '</h4><div class="qrcode"></div><div class="help">' + data.wechatQrcodeHelper + '</div></div>');
  137. var qrcode = getElementsByClassName(elems[0], 'qrcode', 'div');
  138. wechat[0].appendChild(elems[0]);
  139. new QRCode(qrcode[0], {text: data.url, width: data.wechatQrcodeSize, height: data.wechatQrcodeSize});*/
  140. }
  141. /**
  142. * Get available site lists.
  143. *
  144. * @param {Object} data
  145. *
  146. * @returns {Array}
  147. */
  148. function getSites(data) {
  149. if (!data['mobileSites'].length) {
  150. data['mobileSites'] = data['sites'];
  151. }
  152. var sites = (isMobileScreen ? data['mobileSites'] : data['sites']).slice(0);
  153. var disabled = data['disabled'];
  154. if (typeof sites == 'string') {
  155. sites = sites.split(/\s*,\s*/);
  156. }
  157. if (typeof disabled == 'string') {
  158. disabled = disabled.split(/\s*,\s*/);
  159. }
  160. if (runningInWeChat) {
  161. disabled.push('wechat');
  162. }
  163. // Remove elements
  164. disabled.length && each(disabled, function (it) {
  165. sites.splice(inArray(it, sites), 1);
  166. });
  167. return sites;
  168. }
  169. /**
  170. * Build the url of icon.
  171. *
  172. * @param {String} name
  173. * @param {Object} data
  174. *
  175. * @returns {String}
  176. */
  177. function makeUrl(name, data) {
  178. if (! data['summary']){
  179. data['summary'] = data['description'];
  180. }
  181. return templates[name].replace(/\{\{(\w)(\w*)\}\}/g, function (m, fix, key) {
  182. var nameKey = name + fix + key.toLowerCase();
  183. key = (fix + key).toLowerCase();
  184. return encodeURIComponent((data[nameKey] === undefined ? data[key] : data[nameKey]) || '');
  185. });
  186. }
  187. /**
  188. * Supports querySelectorAll, jQuery, Zepto and simple selector.
  189. *
  190. * @param str
  191. *
  192. * @returns {*}
  193. */
  194. function querySelectorAlls(str) {
  195. return (document.querySelectorAll || window.jQuery || window.Zepto || selector).call(document, str);
  196. }
  197. /**
  198. * Simple selector.
  199. *
  200. * @param {String} str #ID or .CLASS
  201. *
  202. * @returns {Array}
  203. */
  204. function selector(str) {
  205. var elems = [];
  206. each(str.split(/\s*,\s*/), function(s) {
  207. var m = s.match(/([#.])(\w+)/);
  208. if (m === null) {
  209. throw Error('Supports only simple single #ID or .CLASS selector.');
  210. }
  211. if (m[1]) {
  212. var elem = document.getElementById(m[2]);
  213. if (elem) {
  214. elems.push(elem);
  215. }
  216. }
  217. elems = elems.concat(getElementsByClassName(str));
  218. });
  219. return elems;
  220. }
  221. /**
  222. * Add the classNames for element.
  223. *
  224. * @param {Element} elem
  225. * @param {String} value
  226. */
  227. function addClass(elem, value) {
  228. if (value && typeof value === "string") {
  229. var classNames = (elem.className + ' ' + value).split(/\s+/);
  230. var setClass = ' ';
  231. each(classNames, function (className) {
  232. if (setClass.indexOf(' ' + className + ' ') < 0) {
  233. setClass += className + ' ';
  234. }
  235. });
  236. elem.className = setClass.slice(1, -1);
  237. }
  238. }
  239. /**
  240. * Get meta element content value
  241. *
  242. * @param {String} name
  243. *
  244. * @returns {String|*}
  245. */
  246. function getMetaContentByName(name) {
  247. return (document.getElementsByName(name)[0] || 0).content;
  248. }
  249. /**
  250. * Get elements By className for IE8-
  251. *
  252. * @param {Element} elem element
  253. * @param {String} name className
  254. * @param {String} tag tagName
  255. *
  256. * @returns {HTMLCollection|Array}
  257. */
  258. function getElementsByClassName(elem, name, tag) {
  259. if (elem.getElementsByClassName) {
  260. return elem.getElementsByClassName(name);
  261. }
  262. var elements = [];
  263. var elems = elem.getElementsByTagName(tag || '*');
  264. name = ' ' + name + ' ';
  265. each(elems, function (elem) {
  266. if ((' ' + (elem.className || '') + ' ').indexOf(name) >= 0) {
  267. elements.push(elem);
  268. }
  269. });
  270. return elements;
  271. }
  272. /**
  273. * Create element by string.
  274. *
  275. * @param {String} str
  276. *
  277. * @returns {NodeList}
  278. */
  279. function createElementByString(str) {
  280. var div = document.createElement('div');
  281. div.innerHTML = str;
  282. return div.childNodes;
  283. }
  284. /**
  285. * Merge objects.
  286. *
  287. * @returns {Object}
  288. */
  289. function mixin() {
  290. var args = arguments;
  291. if (Object$assign) {
  292. return Object$assign.apply(null, args);
  293. }
  294. var target = {};
  295. each(args, function (it) {
  296. each(it, function (v, k) {
  297. target[k] = v;
  298. });
  299. });
  300. return args[0] = target;
  301. }
  302. /**
  303. * Get dataset object.
  304. *
  305. * @param {Element} elem
  306. *
  307. * @returns {Object}
  308. */
  309. function dataset(elem) {
  310. if (elem.dataset) {
  311. return JSON.parse(JSON.stringify(elem.dataset));
  312. }
  313. var target = {};
  314. if (elem.hasAttributes()) {
  315. each(elem.attributes, function (attr) {
  316. var name = attr.name;
  317. if (name.indexOf('data-') !== 0) {
  318. return true;
  319. }
  320. name = name.replace(/^data-/i, '')
  321. .replace(/-(\w)/g, function (all, letter) {
  322. return letter.toUpperCase();
  323. });
  324. target[name] = attr.value;
  325. });
  326. return target;
  327. }
  328. return {};
  329. }
  330. /**
  331. * found element in the array.
  332. *
  333. * @param {Array|Object} elem
  334. * @param {Array} arr
  335. * @param {Number} i
  336. *
  337. * @returns {Number}
  338. */
  339. function inArray(elem, arr, i) {
  340. var len;
  341. if (arr) {
  342. if (Array$indexOf) {
  343. return Array$indexOf.call(arr, elem, i);
  344. }
  345. len = arr.length;
  346. i = i ? i < 0 ? Math.max(0, len + i) : i : 0;
  347. for (; i < len; i++) {
  348. // Skip accessing in sparse arrays
  349. if (i in arr && arr[i] === elem) {
  350. return i;
  351. }
  352. }
  353. }
  354. return -1;
  355. }
  356. /**
  357. * Simple each.
  358. *
  359. * @param {Array|Object} obj
  360. * @param {Function} callback
  361. *
  362. * @returns {*}
  363. */
  364. function each(obj, callback) {
  365. var length = obj.length;
  366. if (length === undefined) {
  367. for (var name in obj) {
  368. if (obj.hasOwnProperty(name)) {
  369. if (callback.call(obj[name], obj[name], name) === false) {
  370. break;
  371. }
  372. }
  373. }
  374. } else {
  375. for (var i = 0; i < length; i++) {
  376. if (callback.call(obj[i], obj[i], i) === false) {
  377. break;
  378. }
  379. }
  380. }
  381. }
  382. /**
  383. * Dom ready.
  384. *
  385. * @param {Function} fn
  386. *
  387. * @link https://github.com/jed/alReady.js
  388. */
  389. function alReady ( fn ) {
  390. var add = 'addEventListener';
  391. var pre = document[ add ] ? '' : 'on';
  392. ~document.readyState.indexOf( 'm' ) ? fn() :
  393. 'load DOMContentLoaded readystatechange'.replace( /\w+/g, function( type, i ) {
  394. ( i ? document : window )
  395. [ pre ? 'attachEvent' : add ]
  396. (
  397. pre + type,
  398. function(){ if ( fn ) if ( i < 6 || ~document.readyState.indexOf( 'm' ) ) fn(), fn = 0 },
  399. !1
  400. )
  401. })
  402. }
  403. })(window, document);