diff --git a/.github/issue_template.md b/.github/issue_template.md
new file mode 100644
index 0000000..aeb709a
--- /dev/null
+++ b/.github/issue_template.md
@@ -0,0 +1,19 @@
+### Expected behaviour
+
+I thought that by going to the page '...' and pressing the button '...' then '...' would happen.
+
+### Actual behaviour
+
+Instead of '...', what I saw was that '...' happened instead.
+
+### Steps to reproduce
+
+1. Go this JSFiddle, JSBin, CodePen, etc
+2. Click on '....'
+3. Scroll down to '....'
+4. Refresh the page and wait 5 secs
+5. Finally the error will magically happen (if it is raining)
+
+### Browsers affected
+
+I tested on all major browsers and only IE 11 does not work.
diff --git a/bower.json b/bower.json
index 5fa2b30..93937a4 100644
--- a/bower.json
+++ b/bower.json
@@ -1,6 +1,6 @@
{
"name": "clipboard",
- "version": "1.5.2",
+ "version": "1.5.8",
"description": "Modern copy to clipboard. No Flash. Just 2kb",
"license": "MIT",
"main": "dist/clipboard.js",
diff --git a/demo/constructor-node.html b/demo/constructor-node.html
index f84857a..c118772 100644
--- a/demo/constructor-node.html
+++ b/demo/constructor-node.html
@@ -6,7 +6,9 @@
- Copy
+
+ Copy
+
diff --git a/dist/clipboard.js b/dist/clipboard.js
index 97d6cd3..24dbac6 100644
--- a/dist/clipboard.js
+++ b/dist/clipboard.js
@@ -1,5 +1,5 @@
/*!
- * clipboard.js v1.5.2
+ * clipboard.js v1.5.8
* https://zenorocha.github.io/clipboard.js
*
* Licensed MIT © Zeno Rocha
@@ -16,48 +16,7 @@ module.exports = function (element, selector, checkYoSelf) {
}
}
-},{"matches-selector":2}],2:[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;
-}
-},{}],3:[function(require,module,exports){
+},{"matches-selector":5}],2:[function(require,module,exports){
var closest = require('closest');
/**
@@ -67,16 +26,17 @@ var closest = require('closest');
* @param {String} selector
* @param {String} type
* @param {Function} callback
+ * @param {Boolean} useCapture
* @return {Object}
*/
-function delegate(element, selector, type, callback) {
+function delegate(element, selector, type, callback, useCapture) {
var listenerFn = listener.apply(this, arguments);
- element.addEventListener(type, listenerFn);
+ element.addEventListener(type, listenerFn, useCapture);
return {
destroy: function() {
- element.removeEventListener(type, listenerFn);
+ element.removeEventListener(type, listenerFn, useCapture);
}
}
}
@@ -92,13 +52,9 @@ function delegate(element, selector, type, callback) {
*/
function listener(element, selector, type, callback) {
return function(e) {
- var delegateTarget = closest(e.target, selector, true);
-
- if (delegateTarget) {
- Object.defineProperty(e, 'target', {
- value: delegateTarget
- });
+ e.delegateTarget = closest(e.target, selector, true);
+ if (e.delegateTarget) {
callback.call(element, e);
}
}
@@ -106,7 +62,7 @@ function listener(element, selector, type, callback) {
module.exports = delegate;
-},{"closest":1}],4:[function(require,module,exports){
+},{"closest":1}],3:[function(require,module,exports){
/**
* Check if argument is a HTML element.
*
@@ -151,13 +107,13 @@ exports.string = function(value) {
* @param {Object} value
* @return {Boolean}
*/
-exports.function = function(value) {
+exports.fn = function(value) {
var type = Object.prototype.toString.call(value);
return type === '[object Function]';
};
-},{}],5:[function(require,module,exports){
+},{}],4:[function(require,module,exports){
var is = require('./is');
var delegate = require('delegate');
@@ -179,7 +135,7 @@ function listen(target, type, callback) {
throw new TypeError('Second argument must be a String');
}
- if (!is.function(callback)) {
+ if (!is.fn(callback)) {
throw new TypeError('Third argument must be a Function');
}
@@ -254,16 +210,62 @@ function listenSelector(selector, type, callback) {
module.exports = listen;
-},{"./is":4,"delegate":3}],6:[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) {
var selectedText;
if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {
- element.select();
+ element.focus();
+ element.setSelectionRange(0, element.value.length);
selectedText = element.value;
}
else {
+ if (element.hasAttribute('contenteditable')) {
+ element.focus();
+ }
+
var selection = window.getSelection();
var range = document.createRange();
@@ -421,6 +423,8 @@ var ClipboardAction = (function () {
ClipboardAction.prototype.selectFake = function selectFake() {
var _this = this;
+ var isRTL = document.documentElement.getAttribute('dir') == 'rtl';
+
this.removeFake();
this.fakeHandler = document.body.addEventListener('click', function () {
@@ -428,8 +432,16 @@ var ClipboardAction = (function () {
});
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.left = '-9999px';
+ 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;
@@ -665,15 +677,17 @@ var Clipboard = (function (_Emitter) {
*/
Clipboard.prototype.onClick = function onClick(e) {
+ var trigger = e.delegateTarget || e.currentTarget;
+
if (this.clipboardAction) {
this.clipboardAction = null;
}
this.clipboardAction = new _clipboardAction2['default']({
- action: this.action(e.target),
- target: this.target(e.target),
- text: this.text(e.target),
- trigger: e.target,
+ action: this.action(trigger),
+ target: this.target(trigger),
+ text: this.text(trigger),
+ trigger: trigger,
emitter: this
});
};
@@ -725,6 +739,7 @@ var Clipboard = (function (_Emitter) {
return Clipboard;
})(_tinyEmitter2['default']);
+exports['default'] = Clipboard;
function getAttributeValue(suffix, element) {
var attribute = 'data-clipboard-' + suffix;
@@ -734,9 +749,7 @@ function getAttributeValue(suffix, element) {
return element.getAttribute(attribute);
}
-
-exports['default'] = Clipboard;
module.exports = exports['default'];
-},{"./clipboard-action":8,"good-listener":5,"tiny-emitter":7}]},{},[9])(9)
+},{"./clipboard-action":8,"good-listener":4,"tiny-emitter":7}]},{},[9])(9)
});
\ No newline at end of file
diff --git a/dist/clipboard.min.js b/dist/clipboard.min.js
index 4ab5cc4..15210c8 100644
--- a/dist/clipboard.min.js
+++ b/dist/clipboard.min.js
@@ -1,7 +1,7 @@
/*!
- * clipboard.js v1.5.2
+ * clipboard.js v1.5.8
* https://zenorocha.github.io/clipboard.js
*
* Licensed MIT © Zeno Rocha
*/
-!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var e;e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,e.Clipboard=t()}}(function(){var t,e,n;return function t(e,n,r){function o(a,c){if(!n[a]){if(!e[a]){var s="function"==typeof require&&require;if(!c&&s)return s(a,!0);if(i)return i(a,!0);var u=new Error("Cannot find module '"+a+"'");throw u.code="MODULE_NOT_FOUND",u}var l=n[a]={exports:{}};e[a][0].call(l.exports,function(t){var n=e[a][1][t];return o(n?n:t)},l,l.exports,t,e,n,r)}return n[a].exports}for(var i="function"==typeof require&&require,a=0;ar;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;a>i;i++)r[i].fn!==e&&r[i].fn._!==e&&o.push(r[i]);return o.length?n[t]=o:delete n[t],this}},e.exports=r},{}],8:[function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}n.__esModule=!0;var i=function(){function t(t,e){for(var n=0;nr;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;a>i;i++)r[i].fn!==e&&r[i].fn._!==e&&o.push(r[i]);return o.length?n[t]=o:delete n[t],this}},e.exports=r},{}],8:[function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}n.__esModule=!0;var i=function(){function t(t,e){for(var n=0;n 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.left = '-9999px';
+ 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;
@@ -192,5 +202,3 @@ class ClipboardAction {
this.removeFake();
}
}
-
-export default ClipboardAction;
diff --git a/src/clipboard.js b/src/clipboard.js
index da513be..517091a 100644
--- a/src/clipboard.js
+++ b/src/clipboard.js
@@ -6,7 +6,7 @@ import listen from 'good-listener';
* Base class which takes one or more elements, adds event listeners to them,
* and instantiates a new `ClipboardAction` on each click.
*/
-class Clipboard extends Emitter {
+export default class Clipboard extends Emitter {
/**
* @param {String|HTMLElement|HTMLCollection|NodeList} trigger
* @param {Object} options
@@ -42,15 +42,17 @@ class Clipboard extends Emitter {
* @param {Event} e
*/
onClick(e) {
+ let trigger = e.delegateTarget || e.currentTarget;
+
if (this.clipboardAction) {
this.clipboardAction = null;
}
this.clipboardAction = new ClipboardAction({
- action : this.action(e.target),
- target : this.target(e.target),
- text : this.text(e.target),
- trigger : e.target,
+ action : this.action(trigger),
+ target : this.target(trigger),
+ text : this.text(trigger),
+ trigger : trigger,
emitter : this
});
}
@@ -111,5 +113,3 @@ function getAttributeValue(suffix, element) {
return element.getAttribute(attribute);
}
-
-export default Clipboard;
diff --git a/test/clipboard-action.js b/test/clipboard-action.js
index b1b5781..4797abb 100644
--- a/test/clipboard-action.js
+++ b/test/clipboard-action.js
@@ -57,6 +57,19 @@ describe('ClipboardAction', () => {
done();
}
});
+
+ it('should set the position right style property', done => {
+ // Set document direction
+ document.documentElement.setAttribute('dir', 'rtl');
+
+ let clip = new ClipboardAction({
+ emitter: new Emitter(),
+ text: 'foo'
+ });
+
+ assert.equal(clip.fakeElem.style.right, '-9999px');
+ done();
+ });
});
describe('#set action', () => {
diff --git a/test/clipboard.js b/test/clipboard.js
index c3ffcea..e35a7c5 100644
--- a/test/clipboard.js
+++ b/test/clipboard.js
@@ -9,8 +9,14 @@ describe('Clipboard', () => {
global.button.setAttribute('data-clipboard-text', 'foo');
document.body.appendChild(global.button);
+ global.span = document.createElement('span');
+ global.span.innerHTML = 'bar';
+
+ global.button.appendChild(span);
+
global.event = {
- target: global.button
+ target: global.button,
+ currentTarget: global.button
};
});
@@ -63,7 +69,15 @@ describe('Clipboard', () => {
assert.instanceOf(clipboard.clipboardAction, ClipboardAction);
});
- it('should throws exception target', done => {
+ 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 {
var clipboard = new Clipboard('.btn', {
target: function() {