mirror of
https://github.com/zenorocha/clipboard.js.git
synced 2023-08-10 21:12:48 +03:00
Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
39e622456c | ||
|
|
f8c322f163 | ||
|
|
f42b57067d | ||
|
|
4065080a17 | ||
|
|
5ab50475e0 | ||
|
|
e1394b3b8c | ||
|
|
f59d4e6b4d | ||
|
|
9ddff7e591 | ||
|
|
a00f1fe327 | ||
|
|
38ae5b34f3 | ||
|
|
41b7234d50 | ||
|
|
3696739e5e | ||
|
|
63d1b0f014 | ||
|
|
402c9ee17b | ||
|
|
0538f6e212 | ||
|
|
8ad16a2c6c | ||
|
|
ce0829054b | ||
|
|
223d30c110 | ||
|
|
b1a68df6e9 | ||
|
|
0149e1de5e | ||
|
|
26a9e9d56c | ||
|
|
fce625f151 | ||
|
|
f7040bae8a | ||
|
|
9f9d03c927 | ||
|
|
e18c26ae07 | ||
|
|
70cfabec69 | ||
|
|
f700a1b12e | ||
|
|
9e3d662c4e | ||
|
|
76b907949c | ||
|
|
60b6887100 |
2
.babelrc
2
.babelrc
@@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"presets": ["es2015-loose"],
|
"presets": ["es2015"],
|
||||||
"plugins": ["transform-es2015-modules-umd"]
|
"plugins": ["transform-es2015-modules-umd"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "clipboard",
|
"name": "clipboard",
|
||||||
"version": "1.5.12",
|
"version": "1.7.0",
|
||||||
"description": "Modern copy to clipboard. No Flash. Just 2kb",
|
"description": "Modern copy to clipboard. No Flash. Just 2kb",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "dist/clipboard.js",
|
"main": "dist/clipboard.js",
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>constructor-node</title>
|
<title>constructor-node</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- 1. Define some markup -->
|
<!-- 1. Define some markup -->
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>constructor-nodelist</title>
|
<title>constructor-nodelist</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- 1. Define some markup -->
|
<!-- 1. Define some markup -->
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>constructor-selector</title>
|
<title>constructor-selector</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- 1. Define some markup -->
|
<!-- 1. Define some markup -->
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>function-target</title>
|
<title>function-target</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- 1. Define some markup -->
|
<!-- 1. Define some markup -->
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>function-text</title>
|
<title>function-text</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- 1. Define some markup -->
|
<!-- 1. Define some markup -->
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>target-div</title>
|
<title>target-div</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- 1. Define some markup -->
|
<!-- 1. Define some markup -->
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>target-input</title>
|
<title>target-input</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- 1. Define some markup -->
|
<!-- 1. Define some markup -->
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>target-textarea</title>
|
<title>target-textarea</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- 1. Define some markup -->
|
<!-- 1. Define some markup -->
|
||||||
|
|||||||
472
dist/clipboard.js
vendored
472
dist/clipboard.js
vendored
@@ -1,23 +1,46 @@
|
|||||||
/*!
|
/*!
|
||||||
* clipboard.js v1.5.12
|
* clipboard.js v1.7.0
|
||||||
* https://zenorocha.github.io/clipboard.js
|
* https://zenorocha.github.io/clipboard.js
|
||||||
*
|
*
|
||||||
* Licensed MIT © Zeno Rocha
|
* Licensed MIT © Zeno Rocha
|
||||||
*/
|
*/
|
||||||
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Clipboard = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Clipboard = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
||||||
var matches = require('matches-selector')
|
var DOCUMENT_NODE_TYPE = 9;
|
||||||
|
|
||||||
module.exports = function (element, selector, checkYoSelf) {
|
|
||||||
var parent = checkYoSelf ? element : element.parentNode
|
|
||||||
|
|
||||||
while (parent && parent !== document) {
|
|
||||||
if (matches(parent, selector)) return parent;
|
|
||||||
parent = parent.parentNode
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
},{"matches-selector":5}],2:[function(require,module,exports){
|
/**
|
||||||
var closest = require('closest');
|
* A polyfill for Element.matches()
|
||||||
|
*/
|
||||||
|
if (typeof Element !== 'undefined' && !Element.prototype.matches) {
|
||||||
|
var proto = Element.prototype;
|
||||||
|
|
||||||
|
proto.matches = proto.matchesSelector ||
|
||||||
|
proto.mozMatchesSelector ||
|
||||||
|
proto.msMatchesSelector ||
|
||||||
|
proto.oMatchesSelector ||
|
||||||
|
proto.webkitMatchesSelector;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the closest parent that matches a selector.
|
||||||
|
*
|
||||||
|
* @param {Element} element
|
||||||
|
* @param {String} selector
|
||||||
|
* @return {Function}
|
||||||
|
*/
|
||||||
|
function closest (element, selector) {
|
||||||
|
while (element && element.nodeType !== DOCUMENT_NODE_TYPE) {
|
||||||
|
if (typeof element.matches === 'function' &&
|
||||||
|
element.matches(selector)) {
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
element = element.parentNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = closest;
|
||||||
|
|
||||||
|
},{}],2:[function(require,module,exports){
|
||||||
|
var closest = require('./closest');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delegates event to a selector.
|
* Delegates event to a selector.
|
||||||
@@ -52,7 +75,7 @@ function delegate(element, selector, type, callback, useCapture) {
|
|||||||
*/
|
*/
|
||||||
function listener(element, selector, type, callback) {
|
function listener(element, selector, type, callback) {
|
||||||
return function(e) {
|
return function(e) {
|
||||||
e.delegateTarget = closest(e.target, selector, true);
|
e.delegateTarget = closest(e.target, selector);
|
||||||
|
|
||||||
if (e.delegateTarget) {
|
if (e.delegateTarget) {
|
||||||
callback.call(element, e);
|
callback.call(element, e);
|
||||||
@@ -62,7 +85,7 @@ function listener(element, selector, type, callback) {
|
|||||||
|
|
||||||
module.exports = delegate;
|
module.exports = delegate;
|
||||||
|
|
||||||
},{"closest":1}],3:[function(require,module,exports){
|
},{"./closest":1}],3:[function(require,module,exports){
|
||||||
/**
|
/**
|
||||||
* Check if argument is a HTML element.
|
* Check if argument is a HTML element.
|
||||||
*
|
*
|
||||||
@@ -211,54 +234,28 @@ function listenSelector(selector, type, callback) {
|
|||||||
module.exports = listen;
|
module.exports = listen;
|
||||||
|
|
||||||
},{"./is":3,"delegate":2}],5:[function(require,module,exports){
|
},{"./is":3,"delegate":2}],5:[function(require,module,exports){
|
||||||
|
|
||||||
/**
|
|
||||||
* Element prototype.
|
|
||||||
*/
|
|
||||||
|
|
||||||
var proto = Element.prototype;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Vendor function.
|
|
||||||
*/
|
|
||||||
|
|
||||||
var vendor = proto.matchesSelector
|
|
||||||
|| proto.webkitMatchesSelector
|
|
||||||
|| proto.mozMatchesSelector
|
|
||||||
|| proto.msMatchesSelector
|
|
||||||
|| proto.oMatchesSelector;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Expose `match()`.
|
|
||||||
*/
|
|
||||||
|
|
||||||
module.exports = match;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Match `el` to `selector`.
|
|
||||||
*
|
|
||||||
* @param {Element} el
|
|
||||||
* @param {String} selector
|
|
||||||
* @return {Boolean}
|
|
||||||
* @api public
|
|
||||||
*/
|
|
||||||
|
|
||||||
function match(el, selector) {
|
|
||||||
if (vendor) return vendor.call(el, selector);
|
|
||||||
var nodes = el.parentNode.querySelectorAll(selector);
|
|
||||||
for (var i = 0; i < nodes.length; ++i) {
|
|
||||||
if (nodes[i] == el) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
},{}],6:[function(require,module,exports){
|
|
||||||
function select(element) {
|
function select(element) {
|
||||||
var selectedText;
|
var selectedText;
|
||||||
|
|
||||||
if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {
|
if (element.nodeName === 'SELECT') {
|
||||||
element.focus();
|
element.focus();
|
||||||
|
|
||||||
|
selectedText = element.value;
|
||||||
|
}
|
||||||
|
else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {
|
||||||
|
var isReadOnly = element.hasAttribute('readonly');
|
||||||
|
|
||||||
|
if (!isReadOnly) {
|
||||||
|
element.setAttribute('readonly', '');
|
||||||
|
}
|
||||||
|
|
||||||
|
element.select();
|
||||||
element.setSelectionRange(0, element.value.length);
|
element.setSelectionRange(0, element.value.length);
|
||||||
|
|
||||||
|
if (!isReadOnly) {
|
||||||
|
element.removeAttribute('readonly');
|
||||||
|
}
|
||||||
|
|
||||||
selectedText = element.value;
|
selectedText = element.value;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -281,14 +278,14 @@ function select(element) {
|
|||||||
|
|
||||||
module.exports = select;
|
module.exports = select;
|
||||||
|
|
||||||
},{}],7:[function(require,module,exports){
|
},{}],6:[function(require,module,exports){
|
||||||
function E () {
|
function E () {
|
||||||
// Keep this empty so it's easier to inherit from
|
// Keep this empty so it's easier to inherit from
|
||||||
// (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)
|
// (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)
|
||||||
}
|
}
|
||||||
|
|
||||||
E.prototype = {
|
E.prototype = {
|
||||||
on: function (name, callback, ctx) {
|
on: function (name, callback, ctx) {
|
||||||
var e = this.e || (this.e = {});
|
var e = this.e || (this.e = {});
|
||||||
|
|
||||||
(e[name] || (e[name] = [])).push({
|
(e[name] || (e[name] = [])).push({
|
||||||
@@ -349,7 +346,7 @@ E.prototype = {
|
|||||||
|
|
||||||
module.exports = E;
|
module.exports = E;
|
||||||
|
|
||||||
},{}],8:[function(require,module,exports){
|
},{}],7:[function(require,module,exports){
|
||||||
(function (global, factory) {
|
(function (global, factory) {
|
||||||
if (typeof define === "function" && define.amd) {
|
if (typeof define === "function" && define.amd) {
|
||||||
define(['module', 'select'], factory);
|
define(['module', 'select'], factory);
|
||||||
@@ -376,7 +373,7 @@ module.exports = E;
|
|||||||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
|
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
|
||||||
return typeof obj;
|
return typeof obj;
|
||||||
} : function (obj) {
|
} : function (obj) {
|
||||||
return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj;
|
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
|
||||||
};
|
};
|
||||||
|
|
||||||
function _classCallCheck(instance, Constructor) {
|
function _classCallCheck(instance, Constructor) {
|
||||||
@@ -407,7 +404,6 @@ module.exports = E;
|
|||||||
/**
|
/**
|
||||||
* @param {Object} options
|
* @param {Object} options
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ClipboardAction(options) {
|
function ClipboardAction(options) {
|
||||||
_classCallCheck(this, ClipboardAction);
|
_classCallCheck(this, ClipboardAction);
|
||||||
|
|
||||||
@@ -421,122 +417,126 @@ module.exports = E;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
ClipboardAction.prototype.resolveOptions = function resolveOptions() {
|
_createClass(ClipboardAction, [{
|
||||||
var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
|
key: 'resolveOptions',
|
||||||
|
value: function resolveOptions() {
|
||||||
|
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
||||||
|
|
||||||
this.action = options.action;
|
this.action = options.action;
|
||||||
this.emitter = options.emitter;
|
this.container = options.container;
|
||||||
this.target = options.target;
|
this.emitter = options.emitter;
|
||||||
this.text = options.text;
|
this.target = options.target;
|
||||||
this.trigger = options.trigger;
|
this.text = options.text;
|
||||||
|
this.trigger = options.trigger;
|
||||||
|
|
||||||
this.selectedText = '';
|
this.selectedText = '';
|
||||||
};
|
|
||||||
|
|
||||||
ClipboardAction.prototype.initSelection = function initSelection() {
|
|
||||||
if (this.text) {
|
|
||||||
this.selectFake();
|
|
||||||
} else if (this.target) {
|
|
||||||
this.selectTarget();
|
|
||||||
}
|
}
|
||||||
};
|
}, {
|
||||||
|
key: 'initSelection',
|
||||||
ClipboardAction.prototype.selectFake = function selectFake() {
|
value: function initSelection() {
|
||||||
var _this = this;
|
if (this.text) {
|
||||||
|
this.selectFake();
|
||||||
var isRTL = document.documentElement.getAttribute('dir') == 'rtl';
|
} else if (this.target) {
|
||||||
|
this.selectTarget();
|
||||||
this.removeFake();
|
}
|
||||||
|
|
||||||
this.fakeHandlerCallback = function () {
|
|
||||||
return _this.removeFake();
|
|
||||||
};
|
|
||||||
this.fakeHandler = document.body.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
|
|
||||||
this.fakeElem.style.top = (window.pageYOffset || document.documentElement.scrollTop) + 'px';
|
|
||||||
this.fakeElem.setAttribute('readonly', '');
|
|
||||||
this.fakeElem.value = this.text;
|
|
||||||
|
|
||||||
document.body.appendChild(this.fakeElem);
|
|
||||||
|
|
||||||
this.selectedText = (0, _select2.default)(this.fakeElem);
|
|
||||||
this.copyText();
|
|
||||||
};
|
|
||||||
|
|
||||||
ClipboardAction.prototype.removeFake = function removeFake() {
|
|
||||||
if (this.fakeHandler) {
|
|
||||||
document.body.removeEventListener('click', this.fakeHandlerCallback);
|
|
||||||
this.fakeHandler = null;
|
|
||||||
this.fakeHandlerCallback = null;
|
|
||||||
}
|
}
|
||||||
|
}, {
|
||||||
|
key: 'selectFake',
|
||||||
|
value: function selectFake() {
|
||||||
|
var _this = this;
|
||||||
|
|
||||||
if (this.fakeElem) {
|
var isRTL = document.documentElement.getAttribute('dir') == 'rtl';
|
||||||
document.body.removeChild(this.fakeElem);
|
|
||||||
this.fakeElem = null;
|
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 = (0, _select2.default)(this.fakeElem);
|
||||||
|
this.copyText();
|
||||||
}
|
}
|
||||||
};
|
}, {
|
||||||
|
key: 'removeFake',
|
||||||
|
value: function removeFake() {
|
||||||
|
if (this.fakeHandler) {
|
||||||
|
this.container.removeEventListener('click', this.fakeHandlerCallback);
|
||||||
|
this.fakeHandler = null;
|
||||||
|
this.fakeHandlerCallback = null;
|
||||||
|
}
|
||||||
|
|
||||||
ClipboardAction.prototype.selectTarget = function selectTarget() {
|
if (this.fakeElem) {
|
||||||
this.selectedText = (0, _select2.default)(this.target);
|
this.container.removeChild(this.fakeElem);
|
||||||
this.copyText();
|
this.fakeElem = null;
|
||||||
};
|
}
|
||||||
|
|
||||||
ClipboardAction.prototype.copyText = function copyText() {
|
|
||||||
var succeeded = undefined;
|
|
||||||
|
|
||||||
try {
|
|
||||||
succeeded = document.execCommand(this.action);
|
|
||||||
} catch (err) {
|
|
||||||
succeeded = false;
|
|
||||||
}
|
}
|
||||||
|
}, {
|
||||||
|
key: 'selectTarget',
|
||||||
|
value: function selectTarget() {
|
||||||
|
this.selectedText = (0, _select2.default)(this.target);
|
||||||
|
this.copyText();
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'copyText',
|
||||||
|
value: function copyText() {
|
||||||
|
var succeeded = void 0;
|
||||||
|
|
||||||
this.handleResult(succeeded);
|
try {
|
||||||
};
|
succeeded = document.execCommand(this.action);
|
||||||
|
} catch (err) {
|
||||||
|
succeeded = false;
|
||||||
|
}
|
||||||
|
|
||||||
ClipboardAction.prototype.handleResult = function handleResult(succeeded) {
|
this.handleResult(succeeded);
|
||||||
if (succeeded) {
|
}
|
||||||
this.emitter.emit('success', {
|
}, {
|
||||||
|
key: 'handleResult',
|
||||||
|
value: function handleResult(succeeded) {
|
||||||
|
this.emitter.emit(succeeded ? 'success' : 'error', {
|
||||||
action: this.action,
|
action: this.action,
|
||||||
text: this.selectedText,
|
text: this.selectedText,
|
||||||
trigger: this.trigger,
|
trigger: this.trigger,
|
||||||
clearSelection: this.clearSelection.bind(this)
|
clearSelection: this.clearSelection.bind(this)
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
this.emitter.emit('error', {
|
|
||||||
action: this.action,
|
|
||||||
trigger: this.trigger,
|
|
||||||
clearSelection: this.clearSelection.bind(this)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
}, {
|
||||||
|
key: 'clearSelection',
|
||||||
|
value: function clearSelection() {
|
||||||
|
if (this.target) {
|
||||||
|
this.target.blur();
|
||||||
|
}
|
||||||
|
|
||||||
ClipboardAction.prototype.clearSelection = function clearSelection() {
|
window.getSelection().removeAllRanges();
|
||||||
if (this.target) {
|
|
||||||
this.target.blur();
|
|
||||||
}
|
}
|
||||||
|
}, {
|
||||||
window.getSelection().removeAllRanges();
|
key: 'destroy',
|
||||||
};
|
value: function destroy() {
|
||||||
|
this.removeFake();
|
||||||
ClipboardAction.prototype.destroy = function destroy() {
|
}
|
||||||
this.removeFake();
|
}, {
|
||||||
};
|
|
||||||
|
|
||||||
_createClass(ClipboardAction, [{
|
|
||||||
key: 'action',
|
key: 'action',
|
||||||
set: function set() {
|
set: function set() {
|
||||||
var action = arguments.length <= 0 || arguments[0] === undefined ? 'copy' : arguments[0];
|
var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'copy';
|
||||||
|
|
||||||
this._action = action;
|
this._action = action;
|
||||||
|
|
||||||
@@ -577,7 +577,7 @@ module.exports = E;
|
|||||||
module.exports = ClipboardAction;
|
module.exports = ClipboardAction;
|
||||||
});
|
});
|
||||||
|
|
||||||
},{"select":6}],9:[function(require,module,exports){
|
},{"select":5}],8:[function(require,module,exports){
|
||||||
(function (global, factory) {
|
(function (global, factory) {
|
||||||
if (typeof define === "function" && define.amd) {
|
if (typeof define === "function" && define.amd) {
|
||||||
define(['module', './clipboard-action', 'tiny-emitter', 'good-listener'], factory);
|
define(['module', './clipboard-action', 'tiny-emitter', 'good-listener'], factory);
|
||||||
@@ -605,12 +605,36 @@ module.exports = E;
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
function _classCallCheck(instance, Constructor) {
|
function _classCallCheck(instance, Constructor) {
|
||||||
if (!(instance instanceof Constructor)) {
|
if (!(instance instanceof Constructor)) {
|
||||||
throw new TypeError("Cannot call a class as a function");
|
throw new TypeError("Cannot call a class as a function");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
}();
|
||||||
|
|
||||||
function _possibleConstructorReturn(self, call) {
|
function _possibleConstructorReturn(self, call) {
|
||||||
if (!self) {
|
if (!self) {
|
||||||
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
|
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
|
||||||
@@ -642,11 +666,10 @@ module.exports = E;
|
|||||||
* @param {String|HTMLElement|HTMLCollection|NodeList} trigger
|
* @param {String|HTMLElement|HTMLCollection|NodeList} trigger
|
||||||
* @param {Object} options
|
* @param {Object} options
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function Clipboard(trigger, options) {
|
function Clipboard(trigger, options) {
|
||||||
_classCallCheck(this, Clipboard);
|
_classCallCheck(this, Clipboard);
|
||||||
|
|
||||||
var _this = _possibleConstructorReturn(this, _Emitter.call(this));
|
var _this = _possibleConstructorReturn(this, (Clipboard.__proto__ || Object.getPrototypeOf(Clipboard)).call(this));
|
||||||
|
|
||||||
_this.resolveOptions(options);
|
_this.resolveOptions(options);
|
||||||
_this.listenClick(trigger);
|
_this.listenClick(trigger);
|
||||||
@@ -660,62 +683,87 @@ module.exports = E;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
Clipboard.prototype.resolveOptions = function resolveOptions() {
|
_createClass(Clipboard, [{
|
||||||
var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
|
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.action = typeof options.action === 'function' ? options.action : this.defaultAction;
|
||||||
this.target = typeof options.target === 'function' ? options.target : this.defaultTarget;
|
this.target = typeof options.target === 'function' ? options.target : this.defaultTarget;
|
||||||
this.text = typeof options.text === 'function' ? options.text : this.defaultText;
|
this.text = typeof options.text === 'function' ? options.text : this.defaultText;
|
||||||
};
|
this.container = _typeof(options.container) === 'object' ? options.container : document.body;
|
||||||
|
|
||||||
Clipboard.prototype.listenClick = function listenClick(trigger) {
|
|
||||||
var _this2 = this;
|
|
||||||
|
|
||||||
this.listener = (0, _goodListener2.default)(trigger, 'click', function (e) {
|
|
||||||
return _this2.onClick(e);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Clipboard.prototype.onClick = function onClick(e) {
|
|
||||||
var trigger = e.delegateTarget || e.currentTarget;
|
|
||||||
|
|
||||||
if (this.clipboardAction) {
|
|
||||||
this.clipboardAction = null;
|
|
||||||
}
|
}
|
||||||
|
}, {
|
||||||
|
key: 'listenClick',
|
||||||
|
value: function listenClick(trigger) {
|
||||||
|
var _this2 = this;
|
||||||
|
|
||||||
this.clipboardAction = new _clipboardAction2.default({
|
this.listener = (0, _goodListener2.default)(trigger, 'click', function (e) {
|
||||||
action: this.action(trigger),
|
return _this2.onClick(e);
|
||||||
target: this.target(trigger),
|
});
|
||||||
text: this.text(trigger),
|
|
||||||
trigger: trigger,
|
|
||||||
emitter: this
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Clipboard.prototype.defaultAction = function defaultAction(trigger) {
|
|
||||||
return getAttributeValue('action', trigger);
|
|
||||||
};
|
|
||||||
|
|
||||||
Clipboard.prototype.defaultTarget = function defaultTarget(trigger) {
|
|
||||||
var selector = getAttributeValue('target', trigger);
|
|
||||||
|
|
||||||
if (selector) {
|
|
||||||
return document.querySelector(selector);
|
|
||||||
}
|
}
|
||||||
};
|
}, {
|
||||||
|
key: 'onClick',
|
||||||
|
value: function onClick(e) {
|
||||||
|
var trigger = e.delegateTarget || e.currentTarget;
|
||||||
|
|
||||||
Clipboard.prototype.defaultText = function defaultText(trigger) {
|
if (this.clipboardAction) {
|
||||||
return getAttributeValue('text', trigger);
|
this.clipboardAction = null;
|
||||||
};
|
}
|
||||||
|
|
||||||
Clipboard.prototype.destroy = function destroy() {
|
this.clipboardAction = new _clipboardAction2.default({
|
||||||
this.listener.destroy();
|
action: this.action(trigger),
|
||||||
|
target: this.target(trigger),
|
||||||
if (this.clipboardAction) {
|
text: this.text(trigger),
|
||||||
this.clipboardAction.destroy();
|
container: this.container,
|
||||||
this.clipboardAction = null;
|
trigger: trigger,
|
||||||
|
emitter: this
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
}, {
|
||||||
|
key: 'defaultAction',
|
||||||
|
value: function defaultAction(trigger) {
|
||||||
|
return getAttributeValue('action', trigger);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'defaultTarget',
|
||||||
|
value: function defaultTarget(trigger) {
|
||||||
|
var selector = getAttributeValue('target', trigger);
|
||||||
|
|
||||||
|
if (selector) {
|
||||||
|
return document.querySelector(selector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'defaultText',
|
||||||
|
value: function defaultText(trigger) {
|
||||||
|
return getAttributeValue('text', trigger);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
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;
|
return Clipboard;
|
||||||
}(_tinyEmitter2.default);
|
}(_tinyEmitter2.default);
|
||||||
@@ -738,5 +786,5 @@ module.exports = E;
|
|||||||
module.exports = Clipboard;
|
module.exports = Clipboard;
|
||||||
});
|
});
|
||||||
|
|
||||||
},{"./clipboard-action":8,"good-listener":4,"tiny-emitter":7}]},{},[9])(9)
|
},{"./clipboard-action":7,"good-listener":4,"tiny-emitter":6}]},{},[8])(8)
|
||||||
});
|
});
|
||||||
4
dist/clipboard.min.js
vendored
4
dist/clipboard.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -3,7 +3,7 @@
|
|||||||
Package.describe({
|
Package.describe({
|
||||||
name: "zenorocha:clipboard",
|
name: "zenorocha:clipboard",
|
||||||
summary: "Modern copy to clipboard. No Flash. Just 2kb.",
|
summary: "Modern copy to clipboard. No Flash. Just 2kb.",
|
||||||
version: "1.5.12",
|
version: "1.7.0",
|
||||||
git: "https://github.com/zenorocha/clipboard.js"
|
git: "https://github.com/zenorocha/clipboard.js"
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
47
package.json
47
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "clipboard",
|
"name": "clipboard",
|
||||||
"version": "1.5.12",
|
"version": "1.7.0",
|
||||||
"description": "Modern copy to clipboard. No Flash. Just 2kb",
|
"description": "Modern copy to clipboard. No Flash. Just 2kb",
|
||||||
"repository": "zenorocha/clipboard.js",
|
"repository": "zenorocha/clipboard.js",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -11,32 +11,31 @@
|
|||||||
"cut"
|
"cut"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"good-listener": "^1.1.6",
|
"good-listener": "^1.2.2",
|
||||||
"select": "^1.0.6",
|
"select": "^1.1.2",
|
||||||
"tiny-emitter": "^1.0.0"
|
"tiny-emitter": "^2.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-cli": "^6.5.1",
|
"babel-cli": "^6.24.1",
|
||||||
"babel-core": "^6.5.2",
|
"babel-core": "^6.24.1",
|
||||||
"babel-plugin-transform-es2015-modules-umd": "^6.5.0",
|
"babel-plugin-transform-es2015-modules-umd": "^6.24.1",
|
||||||
"babel-preset-es2015": "^6.5.0",
|
"babel-preset-es2015": "^6.24.1",
|
||||||
"babel-preset-es2015-loose": "^7.0.0",
|
"babelify": "^7.3.0",
|
||||||
"babelify": "^7.2.0",
|
|
||||||
"bannerify": "Vekat/bannerify#feature-option",
|
"bannerify": "Vekat/bannerify#feature-option",
|
||||||
"browserify": "^13.0.0",
|
"browserify": "^14.3.0",
|
||||||
"chai": "^3.4.1",
|
"chai": "^3.5.0",
|
||||||
"install": "^0.4.4",
|
"install": "^0.9.6",
|
||||||
"karma": "^0.13.10",
|
"karma": "^1.6.0",
|
||||||
"karma-browserify": "^5.0.1",
|
"karma-browserify": "^5.1.1",
|
||||||
"karma-chai": "^0.1.0",
|
"karma-chai": "^0.1.0",
|
||||||
"karma-mocha": "^0.2.0",
|
"karma-mocha": "^1.3.0",
|
||||||
"karma-phantomjs-launcher": "^1.0.0",
|
"karma-phantomjs-launcher": "^1.0.4",
|
||||||
"karma-sinon": "^1.0.4",
|
"karma-sinon": "^1.0.5",
|
||||||
"mocha": "^2.3.3",
|
"mocha": "^3.3.0",
|
||||||
"phantomjs-prebuilt": "^2.1.4",
|
"phantomjs-prebuilt": "^2.1.14",
|
||||||
"sinon": "^1.17.2",
|
"sinon": "^2.2.0",
|
||||||
"uglify-js": "^2.4.24",
|
"uglify-js": "^2.8.22",
|
||||||
"watchify": "^3.4.0"
|
"watchify": "^3.9.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "npm run build-debug && npm run build-min",
|
"build": "npm run build-debug && npm run build-min",
|
||||||
@@ -44,6 +43,6 @@
|
|||||||
"build-min": "uglifyjs dist/clipboard.js --comments '/!/' -m screw_ie8=true -c screw_ie8=true,unused=false -o dist/clipboard.min.js",
|
"build-min": "uglifyjs dist/clipboard.js --comments '/!/' -m screw_ie8=true -c screw_ie8=true,unused=false -o dist/clipboard.min.js",
|
||||||
"build-watch": "watchify src/clipboard.js -s Clipboard -t [babelify] -o dist/clipboard.js -v",
|
"build-watch": "watchify src/clipboard.js -s Clipboard -t [babelify] -o dist/clipboard.js -v",
|
||||||
"test": "karma start --single-run",
|
"test": "karma start --single-run",
|
||||||
"prepublish": "babel src --out-dir lib --loose all"
|
"prepublish": "babel src --out-dir lib"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
44
readme.md
44
readme.md
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
> Modern copy to clipboard. No Flash. Just 3kb gzipped.
|
> Modern copy to clipboard. No Flash. Just 3kb gzipped.
|
||||||
|
|
||||||
<a href="http://clipboardjs.com/"><img width="728" src="https://cloud.githubusercontent.com/assets/398893/9983535/5ab0a950-5fb4-11e5-9602-e73c0b661883.jpg" alt="Demo"></a>
|
<a href="https://clipboardjs.com/"><img width="728" src="https://cloud.githubusercontent.com/assets/398893/16165747/a0f6fc46-349a-11e6-8c9b-c5fd58d9099c.png" alt="Demo"></a>
|
||||||
|
|
||||||
## Why
|
## Why
|
||||||
|
|
||||||
@@ -21,13 +21,7 @@ You can get it on npm.
|
|||||||
npm install clipboard --save
|
npm install clipboard --save
|
||||||
```
|
```
|
||||||
|
|
||||||
Or bower, too.
|
Or if you're not into package management, just [download a ZIP](https://github.com/zenorocha/clipboard.js/archive/master.zip) file.
|
||||||
|
|
||||||
```
|
|
||||||
bower install clipboard --save
|
|
||||||
```
|
|
||||||
|
|
||||||
If you're not into package management, just [download a ZIP](https://github.com/zenorocha/clipboard.js/archive/master.zip) file.
|
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
@@ -57,7 +51,7 @@ A pretty common use case is to copy content from another element. You can do tha
|
|||||||
|
|
||||||
The value you include on this attribute needs to match another's element selector.
|
The value you include on this attribute needs to match another's element selector.
|
||||||
|
|
||||||
<a href="http://clipboardjs.com/#example-target"><img width="473" alt="example-2" src="https://cloud.githubusercontent.com/assets/398893/9983467/a4946aaa-5fb1-11e5-9780-f09fcd7ca6c8.png"></a>
|
<a href="https://clipboardjs.com/#example-target"><img width="473" alt="example-2" src="https://cloud.githubusercontent.com/assets/398893/9983467/a4946aaa-5fb1-11e5-9780-f09fcd7ca6c8.png"></a>
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<!-- Target -->
|
<!-- Target -->
|
||||||
@@ -75,7 +69,7 @@ Additionally, you can define a `data-clipboard-action` attribute to specify if y
|
|||||||
|
|
||||||
If you omit this attribute, `copy` will be used by default.
|
If you omit this attribute, `copy` will be used by default.
|
||||||
|
|
||||||
<a href="http://clipboardjs.com/#example-action"><img width="473" alt="example-3" src="https://cloud.githubusercontent.com/assets/398893/10000358/7df57b9c-6050-11e5-9cd1-fbc51d2fd0a7.png"></a>
|
<a href="https://clipboardjs.com/#example-action"><img width="473" alt="example-3" src="https://cloud.githubusercontent.com/assets/398893/10000358/7df57b9c-6050-11e5-9cd1-fbc51d2fd0a7.png"></a>
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<!-- Target -->
|
<!-- Target -->
|
||||||
@@ -93,7 +87,7 @@ As you may expect, the `cut` action only works on `<input>` or `<textarea>` elem
|
|||||||
|
|
||||||
Truth is, you don't even need another element to copy its content from. You can just include a `data-clipboard-text` attribute in your trigger element.
|
Truth is, you don't even need another element to copy its content from. You can just include a `data-clipboard-text` attribute in your trigger element.
|
||||||
|
|
||||||
<a href="http://clipboardjs.com/#example-text"><img width="147" alt="example-1" src="https://cloud.githubusercontent.com/assets/398893/10000347/6e16cf8c-6050-11e5-9883-1c5681f9ec45.png"></a>
|
<a href="https://clipboardjs.com/#example-text"><img width="147" alt="example-1" src="https://cloud.githubusercontent.com/assets/398893/10000347/6e16cf8c-6050-11e5-9883-1c5681f9ec45.png"></a>
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<!-- Trigger -->
|
<!-- Trigger -->
|
||||||
@@ -125,7 +119,7 @@ clipboard.on('error', function(e) {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
For a live demonstration, open this [site](http://clipboardjs.com/) and just your console :)
|
For a live demonstration, open this [site](https://clipboardjs.com/) and just your console :)
|
||||||
|
|
||||||
## Advanced Options
|
## Advanced Options
|
||||||
|
|
||||||
@@ -151,6 +145,14 @@ new Clipboard('.btn', {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
For use in Bootstrap Modals or with any other library that changes the focus you'll want to set the focused element as the `container` value.
|
||||||
|
|
||||||
|
```js
|
||||||
|
new Clipboard('.btn', {
|
||||||
|
container: document.getElementById('#modal')
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
Also, if you are working with single page apps, you may want to manage the lifecycle of the DOM more precisely. Here's how you clean up the events and objects that we create.
|
Also, if you are working with single page apps, you may want to manage the lifecycle of the DOM more precisely. Here's how you clean up the events and objects that we create.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
@@ -160,17 +162,21 @@ clipboard.destroy();
|
|||||||
|
|
||||||
## Browser Support
|
## Browser Support
|
||||||
|
|
||||||
This library relies on both [Selection](https://developer.mozilla.org/en-US/docs/Web/API/Selection) and [execCommand](https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand) APIs. The second one is supported in the following browsers.
|
This library relies on both [Selection](https://developer.mozilla.org/en-US/docs/Web/API/Selection) and [execCommand](https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand) APIs. The first one is [supported by all browsers](http://caniuse.com/#search=selection) while the second one is supported in the following browsers.
|
||||||
|
|
||||||
| <img src="http://clipboardjs.com/assets/images/chrome.png" width="48px" height="48px" alt="Chrome logo"> | <img src="http://clipboardjs.com/assets/images/firefox.png" width="48px" height="48px" alt="Firefox logo"> | <img src="http://clipboardjs.com/assets/images/ie.png" width="48px" height="48px" alt="Internet Explorer logo"> | <img src="http://clipboardjs.com/assets/images/opera.png" width="48px" height="48px" alt="Opera logo"> | <img src="http://clipboardjs.com/assets/images/safari.png" width="48px" height="48px" alt="Safari logo"> |
|
| <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+ ✔ | 41+ ✔ | 9+ ✔ | 29+ ✔ | Nope ✘ |
|
| 42+ ✔ | 12+ ✔ | 41+ ✔ | 9+ ✔ | 29+ ✔ | 10+ ✔ |
|
||||||
|
|
||||||
Although copy/cut operations with [execCommand](https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand) aren't supported on Safari yet (including mobile), it gracefully degrades because [Selection](https://developer.mozilla.org/en-US/docs/Web/API/Selection) is supported.
|
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.
|
||||||
|
|
||||||
That means you can show a tooltip saying `Copied!` when `success` event is called and `Press Command+C to copy` when `error` event is called because the text is already selected.
|
You can also check if clipboard.js is supported or not by running `Clipboard.isSupported()`, that way you can hide copy/cut buttons from the UI.
|
||||||
|
|
||||||
For a live demonstration, open this [site](http://clipboardjs.com) on Safari.
|
## Bonus
|
||||||
|
|
||||||
|
A browser extension that adds a "copy to clipboard" button to every code block on *GitHub, MDN, Gist, StackOverflow, StackExchange, npm, and even Medium.*
|
||||||
|
|
||||||
|
Install for [Chrome](https://chrome.google.com/webstore/detail/codecopy/fkbfebkcoelajmhanocgppanfoojcdmg) and [Firefox](https://addons.mozilla.org/en-US/firefox/addon/codecopy/).
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
@@ -18,11 +18,12 @@ class ClipboardAction {
|
|||||||
* @param {Object} options
|
* @param {Object} options
|
||||||
*/
|
*/
|
||||||
resolveOptions(options = {}) {
|
resolveOptions(options = {}) {
|
||||||
this.action = options.action;
|
this.action = options.action;
|
||||||
this.emitter = options.emitter;
|
this.container = options.container;
|
||||||
this.target = options.target;
|
this.emitter = options.emitter;
|
||||||
this.text = options.text;
|
this.target = options.target;
|
||||||
this.trigger = options.trigger;
|
this.text = options.text;
|
||||||
|
this.trigger = options.trigger;
|
||||||
|
|
||||||
this.selectedText = '';
|
this.selectedText = '';
|
||||||
}
|
}
|
||||||
@@ -50,7 +51,7 @@ class ClipboardAction {
|
|||||||
this.removeFake();
|
this.removeFake();
|
||||||
|
|
||||||
this.fakeHandlerCallback = () => this.removeFake();
|
this.fakeHandlerCallback = () => this.removeFake();
|
||||||
this.fakeHandler = document.body.addEventListener('click', this.fakeHandlerCallback) || true;
|
this.fakeHandler = this.container.addEventListener('click', this.fakeHandlerCallback) || true;
|
||||||
|
|
||||||
this.fakeElem = document.createElement('textarea');
|
this.fakeElem = document.createElement('textarea');
|
||||||
// Prevent zooming on iOS
|
// Prevent zooming on iOS
|
||||||
@@ -63,11 +64,13 @@ class ClipboardAction {
|
|||||||
this.fakeElem.style.position = 'absolute';
|
this.fakeElem.style.position = 'absolute';
|
||||||
this.fakeElem.style[ isRTL ? 'right' : 'left' ] = '-9999px';
|
this.fakeElem.style[ isRTL ? 'right' : 'left' ] = '-9999px';
|
||||||
// Move element to the same position vertically
|
// Move element to the same position vertically
|
||||||
this.fakeElem.style.top = (window.pageYOffset || document.documentElement.scrollTop) + 'px';
|
let yPosition = window.pageYOffset || document.documentElement.scrollTop;
|
||||||
|
this.fakeElem.style.top = `${yPosition}px`;
|
||||||
|
|
||||||
this.fakeElem.setAttribute('readonly', '');
|
this.fakeElem.setAttribute('readonly', '');
|
||||||
this.fakeElem.value = this.text;
|
this.fakeElem.value = this.text;
|
||||||
|
|
||||||
document.body.appendChild(this.fakeElem);
|
this.container.appendChild(this.fakeElem);
|
||||||
|
|
||||||
this.selectedText = select(this.fakeElem);
|
this.selectedText = select(this.fakeElem);
|
||||||
this.copyText();
|
this.copyText();
|
||||||
@@ -79,13 +82,13 @@ class ClipboardAction {
|
|||||||
*/
|
*/
|
||||||
removeFake() {
|
removeFake() {
|
||||||
if (this.fakeHandler) {
|
if (this.fakeHandler) {
|
||||||
document.body.removeEventListener('click', this.fakeHandlerCallback);
|
this.container.removeEventListener('click', this.fakeHandlerCallback);
|
||||||
this.fakeHandler = null;
|
this.fakeHandler = null;
|
||||||
this.fakeHandlerCallback = null;
|
this.fakeHandlerCallback = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.fakeElem) {
|
if (this.fakeElem) {
|
||||||
document.body.removeChild(this.fakeElem);
|
this.container.removeChild(this.fakeElem);
|
||||||
this.fakeElem = null;
|
this.fakeElem = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -119,21 +122,12 @@ class ClipboardAction {
|
|||||||
* @param {Boolean} succeeded
|
* @param {Boolean} succeeded
|
||||||
*/
|
*/
|
||||||
handleResult(succeeded) {
|
handleResult(succeeded) {
|
||||||
if (succeeded) {
|
this.emitter.emit(succeeded ? 'success' : 'error', {
|
||||||
this.emitter.emit('success', {
|
action: this.action,
|
||||||
action: this.action,
|
text: this.selectedText,
|
||||||
text: this.selectedText,
|
trigger: this.trigger,
|
||||||
trigger: this.trigger,
|
clearSelection: this.clearSelection.bind(this)
|
||||||
clearSelection: this.clearSelection.bind(this)
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.emitter.emit('error', {
|
|
||||||
action: this.action,
|
|
||||||
trigger: this.trigger,
|
|
||||||
clearSelection: this.clearSelection.bind(this)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -24,9 +24,10 @@ class Clipboard extends Emitter {
|
|||||||
* @param {Object} options
|
* @param {Object} options
|
||||||
*/
|
*/
|
||||||
resolveOptions(options = {}) {
|
resolveOptions(options = {}) {
|
||||||
this.action = (typeof options.action === 'function') ? options.action : this.defaultAction;
|
this.action = (typeof options.action === 'function') ? options.action : this.defaultAction;
|
||||||
this.target = (typeof options.target === 'function') ? options.target : this.defaultTarget;
|
this.target = (typeof options.target === 'function') ? options.target : this.defaultTarget;
|
||||||
this.text = (typeof options.text === 'function') ? options.text : this.defaultText;
|
this.text = (typeof options.text === 'function') ? options.text : this.defaultText;
|
||||||
|
this.container = (typeof options.container === 'object') ? options.container : document.body;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -49,11 +50,12 @@ class Clipboard extends Emitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.clipboardAction = new ClipboardAction({
|
this.clipboardAction = new ClipboardAction({
|
||||||
action : this.action(trigger),
|
action : this.action(trigger),
|
||||||
target : this.target(trigger),
|
target : this.target(trigger),
|
||||||
text : this.text(trigger),
|
text : this.text(trigger),
|
||||||
trigger : trigger,
|
container : this.container,
|
||||||
emitter : this
|
trigger : trigger,
|
||||||
|
emitter : this
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,6 +79,22 @@ class Clipboard extends Emitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default `text` lookup function.
|
* Default `text` lookup function.
|
||||||
* @param {Element} trigger
|
* @param {Element} trigger
|
||||||
|
|||||||
@@ -22,10 +22,12 @@ describe('ClipboardAction', () => {
|
|||||||
it('should set base properties', () => {
|
it('should set base properties', () => {
|
||||||
let clip = new ClipboardAction({
|
let clip = new ClipboardAction({
|
||||||
emitter: new Emitter(),
|
emitter: new Emitter(),
|
||||||
|
container: document.body,
|
||||||
text: 'foo'
|
text: 'foo'
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.property(clip, 'action');
|
assert.property(clip, 'action');
|
||||||
|
assert.property(clip, 'container');
|
||||||
assert.property(clip, 'emitter');
|
assert.property(clip, 'emitter');
|
||||||
assert.property(clip, 'target');
|
assert.property(clip, 'target');
|
||||||
assert.property(clip, 'text');
|
assert.property(clip, 'text');
|
||||||
@@ -41,6 +43,7 @@ describe('ClipboardAction', () => {
|
|||||||
|
|
||||||
let clip = new ClipboardAction({
|
let clip = new ClipboardAction({
|
||||||
emitter: new Emitter(),
|
emitter: new Emitter(),
|
||||||
|
container: document.body,
|
||||||
text: 'foo'
|
text: 'foo'
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -82,6 +85,7 @@ describe('ClipboardAction', () => {
|
|||||||
it('should create a fake element and select its value', () => {
|
it('should create a fake element and select its value', () => {
|
||||||
let clip = new ClipboardAction({
|
let clip = new ClipboardAction({
|
||||||
emitter: new Emitter(),
|
emitter: new Emitter(),
|
||||||
|
container: document.body,
|
||||||
text: 'blah'
|
text: 'blah'
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -93,6 +97,7 @@ describe('ClipboardAction', () => {
|
|||||||
it('should remove a temporary fake element', () => {
|
it('should remove a temporary fake element', () => {
|
||||||
let clip = new ClipboardAction({
|
let clip = new ClipboardAction({
|
||||||
emitter: new Emitter(),
|
emitter: new Emitter(),
|
||||||
|
container: document.body,
|
||||||
text: 'blah'
|
text: 'blah'
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -106,6 +111,7 @@ describe('ClipboardAction', () => {
|
|||||||
it('should select text from editable element', () => {
|
it('should select text from editable element', () => {
|
||||||
let clip = new ClipboardAction({
|
let clip = new ClipboardAction({
|
||||||
emitter: new Emitter(),
|
emitter: new Emitter(),
|
||||||
|
container: document.body,
|
||||||
target: document.querySelector('#input')
|
target: document.querySelector('#input')
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -115,6 +121,7 @@ describe('ClipboardAction', () => {
|
|||||||
it('should select text from non-editable element', () => {
|
it('should select text from non-editable element', () => {
|
||||||
let clip = new ClipboardAction({
|
let clip = new ClipboardAction({
|
||||||
emitter: new Emitter(),
|
emitter: new Emitter(),
|
||||||
|
container: document.body,
|
||||||
target: document.querySelector('#paragraph')
|
target: document.querySelector('#paragraph')
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -141,7 +148,7 @@ describe('ClipboardAction', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let clip = new ClipboardAction({
|
let clip = new ClipboardAction({
|
||||||
emitter: emitter,
|
emitter,
|
||||||
target: document.querySelector('#input')
|
target: document.querySelector('#input')
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -156,7 +163,7 @@ describe('ClipboardAction', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let clip = new ClipboardAction({
|
let clip = new ClipboardAction({
|
||||||
emitter: emitter,
|
emitter,
|
||||||
target: document.querySelector('#input')
|
target: document.querySelector('#input')
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -166,6 +173,7 @@ describe('ClipboardAction', () => {
|
|||||||
it('should fire a success event with certain properties', done => {
|
it('should fire a success event with certain properties', done => {
|
||||||
let clip = new ClipboardAction({
|
let clip = new ClipboardAction({
|
||||||
emitter: new Emitter(),
|
emitter: new Emitter(),
|
||||||
|
container: document.body,
|
||||||
target: document.querySelector('#input')
|
target: document.querySelector('#input')
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -184,6 +192,7 @@ describe('ClipboardAction', () => {
|
|||||||
it('should fire a error event with certain properties', done => {
|
it('should fire a error event with certain properties', done => {
|
||||||
let clip = new ClipboardAction({
|
let clip = new ClipboardAction({
|
||||||
emitter: new Emitter(),
|
emitter: new Emitter(),
|
||||||
|
container: document.body,
|
||||||
target: document.querySelector('#input')
|
target: document.querySelector('#input')
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -203,6 +212,7 @@ describe('ClipboardAction', () => {
|
|||||||
it('should remove focus from target and text selection', () => {
|
it('should remove focus from target and text selection', () => {
|
||||||
let clip = new ClipboardAction({
|
let clip = new ClipboardAction({
|
||||||
emitter: new Emitter(),
|
emitter: new Emitter(),
|
||||||
|
container: document.body,
|
||||||
target: document.querySelector('#input')
|
target: document.querySelector('#input')
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -220,6 +230,7 @@ describe('ClipboardAction', () => {
|
|||||||
it('should destroy an existing fake element', () => {
|
it('should destroy an existing fake element', () => {
|
||||||
let clip = new ClipboardAction({
|
let clip = new ClipboardAction({
|
||||||
emitter: new Emitter(),
|
emitter: new Emitter(),
|
||||||
|
container: document.body,
|
||||||
text: 'blah'
|
text: 'blah'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ describe('Clipboard', () => {
|
|||||||
|
|
||||||
describe('#resolveOptions', () => {
|
describe('#resolveOptions', () => {
|
||||||
before(() => {
|
before(() => {
|
||||||
global.fn = function() {};
|
global.fn = () => {};
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set action as a function', () => {
|
it('should set action as a function', () => {
|
||||||
@@ -52,6 +52,20 @@ describe('Clipboard', () => {
|
|||||||
|
|
||||||
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
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(document.body, clipboard.container);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set container as body by default', () => {
|
||||||
|
let clipboard = new Clipboard('.btn');
|
||||||
|
|
||||||
|
assert.equal(document.body, clipboard.container);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#listenClick', () => {
|
describe('#listenClick', () => {
|
||||||
@@ -79,8 +93,8 @@ describe('Clipboard', () => {
|
|||||||
|
|
||||||
it('should throw an exception when target is invalid', done => {
|
it('should throw an exception when target is invalid', done => {
|
||||||
try {
|
try {
|
||||||
var clipboard = new Clipboard('.btn', {
|
const clipboard = new Clipboard('.btn', {
|
||||||
target: function() {
|
target() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -94,6 +108,17 @@ describe('Clipboard', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('#static isSupported', () => {
|
||||||
|
it('should return the support of the given action', () => {
|
||||||
|
assert.equal(Clipboard.isSupported('copy'), false);
|
||||||
|
assert.equal(Clipboard.isSupported('cut'), false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the support of the cut and copy actions', () => {
|
||||||
|
assert.equal(Clipboard.isSupported(), false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('#destroy', () => {
|
describe('#destroy', () => {
|
||||||
it('should destroy an existing instance of ClipboardAction', () => {
|
it('should destroy an existing instance of ClipboardAction', () => {
|
||||||
let clipboard = new Clipboard('.btn');
|
let clipboard = new Clipboard('.btn');
|
||||||
|
|||||||
Reference in New Issue
Block a user