1/** 2 * social-share.js 3 * 4 * @author 52cik <[email protected]> 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 21 // Initialize a variables. 22 23 var Array$indexOf = Array.prototype.indexOf; 24 var Object$assign = Object.assign; 25 26 var runningInWeChat = /MicroMessenger/i.test(navigator.userAgent); 27 var isMobileScreen = document.documentElement.clientWidth <= 768; 28 29 var image = (document.images[0] || 0).src || ''; 30 var site = getMetaContentByName('site') || getMetaContentByName('Site') || document.title; 31 var title = getMetaContentByName('title') || getMetaContentByName('Title') || document.title; 32 var description = getMetaContentByName('description') || getMetaContentByName('Description') || ''; 33 34 var defaults = { 35 url: location.href, 36 origin: location.origin, 37 source: site, 38 title: title, 39 description: description, 40 image: image, 41 imageSelector: undefined, 42 43 weiboKey: '', 44 45 wechatQrcodeTitle: '微信æ«ä¸æ«ï¼å享', 46 wechatQrcodeHelper: '<p>微信éç¹âåç°âï¼æ«ä¸ä¸</p><p>äºç»´ç 便å¯å°æ¬æåäº«è³æååã</p>', 47 wechatQrcodeSize: 100, 48 49 sites: ['weibo', 'qq', 'wechat', 'douban', 'qzone', 'linkedin', 'facebook', 'twitter', 'google'], 50 mobileSites: [], 51 disabled: [], 52 initialized: false 53 }; 54 55 var templates = { 56 qzone: 'http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url={{URL}}&title={{TITLE}}&desc={{DESCRIPTION}}&summary={{SUMMARY}}&site={{SOURCE}}&pics={{IMAGE}}', 57 qq: 'http://connect.qq.com/widget/shareqq/index.html?url={{URL}}&title={{TITLE}}&source={{SOURCE}}&desc={{DESCRIPTION}}&pics={{IMAGE}}&summary="{{SUMMARY}}"', 58 weibo: 'https://service.weibo.com/share/share.php?url={{URL}}&title={{TITLE}}&pic={{IMAGE}}&appkey={{WEIBOKEY}}', 59 wechat: 'javascript:', 60 douban: 'http://shuo.douban.com/!service/share?href={{URL}}&name={{TITLE}}&text={{DESCRIPTION}}&image={{IMAGE}}&starid=0&aid=0&style=11', 61 linkedin: 'http://www.linkedin.com/shareArticle?mini=true&ro=true&title={{TITLE}}&url={{URL}}&summary={{SUMMARY}}&source={{SOURCE}}&armin=armin', 62 facebook: 'https://www.facebook.com/sharer/sharer.php?u={{URL}}', 63 twitter: 'https://twitter.com/intent/tweet?text={{TITLE}}&url={{URL}}&via={{ORIGIN}}', 64 google: 'https://plus.google.com/share?url={{URL}}' 65 }; 66 67 68 /** 69 * Expose API to the global 70 * 71 * @param {String|Element} elem 72 * @param {Object} options 73 */ 74 window.socialShare = function (elem, options) { 75 elem = typeof elem === 'string' ? querySelectorAlls(elem) : elem; 76 77 if (elem.length === undefined) { 78 elem = [elem]; 79 } 80 81 each(elem, function (el) { 82 if (!el.initialized) { 83 share(el, options); 84 } 85 }); 86 }; 87 88 // Domready after initialization 89 alReady(function () { 90 socialShare('.social-share, .share-component'); 91 }); 92 93 94 /** 95 * Initialize a share bar. 96 * 97 * @param {Object} $options globals (optional). 98 * 99 * @return {Void} 100 */ 101 function share(elem, options) { 102 var data = mixin({}, defaults, options || {}, dataset(elem)); 103 104 if (data.imageSelector) { 105 data.image = querySelectorAlls(data.imageSelector).map(function(item) { 106 return item.src; 107 }).join('||'); 108 } 109 110 addClass(elem, 'share-component social-share'); 111 createIcons(elem, data); 112 createWechat(elem, data); 113 114 elem.initialized = true; 115 } 116 117 118 /** 119 * Create site icons 120 * 121 * @param {Element} elem 122 * @param {Object} data 123 */ 124 function createIcons(elem, data) { 125 var sites = getSites(data); 126 var isPrepend = data.mode == 'prepend'; 127 128 each(isPrepend ? sites.reverse() : sites, function (name) { 129 var url = makeUrl(name, data); 130 var link = data.initialized ? getElementsByClassName(elem, 'icon-' + name) : createElementByString('
130<a id="social-share-' + name + '" class="social-share-icon icon-' + name + '"></a>'); 131 132 if (!link.length) { 133 return true; 134 } 135 136 link[0].href = url; 137 138 if (name === 'wechat') { 139 link[0].tabindex = -1; 140 } else { 141 link[0].target = '_blank'; 142 } 143 144 if (!data.initialized) { 145 isPrepend ? elem.insertBefore(link[0], elem.firstChild) : elem.appendChild(link[0]); 146 } 147 }); 148 } 149 150 151 /** 152 * Create the wechat icon and QRCode. 153 * 154 * @param {Element} elem 155 * @param {Object} data 156 */ 157 function createWechat (elem, data) { 158 //var wechat = getElementsByClassName(elem, 'icon-wechat', 'a'); 159 160 //if (wechat.length === 0) { 161 // return false; 162 //} 163 164 //var elems = createElementByString('<div class="wechat-qrcode"><h4>' + data.wechatQrcodeTitle + '</h4><div class="qrcode"></div><div class="help">' + data.wechatQrcodeHelper + '</div></div>'); 165 //var qrcode = getElementsByClassName(elems[0], 'qrcode', 'div'); 166 167 //new QRCode(qrcode[0], {text: data.url, width: data.wechatQrcodeSize, height: data.wechatQrcodeSize}); 168 //wechat[0].appendChild(elems[0]); 169 } 170 171 172 /** 173 * Get available site lists. 174 * 175 * @param {Object} data 176 * 177 * @returns {Array} 178 */ 179 function getSites(data) { 180 if (!data['mobileSites'].length) { 181 data['mobileSites'] = data['sites']; 182 } 183 184 var sites = (isMobileScreen ? data['mobileSites'] : data['sites']).slice(0); 185 var disabled = data['disabled']; 186 187 if (typeof sites == 'string') { 188 sites = sites.split(/\s*,\s*/); 189 } 190 if (typeof disabled == 'string') { 191 disabled = disabled.split(/\s*,\s*/); 192 } 193 194 if (runningInWeChat) { 195 disabled.push('wechat'); 196 } 197 198 // Remove elements 199 disabled.length && each(disabled, function (it) { 200 sites.splice(inArray(it, sites), 1); 201 }); 202 203 return sites; 204 } 205 206 207 /** 208 * Build the url of icon. 209 * 210 * @param {String} name 211 * @param {Object} data 212 * 213 * @returns {String} 214 */ 215 function makeUrl(name, data) { 216 217 if (! data['summary']){ 218 data['summary'] = data['description']; 219 } 220 221 return templates[name].replace(/\{\{(\w)(\w*)\}\}/g, function (m, fix, key) { 222 var nameKey = name + fix + key.toLowerCase(); 223 key = (fix + key).toLowerCase(); 224 225 return encodeURIComponent((data[nameKey] === undefined ? data[key] : data[nameKey]) || ''); 226 }); 227 } 228 229 230 /** 231 * Supports querySelectorAll, jQuery, Zepto and simple selector. 232 * 233 * @param str 234 * 235 * @returns {*} 236 */ 237 function querySelectorAlls(str) { 238 return (document.querySelectorAll || window.jQuery || window.Zepto || selector).call(document, str); 239 } 240 241 242 /** 243 * Simple selector. 244 * 245 * @param {String} str #ID or .CLASS 246 * 247 * @returns {Array} 248 */ 249 function selector(str) { 250 var elems = []; 251 252 each(str.split(/\s*,\s*/), function(s) { 253 var m = s.match(/([#.])(\w+)/); 254 if (m === null) { 255 throw Error('Supports only simple single #ID or .CLASS selector.'); 256 } 257 258 if (m[1]) { 259 var elem = document.getElementById(m[2]); 260 261 if (elem) { 262 elems.push(elem); 263 } 264 } 265 266 elems = elems.concat(getElementsByClassName(str)); 267 }); 268 269 return elems; 270 } 271 272 273 /** 274 * Add the classNames for element. 275 * 276 * @param {Element} elem 277 * @param {String} value 278 */ 279 function addClass(elem, value) { 280 if (value && typeof value === "string") { 281 var classNames = (elem.className + ' ' + value).split(/\s+/); 282 var setClass = ' '; 283 284 each(classNames, function (className) { 285 if (setClass.indexOf(' ' + className + ' ') < 0) { 286 setClass += className + ' '; 287 } 288 }); 289 290 elem.className = setClass.slice(1, -1); 291 } 292 } 293 294 295 /** 296 * Get meta element content value 297 * 298 * @param {String} name 299 * 300 * @returns {String|*} 301 */ 302 function getMetaContentByName(name) { 303 return (document.getElementsByName(name)[0] || 0).content; 304 } 305 306 307 /** 308 * Get elements By className for IE8- 309 * 310 * @param {Element} elem element 311 * @param {String} name className 312 * @param {String} tag tagName 313 * 314 * @returns {HTMLCollection|Array} 315 */ 316 function getElementsByClassName(elem, name, tag) { 317 if (elem.getElementsByClassName) { 318 return elem.getElementsByClassName(name); 319 } 320 321 var elements = []; 322 var elems = elem.getElementsByTagName(tag || '*'); 323 name = ' ' + name + ' '; 324 325 each(elems, function (elem) { 326 if ((' ' + (elem.className || '') + ' ').indexOf(name) >= 0) { 327 elements.push(elem); 328 } 329 }); 330 331 return elements; 332 } 333 334 335 /** 336 * Create element by string. 337 * 338 * @param {String} str 339 * 340 * @returns {NodeList} 341 */ 342 function createElementByString(str) { 343 var div = document.createElement('div'); 344 div.innerHTML = str; 345 346 return div.childNodes; 347 } 348 349 350 /** 351 * Merge objects. 352 * 353 * @returns {Object} 354 */ 355 function mixin() { 356 var args = arguments; 357 358 if (Object$assign) {
359 return Object$assign.apply(null, args); 360 } 361 362 var target = {}; 363 364 each(args, function (it) { 365 each(it, function (v, k) { 366 target[k] = v; 367 }); 368 }); 369 370 return args[0] = target; 371 } 372 373 374 /** 375 * Get dataset object. 376 * 377 * @param {Element} elem 378 * 379 * @returns {Object} 380 */ 381 function dataset(elem) { 382 if (elem.dataset) { 383 return JSON.parse(JSON.stringify(elem.dataset)); 384 } 385 386 var target = {}; 387 388 if (elem.hasAttributes()) { 389 each(elem.attributes, function (attr) { 390 var name = attr.name; 391 if (name.indexOf('data-') !== 0) { 392 return true; 393 } 394 395 name = name.replace(/^data-/i, '') 396 .replace(/-(\w)/g, function (all, letter) { 397 return letter.toUpperCase(); 398 }); 399 400 target[name] = attr.value; 401 }); 402 403 return target; 404 } 405 406 return {}; 407 } 408 409 410 /** 411 * found element in the array. 412 * 413 * @param {Array|Object} elem 414 * @param {Array} arr 415 * @param {Number} i 416 * 417 * @returns {Number} 418 */ 419 function inArray(elem, arr, i) { 420 var len; 421 422 if (arr) { 423 if (Array$indexOf) { 424 return Array$indexOf.call(arr, elem, i); 425 } 426 427 len = arr.length; 428 i = i ? i < 0 ? Math.max(0, len + i) : i : 0; 429 430 for (; i < len; i++) { 431 // Skip accessing in sparse arrays 432 if (i in arr && arr[i] === elem) { 433 return i; 434 } 435 } 436 } 437 438 return -1; 439 } 440 441 442 /** 443 * Simple each. 444 * 445 * @param {Array|Object} obj 446 * @param {Function} callback 447 * 448 * @returns {*} 449 */ 450 function each(obj, callback) { 451 var length = obj.length; 452 453 if (length === undefined) { 454 for (var name in obj) { 455 if (obj.hasOwnProperty(name)) { 456 if (callback.call(obj[name], obj[name], name) === false) { 457 break; 458 } 459 } 460 } 461 } else { 462 for (var i = 0; i < length; i++) { 463 if (callback.call(obj[i], obj[i], i) === false) { 464 break; 465 } 466 } 467 } 468 } 469 470 471 /** 472 * Dom ready. 473 * 474 * @param {Function} fn 475 * 476 * @link https://github.com/jed/alReady.js 477 */ 478 function alReady ( fn ) { 479 var add = 'addEventListener'; 480 var pre = document[ add ] ? '' : 'on'; 481 482 ~document.readyState.indexOf( 'm' ) ? fn() : 483 'load DOMContentLoaded readystatechange'.replace( /\w+/g, function( type, i ) { 484 ( i ? document : window ) 485 [ pre ? 'attachEvent' : add ] 486 ( 487 pre + type, 488 function(){ if ( fn ) if ( i < 6 || ~document.readyState.indexOf( 'm' ) ) fn(), fn = 0 }, 489 !1 490 ) 491 }) 492 } 493})(window, document);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.