UNPKG

vue-socials

Version:

Social media share buttons and counts for Vue.js

205 lines (181 loc) 7.07 kB
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 };