├── .eslintignore ├── .eslintrc.json ├── .gitignore ├── README.md ├── analytics.js ├── async-test.html ├── bower.json ├── count.js ├── dist ├── openshare.js ├── openshare.min.js └── test.js ├── lib ├── countReduce.js ├── dashToCamel.js ├── init.js ├── initializeCountNode.js ├── initializeNodes.js ├── initializeShareNode.js ├── initializeWatcher.js ├── setData.js ├── share.js └── storeCount.js ├── package.json ├── share.js ├── src ├── browser.js ├── index.js ├── modules │ ├── count-api.js │ ├── count-transforms.js │ ├── count.js │ ├── data-attr.js │ ├── events.js │ ├── open-share.js │ ├── share-api.js │ └── share-transforms.js └── test.js └── test.html /.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb", 3 | "rules": { 4 | "new-cap": [0, { "capIsNew": true }], 5 | "max-len": [2, 200], 6 | "no-plusplus": 0, 7 | "no-mixed-operators": 0, 8 | "no-alert": 0, 9 | "no-restricted-syntax": 0, 10 | "no-param-reassign": 0, 11 | "no-new": 0, 12 | "no-console": 0, 13 | "global-require": 0, 14 | "one-var": 0, 15 | "consistent-return": 0, 16 | "no-underscore-dangle": 0, 17 | "no-use-before-define": 0, 18 | "no-shadow": 0 19 | }, 20 | "env": { 21 | "browser": true, 22 | "node": true 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .jscsrc 3 | .jshintrc 4 | .vhost 5 | .sass-cache 6 | npm-debug.log 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenShare 2 | 3 | OpenShare provides straightforward, declarative, and completely customizable API wrappers for sharing and counting on major social networks and platforms. Zero styling, maximum flexibility. But, unlike other social sharing tools, we don't retarget and profit from your users. Your data is your data — this is OpenShare. 4 | 5 | [Check out the examples](http://openshare.social/examples) to see OpenShare in action or [dive right into the documentation](https://github.com/dsurgeons/OpenShare/wiki). 6 | 7 | * [Getting Started](https://github.com/dsurgeons/OpenShare/wiki/1.-Getting-Started) 8 | * [Data Attribute API](https://github.com/dsurgeons/OpenShare/wiki/2.-Data-Attribute-API) 9 | * [JavaScript API](https://github.com/dsurgeons/OpenShare/wiki/3.-JavaScript-API) 10 | * [Automated Analytics Integrations](https://github.com/dsurgeons/OpenShare/wiki/4.-Automated-Analytics-Integrations) 11 | * [Contributing](https://github.com/dsurgeons/OpenShare/wiki/5.-Contributing) 12 | * [Examples](http://openshare.social/examples) 13 | 14 | 15 | --- 16 | **Quick Start** 17 | 18 | ``` 19 | $ npm install openshare --save 20 | ``` 21 | 22 | ```html 23 | 27 | Share 28 | 29 | 31 | 32 | ``` 33 | 34 | --- 35 | **MIT License (MIT)** 36 | 37 | Copyright (c) 2015 Digital Surgeons 38 | 39 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 40 | 41 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 42 | 43 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 44 | -------------------------------------------------------------------------------- /analytics.js: -------------------------------------------------------------------------------- 1 | export default function (type, cb) {// eslint-disable-line 2 | const isGA = type === 'event' || type === 'social'; 3 | const isTagManager = type === 'tagManager'; 4 | 5 | if (isGA) checkIfAnalyticsLoaded(type, cb); 6 | if (isTagManager) setTagManager(cb); 7 | } 8 | 9 | function checkIfAnalyticsLoaded(type, cb) { 10 | if (window.ga) { 11 | if (cb) cb(); 12 | // bind to shared event on each individual node 13 | listen((e) => { 14 | const platform = e.target.getAttribute('data-open-share'); 15 | const target = e.target.getAttribute('data-open-share-link') || 16 | e.target.getAttribute('data-open-share-url') || 17 | e.target.getAttribute('data-open-share-username') || 18 | e.target.getAttribute('data-open-share-center') || 19 | e.target.getAttribute('data-open-share-search') || 20 | e.target.getAttribute('data-open-share-body'); 21 | 22 | if (type === 'event') { 23 | ga('send', 'event', { // eslint-disable-line no-undef 24 | eventCategory: 'OpenShare Click', 25 | eventAction: platform, 26 | eventLabel: target, 27 | transport: 'beacon', 28 | }); 29 | } 30 | 31 | if (type === 'social') { 32 | ga('send', { // eslint-disable-line no-undef 33 | hitType: 'social', 34 | socialNetwork: platform, 35 | socialAction: 'share', 36 | socialTarget: target, 37 | }); 38 | } 39 | }); 40 | } else { 41 | setTimeout(() => { 42 | checkIfAnalyticsLoaded(type, cb); 43 | }, 1000); 44 | } 45 | } 46 | 47 | function setTagManager(cb) { 48 | if (window.dataLayer && window.dataLayer[0]['gtm.start']) { 49 | if (cb) cb(); 50 | 51 | listen(onShareTagManger); 52 | 53 | getCounts((e) => { 54 | const count = e.target ? 55 | e.target.innerHTML : 56 | e.innerHTML; 57 | 58 | const platform = e.target ? 59 | e.target.getAttribute('data-open-share-count-url') : 60 | e.getAttribute('data-open-share-count-url'); 61 | 62 | window.dataLayer.push({ 63 | event: 'OpenShare Count', 64 | platform, 65 | resource: count, 66 | activity: 'count', 67 | }); 68 | }); 69 | } else { 70 | setTimeout(() => { 71 | setTagManager(cb); 72 | }, 1000); 73 | } 74 | } 75 | 76 | function listen(cb) { 77 | // bind to shared event on each individual node 78 | [].forEach.call(document.querySelectorAll('[data-open-share]'), (node) => { 79 | node.addEventListener('OpenShare.shared', cb); 80 | }); 81 | } 82 | 83 | function getCounts(cb) { 84 | const countNode = document.querySelectorAll('[data-open-share-count]'); 85 | 86 | [].forEach.call(countNode, (node) => { 87 | if (node.textContent) cb(node); 88 | else node.addEventListener(`OpenShare.counted-${node.getAttribute('data-open-share-count-url')}`, cb); 89 | }); 90 | } 91 | 92 | function onShareTagManger(e) { 93 | const platform = e.target.getAttribute('data-open-share'); 94 | const target = e.target.getAttribute('data-open-share-link') || 95 | e.target.getAttribute('data-open-share-url') || 96 | e.target.getAttribute('data-open-share-username') || 97 | e.target.getAttribute('data-open-share-center') || 98 | e.target.getAttribute('data-open-share-search') || 99 | e.target.getAttribute('data-open-share-body'); 100 | 101 | window.dataLayer.push({ 102 | event: 'OpenShare Share', 103 | platform, 104 | resource: target, 105 | activity: 'share', 106 | }); 107 | } 108 | -------------------------------------------------------------------------------- /async-test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Open Share 9 | 10 | 11 | 12 | 13 | 14 | 15 | 168 | 169 | 170 | 171 | 178 | 179 | 180 | Tweet 181 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "open-share", 3 | "version": "0.8.1", 4 | "authors": [ 5 | "Digital Surgeons", 6 | "Adam Chambers" 7 | ], 8 | "main": "dist/open-share.js", 9 | "license": "MIT" 10 | } 11 | -------------------------------------------------------------------------------- /count.js: -------------------------------------------------------------------------------- 1 | import Init from './lib/init'; 2 | import cb from './lib/initializeCountNode'; 3 | 4 | function init() { 5 | Init({ 6 | api: 'count', 7 | selector: '[data-open-share-count]:not([data-open-share-node])', 8 | cb, 9 | })(); 10 | } 11 | export default () => { 12 | if (document.readyState === 'complete') { 13 | init(); 14 | } 15 | document.addEventListener('readystatechange', () => { 16 | if (document.readyState === 'complete') { 17 | init(); 18 | } 19 | }, false); 20 | return require('./src/modules/count-api')(); 21 | }; 22 | -------------------------------------------------------------------------------- /dist/openshare.js: -------------------------------------------------------------------------------- 1 | (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o -1) { 150 | var providers = provider.split(','); 151 | providers.forEach(function (p) { 152 | return analytics(p); 153 | }); 154 | } else analytics(provider); 155 | } 156 | } 157 | 158 | function initializeWatcher(watcher, fn) { 159 | [].forEach.call(watcher, function (w) { 160 | var observer = new MutationObserver(function (mutations) { 161 | // target will match between all mutations so just use first 162 | fn(mutations[0].target); 163 | }); 164 | 165 | observer.observe(w, { 166 | childList: true 167 | }); 168 | }); 169 | } 170 | 171 | function init$1(opts) { 172 | return function () { 173 | var initNodes = initializeNodes({ 174 | api: opts.api || null, 175 | container: opts.container || document, 176 | selector: opts.selector, 177 | cb: opts.cb 178 | }); 179 | 180 | initNodes(); 181 | 182 | // check for mutation observers before using, IE11 only 183 | if (window.MutationObserver !== undefined) { 184 | initializeWatcher(document.querySelectorAll('[data-open-share-watch]'), initNodes); 185 | } 186 | }; 187 | } 188 | 189 | /** 190 | * Object of transform functions for each openshare api 191 | * Transform functions passed into OpenShare instance when instantiated 192 | * Return object containing URL and key/value args 193 | */ 194 | var ShareTransforms = { 195 | 196 | // set Twitter share URL 197 | twitter: function twitter(data) { 198 | var ios = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1]; 199 | 200 | // if iOS user and ios data attribute defined 201 | // build iOS URL scheme as single string 202 | if (ios && data.ios) { 203 | var message = ''; 204 | 205 | if (data.text) { 206 | message += data.text; 207 | } 208 | 209 | if (data.url) { 210 | message += ' - ' + data.url; 211 | } 212 | 213 | if (data.hashtags) { 214 | var tags = data.hashtags.split(','); 215 | tags.forEach(function (tag) { 216 | message += ' #' + tag; 217 | }); 218 | } 219 | 220 | if (data.via) { 221 | message += ' via ' + data.via; 222 | } 223 | 224 | return { 225 | url: 'twitter://post?', 226 | data: { 227 | message: message 228 | } 229 | }; 230 | } 231 | 232 | return { 233 | url: 'https://twitter.com/share?', 234 | data: data, 235 | popup: { 236 | width: 700, 237 | height: 296 238 | } 239 | }; 240 | }, 241 | 242 | 243 | // set Twitter retweet URL 244 | twitterRetweet: function twitterRetweet(data) { 245 | var ios = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1]; 246 | 247 | // if iOS user and ios data attribute defined 248 | if (ios && data.ios) { 249 | return { 250 | url: 'twitter://status?', 251 | data: { 252 | id: data.tweetId 253 | } 254 | }; 255 | } 256 | 257 | return { 258 | url: 'https://twitter.com/intent/retweet?', 259 | data: { 260 | tweet_id: data.tweetId, 261 | related: data.related 262 | }, 263 | popup: { 264 | width: 700, 265 | height: 296 266 | } 267 | }; 268 | }, 269 | 270 | 271 | // set Twitter like URL 272 | twitterLike: function twitterLike(data) { 273 | var ios = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1]; 274 | 275 | // if iOS user and ios data attribute defined 276 | if (ios && data.ios) { 277 | return { 278 | url: 'twitter://status?', 279 | data: { 280 | id: data.tweetId 281 | } 282 | }; 283 | } 284 | 285 | return { 286 | url: 'https://twitter.com/intent/favorite?', 287 | data: { 288 | tweet_id: data.tweetId, 289 | related: data.related 290 | }, 291 | popup: { 292 | width: 700, 293 | height: 296 294 | } 295 | }; 296 | }, 297 | 298 | 299 | // set Twitter follow URL 300 | twitterFollow: function twitterFollow(data) { 301 | var ios = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1]; 302 | 303 | // if iOS user and ios data attribute defined 304 | if (ios && data.ios) { 305 | var iosData = data.screenName ? { 306 | screen_name: data.screenName 307 | } : { 308 | id: data.userId 309 | }; 310 | 311 | return { 312 | url: 'twitter://user?', 313 | data: iosData 314 | }; 315 | } 316 | 317 | return { 318 | url: 'https://twitter.com/intent/user?', 319 | data: { 320 | screen_name: data.screenName, 321 | user_id: data.userId 322 | }, 323 | popup: { 324 | width: 700, 325 | height: 296 326 | } 327 | }; 328 | }, 329 | 330 | 331 | // set Facebook share URL 332 | facebook: function facebook(data) { 333 | return { 334 | url: 'https://www.facebook.com/dialog/feed?app_id=961342543922322&redirect_uri=http://facebook.com&', 335 | data: data, 336 | popup: { 337 | width: 560, 338 | height: 593 339 | } 340 | }; 341 | }, 342 | 343 | 344 | // set Facebook send URL 345 | facebookSend: function facebookSend(data) { 346 | return { 347 | url: 'https://www.facebook.com/dialog/send?app_id=961342543922322&redirect_uri=http://facebook.com&', 348 | data: data, 349 | popup: { 350 | width: 980, 351 | height: 596 352 | } 353 | }; 354 | }, 355 | 356 | 357 | // set YouTube play URL 358 | youtube: function youtube(data) { 359 | var ios = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1]; 360 | 361 | // if iOS user 362 | if (ios && data.ios) { 363 | return { 364 | url: 'youtube:' + data.video + '?' 365 | }; 366 | } 367 | 368 | return { 369 | url: 'https://www.youtube.com/watch?v=' + data.video + '?', 370 | popup: { 371 | width: 1086, 372 | height: 608 373 | } 374 | }; 375 | }, 376 | 377 | 378 | // set YouTube subcribe URL 379 | youtubeSubscribe: function youtubeSubscribe(data) { 380 | var ios = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1]; 381 | 382 | // if iOS user 383 | if (ios && data.ios) { 384 | return { 385 | url: 'youtube://www.youtube.com/user/' + data.user + '?' 386 | }; 387 | } 388 | 389 | return { 390 | url: 'https://www.youtube.com/user/' + data.user + '?', 391 | popup: { 392 | width: 880, 393 | height: 350 394 | } 395 | }; 396 | }, 397 | 398 | 399 | // set Instagram follow URL 400 | instagram: function instagram() { 401 | return { 402 | url: 'instagram://camera?' 403 | }; 404 | }, 405 | 406 | 407 | // set Instagram follow URL 408 | instagramFollow: function instagramFollow(data) { 409 | var ios = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1]; 410 | 411 | // if iOS user 412 | if (ios && data.ios) { 413 | return { 414 | url: 'instagram://user?', 415 | data: data 416 | }; 417 | } 418 | 419 | return { 420 | url: 'http://www.instagram.com/' + data.username + '?', 421 | popup: { 422 | width: 980, 423 | height: 655 424 | } 425 | }; 426 | }, 427 | 428 | 429 | // set Snapchat follow URL 430 | snapchat: function snapchat(data) { 431 | return { 432 | url: 'snapchat://add/' + data.username + '?' 433 | }; 434 | }, 435 | 436 | 437 | // set Google share URL 438 | google: function google(data) { 439 | return { 440 | url: 'https://plus.google.com/share?', 441 | data: data, 442 | popup: { 443 | width: 495, 444 | height: 815 445 | } 446 | }; 447 | }, 448 | 449 | 450 | // set Google maps URL 451 | googleMaps: function googleMaps(data) { 452 | var ios = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1]; 453 | 454 | if (data.search) { 455 | data.q = data.search; 456 | delete data.search; 457 | } 458 | 459 | // if iOS user and ios data attribute defined 460 | if (ios && data.ios) { 461 | return { 462 | url: 'comgooglemaps://?', 463 | data: ios 464 | }; 465 | } 466 | 467 | if (!ios && data.ios) { 468 | delete data.ios; 469 | } 470 | 471 | return { 472 | url: 'https://maps.google.com/?', 473 | data: data, 474 | popup: { 475 | width: 800, 476 | height: 600 477 | } 478 | }; 479 | }, 480 | 481 | 482 | // set Pinterest share URL 483 | pinterest: function pinterest(data) { 484 | return { 485 | url: 'https://pinterest.com/pin/create/bookmarklet/?', 486 | data: data, 487 | popup: { 488 | width: 745, 489 | height: 620 490 | } 491 | }; 492 | }, 493 | 494 | 495 | // set LinkedIn share URL 496 | linkedin: function linkedin(data) { 497 | return { 498 | url: 'http://www.linkedin.com/shareArticle?', 499 | data: data, 500 | popup: { 501 | width: 780, 502 | height: 492 503 | } 504 | }; 505 | }, 506 | 507 | 508 | // set Buffer share URL 509 | buffer: function buffer(data) { 510 | return { 511 | url: 'http://bufferapp.com/add?', 512 | data: data, 513 | popup: { 514 | width: 745, 515 | height: 345 516 | } 517 | }; 518 | }, 519 | 520 | 521 | // set Tumblr share URL 522 | tumblr: function tumblr(data) { 523 | return { 524 | url: 'https://www.tumblr.com/widgets/share/tool?', 525 | data: data, 526 | popup: { 527 | width: 540, 528 | height: 940 529 | } 530 | }; 531 | }, 532 | 533 | 534 | // set Reddit share URL 535 | reddit: function reddit(data) { 536 | return { 537 | url: 'http://reddit.com/submit?', 538 | data: data, 539 | popup: { 540 | width: 860, 541 | height: 880 542 | } 543 | }; 544 | }, 545 | 546 | 547 | // set Flickr follow URL 548 | flickr: function flickr(data) { 549 | var ios = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1]; 550 | 551 | // if iOS user 552 | if (ios && data.ios) { 553 | return { 554 | url: 'flickr://photos/' + data.username + '?' 555 | }; 556 | } 557 | return { 558 | url: 'http://www.flickr.com/photos/' + data.username + '?', 559 | popup: { 560 | width: 600, 561 | height: 650 562 | } 563 | }; 564 | }, 565 | 566 | 567 | // set WhatsApp share URL 568 | whatsapp: function whatsapp(data) { 569 | return { 570 | url: 'whatsapp://send?', 571 | data: data 572 | }; 573 | }, 574 | 575 | 576 | // set sms share URL 577 | sms: function sms(data) { 578 | var ios = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1]; 579 | 580 | return { 581 | url: ios ? 'sms:&' : 'sms:?', 582 | data: data 583 | }; 584 | }, 585 | 586 | 587 | // set Email share URL 588 | email: function email(data) { 589 | var url = 'mailto:'; 590 | 591 | // if to address specified then add to URL 592 | if (data.to !== null) { 593 | url += '' + data.to; 594 | } 595 | 596 | url += '?'; 597 | 598 | return { 599 | url: url, 600 | data: { 601 | subject: data.subject, 602 | body: data.body 603 | } 604 | }; 605 | }, 606 | 607 | 608 | // set Github fork URL 609 | github: function github(data) { 610 | var ios = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1]; 611 | // eslint-disable-line no-unused-vars 612 | var url = data.repo ? 'https://github.com/' + data.repo : data.url; 613 | 614 | if (data.issue) { 615 | url += '/issues/new?title=' + data.issue + '&body=' + data.body; 616 | } 617 | 618 | return { 619 | url: url + '?', 620 | popup: { 621 | width: 1020, 622 | height: 323 623 | } 624 | }; 625 | }, 626 | 627 | 628 | // set Dribbble share URL 629 | dribbble: function dribbble(data) { 630 | var ios = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1]; 631 | // eslint-disable-line no-unused-vars 632 | var url = data.shot ? 'https://dribbble.com/shots/' + data.shot + '?' : data.url + '?'; 633 | return { 634 | url: url, 635 | popup: { 636 | width: 440, 637 | height: 640 638 | } 639 | }; 640 | }, 641 | codepen: function codepen(data) { 642 | var url = data.pen && data.username && data.view ? 'https://codepen.io/' + data.username + '/' + data.view + '/' + data.pen + '?' : data.url + '?'; 643 | return { 644 | url: url, 645 | popup: { 646 | width: 1200, 647 | height: 800 648 | } 649 | }; 650 | }, 651 | paypal: function paypal(data) { 652 | return { 653 | data: data 654 | }; 655 | } 656 | }; 657 | 658 | /** 659 | * OpenShare generates a single share link 660 | */ 661 | 662 | var OpenShare = function () { 663 | function OpenShare(type, transform) { 664 | _classCallCheck(this, OpenShare); 665 | 666 | this.ios = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream; 667 | this.type = type; 668 | this.dynamic = false; 669 | this.transform = transform; 670 | 671 | // capitalized type 672 | this.typeCaps = type.charAt(0).toUpperCase() + type.slice(1); 673 | } 674 | 675 | // returns function named as type set in constructor 676 | // e.g twitter() 677 | 678 | 679 | _createClass(OpenShare, [{ 680 | key: 'setData', 681 | value: function setData(data) { 682 | // if iOS user and ios data attribute defined 683 | // build iOS URL scheme as single string 684 | if (this.ios) { 685 | this.transformData = this.transform(data, true); 686 | this.mobileShareUrl = this.template(this.transformData.url, this.transformData.data); 687 | } 688 | 689 | this.transformData = this.transform(data); 690 | this.shareUrl = this.template(this.transformData.url, this.transformData.data); 691 | } 692 | 693 | // open share URL defined in individual platform functions 694 | 695 | }, { 696 | key: 'share', 697 | value: function share() { 698 | var _this = this; 699 | 700 | // if iOS share URL has been set then use timeout hack 701 | // test for native app and fall back to web 702 | if (this.mobileShareUrl) { 703 | (function () { 704 | var start = new Date().valueOf(); 705 | 706 | setTimeout(function () { 707 | var end = new Date().valueOf(); 708 | 709 | // if the user is still here, fall back to web 710 | if (end - start > 1600) { 711 | return; 712 | } 713 | 714 | window.location = _this.shareUrl; 715 | }, 1500); 716 | 717 | window.location = _this.mobileShareUrl; 718 | 719 | // open mailto links in same window 720 | })(); 721 | } else if (this.type === 'email') { 722 | window.location = this.shareUrl; 723 | 724 | // open social share URLs in new window 725 | } else { 726 | // if popup object present then set window dimensions / position 727 | if (this.popup && this.transformData.popup) { 728 | return this.openWindow(this.shareUrl, this.transformData.popup); 729 | } 730 | 731 | window.open(this.shareUrl); 732 | } 733 | } 734 | 735 | // create share URL with GET params 736 | // appending valid properties to query string 737 | 738 | }, { 739 | key: 'template', 740 | value: function template(url, data) { 741 | //eslint-disable-line 742 | var nonURLProps = ['appendTo', 'innerHTML', 'classes']; 743 | 744 | var shareUrl = url, 745 | i = void 0; 746 | 747 | for (i in data) { 748 | // only append valid properties 749 | if (!data[i] || nonURLProps.indexOf(i) > -1) { 750 | continue; //eslint-disable-line 751 | } 752 | 753 | // append URL encoded GET param to share URL 754 | data[i] = encodeURIComponent(data[i]); 755 | shareUrl += i + '=' + data[i] + '&'; 756 | } 757 | 758 | return shareUrl.substr(0, shareUrl.length - 1); 759 | } 760 | 761 | // center popup window supporting dual screens 762 | 763 | }, { 764 | key: 'openWindow', 765 | value: function openWindow(url, options) { 766 | //eslint-disable-line 767 | var dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : screen.left, 768 | dualScreenTop = window.screenTop !== undefined ? window.screenTop : screen.top, 769 | width = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width, 770 | //eslint-disable-line 771 | height = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height, 772 | //eslint-disable-line 773 | left = width / 2 - options.width / 2 + dualScreenLeft, 774 | top = height / 2 - options.height / 2 + dualScreenTop, 775 | newWindow = window.open(url, 'OpenShare', 'width=' + options.width + ', height=' + options.height + ', top=' + top + ', left=' + left); 776 | 777 | // Puts focus on the newWindow 778 | if (window.focus) { 779 | newWindow.focus(); 780 | } 781 | } 782 | }]); 783 | 784 | return OpenShare; 785 | }(); 786 | 787 | function setData(osInstance, osElement) { 788 | osInstance.setData({ 789 | url: osElement.getAttribute('data-open-share-url'), 790 | text: osElement.getAttribute('data-open-share-text'), 791 | via: osElement.getAttribute('data-open-share-via'), 792 | hashtags: osElement.getAttribute('data-open-share-hashtags'), 793 | tweetId: osElement.getAttribute('data-open-share-tweet-id'), 794 | related: osElement.getAttribute('data-open-share-related'), 795 | screenName: osElement.getAttribute('data-open-share-screen-name'), 796 | userId: osElement.getAttribute('data-open-share-user-id'), 797 | link: osElement.getAttribute('data-open-share-link'), 798 | picture: osElement.getAttribute('data-open-share-picture'), 799 | caption: osElement.getAttribute('data-open-share-caption'), 800 | description: osElement.getAttribute('data-open-share-description'), 801 | user: osElement.getAttribute('data-open-share-user'), 802 | video: osElement.getAttribute('data-open-share-video'), 803 | username: osElement.getAttribute('data-open-share-username'), 804 | title: osElement.getAttribute('data-open-share-title'), 805 | media: osElement.getAttribute('data-open-share-media'), 806 | to: osElement.getAttribute('data-open-share-to'), 807 | subject: osElement.getAttribute('data-open-share-subject'), 808 | body: osElement.getAttribute('data-open-share-body'), 809 | ios: osElement.getAttribute('data-open-share-ios'), 810 | type: osElement.getAttribute('data-open-share-type'), 811 | center: osElement.getAttribute('data-open-share-center'), 812 | views: osElement.getAttribute('data-open-share-views'), 813 | zoom: osElement.getAttribute('data-open-share-zoom'), 814 | search: osElement.getAttribute('data-open-share-search'), 815 | saddr: osElement.getAttribute('data-open-share-saddr'), 816 | daddr: osElement.getAttribute('data-open-share-daddr'), 817 | directionsmode: osElement.getAttribute('data-open-share-directions-mode'), 818 | repo: osElement.getAttribute('data-open-share-repo'), 819 | shot: osElement.getAttribute('data-open-share-shot'), 820 | pen: osElement.getAttribute('data-open-share-pen'), 821 | view: osElement.getAttribute('data-open-share-view'), 822 | issue: osElement.getAttribute('data-open-share-issue'), 823 | buttonId: osElement.getAttribute('data-open-share-buttonId'), 824 | popUp: osElement.getAttribute('data-open-share-popup'), 825 | key: osElement.getAttribute('data-open-share-key') 826 | }); 827 | } 828 | 829 | function share(e, os, openShare) { 830 | // if dynamic instance then fetch attributes again in case of updates 831 | if (openShare.dynamic) { 832 | setData(openShare, os); 833 | } 834 | 835 | openShare.share(e); 836 | 837 | // trigger shared event 838 | Events.trigger(os, 'shared'); 839 | } 840 | 841 | // type contains a dash 842 | // transform to camelcase for function reference 843 | // TODO: only supports single dash, should should support multiple 844 | var dashToCamel = function dashToCamel(dash, type) { 845 | var nextChar = type.substr(dash + 1, 1); 846 | var group = type.substr(dash, 2); 847 | 848 | type = type.replace(group, nextChar.toUpperCase()); 849 | return type; 850 | }; 851 | 852 | function initializeShareNode(os) { 853 | // initialize open share object with type attribute 854 | var type = os.getAttribute('data-open-share'); 855 | var dash = type.indexOf('-'); 856 | 857 | if (dash > -1) { 858 | type = dashToCamel(dash, type); 859 | } 860 | 861 | var transform = ShareTransforms[type]; 862 | 863 | if (!transform) { 864 | throw new Error('Open Share: ' + type + ' is an invalid type'); 865 | } 866 | 867 | var openShare = new OpenShare(type, transform); 868 | 869 | // specify if this is a dynamic instance 870 | if (os.getAttribute('data-open-share-dynamic')) { 871 | openShare.dynamic = true; 872 | } 873 | 874 | // specify if this is a popup instance 875 | if (os.getAttribute('data-open-share-popup')) { 876 | openShare.popup = true; 877 | } 878 | 879 | // set all optional attributes on open share instance 880 | setData(openShare, os); 881 | 882 | // open share dialog on click 883 | os.addEventListener('click', function (e) { 884 | share(e, os, openShare); 885 | }); 886 | 887 | os.addEventListener('OpenShare.trigger', function (e) { 888 | share(e, os, openShare); 889 | }); 890 | 891 | os.setAttribute('data-open-share-node', type); 892 | } 893 | 894 | function round(x, precision) { 895 | if (typeof x !== 'number') { 896 | throw new TypeError('Expected value to be a number'); 897 | } 898 | 899 | var exponent = precision > 0 ? 'e' : 'e-'; 900 | var exponentNeg = precision > 0 ? 'e-' : 'e'; 901 | precision = Math.abs(precision); 902 | 903 | return Number(Math.round(x + exponent + precision) + exponentNeg + precision); 904 | } 905 | 906 | function thousandify(num) { 907 | return round(num / 1000, 1) + 'K'; 908 | } 909 | 910 | function millionify(num) { 911 | return round(num / 1000000, 1) + 'M'; 912 | } 913 | 914 | function countReduce(el, count, cb) { 915 | if (count > 999999) { 916 | el.innerHTML = millionify(count); 917 | if (cb && typeof cb === 'function') cb(el); 918 | } else if (count > 999) { 919 | el.innerHTML = thousandify(count); 920 | if (cb && typeof cb === 'function') cb(el); 921 | } else { 922 | el.innerHTML = count; 923 | if (cb && typeof cb === 'function') cb(el); 924 | } 925 | } 926 | 927 | /* 928 | Sometimes social platforms get confused and drop share counts. 929 | In this module we check if the returned count is less than the count in 930 | localstorage. 931 | If the local count is greater than the returned count, 932 | we store the local count + the returned count. 933 | Otherwise, store the returned count. 934 | */ 935 | 936 | var storeCount = function storeCount(t, count) { 937 | var isArr = t.type.indexOf(',') > -1; 938 | var local = Number(t.storeGet(t.type + '-' + t.shared)); 939 | 940 | if (local > count && !isArr) { 941 | var latestCount = Number(t.storeGet(t.type + '-' + t.shared + '-latestCount')); 942 | t.storeSet(t.type + '-' + t.shared + '-latestCount', count); 943 | 944 | count = isNumeric$1(latestCount) && latestCount > 0 ? count += local - latestCount : count += local; 945 | } 946 | 947 | if (!isArr) t.storeSet(t.type + '-' + t.shared, count); 948 | return count; 949 | }; 950 | 951 | function isNumeric$1(n) { 952 | return !isNaN(parseFloat(n)) && isFinite(n); 953 | } 954 | 955 | /** 956 | * Object of transform functions for each openshare api 957 | * Transform functions passed into OpenShare instance when instantiated 958 | * Return object containing URL and key/value args 959 | */ 960 | var CountTransforms = { 961 | 962 | // facebook count data 963 | facebook: function facebook(url) { 964 | return { 965 | type: 'get', 966 | url: 'https://graph.facebook.com/?id=' + url, 967 | transform: function transform(xhr) { 968 | var fb = JSON.parse(xhr.responseText); 969 | 970 | var count = fb.share && fb.share.share_count || 0; 971 | 972 | return storeCount(this, count); 973 | } 974 | }; 975 | }, 976 | 977 | 978 | // pinterest count data 979 | pinterest: function pinterest(url) { 980 | return { 981 | type: 'jsonp', 982 | url: 'https://api.pinterest.com/v1/urls/count.json?callback=?&url=' + url, 983 | transform: function transform(data) { 984 | var count = data.count || 0; 985 | return storeCount(this, count); 986 | } 987 | }; 988 | }, 989 | 990 | 991 | // linkedin count data 992 | linkedin: function linkedin(url) { 993 | return { 994 | type: 'jsonp', 995 | url: 'https://www.linkedin.com/countserv/count/share?url=' + url + '&format=jsonp&callback=?', 996 | transform: function transform(data) { 997 | var count = data.count || 0; 998 | return storeCount(this, count); 999 | } 1000 | }; 1001 | }, 1002 | 1003 | 1004 | // reddit count data 1005 | reddit: function reddit(url) { 1006 | return { 1007 | type: 'get', 1008 | url: 'https://www.reddit.com/api/info.json?url=' + url, 1009 | transform: function transform(xhr) { 1010 | var reddit = JSON.parse(xhr.responseText); 1011 | var posts = reddit.data && reddit.data.children || null; 1012 | var ups = 0; 1013 | 1014 | if (posts) { 1015 | posts.forEach(function (post) { 1016 | ups += Number(post.data.ups); 1017 | }); 1018 | } 1019 | 1020 | return storeCount(this, ups); 1021 | } 1022 | }; 1023 | }, 1024 | 1025 | 1026 | // google count data 1027 | google: function google(url) { 1028 | return { 1029 | type: 'post', 1030 | data: { 1031 | method: 'pos.plusones.get', 1032 | id: 'p', 1033 | params: { 1034 | nolog: true, 1035 | id: url, 1036 | source: 'widget', 1037 | userId: '@viewer', 1038 | groupId: '@self' 1039 | }, 1040 | jsonrpc: '2.0', 1041 | key: 'p', 1042 | apiVersion: 'v1' 1043 | }, 1044 | url: 'https://clients6.google.com/rpc', 1045 | transform: function transform(xhr) { 1046 | var google = JSON.parse(xhr.responseText); 1047 | var count = google.result && google.result.metadata && google.result.metadata.globalCounts && google.result.metadata.globalCounts.count || 0; 1048 | return storeCount(this, count); 1049 | } 1050 | }; 1051 | }, 1052 | 1053 | 1054 | // github star count 1055 | githubStars: function githubStars(repo) { 1056 | repo = repo.indexOf('github.com/') > -1 ? repo.split('github.com/')[1] : repo; 1057 | return { 1058 | type: 'get', 1059 | url: 'https://api.github.com/repos/' + repo, 1060 | transform: function transform(xhr) { 1061 | var count = JSON.parse(xhr.responseText).stargazers_count || 0; 1062 | return storeCount(this, count); 1063 | } 1064 | }; 1065 | }, 1066 | 1067 | 1068 | // github forks count 1069 | githubForks: function githubForks(repo) { 1070 | repo = repo.indexOf('github.com/') > -1 ? repo.split('github.com/')[1] : repo; 1071 | return { 1072 | type: 'get', 1073 | url: 'https://api.github.com/repos/' + repo, 1074 | transform: function transform(xhr) { 1075 | var count = JSON.parse(xhr.responseText).forks_count || 0; 1076 | return storeCount(this, count); 1077 | } 1078 | }; 1079 | }, 1080 | 1081 | 1082 | // github watchers count 1083 | githubWatchers: function githubWatchers(repo) { 1084 | repo = repo.indexOf('github.com/') > -1 ? repo.split('github.com/')[1] : repo; 1085 | return { 1086 | type: 'get', 1087 | url: 'https://api.github.com/repos/' + repo, 1088 | transform: function transform(xhr) { 1089 | var count = JSON.parse(xhr.responseText).watchers_count || 0; 1090 | return storeCount(this, count); 1091 | } 1092 | }; 1093 | }, 1094 | 1095 | 1096 | // dribbble likes count 1097 | dribbble: function dribbble(shot) { 1098 | shot = shot.indexOf('dribbble.com/shots') > -1 ? shot.split('shots/')[1] : shot; 1099 | var url = 'https://api.dribbble.com/v1/shots/' + shot + '/likes'; 1100 | return { 1101 | type: 'get', 1102 | url: url, 1103 | transform: function transform(xhr, Events) { 1104 | var _this2 = this; 1105 | 1106 | var count = JSON.parse(xhr.responseText).length; 1107 | 1108 | // at this time dribbble limits a response of 12 likes per page 1109 | if (count === 12) { 1110 | var page = 2; 1111 | recursiveCount(url, page, count, function (finalCount) { 1112 | if (_this2.appendTo && typeof _this2.appendTo !== 'function') { 1113 | _this2.appendTo.appendChild(_this2.os); 1114 | } 1115 | countReduce(_this2.os, finalCount, _this2.cb); 1116 | Events.trigger(_this2.os, 'counted-' + _this2.url); 1117 | return storeCount(_this2, finalCount); 1118 | }); 1119 | } else { 1120 | return storeCount(this, count); 1121 | } 1122 | } 1123 | }; 1124 | }, 1125 | twitter: function twitter(url) { 1126 | return { 1127 | type: 'get', 1128 | url: 'https://api.openshare.social/job?url=' + url + '&key=', 1129 | transform: function transform(xhr) { 1130 | var count = JSON.parse(xhr.responseText).count || 0; 1131 | return storeCount(this, count); 1132 | } 1133 | }; 1134 | } 1135 | }; 1136 | 1137 | function recursiveCount(url, page, count, cb) { 1138 | var xhr = new XMLHttpRequest(); 1139 | xhr.open('GET', url + '?page=' + page); 1140 | xhr.addEventListener('load', function () { 1141 | //eslint-disable-line 1142 | var likes = JSON.parse(this.response); 1143 | count += likes.length; 1144 | 1145 | // dribbble like per page is 12 1146 | if (likes.length === 12) { 1147 | page++; 1148 | recursiveCount(url, page, count, cb); 1149 | } else { 1150 | cb(count); 1151 | } 1152 | }); 1153 | xhr.send(); 1154 | } 1155 | 1156 | /** 1157 | * Generate share count instance from one to many networks 1158 | */ 1159 | 1160 | var Count = function () { 1161 | function Count(type, url) { 1162 | var _this3 = this; 1163 | 1164 | _classCallCheck(this, Count); 1165 | 1166 | // throw error if no url provided 1167 | if (!url) { 1168 | throw new Error('Open Share: no url provided for count'); 1169 | } 1170 | 1171 | // check for Github counts 1172 | if (type.indexOf('github') === 0) { 1173 | if (type === 'github-stars') { 1174 | type = 'githubStars'; 1175 | } else if (type === 'github-forks') { 1176 | type = 'githubForks'; 1177 | } else if (type === 'github-watchers') { 1178 | type = 'githubWatchers'; 1179 | } else { 1180 | console.error('Invalid Github count type. Try github-stars, github-forks, or github-watchers.'); 1181 | } 1182 | } 1183 | 1184 | // if type is comma separate list create array 1185 | if (type.indexOf(',') > -1) { 1186 | this.type = type; 1187 | this.typeArr = this.type.split(','); 1188 | this.countData = []; 1189 | 1190 | // check each type supplied is valid 1191 | this.typeArr.forEach(function (t) { 1192 | if (!CountTransforms[t]) { 1193 | throw new Error('Open Share: ' + type + ' is an invalid count type'); 1194 | } 1195 | 1196 | _this3.countData.push(CountTransforms[t](url)); 1197 | }); 1198 | 1199 | var count = this.storeGet(this.type + '-' + this.shared); 1200 | 1201 | if (count) { 1202 | if (this.appendTo && typeof this.appendTo !== 'function') { 1203 | this.appendTo.appendChild(this.os); 1204 | } 1205 | countReduce(this.os, count); 1206 | } 1207 | 1208 | // throw error if invalid type provided 1209 | } else if (!CountTransforms[type]) { 1210 | throw new Error('Open Share: ' + type + ' is an invalid count type'); 1211 | 1212 | // single count 1213 | // store count URL and transform function 1214 | } else { 1215 | this.type = type; 1216 | this.countData = CountTransforms[type](url); 1217 | } 1218 | } 1219 | 1220 | // handle calling getCount / getCounts 1221 | // depending on number of types 1222 | 1223 | 1224 | _createClass(Count, [{ 1225 | key: 'count', 1226 | value: function count(os, cb, appendTo) { 1227 | this.os = os; 1228 | this.appendTo = appendTo; 1229 | this.cb = cb; 1230 | this.url = this.os.getAttribute('data-open-share-count'); 1231 | this.shared = this.os.getAttribute('data-open-share-count-url'); 1232 | this.key = this.os.getAttribute('data-open-share-key'); 1233 | 1234 | if (!Array.isArray(this.countData)) { 1235 | this.getCount(); 1236 | } else { 1237 | this.getCounts(); 1238 | } 1239 | } 1240 | 1241 | // fetch count either AJAX or JSONP 1242 | 1243 | }, { 1244 | key: 'getCount', 1245 | value: function getCount() { 1246 | var count = this.storeGet(this.type + '-' + this.shared); 1247 | 1248 | if (count) { 1249 | if (this.appendTo && typeof this.appendTo !== 'function') { 1250 | this.appendTo.appendChild(this.os); 1251 | } 1252 | countReduce(this.os, count); 1253 | } 1254 | this[this.countData.type](this.countData); 1255 | } 1256 | 1257 | // fetch multiple counts and aggregate 1258 | 1259 | }, { 1260 | key: 'getCounts', 1261 | value: function getCounts() { 1262 | var _this4 = this; 1263 | 1264 | this.total = []; 1265 | 1266 | var count = this.storeGet(this.type + '-' + this.shared); 1267 | 1268 | if (count) { 1269 | if (this.appendTo && typeof this.appendTo !== 'function') { 1270 | this.appendTo.appendChild(this.os); 1271 | } 1272 | countReduce(this.os, count); 1273 | } 1274 | 1275 | this.countData.forEach(function (countData) { 1276 | _this4[countData.type](countData, function (num) { 1277 | _this4.total.push(num); 1278 | 1279 | // total counts length now equals type array length 1280 | // so aggregate, store and insert into DOM 1281 | if (_this4.total.length === _this4.typeArr.length) { 1282 | var tot = 0; 1283 | 1284 | _this4.total.forEach(function (t) { 1285 | tot += t; 1286 | }); 1287 | 1288 | if (_this4.appendTo && typeof _this4.appendTo !== 'function') { 1289 | _this4.appendTo.appendChild(_this4.os); 1290 | } 1291 | 1292 | var local = Number(_this4.storeGet(_this4.type + '-' + _this4.shared)); 1293 | if (local > tot) { 1294 | // const latestCount = Number(this.storeGet(`${this.type}-${this.shared}-latestCount`)); 1295 | // this.storeSet(`${this.type}-${this.shared}-latestCount`, tot); 1296 | // 1297 | // tot = isNumeric(latestCount) && latestCount > 0 ? 1298 | // tot += local - latestCount : 1299 | // tot += local; 1300 | tot = local; 1301 | } 1302 | _this4.storeSet(_this4.type + '-' + _this4.shared, tot); 1303 | 1304 | countReduce(_this4.os, tot); 1305 | } 1306 | }); 1307 | }); 1308 | 1309 | if (this.appendTo && typeof this.appendTo !== 'function') { 1310 | this.appendTo.appendChild(this.os); 1311 | } 1312 | } 1313 | 1314 | // handle JSONP requests 1315 | 1316 | }, { 1317 | key: 'jsonp', 1318 | value: function jsonp(countData, cb) { 1319 | var _this5 = this; 1320 | 1321 | // define random callback and assign transform function 1322 | var callback = Math.random().toString(36).substring(7).replace(/[^a-zA-Z]/g, ''); 1323 | window[callback] = function (data) { 1324 | var count = countData.transform.apply(_this5, [data]) || 0; 1325 | 1326 | if (cb && typeof cb === 'function') { 1327 | cb(count); 1328 | } else { 1329 | if (_this5.appendTo && typeof _this5.appendTo !== 'function') { 1330 | _this5.appendTo.appendChild(_this5.os); 1331 | } 1332 | countReduce(_this5.os, count, _this5.cb); 1333 | } 1334 | 1335 | Events.trigger(_this5.os, 'counted-' + _this5.url); 1336 | }; 1337 | 1338 | // append JSONP script tag to page 1339 | var script = document.createElement('script'); 1340 | script.src = countData.url.replace('callback=?', 'callback=' + callback); 1341 | document.getElementsByTagName('head')[0].appendChild(script); 1342 | 1343 | return; 1344 | } 1345 | 1346 | // handle AJAX GET request 1347 | 1348 | }, { 1349 | key: 'get', 1350 | value: function get(countData, cb) { 1351 | var _this6 = this; 1352 | 1353 | var xhr = new XMLHttpRequest(); 1354 | 1355 | // on success pass response to transform function 1356 | xhr.onreadystatechange = function () { 1357 | if (xhr.readyState === 4) { 1358 | if (xhr.status === 200) { 1359 | var count = countData.transform.apply(_this6, [xhr, Events]) || 0; 1360 | 1361 | if (cb && typeof cb === 'function') { 1362 | cb(count); 1363 | } else { 1364 | if (_this6.appendTo && typeof _this6.appendTo !== 'function') { 1365 | _this6.appendTo.appendChild(_this6.os); 1366 | } 1367 | countReduce(_this6.os, count, _this6.cb); 1368 | } 1369 | 1370 | Events.trigger(_this6.os, 'counted-' + _this6.url); 1371 | return; 1372 | } else if (countData.url.toLowerCase().indexOf('https://api.openshare.social/job?') === 0) { 1373 | console.warn('Please sign up for Twitter counts at https://openshare.social/twitter/auth'); 1374 | var _count = 0; 1375 | 1376 | if (cb && typeof cb === 'function') { 1377 | cb(_count); 1378 | } else { 1379 | if (_this6.appendTo && typeof _this6.appendTo !== 'function') { 1380 | _this6.appendTo.appendChild(_this6.os); 1381 | } 1382 | countReduce(_this6.os, _count, _this6.cb); 1383 | } 1384 | 1385 | Events.trigger(_this6.os, 'counted-' + _this6.url); 1386 | } else { 1387 | console.warn('Failed to get API data from', countData.url, '. Please use the latest version of OpenShare.'); 1388 | var _count2 = 0; 1389 | 1390 | if (cb && typeof cb === 'function') { 1391 | cb(_count2); 1392 | } else { 1393 | if (_this6.appendTo && typeof _this6.appendTo !== 'function') { 1394 | _this6.appendTo.appendChild(_this6.os); 1395 | } 1396 | countReduce(_this6.os, _count2, _this6.cb); 1397 | } 1398 | 1399 | Events.trigger(_this6.os, 'counted-' + _this6.url); 1400 | } 1401 | } 1402 | }; 1403 | 1404 | countData.url = countData.url.startsWith('https://api.openshare.social/job?') && this.key ? countData.url + this.key : countData.url; 1405 | 1406 | xhr.open('GET', countData.url); 1407 | xhr.send(); 1408 | } 1409 | 1410 | // handle AJAX POST request 1411 | 1412 | }, { 1413 | key: 'post', 1414 | value: function post(countData, cb) { 1415 | var _this7 = this; 1416 | 1417 | var xhr = new XMLHttpRequest(); 1418 | 1419 | // on success pass response to transform function 1420 | xhr.onreadystatechange = function () { 1421 | if (xhr.readyState !== XMLHttpRequest.DONE || xhr.status !== 200) { 1422 | return; 1423 | } 1424 | 1425 | var count = countData.transform.apply(_this7, [xhr]) || 0; 1426 | 1427 | if (cb && typeof cb === 'function') { 1428 | cb(count); 1429 | } else { 1430 | if (_this7.appendTo && typeof _this7.appendTo !== 'function') { 1431 | _this7.appendTo.appendChild(_this7.os); 1432 | } 1433 | countReduce(_this7.os, count, _this7.cb); 1434 | } 1435 | Events.trigger(_this7.os, 'counted-' + _this7.url); 1436 | }; 1437 | 1438 | xhr.open('POST', countData.url); 1439 | xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8'); 1440 | xhr.send(JSON.stringify(countData.data)); 1441 | } 1442 | }, { 1443 | key: 'storeSet', 1444 | value: function storeSet(type) { 1445 | var count = arguments.length <= 1 || arguments[1] === undefined ? 0 : arguments[1]; 1446 | //eslint-disable-line 1447 | if (!window.localStorage || !type) { 1448 | return; 1449 | } 1450 | 1451 | localStorage.setItem('OpenShare-' + type, count); 1452 | } 1453 | }, { 1454 | key: 'storeGet', 1455 | value: function storeGet(type) { 1456 | //eslint-disable-line 1457 | if (!window.localStorage || !type) { 1458 | return; 1459 | } 1460 | 1461 | return localStorage.getItem('OpenShare-' + type); 1462 | } 1463 | }]); 1464 | 1465 | return Count; 1466 | }(); 1467 | 1468 | function initializeCountNode(os) { 1469 | // initialize open share object with type attribute 1470 | var type = os.getAttribute('data-open-share-count'); 1471 | var url = os.getAttribute('data-open-share-count-repo') || os.getAttribute('data-open-share-count-shot') || os.getAttribute('data-open-share-count-url'); 1472 | var count = new Count(type, url); 1473 | 1474 | count.count(os); 1475 | os.setAttribute('data-open-share-node', type); 1476 | } 1477 | 1478 | function init() { 1479 | init$1({ 1480 | selector: { 1481 | share: '[data-open-share]:not([data-open-share-node])', 1482 | count: '[data-open-share-count]:not([data-open-share-node])' 1483 | }, 1484 | cb: { 1485 | share: initializeShareNode, 1486 | count: initializeCountNode 1487 | } 1488 | })(); 1489 | } 1490 | var DataAttr = function DataAttr() { 1491 | if (document.readyState === 'complete') { 1492 | return init(); 1493 | } 1494 | document.addEventListener('readystatechange', function () { 1495 | if (document.readyState === 'complete') { 1496 | init(); 1497 | } 1498 | }, false); 1499 | }; 1500 | 1501 | /** 1502 | * Global OpenShare API to generate instances programmatically 1503 | */ 1504 | var ShareAPI = function ShareAPI() { 1505 | // global OpenShare referencing internal class for instance generation 1506 | var OpenShare$$1 = function () { 1507 | function OpenShare$$1(data, element) { 1508 | var _this8 = this; 1509 | 1510 | _classCallCheck(this, OpenShare$$1); 1511 | 1512 | if (!data.bindClick) data.bindClick = true; 1513 | 1514 | var dash = data.type.indexOf('-'); 1515 | 1516 | if (dash > -1) { 1517 | data.type = dashToCamel(dash, data.type); 1518 | } 1519 | 1520 | var node = void 0; 1521 | this.element = element; 1522 | this.data = data; 1523 | 1524 | this.os = new OpenShare(data.type, ShareTransforms[data.type]); 1525 | this.os.setData(data); 1526 | 1527 | if (!element || data.element) { 1528 | element = data.element; 1529 | node = document.createElement(element || 'a'); 1530 | if (data.type) { 1531 | node.classList.add('open-share-link', data.type); 1532 | node.setAttribute('data-open-share', data.type); 1533 | node.setAttribute('data-open-share-node', data.type); 1534 | } 1535 | if (data.innerHTML) node.innerHTML = data.innerHTML; 1536 | } 1537 | if (node) element = node; 1538 | 1539 | if (data.bindClick) { 1540 | element.addEventListener('click', function () { 1541 | _this8.share(); 1542 | }); 1543 | } 1544 | 1545 | if (data.appendTo) { 1546 | data.appendTo.appendChild(element); 1547 | } 1548 | 1549 | if (data.classes && Array.isArray(data.classes)) { 1550 | data.classes.forEach(function (cssClass) { 1551 | element.classList.add(cssClass); 1552 | }); 1553 | } 1554 | 1555 | if (data.type.toLowerCase() === 'paypal') { 1556 | var action = data.sandbox ? 'https://www.sandbox.paypal.com/cgi-bin/webscr' : 'https://www.paypal.com/cgi-bin/webscr'; 1557 | 1558 | var buyGIF = data.sandbox ? 'https://www.sandbox.paypal.com/en_US/i/btn/btn_buynow_LG.gif' : 'https://www.paypalobjects.com/en_US/i/btn/btn_buynow_LG.gif'; 1559 | 1560 | var pixelGIF = data.sandbox ? 'https://www.sandbox.paypal.com/en_US/i/scr/pixel.gif' : 'https://www.paypalobjects.com/en_US/i/scr/pixel.gif'; 1561 | 1562 | var paypalButton = '
\n\n \n \n\n \n \n\n \n \n \n\n
'; 1563 | 1564 | var hiddenDiv = document.createElement('div'); 1565 | hiddenDiv.style.display = 'none'; 1566 | hiddenDiv.innerHTML = paypalButton; 1567 | document.body.appendChild(hiddenDiv); 1568 | 1569 | this.paypal = hiddenDiv.querySelector('form'); 1570 | } 1571 | 1572 | this.element = element; 1573 | return element; 1574 | } 1575 | 1576 | // public share method to trigger share programmatically 1577 | 1578 | 1579 | _createClass(OpenShare$$1, [{ 1580 | key: 'share', 1581 | value: function share(e) { 1582 | // if dynamic instance then fetch attributes again in case of updates 1583 | if (this.data.dynamic) { 1584 | //eslint-disable-next-line 1585 | this.os.setData(data); // data is not defined 1586 | } 1587 | 1588 | if (this.data.type.toLowerCase() === 'paypal') { 1589 | this.paypal.submit(); 1590 | } else this.os.share(e); 1591 | 1592 | Events.trigger(this.element, 'shared'); 1593 | } 1594 | }]); 1595 | 1596 | return OpenShare$$1; 1597 | }(); 1598 | 1599 | return OpenShare$$1; 1600 | }; 1601 | 1602 | /** 1603 | * count API 1604 | */ 1605 | 1606 | var CountAPI = function CountAPI() { 1607 | //eslint-disable-line 1608 | // global OpenShare referencing internal class for instance generation 1609 | var Count$$1 = function Count$$1(_ref, cb) { 1610 | var type = _ref.type; 1611 | var url = _ref.url; 1612 | var _ref$appendTo = _ref.appendTo; 1613 | var appendTo = _ref$appendTo === undefined ? false : _ref$appendTo; 1614 | var element = _ref.element; 1615 | var classes = _ref.classes; 1616 | var _ref$key = _ref.key; 1617 | var key = _ref$key === undefined ? null : _ref$key; 1618 | 1619 | _classCallCheck(this, Count$$1); 1620 | 1621 | var countNode = document.createElement(element || 'span'); 1622 | 1623 | countNode.setAttribute('data-open-share-count', type); 1624 | countNode.setAttribute('data-open-share-count-url', url); 1625 | if (key) countNode.setAttribute('data-open-share-key', key); 1626 | 1627 | countNode.classList.add('open-share-count'); 1628 | 1629 | if (classes && Array.isArray(classes)) { 1630 | classes.forEach(function (cssCLass) { 1631 | countNode.classList.add(cssCLass); 1632 | }); 1633 | } 1634 | 1635 | if (appendTo) { 1636 | return new Count(type, url).count(countNode, cb, appendTo); 1637 | } 1638 | 1639 | return new Count(type, url).count(countNode, cb); 1640 | }; 1641 | 1642 | return Count$$1; 1643 | }; 1644 | 1645 | var browser = function browser() { 1646 | DataAttr(OpenShare, Count, ShareTransforms, Events); 1647 | window.OpenShare = { 1648 | share: ShareAPI(OpenShare, ShareTransforms, Events), 1649 | count: CountAPI(), 1650 | analytics: analytics 1651 | }; 1652 | }; 1653 | var browser_js = browser(); 1654 | 1655 | module.exports = browser_js; 1656 | 1657 | },{}]},{},[1]); 1658 | -------------------------------------------------------------------------------- /dist/openshare.min.js: -------------------------------------------------------------------------------- 1 | !function t(e,n,r){function a(i,s){if(!n[i]){if(!e[i]){var u="function"==typeof require&&require;if(!s&&u)return u(i,!0);if(o)return o(i,!0);var p=new Error("Cannot find module '"+i+"'");throw p.code="MODULE_NOT_FOUND",p}var h=n[i]={exports:{}};e[i][0].call(h.exports,function(t){var n=e[i][1][t];return a(n?n:t)},h,h.exports,t,e,n,r)}return n[i].exports}for(var o="function"==typeof require&&require,i=0;i-1){var e=t.split(",");e.forEach(function(t){return E(t)})}else E(t)}}function d(t,e){[].forEach.call(t,function(t){var n=new MutationObserver(function(t){e(t[0].target)});n.observe(t,{childList:!0})})}function c(t){return function(){var e=p({api:t.api||null,container:t.container||document,selector:t.selector,cb:t.cb});e(),void 0!==window.MutationObserver&&d(document.querySelectorAll("[data-open-share-watch]"),e)}}function l(t,e){t.setData({url:e.getAttribute("data-open-share-url"),text:e.getAttribute("data-open-share-text"),via:e.getAttribute("data-open-share-via"),hashtags:e.getAttribute("data-open-share-hashtags"),tweetId:e.getAttribute("data-open-share-tweet-id"),related:e.getAttribute("data-open-share-related"),screenName:e.getAttribute("data-open-share-screen-name"),userId:e.getAttribute("data-open-share-user-id"),link:e.getAttribute("data-open-share-link"),picture:e.getAttribute("data-open-share-picture"),caption:e.getAttribute("data-open-share-caption"),description:e.getAttribute("data-open-share-description"),user:e.getAttribute("data-open-share-user"),video:e.getAttribute("data-open-share-video"),username:e.getAttribute("data-open-share-username"),title:e.getAttribute("data-open-share-title"),media:e.getAttribute("data-open-share-media"),to:e.getAttribute("data-open-share-to"),subject:e.getAttribute("data-open-share-subject"),body:e.getAttribute("data-open-share-body"),ios:e.getAttribute("data-open-share-ios"),type:e.getAttribute("data-open-share-type"),center:e.getAttribute("data-open-share-center"),views:e.getAttribute("data-open-share-views"),zoom:e.getAttribute("data-open-share-zoom"),search:e.getAttribute("data-open-share-search"),saddr:e.getAttribute("data-open-share-saddr"),daddr:e.getAttribute("data-open-share-daddr"),directionsmode:e.getAttribute("data-open-share-directions-mode"),repo:e.getAttribute("data-open-share-repo"),shot:e.getAttribute("data-open-share-shot"),pen:e.getAttribute("data-open-share-pen"),view:e.getAttribute("data-open-share-view"),issue:e.getAttribute("data-open-share-issue"),buttonId:e.getAttribute("data-open-share-buttonId"),popUp:e.getAttribute("data-open-share-popup"),key:e.getAttribute("data-open-share-key")})}function f(t,e,n){n.dynamic&&l(n,e),n.share(t),O.trigger(e,"shared")}function g(t){var e=t.getAttribute("data-open-share"),n=e.indexOf("-");n>-1&&(e=C(n,e));var r=x[e];if(!r)throw new Error("Open Share: "+e+" is an invalid type");var a=new L(e,r);t.getAttribute("data-open-share-dynamic")&&(a.dynamic=!0),t.getAttribute("data-open-share-popup")&&(a.popup=!0),l(a,t),t.addEventListener("click",function(e){f(e,t,a)}),t.addEventListener("OpenShare.trigger",function(e){f(e,t,a)}),t.setAttribute("data-open-share-node",e)}function b(t,e){if("number"!=typeof t)throw new TypeError("Expected value to be a number");var n=e>0?"e":"e-",r=e>0?"e-":"e";return e=Math.abs(e),Number(Math.round(t+n+e)+r+e)}function m(t){return b(t/1e3,1)+"K"}function w(t){return b(t/1e6,1)+"M"}function v(t,e,n){e>999999?(t.innerHTML=w(e),n&&"function"==typeof n&&n(t)):e>999?(t.innerHTML=m(e),n&&"function"==typeof n&&n(t)):(t.innerHTML=e,n&&"function"==typeof n&&n(t))}function y(t){return!isNaN(parseFloat(t))&&isFinite(t)}function A(t,e,n,r){var a=new XMLHttpRequest;a.open("GET",t+"?page="+e),a.addEventListener("load",function(){var a=JSON.parse(this.response);n+=a.length,12===a.length?(e++,A(t,e,n,r)):r(n)}),a.send()}function T(t){var e=t.getAttribute("data-open-share-count"),n=t.getAttribute("data-open-share-count-repo")||t.getAttribute("data-open-share-count-shot")||t.getAttribute("data-open-share-count-url"),r=new D(e,n);r.count(t),t.setAttribute("data-open-share-node",e)}function k(){c({selector:{share:"[data-open-share]:not([data-open-share-node])",count:"[data-open-share-count]:not([data-open-share-node])"},cb:{share:g,count:T}})()}var S=function(){function t(t,e){for(var n=0;n1600||(window.location=t.shareUrl)},1500),window.location=t.mobileShareUrl}();else if("email"===this.type)window.location=this.shareUrl;else{if(this.popup&&this.transformData.popup)return this.openWindow(this.shareUrl,this.transformData.popup);window.open(this.shareUrl)}}},{key:"template",value:function(t,e){var n=["appendTo","innerHTML","classes"],r=t,a=void 0;for(a in e)!e[a]||n.indexOf(a)>-1||(e[a]=encodeURIComponent(e[a]),r+=a+"="+e[a]+"&");return r.substr(0,r.length-1)}},{key:"openWindow",value:function(t,e){var n=void 0!==window.screenLeft?window.screenLeft:screen.left,r=void 0!==window.screenTop?window.screenTop:screen.top,a=window.innerWidth?window.innerWidth:document.documentElement.clientWidth?document.documentElement.clientWidth:screen.width,o=window.innerHeight?window.innerHeight:document.documentElement.clientHeight?document.documentElement.clientHeight:screen.height,i=a/2-e.width/2+n,s=o/2-e.height/2+r,u=window.open(t,"OpenShare","width="+e.width+", height="+e.height+", top="+s+", left="+i);window.focus&&u.focus()}}]),t}(),C=function(t,e){var n=e.substr(t+1,1),r=e.substr(t,2);return e=e.replace(r,n.toUpperCase())},_=function(t,e){var n=t.type.indexOf(",")>-1,r=Number(t.storeGet(t.type+"-"+t.shared));if(r>e&&!n){var a=Number(t.storeGet(t.type+"-"+t.shared+"-latestCount"));t.storeSet(t.type+"-"+t.shared+"-latestCount",e),e=e+=y(a)&&a>0?r-a:r}return n||t.storeSet(t.type+"-"+t.shared,e),e},N={facebook:function(t){return{type:"get",url:"https://graph.facebook.com/?id="+t,transform:function(t){var e=JSON.parse(t.responseText),n=e.share&&e.share.share_count||0;return _(this,n)}}},pinterest:function(t){return{type:"jsonp",url:"https://api.pinterest.com/v1/urls/count.json?callback=?&url="+t,transform:function(t){var e=t.count||0;return _(this,e)}}},linkedin:function(t){return{type:"jsonp",url:"https://www.linkedin.com/countserv/count/share?url="+t+"&format=jsonp&callback=?",transform:function(t){var e=t.count||0;return _(this,e)}}},reddit:function(t){return{type:"get",url:"https://www.reddit.com/api/info.json?url="+t,transform:function(t){var e=JSON.parse(t.responseText),n=e.data&&e.data.children||null,r=0;return n&&n.forEach(function(t){r+=Number(t.data.ups)}),_(this,r)}}},google:function(t){return{type:"post",data:{method:"pos.plusones.get",id:"p",params:{nolog:!0,id:t,source:"widget",userId:"@viewer",groupId:"@self"},jsonrpc:"2.0",key:"p",apiVersion:"v1"},url:"https://clients6.google.com/rpc",transform:function(t){var e=JSON.parse(t.responseText),n=e.result&&e.result.metadata&&e.result.metadata.globalCounts&&e.result.metadata.globalCounts.count||0;return _(this,n)}}},githubStars:function(t){return t=t.indexOf("github.com/")>-1?t.split("github.com/")[1]:t,{type:"get",url:"https://api.github.com/repos/"+t,transform:function(t){var e=JSON.parse(t.responseText).stargazers_count||0;return _(this,e)}}},githubForks:function(t){return t=t.indexOf("github.com/")>-1?t.split("github.com/")[1]:t,{type:"get",url:"https://api.github.com/repos/"+t,transform:function(t){var e=JSON.parse(t.responseText).forks_count||0;return _(this,e)}}},githubWatchers:function(t){return t=t.indexOf("github.com/")>-1?t.split("github.com/")[1]:t,{type:"get",url:"https://api.github.com/repos/"+t,transform:function(t){var e=JSON.parse(t.responseText).watchers_count||0;return _(this,e)}}},dribbble:function(t){t=t.indexOf("dribbble.com/shots")>-1?t.split("shots/")[1]:t;var e="https://api.dribbble.com/v1/shots/"+t+"/likes";return{type:"get",url:e,transform:function(t,n){var r=this,a=JSON.parse(t.responseText).length;if(12!==a)return _(this,a);var o=2;A(e,o,a,function(t){return r.appendTo&&"function"!=typeof r.appendTo&&r.appendTo.appendChild(r.os),v(r.os,t,r.cb),n.trigger(r.os,"counted-"+r.url),_(r,t)})}}},twitter:function(t){return{type:"get",url:"https://api.openshare.social/job?url="+t+"&key=",transform:function(t){var e=JSON.parse(t.responseText).count||0;return _(this,e)}}}},D=function(){function t(e,n){var a=this;if(r(this,t),!n)throw new Error("Open Share: no url provided for count");if(0===e.indexOf("github")&&("github-stars"===e?e="githubStars":"github-forks"===e?e="githubForks":"github-watchers"===e?e="githubWatchers":console.error("Invalid Github count type. Try github-stars, github-forks, or github-watchers.")),e.indexOf(",")>-1){this.type=e,this.typeArr=this.type.split(","),this.countData=[],this.typeArr.forEach(function(t){if(!N[t])throw new Error("Open Share: "+e+" is an invalid count type");a.countData.push(N[t](n))});var o=this.storeGet(this.type+"-"+this.shared);o&&(this.appendTo&&"function"!=typeof this.appendTo&&this.appendTo.appendChild(this.os),v(this.os,o))}else{if(!N[e])throw new Error("Open Share: "+e+" is an invalid count type");this.type=e,this.countData=N[e](n)}}return S(t,[{key:"count",value:function(t,e,n){this.os=t,this.appendTo=n,this.cb=e,this.url=this.os.getAttribute("data-open-share-count"),this.shared=this.os.getAttribute("data-open-share-count-url"),this.key=this.os.getAttribute("data-open-share-key"),Array.isArray(this.countData)?this.getCounts():this.getCount()}},{key:"getCount",value:function(){var t=this.storeGet(this.type+"-"+this.shared);t&&(this.appendTo&&"function"!=typeof this.appendTo&&this.appendTo.appendChild(this.os),v(this.os,t)),this[this.countData.type](this.countData)}},{key:"getCounts",value:function(){var t=this;this.total=[];var e=this.storeGet(this.type+"-"+this.shared);e&&(this.appendTo&&"function"!=typeof this.appendTo&&this.appendTo.appendChild(this.os),v(this.os,e)),this.countData.forEach(function(e){t[e.type](e,function(e){if(t.total.push(e),t.total.length===t.typeArr.length){var n=0;t.total.forEach(function(t){n+=t}),t.appendTo&&"function"!=typeof t.appendTo&&t.appendTo.appendChild(t.os);var r=Number(t.storeGet(t.type+"-"+t.shared));r>n&&(n=r),t.storeSet(t.type+"-"+t.shared,n),v(t.os,n)}})}),this.appendTo&&"function"!=typeof this.appendTo&&this.appendTo.appendChild(this.os)}},{key:"jsonp",value:function(t,e){var n=this,r=Math.random().toString(36).substring(7).replace(/[^a-zA-Z]/g,"");window[r]=function(r){var a=t.transform.apply(n,[r])||0;e&&"function"==typeof e?e(a):(n.appendTo&&"function"!=typeof n.appendTo&&n.appendTo.appendChild(n.os),v(n.os,a,n.cb)),O.trigger(n.os,"counted-"+n.url)};var a=document.createElement("script");a.src=t.url.replace("callback=?","callback="+r),document.getElementsByTagName("head")[0].appendChild(a)}},{key:"get",value:function(t,e){var n=this,r=new XMLHttpRequest;r.onreadystatechange=function(){if(4===r.readyState){if(200===r.status){var a=t.transform.apply(n,[r,O])||0;return e&&"function"==typeof e?e(a):(n.appendTo&&"function"!=typeof n.appendTo&&n.appendTo.appendChild(n.os),v(n.os,a,n.cb)),void O.trigger(n.os,"counted-"+n.url)}if(0===t.url.toLowerCase().indexOf("https://api.openshare.social/job?")){console.warn("Please sign up for Twitter counts at https://openshare.social/twitter/auth");var o=0;e&&"function"==typeof e?e(o):(n.appendTo&&"function"!=typeof n.appendTo&&n.appendTo.appendChild(n.os),v(n.os,o,n.cb)),O.trigger(n.os,"counted-"+n.url)}else{console.warn("Failed to get API data from",t.url,". Please use the latest version of OpenShare.");var i=0;e&&"function"==typeof e?e(i):(n.appendTo&&"function"!=typeof n.appendTo&&n.appendTo.appendChild(n.os),v(n.os,i,n.cb)),O.trigger(n.os,"counted-"+n.url)}}},t.url=t.url.startsWith("https://api.openshare.social/job?")&&this.key?t.url+this.key:t.url,r.open("GET",t.url),r.send()}},{key:"post",value:function(t,e){var n=this,r=new XMLHttpRequest;r.onreadystatechange=function(){if(r.readyState===XMLHttpRequest.DONE&&200===r.status){var a=t.transform.apply(n,[r])||0;e&&"function"==typeof e?e(a):(n.appendTo&&"function"!=typeof n.appendTo&&n.appendTo.appendChild(n.os),v(n.os,a,n.cb)),O.trigger(n.os,"counted-"+n.url)}},r.open("POST",t.url),r.setRequestHeader("Content-Type","application/json;charset=UTF-8"),r.send(JSON.stringify(t.data))}},{key:"storeSet",value:function(t){var e=arguments.length<=1||void 0===arguments[1]?0:arguments[1];window.localStorage&&t&&localStorage.setItem("OpenShare-"+t,e)}},{key:"storeGet",value:function(t){if(window.localStorage&&t)return localStorage.getItem("OpenShare-"+t)}}]),t}(),M=function(){return"complete"===document.readyState?k():void document.addEventListener("readystatechange",function(){"complete"===document.readyState&&k()},!1)},q=function(){var t=function(){function t(e,n){var a=this;r(this,t),e.bindClick||(e.bindClick=!0);var o=e.type.indexOf("-");o>-1&&(e.type=C(o,e.type));var i=void 0;if(this.element=n,this.data=e,this.os=new L(e.type,x[e.type]),this.os.setData(e),n&&!e.element||(n=e.element,i=document.createElement(n||"a"),e.type&&(i.classList.add("open-share-link",e.type),i.setAttribute("data-open-share",e.type),i.setAttribute("data-open-share-node",e.type)),e.innerHTML&&(i.innerHTML=e.innerHTML)),i&&(n=i),e.bindClick&&n.addEventListener("click",function(){a.share()}),e.appendTo&&e.appendTo.appendChild(n),e.classes&&Array.isArray(e.classes)&&e.classes.forEach(function(t){n.classList.add(t)}),"paypal"===e.type.toLowerCase()){var s=e.sandbox?"https://www.sandbox.paypal.com/cgi-bin/webscr":"https://www.paypal.com/cgi-bin/webscr",u=e.sandbox?"https://www.sandbox.paypal.com/en_US/i/btn/btn_buynow_LG.gif":"https://www.paypalobjects.com/en_US/i/btn/btn_buynow_LG.gif",p=e.sandbox?"https://www.sandbox.paypal.com/en_US/i/scr/pixel.gif":"https://www.paypalobjects.com/en_US/i/scr/pixel.gif",h="
\n\n \n \n\n \n \n\n \n \n -1){var e=t.split(",");e.forEach(function(t){return S(t)})}else S(t)}}function h(t,e){[].forEach.call(t,function(t){var n=new MutationObserver(function(t){e(t[0].target)});n.observe(t,{childList:!0})})}function d(t){return function(){var e=p({api:t.api||null,container:t.container||document,selector:t.selector,cb:t.cb});e(),void 0!==window.MutationObserver&&h(document.querySelectorAll("[data-open-share-watch]"),e)}}function l(t,e){if("number"!=typeof t)throw new TypeError("Expected value to be a number");var n=e>0?"e":"e-",r=e>0?"e-":"e";return e=Math.abs(e),Number(Math.round(t+n+e)+r+e)}function f(t){return l(t/1e3,1)+"K"}function g(t){return l(t/1e6,1)+"M"}function b(t,e,n){e>999999?(t.innerHTML=g(e),n&&"function"==typeof n&&n(t)):e>999?(t.innerHTML=f(e),n&&"function"==typeof n&&n(t)):(t.innerHTML=e,n&&"function"==typeof n&&n(t))}function y(t){return!isNaN(parseFloat(t))&&isFinite(t)}function v(t,e,n,r){var a=new XMLHttpRequest;a.open("GET",t+"?page="+e),a.addEventListener("load",function(){var a=JSON.parse(this.response);n+=a.length,12===a.length?(e++,v(t,e,n,r)):r(n)}),a.send()}function m(t){var e=t.getAttribute("data-open-share-count"),n=t.getAttribute("data-open-share-count-repo")||t.getAttribute("data-open-share-count-shot")||t.getAttribute("data-open-share-count-url"),r=new E(e,n);r.count(t),t.setAttribute("data-open-share-node",e)}function w(){d({api:"count",selector:"[data-open-share-count]:not([data-open-share-node])",cb:m})()}var T=function(){function t(t,e){for(var n=0;n-1,r=Number(t.storeGet(t.type+"-"+t.shared));if(r>e&&!n){var a=Number(t.storeGet(t.type+"-"+t.shared+"-latestCount"));t.storeSet(t.type+"-"+t.shared+"-latestCount",e),e=e+=y(a)&&a>0?r-a:r}return n||t.storeSet(t.type+"-"+t.shared,e),e},O={facebook:function(t){return{type:"get",url:"https://graph.facebook.com/?id="+t,transform:function(t){var e=JSON.parse(t.responseText),n=e.share&&e.share.share_count||0;return k(this,n)}}},pinterest:function(t){return{type:"jsonp",url:"https://api.pinterest.com/v1/urls/count.json?callback=?&url="+t,transform:function(t){var e=t.count||0;return k(this,e)}}},linkedin:function(t){return{type:"jsonp",url:"https://www.linkedin.com/countserv/count/share?url="+t+"&format=jsonp&callback=?",transform:function(t){var e=t.count||0;return k(this,e)}}},reddit:function(t){return{type:"get",url:"https://www.reddit.com/api/info.json?url="+t,transform:function(t){var e=JSON.parse(t.responseText),n=e.data&&e.data.children||null,r=0;return n&&n.forEach(function(t){r+=Number(t.data.ups)}),k(this,r)}}},google:function(t){return{type:"post",data:{method:"pos.plusones.get",id:"p",params:{nolog:!0,id:t,source:"widget",userId:"@viewer",groupId:"@self"},jsonrpc:"2.0",key:"p",apiVersion:"v1"},url:"https://clients6.google.com/rpc",transform:function(t){var e=JSON.parse(t.responseText),n=e.result&&e.result.metadata&&e.result.metadata.globalCounts&&e.result.metadata.globalCounts.count||0;return k(this,n)}}},githubStars:function(t){return t=t.indexOf("github.com/")>-1?t.split("github.com/")[1]:t,{type:"get",url:"https://api.github.com/repos/"+t,transform:function(t){var e=JSON.parse(t.responseText).stargazers_count||0;return k(this,e)}}},githubForks:function(t){return t=t.indexOf("github.com/")>-1?t.split("github.com/")[1]:t,{type:"get",url:"https://api.github.com/repos/"+t,transform:function(t){var e=JSON.parse(t.responseText).forks_count||0;return k(this,e)}}},githubWatchers:function(t){return t=t.indexOf("github.com/")>-1?t.split("github.com/")[1]:t,{type:"get",url:"https://api.github.com/repos/"+t,transform:function(t){var e=JSON.parse(t.responseText).watchers_count||0;return k(this,e)}}},dribbble:function(t){t=t.indexOf("dribbble.com/shots")>-1?t.split("shots/")[1]:t;var e="https://api.dribbble.com/v1/shots/"+t+"/likes";return{type:"get",url:e,transform:function(t,n){var r=this,a=JSON.parse(t.responseText).length;if(12!==a)return k(this,a);var o=2;v(e,o,a,function(t){return r.appendTo&&"function"!=typeof r.appendTo&&r.appendTo.appendChild(r.os),b(r.os,t,r.cb),n.trigger(r.os,"counted-"+r.url),k(r,t)})}}},twitter:function(t){return{type:"get",url:"https://api.openshare.social/job?url="+t+"&key=",transform:function(t){var e=JSON.parse(t.responseText).count||0;return k(this,e)}}}},E=function(){function t(e,n){var a=this;if(r(this,t),!n)throw new Error("Open Share: no url provided for count");if(0===e.indexOf("github")&&("github-stars"===e?e="githubStars":"github-forks"===e?e="githubForks":"github-watchers"===e?e="githubWatchers":console.error("Invalid Github count type. Try github-stars, github-forks, or github-watchers.")),e.indexOf(",")>-1){this.type=e,this.typeArr=this.type.split(","),this.countData=[],this.typeArr.forEach(function(t){if(!O[t])throw new Error("Open Share: "+e+" is an invalid count type");a.countData.push(O[t](n))});var o=this.storeGet(this.type+"-"+this.shared);o&&(this.appendTo&&"function"!=typeof this.appendTo&&this.appendTo.appendChild(this.os),b(this.os,o))}else{if(!O[e])throw new Error("Open Share: "+e+" is an invalid count type");this.type=e,this.countData=O[e](n)}}return T(t,[{key:"count",value:function(t,e,n){this.os=t,this.appendTo=n,this.cb=e,this.url=this.os.getAttribute("data-open-share-count"),this.shared=this.os.getAttribute("data-open-share-count-url"),this.key=this.os.getAttribute("data-open-share-key"),Array.isArray(this.countData)?this.getCounts():this.getCount()}},{key:"getCount",value:function(){var t=this.storeGet(this.type+"-"+this.shared);t&&(this.appendTo&&"function"!=typeof this.appendTo&&this.appendTo.appendChild(this.os),b(this.os,t)),this[this.countData.type](this.countData)}},{key:"getCounts",value:function(){var t=this;this.total=[];var e=this.storeGet(this.type+"-"+this.shared);e&&(this.appendTo&&"function"!=typeof this.appendTo&&this.appendTo.appendChild(this.os),b(this.os,e)),this.countData.forEach(function(e){t[e.type](e,function(e){if(t.total.push(e),t.total.length===t.typeArr.length){var n=0;t.total.forEach(function(t){n+=t}),t.appendTo&&"function"!=typeof t.appendTo&&t.appendTo.appendChild(t.os);var r=Number(t.storeGet(t.type+"-"+t.shared));r>n&&(n=r),t.storeSet(t.type+"-"+t.shared,n),b(t.os,n)}})}),this.appendTo&&"function"!=typeof this.appendTo&&this.appendTo.appendChild(this.os)}},{key:"jsonp",value:function(t,e){var n=this,r=Math.random().toString(36).substring(7).replace(/[^a-zA-Z]/g,"");window[r]=function(r){var a=t.transform.apply(n,[r])||0;e&&"function"==typeof e?e(a):(n.appendTo&&"function"!=typeof n.appendTo&&n.appendTo.appendChild(n.os),b(n.os,a,n.cb)),A.trigger(n.os,"counted-"+n.url)};var a=document.createElement("script");a.src=t.url.replace("callback=?","callback="+r),document.getElementsByTagName("head")[0].appendChild(a)}},{key:"get",value:function(t,e){var n=this,r=new XMLHttpRequest;r.onreadystatechange=function(){if(4===r.readyState){if(200===r.status){var a=t.transform.apply(n,[r,A])||0;return e&&"function"==typeof e?e(a):(n.appendTo&&"function"!=typeof n.appendTo&&n.appendTo.appendChild(n.os),b(n.os,a,n.cb)),void A.trigger(n.os,"counted-"+n.url)}if(0===t.url.toLowerCase().indexOf("https://api.openshare.social/job?")){console.warn("Please sign up for Twitter counts at https://openshare.social/twitter/auth");var o=0;e&&"function"==typeof e?e(o):(n.appendTo&&"function"!=typeof n.appendTo&&n.appendTo.appendChild(n.os),b(n.os,o,n.cb)),A.trigger(n.os,"counted-"+n.url)}else{console.warn("Failed to get API data from",t.url,". Please use the latest version of OpenShare.");var i=0;e&&"function"==typeof e?e(i):(n.appendTo&&"function"!=typeof n.appendTo&&n.appendTo.appendChild(n.os),b(n.os,i,n.cb)),A.trigger(n.os,"counted-"+n.url)}}},t.url=t.url.startsWith("https://api.openshare.social/job?")&&this.key?t.url+this.key:t.url,r.open("GET",t.url),r.send()}},{key:"post",value:function(t,e){var n=this,r=new XMLHttpRequest;r.onreadystatechange=function(){if(r.readyState===XMLHttpRequest.DONE&&200===r.status){var a=t.transform.apply(n,[r])||0;e&&"function"==typeof e?e(a):(n.appendTo&&"function"!=typeof n.appendTo&&n.appendTo.appendChild(n.os),b(n.os,a,n.cb)),A.trigger(n.os,"counted-"+n.url)}},r.open("POST",t.url),r.setRequestHeader("Content-Type","application/json;charset=UTF-8"),r.send(JSON.stringify(t.data))}},{key:"storeSet",value:function(t){var e=arguments.length<=1||void 0===arguments[1]?0:arguments[1];window.localStorage&&t&&localStorage.setItem("OpenShare-"+t,e)}},{key:"storeGet",value:function(t){if(window.localStorage&&t)return localStorage.getItem("OpenShare-"+t)}}]),t}(),C=function(){return"complete"===document.readyState&&w(),document.addEventListener("readystatechange",function(){"complete"===document.readyState&&w()},!1),t("./src/modules/count-api")()};e.exports=C},{"./src/modules/count-api":4}],3:[function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function a(t,e){window.ga?(e&&e(),i(function(e){var n=e.target.getAttribute("data-open-share"),r=e.target.getAttribute("data-open-share-link")||e.target.getAttribute("data-open-share-url")||e.target.getAttribute("data-open-share-username")||e.target.getAttribute("data-open-share-center")||e.target.getAttribute("data-open-share-search")||e.target.getAttribute("data-open-share-body");"event"===t&&ga("send","event",{eventCategory:"OpenShare Click",eventAction:n,eventLabel:r,transport:"beacon"}),"social"===t&&ga("send",{hitType:"social",socialNetwork:n,socialAction:"share",socialTarget:r})})):setTimeout(function(){a(t,e)},1e3)}function o(t){window.dataLayer&&window.dataLayer[0]["gtm.start"]?(t&&t(),i(u),s(function(t){var e=t.target?t.target.innerHTML:t.innerHTML,n=t.target?t.target.getAttribute("data-open-share-count-url"):t.getAttribute("data-open-share-count-url");window.dataLayer.push({event:"OpenShare Count",platform:n,resource:e,activity:"count"})})):setTimeout(function(){o(t)},1e3)}function i(t){[].forEach.call(document.querySelectorAll("[data-open-share]"),function(e){e.addEventListener("OpenShare.shared",t)})}function s(t){var e=document.querySelectorAll("[data-open-share-count]");[].forEach.call(e,function(e){e.textContent?t(e):e.addEventListener("OpenShare.counted-"+e.getAttribute("data-open-share-count-url"),t)})}function u(t){var e=t.target.getAttribute("data-open-share"),n=t.target.getAttribute("data-open-share-link")||t.target.getAttribute("data-open-share-url")||t.target.getAttribute("data-open-share-username")||t.target.getAttribute("data-open-share-center")||t.target.getAttribute("data-open-share-search")||t.target.getAttribute("data-open-share-body");window.dataLayer.push({event:"OpenShare Share",platform:e,resource:n,activity:"share"})}function p(t){return function(){if(c(),t.api){var e=t.container.querySelectorAll(t.selector);[].forEach.call(e,t.cb),k.trigger(document,t.api+"-loaded")}else{var n=t.container.querySelectorAll(t.selector.share);[].forEach.call(n,t.cb.share),k.trigger(document,"share-loaded");var r=t.container.querySelectorAll(t.selector.count);[].forEach.call(r,t.cb.count),k.trigger(document,"count-loaded")}}}function c(){if(document.querySelector("[data-open-share-analytics]")){var t=document.querySelector("[data-open-share-analytics]").getAttribute("data-open-share-analytics");if(t.indexOf(",")>-1){var e=t.split(",");e.forEach(function(t){return O(t)})}else O(t)}}function h(t,e){[].forEach.call(t,function(t){var n=new MutationObserver(function(t){e(t[0].target)});n.observe(t,{childList:!0})})}function d(t){return function(){var e=p({api:t.api||null,container:t.container||document,selector:t.selector,cb:t.cb});e(),void 0!==window.MutationObserver&&h(document.querySelectorAll("[data-open-share-watch]"),e)}}function l(t,e){t.setData({url:e.getAttribute("data-open-share-url"),text:e.getAttribute("data-open-share-text"),via:e.getAttribute("data-open-share-via"),hashtags:e.getAttribute("data-open-share-hashtags"),tweetId:e.getAttribute("data-open-share-tweet-id"),related:e.getAttribute("data-open-share-related"),screenName:e.getAttribute("data-open-share-screen-name"),userId:e.getAttribute("data-open-share-user-id"),link:e.getAttribute("data-open-share-link"),picture:e.getAttribute("data-open-share-picture"),caption:e.getAttribute("data-open-share-caption"),description:e.getAttribute("data-open-share-description"),user:e.getAttribute("data-open-share-user"),video:e.getAttribute("data-open-share-video"),username:e.getAttribute("data-open-share-username"),title:e.getAttribute("data-open-share-title"),media:e.getAttribute("data-open-share-media"),to:e.getAttribute("data-open-share-to"),subject:e.getAttribute("data-open-share-subject"),body:e.getAttribute("data-open-share-body"),ios:e.getAttribute("data-open-share-ios"),type:e.getAttribute("data-open-share-type"),center:e.getAttribute("data-open-share-center"),views:e.getAttribute("data-open-share-views"),zoom:e.getAttribute("data-open-share-zoom"),search:e.getAttribute("data-open-share-search"),saddr:e.getAttribute("data-open-share-saddr"),daddr:e.getAttribute("data-open-share-daddr"),directionsmode:e.getAttribute("data-open-share-directions-mode"),repo:e.getAttribute("data-open-share-repo"),shot:e.getAttribute("data-open-share-shot"),pen:e.getAttribute("data-open-share-pen"),view:e.getAttribute("data-open-share-view"),issue:e.getAttribute("data-open-share-issue"),buttonId:e.getAttribute("data-open-share-buttonId"),popUp:e.getAttribute("data-open-share-popup"),key:e.getAttribute("data-open-share-key")})}function f(t,e,n){n.dynamic&&l(n,e),n.share(t),k.trigger(e,"shared")}function g(t){var e=t.getAttribute("data-open-share"),n=e.indexOf("-");n>-1&&(e=L(n,e));var r=E[e];if(!r)throw new Error("Open Share: "+e+" is an invalid type");var a=new C(e,r);t.getAttribute("data-open-share-dynamic")&&(a.dynamic=!0),t.getAttribute("data-open-share-popup")&&(a.popup=!0),l(a,t),t.addEventListener("click",function(e){f(e,t,a)}),t.addEventListener("OpenShare.trigger",function(e){f(e,t,a)}),t.setAttribute("data-open-share-node",e)}function b(t,e){if("number"!=typeof t)throw new TypeError("Expected value to be a number");var n=e>0?"e":"e-",r=e>0?"e-":"e";return e=Math.abs(e),Number(Math.round(t+n+e)+r+e)}function y(t){return b(t/1e3,1)+"K"}function v(t){return b(t/1e6,1)+"M"}function m(t,e,n){e>999999?(t.innerHTML=v(e),n&&"function"==typeof n&&n(t)):e>999?(t.innerHTML=y(e),n&&"function"==typeof n&&n(t)):(t.innerHTML=e,n&&"function"==typeof n&&n(t))}function w(t){return!isNaN(parseFloat(t))&&isFinite(t)}function T(t,e,n,r){var a=new XMLHttpRequest;a.open("GET",t+"?page="+e),a.addEventListener("load",function(){var a=JSON.parse(this.response);n+=a.length,12===a.length?(e++,T(t,e,n,r)):r(n)}),a.send()}function A(){d({api:"share",selector:"[data-open-share]:not([data-open-share-node])",cb:g})()}var S=function(){function t(t,e){for(var n=0;n1600||(window.location=t.shareUrl)},1500),window.location=t.mobileShareUrl}();else if("email"===this.type)window.location=this.shareUrl;else{if(this.popup&&this.transformData.popup)return this.openWindow(this.shareUrl,this.transformData.popup);window.open(this.shareUrl)}}},{key:"template",value:function(t,e){var n=["appendTo","innerHTML","classes"],r=t,a=void 0;for(a in e)!e[a]||n.indexOf(a)>-1||(e[a]=encodeURIComponent(e[a]),r+=a+"="+e[a]+"&");return r.substr(0,r.length-1)}},{key:"openWindow",value:function(t,e){var n=void 0!==window.screenLeft?window.screenLeft:screen.left,r=void 0!==window.screenTop?window.screenTop:screen.top,a=window.innerWidth?window.innerWidth:document.documentElement.clientWidth?document.documentElement.clientWidth:screen.width,o=window.innerHeight?window.innerHeight:document.documentElement.clientHeight?document.documentElement.clientHeight:screen.height,i=a/2-e.width/2+n,s=o/2-e.height/2+r,u=window.open(t,"OpenShare","width="+e.width+", height="+e.height+", top="+s+", left="+i);window.focus&&u.focus()}}]),t}(),L=function(t,e){var n=e.substr(t+1,1),r=e.substr(t,2);return e=e.replace(r,n.toUpperCase())},x=function(t,e){var n=t.type.indexOf(",")>-1,r=Number(t.storeGet(t.type+"-"+t.shared));if(r>e&&!n){var a=Number(t.storeGet(t.type+"-"+t.shared+"-latestCount"));t.storeSet(t.type+"-"+t.shared+"-latestCount",e),e=e+=w(a)&&a>0?r-a:r}return n||t.storeSet(t.type+"-"+t.shared,e),e},N={facebook:function(t){return{type:"get",url:"https://graph.facebook.com/?id="+t,transform:function(t){var e=JSON.parse(t.responseText),n=e.share&&e.share.share_count||0;return x(this,n)}}},pinterest:function(t){return{type:"jsonp",url:"https://api.pinterest.com/v1/urls/count.json?callback=?&url="+t,transform:function(t){var e=t.count||0;return x(this,e)}}},linkedin:function(t){return{type:"jsonp",url:"https://www.linkedin.com/countserv/count/share?url="+t+"&format=jsonp&callback=?",transform:function(t){var e=t.count||0;return x(this,e)}}},reddit:function(t){return{type:"get",url:"https://www.reddit.com/api/info.json?url="+t,transform:function(t){var e=JSON.parse(t.responseText),n=e.data&&e.data.children||null,r=0;return n&&n.forEach(function(t){r+=Number(t.data.ups)}),x(this,r)}}},google:function(t){return{type:"post",data:{method:"pos.plusones.get",id:"p",params:{nolog:!0,id:t,source:"widget",userId:"@viewer",groupId:"@self"},jsonrpc:"2.0",key:"p",apiVersion:"v1"},url:"https://clients6.google.com/rpc",transform:function(t){var e=JSON.parse(t.responseText),n=e.result&&e.result.metadata&&e.result.metadata.globalCounts&&e.result.metadata.globalCounts.count||0;return x(this,n)}}},githubStars:function(t){return t=t.indexOf("github.com/")>-1?t.split("github.com/")[1]:t,{type:"get",url:"https://api.github.com/repos/"+t,transform:function(t){var e=JSON.parse(t.responseText).stargazers_count||0;return x(this,e)}}},githubForks:function(t){return t=t.indexOf("github.com/")>-1?t.split("github.com/")[1]:t,{type:"get",url:"https://api.github.com/repos/"+t,transform:function(t){var e=JSON.parse(t.responseText).forks_count||0;return x(this,e)}}},githubWatchers:function(t){return t=t.indexOf("github.com/")>-1?t.split("github.com/")[1]:t,{type:"get",url:"https://api.github.com/repos/"+t,transform:function(t){var e=JSON.parse(t.responseText).watchers_count||0;return x(this,e)}}},dribbble:function(t){t=t.indexOf("dribbble.com/shots")>-1?t.split("shots/")[1]:t;var e="https://api.dribbble.com/v1/shots/"+t+"/likes";return{type:"get",url:e,transform:function(t,n){var r=this,a=JSON.parse(t.responseText).length;if(12!==a)return x(this,a);var o=2;T(e,o,a,function(t){return r.appendTo&&"function"!=typeof r.appendTo&&r.appendTo.appendChild(r.os),m(r.os,t,r.cb),n.trigger(r.os,"counted-"+r.url),x(r,t)})}}},twitter:function(t){return{type:"get",url:"https://api.openshare.social/job?url="+t+"&key=",transform:function(t){var e=JSON.parse(t.responseText).count||0;return x(this,e)}}}},M=function(){function t(e,n){var a=this;if(r(this,t),!n)throw new Error("Open Share: no url provided for count");if(0===e.indexOf("github")&&("github-stars"===e?e="githubStars":"github-forks"===e?e="githubForks":"github-watchers"===e?e="githubWatchers":console.error("Invalid Github count type. Try github-stars, github-forks, or github-watchers.")),e.indexOf(",")>-1){this.type=e,this.typeArr=this.type.split(","),this.countData=[],this.typeArr.forEach(function(t){if(!N[t])throw new Error("Open Share: "+e+" is an invalid count type");a.countData.push(N[t](n))});var o=this.storeGet(this.type+"-"+this.shared);o&&(this.appendTo&&"function"!=typeof this.appendTo&&this.appendTo.appendChild(this.os),m(this.os,o))}else{if(!N[e])throw new Error("Open Share: "+e+" is an invalid count type");this.type=e,this.countData=N[e](n)}}return S(t,[{key:"count",value:function(t,e,n){this.os=t,this.appendTo=n,this.cb=e,this.url=this.os.getAttribute("data-open-share-count"),this.shared=this.os.getAttribute("data-open-share-count-url"),this.key=this.os.getAttribute("data-open-share-key"),Array.isArray(this.countData)?this.getCounts():this.getCount()}},{key:"getCount",value:function(){var t=this.storeGet(this.type+"-"+this.shared);t&&(this.appendTo&&"function"!=typeof this.appendTo&&this.appendTo.appendChild(this.os),m(this.os,t)),this[this.countData.type](this.countData)}},{key:"getCounts",value:function(){var t=this;this.total=[];var e=this.storeGet(this.type+"-"+this.shared);e&&(this.appendTo&&"function"!=typeof this.appendTo&&this.appendTo.appendChild(this.os),m(this.os,e)),this.countData.forEach(function(e){t[e.type](e,function(e){if(t.total.push(e),t.total.length===t.typeArr.length){var n=0;t.total.forEach(function(t){n+=t}),t.appendTo&&"function"!=typeof t.appendTo&&t.appendTo.appendChild(t.os);var r=Number(t.storeGet(t.type+"-"+t.shared));r>n&&(n=r),t.storeSet(t.type+"-"+t.shared,n),m(t.os,n)}})}),this.appendTo&&"function"!=typeof this.appendTo&&this.appendTo.appendChild(this.os)}},{key:"jsonp",value:function(t,e){var n=this,r=Math.random().toString(36).substring(7).replace(/[^a-zA-Z]/g,"");window[r]=function(r){var a=t.transform.apply(n,[r])||0;e&&"function"==typeof e?e(a):(n.appendTo&&"function"!=typeof n.appendTo&&n.appendTo.appendChild(n.os),m(n.os,a,n.cb)),k.trigger(n.os,"counted-"+n.url)};var a=document.createElement("script");a.src=t.url.replace("callback=?","callback="+r),document.getElementsByTagName("head")[0].appendChild(a)}},{key:"get",value:function(t,e){var n=this,r=new XMLHttpRequest; 2 | r.onreadystatechange=function(){if(4===r.readyState){if(200===r.status){var a=t.transform.apply(n,[r,k])||0;return e&&"function"==typeof e?e(a):(n.appendTo&&"function"!=typeof n.appendTo&&n.appendTo.appendChild(n.os),m(n.os,a,n.cb)),void k.trigger(n.os,"counted-"+n.url)}if(0===t.url.toLowerCase().indexOf("https://api.openshare.social/job?")){console.warn("Please sign up for Twitter counts at https://openshare.social/twitter/auth");var o=0;e&&"function"==typeof e?e(o):(n.appendTo&&"function"!=typeof n.appendTo&&n.appendTo.appendChild(n.os),m(n.os,o,n.cb)),k.trigger(n.os,"counted-"+n.url)}else{console.warn("Failed to get API data from",t.url,". Please use the latest version of OpenShare.");var i=0;e&&"function"==typeof e?e(i):(n.appendTo&&"function"!=typeof n.appendTo&&n.appendTo.appendChild(n.os),m(n.os,i,n.cb)),k.trigger(n.os,"counted-"+n.url)}}},t.url=t.url.startsWith("https://api.openshare.social/job?")&&this.key?t.url+this.key:t.url,r.open("GET",t.url),r.send()}},{key:"post",value:function(t,e){var n=this,r=new XMLHttpRequest;r.onreadystatechange=function(){if(r.readyState===XMLHttpRequest.DONE&&200===r.status){var a=t.transform.apply(n,[r])||0;e&&"function"==typeof e?e(a):(n.appendTo&&"function"!=typeof n.appendTo&&n.appendTo.appendChild(n.os),m(n.os,a,n.cb)),k.trigger(n.os,"counted-"+n.url)}},r.open("POST",t.url),r.setRequestHeader("Content-Type","application/json;charset=UTF-8"),r.send(JSON.stringify(t.data))}},{key:"storeSet",value:function(t){var e=arguments.length<=1||void 0===arguments[1]?0:arguments[1];window.localStorage&&t&&localStorage.setItem("OpenShare-"+t,e)}},{key:"storeGet",value:function(t){if(window.localStorage&&t)return localStorage.getItem("OpenShare-"+t)}}]),t}(),q=function(){var t=function t(e,n){var a=e.type,o=e.url,i=e.appendTo,s=void 0!==i&&i,u=e.element,p=e.classes,c=e.key,h=void 0===c?null:c;r(this,t);var d=document.createElement(u||"span");return d.setAttribute("data-open-share-count",a),d.setAttribute("data-open-share-count-url",o),h&&d.setAttribute("data-open-share-key",h),d.classList.add("open-share-count"),p&&Array.isArray(p)&&p.forEach(function(t){d.classList.add(t)}),s?new M(a,o).count(d,n,s):new M(a,o).count(d,n)};return t},j=function(){return"complete"===document.readyState&&A(),document.addEventListener("readystatechange",function(){"complete"===document.readyState&&A()},!1),q()};e.exports=j},{}],4:[function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function a(t,e){if("number"!=typeof t)throw new TypeError("Expected value to be a number");var n=e>0?"e":"e-",r=e>0?"e-":"e";return e=Math.abs(e),Number(Math.round(t+n+e)+r+e)}function o(t){return a(t/1e3,1)+"K"}function i(t){return a(t/1e6,1)+"M"}function s(t,e,n){e>999999?(t.innerHTML=i(e),n&&"function"==typeof n&&n(t)):e>999?(t.innerHTML=o(e),n&&"function"==typeof n&&n(t)):(t.innerHTML=e,n&&"function"==typeof n&&n(t))}function u(t){return!isNaN(parseFloat(t))&&isFinite(t)}function p(t,e,n,r){var a=new XMLHttpRequest;a.open("GET",t+"?page="+e),a.addEventListener("load",function(){var a=JSON.parse(this.response);n+=a.length,12===a.length?(e++,p(t,e,n,r)):r(n)}),a.send()}var c=function(){function t(t,e){for(var n=0;n-1,r=Number(t.storeGet(t.type+"-"+t.shared));if(r>e&&!n){var a=Number(t.storeGet(t.type+"-"+t.shared+"-latestCount"));t.storeSet(t.type+"-"+t.shared+"-latestCount",e),e=e+=u(a)&&a>0?r-a:r}return n||t.storeSet(t.type+"-"+t.shared,e),e},d={facebook:function(t){return{type:"get",url:"https://graph.facebook.com/?id="+t,transform:function(t){var e=JSON.parse(t.responseText),n=e.share&&e.share.share_count||0;return h(this,n)}}},pinterest:function(t){return{type:"jsonp",url:"https://api.pinterest.com/v1/urls/count.json?callback=?&url="+t,transform:function(t){var e=t.count||0;return h(this,e)}}},linkedin:function(t){return{type:"jsonp",url:"https://www.linkedin.com/countserv/count/share?url="+t+"&format=jsonp&callback=?",transform:function(t){var e=t.count||0;return h(this,e)}}},reddit:function(t){return{type:"get",url:"https://www.reddit.com/api/info.json?url="+t,transform:function(t){var e=JSON.parse(t.responseText),n=e.data&&e.data.children||null,r=0;return n&&n.forEach(function(t){r+=Number(t.data.ups)}),h(this,r)}}},google:function(t){return{type:"post",data:{method:"pos.plusones.get",id:"p",params:{nolog:!0,id:t,source:"widget",userId:"@viewer",groupId:"@self"},jsonrpc:"2.0",key:"p",apiVersion:"v1"},url:"https://clients6.google.com/rpc",transform:function(t){var e=JSON.parse(t.responseText),n=e.result&&e.result.metadata&&e.result.metadata.globalCounts&&e.result.metadata.globalCounts.count||0;return h(this,n)}}},githubStars:function(t){return t=t.indexOf("github.com/")>-1?t.split("github.com/")[1]:t,{type:"get",url:"https://api.github.com/repos/"+t,transform:function(t){var e=JSON.parse(t.responseText).stargazers_count||0;return h(this,e)}}},githubForks:function(t){return t=t.indexOf("github.com/")>-1?t.split("github.com/")[1]:t,{type:"get",url:"https://api.github.com/repos/"+t,transform:function(t){var e=JSON.parse(t.responseText).forks_count||0;return h(this,e)}}},githubWatchers:function(t){return t=t.indexOf("github.com/")>-1?t.split("github.com/")[1]:t,{type:"get",url:"https://api.github.com/repos/"+t,transform:function(t){var e=JSON.parse(t.responseText).watchers_count||0;return h(this,e)}}},dribbble:function(t){t=t.indexOf("dribbble.com/shots")>-1?t.split("shots/")[1]:t;var e="https://api.dribbble.com/v1/shots/"+t+"/likes";return{type:"get",url:e,transform:function(t,n){var r=this,a=JSON.parse(t.responseText).length;if(12!==a)return h(this,a);var o=2;p(e,o,a,function(t){return r.appendTo&&"function"!=typeof r.appendTo&&r.appendTo.appendChild(r.os),s(r.os,t,r.cb),n.trigger(r.os,"counted-"+r.url),h(r,t)})}}},twitter:function(t){return{type:"get",url:"https://api.openshare.social/job?url="+t+"&key=",transform:function(t){var e=JSON.parse(t.responseText).count||0;return h(this,e)}}}},l={trigger:function(t,e){var n=document.createEvent("Event");n.initEvent("OpenShare."+e,!0,!0),t.dispatchEvent(n)}},f=function(){function t(e,n){var a=this;if(r(this,t),!n)throw new Error("Open Share: no url provided for count");if(0===e.indexOf("github")&&("github-stars"===e?e="githubStars":"github-forks"===e?e="githubForks":"github-watchers"===e?e="githubWatchers":console.error("Invalid Github count type. Try github-stars, github-forks, or github-watchers.")),e.indexOf(",")>-1){this.type=e,this.typeArr=this.type.split(","),this.countData=[],this.typeArr.forEach(function(t){if(!d[t])throw new Error("Open Share: "+e+" is an invalid count type");a.countData.push(d[t](n))});var o=this.storeGet(this.type+"-"+this.shared);o&&(this.appendTo&&"function"!=typeof this.appendTo&&this.appendTo.appendChild(this.os),s(this.os,o))}else{if(!d[e])throw new Error("Open Share: "+e+" is an invalid count type");this.type=e,this.countData=d[e](n)}}return c(t,[{key:"count",value:function(t,e,n){this.os=t,this.appendTo=n,this.cb=e,this.url=this.os.getAttribute("data-open-share-count"),this.shared=this.os.getAttribute("data-open-share-count-url"),this.key=this.os.getAttribute("data-open-share-key"),Array.isArray(this.countData)?this.getCounts():this.getCount()}},{key:"getCount",value:function(){var t=this.storeGet(this.type+"-"+this.shared);t&&(this.appendTo&&"function"!=typeof this.appendTo&&this.appendTo.appendChild(this.os),s(this.os,t)),this[this.countData.type](this.countData)}},{key:"getCounts",value:function(){var t=this;this.total=[];var e=this.storeGet(this.type+"-"+this.shared);e&&(this.appendTo&&"function"!=typeof this.appendTo&&this.appendTo.appendChild(this.os),s(this.os,e)),this.countData.forEach(function(e){t[e.type](e,function(e){if(t.total.push(e),t.total.length===t.typeArr.length){var n=0;t.total.forEach(function(t){n+=t}),t.appendTo&&"function"!=typeof t.appendTo&&t.appendTo.appendChild(t.os);var r=Number(t.storeGet(t.type+"-"+t.shared));r>n&&(n=r),t.storeSet(t.type+"-"+t.shared,n),s(t.os,n)}})}),this.appendTo&&"function"!=typeof this.appendTo&&this.appendTo.appendChild(this.os)}},{key:"jsonp",value:function(t,e){var n=this,r=Math.random().toString(36).substring(7).replace(/[^a-zA-Z]/g,"");window[r]=function(r){var a=t.transform.apply(n,[r])||0;e&&"function"==typeof e?e(a):(n.appendTo&&"function"!=typeof n.appendTo&&n.appendTo.appendChild(n.os),s(n.os,a,n.cb)),l.trigger(n.os,"counted-"+n.url)};var a=document.createElement("script");a.src=t.url.replace("callback=?","callback="+r),document.getElementsByTagName("head")[0].appendChild(a)}},{key:"get",value:function(t,e){var n=this,r=new XMLHttpRequest;r.onreadystatechange=function(){if(4===r.readyState){if(200===r.status){var a=t.transform.apply(n,[r,l])||0;return e&&"function"==typeof e?e(a):(n.appendTo&&"function"!=typeof n.appendTo&&n.appendTo.appendChild(n.os),s(n.os,a,n.cb)),void l.trigger(n.os,"counted-"+n.url)}if(0===t.url.toLowerCase().indexOf("https://api.openshare.social/job?")){console.warn("Please sign up for Twitter counts at https://openshare.social/twitter/auth");var o=0;e&&"function"==typeof e?e(o):(n.appendTo&&"function"!=typeof n.appendTo&&n.appendTo.appendChild(n.os),s(n.os,o,n.cb)),l.trigger(n.os,"counted-"+n.url)}else{console.warn("Failed to get API data from",t.url,". Please use the latest version of OpenShare.");var i=0;e&&"function"==typeof e?e(i):(n.appendTo&&"function"!=typeof n.appendTo&&n.appendTo.appendChild(n.os),s(n.os,i,n.cb)),l.trigger(n.os,"counted-"+n.url)}}},t.url=t.url.startsWith("https://api.openshare.social/job?")&&this.key?t.url+this.key:t.url,r.open("GET",t.url),r.send()}},{key:"post",value:function(t,e){var n=this,r=new XMLHttpRequest;r.onreadystatechange=function(){if(r.readyState===XMLHttpRequest.DONE&&200===r.status){var a=t.transform.apply(n,[r])||0;e&&"function"==typeof e?e(a):(n.appendTo&&"function"!=typeof n.appendTo&&n.appendTo.appendChild(n.os),s(n.os,a,n.cb)),l.trigger(n.os,"counted-"+n.url)}},r.open("POST",t.url),r.setRequestHeader("Content-Type","application/json;charset=UTF-8"),r.send(JSON.stringify(t.data))}},{key:"storeSet",value:function(t){var e=arguments.length<=1||void 0===arguments[1]?0:arguments[1];window.localStorage&&t&&localStorage.setItem("OpenShare-"+t,e)}},{key:"storeGet",value:function(t){if(window.localStorage&&t)return localStorage.getItem("OpenShare-"+t)}}]),t}(),g=function(){var t=function t(e,n){var a=e.type,o=e.url,i=e.appendTo,s=void 0!==i&&i,u=e.element,p=e.classes,c=e.key,h=void 0===c?null:c;r(this,t);var d=document.createElement(u||"span");return d.setAttribute("data-open-share-count",a),d.setAttribute("data-open-share-count-url",o),h&&d.setAttribute("data-open-share-key",h),d.classList.add("open-share-count"),p&&Array.isArray(p)&&p.forEach(function(t){d.classList.add(t)}),s?new f(a,o).count(d,n,s):new f(a,o).count(d,n)};return t};e.exports=g},{}],5:[function(t,e,n){"use strict";function r(t){var e=document.createElement("a");return e.classList.add("open-share-link","twitter"),e.setAttribute("data-open-share","twitter"),e.setAttribute("data-open-share-url",t.url),e.setAttribute("data-open-share-via",t.via),e.setAttribute("data-open-share-text",t.text),e.setAttribute("data-open-share-hashtags",t.hashtags),e.innerHTML=''+t.button,new s.share({type:"twitter",url:"http://www.digitalsurgeons.com",via:"digitalsurgeons",hashtags:"forwardobsessed",appendTo:document.querySelector(".open-share-watch"),innerHTML:"Created via OpenShareAPI",element:"div",classes:["wow","such","classes"]}),e}function a(){var t=u;document.querySelector(".open-share-watch").appendChild(r(t))}function o(){new s.count({type:"facebook",url:"https://www.digitalsurgeons.com/"},function(t){var e=new s.share({type:"twitter",url:"http://www.digitalsurgeons.com",via:"digitalsurgeons",hashtags:"forwardobsessed",innerHTML:"Created via OpenShareAPI",element:"div",classes:["wow","such","classes"]});document.querySelector(".create-node.w-count").appendChild(e),e.appendChild(t)})}function i(){var t=document.querySelector(".create-node.count-nodes"),e=t.querySelector("input.count-type").value,n=t.querySelector("input.count-url").value;new s.count({type:e,url:n,appendTo:t,classes:["test"]},function(t){t.style.position="relative"}),t.querySelector("input.count-type").value="",t.querySelector("input.count-url").value=""}var s={share:t("../share.js"),count:t("../count.js"),analytics:t("../analytics.js")};s.analytics("tagManager",function(){console.log("tag manager loaded")}),s.analytics("event",function(){console.log("google analytics events loaded")}),s.analytics("social",function(){console.log("google analytics social loaded")});var u={url:"http://www.digitalsurgeons.com",via:"digitalsurgeons",text:"Forward Obsessed",hashtags:"forwardobsessed",button:"Open Share Watcher!"};window.addNode=a,window.addNodeWithCount=o,window.createCountNode=i,new s.share({type:"googleMaps",center:"40.765819,-73.975866",view:"traffic",zoom:14,appendTo:document.body,innerHTML:"Maps"}),new s.share({type:"twitter-follow",screenName:"digitalsurgeons",userId:"18189130",appendTo:document.body,innerHTML:"Follow Test"}),new s.share({type:"paypal",buttonId:"2P3RJYEFL7Z62",sandbox:!0,appendTo:document.body,innerHTML:"PayPal Test"}),document.addEventListener("OpenShare.count-loaded",function(){console.log("OpenShare (count) loaded")}),document.addEventListener("OpenShare.share-loaded",function(){console.log("OpenShare (share) loaded"),[].forEach.call(document.querySelectorAll("[data-open-share]"),function(t){t.addEventListener("OpenShare.shared",function(t){console.log("Open Share Shared",t)})}),{twitter:new s.share({type:"twitter",bindClick:!0,url:"http://digitalsurgeons.com",via:"digitalsurgeons",text:"Digital Surgeons",hashtags:"forwardobsessed"},document.querySelector('[data-api-example="twitter"]')),facebook:new s.share({type:"facebook",bindClick:!0,link:"http://digitalsurgeons.com",picture:"http://www.digitalsurgeons.com/img/about/bg_office_team.jpg",caption:"Digital Surgeons",description:"forwardobsessed"},document.querySelector('[data-api-example="facebook"]')),pinterest:new s.share({type:"pinterest",bindClick:!0,url:"http://digitalsurgeons.com",media:"http://www.digitalsurgeons.com/img/about/bg_office_team.jpg",description:"Digital Surgeons",appendTo:document.body},document.querySelector('[data-api-example="pinterest"]')),email:new s.share({type:"email",bindClick:!0,to:"techroom@digitalsurgeons.com",subject:"Digital Surgeons",body:"Forward Obsessed"},document.querySelector('[data-api-example="email"]'))}});var p=["facebook","google","linkedin","reddit","pinterest",["google","linkedin","reddit","pinterest"]];p.forEach(function(t){Array.isArray(t)&&(t=t.join(","));var e=document.querySelectorAll('[data-open-share-count="'+t+'"]');[].forEach.call(e,function(e){e.addEventListener("OpenShare.counted-"+t,function(){var n=e.innerHTML;n&&console.log(t,"shares: ",n)})})}),new s.count({type:"twitter",url:"https://www.digitalsurgeons.com/thoughts/technology/the-blockchain-revolution",key:"dstweets"},function(t){var e=new s.share({type:"twitter",url:"https://www.digitalsurgeons.com/thoughts/technology/the-blockchain-revolution",via:"digitalsurgeons",hashtags:"forwardobsessed, blockchain",appendTo:document.body,innerHTML:"BLOCKCHAIN"});e.appendChild(t)})},{"../analytics.js":1,"../count.js":2,"../share.js":3}]},{},[5]); 3 | -------------------------------------------------------------------------------- /lib/countReduce.js: -------------------------------------------------------------------------------- 1 | function round(x, precision) { 2 | if (typeof x !== 'number') { 3 | throw new TypeError('Expected value to be a number'); 4 | } 5 | 6 | const exponent = precision > 0 ? 'e' : 'e-'; 7 | const exponentNeg = precision > 0 ? 'e-' : 'e'; 8 | precision = Math.abs(precision); 9 | 10 | return Number(Math.round(x + exponent + precision) + exponentNeg + precision); 11 | } 12 | 13 | function thousandify(num) { 14 | return `${round(num / 1000, 1)}K`; 15 | } 16 | 17 | function millionify(num) { 18 | return `${round(num / 1000000, 1)}M`; 19 | } 20 | 21 | export default function countReduce(el, count, cb) { 22 | if (count > 999999) { 23 | el.innerHTML = millionify(count); 24 | if (cb && typeof cb === 'function') cb(el); 25 | } else if (count > 999) { 26 | el.innerHTML = thousandify(count); 27 | if (cb && typeof cb === 'function') cb(el); 28 | } else { 29 | el.innerHTML = count; 30 | if (cb && typeof cb === 'function') cb(el); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/dashToCamel.js: -------------------------------------------------------------------------------- 1 | // type contains a dash 2 | // transform to camelcase for function reference 3 | // TODO: only supports single dash, should should support multiple 4 | export default (dash, type) => { 5 | const nextChar = type.substr(dash + 1, 1); 6 | const group = type.substr(dash, 2); 7 | 8 | type = type.replace(group, nextChar.toUpperCase()); 9 | return type; 10 | }; 11 | -------------------------------------------------------------------------------- /lib/init.js: -------------------------------------------------------------------------------- 1 | import initializeNodes from './initializeNodes'; 2 | import initializeWatcher from './initializeWatcher'; 3 | 4 | export default function init(opts) { 5 | return () => { 6 | const initNodes = initializeNodes({ 7 | api: opts.api || null, 8 | container: opts.container || document, 9 | selector: opts.selector, 10 | cb: opts.cb, 11 | }); 12 | 13 | initNodes(); 14 | 15 | // check for mutation observers before using, IE11 only 16 | if (window.MutationObserver !== undefined) { 17 | initializeWatcher(document.querySelectorAll('[data-open-share-watch]'), initNodes); 18 | } 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /lib/initializeCountNode.js: -------------------------------------------------------------------------------- 1 | import Count from '../src/modules/count'; 2 | 3 | export default function initializeCountNode(os) { 4 | // initialize open share object with type attribute 5 | const type = os.getAttribute('data-open-share-count'); 6 | const url = os.getAttribute('data-open-share-count-repo') || 7 | os.getAttribute('data-open-share-count-shot') || 8 | os.getAttribute('data-open-share-count-url'); 9 | const count = new Count(type, url); 10 | 11 | count.count(os); 12 | os.setAttribute('data-open-share-node', type); 13 | } 14 | -------------------------------------------------------------------------------- /lib/initializeNodes.js: -------------------------------------------------------------------------------- 1 | import Events from '../src/modules/events'; 2 | import analytics from '../analytics'; 3 | 4 | export default function initializeNodes(opts) { 5 | // loop through open share node collection 6 | return () => { 7 | // check for analytics 8 | checkAnalytics(); 9 | 10 | if (opts.api) { 11 | const nodes = opts.container.querySelectorAll(opts.selector); 12 | [].forEach.call(nodes, opts.cb); 13 | 14 | // trigger completed event 15 | Events.trigger(document, `${opts.api}-loaded`); 16 | } else { 17 | // loop through open share node collection 18 | const shareNodes = opts.container.querySelectorAll(opts.selector.share); 19 | [].forEach.call(shareNodes, opts.cb.share); 20 | 21 | // trigger completed event 22 | Events.trigger(document, 'share-loaded'); 23 | 24 | // loop through count node collection 25 | const countNodes = opts.container.querySelectorAll(opts.selector.count); 26 | [].forEach.call(countNodes, opts.cb.count); 27 | 28 | // trigger completed event 29 | Events.trigger(document, 'count-loaded'); 30 | } 31 | }; 32 | } 33 | 34 | function checkAnalytics() { 35 | // check for analytics 36 | if (document.querySelector('[data-open-share-analytics]')) { 37 | const provider = document.querySelector('[data-open-share-analytics]') 38 | .getAttribute('data-open-share-analytics'); 39 | 40 | if (provider.indexOf(',') > -1) { 41 | const providers = provider.split(','); 42 | providers.forEach(p => analytics(p)); 43 | } else analytics(provider); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /lib/initializeShareNode.js: -------------------------------------------------------------------------------- 1 | import ShareTransforms from '../src/modules/share-transforms'; 2 | import OpenShare from '../src/modules/open-share'; 3 | import setData from './setData'; 4 | import share from './share'; 5 | import dashToCamel from './dashToCamel'; 6 | 7 | export default function initializeShareNode(os) { 8 | // initialize open share object with type attribute 9 | let type = os.getAttribute('data-open-share'); 10 | const dash = type.indexOf('-'); 11 | 12 | if (dash > -1) { 13 | type = dashToCamel(dash, type); 14 | } 15 | 16 | const transform = ShareTransforms[type]; 17 | 18 | if (!transform) { 19 | throw new Error(`Open Share: ${type} is an invalid type`); 20 | } 21 | 22 | const openShare = new OpenShare(type, transform); 23 | 24 | // specify if this is a dynamic instance 25 | if (os.getAttribute('data-open-share-dynamic')) { 26 | openShare.dynamic = true; 27 | } 28 | 29 | // specify if this is a popup instance 30 | if (os.getAttribute('data-open-share-popup')) { 31 | openShare.popup = true; 32 | } 33 | 34 | // set all optional attributes on open share instance 35 | setData(openShare, os); 36 | 37 | // open share dialog on click 38 | os.addEventListener('click', (e) => { 39 | share(e, os, openShare); 40 | }); 41 | 42 | os.addEventListener('OpenShare.trigger', (e) => { 43 | share(e, os, openShare); 44 | }); 45 | 46 | os.setAttribute('data-open-share-node', type); 47 | } 48 | -------------------------------------------------------------------------------- /lib/initializeWatcher.js: -------------------------------------------------------------------------------- 1 | export default function initializeWatcher(watcher, fn) { 2 | [].forEach.call(watcher, (w) => { 3 | const observer = new MutationObserver((mutations) => { 4 | // target will match between all mutations so just use first 5 | fn(mutations[0].target); 6 | }); 7 | 8 | observer.observe(w, { 9 | childList: true, 10 | }); 11 | }); 12 | } 13 | -------------------------------------------------------------------------------- /lib/setData.js: -------------------------------------------------------------------------------- 1 | export default function setData(osInstance, osElement) { 2 | osInstance.setData({ 3 | url: osElement.getAttribute('data-open-share-url'), 4 | text: osElement.getAttribute('data-open-share-text'), 5 | via: osElement.getAttribute('data-open-share-via'), 6 | hashtags: osElement.getAttribute('data-open-share-hashtags'), 7 | tweetId: osElement.getAttribute('data-open-share-tweet-id'), 8 | related: osElement.getAttribute('data-open-share-related'), 9 | screenName: osElement.getAttribute('data-open-share-screen-name'), 10 | userId: osElement.getAttribute('data-open-share-user-id'), 11 | link: osElement.getAttribute('data-open-share-link'), 12 | picture: osElement.getAttribute('data-open-share-picture'), 13 | caption: osElement.getAttribute('data-open-share-caption'), 14 | description: osElement.getAttribute('data-open-share-description'), 15 | user: osElement.getAttribute('data-open-share-user'), 16 | video: osElement.getAttribute('data-open-share-video'), 17 | username: osElement.getAttribute('data-open-share-username'), 18 | title: osElement.getAttribute('data-open-share-title'), 19 | media: osElement.getAttribute('data-open-share-media'), 20 | to: osElement.getAttribute('data-open-share-to'), 21 | subject: osElement.getAttribute('data-open-share-subject'), 22 | body: osElement.getAttribute('data-open-share-body'), 23 | ios: osElement.getAttribute('data-open-share-ios'), 24 | type: osElement.getAttribute('data-open-share-type'), 25 | center: osElement.getAttribute('data-open-share-center'), 26 | views: osElement.getAttribute('data-open-share-views'), 27 | zoom: osElement.getAttribute('data-open-share-zoom'), 28 | search: osElement.getAttribute('data-open-share-search'), 29 | saddr: osElement.getAttribute('data-open-share-saddr'), 30 | daddr: osElement.getAttribute('data-open-share-daddr'), 31 | directionsmode: osElement.getAttribute('data-open-share-directions-mode'), 32 | repo: osElement.getAttribute('data-open-share-repo'), 33 | shot: osElement.getAttribute('data-open-share-shot'), 34 | pen: osElement.getAttribute('data-open-share-pen'), 35 | view: osElement.getAttribute('data-open-share-view'), 36 | issue: osElement.getAttribute('data-open-share-issue'), 37 | buttonId: osElement.getAttribute('data-open-share-buttonId'), 38 | popUp: osElement.getAttribute('data-open-share-popup'), 39 | key: osElement.getAttribute('data-open-share-key'), 40 | }); 41 | } 42 | -------------------------------------------------------------------------------- /lib/share.js: -------------------------------------------------------------------------------- 1 | import Events from '../src/modules/events'; 2 | import setData from './setData'; 3 | 4 | export default function share(e, os, openShare) { 5 | // if dynamic instance then fetch attributes again in case of updates 6 | if (openShare.dynamic) { 7 | setData(openShare, os); 8 | } 9 | 10 | openShare.share(e); 11 | 12 | // trigger shared event 13 | Events.trigger(os, 'shared'); 14 | } 15 | -------------------------------------------------------------------------------- /lib/storeCount.js: -------------------------------------------------------------------------------- 1 | /* 2 | Sometimes social platforms get confused and drop share counts. 3 | In this module we check if the returned count is less than the count in 4 | localstorage. 5 | If the local count is greater than the returned count, 6 | we store the local count + the returned count. 7 | Otherwise, store the returned count. 8 | */ 9 | 10 | export default (t, count) => { 11 | const isArr = t.type.indexOf(',') > -1; 12 | const local = Number(t.storeGet(`${t.type}-${t.shared}`)); 13 | 14 | if (local > count && !isArr) { 15 | const latestCount = Number(t.storeGet(`${t.type}-${t.shared}-latestCount`)); 16 | t.storeSet(`${t.type}-${t.shared}-latestCount`, count); 17 | 18 | count = isNumeric(latestCount) && latestCount > 0 ? 19 | count += local - latestCount : 20 | count += local; 21 | } 22 | 23 | if (!isArr) t.storeSet(`${t.type}-${t.shared}`, count); 24 | return count; 25 | }; 26 | 27 | function isNumeric(n) { 28 | return !isNaN(parseFloat(n)) && isFinite(n); 29 | } 30 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "openshare", 3 | "version": "1.4.11", 4 | "description": "Social sharing for developers", 5 | "main": "dist/openshare.js", 6 | "browserify": { 7 | "transform": [ 8 | "rollupify", 9 | [ 10 | "babelify", 11 | { 12 | "presets": [ 13 | "es2015" 14 | ] 15 | } 16 | ] 17 | ] 18 | }, 19 | "scripts": { 20 | "watch:js": "watchify src/browser.js -o dist/openshare.js -dv", 21 | "watch:test": "watchify src/test.js -o dist/test.js -dv", 22 | "build:js": "browserify src/browser.js > dist/openshare.js", 23 | "build:min:js": "browserify src/browser.js -g uglifyify | uglifyjs -cm > dist/openshare.min.js", 24 | "build:test": "browserify src/test.js -g uglifyify | uglifyjs -cm > dist/test.js", 25 | "watch": "npm run watch:js & npm run watch:test", 26 | "dev": "npm run watch & npm run test", 27 | "build": "npm run build:js & npm run build:test", 28 | "production": "npm run build & npm run test", 29 | "test": "opn http://0.0.0.0:8000/test.html && ecstatic .", 30 | "lint": "eslint src/", 31 | "prepublish": "npm run build:js" 32 | }, 33 | "repository": { 34 | "type": "git", 35 | "url": "git+https://github.com/OpenShare/openshare.git" 36 | }, 37 | "keywords": [ 38 | "social", 39 | "share", 40 | "sharing" 41 | ], 42 | "author": "Digital Surgeons", 43 | "license": "MIT", 44 | "devDependencies": { 45 | "babel": "^5.8.23", 46 | "babel-eslint": "^7.0.0", 47 | "babel-preset-es2015": "^6.9.0", 48 | "babelify": "^7.3.0", 49 | "browserify": "^11.2.0", 50 | "ecstatic": "^1.4.1", 51 | "eslint": "^3.7.1", 52 | "eslint-config-airbnb": "^12.0.0", 53 | "eslint-plugin-import": "^1.16.0", 54 | "eslint-plugin-jsx-a11y": "^2.2.3", 55 | "eslint-plugin-react": "^6.3.0", 56 | "node-sass": "^3.8.0", 57 | "opn-cli": "^3.1.0", 58 | "rollupify": "^0.3.5", 59 | "uglify-js": "^2.7.0", 60 | "uglifyify": "^3.0.2", 61 | "watchify": "^3.7.0" 62 | }, 63 | "bugs": { 64 | "url": "https://github.com/OpenShare/openshare/issues" 65 | }, 66 | "homepage": "https://github.com/OpenShare/openshare#readme", 67 | "dependencies": { 68 | "eslint": "^3.7.1", 69 | "eslint-config-airbnb": "^12.0.0", 70 | "eslint-plugin-import": "^1.16.0", 71 | "eslint-plugin-jsx-a11y": "^2.2.3", 72 | "eslint-plugin-react": "^6.3.0", 73 | "rollupify": "^0.3.5" 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /share.js: -------------------------------------------------------------------------------- 1 | import Init from './lib/init'; 2 | import cb from './lib/initializeShareNode'; 3 | import countAPI from './src/modules/count-api'; 4 | 5 | function init() { 6 | Init({ 7 | api: 'share', 8 | selector: '[data-open-share]:not([data-open-share-node])', 9 | cb, 10 | })(); 11 | } 12 | export default () => { 13 | if (document.readyState === 'complete') { 14 | init(); 15 | } 16 | document.addEventListener('readystatechange', () => { 17 | if (document.readyState === 'complete') { 18 | init(); 19 | } 20 | }, false); 21 | return countAPI(); 22 | }; 23 | -------------------------------------------------------------------------------- /src/browser.js: -------------------------------------------------------------------------------- 1 | import DataAttr from './modules/data-attr'; 2 | import ShareAPI from './modules/share-api'; 3 | import Events from './modules/events'; 4 | import OpenShare from './modules/open-share'; 5 | import ShareTransforms from './modules/share-transforms'; 6 | import Count from './modules/count'; 7 | import CountAPI from './modules/count-api'; 8 | import analyticsAPI from '../analytics'; 9 | 10 | const browser = () => { 11 | DataAttr(OpenShare, Count, ShareTransforms, Events); 12 | window.OpenShare = { 13 | share: ShareAPI(OpenShare, ShareTransforms, Events), 14 | count: CountAPI(), 15 | analytics: analyticsAPI, 16 | }; 17 | }; 18 | export default browser(); 19 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import attr from './modules/data-attr'; 2 | import ShareAPI from './modules/share-api'; 3 | import CountAPI from './modules/count-api'; 4 | import analyticsAPI from '../analytics'; 5 | 6 | const DataAttr = attr(); // eslint-disable-line 7 | 8 | export default { 9 | share: ShareAPI(), 10 | count: CountAPI(), 11 | analytics: analyticsAPI, 12 | }; 13 | -------------------------------------------------------------------------------- /src/modules/count-api.js: -------------------------------------------------------------------------------- 1 | /** 2 | * count API 3 | */ 4 | 5 | import count from './count'; 6 | 7 | export default () => { //eslint-disable-line 8 | // global OpenShare referencing internal class for instance generation 9 | class Count { 10 | 11 | constructor({ 12 | type, 13 | url, 14 | appendTo = false, 15 | element, 16 | classes, 17 | key = null, 18 | }, cb) { 19 | const countNode = document.createElement(element || 'span'); 20 | 21 | countNode.setAttribute('data-open-share-count', type); 22 | countNode.setAttribute('data-open-share-count-url', url); 23 | if (key) countNode.setAttribute('data-open-share-key', key); 24 | 25 | countNode.classList.add('open-share-count'); 26 | 27 | if (classes && Array.isArray(classes)) { 28 | classes.forEach((cssCLass) => { 29 | countNode.classList.add(cssCLass); 30 | }); 31 | } 32 | 33 | if (appendTo) { 34 | return new count(type, url).count(countNode, cb, appendTo); 35 | } 36 | 37 | return new count(type, url).count(countNode, cb); 38 | } 39 | } 40 | 41 | return Count; 42 | }; 43 | -------------------------------------------------------------------------------- /src/modules/count-transforms.js: -------------------------------------------------------------------------------- 1 | import countReduce from '../../lib/countReduce'; 2 | import storeCount from '../../lib/storeCount'; 3 | /** 4 | * Object of transform functions for each openshare api 5 | * Transform functions passed into OpenShare instance when instantiated 6 | * Return object containing URL and key/value args 7 | */ 8 | export default { 9 | 10 | // facebook count data 11 | facebook(url) { 12 | return { 13 | type: 'get', 14 | url: `https://graph.facebook.com/?id=${url}`, 15 | transform(xhr) { 16 | const fb = JSON.parse(xhr.responseText); 17 | 18 | const count = (fb.share && fb.share.share_count) || 0; 19 | 20 | return storeCount(this, count); 21 | }, 22 | }; 23 | }, 24 | 25 | // pinterest count data 26 | pinterest(url) { 27 | return { 28 | type: 'jsonp', 29 | url: `https://api.pinterest.com/v1/urls/count.json?callback=?&url=${url}`, 30 | transform(data) { 31 | const count = data.count || 0; 32 | return storeCount(this, count); 33 | }, 34 | }; 35 | }, 36 | 37 | // linkedin count data 38 | linkedin(url) { 39 | return { 40 | type: 'jsonp', 41 | url: `https://www.linkedin.com/countserv/count/share?url=${url}&format=jsonp&callback=?`, 42 | transform(data) { 43 | const count = data.count || 0; 44 | return storeCount(this, count); 45 | }, 46 | }; 47 | }, 48 | 49 | // reddit count data 50 | reddit(url) { 51 | return { 52 | type: 'get', 53 | url: `https://www.reddit.com/api/info.json?url=${url}`, 54 | transform(xhr) { 55 | const reddit = JSON.parse(xhr.responseText); 56 | const posts = (reddit.data && reddit.data.children) || null; 57 | let ups = 0; 58 | 59 | if (posts) { 60 | posts.forEach((post) => { 61 | ups += Number(post.data.ups); 62 | }); 63 | } 64 | 65 | return storeCount(this, ups); 66 | }, 67 | }; 68 | }, 69 | 70 | // google count data 71 | google(url) { 72 | return { 73 | type: 'post', 74 | data: { 75 | method: 'pos.plusones.get', 76 | id: 'p', 77 | params: { 78 | nolog: true, 79 | id: url, 80 | source: 'widget', 81 | userId: '@viewer', 82 | groupId: '@self', 83 | }, 84 | jsonrpc: '2.0', 85 | key: 'p', 86 | apiVersion: 'v1', 87 | }, 88 | url: 'https://clients6.google.com/rpc', 89 | transform(xhr) { 90 | const google = JSON.parse(xhr.responseText); 91 | const count = (google.result 92 | && google.result.metadata 93 | && google.result.metadata.globalCounts 94 | && google.result.metadata.globalCounts.count) || 0; 95 | return storeCount(this, count); 96 | }, 97 | }; 98 | }, 99 | 100 | // github star count 101 | githubStars(repo) { 102 | repo = repo.indexOf('github.com/') > -1 ? 103 | repo.split('github.com/')[1] : 104 | repo; 105 | return { 106 | type: 'get', 107 | url: `https://api.github.com/repos/${repo}`, 108 | transform(xhr) { 109 | const count = JSON.parse(xhr.responseText).stargazers_count || 0; 110 | return storeCount(this, count); 111 | }, 112 | }; 113 | }, 114 | 115 | // github forks count 116 | githubForks(repo) { 117 | repo = repo.indexOf('github.com/') > -1 ? 118 | repo.split('github.com/')[1] : 119 | repo; 120 | return { 121 | type: 'get', 122 | url: `https://api.github.com/repos/${repo}`, 123 | transform(xhr) { 124 | const count = JSON.parse(xhr.responseText).forks_count || 0; 125 | return storeCount(this, count); 126 | }, 127 | }; 128 | }, 129 | 130 | // github watchers count 131 | githubWatchers(repo) { 132 | repo = repo.indexOf('github.com/') > -1 ? 133 | repo.split('github.com/')[1] : 134 | repo; 135 | return { 136 | type: 'get', 137 | url: `https://api.github.com/repos/${repo}`, 138 | transform(xhr) { 139 | const count = JSON.parse(xhr.responseText).watchers_count || 0; 140 | return storeCount(this, count); 141 | }, 142 | }; 143 | }, 144 | 145 | // dribbble likes count 146 | dribbble(shot) { 147 | shot = shot.indexOf('dribbble.com/shots') > -1 ? 148 | shot.split('shots/')[1] : 149 | shot; 150 | const url = `https://api.dribbble.com/v1/shots/${shot}/likes`; 151 | return { 152 | type: 'get', 153 | url, 154 | transform(xhr, Events) { 155 | const count = JSON.parse(xhr.responseText).length; 156 | 157 | // at this time dribbble limits a response of 12 likes per page 158 | if (count === 12) { 159 | const page = 2; 160 | recursiveCount(url, page, count, (finalCount) => { 161 | if (this.appendTo && typeof this.appendTo !== 'function') { 162 | this.appendTo.appendChild(this.os); 163 | } 164 | countReduce(this.os, finalCount, this.cb); 165 | Events.trigger(this.os, `counted-${this.url}`); 166 | return storeCount(this, finalCount); 167 | }); 168 | } else { 169 | return storeCount(this, count); 170 | } 171 | }, 172 | }; 173 | }, 174 | 175 | twitter(url) { 176 | return { 177 | type: 'get', 178 | url: `https://api.openshare.social/job?url=${url}&key=`, 179 | transform(xhr) { 180 | const count = JSON.parse(xhr.responseText).count || 0; 181 | return storeCount(this, count); 182 | }, 183 | }; 184 | }, 185 | }; 186 | 187 | function recursiveCount(url, page, count, cb) { 188 | const xhr = new XMLHttpRequest(); 189 | xhr.open('GET', `${url}?page=${page}`); 190 | xhr.addEventListener('load', function () { //eslint-disable-line 191 | const likes = JSON.parse(this.response); 192 | count += likes.length; 193 | 194 | // dribbble like per page is 12 195 | if (likes.length === 12) { 196 | page++; 197 | recursiveCount(url, page, count, cb); 198 | } else { 199 | cb(count); 200 | } 201 | }); 202 | xhr.send(); 203 | } 204 | -------------------------------------------------------------------------------- /src/modules/count.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Generate share count instance from one to many networks 3 | */ 4 | 5 | import CountTransforms from './count-transforms'; 6 | import Events from './events'; 7 | import countReduce from '../../lib/countReduce'; 8 | import storeCount from '../../lib/storeCount'; // eslint-disable-line no-unused-vars 9 | 10 | function isNumeric(n) { 11 | return !isNaN(parseFloat(n)) && isFinite(n); 12 | } 13 | 14 | class Count { 15 | constructor(type, url) { 16 | // throw error if no url provided 17 | if (!url) { 18 | throw new Error('Open Share: no url provided for count'); 19 | } 20 | 21 | // check for Github counts 22 | if (type.indexOf('github') === 0) { 23 | if (type === 'github-stars') { 24 | type = 'githubStars'; 25 | } else if (type === 'github-forks') { 26 | type = 'githubForks'; 27 | } else if (type === 'github-watchers') { 28 | type = 'githubWatchers'; 29 | } else { 30 | console.error('Invalid Github count type. Try github-stars, github-forks, or github-watchers.'); 31 | } 32 | } 33 | 34 | // if type is comma separate list create array 35 | if (type.indexOf(',') > -1) { 36 | this.type = type; 37 | this.typeArr = this.type.split(','); 38 | this.countData = []; 39 | 40 | // check each type supplied is valid 41 | this.typeArr.forEach((t) => { 42 | if (!CountTransforms[t]) { 43 | throw new Error(`Open Share: ${type} is an invalid count type`); 44 | } 45 | 46 | this.countData.push(CountTransforms[t](url)); 47 | }); 48 | 49 | const count = this.storeGet(`${this.type}-${this.shared}`); 50 | 51 | if (count) { 52 | if (this.appendTo && typeof this.appendTo !== 'function') { 53 | this.appendTo.appendChild(this.os); 54 | } 55 | countReduce(this.os, count); 56 | } 57 | 58 | // throw error if invalid type provided 59 | } else if (!CountTransforms[type]) { 60 | throw new Error(`Open Share: ${type} is an invalid count type`); 61 | 62 | // single count 63 | // store count URL and transform function 64 | } else { 65 | this.type = type; 66 | this.countData = CountTransforms[type](url); 67 | } 68 | } 69 | 70 | // handle calling getCount / getCounts 71 | // depending on number of types 72 | count(os, cb, appendTo) { 73 | this.os = os; 74 | this.appendTo = appendTo; 75 | this.cb = cb; 76 | this.url = this.os.getAttribute('data-open-share-count'); 77 | this.shared = this.os.getAttribute('data-open-share-count-url'); 78 | this.key = this.os.getAttribute('data-open-share-key'); 79 | 80 | if (!Array.isArray(this.countData)) { 81 | this.getCount(); 82 | } else { 83 | this.getCounts(); 84 | } 85 | } 86 | 87 | // fetch count either AJAX or JSONP 88 | getCount() { 89 | const count = this.storeGet(`${this.type}-${this.shared}`); 90 | 91 | if (count) { 92 | if (this.appendTo && typeof this.appendTo !== 'function') { 93 | this.appendTo.appendChild(this.os); 94 | } 95 | countReduce(this.os, count); 96 | } 97 | this[this.countData.type](this.countData); 98 | } 99 | 100 | // fetch multiple counts and aggregate 101 | getCounts() { 102 | this.total = []; 103 | 104 | const count = this.storeGet(`${this.type}-${this.shared}`); 105 | 106 | if (count) { 107 | if (this.appendTo && typeof this.appendTo !== 'function') { 108 | this.appendTo.appendChild(this.os); 109 | } 110 | countReduce(this.os, count); 111 | } 112 | 113 | this.countData.forEach((countData) => { 114 | this[countData.type](countData, (num) => { 115 | this.total.push(num); 116 | 117 | // total counts length now equals type array length 118 | // so aggregate, store and insert into DOM 119 | if (this.total.length === this.typeArr.length) { 120 | let tot = 0; 121 | 122 | this.total.forEach((t) => { 123 | tot += t; 124 | }); 125 | 126 | if (this.appendTo && typeof this.appendTo !== 'function') { 127 | this.appendTo.appendChild(this.os); 128 | } 129 | 130 | const local = Number(this.storeGet(`${this.type}-${this.shared}`)); 131 | if (local > tot) { 132 | // const latestCount = Number(this.storeGet(`${this.type}-${this.shared}-latestCount`)); 133 | // this.storeSet(`${this.type}-${this.shared}-latestCount`, tot); 134 | // 135 | // tot = isNumeric(latestCount) && latestCount > 0 ? 136 | // tot += local - latestCount : 137 | // tot += local; 138 | tot = local; 139 | } 140 | this.storeSet(`${this.type}-${this.shared}`, tot); 141 | 142 | countReduce(this.os, tot); 143 | } 144 | }); 145 | }); 146 | 147 | if (this.appendTo && typeof this.appendTo !== 'function') { 148 | this.appendTo.appendChild(this.os); 149 | } 150 | } 151 | 152 | // handle JSONP requests 153 | jsonp(countData, cb) { 154 | // define random callback and assign transform function 155 | const callback = Math.random().toString(36).substring(7).replace(/[^a-zA-Z]/g, ''); 156 | window[callback] = (data) => { 157 | const count = countData.transform.apply(this, [data]) || 0; 158 | 159 | if (cb && typeof cb === 'function') { 160 | cb(count); 161 | } else { 162 | if (this.appendTo && typeof this.appendTo !== 'function') { 163 | this.appendTo.appendChild(this.os); 164 | } 165 | countReduce(this.os, count, this.cb); 166 | } 167 | 168 | Events.trigger(this.os, `counted-${this.url}`); 169 | }; 170 | 171 | // append JSONP script tag to page 172 | const script = document.createElement('script'); 173 | script.src = countData.url.replace('callback=?', `callback=${callback}`); 174 | document.getElementsByTagName('head')[0].appendChild(script); 175 | 176 | return; 177 | } 178 | 179 | // handle AJAX GET request 180 | get(countData, cb) { 181 | const xhr = new XMLHttpRequest(); 182 | 183 | // on success pass response to transform function 184 | xhr.onreadystatechange = () => { 185 | if (xhr.readyState === 4) { 186 | if (xhr.status === 200) { 187 | const count = countData.transform.apply(this, [xhr, Events]) || 0; 188 | 189 | if (cb && typeof cb === 'function') { 190 | cb(count); 191 | } else { 192 | if (this.appendTo && typeof this.appendTo !== 'function') { 193 | this.appendTo.appendChild(this.os); 194 | } 195 | countReduce(this.os, count, this.cb); 196 | } 197 | 198 | Events.trigger(this.os, `counted-${this.url}`); 199 | return; 200 | } else if (countData.url.toLowerCase().indexOf('https://api.openshare.social/job?') === 0) { 201 | console.warn('Please sign up for Twitter counts at https://openshare.social/twitter/auth'); 202 | const count = 0; 203 | 204 | if (cb && typeof cb === 'function') { 205 | cb(count); 206 | } else { 207 | if (this.appendTo && typeof this.appendTo !== 'function') { 208 | this.appendTo.appendChild(this.os); 209 | } 210 | countReduce(this.os, count, this.cb); 211 | } 212 | 213 | Events.trigger(this.os, `counted-${this.url}`); 214 | } else { 215 | console.warn('Failed to get API data from', countData.url, '. Please use the latest version of OpenShare.'); 216 | const count = 0; 217 | 218 | if (cb && typeof cb === 'function') { 219 | cb(count); 220 | } else { 221 | if (this.appendTo && typeof this.appendTo !== 'function') { 222 | this.appendTo.appendChild(this.os); 223 | } 224 | countReduce(this.os, count, this.cb); 225 | } 226 | 227 | Events.trigger(this.os, `counted-${this.url}`); 228 | } 229 | } 230 | }; 231 | 232 | countData.url = countData.url.startsWith('https://api.openshare.social/job?') && this.key ? 233 | countData.url + this.key : 234 | countData.url; 235 | 236 | xhr.open('GET', countData.url); 237 | xhr.send(); 238 | } 239 | 240 | // handle AJAX POST request 241 | post(countData, cb) { 242 | const xhr = new XMLHttpRequest(); 243 | 244 | // on success pass response to transform function 245 | xhr.onreadystatechange = () => { 246 | if (xhr.readyState !== XMLHttpRequest.DONE || 247 | xhr.status !== 200) { 248 | return; 249 | } 250 | 251 | const count = countData.transform.apply(this, [xhr]) || 0; 252 | 253 | if (cb && typeof cb === 'function') { 254 | cb(count); 255 | } else { 256 | if (this.appendTo && typeof this.appendTo !== 'function') { 257 | this.appendTo.appendChild(this.os); 258 | } 259 | countReduce(this.os, count, this.cb); 260 | } 261 | Events.trigger(this.os, `counted-${this.url}`); 262 | }; 263 | 264 | xhr.open('POST', countData.url); 265 | xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8'); 266 | xhr.send(JSON.stringify(countData.data)); 267 | } 268 | 269 | storeSet(type, count = 0) {//eslint-disable-line 270 | if (!window.localStorage || !type) { 271 | return; 272 | } 273 | 274 | localStorage.setItem(`OpenShare-${type}`, count); 275 | } 276 | 277 | storeGet(type) {//eslint-disable-line 278 | if (!window.localStorage || !type) { 279 | return; 280 | } 281 | 282 | return localStorage.getItem(`OpenShare-${type}`); 283 | } 284 | 285 | } 286 | 287 | export default Count; 288 | -------------------------------------------------------------------------------- /src/modules/data-attr.js: -------------------------------------------------------------------------------- 1 | import Init from '../../lib/init'; 2 | import share from '../../lib/initializeShareNode'; 3 | import count from '../../lib/initializeCountNode'; 4 | 5 | function init() { 6 | Init({ 7 | selector: { 8 | share: '[data-open-share]:not([data-open-share-node])', 9 | count: '[data-open-share-count]:not([data-open-share-node])', 10 | }, 11 | cb: { 12 | share, 13 | count, 14 | }, 15 | })(); 16 | } 17 | export default () => { 18 | if (document.readyState === 'complete') { 19 | return init(); 20 | } 21 | document.addEventListener('readystatechange', () => { 22 | if (document.readyState === 'complete') { 23 | init(); 24 | } 25 | }, false); 26 | }; 27 | -------------------------------------------------------------------------------- /src/modules/events.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Trigger custom OpenShare namespaced event 3 | */ 4 | export default { 5 | trigger(element, event) { 6 | const ev = document.createEvent('Event'); 7 | ev.initEvent(`OpenShare.${event}`, true, true); 8 | element.dispatchEvent(ev); 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /src/modules/open-share.js: -------------------------------------------------------------------------------- 1 | /** 2 | * OpenShare generates a single share link 3 | */ 4 | export default class OpenShare { 5 | 6 | constructor(type, transform) { 7 | this.ios = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream; 8 | this.type = type; 9 | this.dynamic = false; 10 | this.transform = transform; 11 | 12 | // capitalized type 13 | this.typeCaps = type.charAt(0).toUpperCase() + type.slice(1); 14 | } 15 | 16 | // returns function named as type set in constructor 17 | // e.g twitter() 18 | setData(data) { 19 | // if iOS user and ios data attribute defined 20 | // build iOS URL scheme as single string 21 | if (this.ios) { 22 | this.transformData = this.transform(data, true); 23 | this.mobileShareUrl = this.template(this.transformData.url, this.transformData.data); 24 | } 25 | 26 | this.transformData = this.transform(data); 27 | this.shareUrl = this.template(this.transformData.url, this.transformData.data); 28 | } 29 | 30 | // open share URL defined in individual platform functions 31 | share() { 32 | // if iOS share URL has been set then use timeout hack 33 | // test for native app and fall back to web 34 | if (this.mobileShareUrl) { 35 | const start = (new Date()).valueOf(); 36 | 37 | setTimeout(() => { 38 | const end = (new Date()).valueOf(); 39 | 40 | // if the user is still here, fall back to web 41 | if (end - start > 1600) { 42 | return; 43 | } 44 | 45 | window.location = this.shareUrl; 46 | }, 1500); 47 | 48 | window.location = this.mobileShareUrl; 49 | 50 | // open mailto links in same window 51 | } else if (this.type === 'email') { 52 | window.location = this.shareUrl; 53 | 54 | // open social share URLs in new window 55 | } else { 56 | // if popup object present then set window dimensions / position 57 | if (this.popup && this.transformData.popup) { 58 | return this.openWindow(this.shareUrl, this.transformData.popup); 59 | } 60 | 61 | window.open(this.shareUrl); 62 | } 63 | } 64 | 65 | // create share URL with GET params 66 | // appending valid properties to query string 67 | template(url, data) {//eslint-disable-line 68 | const nonURLProps = [ 69 | 'appendTo', 70 | 'innerHTML', 71 | 'classes', 72 | ]; 73 | 74 | let shareUrl = url, 75 | i; 76 | 77 | for (i in data) { 78 | // only append valid properties 79 | if (!data[i] || nonURLProps.indexOf(i) > -1) { 80 | continue; //eslint-disable-line 81 | } 82 | 83 | // append URL encoded GET param to share URL 84 | data[i] = encodeURIComponent(data[i]); 85 | shareUrl += `${i}=${data[i]}&`; 86 | } 87 | 88 | return shareUrl.substr(0, shareUrl.length - 1); 89 | } 90 | 91 | // center popup window supporting dual screens 92 | openWindow(url, options) {//eslint-disable-line 93 | const dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : screen.left, 94 | dualScreenTop = window.screenTop !== undefined ? window.screenTop : screen.top, 95 | width = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width,//eslint-disable-line 96 | height = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height,//eslint-disable-line 97 | left = ((width / 2) - (options.width / 2)) + dualScreenLeft, 98 | top = ((height / 2) - (options.height / 2)) + dualScreenTop, 99 | newWindow = window.open(url, 'OpenShare', `width=${options.width}, height=${options.height}, top=${top}, left=${left}`); 100 | 101 | // Puts focus on the newWindow 102 | if (window.focus) { 103 | newWindow.focus(); 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/modules/share-api.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Global OpenShare API to generate instances programmatically 3 | */ 4 | import OS from './open-share'; 5 | import ShareTransforms from './share-transforms'; 6 | import Events from './events'; 7 | import dashToCamel from '../../lib/dashToCamel'; 8 | 9 | export default () => { 10 | // global OpenShare referencing internal class for instance generation 11 | class OpenShare { 12 | 13 | constructor(data, element) { 14 | if (!data.bindClick) data.bindClick = true; 15 | 16 | const dash = data.type.indexOf('-'); 17 | 18 | if (dash > -1) { 19 | data.type = dashToCamel(dash, data.type); 20 | } 21 | 22 | let node; 23 | this.element = element; 24 | this.data = data; 25 | 26 | this.os = new OS(data.type, ShareTransforms[data.type]); 27 | this.os.setData(data); 28 | 29 | if (!element || data.element) { 30 | element = data.element; 31 | node = document.createElement(element || 'a'); 32 | if (data.type) { 33 | node.classList.add('open-share-link', data.type); 34 | node.setAttribute('data-open-share', data.type); 35 | node.setAttribute('data-open-share-node', data.type); 36 | } 37 | if (data.innerHTML) node.innerHTML = data.innerHTML; 38 | } 39 | if (node) element = node; 40 | 41 | if (data.bindClick) { 42 | element.addEventListener('click', () => { 43 | this.share(); 44 | }); 45 | } 46 | 47 | if (data.appendTo) { 48 | data.appendTo.appendChild(element); 49 | } 50 | 51 | if (data.classes && Array.isArray(data.classes)) { 52 | data.classes.forEach((cssClass) => { 53 | element.classList.add(cssClass); 54 | }); 55 | } 56 | 57 | if (data.type.toLowerCase() === 'paypal') { 58 | const action = data.sandbox ? 59 | 'https://www.sandbox.paypal.com/cgi-bin/webscr' : 60 | 'https://www.paypal.com/cgi-bin/webscr'; 61 | 62 | const buyGIF = data.sandbox ? 63 | 'https://www.sandbox.paypal.com/en_US/i/btn/btn_buynow_LG.gif' : 64 | 'https://www.paypalobjects.com/en_US/i/btn/btn_buynow_LG.gif'; 65 | 66 | const pixelGIF = data.sandbox ? 67 | 'https://www.sandbox.paypal.com/en_US/i/scr/pixel.gif' : 68 | 'https://www.paypalobjects.com/en_US/i/scr/pixel.gif'; 69 | 70 | 71 | const paypalButton = ` 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 83 | 85 | 86 | `; 87 | 88 | const hiddenDiv = document.createElement('div'); 89 | hiddenDiv.style.display = 'none'; 90 | hiddenDiv.innerHTML = paypalButton; 91 | document.body.appendChild(hiddenDiv); 92 | 93 | this.paypal = hiddenDiv.querySelector('form'); 94 | } 95 | 96 | this.element = element; 97 | return element; 98 | } 99 | 100 | // public share method to trigger share programmatically 101 | share(e) { 102 | // if dynamic instance then fetch attributes again in case of updates 103 | if (this.data.dynamic) { 104 | //eslint-disable-next-line 105 | this.os.setData(data);// data is not defined 106 | } 107 | 108 | if (this.data.type.toLowerCase() === 'paypal') { 109 | this.paypal.submit(); 110 | } else this.os.share(e); 111 | 112 | Events.trigger(this.element, 'shared'); 113 | } 114 | } 115 | 116 | return OpenShare; 117 | }; 118 | -------------------------------------------------------------------------------- /src/modules/share-transforms.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Object of transform functions for each openshare api 3 | * Transform functions passed into OpenShare instance when instantiated 4 | * Return object containing URL and key/value args 5 | */ 6 | export default { 7 | 8 | // set Twitter share URL 9 | twitter(data, ios = false) { 10 | // if iOS user and ios data attribute defined 11 | // build iOS URL scheme as single string 12 | if (ios && data.ios) { 13 | let message = ''; 14 | 15 | if (data.text) { 16 | message += data.text; 17 | } 18 | 19 | if (data.url) { 20 | message += ` - ${data.url}`; 21 | } 22 | 23 | if (data.hashtags) { 24 | const tags = data.hashtags.split(','); 25 | tags.forEach((tag) => { 26 | message += ` #${tag}`; 27 | }); 28 | } 29 | 30 | if (data.via) { 31 | message += ` via ${data.via}`; 32 | } 33 | 34 | return { 35 | url: 'twitter://post?', 36 | data: { 37 | message, 38 | }, 39 | }; 40 | } 41 | 42 | return { 43 | url: 'https://twitter.com/share?', 44 | data, 45 | popup: { 46 | width: 700, 47 | height: 296, 48 | }, 49 | }; 50 | }, 51 | 52 | // set Twitter retweet URL 53 | twitterRetweet(data, ios = false) { 54 | // if iOS user and ios data attribute defined 55 | if (ios && data.ios) { 56 | return { 57 | url: 'twitter://status?', 58 | data: { 59 | id: data.tweetId, 60 | }, 61 | }; 62 | } 63 | 64 | return { 65 | url: 'https://twitter.com/intent/retweet?', 66 | data: { 67 | tweet_id: data.tweetId, 68 | related: data.related, 69 | }, 70 | popup: { 71 | width: 700, 72 | height: 296, 73 | }, 74 | }; 75 | }, 76 | 77 | // set Twitter like URL 78 | twitterLike(data, ios = false) { 79 | // if iOS user and ios data attribute defined 80 | if (ios && data.ios) { 81 | return { 82 | url: 'twitter://status?', 83 | data: { 84 | id: data.tweetId, 85 | }, 86 | }; 87 | } 88 | 89 | return { 90 | url: 'https://twitter.com/intent/favorite?', 91 | data: { 92 | tweet_id: data.tweetId, 93 | related: data.related, 94 | }, 95 | popup: { 96 | width: 700, 97 | height: 296, 98 | }, 99 | }; 100 | }, 101 | 102 | // set Twitter follow URL 103 | twitterFollow(data, ios = false) { 104 | // if iOS user and ios data attribute defined 105 | if (ios && data.ios) { 106 | const iosData = data.screenName ? { 107 | screen_name: data.screenName, 108 | } : { 109 | id: data.userId, 110 | }; 111 | 112 | return { 113 | url: 'twitter://user?', 114 | data: iosData, 115 | }; 116 | } 117 | 118 | return { 119 | url: 'https://twitter.com/intent/user?', 120 | data: { 121 | screen_name: data.screenName, 122 | user_id: data.userId, 123 | }, 124 | popup: { 125 | width: 700, 126 | height: 296, 127 | }, 128 | }; 129 | }, 130 | 131 | // set Facebook share URL 132 | facebook(data) { 133 | return { 134 | url: 'https://www.facebook.com/dialog/feed?app_id=961342543922322&redirect_uri=http://facebook.com&', 135 | data, 136 | popup: { 137 | width: 560, 138 | height: 593, 139 | }, 140 | }; 141 | }, 142 | 143 | // set Facebook send URL 144 | facebookSend(data) { 145 | return { 146 | url: 'https://www.facebook.com/dialog/send?app_id=961342543922322&redirect_uri=http://facebook.com&', 147 | data, 148 | popup: { 149 | width: 980, 150 | height: 596, 151 | }, 152 | }; 153 | }, 154 | 155 | // set YouTube play URL 156 | youtube(data, ios = false) { 157 | // if iOS user 158 | if (ios && data.ios) { 159 | return { 160 | url: `youtube:${data.video}?`, 161 | }; 162 | } 163 | 164 | return { 165 | url: `https://www.youtube.com/watch?v=${data.video}?`, 166 | popup: { 167 | width: 1086, 168 | height: 608, 169 | }, 170 | }; 171 | }, 172 | 173 | // set YouTube subcribe URL 174 | youtubeSubscribe(data, ios = false) { 175 | // if iOS user 176 | if (ios && data.ios) { 177 | return { 178 | url: `youtube://www.youtube.com/user/${data.user}?`, 179 | }; 180 | } 181 | 182 | return { 183 | url: `https://www.youtube.com/user/${data.user}?`, 184 | popup: { 185 | width: 880, 186 | height: 350, 187 | }, 188 | }; 189 | }, 190 | 191 | // set Instagram follow URL 192 | instagram() { 193 | return { 194 | url: 'instagram://camera?', 195 | }; 196 | }, 197 | 198 | // set Instagram follow URL 199 | instagramFollow(data, ios = false) { 200 | // if iOS user 201 | if (ios && data.ios) { 202 | return { 203 | url: 'instagram://user?', 204 | data, 205 | }; 206 | } 207 | 208 | return { 209 | url: `http://www.instagram.com/${data.username}?`, 210 | popup: { 211 | width: 980, 212 | height: 655, 213 | }, 214 | }; 215 | }, 216 | 217 | // set Snapchat follow URL 218 | snapchat(data) { 219 | return { 220 | url: `snapchat://add/${data.username}?`, 221 | }; 222 | }, 223 | 224 | // set Google share URL 225 | google(data) { 226 | return { 227 | url: 'https://plus.google.com/share?', 228 | data, 229 | popup: { 230 | width: 495, 231 | height: 815, 232 | }, 233 | }; 234 | }, 235 | 236 | // set Google maps URL 237 | googleMaps(data, ios = false) { 238 | if (data.search) { 239 | data.q = data.search; 240 | delete data.search; 241 | } 242 | 243 | // if iOS user and ios data attribute defined 244 | if (ios && data.ios) { 245 | return { 246 | url: 'comgooglemaps://?', 247 | data: ios, 248 | }; 249 | } 250 | 251 | if (!ios && data.ios) { 252 | delete data.ios; 253 | } 254 | 255 | return { 256 | url: 'https://maps.google.com/?', 257 | data, 258 | popup: { 259 | width: 800, 260 | height: 600, 261 | }, 262 | }; 263 | }, 264 | 265 | // set Pinterest share URL 266 | pinterest(data) { 267 | return { 268 | url: 'https://pinterest.com/pin/create/bookmarklet/?', 269 | data, 270 | popup: { 271 | width: 745, 272 | height: 620, 273 | }, 274 | }; 275 | }, 276 | 277 | // set LinkedIn share URL 278 | linkedin(data) { 279 | return { 280 | url: 'http://www.linkedin.com/shareArticle?', 281 | data, 282 | popup: { 283 | width: 780, 284 | height: 492, 285 | }, 286 | }; 287 | }, 288 | 289 | // set Buffer share URL 290 | buffer(data) { 291 | return { 292 | url: 'http://bufferapp.com/add?', 293 | data, 294 | popup: { 295 | width: 745, 296 | height: 345, 297 | }, 298 | }; 299 | }, 300 | 301 | // set Tumblr share URL 302 | tumblr(data) { 303 | return { 304 | url: 'https://www.tumblr.com/widgets/share/tool?', 305 | data, 306 | popup: { 307 | width: 540, 308 | height: 940, 309 | }, 310 | }; 311 | }, 312 | 313 | // set Reddit share URL 314 | reddit(data) { 315 | return { 316 | url: 'http://reddit.com/submit?', 317 | data, 318 | popup: { 319 | width: 860, 320 | height: 880, 321 | }, 322 | }; 323 | }, 324 | 325 | // set Flickr follow URL 326 | flickr(data, ios = false) { 327 | // if iOS user 328 | if (ios && data.ios) { 329 | return { 330 | url: `flickr://photos/${data.username}?`, 331 | }; 332 | } 333 | return { 334 | url: `http://www.flickr.com/photos/${data.username}?`, 335 | popup: { 336 | width: 600, 337 | height: 650, 338 | }, 339 | }; 340 | }, 341 | 342 | // set WhatsApp share URL 343 | whatsapp(data) { 344 | return { 345 | url: 'whatsapp://send?', 346 | data, 347 | }; 348 | }, 349 | 350 | // set sms share URL 351 | sms(data, ios = false) { 352 | return { 353 | url: ios ? 'sms:&' : 'sms:?', 354 | data, 355 | }; 356 | }, 357 | 358 | // set Email share URL 359 | email(data) { 360 | let url = 'mailto:'; 361 | 362 | // if to address specified then add to URL 363 | if (data.to !== null) { 364 | url += `${data.to}`; 365 | } 366 | 367 | url += '?'; 368 | 369 | return { 370 | url, 371 | data: { 372 | subject: data.subject, 373 | body: data.body, 374 | }, 375 | }; 376 | }, 377 | 378 | // set Github fork URL 379 | github(data, ios = false) { // eslint-disable-line no-unused-vars 380 | let url = data.repo ? `https://github.com/${data.repo}` : data.url; 381 | 382 | if (data.issue) { 383 | url += `/issues/new?title=${data.issue}&body=${data.body}`; 384 | } 385 | 386 | return { 387 | url: `${url}?`, 388 | popup: { 389 | width: 1020, 390 | height: 323, 391 | }, 392 | }; 393 | }, 394 | 395 | // set Dribbble share URL 396 | dribbble(data, ios = false) { // eslint-disable-line no-unused-vars 397 | const url = data.shot ? `https://dribbble.com/shots/${data.shot}?` : `${data.url}?`; 398 | return { 399 | url, 400 | popup: { 401 | width: 440, 402 | height: 640, 403 | }, 404 | }; 405 | }, 406 | 407 | codepen(data) { 408 | const url = (data.pen && data.username && data.view) ? `https://codepen.io/${data.username}/${data.view}/${data.pen}?` : `${data.url}?`; 409 | return { 410 | url, 411 | popup: { 412 | width: 1200, 413 | height: 800, 414 | }, 415 | }; 416 | }, 417 | 418 | paypal(data) { 419 | return { 420 | data, 421 | }; 422 | }, 423 | }; 424 | -------------------------------------------------------------------------------- /src/test.js: -------------------------------------------------------------------------------- 1 | const OpenShare = { 2 | share: require('../share.js'), 3 | count: require('../count.js'), 4 | analytics: require('../analytics.js'), 5 | }; 6 | 7 | OpenShare.analytics('tagManager', () => { 8 | console.log('tag manager loaded'); 9 | }); 10 | 11 | OpenShare.analytics('event', () => { 12 | console.log('google analytics events loaded'); 13 | }); 14 | 15 | OpenShare.analytics('social', () => { 16 | console.log('google analytics social loaded'); 17 | }); 18 | 19 | const dynamicNodeData = { 20 | url: 'http://www.digitalsurgeons.com', 21 | via: 'digitalsurgeons', 22 | text: 'Forward Obsessed', 23 | hashtags: 'forwardobsessed', 24 | button: 'Open Share Watcher!', 25 | }; 26 | 27 | function createOpenShareNode(data) { 28 | const openShare = document.createElement('a'); 29 | 30 | openShare.classList.add('open-share-link', 'twitter'); 31 | openShare.setAttribute('data-open-share', 'twitter'); 32 | openShare.setAttribute('data-open-share-url', data.url); 33 | openShare.setAttribute('data-open-share-via', data.via); 34 | openShare.setAttribute('data-open-share-text', data.text); 35 | openShare.setAttribute('data-open-share-hashtags', data.hashtags); 36 | openShare.innerHTML = `${data.button}`; 37 | 38 | const node = new OpenShare.share({ //eslint-disable-line 39 | type: 'twitter', 40 | url: 'http://www.digitalsurgeons.com', 41 | via: 'digitalsurgeons', 42 | hashtags: 'forwardobsessed', 43 | appendTo: document.querySelector('.open-share-watch'), 44 | innerHTML: 'Created via OpenShareAPI', 45 | element: 'div', 46 | classes: ['wow', 'such', 'classes'], 47 | }); 48 | 49 | return openShare; 50 | } 51 | 52 | function addNode() { 53 | const data = dynamicNodeData; 54 | document.querySelector('.open-share-watch') 55 | .appendChild(createOpenShareNode(data)); 56 | } 57 | 58 | window.addNode = addNode; 59 | 60 | function addNodeWithCount() { 61 | const data = dynamicNodeData; // eslint-disable-line no-unused-vars 62 | new OpenShare.count({ // eslint-disable-line 63 | type: 'facebook', 64 | url: 'https://www.digitalsurgeons.com/', 65 | }, (node) => { 66 | const os = new OpenShare.share({ // eslint-disable-line 67 | type: 'twitter', 68 | url: 'http://www.digitalsurgeons.com', 69 | via: 'digitalsurgeons', 70 | hashtags: 'forwardobsessed', 71 | innerHTML: 'Created via OpenShareAPI', 72 | element: 'div', 73 | classes: ['wow', 'such', 'classes'], 74 | }); 75 | document.querySelector('.create-node.w-count') 76 | .appendChild(os); 77 | os.appendChild(node); 78 | }); 79 | } 80 | 81 | window.addNodeWithCount = addNodeWithCount; 82 | 83 | function createCountNode() { 84 | const container = document.querySelector('.create-node.count-nodes'); 85 | const type = container.querySelector('input.count-type').value; 86 | const url = container.querySelector('input.count-url').value; 87 | 88 | new OpenShare.count({ //eslint-disable-line 89 | type: type, //eslint-disable-line 90 | url: url, //eslint-disable-line 91 | appendTo: container, 92 | classes: ['test'], 93 | }, (node) => { 94 | node.style.position = 'relative'; 95 | }); 96 | 97 | 98 | container.querySelector('input.count-type').value = ''; 99 | container.querySelector('input.count-url').value = ''; 100 | } 101 | 102 | window.createCountNode = createCountNode; 103 | 104 | // test JS OpenShare API with dashes 105 | new OpenShare.share({ //eslint-disable-line 106 | type: 'googleMaps', 107 | center: '40.765819,-73.975866', 108 | view: 'traffic', 109 | zoom: 14, 110 | appendTo: document.body, 111 | innerHTML: 'Maps', 112 | }); 113 | 114 | new OpenShare.share({ //eslint-disable-line 115 | type: 'twitter-follow', 116 | screenName: 'digitalsurgeons', 117 | userId: '18189130', 118 | appendTo: document.body, 119 | innerHTML: 'Follow Test', 120 | }); 121 | 122 | // test PayPal 123 | new OpenShare.share({ //eslint-disable-line 124 | type: 'paypal', 125 | buttonId: '2P3RJYEFL7Z62', 126 | sandbox: true, 127 | appendTo: document.body, 128 | innerHTML: 'PayPal Test', 129 | }); 130 | 131 | // bind to count loaded event 132 | document.addEventListener('OpenShare.count-loaded', () => { 133 | console.log('OpenShare (count) loaded'); 134 | }); 135 | 136 | // bind to share loaded event 137 | document.addEventListener('OpenShare.share-loaded', () => { 138 | console.log('OpenShare (share) loaded'); 139 | 140 | // bind to shared event on each individual node 141 | [].forEach.call(document.querySelectorAll('[data-open-share]'), (node) => { 142 | node.addEventListener('OpenShare.shared', (e) => { 143 | console.log('Open Share Shared', e); 144 | }); 145 | }); 146 | 147 | const examples = { // eslint-disable-line no-unused-vars 148 | twitter: new OpenShare.share({ //eslint-disable-line 149 | type: 'twitter', 150 | bindClick: true, 151 | url: 'http://digitalsurgeons.com', 152 | via: 'digitalsurgeons', 153 | text: 'Digital Surgeons', 154 | hashtags: 'forwardobsessed', 155 | }, document.querySelector('[data-api-example="twitter"]')), 156 | 157 | facebook: new OpenShare.share({ //eslint-disable-line 158 | type: 'facebook', 159 | bindClick: true, 160 | link: 'http://digitalsurgeons.com', 161 | picture: 'http://www.digitalsurgeons.com/img/about/bg_office_team.jpg', 162 | caption: 'Digital Surgeons', 163 | description: 'forwardobsessed', 164 | }, document.querySelector('[data-api-example="facebook"]')), 165 | 166 | pinterest: new OpenShare.share({ //eslint-disable-line 167 | type: 'pinterest', 168 | bindClick: true, 169 | url: 'http://digitalsurgeons.com', 170 | media: 'http://www.digitalsurgeons.com/img/about/bg_office_team.jpg', 171 | description: 'Digital Surgeons', 172 | appendTo: document.body, 173 | }, document.querySelector('[data-api-example="pinterest"]')), 174 | 175 | email: new OpenShare.share({ //eslint-disable-line 176 | type: 'email', 177 | bindClick: true, 178 | to: 'techroom@digitalsurgeons.com', 179 | subject: 'Digital Surgeons', 180 | body: 'Forward Obsessed', 181 | }, document.querySelector('[data-api-example="email"]')), 182 | }; 183 | }); 184 | 185 | // Example of listening for counted events on individual urls or arrays of urls 186 | const urls = [ 187 | 'facebook', 188 | 'google', 189 | 'linkedin', 190 | 'reddit', 191 | 'pinterest', 192 | [ 193 | 'google', 194 | 'linkedin', 195 | 'reddit', 196 | 'pinterest', 197 | ], 198 | ]; 199 | 200 | urls.forEach((url) => { 201 | if (Array.isArray(url)) { 202 | url = url.join(','); 203 | } 204 | const countNode = document.querySelectorAll(`[data-open-share-count="${url}"]`); 205 | 206 | [].forEach.call(countNode, (node) => { 207 | node.addEventListener(`OpenShare.counted-${url}`, () => { 208 | const counts = node.innerHTML; 209 | if (counts) console.log(url, 'shares: ', counts); 210 | }); 211 | }); 212 | }); 213 | 214 | // test twitter count js api 215 | new OpenShare.count({ //eslint-disable-line 216 | type: 'twitter', 217 | url: 'https://www.digitalsurgeons.com/thoughts/technology/the-blockchain-revolution', 218 | key: 'dstweets', 219 | }, (node) => { 220 | const os = new OpenShare.share({ //eslint-disable-line 221 | type: 'twitter', 222 | url: 'https://www.digitalsurgeons.com/thoughts/technology/the-blockchain-revolution', 223 | via: 'digitalsurgeons', 224 | hashtags: 'forwardobsessed, blockchain', 225 | appendTo: document.body, 226 | innerHTML: 'BLOCKCHAIN', 227 | }); 228 | os.appendChild(node); 229 | }); 230 | -------------------------------------------------------------------------------- /test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Open Share 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 168 | 169 | 170 | 171 |

Open Share Test Suite

172 | 173 |
174 | 175 |

176 | Total DigitalSurgeons.com Shares: 177 | 181 |

182 | 183 | 198 | 199 | 208 | 209 | 218 | 219 | 228 | 229 | 243 | 244 | 252 | 253 | 257 | 258 | 259 | Watch 260 | 261 | 262 | 266 | 267 | 268 | Subscribe 269 | 270 | 271 | 273 | 274 | 275 | Share 276 | 277 | 278 | 282 | 283 | 284 | Follow 285 | 286 | 287 | 290 | 291 | 292 | Follow 293 | 294 | 295 | 298 | 299 | 300 | Share 301 | 304 | 305 | 306 | 312 | 313 | 314 | Open Google Maps 315 | 316 | 317 | 324 | 325 | 326 | Open Google Maps Search 327 | 328 | 334 | 335 | 336 | Open Google Maps Directions 337 | 338 | 339 | 344 | 345 | 346 | Pin 347 | 350 | 351 | 352 | 356 | 357 | 358 | Share 359 | 362 | 363 | 364 | 368 | 369 | 370 | Buffer 371 | 372 | 373 | 378 | 379 | 380 | Share 381 | 382 | 383 | 387 | 388 | 389 | Share 390 | 393 | 394 | 395 | 398 | 399 | 400 | Follow 401 | 402 | 403 | 406 | 407 | 408 | Send 409 | 410 | 411 | 414 | 415 | 416 | Text 417 | 418 | 419 | 428 | 429 | 433 | 434 | 438 | 439 | 440 | 441 | Pin 442 | 443 | 444 | 448 | 449 | 452 | 453 | 454 | Fork me on Github (stars count) 455 | 458 | 459 | 460 | 463 | 464 | 465 | Fork me on Github (forks count) 466 | 467 | 470 | 471 | 472 | 475 | 476 | 477 | Fork me on Github (watchers count) 478 | 481 | 482 | 483 | 488 | 489 | 490 | New Issue 491 | 492 | 493 | 496 | 497 | 498 | Dribbble 499 | 502 | 503 | 504 | 509 | 510 | 511 | codepen 512 | 513 |
514 | 515 |
516 | 517 |
518 | 519 |
520 | 521 |
522 | 523 |
524 | 525 |
526 | 527 |

Create individual Count Nodes

528 |
529 | 530 | 531 | 532 |
533 | 534 | 535 | 536 | 764 | 765 | 766 | 767 | 775 | 776 | 777 | 778 | 780 | 785 | 786 | 787 | --------------------------------------------------------------------------------