diff --git a/CHANGELOG.md b/CHANGELOG.md index a1cd9e6..048075f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ + +# [2.2.0](https://github.com/nicolasbeauvais/vue-social-sharing/compare/2.1.5...2.2.0) (2017-03-29) +- Internal methods refactor +- Rename `social_shares_click` event to `social_shares_open` +- Add `social_shares_change` and `social_shares_close` event + # [2.1.5](https://github.com/nicolasbeauvais/vue-social-sharing/compare/2.1.4...2.1.5) (2017-03-18) - Vue 2.2.4 compatibility diff --git a/README.md b/README.md index 523cedc..6ae2f64 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,25 @@ Prop | Data Type | Default | Description `twitter-user` | String | | Twitter user (Twitter only). `media` | String | | Url to a media (Pinterest only). +#### Available events + +Events are emitted on the vue $root instance: + +Name | Data | Description +---------------------- | -------------------------- | -------------------------------------------------------------------------- +`social_shares_open` | Network object, shared url | Fired when a sharing popup is open +`social_shares_change` | Network object, shared url | Fired when the user open a new sharing popup while another is already open +`social_shares_close` | Network object, shared url | Fired when a sharing popup is closed or changed by another popup + +You can listen to a `vue-social-sharing` event by using the following code: +```javascript +Vue.$root.$on('social_shares_open', function (network, url) { + // your event code +}); +``` + +> Note that the `social_shares_close` event is not fired for Whatsapp. + ## Feature request Feel free to open an issue to ask for a new social network support. diff --git a/bower.json b/bower.json index f0023d3..e718cc6 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "vue-social-sharing", - "version": "2.1.4", + "version": "2.2.0", "homepage": "https://github.com/nicolasbeauvais/vue-social-sharing", "authors": [ "nicolasbeauvais " diff --git a/dist/vue-social-sharing.common.js b/dist/vue-social-sharing.common.js index 17b970f..a6b45ae 100644 --- a/dist/vue-social-sharing.common.js +++ b/dist/vue-social-sharing.common.js @@ -1,5 +1,5 @@ /*! - * vue-social-sharing v2.1.4 + * vue-social-sharing v2.2.0 * (c) 2017 nicolasbeauvais * Released under the MIT License. */ @@ -46,7 +46,7 @@ var SocialSharingNetwork = { id: context.data.attrs.id || null, 'data-link': network.type === 'popup' ? '#share-' + context.props.network - : context.parent._getSharer(context.props.network), + : context.parent.createSharingUrl(context.props.network), 'data-action': network.type === 'popup' ? null : network.action }, on: { @@ -181,7 +181,8 @@ var SocialSharing = { height: 436, top: 0, left: 0, - window: undefined + window: undefined, + interval: null } }; }, @@ -192,7 +193,7 @@ var SocialSharing = { * * @param network Social network key. */ - _getSharer: function (network) { + createSharingUrl: function createSharingUrl (network) { return this.networks[network].sharer .replace(/@url/g, encodeURIComponent(this.url)) .replace(/@title/g, encodeURIComponent(this.title)) @@ -208,9 +209,9 @@ var SocialSharing = { * * @param string network Social network key. */ - share: function (network) { - this._openSharer(this._getSharer(network)); - this.$root.$emit('social_shares_click', network, this.url); + share: function share (network) { + this.openSharer(network, this.createSharingUrl(network)); + this.$root.$emit('social_shares_open', network, this.url); }, /** @@ -218,9 +219,9 @@ var SocialSharing = { * * @param string network Social network key. */ - touch: function (network) { - window.open(this._getSharer(network), '_self'); - this.$root.$emit('social_shares_click', network, this.url); + touch: function touch (network) { + window.open(this.createSharingUrl(network), '_self'); + this.$root.$emit('social_shares_open', network, this.url); }, /** @@ -228,7 +229,16 @@ var SocialSharing = { * * @param string url Url to share. */ - _openSharer: function (url) { + openSharer: function openSharer (network, url) { + var this$1 = this; + + // If a popup window already exist it will be replaced, trigger a close event. + if (this.popup.window && this.popup.interval) { + clearInterval(this.popup.interval); + this.popup.window.close();// Force close (for Facebook) + this.$root.$emit('social_shares_change', network, this.url); + } + this.popup.window = window.open( url, 'sharer', @@ -246,13 +256,24 @@ var SocialSharing = { ',location=' + (this.popup.location ? 'yes' : 'no') + ',directories=' + (this.popup.directories ? 'yes' : 'no') ); + + this.popup.window.focus(); + + // Create an interval to detect popup closing event + this.popup.interval = setInterval(function () { + if (this$1.popup.window.closed) { + clearInterval(this$1.popup.interval); + this$1.popup.window = undefined; + this$1.$root.$emit('social_shares_close', network, this$1.url); + } + }, 500); } }, /** * Sets popup default dimensions. */ - mounted: function () { + mounted: function mounted () { if (!inBrowser) { return; } @@ -279,7 +300,7 @@ var SocialSharing = { } }; -SocialSharing.version = '2.1.4'; +SocialSharing.version = '2.2.0'; SocialSharing.install = function (Vue) { Vue.component('social-sharing', SocialSharing); diff --git a/dist/vue-social-sharing.js b/dist/vue-social-sharing.js index b3cd618..e96b75b 100644 --- a/dist/vue-social-sharing.js +++ b/dist/vue-social-sharing.js @@ -1,5 +1,5 @@ /*! - * vue-social-sharing v2.1.4 + * vue-social-sharing v2.2.0 * (c) 2017 nicolasbeauvais * Released under the MIT License. */ @@ -50,7 +50,7 @@ var SocialSharingNetwork = { id: context.data.attrs.id || null, 'data-link': network.type === 'popup' ? '#share-' + context.props.network - : context.parent._getSharer(context.props.network), + : context.parent.createSharingUrl(context.props.network), 'data-action': network.type === 'popup' ? null : network.action }, on: { @@ -185,7 +185,8 @@ var SocialSharing = { height: 436, top: 0, left: 0, - window: undefined + window: undefined, + interval: null } }; }, @@ -196,7 +197,7 @@ var SocialSharing = { * * @param network Social network key. */ - _getSharer: function (network) { + createSharingUrl: function createSharingUrl (network) { return this.networks[network].sharer .replace(/@url/g, encodeURIComponent(this.url)) .replace(/@title/g, encodeURIComponent(this.title)) @@ -212,9 +213,9 @@ var SocialSharing = { * * @param string network Social network key. */ - share: function (network) { - this._openSharer(this._getSharer(network)); - this.$root.$emit('social_shares_click', network, this.url); + share: function share (network) { + this.openSharer(network, this.createSharingUrl(network)); + this.$root.$emit('social_shares_open', network, this.url); }, /** @@ -222,9 +223,9 @@ var SocialSharing = { * * @param string network Social network key. */ - touch: function (network) { - window.open(this._getSharer(network), '_self'); - this.$root.$emit('social_shares_click', network, this.url); + touch: function touch (network) { + window.open(this.createSharingUrl(network), '_self'); + this.$root.$emit('social_shares_open', network, this.url); }, /** @@ -232,7 +233,16 @@ var SocialSharing = { * * @param string url Url to share. */ - _openSharer: function (url) { + openSharer: function openSharer (network, url) { + var this$1 = this; + + // If a popup window already exist it will be replaced, trigger a close event. + if (this.popup.window && this.popup.interval) { + clearInterval(this.popup.interval); + this.popup.window.close();// Force close (for Facebook) + this.$root.$emit('social_shares_change', network, this.url); + } + this.popup.window = window.open( url, 'sharer', @@ -250,13 +260,24 @@ var SocialSharing = { ',location=' + (this.popup.location ? 'yes' : 'no') + ',directories=' + (this.popup.directories ? 'yes' : 'no') ); + + this.popup.window.focus(); + + // Create an interval to detect popup closing event + this.popup.interval = setInterval(function () { + if (this$1.popup.window.closed) { + clearInterval(this$1.popup.interval); + this$1.popup.window = undefined; + this$1.$root.$emit('social_shares_close', network, this$1.url); + } + }, 500); } }, /** * Sets popup default dimensions. */ - mounted: function () { + mounted: function mounted () { if (!inBrowser) { return; } @@ -283,7 +304,7 @@ var SocialSharing = { } }; -SocialSharing.version = '2.1.4'; +SocialSharing.version = '2.2.0'; SocialSharing.install = function (Vue) { Vue.component('social-sharing', SocialSharing); diff --git a/dist/vue-social-sharing.min.js b/dist/vue-social-sharing.min.js index 5c850f3..6f13e84 100644 --- a/dist/vue-social-sharing.min.js +++ b/dist/vue-social-sharing.min.js @@ -1,6 +1,6 @@ /*! - * vue-social-sharing v2.1.4 + * vue-social-sharing v2.2.0 * (c) 2017 nicolasbeauvais * Released under the MIT License. */ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.VueSocialSharing=e()}(this,function(){"use strict";var t={sharer:"https://www.facebook.com/sharer/sharer.php?u=@url&title=@title&description=@description"e=@quote",type:"popup"},e={sharer:"https://plus.google.com/share?url=@url",type:"popup"},i={sharer:"https://www.linkedin.com/shareArticle?mini=true&url=@url&title=@title&summary=@description",type:"popup"},o={sharer:"https://pinterest.com/pin/create/button/?url=@url&media=@media&description=@title",type:"popup"},r={sharer:"https://www.reddit.com/submit?url=@url&title=@title",type:"popup"},p={sharer:"https://twitter.com/intent/tweet?text=@title&url=@url&hashtags=@hashtags@twitteruser",type:"popup"},n={sharer:"https://vk.com/share.php?url=@url&title=@title&description=@description&image=@media&noparse=true",type:"popup"},s={sharer:"http://service.weibo.com/share/share.php?url=@url&title=@title",type:"popup"},a={sharer:"whatsapp://send?text=@url",type:"direct",action:"share/whatsapp/share"},u={facebook:t,googleplus:e,linkedin:i,pinterest:o,reddit:r,twitter:p,vk:n,weibo:s,whatsapp:a},l={functional:!0,props:{network:{type:String,default:""}},render:function(t,e){var i=u[e.props.network];return t(e.parent.networkTag,{class:e.data.staticClass||null,style:e.data.staticStyle||null,attrs:{id:e.data.attrs.id||null,"data-link":"popup"===i.type?"#share-"+e.props.network:e.parent._getSharer(e.props.network),"data-action":"popup"===i.type?null:i.action},on:{click:"popup"===i.type?function(){e.parent.share(e.props.network)}:function(){e.parent.touch(e.props.network)}}},e.children)}},h="undefined"!=typeof window,c=h?window:null,d={props:{url:{type:String,default:h?window.location.href:""},title:{type:String,default:""},description:{type:String,default:""},quote:{type:String,default:""},hashtags:{type:String,default:""},twitterUser:{type:String,default:""},withCounts:{type:[String,Boolean],default:!1},googleKey:{type:String,default:void 0},media:{type:String,default:""},networkTag:{type:String,default:"span"}},data:function(){return{networks:u,popup:{status:!1,resizable:!0,toolbar:!1,menubar:!1,scrollbars:!1,location:!1,directories:!1,width:626,height:436,top:0,left:0,window:void 0}}},methods:{_getSharer:function(t){return this.networks[t].sharer.replace(/@url/g,encodeURIComponent(this.url)).replace(/@title/g,encodeURIComponent(this.title)).replace(/@description/g,encodeURIComponent(this.description)).replace(/@quote/g,encodeURIComponent(this.quote)).replace(/@hashtags/g,this.hashtags).replace(/@media/g,this.media).replace(/@twitteruser/g,this.twitterUser?"&via="+this.twitterUser:"")},share:function(t){this._openSharer(this._getSharer(t)),this.$root.$emit("social_shares_click",t,this.url)},touch:function(t){window.open(this._getSharer(t),"_self"),this.$root.$emit("social_shares_click",t,this.url)},_openSharer:function(t){this.popup.window=window.open(t,"sharer","status="+(this.popup.status?"yes":"no")+",height="+this.popup.height+",width="+this.popup.width+",resizable="+(this.popup.resizable?"yes":"no")+",left="+this.popup.left+",top="+this.popup.top+",screenX="+this.popup.left+",screenY="+this.popup.top+",toolbar="+(this.popup.toolbar?"yes":"no")+",menubar="+(this.popup.menubar?"yes":"no")+",scrollbars="+(this.popup.scrollbars?"yes":"no")+",location="+(this.popup.location?"yes":"no")+",directories="+(this.popup.directories?"yes":"no"))}},mounted:function(){if(h){var t=void 0!==c.screenLeft?c.screenLeft:screen.left,e=void 0!==c.screenTop?c.screenTop:screen.top,i=c.innerWidth?c.innerWidth:document.documentElement.clientWidth?document.documentElement.clientWidth:screen.width,o=c.innerHeight?c.innerHeight:document.documentElement.clientHeight?document.documentElement.clientHeight:screen.height;this.popup.left=i/2-this.popup.width/2+t,this.popup.top=o/2-this.popup.height/2+e}},components:{network:l}};return d.version="2.1.4",d.install=function(t){t.component("social-sharing",d)},"undefined"!=typeof window&&(window.SocialSharing=d),d}); \ No newline at end of file +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.VueSocialSharing=e()}(this,function(){"use strict";var t={sharer:"https://www.facebook.com/sharer/sharer.php?u=@url&title=@title&description=@description"e=@quote",type:"popup"},e={sharer:"https://plus.google.com/share?url=@url",type:"popup"},i={sharer:"https://www.linkedin.com/shareArticle?mini=true&url=@url&title=@title&summary=@description",type:"popup"},o={sharer:"https://pinterest.com/pin/create/button/?url=@url&media=@media&description=@title",type:"popup"},p={sharer:"https://www.reddit.com/submit?url=@url&title=@title",type:"popup"},r={sharer:"https://twitter.com/intent/tweet?text=@title&url=@url&hashtags=@hashtags@twitteruser",type:"popup"},n={sharer:"https://vk.com/share.php?url=@url&title=@title&description=@description&image=@media&noparse=true",type:"popup"},s={sharer:"http://service.weibo.com/share/share.php?url=@url&title=@title",type:"popup"},a={sharer:"whatsapp://send?text=@url",type:"direct",action:"share/whatsapp/share"},l={facebook:t,googleplus:e,linkedin:i,pinterest:o,reddit:p,twitter:r,vk:n,weibo:s,whatsapp:a},u={functional:!0,props:{network:{type:String,default:""}},render:function(t,e){var i=l[e.props.network];return t(e.parent.networkTag,{class:e.data.staticClass||null,style:e.data.staticStyle||null,attrs:{id:e.data.attrs.id||null,"data-link":"popup"===i.type?"#share-"+e.props.network:e.parent.createSharingUrl(e.props.network),"data-action":"popup"===i.type?null:i.action},on:{click:"popup"===i.type?function(){e.parent.share(e.props.network)}:function(){e.parent.touch(e.props.network)}}},e.children)}},h="undefined"!=typeof window,c=h?window:null,d={props:{url:{type:String,default:h?window.location.href:""},title:{type:String,default:""},description:{type:String,default:""},quote:{type:String,default:""},hashtags:{type:String,default:""},twitterUser:{type:String,default:""},withCounts:{type:[String,Boolean],default:!1},googleKey:{type:String,default:void 0},media:{type:String,default:""},networkTag:{type:String,default:"span"}},data:function(){return{networks:l,popup:{status:!1,resizable:!0,toolbar:!1,menubar:!1,scrollbars:!1,location:!1,directories:!1,width:626,height:436,top:0,left:0,window:void 0,interval:null}}},methods:{createSharingUrl:function(t){return this.networks[t].sharer.replace(/@url/g,encodeURIComponent(this.url)).replace(/@title/g,encodeURIComponent(this.title)).replace(/@description/g,encodeURIComponent(this.description)).replace(/@quote/g,encodeURIComponent(this.quote)).replace(/@hashtags/g,this.hashtags).replace(/@media/g,this.media).replace(/@twitteruser/g,this.twitterUser?"&via="+this.twitterUser:"")},share:function(t){this.openSharer(t,this.createSharingUrl(t)),this.$root.$emit("social_shares_open",t,this.url)},touch:function(t){window.open(this.createSharingUrl(t),"_self"),this.$root.$emit("social_shares_open",t,this.url)},openSharer:function(t,e){var i=this;this.popup.window&&this.popup.interval&&(clearInterval(this.popup.interval),this.popup.window.close(),this.$root.$emit("social_shares_change",t,this.url)),this.popup.window=window.open(e,"sharer","status="+(this.popup.status?"yes":"no")+",height="+this.popup.height+",width="+this.popup.width+",resizable="+(this.popup.resizable?"yes":"no")+",left="+this.popup.left+",top="+this.popup.top+",screenX="+this.popup.left+",screenY="+this.popup.top+",toolbar="+(this.popup.toolbar?"yes":"no")+",menubar="+(this.popup.menubar?"yes":"no")+",scrollbars="+(this.popup.scrollbars?"yes":"no")+",location="+(this.popup.location?"yes":"no")+",directories="+(this.popup.directories?"yes":"no")),this.popup.window.focus(),this.popup.interval=setInterval(function(){i.popup.window.closed&&(clearInterval(i.popup.interval),i.popup.window=void 0,i.$root.$emit("social_shares_close",t,i.url))},500)}},mounted:function(){if(h){var t=void 0!==c.screenLeft?c.screenLeft:screen.left,e=void 0!==c.screenTop?c.screenTop:screen.top,i=c.innerWidth?c.innerWidth:document.documentElement.clientWidth?document.documentElement.clientWidth:screen.width,o=c.innerHeight?c.innerHeight:document.documentElement.clientHeight?document.documentElement.clientHeight:screen.height;this.popup.left=i/2-this.popup.width/2+t,this.popup.top=o/2-this.popup.height/2+e}},components:{network:u}};return d.version="2.2.0",d.install=function(t){t.component("social-sharing",d)},"undefined"!=typeof window&&(window.SocialSharing=d),d}); \ No newline at end of file diff --git a/examples/vue2-example.html b/examples/vue2-example.html index 0c82681..aef65d1 100644 --- a/examples/vue2-example.html +++ b/examples/vue2-example.html @@ -5,6 +5,17 @@ Vue social sharing example + + @@ -21,47 +32,47 @@ diff --git a/package.json b/package.json index cd97d11..1699e3e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "vue-social-sharing", "description": "A Vue.js component for sharing links to social networks", - "version": "2.1.5", + "version": "2.2.0", "author": { "name": "nicolasbeauvais", "email": "nicolasbeauvais1@gmail.com" diff --git a/src/index.js b/src/index.js index 7e09afd..04aacfb 100644 --- a/src/index.js +++ b/src/index.js @@ -1,6 +1,6 @@ import SocialSharing from './social-sharing'; -SocialSharing.version = '2.1.4'; +SocialSharing.version = '2.2.0'; SocialSharing.install = (Vue) => { Vue.component('social-sharing', SocialSharing); diff --git a/src/social-sharing-network.js b/src/social-sharing-network.js index 6d9bbe5..d94034d 100644 --- a/src/social-sharing-network.js +++ b/src/social-sharing-network.js @@ -20,7 +20,7 @@ export default { id: context.data.attrs.id || null, 'data-link': network.type === 'popup' ? '#share-' + context.props.network - : context.parent._getSharer(context.props.network), + : context.parent.createSharingUrl(context.props.network), 'data-action': network.type === 'popup' ? null : network.action }, on: { diff --git a/src/social-sharing.js b/src/social-sharing.js index 4cfac8f..599026b 100644 --- a/src/social-sharing.js +++ b/src/social-sharing.js @@ -126,7 +126,8 @@ export default { height: 436, top: 0, left: 0, - window: undefined + window: undefined, + interval: null } }; }, @@ -137,7 +138,7 @@ export default { * * @param network Social network key. */ - _getSharer: function (network) { + createSharingUrl (network) { return this.networks[network].sharer .replace(/@url/g, encodeURIComponent(this.url)) .replace(/@title/g, encodeURIComponent(this.title)) @@ -153,9 +154,9 @@ export default { * * @param string network Social network key. */ - share: function (network) { - this._openSharer(this._getSharer(network)); - this.$root.$emit('social_shares_click', network, this.url); + share (network) { + this.openSharer(network, this.createSharingUrl(network)); + this.$root.$emit('social_shares_open', network, this.url); }, /** @@ -163,9 +164,9 @@ export default { * * @param string network Social network key. */ - touch: function (network) { - window.open(this._getSharer(network), '_self'); - this.$root.$emit('social_shares_click', network, this.url); + touch (network) { + window.open(this.createSharingUrl(network), '_self'); + this.$root.$emit('social_shares_open', network, this.url); }, /** @@ -173,7 +174,14 @@ export default { * * @param string url Url to share. */ - _openSharer: function (url) { + openSharer (network, url) { + // If a popup window already exist it will be replaced, trigger a close event. + if (this.popup.window && this.popup.interval) { + clearInterval(this.popup.interval); + this.popup.window.close();// Force close (for Facebook) + this.$root.$emit('social_shares_change', network, this.url); + } + this.popup.window = window.open( url, 'sharer', @@ -191,13 +199,24 @@ export default { ',location=' + (this.popup.location ? 'yes' : 'no') + ',directories=' + (this.popup.directories ? 'yes' : 'no') ); + + this.popup.window.focus(); + + // Create an interval to detect popup closing event + this.popup.interval = setInterval(() => { + if (this.popup.window.closed) { + clearInterval(this.popup.interval); + this.popup.window = undefined; + this.$root.$emit('social_shares_close', network, this.url); + } + }, 500); } }, /** * Sets popup default dimensions. */ - mounted: function () { + mounted () { if (!inBrowser) { return; } diff --git a/test/unit/test.js b/test/unit/test.js index 1e65f08..e49df2a 100644 --- a/test/unit/test.js +++ b/test/unit/test.js @@ -5,7 +5,7 @@ import Networks from '../../src/networks'; describe('SocialSharing', () => { const createComponent = (propsData = {}, attr = {}) => { - const Ctor = Vue.extend({ + const Comp = Vue.extend({ template: ` @@ -39,7 +39,7 @@ describe('SocialSharing', () => { } }); - return new Ctor({ + return new Comp({ propsData, data () { return { @@ -137,4 +137,16 @@ describe('SocialSharing', () => { expect(typeof SocialSharingNetwork.props).toBe('object'); expect(SocialSharingNetwork.functional).toBe(true); }); + + it('it create a popup', () => { + const vm = createComponent(); + const network = Object.keys(Networks)[0]; + + vm.$on('social_shares_open', (sharedNetwork, url) => { + expect(sharedNetwork).toBe(network); + expect(url).toBe('https://vuejs.org/'); + }); + + vm.$children[0].share(network); + }); });