Comparing version 2.0.6 to 2.0.7
@@ -17,7 +17,3 @@ { | ||
], | ||
"keywords": [ | ||
"clipboard", | ||
"copy", | ||
"cut" | ||
] | ||
"keywords": ["clipboard", "copy", "cut"] | ||
} |
@@ -27,3 +27,4 @@ # Contributing guide | ||
## Known issues | ||
If you're using npm@3 you'll probably face some issues related to peerDependencies. | ||
https://github.com/npm/npm/issues/9204 |
/*! | ||
* clipboard.js v2.0.6 | ||
* clipboard.js v2.0.7 | ||
* https://clipboardjs.com/ | ||
* | ||
* | ||
* Licensed MIT © Zeno Rocha | ||
@@ -17,372 +17,515 @@ */ | ||
})(this, function() { | ||
return /******/ (function(modules) { // webpackBootstrap | ||
/******/ // The module cache | ||
/******/ var installedModules = {}; | ||
/******/ | ||
/******/ // The require function | ||
/******/ function __webpack_require__(moduleId) { | ||
/******/ | ||
/******/ // Check if module is in cache | ||
/******/ if(installedModules[moduleId]) { | ||
/******/ return installedModules[moduleId].exports; | ||
/******/ } | ||
/******/ // Create a new module (and put it into the cache) | ||
/******/ var module = installedModules[moduleId] = { | ||
/******/ i: moduleId, | ||
/******/ l: false, | ||
/******/ exports: {} | ||
/******/ }; | ||
/******/ | ||
/******/ // Execute the module function | ||
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); | ||
/******/ | ||
/******/ // Flag the module as loaded | ||
/******/ module.l = true; | ||
/******/ | ||
/******/ // Return the exports of the module | ||
/******/ return module.exports; | ||
/******/ } | ||
/******/ | ||
/******/ | ||
/******/ // expose the modules object (__webpack_modules__) | ||
/******/ __webpack_require__.m = modules; | ||
/******/ | ||
/******/ // expose the module cache | ||
/******/ __webpack_require__.c = installedModules; | ||
/******/ | ||
/******/ // define getter function for harmony exports | ||
/******/ __webpack_require__.d = function(exports, name, getter) { | ||
/******/ if(!__webpack_require__.o(exports, name)) { | ||
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); | ||
/******/ } | ||
/******/ }; | ||
/******/ | ||
/******/ // define __esModule on exports | ||
/******/ __webpack_require__.r = function(exports) { | ||
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { | ||
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
/******/ } | ||
/******/ Object.defineProperty(exports, '__esModule', { value: true }); | ||
/******/ }; | ||
/******/ | ||
/******/ // create a fake namespace object | ||
/******/ // mode & 1: value is a module id, require it | ||
/******/ // mode & 2: merge all properties of value into the ns | ||
/******/ // mode & 4: return value when already ns object | ||
/******/ // mode & 8|1: behave like require | ||
/******/ __webpack_require__.t = function(value, mode) { | ||
/******/ if(mode & 1) value = __webpack_require__(value); | ||
/******/ if(mode & 8) return value; | ||
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; | ||
/******/ var ns = Object.create(null); | ||
/******/ __webpack_require__.r(ns); | ||
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); | ||
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); | ||
/******/ return ns; | ||
/******/ }; | ||
/******/ | ||
/******/ // getDefaultExport function for compatibility with non-harmony modules | ||
/******/ __webpack_require__.n = function(module) { | ||
/******/ var getter = module && module.__esModule ? | ||
/******/ function getDefault() { return module['default']; } : | ||
/******/ function getModuleExports() { return module; }; | ||
/******/ __webpack_require__.d(getter, 'a', getter); | ||
/******/ return getter; | ||
/******/ }; | ||
/******/ | ||
/******/ // Object.prototype.hasOwnProperty.call | ||
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; | ||
/******/ | ||
/******/ // __webpack_public_path__ | ||
/******/ __webpack_require__.p = ""; | ||
/******/ | ||
/******/ | ||
/******/ // Load entry module and return exports | ||
/******/ return __webpack_require__(__webpack_require__.s = 6); | ||
/******/ }) | ||
/************************************************************************/ | ||
/******/ ([ | ||
/* 0 */ | ||
/***/ (function(module, exports) { | ||
return /******/ (() => { // webpackBootstrap | ||
/******/ var __webpack_modules__ = ({ | ||
function select(element) { | ||
var selectedText; | ||
/***/ 134: | ||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { | ||
if (element.nodeName === 'SELECT') { | ||
element.focus(); | ||
"use strict"; | ||
selectedText = element.value; | ||
// EXPORTS | ||
__webpack_require__.d(__webpack_exports__, { | ||
"default": () => /* binding */ clipboard | ||
}); | ||
// EXTERNAL MODULE: ./node_modules/tiny-emitter/index.js | ||
var tiny_emitter = __webpack_require__(279); | ||
var tiny_emitter_default = /*#__PURE__*/__webpack_require__.n(tiny_emitter); | ||
// EXTERNAL MODULE: ./node_modules/good-listener/src/listen.js | ||
var listen = __webpack_require__(370); | ||
var listen_default = /*#__PURE__*/__webpack_require__.n(listen); | ||
// EXTERNAL MODULE: ./node_modules/select/src/select.js | ||
var src_select = __webpack_require__(817); | ||
var select_default = /*#__PURE__*/__webpack_require__.n(src_select); | ||
;// CONCATENATED MODULE: ./src/clipboard-action.js | ||
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } | ||
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } | ||
/** | ||
* Inner class which performs selection from either `text` or `target` | ||
* properties and then executes copy or cut operations. | ||
*/ | ||
var ClipboardAction = /*#__PURE__*/function () { | ||
/** | ||
* @param {Object} options | ||
*/ | ||
function ClipboardAction(options) { | ||
_classCallCheck(this, ClipboardAction); | ||
this.resolveOptions(options); | ||
this.initSelection(); | ||
} | ||
/** | ||
* Defines base properties passed from constructor. | ||
* @param {Object} options | ||
*/ | ||
_createClass(ClipboardAction, [{ | ||
key: "resolveOptions", | ||
value: function resolveOptions() { | ||
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; | ||
this.action = options.action; | ||
this.container = options.container; | ||
this.emitter = options.emitter; | ||
this.target = options.target; | ||
this.text = options.text; | ||
this.trigger = options.trigger; | ||
this.selectedText = ''; | ||
} | ||
else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') { | ||
var isReadOnly = element.hasAttribute('readonly'); | ||
/** | ||
* Decides which selection strategy is going to be applied based | ||
* on the existence of `text` and `target` properties. | ||
*/ | ||
if (!isReadOnly) { | ||
element.setAttribute('readonly', ''); | ||
} | ||
}, { | ||
key: "initSelection", | ||
value: function initSelection() { | ||
if (this.text) { | ||
this.selectFake(); | ||
} else if (this.target) { | ||
this.selectTarget(); | ||
} | ||
} | ||
/** | ||
* Creates a fake textarea element, sets its value from `text` property, | ||
*/ | ||
element.select(); | ||
element.setSelectionRange(0, element.value.length); | ||
}, { | ||
key: "createFakeElement", | ||
value: function createFakeElement() { | ||
var isRTL = document.documentElement.getAttribute('dir') === 'rtl'; | ||
this.fakeElem = document.createElement('textarea'); // Prevent zooming on iOS | ||
if (!isReadOnly) { | ||
element.removeAttribute('readonly'); | ||
} | ||
this.fakeElem.style.fontSize = '12pt'; // Reset box model | ||
selectedText = element.value; | ||
this.fakeElem.style.border = '0'; | ||
this.fakeElem.style.padding = '0'; | ||
this.fakeElem.style.margin = '0'; // Move element out of screen horizontally | ||
this.fakeElem.style.position = 'absolute'; | ||
this.fakeElem.style[isRTL ? 'right' : 'left'] = '-9999px'; // Move element to the same position vertically | ||
var yPosition = window.pageYOffset || document.documentElement.scrollTop; | ||
this.fakeElem.style.top = "".concat(yPosition, "px"); | ||
this.fakeElem.setAttribute('readonly', ''); | ||
this.fakeElem.value = this.text; | ||
return this.fakeElem; | ||
} | ||
else { | ||
if (element.hasAttribute('contenteditable')) { | ||
element.focus(); | ||
} | ||
/** | ||
* Get's the value of fakeElem, | ||
* and makes a selection on it. | ||
*/ | ||
var selection = window.getSelection(); | ||
var range = document.createRange(); | ||
}, { | ||
key: "selectFake", | ||
value: function selectFake() { | ||
var _this = this; | ||
range.selectNodeContents(element); | ||
selection.removeAllRanges(); | ||
selection.addRange(range); | ||
var fakeElem = this.createFakeElement(); | ||
selectedText = selection.toString(); | ||
this.fakeHandlerCallback = function () { | ||
return _this.removeFake(); | ||
}; | ||
this.fakeHandler = this.container.addEventListener('click', this.fakeHandlerCallback) || true; | ||
this.container.appendChild(fakeElem); | ||
this.selectedText = select_default()(fakeElem); | ||
this.copyText(); | ||
this.removeFake(); | ||
} | ||
/** | ||
* Only removes the fake element after another click event, that way | ||
* a user can hit `Ctrl+C` to copy because selection still exists. | ||
*/ | ||
return selectedText; | ||
} | ||
}, { | ||
key: "removeFake", | ||
value: function removeFake() { | ||
if (this.fakeHandler) { | ||
this.container.removeEventListener('click', this.fakeHandlerCallback); | ||
this.fakeHandler = null; | ||
this.fakeHandlerCallback = null; | ||
} | ||
module.exports = select; | ||
if (this.fakeElem) { | ||
this.container.removeChild(this.fakeElem); | ||
this.fakeElem = null; | ||
} | ||
} | ||
/** | ||
* Selects the content from element passed on `target` property. | ||
*/ | ||
}, { | ||
key: "selectTarget", | ||
value: function selectTarget() { | ||
this.selectedText = select_default()(this.target); | ||
this.copyText(); | ||
} | ||
/** | ||
* Executes the copy operation based on the current selection. | ||
*/ | ||
/***/ }), | ||
/* 1 */ | ||
/***/ (function(module, exports) { | ||
}, { | ||
key: "copyText", | ||
value: function copyText() { | ||
var succeeded; | ||
function E () { | ||
// Keep this empty so it's easier to inherit from | ||
// (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3) | ||
} | ||
try { | ||
succeeded = document.execCommand(this.action); | ||
} catch (err) { | ||
succeeded = false; | ||
} | ||
E.prototype = { | ||
on: function (name, callback, ctx) { | ||
var e = this.e || (this.e = {}); | ||
this.handleResult(succeeded); | ||
} | ||
/** | ||
* Fires an event based on the copy operation result. | ||
* @param {Boolean} succeeded | ||
*/ | ||
(e[name] || (e[name] = [])).push({ | ||
fn: callback, | ||
ctx: ctx | ||
}); | ||
}, { | ||
key: "handleResult", | ||
value: function handleResult(succeeded) { | ||
this.emitter.emit(succeeded ? 'success' : 'error', { | ||
action: this.action, | ||
text: this.selectedText, | ||
trigger: this.trigger, | ||
clearSelection: this.clearSelection.bind(this) | ||
}); | ||
} | ||
/** | ||
* Moves focus away from `target` and back to the trigger, removes current selection. | ||
*/ | ||
return this; | ||
}, | ||
}, { | ||
key: "clearSelection", | ||
value: function clearSelection() { | ||
if (this.trigger) { | ||
this.trigger.focus(); | ||
} | ||
once: function (name, callback, ctx) { | ||
var self = this; | ||
function listener () { | ||
self.off(name, listener); | ||
callback.apply(ctx, arguments); | ||
}; | ||
document.activeElement.blur(); | ||
window.getSelection().removeAllRanges(); | ||
} | ||
/** | ||
* Sets the `action` to be performed which can be either 'copy' or 'cut'. | ||
* @param {String} action | ||
*/ | ||
listener._ = callback | ||
return this.on(name, listener, ctx); | ||
}, | ||
}, { | ||
key: "destroy", | ||
emit: function (name) { | ||
var data = [].slice.call(arguments, 1); | ||
var evtArr = ((this.e || (this.e = {}))[name] || []).slice(); | ||
var i = 0; | ||
var len = evtArr.length; | ||
/** | ||
* Destroy lifecycle. | ||
*/ | ||
value: function destroy() { | ||
this.removeFake(); | ||
} | ||
}, { | ||
key: "action", | ||
set: function set() { | ||
var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'copy'; | ||
this._action = action; | ||
for (i; i < len; i++) { | ||
evtArr[i].fn.apply(evtArr[i].ctx, data); | ||
if (this._action !== 'copy' && this._action !== 'cut') { | ||
throw new Error('Invalid "action" value, use either "copy" or "cut"'); | ||
} | ||
} | ||
/** | ||
* Gets the `action` property. | ||
* @return {String} | ||
*/ | ||
, | ||
get: function get() { | ||
return this._action; | ||
} | ||
/** | ||
* Sets the `target` property using an element | ||
* that will be have its content copied. | ||
* @param {Element} target | ||
*/ | ||
return this; | ||
}, | ||
}, { | ||
key: "target", | ||
set: function set(target) { | ||
if (target !== undefined) { | ||
if (target && _typeof(target) === 'object' && target.nodeType === 1) { | ||
if (this.action === 'copy' && target.hasAttribute('disabled')) { | ||
throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute'); | ||
} | ||
off: function (name, callback) { | ||
var e = this.e || (this.e = {}); | ||
var evts = e[name]; | ||
var liveEvents = []; | ||
if (this.action === 'cut' && (target.hasAttribute('readonly') || target.hasAttribute('disabled'))) { | ||
throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes'); | ||
} | ||
if (evts && callback) { | ||
for (var i = 0, len = evts.length; i < len; i++) { | ||
if (evts[i].fn !== callback && evts[i].fn._ !== callback) | ||
liveEvents.push(evts[i]); | ||
this._target = target; | ||
} else { | ||
throw new Error('Invalid "target" value, use a valid Element'); | ||
} | ||
} | ||
} | ||
/** | ||
* Gets the `target` property. | ||
* @return {String|HTMLElement} | ||
*/ | ||
, | ||
get: function get() { | ||
return this._target; | ||
} | ||
}]); | ||
// Remove event from queue to prevent memory leak | ||
// Suggested by https://github.com/lazd | ||
// Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910 | ||
return ClipboardAction; | ||
}(); | ||
(liveEvents.length) | ||
? e[name] = liveEvents | ||
: delete e[name]; | ||
/* harmony default export */ const clipboard_action = (ClipboardAction); | ||
;// CONCATENATED MODULE: ./src/clipboard.js | ||
function clipboard_typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { clipboard_typeof = function _typeof(obj) { return typeof obj; }; } else { clipboard_typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return clipboard_typeof(obj); } | ||
return this; | ||
} | ||
}; | ||
function clipboard_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
module.exports = E; | ||
module.exports.TinyEmitter = E; | ||
function clipboard_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } | ||
function clipboard_createClass(Constructor, protoProps, staticProps) { if (protoProps) clipboard_defineProperties(Constructor.prototype, protoProps); if (staticProps) clipboard_defineProperties(Constructor, staticProps); return Constructor; } | ||
/***/ }), | ||
/* 2 */ | ||
/***/ (function(module, exports, __webpack_require__) { | ||
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } | ||
var is = __webpack_require__(3); | ||
var delegate = __webpack_require__(4); | ||
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } | ||
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } | ||
function _possibleConstructorReturn(self, call) { if (call && (clipboard_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } | ||
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } | ||
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } } | ||
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } | ||
/** | ||
* Validates all params and calls the right | ||
* listener function based on its target type. | ||
* | ||
* @param {String|HTMLElement|HTMLCollection|NodeList} target | ||
* @param {String} type | ||
* @param {Function} callback | ||
* @return {Object} | ||
* Helper function to retrieve attribute value. | ||
* @param {String} suffix | ||
* @param {Element} element | ||
*/ | ||
function listen(target, type, callback) { | ||
if (!target && !type && !callback) { | ||
throw new Error('Missing required arguments'); | ||
function getAttributeValue(suffix, element) { | ||
var attribute = "data-clipboard-".concat(suffix); | ||
if (!element.hasAttribute(attribute)) { | ||
return; | ||
} | ||
return element.getAttribute(attribute); | ||
} | ||
/** | ||
* Base class which takes one or more elements, adds event listeners to them, | ||
* and instantiates a new `ClipboardAction` on each click. | ||
*/ | ||
var Clipboard = /*#__PURE__*/function (_Emitter) { | ||
_inherits(Clipboard, _Emitter); | ||
var _super = _createSuper(Clipboard); | ||
/** | ||
* @param {String|HTMLElement|HTMLCollection|NodeList} trigger | ||
* @param {Object} options | ||
*/ | ||
function Clipboard(trigger, options) { | ||
var _this; | ||
clipboard_classCallCheck(this, Clipboard); | ||
_this = _super.call(this); | ||
_this.resolveOptions(options); | ||
_this.listenClick(trigger); | ||
return _this; | ||
} | ||
/** | ||
* Defines if attributes would be resolved using internal setter functions | ||
* or custom functions that were passed in the constructor. | ||
* @param {Object} options | ||
*/ | ||
clipboard_createClass(Clipboard, [{ | ||
key: "resolveOptions", | ||
value: function resolveOptions() { | ||
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; | ||
this.action = typeof options.action === 'function' ? options.action : this.defaultAction; | ||
this.target = typeof options.target === 'function' ? options.target : this.defaultTarget; | ||
this.text = typeof options.text === 'function' ? options.text : this.defaultText; | ||
this.container = clipboard_typeof(options.container) === 'object' ? options.container : document.body; | ||
} | ||
/** | ||
* Adds a click event listener to the passed trigger. | ||
* @param {String|HTMLElement|HTMLCollection|NodeList} trigger | ||
*/ | ||
if (!is.string(type)) { | ||
throw new TypeError('Second argument must be a String'); | ||
}, { | ||
key: "listenClick", | ||
value: function listenClick(trigger) { | ||
var _this2 = this; | ||
this.listener = listen_default()(trigger, 'click', function (e) { | ||
return _this2.onClick(e); | ||
}); | ||
} | ||
/** | ||
* Defines a new `ClipboardAction` on each click event. | ||
* @param {Event} e | ||
*/ | ||
if (!is.fn(callback)) { | ||
throw new TypeError('Third argument must be a Function'); | ||
}, { | ||
key: "onClick", | ||
value: function onClick(e) { | ||
var trigger = e.delegateTarget || e.currentTarget; | ||
if (this.clipboardAction) { | ||
this.clipboardAction = null; | ||
} | ||
this.clipboardAction = new clipboard_action({ | ||
action: this.action(trigger), | ||
target: this.target(trigger), | ||
text: this.text(trigger), | ||
container: this.container, | ||
trigger: trigger, | ||
emitter: this | ||
}); | ||
} | ||
/** | ||
* Default `action` lookup function. | ||
* @param {Element} trigger | ||
*/ | ||
if (is.node(target)) { | ||
return listenNode(target, type, callback); | ||
}, { | ||
key: "defaultAction", | ||
value: function defaultAction(trigger) { | ||
return getAttributeValue('action', trigger); | ||
} | ||
else if (is.nodeList(target)) { | ||
return listenNodeList(target, type, callback); | ||
/** | ||
* Default `target` lookup function. | ||
* @param {Element} trigger | ||
*/ | ||
}, { | ||
key: "defaultTarget", | ||
value: function defaultTarget(trigger) { | ||
var selector = getAttributeValue('target', trigger); | ||
if (selector) { | ||
return document.querySelector(selector); | ||
} | ||
} | ||
else if (is.string(target)) { | ||
return listenSelector(target, type, callback); | ||
} | ||
else { | ||
throw new TypeError('First argument must be a String, HTMLElement, HTMLCollection, or NodeList'); | ||
} | ||
} | ||
/** | ||
* Returns the support of the given action, or all actions if no action is | ||
* given. | ||
* @param {String} [action] | ||
*/ | ||
/** | ||
* Adds an event listener to a HTML element | ||
* and returns a remove listener function. | ||
* | ||
* @param {HTMLElement} node | ||
* @param {String} type | ||
* @param {Function} callback | ||
* @return {Object} | ||
*/ | ||
function listenNode(node, type, callback) { | ||
node.addEventListener(type, callback); | ||
}, { | ||
key: "defaultText", | ||
return { | ||
destroy: function() { | ||
node.removeEventListener(type, callback); | ||
} | ||
/** | ||
* Default `text` lookup function. | ||
* @param {Element} trigger | ||
*/ | ||
value: function defaultText(trigger) { | ||
return getAttributeValue('text', trigger); | ||
} | ||
} | ||
/** | ||
* Destroy lifecycle. | ||
*/ | ||
/** | ||
* Add an event listener to a list of HTML elements | ||
* and returns a remove listener function. | ||
* | ||
* @param {NodeList|HTMLCollection} nodeList | ||
* @param {String} type | ||
* @param {Function} callback | ||
* @return {Object} | ||
*/ | ||
function listenNodeList(nodeList, type, callback) { | ||
Array.prototype.forEach.call(nodeList, function(node) { | ||
node.addEventListener(type, callback); | ||
}); | ||
}, { | ||
key: "destroy", | ||
value: function destroy() { | ||
this.listener.destroy(); | ||
return { | ||
destroy: function() { | ||
Array.prototype.forEach.call(nodeList, function(node) { | ||
node.removeEventListener(type, callback); | ||
}); | ||
} | ||
if (this.clipboardAction) { | ||
this.clipboardAction.destroy(); | ||
this.clipboardAction = null; | ||
} | ||
} | ||
} | ||
}], [{ | ||
key: "isSupported", | ||
value: function isSupported() { | ||
var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ['copy', 'cut']; | ||
var actions = typeof action === 'string' ? [action] : action; | ||
var support = !!document.queryCommandSupported; | ||
actions.forEach(function (action) { | ||
support = support && !!document.queryCommandSupported(action); | ||
}); | ||
return support; | ||
} | ||
}]); | ||
/** | ||
* Add an event listener to a selector | ||
* and returns a remove listener function. | ||
* | ||
* @param {String} selector | ||
* @param {String} type | ||
* @param {Function} callback | ||
* @return {Object} | ||
*/ | ||
function listenSelector(selector, type, callback) { | ||
return delegate(document.body, selector, type, callback); | ||
} | ||
return Clipboard; | ||
}((tiny_emitter_default())); | ||
module.exports = listen; | ||
/* harmony default export */ const clipboard = (Clipboard); | ||
/***/ }), | ||
/* 3 */ | ||
/***/ (function(module, exports) { | ||
/** | ||
* Check if argument is a HTML element. | ||
* | ||
* @param {Object} value | ||
* @return {Boolean} | ||
*/ | ||
exports.node = function(value) { | ||
return value !== undefined | ||
&& value instanceof HTMLElement | ||
&& value.nodeType === 1; | ||
}; | ||
/***/ 828: | ||
/***/ ((module) => { | ||
var DOCUMENT_NODE_TYPE = 9; | ||
/** | ||
* Check if argument is a list of HTML elements. | ||
* | ||
* @param {Object} value | ||
* @return {Boolean} | ||
* A polyfill for Element.matches() | ||
*/ | ||
exports.nodeList = function(value) { | ||
var type = Object.prototype.toString.call(value); | ||
if (typeof Element !== 'undefined' && !Element.prototype.matches) { | ||
var proto = Element.prototype; | ||
return value !== undefined | ||
&& (type === '[object NodeList]' || type === '[object HTMLCollection]') | ||
&& ('length' in value) | ||
&& (value.length === 0 || exports.node(value[0])); | ||
}; | ||
proto.matches = proto.matchesSelector || | ||
proto.mozMatchesSelector || | ||
proto.msMatchesSelector || | ||
proto.oMatchesSelector || | ||
proto.webkitMatchesSelector; | ||
} | ||
/** | ||
* Check if argument is a string. | ||
* Finds the closest parent that matches a selector. | ||
* | ||
* @param {Object} value | ||
* @return {Boolean} | ||
* @param {Element} element | ||
* @param {String} selector | ||
* @return {Function} | ||
*/ | ||
exports.string = function(value) { | ||
return typeof value === 'string' | ||
|| value instanceof String; | ||
}; | ||
function closest (element, selector) { | ||
while (element && element.nodeType !== DOCUMENT_NODE_TYPE) { | ||
if (typeof element.matches === 'function' && | ||
element.matches(selector)) { | ||
return element; | ||
} | ||
element = element.parentNode; | ||
} | ||
} | ||
/** | ||
* Check if argument is a function. | ||
* | ||
* @param {Object} value | ||
* @return {Boolean} | ||
*/ | ||
exports.fn = function(value) { | ||
var type = Object.prototype.toString.call(value); | ||
module.exports = closest; | ||
return type === '[object Function]'; | ||
}; | ||
/***/ }), | ||
/* 4 */ | ||
/***/ (function(module, exports, __webpack_require__) { | ||
var closest = __webpack_require__(5); | ||
/***/ 438: | ||
/***/ ((module, __unused_webpack_exports, __webpack_require__) => { | ||
var closest = __webpack_require__(828); | ||
/** | ||
@@ -467,509 +610,347 @@ * Delegates event to a selector. | ||
/***/ }), | ||
/* 5 */ | ||
/***/ (function(module, exports) { | ||
var DOCUMENT_NODE_TYPE = 9; | ||
/***/ 879: | ||
/***/ ((__unused_webpack_module, exports) => { | ||
/** | ||
* A polyfill for Element.matches() | ||
* Check if argument is a HTML element. | ||
* | ||
* @param {Object} value | ||
* @return {Boolean} | ||
*/ | ||
if (typeof Element !== 'undefined' && !Element.prototype.matches) { | ||
var proto = Element.prototype; | ||
exports.node = function(value) { | ||
return value !== undefined | ||
&& value instanceof HTMLElement | ||
&& value.nodeType === 1; | ||
}; | ||
proto.matches = proto.matchesSelector || | ||
proto.mozMatchesSelector || | ||
proto.msMatchesSelector || | ||
proto.oMatchesSelector || | ||
proto.webkitMatchesSelector; | ||
} | ||
/** | ||
* Finds the closest parent that matches a selector. | ||
* Check if argument is a list of HTML elements. | ||
* | ||
* @param {Element} element | ||
* @param {String} selector | ||
* @return {Function} | ||
* @param {Object} value | ||
* @return {Boolean} | ||
*/ | ||
function closest (element, selector) { | ||
while (element && element.nodeType !== DOCUMENT_NODE_TYPE) { | ||
if (typeof element.matches === 'function' && | ||
element.matches(selector)) { | ||
return element; | ||
} | ||
element = element.parentNode; | ||
} | ||
} | ||
exports.nodeList = function(value) { | ||
var type = Object.prototype.toString.call(value); | ||
module.exports = closest; | ||
return value !== undefined | ||
&& (type === '[object NodeList]' || type === '[object HTMLCollection]') | ||
&& ('length' in value) | ||
&& (value.length === 0 || exports.node(value[0])); | ||
}; | ||
/** | ||
* Check if argument is a string. | ||
* | ||
* @param {Object} value | ||
* @return {Boolean} | ||
*/ | ||
exports.string = function(value) { | ||
return typeof value === 'string' | ||
|| value instanceof String; | ||
}; | ||
/***/ }), | ||
/* 6 */ | ||
/***/ (function(module, __webpack_exports__, __webpack_require__) { | ||
/** | ||
* Check if argument is a function. | ||
* | ||
* @param {Object} value | ||
* @return {Boolean} | ||
*/ | ||
exports.fn = function(value) { | ||
var type = Object.prototype.toString.call(value); | ||
"use strict"; | ||
__webpack_require__.r(__webpack_exports__); | ||
return type === '[object Function]'; | ||
}; | ||
// EXTERNAL MODULE: ./node_modules/select/src/select.js | ||
var src_select = __webpack_require__(0); | ||
var select_default = /*#__PURE__*/__webpack_require__.n(src_select); | ||
// CONCATENATED MODULE: ./src/clipboard-action.js | ||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; | ||
/***/ }), | ||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); | ||
/***/ 370: | ||
/***/ ((module, __unused_webpack_exports, __webpack_require__) => { | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
var is = __webpack_require__(879); | ||
var delegate = __webpack_require__(438); | ||
/** | ||
* Inner class which performs selection from either `text` or `target` | ||
* properties and then executes copy or cut operations. | ||
* Validates all params and calls the right | ||
* listener function based on its target type. | ||
* | ||
* @param {String|HTMLElement|HTMLCollection|NodeList} target | ||
* @param {String} type | ||
* @param {Function} callback | ||
* @return {Object} | ||
*/ | ||
function listen(target, type, callback) { | ||
if (!target && !type && !callback) { | ||
throw new Error('Missing required arguments'); | ||
} | ||
var clipboard_action_ClipboardAction = function () { | ||
/** | ||
* @param {Object} options | ||
*/ | ||
function ClipboardAction(options) { | ||
_classCallCheck(this, ClipboardAction); | ||
if (!is.string(type)) { | ||
throw new TypeError('Second argument must be a String'); | ||
} | ||
this.resolveOptions(options); | ||
this.initSelection(); | ||
if (!is.fn(callback)) { | ||
throw new TypeError('Third argument must be a Function'); | ||
} | ||
/** | ||
* Defines base properties passed from constructor. | ||
* @param {Object} options | ||
*/ | ||
if (is.node(target)) { | ||
return listenNode(target, type, callback); | ||
} | ||
else if (is.nodeList(target)) { | ||
return listenNodeList(target, type, callback); | ||
} | ||
else if (is.string(target)) { | ||
return listenSelector(target, type, callback); | ||
} | ||
else { | ||
throw new TypeError('First argument must be a String, HTMLElement, HTMLCollection, or NodeList'); | ||
} | ||
} | ||
/** | ||
* Adds an event listener to a HTML element | ||
* and returns a remove listener function. | ||
* | ||
* @param {HTMLElement} node | ||
* @param {String} type | ||
* @param {Function} callback | ||
* @return {Object} | ||
*/ | ||
function listenNode(node, type, callback) { | ||
node.addEventListener(type, callback); | ||
_createClass(ClipboardAction, [{ | ||
key: 'resolveOptions', | ||
value: function resolveOptions() { | ||
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; | ||
this.action = options.action; | ||
this.container = options.container; | ||
this.emitter = options.emitter; | ||
this.target = options.target; | ||
this.text = options.text; | ||
this.trigger = options.trigger; | ||
this.selectedText = ''; | ||
return { | ||
destroy: function() { | ||
node.removeEventListener(type, callback); | ||
} | ||
} | ||
} | ||
/** | ||
* Decides which selection strategy is going to be applied based | ||
* on the existence of `text` and `target` properties. | ||
*/ | ||
/** | ||
* Add an event listener to a list of HTML elements | ||
* and returns a remove listener function. | ||
* | ||
* @param {NodeList|HTMLCollection} nodeList | ||
* @param {String} type | ||
* @param {Function} callback | ||
* @return {Object} | ||
*/ | ||
function listenNodeList(nodeList, type, callback) { | ||
Array.prototype.forEach.call(nodeList, function(node) { | ||
node.addEventListener(type, callback); | ||
}); | ||
}, { | ||
key: 'initSelection', | ||
value: function initSelection() { | ||
if (this.text) { | ||
this.selectFake(); | ||
} else if (this.target) { | ||
this.selectTarget(); | ||
} | ||
} | ||
/** | ||
* Creates a fake textarea element, sets its value from `text` property, | ||
* and makes a selection on it. | ||
*/ | ||
}, { | ||
key: 'selectFake', | ||
value: function selectFake() { | ||
var _this = this; | ||
var isRTL = document.documentElement.getAttribute('dir') == 'rtl'; | ||
this.removeFake(); | ||
this.fakeHandlerCallback = function () { | ||
return _this.removeFake(); | ||
}; | ||
this.fakeHandler = this.container.addEventListener('click', this.fakeHandlerCallback) || true; | ||
this.fakeElem = document.createElement('textarea'); | ||
// Prevent zooming on iOS | ||
this.fakeElem.style.fontSize = '12pt'; | ||
// Reset box model | ||
this.fakeElem.style.border = '0'; | ||
this.fakeElem.style.padding = '0'; | ||
this.fakeElem.style.margin = '0'; | ||
// Move element out of screen horizontally | ||
this.fakeElem.style.position = 'absolute'; | ||
this.fakeElem.style[isRTL ? 'right' : 'left'] = '-9999px'; | ||
// Move element to the same position vertically | ||
var yPosition = window.pageYOffset || document.documentElement.scrollTop; | ||
this.fakeElem.style.top = yPosition + 'px'; | ||
this.fakeElem.setAttribute('readonly', ''); | ||
this.fakeElem.value = this.text; | ||
this.container.appendChild(this.fakeElem); | ||
this.selectedText = select_default()(this.fakeElem); | ||
this.copyText(); | ||
} | ||
/** | ||
* Only removes the fake element after another click event, that way | ||
* a user can hit `Ctrl+C` to copy because selection still exists. | ||
*/ | ||
}, { | ||
key: 'removeFake', | ||
value: function removeFake() { | ||
if (this.fakeHandler) { | ||
this.container.removeEventListener('click', this.fakeHandlerCallback); | ||
this.fakeHandler = null; | ||
this.fakeHandlerCallback = null; | ||
} | ||
if (this.fakeElem) { | ||
this.container.removeChild(this.fakeElem); | ||
this.fakeElem = null; | ||
} | ||
} | ||
/** | ||
* Selects the content from element passed on `target` property. | ||
*/ | ||
}, { | ||
key: 'selectTarget', | ||
value: function selectTarget() { | ||
this.selectedText = select_default()(this.target); | ||
this.copyText(); | ||
} | ||
/** | ||
* Executes the copy operation based on the current selection. | ||
*/ | ||
}, { | ||
key: 'copyText', | ||
value: function copyText() { | ||
var succeeded = void 0; | ||
try { | ||
succeeded = document.execCommand(this.action); | ||
} catch (err) { | ||
succeeded = false; | ||
} | ||
this.handleResult(succeeded); | ||
} | ||
/** | ||
* Fires an event based on the copy operation result. | ||
* @param {Boolean} succeeded | ||
*/ | ||
}, { | ||
key: 'handleResult', | ||
value: function handleResult(succeeded) { | ||
this.emitter.emit(succeeded ? 'success' : 'error', { | ||
action: this.action, | ||
text: this.selectedText, | ||
trigger: this.trigger, | ||
clearSelection: this.clearSelection.bind(this) | ||
return { | ||
destroy: function() { | ||
Array.prototype.forEach.call(nodeList, function(node) { | ||
node.removeEventListener(type, callback); | ||
}); | ||
} | ||
} | ||
} | ||
/** | ||
* Moves focus away from `target` and back to the trigger, removes current selection. | ||
*/ | ||
/** | ||
* Add an event listener to a selector | ||
* and returns a remove listener function. | ||
* | ||
* @param {String} selector | ||
* @param {String} type | ||
* @param {Function} callback | ||
* @return {Object} | ||
*/ | ||
function listenSelector(selector, type, callback) { | ||
return delegate(document.body, selector, type, callback); | ||
} | ||
}, { | ||
key: 'clearSelection', | ||
value: function clearSelection() { | ||
if (this.trigger) { | ||
this.trigger.focus(); | ||
} | ||
document.activeElement.blur(); | ||
window.getSelection().removeAllRanges(); | ||
} | ||
module.exports = listen; | ||
/** | ||
* Sets the `action` to be performed which can be either 'copy' or 'cut'. | ||
* @param {String} action | ||
*/ | ||
}, { | ||
key: 'destroy', | ||
/***/ }), | ||
/***/ 817: | ||
/***/ ((module) => { | ||
/** | ||
* Destroy lifecycle. | ||
*/ | ||
value: function destroy() { | ||
this.removeFake(); | ||
} | ||
}, { | ||
key: 'action', | ||
set: function set() { | ||
var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'copy'; | ||
function select(element) { | ||
var selectedText; | ||
this._action = action; | ||
if (element.nodeName === 'SELECT') { | ||
element.focus(); | ||
if (this._action !== 'copy' && this._action !== 'cut') { | ||
throw new Error('Invalid "action" value, use either "copy" or "cut"'); | ||
} | ||
} | ||
selectedText = element.value; | ||
} | ||
else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') { | ||
var isReadOnly = element.hasAttribute('readonly'); | ||
/** | ||
* Gets the `action` property. | ||
* @return {String} | ||
*/ | ||
, | ||
get: function get() { | ||
return this._action; | ||
if (!isReadOnly) { | ||
element.setAttribute('readonly', ''); | ||
} | ||
/** | ||
* Sets the `target` property using an element | ||
* that will be have its content copied. | ||
* @param {Element} target | ||
*/ | ||
element.select(); | ||
element.setSelectionRange(0, element.value.length); | ||
}, { | ||
key: 'target', | ||
set: function set(target) { | ||
if (target !== undefined) { | ||
if (target && (typeof target === 'undefined' ? 'undefined' : _typeof(target)) === 'object' && target.nodeType === 1) { | ||
if (this.action === 'copy' && target.hasAttribute('disabled')) { | ||
throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute'); | ||
} | ||
if (this.action === 'cut' && (target.hasAttribute('readonly') || target.hasAttribute('disabled'))) { | ||
throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes'); | ||
} | ||
this._target = target; | ||
} else { | ||
throw new Error('Invalid "target" value, use a valid Element'); | ||
} | ||
} | ||
if (!isReadOnly) { | ||
element.removeAttribute('readonly'); | ||
} | ||
/** | ||
* Gets the `target` property. | ||
* @return {String|HTMLElement} | ||
*/ | ||
, | ||
get: function get() { | ||
return this._target; | ||
selectedText = element.value; | ||
} | ||
else { | ||
if (element.hasAttribute('contenteditable')) { | ||
element.focus(); | ||
} | ||
}]); | ||
return ClipboardAction; | ||
}(); | ||
var selection = window.getSelection(); | ||
var range = document.createRange(); | ||
/* harmony default export */ var clipboard_action = (clipboard_action_ClipboardAction); | ||
// EXTERNAL MODULE: ./node_modules/tiny-emitter/index.js | ||
var tiny_emitter = __webpack_require__(1); | ||
var tiny_emitter_default = /*#__PURE__*/__webpack_require__.n(tiny_emitter); | ||
range.selectNodeContents(element); | ||
selection.removeAllRanges(); | ||
selection.addRange(range); | ||
// EXTERNAL MODULE: ./node_modules/good-listener/src/listen.js | ||
var listen = __webpack_require__(2); | ||
var listen_default = /*#__PURE__*/__webpack_require__.n(listen); | ||
selectedText = selection.toString(); | ||
} | ||
// CONCATENATED MODULE: ./src/clipboard.js | ||
var clipboard_typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; | ||
return selectedText; | ||
} | ||
var clipboard_createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); | ||
module.exports = select; | ||
function clipboard_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } | ||
/***/ }), | ||
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
/***/ 279: | ||
/***/ ((module) => { | ||
function E () { | ||
// Keep this empty so it's easier to inherit from | ||
// (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3) | ||
} | ||
E.prototype = { | ||
on: function (name, callback, ctx) { | ||
var e = this.e || (this.e = {}); | ||
(e[name] || (e[name] = [])).push({ | ||
fn: callback, | ||
ctx: ctx | ||
}); | ||
return this; | ||
}, | ||
/** | ||
* Base class which takes one or more elements, adds event listeners to them, | ||
* and instantiates a new `ClipboardAction` on each click. | ||
*/ | ||
once: function (name, callback, ctx) { | ||
var self = this; | ||
function listener () { | ||
self.off(name, listener); | ||
callback.apply(ctx, arguments); | ||
}; | ||
var clipboard_Clipboard = function (_Emitter) { | ||
_inherits(Clipboard, _Emitter); | ||
listener._ = callback | ||
return this.on(name, listener, ctx); | ||
}, | ||
/** | ||
* @param {String|HTMLElement|HTMLCollection|NodeList} trigger | ||
* @param {Object} options | ||
*/ | ||
function Clipboard(trigger, options) { | ||
clipboard_classCallCheck(this, Clipboard); | ||
emit: function (name) { | ||
var data = [].slice.call(arguments, 1); | ||
var evtArr = ((this.e || (this.e = {}))[name] || []).slice(); | ||
var i = 0; | ||
var len = evtArr.length; | ||
var _this = _possibleConstructorReturn(this, (Clipboard.__proto__ || Object.getPrototypeOf(Clipboard)).call(this)); | ||
_this.resolveOptions(options); | ||
_this.listenClick(trigger); | ||
return _this; | ||
for (i; i < len; i++) { | ||
evtArr[i].fn.apply(evtArr[i].ctx, data); | ||
} | ||
/** | ||
* Defines if attributes would be resolved using internal setter functions | ||
* or custom functions that were passed in the constructor. | ||
* @param {Object} options | ||
*/ | ||
return this; | ||
}, | ||
off: function (name, callback) { | ||
var e = this.e || (this.e = {}); | ||
var evts = e[name]; | ||
var liveEvents = []; | ||
clipboard_createClass(Clipboard, [{ | ||
key: 'resolveOptions', | ||
value: function resolveOptions() { | ||
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; | ||
if (evts && callback) { | ||
for (var i = 0, len = evts.length; i < len; i++) { | ||
if (evts[i].fn !== callback && evts[i].fn._ !== callback) | ||
liveEvents.push(evts[i]); | ||
} | ||
} | ||
this.action = typeof options.action === 'function' ? options.action : this.defaultAction; | ||
this.target = typeof options.target === 'function' ? options.target : this.defaultTarget; | ||
this.text = typeof options.text === 'function' ? options.text : this.defaultText; | ||
this.container = clipboard_typeof(options.container) === 'object' ? options.container : document.body; | ||
} | ||
// Remove event from queue to prevent memory leak | ||
// Suggested by https://github.com/lazd | ||
// Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910 | ||
/** | ||
* Adds a click event listener to the passed trigger. | ||
* @param {String|HTMLElement|HTMLCollection|NodeList} trigger | ||
*/ | ||
(liveEvents.length) | ||
? e[name] = liveEvents | ||
: delete e[name]; | ||
}, { | ||
key: 'listenClick', | ||
value: function listenClick(trigger) { | ||
var _this2 = this; | ||
return this; | ||
} | ||
}; | ||
this.listener = listen_default()(trigger, 'click', function (e) { | ||
return _this2.onClick(e); | ||
}); | ||
} | ||
module.exports = E; | ||
module.exports.TinyEmitter = E; | ||
/** | ||
* Defines a new `ClipboardAction` on each click event. | ||
* @param {Event} e | ||
*/ | ||
}, { | ||
key: 'onClick', | ||
value: function onClick(e) { | ||
var trigger = e.delegateTarget || e.currentTarget; | ||
/***/ }) | ||
if (this.clipboardAction) { | ||
this.clipboardAction = null; | ||
} | ||
this.clipboardAction = new clipboard_action({ | ||
action: this.action(trigger), | ||
target: this.target(trigger), | ||
text: this.text(trigger), | ||
container: this.container, | ||
trigger: trigger, | ||
emitter: this | ||
}); | ||
} | ||
/** | ||
* Default `action` lookup function. | ||
* @param {Element} trigger | ||
*/ | ||
}, { | ||
key: 'defaultAction', | ||
value: function defaultAction(trigger) { | ||
return getAttributeValue('action', trigger); | ||
} | ||
/** | ||
* Default `target` lookup function. | ||
* @param {Element} trigger | ||
*/ | ||
}, { | ||
key: 'defaultTarget', | ||
value: function defaultTarget(trigger) { | ||
var selector = getAttributeValue('target', trigger); | ||
if (selector) { | ||
return document.querySelector(selector); | ||
} | ||
} | ||
/** | ||
* Returns the support of the given action, or all actions if no action is | ||
* given. | ||
* @param {String} [action] | ||
*/ | ||
}, { | ||
key: 'defaultText', | ||
/** | ||
* Default `text` lookup function. | ||
* @param {Element} trigger | ||
*/ | ||
value: function defaultText(trigger) { | ||
return getAttributeValue('text', trigger); | ||
} | ||
/** | ||
* Destroy lifecycle. | ||
*/ | ||
}, { | ||
key: 'destroy', | ||
value: function destroy() { | ||
this.listener.destroy(); | ||
if (this.clipboardAction) { | ||
this.clipboardAction.destroy(); | ||
this.clipboardAction = null; | ||
} | ||
} | ||
}], [{ | ||
key: 'isSupported', | ||
value: function isSupported() { | ||
var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ['copy', 'cut']; | ||
var actions = typeof action === 'string' ? [action] : action; | ||
var support = !!document.queryCommandSupported; | ||
actions.forEach(function (action) { | ||
support = support && !!document.queryCommandSupported(action); | ||
}); | ||
return support; | ||
} | ||
}]); | ||
return Clipboard; | ||
}(tiny_emitter_default.a); | ||
/** | ||
* Helper function to retrieve attribute value. | ||
* @param {String} suffix | ||
* @param {Element} element | ||
*/ | ||
function getAttributeValue(suffix, element) { | ||
var attribute = 'data-clipboard-' + suffix; | ||
if (!element.hasAttribute(attribute)) { | ||
return; | ||
} | ||
return element.getAttribute(attribute); | ||
} | ||
/* harmony default export */ var clipboard = __webpack_exports__["default"] = (clipboard_Clipboard); | ||
/***/ }) | ||
/******/ ])["default"]; | ||
/******/ }); | ||
/************************************************************************/ | ||
/******/ // The module cache | ||
/******/ var __webpack_module_cache__ = {}; | ||
/******/ | ||
/******/ // The require function | ||
/******/ function __webpack_require__(moduleId) { | ||
/******/ // Check if module is in cache | ||
/******/ if(__webpack_module_cache__[moduleId]) { | ||
/******/ return __webpack_module_cache__[moduleId].exports; | ||
/******/ } | ||
/******/ // Create a new module (and put it into the cache) | ||
/******/ var module = __webpack_module_cache__[moduleId] = { | ||
/******/ // no module.id needed | ||
/******/ // no module.loaded needed | ||
/******/ exports: {} | ||
/******/ }; | ||
/******/ | ||
/******/ // Execute the module function | ||
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); | ||
/******/ | ||
/******/ // Return the exports of the module | ||
/******/ return module.exports; | ||
/******/ } | ||
/******/ | ||
/************************************************************************/ | ||
/******/ /* webpack/runtime/compat get default export */ | ||
/******/ (() => { | ||
/******/ // getDefaultExport function for compatibility with non-harmony modules | ||
/******/ __webpack_require__.n = (module) => { | ||
/******/ var getter = module && module.__esModule ? | ||
/******/ () => module['default'] : | ||
/******/ () => module; | ||
/******/ __webpack_require__.d(getter, { a: getter }); | ||
/******/ return getter; | ||
/******/ }; | ||
/******/ })(); | ||
/******/ | ||
/******/ /* webpack/runtime/define property getters */ | ||
/******/ (() => { | ||
/******/ // define getter functions for harmony exports | ||
/******/ __webpack_require__.d = (exports, definition) => { | ||
/******/ for(var key in definition) { | ||
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { | ||
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); | ||
/******/ } | ||
/******/ } | ||
/******/ }; | ||
/******/ })(); | ||
/******/ | ||
/******/ /* webpack/runtime/hasOwnProperty shorthand */ | ||
/******/ (() => { | ||
/******/ __webpack_require__.o = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop) | ||
/******/ })(); | ||
/******/ | ||
/************************************************************************/ | ||
/******/ // module exports must be returned from runtime so entry inlining is disabled | ||
/******/ // startup | ||
/******/ // Load entry module and return exports | ||
/******/ return __webpack_require__(134); | ||
/******/ })() | ||
.default; | ||
}); |
/*! | ||
* clipboard.js v2.0.6 | ||
* clipboard.js v2.0.7 | ||
* https://clipboardjs.com/ | ||
* | ||
* | ||
* Licensed MIT © Zeno Rocha | ||
*/ | ||
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return o={},r.m=n=[function(t,e){t.exports=function(t){var e;if("SELECT"===t.nodeName)t.focus(),e=t.value;else if("INPUT"===t.nodeName||"TEXTAREA"===t.nodeName){var n=t.hasAttribute("readonly");n||t.setAttribute("readonly",""),t.select(),t.setSelectionRange(0,t.value.length),n||t.removeAttribute("readonly"),e=t.value}else{t.hasAttribute("contenteditable")&&t.focus();var o=window.getSelection(),r=document.createRange();r.selectNodeContents(t),o.removeAllRanges(),o.addRange(r),e=o.toString()}return e}},function(t,e){function n(){}n.prototype={on:function(t,e,n){var o=this.e||(this.e={});return(o[t]||(o[t]=[])).push({fn:e,ctx:n}),this},once:function(t,e,n){var o=this;function r(){o.off(t,r),e.apply(n,arguments)}return r._=e,this.on(t,r,n)},emit:function(t){for(var e=[].slice.call(arguments,1),n=((this.e||(this.e={}))[t]||[]).slice(),o=0,r=n.length;o<r;o++)n[o].fn.apply(n[o].ctx,e);return this},off:function(t,e){var n=this.e||(this.e={}),o=n[t],r=[];if(o&&e)for(var i=0,a=o.length;i<a;i++)o[i].fn!==e&&o[i].fn._!==e&&r.push(o[i]);return r.length?n[t]=r:delete n[t],this}},t.exports=n,t.exports.TinyEmitter=n},function(t,e,n){var d=n(3),h=n(4);t.exports=function(t,e,n){if(!t&&!e&&!n)throw new Error("Missing required arguments");if(!d.string(e))throw new TypeError("Second argument must be a String");if(!d.fn(n))throw new TypeError("Third argument must be a Function");if(d.node(t))return s=e,f=n,(u=t).addEventListener(s,f),{destroy:function(){u.removeEventListener(s,f)}};if(d.nodeList(t))return a=t,c=e,l=n,Array.prototype.forEach.call(a,function(t){t.addEventListener(c,l)}),{destroy:function(){Array.prototype.forEach.call(a,function(t){t.removeEventListener(c,l)})}};if(d.string(t))return o=t,r=e,i=n,h(document.body,o,r,i);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList");var o,r,i,a,c,l,u,s,f}},function(t,n){n.node=function(t){return void 0!==t&&t instanceof HTMLElement&&1===t.nodeType},n.nodeList=function(t){var e=Object.prototype.toString.call(t);return void 0!==t&&("[object NodeList]"===e||"[object HTMLCollection]"===e)&&"length"in t&&(0===t.length||n.node(t[0]))},n.string=function(t){return"string"==typeof t||t instanceof String},n.fn=function(t){return"[object Function]"===Object.prototype.toString.call(t)}},function(t,e,n){var a=n(5);function i(t,e,n,o,r){var i=function(e,n,t,o){return function(t){t.delegateTarget=a(t.target,n),t.delegateTarget&&o.call(e,t)}}.apply(this,arguments);return t.addEventListener(n,i,r),{destroy:function(){t.removeEventListener(n,i,r)}}}t.exports=function(t,e,n,o,r){return"function"==typeof t.addEventListener?i.apply(null,arguments):"function"==typeof n?i.bind(null,document).apply(null,arguments):("string"==typeof t&&(t=document.querySelectorAll(t)),Array.prototype.map.call(t,function(t){return i(t,e,n,o,r)}))}},function(t,e){if("undefined"!=typeof Element&&!Element.prototype.matches){var n=Element.prototype;n.matches=n.matchesSelector||n.mozMatchesSelector||n.msMatchesSelector||n.oMatchesSelector||n.webkitMatchesSelector}t.exports=function(t,e){for(;t&&9!==t.nodeType;){if("function"==typeof t.matches&&t.matches(e))return t;t=t.parentNode}}},function(t,e,n){"use strict";n.r(e);var o=n(0),r=n.n(o),i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t};function a(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}function c(t){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,c),this.resolveOptions(t),this.initSelection()}var l=(function(t,e,n){return e&&a(t.prototype,e),n&&a(t,n),t}(c,[{key:"resolveOptions",value:function(t){var e=0<arguments.length&&void 0!==t?t:{};this.action=e.action,this.container=e.container,this.emitter=e.emitter,this.target=e.target,this.text=e.text,this.trigger=e.trigger,this.selectedText=""}},{key:"initSelection",value:function(){this.text?this.selectFake():this.target&&this.selectTarget()}},{key:"selectFake",value:function(){var t=this,e="rtl"==document.documentElement.getAttribute("dir");this.removeFake(),this.fakeHandlerCallback=function(){return t.removeFake()},this.fakeHandler=this.container.addEventListener("click",this.fakeHandlerCallback)||!0,this.fakeElem=document.createElement("textarea"),this.fakeElem.style.fontSize="12pt",this.fakeElem.style.border="0",this.fakeElem.style.padding="0",this.fakeElem.style.margin="0",this.fakeElem.style.position="absolute",this.fakeElem.style[e?"right":"left"]="-9999px";var n=window.pageYOffset||document.documentElement.scrollTop;this.fakeElem.style.top=n+"px",this.fakeElem.setAttribute("readonly",""),this.fakeElem.value=this.text,this.container.appendChild(this.fakeElem),this.selectedText=r()(this.fakeElem),this.copyText()}},{key:"removeFake",value:function(){this.fakeHandler&&(this.container.removeEventListener("click",this.fakeHandlerCallback),this.fakeHandler=null,this.fakeHandlerCallback=null),this.fakeElem&&(this.container.removeChild(this.fakeElem),this.fakeElem=null)}},{key:"selectTarget",value:function(){this.selectedText=r()(this.target),this.copyText()}},{key:"copyText",value:function(){var e=void 0;try{e=document.execCommand(this.action)}catch(t){e=!1}this.handleResult(e)}},{key:"handleResult",value:function(t){this.emitter.emit(t?"success":"error",{action:this.action,text:this.selectedText,trigger:this.trigger,clearSelection:this.clearSelection.bind(this)})}},{key:"clearSelection",value:function(){this.trigger&&this.trigger.focus(),document.activeElement.blur(),window.getSelection().removeAllRanges()}},{key:"destroy",value:function(){this.removeFake()}},{key:"action",set:function(t){var e=0<arguments.length&&void 0!==t?t:"copy";if(this._action=e,"copy"!==this._action&&"cut"!==this._action)throw new Error('Invalid "action" value, use either "copy" or "cut"')},get:function(){return this._action}},{key:"target",set:function(t){if(void 0!==t){if(!t||"object"!==(void 0===t?"undefined":i(t))||1!==t.nodeType)throw new Error('Invalid "target" value, use a valid Element');if("copy"===this.action&&t.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if("cut"===this.action&&(t.hasAttribute("readonly")||t.hasAttribute("disabled")))throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes');this._target=t}},get:function(){return this._target}}]),c),u=n(1),s=n.n(u),f=n(2),d=n.n(f),h="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},p=function(t,e,n){return e&&y(t.prototype,e),n&&y(t,n),t};function y(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}var m=(function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}(v,s.a),p(v,[{key:"resolveOptions",value:function(t){var e=0<arguments.length&&void 0!==t?t:{};this.action="function"==typeof e.action?e.action:this.defaultAction,this.target="function"==typeof e.target?e.target:this.defaultTarget,this.text="function"==typeof e.text?e.text:this.defaultText,this.container="object"===h(e.container)?e.container:document.body}},{key:"listenClick",value:function(t){var e=this;this.listener=d()(t,"click",function(t){return e.onClick(t)})}},{key:"onClick",value:function(t){var e=t.delegateTarget||t.currentTarget;this.clipboardAction&&(this.clipboardAction=null),this.clipboardAction=new l({action:this.action(e),target:this.target(e),text:this.text(e),container:this.container,trigger:e,emitter:this})}},{key:"defaultAction",value:function(t){return b("action",t)}},{key:"defaultTarget",value:function(t){var e=b("target",t);if(e)return document.querySelector(e)}},{key:"defaultText",value:function(t){return b("text",t)}},{key:"destroy",value:function(){this.listener.destroy(),this.clipboardAction&&(this.clipboardAction.destroy(),this.clipboardAction=null)}}],[{key:"isSupported",value:function(t){var e=0<arguments.length&&void 0!==t?t:["copy","cut"],n="string"==typeof e?[e]:e,o=!!document.queryCommandSupported;return n.forEach(function(t){o=o&&!!document.queryCommandSupported(t)}),o}}]),v);function v(t,e){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,v);var n=function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}(this,(v.__proto__||Object.getPrototypeOf(v)).call(this));return n.resolveOptions(e),n.listenClick(t),n}function b(t,e){var n="data-clipboard-"+t;if(e.hasAttribute(n))return e.getAttribute(n)}e.default=m}],r.c=o,r.d=function(t,e,n){r.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},r.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(e,"a",e),e},r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r.p="",r(r.s=6).default;function r(t){if(o[t])return o[t].exports;var e=o[t]={i:t,l:!1,exports:{}};return n[t].call(e.exports,e,e.exports,r),e.l=!0,e.exports}var n,o}); | ||
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={134:(t,e,n)=>{"use strict";n.d(e,{default:()=>r});var e=n(279),i=n.n(e),e=n(370),a=n.n(e),e=n(817),o=n.n(e);function c(t){return(c="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function l(t,e){for(var n=0;n<e.length;n++){var r=e[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(t,r.key,r)}}const u=function(){function e(t){!function(t){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this),this.resolveOptions(t),this.initSelection()}var t,n,r;return t=e,(n=[{key:"resolveOptions",value:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};this.action=t.action,this.container=t.container,this.emitter=t.emitter,this.target=t.target,this.text=t.text,this.trigger=t.trigger,this.selectedText=""}},{key:"initSelection",value:function(){this.text?this.selectFake():this.target&&this.selectTarget()}},{key:"createFakeElement",value:function(){var t="rtl"===document.documentElement.getAttribute("dir");this.fakeElem=document.createElement("textarea"),this.fakeElem.style.fontSize="12pt",this.fakeElem.style.border="0",this.fakeElem.style.padding="0",this.fakeElem.style.margin="0",this.fakeElem.style.position="absolute",this.fakeElem.style[t?"right":"left"]="-9999px";t=window.pageYOffset||document.documentElement.scrollTop;return this.fakeElem.style.top="".concat(t,"px"),this.fakeElem.setAttribute("readonly",""),this.fakeElem.value=this.text,this.fakeElem}},{key:"selectFake",value:function(){var t=this,e=this.createFakeElement();this.fakeHandlerCallback=function(){return t.removeFake()},this.fakeHandler=this.container.addEventListener("click",this.fakeHandlerCallback)||!0,this.container.appendChild(e),this.selectedText=o()(e),this.copyText(),this.removeFake()}},{key:"removeFake",value:function(){this.fakeHandler&&(this.container.removeEventListener("click",this.fakeHandlerCallback),this.fakeHandler=null,this.fakeHandlerCallback=null),this.fakeElem&&(this.container.removeChild(this.fakeElem),this.fakeElem=null)}},{key:"selectTarget",value:function(){this.selectedText=o()(this.target),this.copyText()}},{key:"copyText",value:function(){var e;try{e=document.execCommand(this.action)}catch(t){e=!1}this.handleResult(e)}},{key:"handleResult",value:function(t){this.emitter.emit(t?"success":"error",{action:this.action,text:this.selectedText,trigger:this.trigger,clearSelection:this.clearSelection.bind(this)})}},{key:"clearSelection",value:function(){this.trigger&&this.trigger.focus(),document.activeElement.blur(),window.getSelection().removeAllRanges()}},{key:"destroy",value:function(){this.removeFake()}},{key:"action",set:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:"copy";if(this._action=t,"copy"!==this._action&&"cut"!==this._action)throw new Error('Invalid "action" value, use either "copy" or "cut"')},get:function(){return this._action}},{key:"target",set:function(t){if(void 0!==t){if(!t||"object"!==c(t)||1!==t.nodeType)throw new Error('Invalid "target" value, use a valid Element');if("copy"===this.action&&t.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if("cut"===this.action&&(t.hasAttribute("readonly")||t.hasAttribute("disabled")))throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes');this._target=t}},get:function(){return this._target}}])&&l(t.prototype,n),r&&l(t,r),e}();function s(t){return(s="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function f(t,e){for(var n=0;n<e.length;n++){var r=e[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(t,r.key,r)}}function h(t,e){return(h=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function d(n){var r=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],function(){})),!0}catch(t){return!1}}();return function(){var t,e=p(n);return t=r?(t=p(this).constructor,Reflect.construct(e,arguments,t)):e.apply(this,arguments),e=this,!(t=t)||"object"!==s(t)&&"function"!=typeof t?function(t){if(void 0!==t)return t;throw new ReferenceError("this hasn't been initialised - super() hasn't been called")}(e):t}}function p(t){return(p=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function y(t,e){t="data-clipboard-".concat(t);if(e.hasAttribute(t))return e.getAttribute(t)}const r=function(){!function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),e&&h(t,e)}(o,i());var t,e,n,r=d(o);function o(t,e){var n;return function(t){if(!(t instanceof o))throw new TypeError("Cannot call a class as a function")}(this),(n=r.call(this)).resolveOptions(e),n.listenClick(t),n}return t=o,n=[{key:"isSupported",value:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:["copy","cut"],t="string"==typeof t?[t]:t,e=!!document.queryCommandSupported;return t.forEach(function(t){e=e&&!!document.queryCommandSupported(t)}),e}}],(e=[{key:"resolveOptions",value:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};this.action="function"==typeof t.action?t.action:this.defaultAction,this.target="function"==typeof t.target?t.target:this.defaultTarget,this.text="function"==typeof t.text?t.text:this.defaultText,this.container="object"===s(t.container)?t.container:document.body}},{key:"listenClick",value:function(t){var e=this;this.listener=a()(t,"click",function(t){return e.onClick(t)})}},{key:"onClick",value:function(t){t=t.delegateTarget||t.currentTarget;this.clipboardAction&&(this.clipboardAction=null),this.clipboardAction=new u({action:this.action(t),target:this.target(t),text:this.text(t),container:this.container,trigger:t,emitter:this})}},{key:"defaultAction",value:function(t){return y("action",t)}},{key:"defaultTarget",value:function(t){t=y("target",t);if(t)return document.querySelector(t)}},{key:"defaultText",value:function(t){return y("text",t)}},{key:"destroy",value:function(){this.listener.destroy(),this.clipboardAction&&(this.clipboardAction.destroy(),this.clipboardAction=null)}}])&&f(t.prototype,e),n&&f(t,n),o}()},828:t=>{var e;"undefined"==typeof Element||Element.prototype.matches||((e=Element.prototype).matches=e.matchesSelector||e.mozMatchesSelector||e.msMatchesSelector||e.oMatchesSelector||e.webkitMatchesSelector),t.exports=function(t,e){for(;t&&9!==t.nodeType;){if("function"==typeof t.matches&&t.matches(e))return t;t=t.parentNode}}},438:(t,e,n)=>{var a=n(828);function i(t,e,n,r,o){var i=function(e,n,t,r){return function(t){t.delegateTarget=a(t.target,n),t.delegateTarget&&r.call(e,t)}}.apply(this,arguments);return t.addEventListener(n,i,o),{destroy:function(){t.removeEventListener(n,i,o)}}}t.exports=function(t,e,n,r,o){return"function"==typeof t.addEventListener?i.apply(null,arguments):"function"==typeof n?i.bind(null,document).apply(null,arguments):("string"==typeof t&&(t=document.querySelectorAll(t)),Array.prototype.map.call(t,function(t){return i(t,e,n,r,o)}))}},879:(t,n)=>{n.node=function(t){return void 0!==t&&t instanceof HTMLElement&&1===t.nodeType},n.nodeList=function(t){var e=Object.prototype.toString.call(t);return void 0!==t&&("[object NodeList]"===e||"[object HTMLCollection]"===e)&&"length"in t&&(0===t.length||n.node(t[0]))},n.string=function(t){return"string"==typeof t||t instanceof String},n.fn=function(t){return"[object Function]"===Object.prototype.toString.call(t)}},370:(t,e,n)=>{var u=n(879),s=n(438);t.exports=function(t,e,n){if(!t&&!e&&!n)throw new Error("Missing required arguments");if(!u.string(e))throw new TypeError("Second argument must be a String");if(!u.fn(n))throw new TypeError("Third argument must be a Function");if(u.node(t))return c=e,l=n,(a=t).addEventListener(c,l),{destroy:function(){a.removeEventListener(c,l)}};if(u.nodeList(t))return r=t,o=e,i=n,Array.prototype.forEach.call(r,function(t){t.addEventListener(o,i)}),{destroy:function(){Array.prototype.forEach.call(r,function(t){t.removeEventListener(o,i)})}};if(u.string(t))return t=t,e=e,n=n,s(document.body,t,e,n);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList");var r,o,i,a,c,l}},817:t=>{t.exports=function(t){var e,n="SELECT"===t.nodeName?(t.focus(),t.value):"INPUT"===t.nodeName||"TEXTAREA"===t.nodeName?((e=t.hasAttribute("readonly"))||t.setAttribute("readonly",""),t.select(),t.setSelectionRange(0,t.value.length),e||t.removeAttribute("readonly"),t.value):(t.hasAttribute("contenteditable")&&t.focus(),n=window.getSelection(),(e=document.createRange()).selectNodeContents(t),n.removeAllRanges(),n.addRange(e),n.toString());return n}},279:t=>{function e(){}e.prototype={on:function(t,e,n){var r=this.e||(this.e={});return(r[t]||(r[t]=[])).push({fn:e,ctx:n}),this},once:function(t,e,n){var r=this;function o(){r.off(t,o),e.apply(n,arguments)}return o._=e,this.on(t,o,n)},emit:function(t){for(var e=[].slice.call(arguments,1),n=((this.e||(this.e={}))[t]||[]).slice(),r=0,o=n.length;r<o;r++)n[r].fn.apply(n[r].ctx,e);return this},off:function(t,e){var n=this.e||(this.e={}),r=n[t],o=[];if(r&&e)for(var i=0,a=r.length;i<a;i++)r[i].fn!==e&&r[i].fn._!==e&&o.push(r[i]);return o.length?n[t]=o:delete n[t],this}},t.exports=e,t.exports.TinyEmitter=e}},o={},r.n=t=>{var e=t&&t.__esModule?()=>t.default:()=>t;return r.d(e,{a:e}),e},r.d=(t,e)=>{for(var n in e)r.o(e,n)&&!r.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:e[n]})},r.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r(134).default;function r(t){if(o[t])return o[t].exports;var e=o[t]={exports:{}};return n[t](e,e.exports,r),e.exports}var n,o}); |
var webpackConfig = require('./webpack.config.js'); | ||
module.exports = function (karma) { | ||
karma.set({ | ||
plugins: ['karma-webpack', 'karma-chai', 'karma-sinon', 'karma-mocha', 'karma-chrome-launcher'], | ||
karma.set({ | ||
plugins: [ | ||
'karma-webpack', | ||
'karma-chai', | ||
'karma-sinon', | ||
'karma-mocha', | ||
'karma-chrome-launcher', | ||
], | ||
frameworks: ['chai', 'sinon', 'mocha'], | ||
frameworks: ['chai', 'sinon', 'mocha', 'webpack'], | ||
files: [ | ||
'src/**/*.js', | ||
'test/**/*.js', | ||
], | ||
files: [ | ||
{ pattern: 'src/**/*.js', watched: false }, | ||
{ pattern: 'test/**/*.js', watched: false }, | ||
], | ||
preprocessors: { | ||
'src/**/*.js': ['webpack'], | ||
'test/**/*.js': ['webpack'] | ||
}, | ||
preprocessors: { | ||
'src/**/*.js': ['webpack'], | ||
'test/**/*.js': ['webpack'], | ||
}, | ||
webpack: { | ||
module: webpackConfig.module, | ||
plugins: webpackConfig.plugins | ||
}, | ||
webpack: { | ||
module: webpackConfig.module, | ||
plugins: webpackConfig.plugins, | ||
}, | ||
webpackMiddleware: { | ||
stats: 'errors-only' | ||
}, | ||
webpackMiddleware: { | ||
stats: 'errors-only', | ||
}, | ||
browsers: ['ChromeHeadless'] | ||
}); | ||
browsers: ['ChromeHeadless'], | ||
}); | ||
}; |
// Package metadata for Meteor.js. | ||
Package.describe({ | ||
name: "zenorocha:clipboard", | ||
summary: "Modern copy to clipboard. No Flash. Just 3kb.", | ||
version: "2.0.6", | ||
git: "https://github.com/zenorocha/clipboard.js" | ||
name: 'zenorocha:clipboard', | ||
summary: 'Modern copy to clipboard. No Flash. Just 3kb.', | ||
version: '2.0.6', | ||
git: 'https://github.com/zenorocha/clipboard.js', | ||
}); | ||
Package.onUse(function(api) { | ||
api.addFiles("dist/clipboard.js", "client"); | ||
Package.onUse(function (api) { | ||
api.addFiles('dist/clipboard.js', 'client'); | ||
}); |
{ | ||
"name": "clipboard", | ||
"version": "2.0.6", | ||
"version": "2.0.7", | ||
"description": "Modern copy to clipboard. No Flash. Just 2kb", | ||
"homepage": "https://clipboardjs.com", | ||
"repository": "zenorocha/clipboard.js", | ||
"license": "MIT", | ||
"main": "dist/clipboard.js", | ||
"types": "src/clipboard.d.ts", | ||
"keywords": [ | ||
@@ -19,20 +21,30 @@ "clipboard", | ||
"devDependencies": { | ||
"babel-core": "^6.26.0", | ||
"babel-loader": "^7.1.4", | ||
"babel-preset-env": "^1.7.0", | ||
"@babel/core": "^7.12.10", | ||
"@babel/preset-env": "^7.12.11", | ||
"babel-loader": "^8.2.2", | ||
"chai": "^4.2.0", | ||
"cross-env": "^5.2.0", | ||
"karma": "^3.1.1", | ||
"cross-env": "^7.0.3", | ||
"eslint": "^7.20.0", | ||
"eslint-config-airbnb-base": "^14.2.1", | ||
"eslint-config-prettier": "^7.2.0", | ||
"eslint-plugin-import": "^2.22.1", | ||
"eslint-plugin-prettier": "^3.3.1", | ||
"husky": "^5.0.9", | ||
"karma": "^6.0.0", | ||
"karma-chai": "^0.1.0", | ||
"karma-mocha": "^1.2.0", | ||
"karma-chrome-launcher": "^2.2.0", | ||
"karma-chrome-launcher": "^3.1.0", | ||
"karma-mocha": "^2.0.1", | ||
"karma-sinon": "^1.0.4", | ||
"karma-webpack": "^3.0.5", | ||
"mocha": "^5.2.0", | ||
"sinon": "^7.1.1", | ||
"uglifyjs-webpack-plugin": "^2.0.1", | ||
"webpack": "^4.5.0", | ||
"webpack-cli": "^3.1.2" | ||
"karma-webpack": "^5.0.0-alpha.5", | ||
"lint-staged": "^10.5.3", | ||
"mocha": "^8.2.1", | ||
"prettier": "2.2.1", | ||
"sinon": "^9.2.3", | ||
"tsd": "^0.7.2", | ||
"uglifyjs-webpack-plugin": "^2.2.0", | ||
"webpack": "^5.15.0", | ||
"webpack-cli": "^4.4.0" | ||
}, | ||
"scripts": { | ||
"test:types": "tsd", | ||
"build": "npm run build-debug && npm run build-min", | ||
@@ -43,4 +55,11 @@ "build-debug": "webpack", | ||
"test": "karma start --single-run", | ||
"prepublish": "npm run build" | ||
"prepublish": "npm run build", | ||
"lint": "eslint --ext .js src/" | ||
}, | ||
"lint-staged": { | ||
"*.{js,css,md}": [ | ||
"prettier --write", | ||
"eslint --fix" | ||
] | ||
} | ||
} |
# clipboard.js | ||
[![Build Status](http://img.shields.io/travis/zenorocha/clipboard.js/master.svg?style=flat)](https://travis-ci.org/zenorocha/clipboard.js) | ||
![Build Status](https://github.com/zenorocha/clipboard.js/workflows/build/badge.svg) | ||
![Killing Flash](https://img.shields.io/badge/killing-flash-brightgreen.svg?style=flat) | ||
@@ -58,7 +58,7 @@ | ||
<!-- Target --> | ||
<input id="foo" value="https://github.com/zenorocha/clipboard.js.git"> | ||
<input id="foo" value="https://github.com/zenorocha/clipboard.js.git" /> | ||
<!-- Trigger --> | ||
<button class="btn" data-clipboard-target="#foo"> | ||
<img src="assets/clippy.svg" alt="Copy to clipboard"> | ||
<img src="assets/clippy.svg" alt="Copy to clipboard" /> | ||
</button> | ||
@@ -81,3 +81,3 @@ ``` | ||
<button class="btn" data-clipboard-action="cut" data-clipboard-target="#bar"> | ||
Cut to clipboard | ||
Cut to clipboard | ||
</button> | ||
@@ -96,4 +96,7 @@ ``` | ||
<!-- Trigger --> | ||
<button class="btn" data-clipboard-text="Just because you can doesn't mean you should — clipboard.js"> | ||
Copy to clipboard | ||
<button | ||
class="btn" | ||
data-clipboard-text="Just because you can doesn't mean you should — clipboard.js" | ||
> | ||
Copy to clipboard | ||
</button> | ||
@@ -111,13 +114,13 @@ ``` | ||
clipboard.on('success', function(e) { | ||
console.info('Action:', e.action); | ||
console.info('Text:', e.text); | ||
console.info('Trigger:', e.trigger); | ||
clipboard.on('success', function (e) { | ||
console.info('Action:', e.action); | ||
console.info('Text:', e.text); | ||
console.info('Trigger:', e.trigger); | ||
e.clearSelection(); | ||
e.clearSelection(); | ||
}); | ||
clipboard.on('error', function(e) { | ||
console.error('Action:', e.action); | ||
console.error('Trigger:', e.trigger); | ||
clipboard.on('error', function (e) { | ||
console.error('Action:', e.action); | ||
console.error('Trigger:', e.trigger); | ||
}); | ||
@@ -142,5 +145,5 @@ ``` | ||
new ClipboardJS('.btn', { | ||
target: function(trigger) { | ||
return trigger.nextElementSibling; | ||
} | ||
target: function (trigger) { | ||
return trigger.nextElementSibling; | ||
}, | ||
}); | ||
@@ -153,5 +156,5 @@ ``` | ||
new ClipboardJS('.btn', { | ||
text: function(trigger) { | ||
return trigger.getAttribute('aria-label'); | ||
} | ||
text: function (trigger) { | ||
return trigger.getAttribute('aria-label'); | ||
}, | ||
}); | ||
@@ -164,3 +167,3 @@ ``` | ||
new ClipboardJS('.btn', { | ||
container: document.getElementById('modal') | ||
container: document.getElementById('modal'), | ||
}); | ||
@@ -181,4 +184,4 @@ ``` | ||
| <img src="https://clipboardjs.com/assets/images/chrome.png" width="48px" height="48px" alt="Chrome logo"> | <img src="https://clipboardjs.com/assets/images/edge.png" width="48px" height="48px" alt="Edge logo"> | <img src="https://clipboardjs.com/assets/images/firefox.png" width="48px" height="48px" alt="Firefox logo"> | <img src="https://clipboardjs.com/assets/images/ie.png" width="48px" height="48px" alt="Internet Explorer logo"> | <img src="https://clipboardjs.com/assets/images/opera.png" width="48px" height="48px" alt="Opera logo"> | <img src="https://clipboardjs.com/assets/images/safari.png" width="48px" height="48px" alt="Safari logo"> | | ||
|:---:|:---:|:---:|:---:|:---:|:---:| | ||
| 42+ ✔ | 12+ ✔ | 41+ ✔ | 9+ ✔ | 29+ ✔ | 10+ ✔ | | ||
| :-------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------: | | ||
| 42+ ✔ | 12+ ✔ | 41+ ✔ | 9+ ✔ | 29+ ✔ | 10+ ✔ | | ||
@@ -191,3 +194,3 @@ The good news is that clipboard.js gracefully degrades if you need to support older browsers. All you have to do is show a tooltip saying `Copied!` when `success` event is called and `Press Ctrl+C to copy` when `error` event is called because the text is already selected. | ||
A browser extension that adds a "copy to clipboard" button to every code block on *GitHub, MDN, Gist, StackOverflow, StackExchange, npm, and even Medium.* | ||
A browser extension that adds a "copy to clipboard" button to every code block on _GitHub, MDN, Gist, StackOverflow, StackExchange, npm, and even Medium._ | ||
@@ -194,0 +197,0 @@ Install for [Chrome](https://chrome.google.com/webstore/detail/codecopy/fkbfebkcoelajmhanocgppanfoojcdmg) and [Firefox](https://addons.mozilla.org/en-US/firefox/addon/codecopy/). |
@@ -8,198 +8,215 @@ import select from 'select'; | ||
class ClipboardAction { | ||
/** | ||
* @param {Object} options | ||
*/ | ||
constructor(options) { | ||
this.resolveOptions(options); | ||
this.initSelection(); | ||
} | ||
/** | ||
* @param {Object} options | ||
*/ | ||
constructor(options) { | ||
this.resolveOptions(options); | ||
this.initSelection(); | ||
} | ||
/** | ||
* Defines base properties passed from constructor. | ||
* @param {Object} options | ||
*/ | ||
resolveOptions(options = {}) { | ||
this.action = options.action; | ||
this.container = options.container; | ||
this.emitter = options.emitter; | ||
this.target = options.target; | ||
this.text = options.text; | ||
this.trigger = options.trigger; | ||
/** | ||
* Defines base properties passed from constructor. | ||
* @param {Object} options | ||
*/ | ||
resolveOptions(options = {}) { | ||
this.action = options.action; | ||
this.container = options.container; | ||
this.emitter = options.emitter; | ||
this.target = options.target; | ||
this.text = options.text; | ||
this.trigger = options.trigger; | ||
this.selectedText = ''; | ||
} | ||
this.selectedText = ''; | ||
} | ||
/** | ||
* Decides which selection strategy is going to be applied based | ||
* on the existence of `text` and `target` properties. | ||
*/ | ||
initSelection() { | ||
if (this.text) { | ||
this.selectFake(); | ||
} | ||
else if (this.target) { | ||
this.selectTarget(); | ||
} | ||
/** | ||
* Decides which selection strategy is going to be applied based | ||
* on the existence of `text` and `target` properties. | ||
*/ | ||
initSelection() { | ||
if (this.text) { | ||
this.selectFake(); | ||
} else if (this.target) { | ||
this.selectTarget(); | ||
} | ||
} | ||
/** | ||
* Creates a fake textarea element, sets its value from `text` property, | ||
* and makes a selection on it. | ||
*/ | ||
selectFake() { | ||
const isRTL = document.documentElement.getAttribute('dir') == 'rtl'; | ||
/** | ||
* Creates a fake textarea element, sets its value from `text` property, | ||
*/ | ||
createFakeElement() { | ||
const isRTL = document.documentElement.getAttribute('dir') === 'rtl'; | ||
this.removeFake(); | ||
this.fakeElem = document.createElement('textarea'); | ||
// Prevent zooming on iOS | ||
this.fakeElem.style.fontSize = '12pt'; | ||
// Reset box model | ||
this.fakeElem.style.border = '0'; | ||
this.fakeElem.style.padding = '0'; | ||
this.fakeElem.style.margin = '0'; | ||
// Move element out of screen horizontally | ||
this.fakeElem.style.position = 'absolute'; | ||
this.fakeElem.style[isRTL ? 'right' : 'left'] = '-9999px'; | ||
// Move element to the same position vertically | ||
let yPosition = window.pageYOffset || document.documentElement.scrollTop; | ||
this.fakeElem.style.top = `${yPosition}px`; | ||
this.fakeHandlerCallback = () => this.removeFake(); | ||
this.fakeHandler = this.container.addEventListener('click', this.fakeHandlerCallback) || true; | ||
this.fakeElem.setAttribute('readonly', ''); | ||
this.fakeElem.value = this.text; | ||
this.fakeElem = document.createElement('textarea'); | ||
// Prevent zooming on iOS | ||
this.fakeElem.style.fontSize = '12pt'; | ||
// Reset box model | ||
this.fakeElem.style.border = '0'; | ||
this.fakeElem.style.padding = '0'; | ||
this.fakeElem.style.margin = '0'; | ||
// Move element out of screen horizontally | ||
this.fakeElem.style.position = 'absolute'; | ||
this.fakeElem.style[ isRTL ? 'right' : 'left' ] = '-9999px'; | ||
// Move element to the same position vertically | ||
let yPosition = window.pageYOffset || document.documentElement.scrollTop; | ||
this.fakeElem.style.top = `${yPosition}px`; | ||
return this.fakeElem; | ||
} | ||
this.fakeElem.setAttribute('readonly', ''); | ||
this.fakeElem.value = this.text; | ||
/** | ||
* Get's the value of fakeElem, | ||
* and makes a selection on it. | ||
*/ | ||
selectFake() { | ||
const fakeElem = this.createFakeElement(); | ||
this.container.appendChild(this.fakeElem); | ||
this.fakeHandlerCallback = () => this.removeFake(); | ||
this.selectedText = select(this.fakeElem); | ||
this.copyText(); | ||
} | ||
this.fakeHandler = | ||
this.container.addEventListener('click', this.fakeHandlerCallback) || | ||
true; | ||
/** | ||
* Only removes the fake element after another click event, that way | ||
* a user can hit `Ctrl+C` to copy because selection still exists. | ||
*/ | ||
removeFake() { | ||
if (this.fakeHandler) { | ||
this.container.removeEventListener('click', this.fakeHandlerCallback); | ||
this.fakeHandler = null; | ||
this.fakeHandlerCallback = null; | ||
} | ||
this.container.appendChild(fakeElem); | ||
if (this.fakeElem) { | ||
this.container.removeChild(this.fakeElem); | ||
this.fakeElem = null; | ||
} | ||
this.selectedText = select(fakeElem); | ||
this.copyText(); | ||
this.removeFake(); | ||
} | ||
/** | ||
* Only removes the fake element after another click event, that way | ||
* a user can hit `Ctrl+C` to copy because selection still exists. | ||
*/ | ||
removeFake() { | ||
if (this.fakeHandler) { | ||
this.container.removeEventListener('click', this.fakeHandlerCallback); | ||
this.fakeHandler = null; | ||
this.fakeHandlerCallback = null; | ||
} | ||
/** | ||
* Selects the content from element passed on `target` property. | ||
*/ | ||
selectTarget() { | ||
this.selectedText = select(this.target); | ||
this.copyText(); | ||
if (this.fakeElem) { | ||
this.container.removeChild(this.fakeElem); | ||
this.fakeElem = null; | ||
} | ||
} | ||
/** | ||
* Executes the copy operation based on the current selection. | ||
*/ | ||
copyText() { | ||
let succeeded; | ||
/** | ||
* Selects the content from element passed on `target` property. | ||
*/ | ||
selectTarget() { | ||
this.selectedText = select(this.target); | ||
this.copyText(); | ||
} | ||
try { | ||
succeeded = document.execCommand(this.action); | ||
} | ||
catch (err) { | ||
succeeded = false; | ||
} | ||
/** | ||
* Executes the copy operation based on the current selection. | ||
*/ | ||
copyText() { | ||
let succeeded; | ||
this.handleResult(succeeded); | ||
try { | ||
succeeded = document.execCommand(this.action); | ||
} catch (err) { | ||
succeeded = false; | ||
} | ||
/** | ||
* Fires an event based on the copy operation result. | ||
* @param {Boolean} succeeded | ||
*/ | ||
handleResult(succeeded) { | ||
this.emitter.emit(succeeded ? 'success' : 'error', { | ||
action: this.action, | ||
text: this.selectedText, | ||
trigger: this.trigger, | ||
clearSelection: this.clearSelection.bind(this) | ||
}); | ||
} | ||
this.handleResult(succeeded); | ||
} | ||
/** | ||
* Moves focus away from `target` and back to the trigger, removes current selection. | ||
*/ | ||
clearSelection() { | ||
if (this.trigger) { | ||
this.trigger.focus(); | ||
} | ||
document.activeElement.blur(); | ||
window.getSelection().removeAllRanges(); | ||
/** | ||
* Fires an event based on the copy operation result. | ||
* @param {Boolean} succeeded | ||
*/ | ||
handleResult(succeeded) { | ||
this.emitter.emit(succeeded ? 'success' : 'error', { | ||
action: this.action, | ||
text: this.selectedText, | ||
trigger: this.trigger, | ||
clearSelection: this.clearSelection.bind(this), | ||
}); | ||
} | ||
/** | ||
* Moves focus away from `target` and back to the trigger, removes current selection. | ||
*/ | ||
clearSelection() { | ||
if (this.trigger) { | ||
this.trigger.focus(); | ||
} | ||
document.activeElement.blur(); | ||
window.getSelection().removeAllRanges(); | ||
} | ||
/** | ||
* Sets the `action` to be performed which can be either 'copy' or 'cut'. | ||
* @param {String} action | ||
*/ | ||
set action(action = 'copy') { | ||
this._action = action; | ||
/** | ||
* Sets the `action` to be performed which can be either 'copy' or 'cut'. | ||
* @param {String} action | ||
*/ | ||
set action(action = 'copy') { | ||
this._action = action; | ||
if (this._action !== 'copy' && this._action !== 'cut') { | ||
throw new Error('Invalid "action" value, use either "copy" or "cut"'); | ||
} | ||
if (this._action !== 'copy' && this._action !== 'cut') { | ||
throw new Error('Invalid "action" value, use either "copy" or "cut"'); | ||
} | ||
} | ||
/** | ||
* Gets the `action` property. | ||
* @return {String} | ||
*/ | ||
get action() { | ||
return this._action; | ||
} | ||
/** | ||
* Gets the `action` property. | ||
* @return {String} | ||
*/ | ||
get action() { | ||
return this._action; | ||
} | ||
/** | ||
* Sets the `target` property using an element | ||
* that will be have its content copied. | ||
* @param {Element} target | ||
*/ | ||
set target(target) { | ||
if (target !== undefined) { | ||
if (target && typeof target === 'object' && target.nodeType === 1) { | ||
if (this.action === 'copy' && target.hasAttribute('disabled')) { | ||
throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute'); | ||
} | ||
/** | ||
* Sets the `target` property using an element | ||
* that will be have its content copied. | ||
* @param {Element} target | ||
*/ | ||
set target(target) { | ||
if (target !== undefined) { | ||
if (target && typeof target === 'object' && target.nodeType === 1) { | ||
if (this.action === 'copy' && target.hasAttribute('disabled')) { | ||
throw new Error( | ||
'Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute' | ||
); | ||
} | ||
if (this.action === 'cut' && (target.hasAttribute('readonly') || target.hasAttribute('disabled'))) { | ||
throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes'); | ||
} | ||
this._target = target; | ||
} | ||
else { | ||
throw new Error('Invalid "target" value, use a valid Element'); | ||
} | ||
if ( | ||
this.action === 'cut' && | ||
(target.hasAttribute('readonly') || target.hasAttribute('disabled')) | ||
) { | ||
throw new Error( | ||
'Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes' | ||
); | ||
} | ||
} | ||
/** | ||
* Gets the `target` property. | ||
* @return {String|HTMLElement} | ||
*/ | ||
get target() { | ||
return this._target; | ||
this._target = target; | ||
} else { | ||
throw new Error('Invalid "target" value, use a valid Element'); | ||
} | ||
} | ||
} | ||
/** | ||
* Destroy lifecycle. | ||
*/ | ||
destroy() { | ||
this.removeFake(); | ||
} | ||
/** | ||
* Gets the `target` property. | ||
* @return {String|HTMLElement} | ||
*/ | ||
get target() { | ||
return this._target; | ||
} | ||
/** | ||
* Destroy lifecycle. | ||
*/ | ||
destroy() { | ||
this.removeFake(); | ||
} | ||
} | ||
export default ClipboardAction; |
@@ -1,6 +0,21 @@ | ||
import ClipboardAction from './clipboard-action'; | ||
import Emitter from 'tiny-emitter'; | ||
import listen from 'good-listener'; | ||
import ClipboardAction from './clipboard-action'; | ||
/** | ||
* Helper function to retrieve attribute value. | ||
* @param {String} suffix | ||
* @param {Element} element | ||
*/ | ||
function getAttributeValue(suffix, element) { | ||
const attribute = `data-clipboard-${suffix}`; | ||
if (!element.hasAttribute(attribute)) { | ||
return; | ||
} | ||
return element.getAttribute(attribute); | ||
} | ||
/** | ||
* Base class which takes one or more elements, adds event listeners to them, | ||
@@ -10,127 +25,119 @@ * and instantiates a new `ClipboardAction` on each click. | ||
class Clipboard extends Emitter { | ||
/** | ||
* @param {String|HTMLElement|HTMLCollection|NodeList} trigger | ||
* @param {Object} options | ||
*/ | ||
constructor(trigger, options) { | ||
super(); | ||
/** | ||
* @param {String|HTMLElement|HTMLCollection|NodeList} trigger | ||
* @param {Object} options | ||
*/ | ||
constructor(trigger, options) { | ||
super(); | ||
this.resolveOptions(options); | ||
this.listenClick(trigger); | ||
} | ||
this.resolveOptions(options); | ||
this.listenClick(trigger); | ||
} | ||
/** | ||
* Defines if attributes would be resolved using internal setter functions | ||
* or custom functions that were passed in the constructor. | ||
* @param {Object} options | ||
*/ | ||
resolveOptions(options = {}) { | ||
this.action = (typeof options.action === 'function') ? options.action : this.defaultAction; | ||
this.target = (typeof options.target === 'function') ? options.target : this.defaultTarget; | ||
this.text = (typeof options.text === 'function') ? options.text : this.defaultText; | ||
this.container = (typeof options.container === 'object') ? options.container : document.body; | ||
} | ||
/** | ||
* Defines if attributes would be resolved using internal setter functions | ||
* or custom functions that were passed in the constructor. | ||
* @param {Object} options | ||
*/ | ||
resolveOptions(options = {}) { | ||
this.action = | ||
typeof options.action === 'function' | ||
? options.action | ||
: this.defaultAction; | ||
this.target = | ||
typeof options.target === 'function' | ||
? options.target | ||
: this.defaultTarget; | ||
this.text = | ||
typeof options.text === 'function' ? options.text : this.defaultText; | ||
this.container = | ||
typeof options.container === 'object' ? options.container : document.body; | ||
} | ||
/** | ||
* Adds a click event listener to the passed trigger. | ||
* @param {String|HTMLElement|HTMLCollection|NodeList} trigger | ||
*/ | ||
listenClick(trigger) { | ||
this.listener = listen(trigger, 'click', (e) => this.onClick(e)); | ||
} | ||
/** | ||
* Adds a click event listener to the passed trigger. | ||
* @param {String|HTMLElement|HTMLCollection|NodeList} trigger | ||
*/ | ||
listenClick(trigger) { | ||
this.listener = listen(trigger, 'click', (e) => this.onClick(e)); | ||
} | ||
/** | ||
* Defines a new `ClipboardAction` on each click event. | ||
* @param {Event} e | ||
*/ | ||
onClick(e) { | ||
const trigger = e.delegateTarget || e.currentTarget; | ||
/** | ||
* Defines a new `ClipboardAction` on each click event. | ||
* @param {Event} e | ||
*/ | ||
onClick(e) { | ||
const trigger = e.delegateTarget || e.currentTarget; | ||
if (this.clipboardAction) { | ||
this.clipboardAction = null; | ||
} | ||
this.clipboardAction = new ClipboardAction({ | ||
action : this.action(trigger), | ||
target : this.target(trigger), | ||
text : this.text(trigger), | ||
container : this.container, | ||
trigger : trigger, | ||
emitter : this | ||
}); | ||
if (this.clipboardAction) { | ||
this.clipboardAction = null; | ||
} | ||
/** | ||
* Default `action` lookup function. | ||
* @param {Element} trigger | ||
*/ | ||
defaultAction(trigger) { | ||
return getAttributeValue('action', trigger); | ||
} | ||
this.clipboardAction = new ClipboardAction({ | ||
action: this.action(trigger), | ||
target: this.target(trigger), | ||
text: this.text(trigger), | ||
container: this.container, | ||
trigger, | ||
emitter: this, | ||
}); | ||
} | ||
/** | ||
* Default `target` lookup function. | ||
* @param {Element} trigger | ||
*/ | ||
defaultTarget(trigger) { | ||
const selector = getAttributeValue('target', trigger); | ||
/** | ||
* Default `action` lookup function. | ||
* @param {Element} trigger | ||
*/ | ||
defaultAction(trigger) { | ||
return getAttributeValue('action', trigger); | ||
} | ||
if (selector) { | ||
return document.querySelector(selector); | ||
} | ||
} | ||
/** | ||
* Default `target` lookup function. | ||
* @param {Element} trigger | ||
*/ | ||
defaultTarget(trigger) { | ||
const selector = getAttributeValue('target', trigger); | ||
/** | ||
* Returns the support of the given action, or all actions if no action is | ||
* given. | ||
* @param {String} [action] | ||
*/ | ||
static isSupported(action = ['copy', 'cut']) { | ||
const actions = (typeof action === 'string') ? [action] : action; | ||
let support = !!document.queryCommandSupported; | ||
actions.forEach((action) => { | ||
support = support && !!document.queryCommandSupported(action); | ||
}); | ||
return support; | ||
if (selector) { | ||
return document.querySelector(selector); | ||
} | ||
} | ||
/** | ||
* Default `text` lookup function. | ||
* @param {Element} trigger | ||
*/ | ||
defaultText(trigger) { | ||
return getAttributeValue('text', trigger); | ||
} | ||
/** | ||
* Returns the support of the given action, or all actions if no action is | ||
* given. | ||
* @param {String} [action] | ||
*/ | ||
static isSupported(action = ['copy', 'cut']) { | ||
const actions = typeof action === 'string' ? [action] : action; | ||
let support = !!document.queryCommandSupported; | ||
/** | ||
* Destroy lifecycle. | ||
*/ | ||
destroy() { | ||
this.listener.destroy(); | ||
actions.forEach((action) => { | ||
support = support && !!document.queryCommandSupported(action); | ||
}); | ||
if (this.clipboardAction) { | ||
this.clipboardAction.destroy(); | ||
this.clipboardAction = null; | ||
} | ||
} | ||
} | ||
return support; | ||
} | ||
/** | ||
* Default `text` lookup function. | ||
* @param {Element} trigger | ||
*/ | ||
defaultText(trigger) { | ||
return getAttributeValue('text', trigger); | ||
} | ||
/** | ||
* Helper function to retrieve attribute value. | ||
* @param {String} suffix | ||
* @param {Element} element | ||
*/ | ||
function getAttributeValue(suffix, element) { | ||
const attribute = `data-clipboard-${suffix}`; | ||
/** | ||
* Destroy lifecycle. | ||
*/ | ||
destroy() { | ||
this.listener.destroy(); | ||
if (!element.hasAttribute(attribute)) { | ||
return; | ||
if (this.clipboardAction) { | ||
this.clipboardAction.destroy(); | ||
this.clipboardAction = null; | ||
} | ||
return element.getAttribute(attribute); | ||
} | ||
} | ||
export default Clipboard; |
@@ -0,243 +1,248 @@ | ||
import Emitter from 'tiny-emitter'; | ||
import ClipboardAction from '../src/clipboard-action'; | ||
import Emitter from 'tiny-emitter'; | ||
describe('ClipboardAction', () => { | ||
before(() => { | ||
global.input = document.createElement('input'); | ||
global.input.setAttribute('id', 'input'); | ||
global.input.setAttribute('value', 'abc'); | ||
document.body.appendChild(global.input); | ||
before(() => { | ||
global.input = document.createElement('input'); | ||
global.input.setAttribute('id', 'input'); | ||
global.input.setAttribute('value', 'abc'); | ||
document.body.appendChild(global.input); | ||
global.paragraph = document.createElement('p'); | ||
global.paragraph.setAttribute('id', 'paragraph'); | ||
global.paragraph.textContent = 'abc'; | ||
document.body.appendChild(global.paragraph); | ||
}); | ||
global.paragraph = document.createElement('p'); | ||
global.paragraph.setAttribute('id', 'paragraph'); | ||
global.paragraph.textContent = 'abc'; | ||
document.body.appendChild(global.paragraph); | ||
}); | ||
after(() => { | ||
document.body.innerHTML = ''; | ||
}); | ||
after(() => { | ||
document.body.innerHTML = ''; | ||
}); | ||
describe('#resolveOptions', () => { | ||
it('should set base properties', () => { | ||
let clip = new ClipboardAction({ | ||
emitter: new Emitter(), | ||
container: document.body, | ||
text: 'foo' | ||
}); | ||
describe('#resolveOptions', () => { | ||
it('should set base properties', () => { | ||
let clip = new ClipboardAction({ | ||
emitter: new Emitter(), | ||
container: document.body, | ||
text: 'foo', | ||
}); | ||
assert.property(clip, 'action'); | ||
assert.property(clip, 'container'); | ||
assert.property(clip, 'emitter'); | ||
assert.property(clip, 'target'); | ||
assert.property(clip, 'text'); | ||
assert.property(clip, 'trigger'); | ||
assert.property(clip, 'selectedText'); | ||
}); | ||
assert.property(clip, 'action'); | ||
assert.property(clip, 'container'); | ||
assert.property(clip, 'emitter'); | ||
assert.property(clip, 'target'); | ||
assert.property(clip, 'text'); | ||
assert.property(clip, 'trigger'); | ||
assert.property(clip, 'selectedText'); | ||
}); | ||
}); | ||
describe('#initSelection', () => { | ||
it('should set the position right style property', done => { | ||
// Set document direction | ||
document.documentElement.setAttribute('dir', 'rtl'); | ||
describe('#initSelection', () => { | ||
it('should set the position right style property', (done) => { | ||
// Set document direction | ||
document.documentElement.setAttribute('dir', 'rtl'); | ||
let clip = new ClipboardAction({ | ||
emitter: new Emitter(), | ||
container: document.body, | ||
text: 'foo' | ||
}); | ||
let clip = new ClipboardAction({ | ||
emitter: new Emitter(), | ||
container: document.body, | ||
text: 'foo', | ||
}); | ||
assert.equal(clip.fakeElem.style.right, '-9999px'); | ||
done(); | ||
}); | ||
const el = clip.createFakeElement(); | ||
assert.equal(el.style.right, '-9999px'); | ||
done(); | ||
}); | ||
}); | ||
describe('#set action', () => { | ||
it('should throw an error since "action" is invalid', done => { | ||
try { | ||
new ClipboardAction({ | ||
text: 'foo', | ||
action: 'paste' | ||
}); | ||
} | ||
catch(e) { | ||
assert.equal(e.message, 'Invalid "action" value, use either "copy" or "cut"'); | ||
done(); | ||
} | ||
describe('#set action', () => { | ||
it('should throw an error since "action" is invalid', (done) => { | ||
try { | ||
let clip = new ClipboardAction({ | ||
text: 'foo', | ||
action: 'paste', | ||
}); | ||
} catch (e) { | ||
assert.equal( | ||
e.message, | ||
'Invalid "action" value, use either "copy" or "cut"' | ||
); | ||
done(); | ||
} | ||
}); | ||
}); | ||
describe('#set target', () => { | ||
it('should throw an error since "target" do not match any element', done => { | ||
try { | ||
new ClipboardAction({ | ||
target: document.querySelector('#foo') | ||
}); | ||
} | ||
catch(e) { | ||
assert.equal(e.message, 'Invalid "target" value, use a valid Element'); | ||
done(); | ||
} | ||
describe('#set target', () => { | ||
it('should throw an error since "target" do not match any element', (done) => { | ||
try { | ||
let clip = new ClipboardAction({ | ||
target: document.querySelector('#foo'), | ||
}); | ||
} catch (e) { | ||
assert.equal(e.message, 'Invalid "target" value, use a valid Element'); | ||
done(); | ||
} | ||
}); | ||
}); | ||
describe('#selectText', () => { | ||
it('should create a fake element and select its value', () => { | ||
let clip = new ClipboardAction({ | ||
emitter: new Emitter(), | ||
container: document.body, | ||
text: 'blah' | ||
}); | ||
describe('#selectText', () => { | ||
it('should create a fake element and select its value', () => { | ||
let clip = new ClipboardAction({ | ||
emitter: new Emitter(), | ||
container: document.body, | ||
text: 'blah', | ||
}); | ||
assert.equal(clip.selectedText, clip.fakeElem.value); | ||
}); | ||
const el = clip.createFakeElement(); | ||
assert.equal(clip.selectedText, el.value); | ||
}); | ||
}); | ||
describe('#removeFake', () => { | ||
it('should remove a temporary fake element', () => { | ||
let clip = new ClipboardAction({ | ||
emitter: new Emitter(), | ||
container: document.body, | ||
text: 'blah' | ||
}); | ||
describe('#removeFake', () => { | ||
it('should remove a temporary fake element', () => { | ||
let clip = new ClipboardAction({ | ||
emitter: new Emitter(), | ||
container: document.body, | ||
text: 'blah', | ||
}); | ||
clip.removeFake(); | ||
clip.removeFake(); | ||
assert.equal(clip.fakeElem, null); | ||
}); | ||
assert.equal(clip.fakeElem, null); | ||
}); | ||
}); | ||
describe('#selectTarget', () => { | ||
it('should select text from editable element', () => { | ||
let clip = new ClipboardAction({ | ||
emitter: new Emitter(), | ||
container: document.body, | ||
target: document.querySelector('#input') | ||
}); | ||
describe('#selectTarget', () => { | ||
it('should select text from editable element', () => { | ||
let clip = new ClipboardAction({ | ||
emitter: new Emitter(), | ||
container: document.body, | ||
target: document.querySelector('#input'), | ||
}); | ||
assert.equal(clip.selectedText, clip.target.value); | ||
}); | ||
assert.equal(clip.selectedText, clip.target.value); | ||
}); | ||
it('should select text from non-editable element', () => { | ||
let clip = new ClipboardAction({ | ||
emitter: new Emitter(), | ||
container: document.body, | ||
target: document.querySelector('#paragraph') | ||
}); | ||
it('should select text from non-editable element', () => { | ||
let clip = new ClipboardAction({ | ||
emitter: new Emitter(), | ||
container: document.body, | ||
target: document.querySelector('#paragraph'), | ||
}); | ||
assert.equal(clip.selectedText, clip.target.textContent); | ||
}); | ||
assert.equal(clip.selectedText, clip.target.textContent); | ||
}); | ||
}); | ||
describe('#copyText', () => { | ||
before(() => { | ||
global.stub = sinon.stub(document, 'execCommand'); | ||
}); | ||
describe('#copyText', () => { | ||
before(() => { | ||
global.stub = sinon.stub(document, 'execCommand'); | ||
}); | ||
after(() => { | ||
global.stub.restore(); | ||
}); | ||
after(() => { | ||
global.stub.restore(); | ||
}); | ||
it('should fire a success event on browsers that support copy command', done => { | ||
global.stub.returns(true); | ||
it('should fire a success event on browsers that support copy command', (done) => { | ||
global.stub.returns(true); | ||
let emitter = new Emitter(); | ||
let emitter = new Emitter(); | ||
emitter.on('success', () => { | ||
done(); | ||
}); | ||
emitter.on('success', () => { | ||
done(); | ||
}); | ||
let clip = new ClipboardAction({ | ||
emitter, | ||
target: document.querySelector('#input') | ||
}); | ||
}); | ||
let clip = new ClipboardAction({ | ||
emitter, | ||
target: document.querySelector('#input'), | ||
}); | ||
}); | ||
it('should fire an error event on browsers that support copy command', done => { | ||
global.stub.returns(false); | ||
it('should fire an error event on browsers that support copy command', (done) => { | ||
global.stub.returns(false); | ||
let emitter = new Emitter(); | ||
let emitter = new Emitter(); | ||
emitter.on('error', () => { | ||
done(); | ||
}); | ||
emitter.on('error', () => { | ||
done(); | ||
}); | ||
let clip = new ClipboardAction({ | ||
emitter, | ||
target: document.querySelector('#input') | ||
}); | ||
}); | ||
let clip = new ClipboardAction({ | ||
emitter, | ||
target: document.querySelector('#input'), | ||
}); | ||
}); | ||
}); | ||
describe('#handleResult', () => { | ||
it('should fire a success event with certain properties', done => { | ||
let clip = new ClipboardAction({ | ||
emitter: new Emitter(), | ||
container: document.body, | ||
target: document.querySelector('#input') | ||
}); | ||
describe('#handleResult', () => { | ||
it('should fire a success event with certain properties', (done) => { | ||
let clip = new ClipboardAction({ | ||
emitter: new Emitter(), | ||
container: document.body, | ||
target: document.querySelector('#input'), | ||
}); | ||
clip.emitter.on('success', (e) => { | ||
assert.property(e, 'action'); | ||
assert.property(e, 'text'); | ||
assert.property(e, 'trigger'); | ||
assert.property(e, 'clearSelection'); | ||
clip.emitter.on('success', (e) => { | ||
assert.property(e, 'action'); | ||
assert.property(e, 'text'); | ||
assert.property(e, 'trigger'); | ||
assert.property(e, 'clearSelection'); | ||
done(); | ||
}); | ||
done(); | ||
}); | ||
clip.handleResult(true); | ||
}); | ||
clip.handleResult(true); | ||
}); | ||
it('should fire a error event with certain properties', done => { | ||
let clip = new ClipboardAction({ | ||
emitter: new Emitter(), | ||
container: document.body, | ||
target: document.querySelector('#input') | ||
}); | ||
it('should fire a error event with certain properties', (done) => { | ||
let clip = new ClipboardAction({ | ||
emitter: new Emitter(), | ||
container: document.body, | ||
target: document.querySelector('#input'), | ||
}); | ||
clip.emitter.on('error', (e) => { | ||
assert.property(e, 'action'); | ||
assert.property(e, 'trigger'); | ||
assert.property(e, 'clearSelection'); | ||
clip.emitter.on('error', (e) => { | ||
assert.property(e, 'action'); | ||
assert.property(e, 'trigger'); | ||
assert.property(e, 'clearSelection'); | ||
done(); | ||
}); | ||
done(); | ||
}); | ||
clip.handleResult(false); | ||
}); | ||
clip.handleResult(false); | ||
}); | ||
}); | ||
describe('#clearSelection', () => { | ||
it('should remove focus from target and text selection', () => { | ||
let clip = new ClipboardAction({ | ||
emitter: new Emitter(), | ||
container: document.body, | ||
target: document.querySelector('#input') | ||
}); | ||
describe('#clearSelection', () => { | ||
it('should remove focus from target and text selection', () => { | ||
let clip = new ClipboardAction({ | ||
emitter: new Emitter(), | ||
container: document.body, | ||
target: document.querySelector('#input'), | ||
}); | ||
clip.clearSelection(); | ||
clip.clearSelection(); | ||
let selectedElem = document.activeElement; | ||
let selectedText = window.getSelection().toString(); | ||
let selectedElem = document.activeElement; | ||
let selectedText = window.getSelection().toString(); | ||
assert.equal(selectedElem, document.body); | ||
assert.equal(selectedText, ''); | ||
}); | ||
assert.equal(selectedElem, document.body); | ||
assert.equal(selectedText, ''); | ||
}); | ||
}); | ||
describe('#destroy', () => { | ||
it('should destroy an existing fake element', () => { | ||
let clip = new ClipboardAction({ | ||
emitter: new Emitter(), | ||
container: document.body, | ||
text: 'blah' | ||
}); | ||
describe('#destroy', () => { | ||
it('should destroy an existing fake element', () => { | ||
let clip = new ClipboardAction({ | ||
emitter: new Emitter(), | ||
container: document.body, | ||
text: 'blah', | ||
}); | ||
clip.selectFake(); | ||
clip.destroy(); | ||
clip.selectFake(); | ||
clip.destroy(); | ||
assert.equal(clip.fakeElem, null); | ||
}); | ||
assert.equal(clip.fakeElem, null); | ||
}); | ||
}); | ||
}); |
import Clipboard from '../src/clipboard'; | ||
import ClipboardAction from '../src/clipboard-action'; | ||
import listen from 'good-listener'; | ||
describe('Clipboard', () => { | ||
before(() => { | ||
global.button = document.createElement('button'); | ||
global.button.setAttribute('class', 'btn'); | ||
global.button.setAttribute('data-clipboard-text', 'foo'); | ||
document.body.appendChild(global.button); | ||
before(() => { | ||
global.button = document.createElement('button'); | ||
global.button.setAttribute('class', 'btn'); | ||
global.button.setAttribute('data-clipboard-text', 'foo'); | ||
document.body.appendChild(global.button); | ||
global.span = document.createElement('span'); | ||
global.span.innerHTML = 'bar'; | ||
global.span = document.createElement('span'); | ||
global.span.innerHTML = 'bar'; | ||
global.button.appendChild(span); | ||
global.button.appendChild(span); | ||
global.event = { | ||
target: global.button, | ||
currentTarget: global.button | ||
}; | ||
}); | ||
global.event = { | ||
target: global.button, | ||
currentTarget: global.button, | ||
}; | ||
}); | ||
after(() => { | ||
document.body.innerHTML = ''; | ||
after(() => { | ||
document.body.innerHTML = ''; | ||
}); | ||
describe('#resolveOptions', () => { | ||
before(() => { | ||
global.fn = () => {}; | ||
}); | ||
describe('#resolveOptions', () => { | ||
before(() => { | ||
global.fn = () => {}; | ||
}); | ||
it('should set action as a function', () => { | ||
let clipboard = new Clipboard('.btn', { | ||
action: global.fn, | ||
}); | ||
it('should set action as a function', () => { | ||
let clipboard = new Clipboard('.btn', { | ||
action: global.fn | ||
}); | ||
assert.equal(global.fn, clipboard.action); | ||
}); | ||
assert.equal(global.fn, clipboard.action); | ||
}); | ||
it('should set target as a function', () => { | ||
let clipboard = new Clipboard('.btn', { | ||
target: global.fn, | ||
}); | ||
it('should set target as a function', () => { | ||
let clipboard = new Clipboard('.btn', { | ||
target: global.fn | ||
}); | ||
assert.equal(global.fn, clipboard.target); | ||
}); | ||
assert.equal(global.fn, clipboard.target); | ||
}); | ||
it('should set text as a function', () => { | ||
let clipboard = new Clipboard('.btn', { | ||
text: global.fn, | ||
}); | ||
it('should set text as a function', () => { | ||
let clipboard = new Clipboard('.btn', { | ||
text: global.fn | ||
}); | ||
assert.equal(global.fn, clipboard.text); | ||
}); | ||
assert.equal(global.fn, clipboard.text); | ||
}); | ||
it('should set container as an object', () => { | ||
let clipboard = new Clipboard('.btn', { | ||
container: document.body, | ||
}); | ||
it('should set container as an object', () => { | ||
let clipboard = new Clipboard('.btn', { | ||
container: document.body | ||
}); | ||
assert.equal(document.body, clipboard.container); | ||
}); | ||
assert.equal(document.body, clipboard.container); | ||
}); | ||
it('should set container as body by default', () => { | ||
let clipboard = new Clipboard('.btn'); | ||
it('should set container as body by default', () => { | ||
let clipboard = new Clipboard('.btn'); | ||
assert.equal(document.body, clipboard.container); | ||
}); | ||
}); | ||
assert.equal(document.body, clipboard.container); | ||
}); | ||
describe('#listenClick', () => { | ||
it('should add a click event listener to the passed selector', () => { | ||
let clipboard = new Clipboard('.btn'); | ||
assert.isObject(clipboard.listener); | ||
}); | ||
}); | ||
describe('#listenClick', () => { | ||
it('should add a click event listener to the passed selector', () => { | ||
let clipboard = new Clipboard('.btn'); | ||
assert.isObject(clipboard.listener); | ||
}); | ||
describe('#onClick', () => { | ||
it('should create a new instance of ClipboardAction', () => { | ||
let clipboard = new Clipboard('.btn'); | ||
clipboard.onClick(global.event); | ||
assert.instanceOf(clipboard.clipboardAction, ClipboardAction); | ||
}); | ||
describe('#onClick', () => { | ||
it('should create a new instance of ClipboardAction', () => { | ||
let clipboard = new Clipboard('.btn'); | ||
it("should use an event's currentTarget when not equal to target", () => { | ||
let clipboard = new Clipboard('.btn'); | ||
let bubbledEvent = { | ||
target: global.span, | ||
currentTarget: global.button, | ||
}; | ||
clipboard.onClick(global.event); | ||
assert.instanceOf(clipboard.clipboardAction, ClipboardAction); | ||
}); | ||
clipboard.onClick(bubbledEvent); | ||
assert.instanceOf(clipboard.clipboardAction, ClipboardAction); | ||
}); | ||
it('should use an event\'s currentTarget when not equal to target', () => { | ||
let clipboard = new Clipboard('.btn'); | ||
let bubbledEvent = { target: global.span, currentTarget: global.button }; | ||
clipboard.onClick(bubbledEvent); | ||
assert.instanceOf(clipboard.clipboardAction, ClipboardAction); | ||
it('should throw an exception when target is invalid', (done) => { | ||
try { | ||
const clipboard = new Clipboard('.btn', { | ||
target() { | ||
return null; | ||
}, | ||
}); | ||
it('should throw an exception when target is invalid', done => { | ||
try { | ||
const clipboard = new Clipboard('.btn', { | ||
target() { | ||
return null; | ||
} | ||
}); | ||
clipboard.onClick(global.event); | ||
} catch (e) { | ||
assert.equal(e.message, 'Invalid "target" value, use a valid Element'); | ||
done(); | ||
} | ||
}); | ||
}); | ||
clipboard.onClick(global.event); | ||
} | ||
catch(e) { | ||
assert.equal(e.message, 'Invalid "target" value, use a valid Element'); | ||
done(); | ||
} | ||
}); | ||
describe('#static isSupported', () => { | ||
it('should return the support of the given action', () => { | ||
assert.equal(Clipboard.isSupported('copy'), true); | ||
assert.equal(Clipboard.isSupported('cut'), true); | ||
}); | ||
describe('#static isSupported', () => { | ||
it('should return the support of the given action', () => { | ||
assert.equal(Clipboard.isSupported('copy'), true); | ||
assert.equal(Clipboard.isSupported('cut'), true); | ||
}); | ||
it('should return the support of the cut and copy actions', () => { | ||
assert.equal(Clipboard.isSupported(), true); | ||
}); | ||
it('should return the support of the cut and copy actions', () => { | ||
assert.equal(Clipboard.isSupported(), true); | ||
}); | ||
}); | ||
describe('#destroy', () => { | ||
it('should destroy an existing instance of ClipboardAction', () => { | ||
let clipboard = new Clipboard('.btn'); | ||
describe('#destroy', () => { | ||
it('should destroy an existing instance of ClipboardAction', () => { | ||
let clipboard = new Clipboard('.btn'); | ||
clipboard.onClick(global.event); | ||
clipboard.destroy(); | ||
clipboard.onClick(global.event); | ||
clipboard.destroy(); | ||
assert.equal(clipboard.clipboardAction, null); | ||
}); | ||
assert.equal(clipboard.clipboardAction, null); | ||
}); | ||
}); | ||
}); |
@@ -14,34 +14,33 @@ const pkg = require('./package.json'); | ||
module.exports = { | ||
entry: './src/clipboard.js', | ||
mode: 'production', | ||
output: { | ||
filename: production ? 'clipboard.min.js' : 'clipboard.js', | ||
path: path.resolve(__dirname, 'dist'), | ||
library: 'ClipboardJS', | ||
globalObject: 'this', | ||
libraryExport: 'default', | ||
libraryTarget: 'umd' | ||
}, | ||
module: { | ||
rules: [ | ||
{test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader'} | ||
] | ||
}, | ||
optimization: { | ||
minimize: production, | ||
minimizer: [ | ||
new UglifyJSPlugin({ | ||
parallel: require('os').cpus().length, | ||
uglifyOptions: { | ||
ie8: false, | ||
keep_fnames: false, | ||
output: { | ||
beautify: false, | ||
comments: (node, {value, type}) => type == 'comment2' && value.startsWith('!') | ||
} | ||
} | ||
}) | ||
] | ||
}, | ||
plugins: [new webpack.BannerPlugin({ banner })] | ||
entry: './src/clipboard.js', | ||
mode: 'production', | ||
output: { | ||
filename: production ? 'clipboard.min.js' : 'clipboard.js', | ||
path: path.resolve(__dirname, 'dist'), | ||
library: 'ClipboardJS', | ||
globalObject: 'this', | ||
libraryExport: 'default', | ||
libraryTarget: 'umd', | ||
}, | ||
module: { | ||
rules: [{ test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader' }], | ||
}, | ||
optimization: { | ||
minimize: production, | ||
minimizer: [ | ||
new UglifyJSPlugin({ | ||
parallel: require('os').cpus().length, | ||
uglifyOptions: { | ||
ie8: false, | ||
keep_fnames: false, | ||
output: { | ||
beautify: false, | ||
comments: (node, { value, type }) => | ||
type == 'comment2' && value.startsWith('!'), | ||
}, | ||
}, | ||
}), | ||
], | ||
}, | ||
plugins: [new webpack.BannerPlugin({ banner })], | ||
}; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
92889
40
1708
0
193
25
1