vue-socials
Version:
Social media share buttons and counts for Vue.js
205 lines (181 loc) • 7.07 kB
JavaScript
import { defineComponent, h } from 'vue';
import getFormattedWindowFeatures from '../../utils/getFormattedWindowFeatures.js';
import getPopupClientRect from '../../utils/getPopupClientRect.js';
import { isUndefined } from '../../utils/inspect.js';
/**
* Hey!
*
* Base socials mixin used for every social component
* which have share window. It provides a method for window.open()
* and has props for window features. Also has a method for component render.
*/
var DEFAULT_WINDOW_FEATURES = {
width: 600,
height: 540
};
/**
* Wrapper around Vue mixin to pass parameters inside.
* We use multiple parameters instead of a single object because
* it causes problems with tree-shaking. I don't know why.
* A little bit inconvenient, but overall OK :)
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
function BaseSocials(name, customWindowFeatures, customShareOptions, customAriaLabel, isShareOptionsRequired, isWindowFeaturesRequired) {
return /* #__PURE__ */defineComponent({
props: {
/**
* Requested features of the new window
* @link https://developer.mozilla.org/en-US/docs/Web/API/Window/open#Window_features
*/
windowFeatures: {
type: Object,
default: function _default() {
return customWindowFeatures || DEFAULT_WINDOW_FEATURES;
},
required: isWindowFeaturesRequired
},
/**
* Share parameters for social network
*/
shareOptions: {
type: Object,
default: function _default() {
return customShareOptions || {};
},
required: isShareOptionsRequired || true
},
/**
* Use native link behavior instead of window.open()
*/
useNativeBehavior: {
type: Boolean,
default: false
}
},
data: function data() {
return {
shareDialog: null,
shareDialogCloseIntervalId: undefined
};
},
emits: ['click', 'popup-block', 'popup-open', 'popup-close', 'popup-focus'],
/**
* Make sure interval has been cleared
*/
beforeUnmount: function beforeUnmount() {
window.clearInterval(this.shareDialogCloseIntervalId);
},
computed: {
/**
* Merge default and user window features
*/
mergedWindowFeatures: function mergedWindowFeatures() {
var windowFeatures = this.windowFeatures;
/**
* We use `Object.assign` instead of the spread operator
* to prevent adding the polyfill (about 150 bytes gzipped)
*/
return Object.assign({}, DEFAULT_WINDOW_FEATURES, windowFeatures);
},
/**
* Calculate the aria-label for a link.
* It replaces @s in a string with a social network name.
*/
ariaLabel: function ariaLabel() {
var $attrs = this.$attrs;
var target = $attrs.target;
var label = customAriaLabel || 'Share this with @s.';
if (target === '_blank' || isUndefined(target)) {
label += ' (opens in new window)';
}
return label.replace(/@s/g, name);
}
},
methods: {
/**
* Create new share popup from url
* @link https://developer.mozilla.org/en-US/docs/Web/API/Window/open#Syntax
*/
openShareDialog: function openShareDialog(url) {
var _this$shareDialog,
_this = this;
var mergedWindowFeatures = this.mergedWindowFeatures;
var _mergedWindowFeatures = mergedWindowFeatures.width,
width = _mergedWindowFeatures === void 0 ? DEFAULT_WINDOW_FEATURES.width : _mergedWindowFeatures,
_mergedWindowFeatures2 = mergedWindowFeatures.height,
height = _mergedWindowFeatures2 === void 0 ? DEFAULT_WINDOW_FEATURES.height : _mergedWindowFeatures2;
var shareDialogClientRect = getPopupClientRect(width, height);
var formattedFeatures = getFormattedWindowFeatures(Object.assign({}, mergedWindowFeatures, shareDialogClientRect));
/**
* If the pointer to the window object in memory does not exist
* or if such pointer exists but the window was closed
*/
if (this.shareDialog === null || (_this$shareDialog = this.shareDialog) !== null && _this$shareDialog !== void 0 && _this$shareDialog.closed) {
/**
* then create it. The new window will be created and
* will be brought on top of any other window.
*/
this.shareDialog = window.open(url, '_blank', formattedFeatures);
/**
* If window.open has been blocked – emit 'block' event and then do nothing
* If not – emit 'open' event
*/
if (!this.shareDialog) {
this.$emit('popup-block');
return;
}
this.$emit('popup-open');
/**
* window.onbeforeunload event didn't work because of Same Origin Policy
* So we check if it has been closed every 300 ms
* @link https://atashbahar.com/post/2010-04-27-detect-when-a-javascript-popup-window-gets-closed
*/
this.shareDialogCloseIntervalId = window.setInterval(function () {
var _this$shareDialog2;
if (_this.shareDialog === null || (_this$shareDialog2 = _this.shareDialog) !== null && _this$shareDialog2 !== void 0 && _this$shareDialog2.closed) {
window.clearInterval(_this.shareDialogCloseIntervalId);
_this.$emit('popup-close');
/**
* Unset reference to the popup window
* @link https://web.dev/detached-window-memory-leaks/#solution-unset-references
*/
_this.shareDialog = null;
}
}, 300);
} else {
/**
* else the window reference must exist and the window
* is not closed; therefore, we can bring it back on top of any other
* window with the focus() method. There would be no need to re-create
* the window or to reload the referenced resource.
*/
this.shareDialog.focus();
this.$emit('popup-focus');
}
},
/**
* Create new share component
*/
generateComponent: function generateComponent(url) {
var _this2 = this,
_this$$slots$default,
_this$$slots;
return h('a', {
href: url,
target: '_blank',
rel: 'nofollow noopener noreferrer',
'aria-label': this.ariaLabel,
onClick: function onClick(event) {
if (!_this2.useNativeBehavior) {
event.preventDefault();
_this2.openShareDialog(url);
}
_this2.$emit('click');
}
}, (_this$$slots$default = (_this$$slots = this.$slots).default) === null || _this$$slots$default === void 0 ? void 0 : _this$$slots$default.call(_this$$slots));
}
}
});
}
export default BaseSocials;
export { DEFAULT_WINDOW_FEATURES };