Compare commits

..

39 Commits

Author SHA1 Message Date
Zeno Rocha
7e37c95121 Release v1.5.8 2016-02-04 11:28:33 -08:00
Zeno Rocha
bc9bcdd678 Adds explanations on textarea styling #143 #179 #180 2016-02-04 11:25:00 -08:00
Zeno Rocha
4c9e29a0dc Resets invisible textarea's paddings and margins #179 2016-02-04 11:09:10 -08:00
speedplane
bd6dc9eb9f Prevent auto-zooming on an iphone by making the text area size appropriate size. Fixes Issue 180. 2016-02-04 11:12:04 -05:00
Zeno Rocha
a88bb77be4 Release v1.5.7 2016-02-03 08:31:41 -08:00
Zeno Rocha
e86dc2caa2 Revert "Upgrades to Babel 6"
This reverts commit ee1eb455f4.
2016-02-03 08:22:35 -08:00
Zeno Rocha
8392a7ba1c Release v1.5.6 2016-02-02 13:44:26 -08:00
RAFIE Younes
31e3622e17 Fixed RTL issue #161 2016-02-02 13:27:11 -08:00
Zeno Rocha
ee1eb455f4 Upgrades to Babel 6 2016-02-02 13:11:25 -08:00
Zeno Rocha
d50f2fb73f Updates good-listener
Fixes #170
2016-02-02 12:52:17 -08:00
Zeno Rocha
c8221c742d Serves the unminified version for Meteor
Fixes #167
2016-01-21 08:21:44 -08:00
Zeno Rocha
efc22cf651 Merge pull request #150 from nettofarah/patch-1
Add a bit more clarity to Invalid Target test
2015-12-17 10:48:14 -08:00
Netto Farah
4b27a72dce Add a bit more clarity to Invalid Target test 2015-12-13 13:11:02 -08:00
Zeno Rocha
c12c610b22 Merge pull request #134 from hmln/minor-readme-change
Fix typo in readme.
2015-11-19 07:21:32 -08:00
hmln
1d772a0cbe Fix typo in readme. 2015-11-19 00:38:20 -03:00
Zeno Rocha
d9254459b7 Merge pull request #131 from oskarcieslik/es2015_minor_fixes
Small ES2015 changes
2015-11-14 12:25:53 -06:00
Oskar Cieslik (rpawfuiml)
2aa163b1d0 Small ES2015 changes ;). 2015-11-13 22:01:59 +01:00
Zeno Rocha
783dc6f3cf Adds devDependencies since peerDependencies does not work anymore 2015-11-13 01:39:19 -08:00
Zeno Rocha
3188ffbce3 Release v1.5.5 2015-11-13 01:20:15 -08:00
Zeno Rocha
5dba68634e Fixes a bug where non-editable elements were being focused 2015-11-13 01:20:02 -08:00
Zeno Rocha
a12a056ef6 Release v1.5.4 2015-11-13 00:25:35 -08:00
Zeno Rocha
cb4301658c Updates delegate package which now exposes e.delegateTarget property #120 2015-11-13 00:24:46 -08:00
Zeno Rocha
5efcdf2810 Merge pull request #120 from pawlufelice/fix_event_target
use event's currentTarget instead of target
2015-11-13 00:20:20 -08:00
Zeno Rocha
72926580c3 Updates meteor version #123 2015-11-12 09:58:10 -08:00
Zeno Rocha
4967f118fe Release v1.5.3 2015-11-12 09:57:35 -08:00
Zeno Rocha
44d59b34a2 Merge pull request #123 from alippai/patch-1
Bump npm version to match the bower version.
2015-11-12 09:57:29 -08:00
Ádám Lippai
9d6375d20e Bump npm version to match the others. 2015-11-10 11:08:35 +01:00
Paul Felice
37136663df use event's currentTarget instead of target 2015-11-06 15:49:21 +01:00
Zeno Rocha
db575bb4df Removes babelify from being a dependency to a devDependency #15 #105 2015-10-28 13:06:14 -07:00
Zeno Rocha
bb6c4c0e7c Release v1.5.2 2015-10-28 12:57:47 -07:00
Zeno Rocha
03ee9829e0 Removes browserify tests 2015-10-28 12:56:52 -07:00
Zeno Rocha
24f6e1f541 Moves babel to devDependencies 2015-10-28 12:56:38 -07:00
Zeno Rocha
5bdfff6375 Ignores unnecessary files on bower and npm 2015-10-28 12:56:21 -07:00
Zeno Rocha
4b73122f81 Provides a transpiled version to npm so browserify and webpack users do not have to transpile by themselves
Fixes #15 #27 #105
2015-10-28 12:54:29 -07:00
Zeno Rocha
171f438f22 Release v1.5.1 2015-10-27 09:32:43 -07:00
Zeno Rocha
42a459402c Release v1.5.0 2015-10-26 23:04:54 -07:00
Zeno Rocha
b26cdb3b41 Allows HTML elements to be passed in the constructor - Fixes #25 2015-10-26 23:02:29 -07:00
Zeno Rocha
57c7fcf9a4 Adds a bunch of demos 2015-10-26 22:53:03 -07:00
Zeno Rocha
6b1f6b22a6 Allows HTML elements to be passed in the constructor - Fixes #25 2015-10-26 01:06:29 -07:00
21 changed files with 575 additions and 203 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
lib
npm-debug.log
bower_components
node_modules

View File

@@ -1,6 +1,7 @@
/.*/
/example/
/demo/
/test/
/.*
/bower.json
/karma.conf.js
/src

View File

@@ -1,16 +1,18 @@
{
"name": "clipboard",
"version": "1.4.3",
"version": "1.5.8",
"description": "Modern copy to clipboard. No Flash. Just 2kb",
"license": "MIT",
"main": "dist/clipboard.js",
"ignore": [
"/.*/",
"/example/",
"/demo/",
"/test/",
"/.*",
"/bower.json",
"/karma.conf.js"
"/karma.conf.js",
"/src",
"/lib"
],
"keywords": [
"clipboard",

View File

@@ -0,0 +1,30 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>constructor-node</title>
</head>
<body>
<!-- 1. Define some markup -->
<div id="btn" data-clipboard-text="1">
<span>Copy</span>
</div>
<!-- 2. Include library -->
<script src="../dist/clipboard.min.js"></script>
<!-- 3. Instantiate clipboard by passing a HTML element -->
<script>
var btn = document.getElementById('btn');
var clipboard = new Clipboard(btn);
clipboard.on('success', function(e) {
console.log(e);
});
clipboard.on('error', function(e) {
console.log(e);
});
</script>
</body>
</html>

View File

@@ -0,0 +1,30 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>constructor-nodelist</title>
</head>
<body>
<!-- 1. Define some markup -->
<button data-clipboard-text="1">Copy</button>
<button data-clipboard-text="2">Copy</button>
<button data-clipboard-text="3">Copy</button>
<!-- 2. Include library -->
<script src="../dist/clipboard.min.js"></script>
<!-- 3. Instantiate clipboard by passing a list of HTML elements -->
<script>
var btns = document.querySelectorAll('button');
var clipboard = new Clipboard(btns);
clipboard.on('success', function(e) {
console.log(e);
});
clipboard.on('error', function(e) {
console.log(e);
});
</script>
</body>
</html>

View File

@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>constructor-selector</title>
</head>
<body>
<!-- 1. Define some markup -->
<button class="btn" data-clipboard-text="1">Copy</button>
<button class="btn" data-clipboard-text="2">Copy</button>
<button class="btn" data-clipboard-text="3">Copy</button>
<!-- 2. Include library -->
<script src="../dist/clipboard.min.js"></script>
<!-- 3. Instantiate clipboard by passing a string selector -->
<script>
var clipboard = new Clipboard('.btn');
clipboard.on('success', function(e) {
console.log(e);
});
clipboard.on('error', function(e) {
console.log(e);
});
</script>
</body>
</html>

32
demo/function-target.html Normal file
View File

@@ -0,0 +1,32 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>function-target</title>
</head>
<body>
<!-- 1. Define some markup -->
<button class="btn">Copy</button>
<div>hello</div>
<!-- 2. Include library -->
<script src="../dist/clipboard.min.js"></script>
<!-- 3. Instantiate clipboard -->
<script>
var clipboard = new Clipboard('.btn', {
target: function() {
return document.querySelector('div');
}
});
clipboard.on('success', function(e) {
console.log(e);
});
clipboard.on('error', function(e) {
console.log(e);
});
</script>
</body>
</html>

31
demo/function-text.html Normal file
View File

@@ -0,0 +1,31 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>function-text</title>
</head>
<body>
<!-- 1. Define some markup -->
<button class="btn">Copy</button>
<!-- 2. Include library -->
<script src="../dist/clipboard.min.js"></script>
<!-- 3. Instantiate clipboard -->
<script>
var clipboard = new Clipboard('.btn', {
text: function() {
return 'to be or not to be';
}
});
clipboard.on('success', function(e) {
console.log(e);
});
clipboard.on('error', function(e) {
console.log(e);
});
</script>
</body>
</html>

28
demo/target-div.html Normal file
View File

@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>target-div</title>
</head>
<body>
<!-- 1. Define some markup -->
<div>hello</div>
<button class="btn" data-clipboard-action="copy" data-clipboard-target="div">Copy</button>
<!-- 2. Include library -->
<script src="../dist/clipboard.min.js"></script>
<!-- 3. Instantiate clipboard -->
<script>
var clipboard = new Clipboard('.btn');
clipboard.on('success', function(e) {
console.log(e);
});
clipboard.on('error', function(e) {
console.log(e);
});
</script>
</body>
</html>

28
demo/target-input.html Normal file
View File

@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>target-input</title>
</head>
<body>
<!-- 1. Define some markup -->
<input id="foo" type="text" value="hello">
<button class="btn" data-clipboard-action="copy" data-clipboard-target="#foo">Copy</button>
<!-- 2. Include library -->
<script src="../dist/clipboard.min.js"></script>
<!-- 3. Instantiate clipboard -->
<script>
var clipboard = new Clipboard('.btn');
clipboard.on('success', function(e) {
console.log(e);
});
clipboard.on('error', function(e) {
console.log(e);
});
</script>
</body>
</html>

28
demo/target-textarea.html Normal file
View File

@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>target-textarea</title>
</head>
<body>
<!-- 1. Define some markup -->
<textarea id="bar">hello</textarea>
<button class="btn" data-clipboard-action="cut" data-clipboard-target="#bar">Cut</button>
<!-- 2. Include library -->
<script src="../dist/clipboard.min.js"></script>
<!-- 3. Instantiate clipboard -->
<script>
var clipboard = new Clipboard('.btn');
clipboard.on('success', function(e) {
console.log(e);
});
clipboard.on('error', function(e) {
console.log(e);
});
</script>
</body>
</html>

322
dist/clipboard.js vendored
View File

@@ -1,5 +1,5 @@
/*!
* clipboard.js v1.4.3
* clipboard.js v1.5.8
* https://zenorocha.github.io/clipboard.js
*
* Licensed MIT © Zeno Rocha
@@ -16,7 +16,201 @@ module.exports = function (element, selector, checkYoSelf) {
}
}
},{"matches-selector":2}],2:[function(require,module,exports){
},{"matches-selector":5}],2:[function(require,module,exports){
var closest = require('closest');
/**
* Delegates event to a selector.
*
* @param {Element} element
* @param {String} selector
* @param {String} type
* @param {Function} callback
* @param {Boolean} useCapture
* @return {Object}
*/
function delegate(element, selector, type, callback, useCapture) {
var listenerFn = listener.apply(this, arguments);
element.addEventListener(type, listenerFn, useCapture);
return {
destroy: function() {
element.removeEventListener(type, listenerFn, useCapture);
}
}
}
/**
* Finds closest match and invokes callback.
*
* @param {Element} element
* @param {String} selector
* @param {String} type
* @param {Function} callback
* @return {Function}
*/
function listener(element, selector, type, callback) {
return function(e) {
e.delegateTarget = closest(e.target, selector, true);
if (e.delegateTarget) {
callback.call(element, e);
}
}
}
module.exports = delegate;
},{"closest":1}],3:[function(require,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;
};
/**
* Check if argument is a list of HTML elements.
*
* @param {Object} value
* @return {Boolean}
*/
exports.nodeList = function(value) {
var type = Object.prototype.toString.call(value);
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;
};
/**
* Check if argument is a function.
*
* @param {Object} value
* @return {Boolean}
*/
exports.fn = function(value) {
var type = Object.prototype.toString.call(value);
return type === '[object Function]';
};
},{}],4:[function(require,module,exports){
var is = require('./is');
var delegate = require('delegate');
/**
* 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');
}
if (!is.string(type)) {
throw new TypeError('Second argument must be a String');
}
if (!is.fn(callback)) {
throw new TypeError('Third argument must be a Function');
}
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);
return {
destroy: function() {
node.removeEventListener(type, callback);
}
}
}
/**
* 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);
});
return {
destroy: function() {
Array.prototype.forEach.call(nodeList, function(node) {
node.removeEventListener(type, callback);
});
}
}
}
/**
* 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);
}
module.exports = listen;
},{"./is":3,"delegate":2}],5:[function(require,module,exports){
/**
* Element prototype.
@@ -57,65 +251,37 @@ function match(el, selector) {
}
return false;
}
},{}],3:[function(require,module,exports){
var closest = require('closest');
/**
* Delegate event `type` to `selector`
* and invoke `fn(e)`. A callback function
* is returned which may be passed to `.unbind()`.
*
* @param {Element} el
* @param {String} selector
* @param {String} type
* @param {Function} fn
* @param {Boolean} capture
* @return {Function}
*/
exports.bind = function(el, selector, type, fn, capture){
return el.addEventListener(type, function(e){
var target = e.target || e.srcElement;
e.delegateTarget = closest(target, selector, true, el);
if (e.delegateTarget) fn.call(el, e);
}, capture);
};
/**
* Unbind event `type`'s callback `fn`.
*
* @param {Element} el
* @param {String} type
* @param {Function} fn
* @param {Boolean} capture
*/
exports.unbind = function(el, type, fn, capture){
el.removeEventListener(type, fn, capture);
};
},{"closest":1}],4:[function(require,module,exports){
},{}],6:[function(require,module,exports){
function select(element) {
var selection = window.getSelection();
var selectedText;
if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {
element.selectionStart = 0;
element.selectionEnd = element.value.length;
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();
range.selectNodeContents(element);
selection.removeAllRanges();
selection.addRange(range);
selectedText = selection.toString();
}
return selection.toString();
return selectedText;
}
module.exports = select;
},{}],5:[function(require,module,exports){
},{}],7:[function(require,module,exports){
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)
@@ -183,7 +349,7 @@ E.prototype = {
module.exports = E;
},{}],6:[function(require,module,exports){
},{}],8:[function(require,module,exports){
'use strict';
exports.__esModule = true;
@@ -257,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 () {
@@ -264,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;
@@ -417,7 +593,7 @@ var ClipboardAction = (function () {
exports['default'] = ClipboardAction;
module.exports = exports['default'];
},{"select":4}],7:[function(require,module,exports){
},{"select":6}],9:[function(require,module,exports){
'use strict';
exports.__esModule = true;
@@ -432,16 +608,16 @@ var _clipboardAction = require('./clipboard-action');
var _clipboardAction2 = _interopRequireDefault(_clipboardAction);
var _delegate = require('delegate');
var _delegate2 = _interopRequireDefault(_delegate);
var _tinyEmitter = require('tiny-emitter');
var _tinyEmitter2 = _interopRequireDefault(_tinyEmitter);
var _goodListener = require('good-listener');
var _goodListener2 = _interopRequireDefault(_goodListener);
/**
* Base class which takes a selector, delegates a click event to it,
* Base class which takes one or more elements, adds event listeners to them,
* and instantiates a new `ClipboardAction` on each click.
*/
@@ -449,17 +625,17 @@ var Clipboard = (function (_Emitter) {
_inherits(Clipboard, _Emitter);
/**
* @param {String} selector
* @param {String|HTMLElement|HTMLCollection|NodeList} trigger
* @param {Object} options
*/
function Clipboard(selector, options) {
function Clipboard(trigger, options) {
_classCallCheck(this, Clipboard);
_Emitter.call(this);
this.resolveOptions(options);
this.delegateClick(selector);
this.listenClick(trigger);
}
/**
@@ -483,42 +659,35 @@ var Clipboard = (function (_Emitter) {
};
/**
* Delegates a click event on the passed selector.
* @param {String} selector
* Adds a click event listener to the passed trigger.
* @param {String|HTMLElement|HTMLCollection|NodeList} trigger
*/
Clipboard.prototype.delegateClick = function delegateClick(selector) {
Clipboard.prototype.listenClick = function listenClick(trigger) {
var _this = this;
this.binding = _delegate2['default'].bind(document.body, selector, 'click', function (e) {
this.listener = _goodListener2['default'](trigger, 'click', function (e) {
return _this.onClick(e);
});
};
/**
* Undelegates a click event on body.
* @param {String} selector
*/
Clipboard.prototype.undelegateClick = function undelegateClick() {
_delegate2['default'].unbind(document.body, 'click', this.binding);
};
/**
* Defines a new `ClipboardAction` on each click event.
* @param {Event} e
*/
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.delegateTarget),
target: this.target(e.delegateTarget),
text: this.text(e.delegateTarget),
trigger: e.delegateTarget,
action: this.action(trigger),
target: this.target(trigger),
text: this.text(trigger),
trigger: trigger,
emitter: this
});
};
@@ -559,7 +728,7 @@ var Clipboard = (function (_Emitter) {
*/
Clipboard.prototype.destroy = function destroy() {
this.undelegateClick();
this.listener.destroy();
if (this.clipboardAction) {
this.clipboardAction.destroy();
@@ -570,6 +739,7 @@ var Clipboard = (function (_Emitter) {
return Clipboard;
})(_tinyEmitter2['default']);
exports['default'] = Clipboard;
function getAttributeValue(suffix, element) {
var attribute = 'data-clipboard-' + suffix;
@@ -579,9 +749,7 @@ function getAttributeValue(suffix, element) {
return element.getAttribute(attribute);
}
exports['default'] = Clipboard;
module.exports = exports['default'];
},{"./clipboard-action":6,"delegate":3,"tiny-emitter":5}]},{},[7])(7)
},{"./clipboard-action":8,"good-listener":4,"tiny-emitter":7}]},{},[9])(9)
});

File diff suppressed because one or more lines are too long

View File

@@ -3,10 +3,10 @@
Package.describe({
name: "zenorocha:clipboard",
summary: "Modern copy to clipboard. No Flash. Just 2kb.",
version: "1.4.2",
version: "1.5.8",
git: "https://github.com/zenorocha/clipboard.js"
});
Package.onUse(function(api) {
api.addFiles("dist/clipboard.min.js", "client");
api.addFiles("dist/clipboard.js", "client");
});

View File

@@ -1,34 +1,26 @@
{
"name": "clipboard",
"version": "1.4.3",
"version": "1.5.8",
"description": "Modern copy to clipboard. No Flash. Just 2kb",
"repository": "zenorocha/clipboard.js",
"license": "MIT",
"main": "dist/clipboard.js",
"browser": "src/clipboard.js",
"browserify": {
"transform": [
[
"babelify",
{
"loose": "all"
}
]
]
},
"main": "lib/clipboard.js",
"keywords": [
"clipboard",
"copy",
"cut"
],
"dependencies": {
"babelify": "^6.3.0",
"browserify": "^11.2.0",
"delegate": "^1.0.0",
"select": "^1.0.0",
"good-listener": "^1.1.6",
"select": "^1.0.6",
"tiny-emitter": "^1.0.0"
},
"devDependencies": {
"babel": "^5.8.29",
"babelify": "^6.3.0",
"bannerify": "Vekat/bannerify#feature-option",
"browserify": "^11.2.0",
"chai": "^3.4.1",
"karma": "^0.13.10",
"karma-browserify": "^4.4.0",
"karma-chai": "^0.1.0",
@@ -36,18 +28,18 @@
"karma-phantomjs-launcher": "^0.2.1",
"karma-sinon": "^1.0.4",
"mocha": "^2.3.3",
"phantomjs": "^1.9.18",
"phantomjs-polyfill": "0.0.1",
"sinon": "^1.17.2",
"uglify-js": "^2.4.24",
"watchify": "^3.4.0",
"bannerify": "Vekat/bannerify#feature-option"
"watchify": "^3.4.0"
},
"scripts": {
"build": "npm run build-debug && npm run build-min",
"build-debug": "browserify src/clipboard.js -s Clipboard -p [bannerify --file .banner ] -o dist/clipboard.js",
"build-debug": "browserify src/clipboard.js -s Clipboard -t [babelify --loose all] -p [bannerify --file .banner ] -o dist/clipboard.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 -o dist/clipboard.js -v",
"test": "npm run test-browser && npm run test-server",
"test-browser": "karma start --single-run",
"test-server": "mocha test/module-systems.js"
"build-watch": "watchify src/clipboard.js -s Clipboard -t [babelify --loose all] -o dist/clipboard.js -v",
"test": "karma start --single-run",
"prepublish": "babel src --out-dir lib --loose all"
}
}

View File

@@ -31,19 +31,13 @@ If you're not into package management, just [download a ZIP](https://github.com/
## Setup
First, include the script located on the `dist` folder.
First, include the script located on the `dist` folder or load it from [a third-party CDN provider](https://github.com/zenorocha/clipboard.js/wiki/CDN-Providers).
```html
<script src="dist/clipboard.min.js"></script>
```
Or load it from a CDN.
```html
<script src="https://cdn.rawgit.com/zenorocha/clipboard.js/master/dist/clipboard.min.js"></script>
```
Now, you need to instantiate it using a DOM selector. This selector corresponds to the trigger element(s), for example `<button class="btn">`.
Now, you need to instantiate it by [passing a DOM selector](https://github.com/zenorocha/clipboard.js/blob/master/demo/constructor-selector.html#L18), [HTML element](https://github.com/zenorocha/clipboard.js/blob/master/demo/constructor-node.html#L16-L17), or [list of HTML elements](https://github.com/zenorocha/clipboard.js/blob/master/demo/constructor-nodelist.html#L18-L19).
```js
new Clipboard('.btn');
@@ -157,7 +151,7 @@ new Clipboard('.btn', {
});
```
Also, with 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
var clipboard = new Clipboard('.btn');

View File

@@ -4,7 +4,7 @@ import select from 'select';
* Inner class which performs selection from either `text` or `target`
* properties and then executes copy or cut operations.
*/
class ClipboardAction {
export default class ClipboardAction {
/**
* @param {Object} options
*/
@@ -51,13 +51,23 @@ class ClipboardAction {
* and makes a selection on it.
*/
selectFake() {
let isRTL = document.documentElement.getAttribute('dir') == 'rtl';
this.removeFake();
this.fakeHandler = document.body.addEventListener('click', () => 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;

View File

@@ -1,21 +1,21 @@
import ClipboardAction from './clipboard-action';
import Delegate from 'delegate';
import Emitter from 'tiny-emitter';
import listen from 'good-listener';
/**
* Base class which takes a selector, delegates a click event to it,
* 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} selector
* @param {String|HTMLElement|HTMLCollection|NodeList} trigger
* @param {Object} options
*/
constructor(selector, options) {
constructor(trigger, options) {
super();
this.resolveOptions(options);
this.delegateClick(selector);
this.listenClick(trigger);
}
/**
@@ -30,19 +30,11 @@ class Clipboard extends Emitter {
}
/**
* Delegates a click event on the passed selector.
* @param {String} selector
* Adds a click event listener to the passed trigger.
* @param {String|HTMLElement|HTMLCollection|NodeList} trigger
*/
delegateClick(selector) {
this.binding = Delegate.bind(document.body, selector, 'click', (e) => this.onClick(e));
}
/**
* Undelegates a click event on body.
* @param {String} selector
*/
undelegateClick() {
Delegate.unbind(document.body, 'click', this.binding);
listenClick(trigger) {
this.listener = listen(trigger, 'click', (e) => this.onClick(e));
}
/**
@@ -50,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.delegateTarget),
target : this.target(e.delegateTarget),
text : this.text(e.delegateTarget),
trigger : e.delegateTarget,
action : this.action(trigger),
target : this.target(trigger),
text : this.text(trigger),
trigger : trigger,
emitter : this
});
}
@@ -95,7 +89,7 @@ class Clipboard extends Emitter {
* Destroy lifecycle.
*/
destroy() {
this.undelegateClick();
this.listener.destroy();
if (this.clipboardAction) {
this.clipboardAction.destroy();
@@ -119,5 +113,3 @@ function getAttributeValue(suffix, element) {
return element.getAttribute(attribute);
}
export default Clipboard;

View File

@@ -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', () => {

View File

@@ -1,6 +1,6 @@
import Clipboard from '../src/clipboard';
import ClipboardAction from '../src/clipboard-action';
import Delegate from 'delegate';
import listen from 'good-listener';
describe('Clipboard', () => {
before(() => {
@@ -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 = {
delegateTarget: global.button
target: global.button,
currentTarget: global.button
};
});
@@ -48,45 +54,10 @@ describe('Clipboard', () => {
});
});
describe('#delegateClick', () => {
before(() => {
global.spy = sinon.spy(Delegate, 'bind');
});
after(() => {
global.spy.restore();
});
it('should delegate a click event to the passed selector', () => {
let element = document.body;
let selector = '.btn';
let event = 'click';
let clipboard = new Clipboard(selector);
assert.ok(global.spy.calledOnce);
assert.ok(global.spy.calledWith(element, selector, event));
});
});
describe('#undelegateClick', () => {
before(() => {
global.spy = sinon.spy(Delegate, 'unbind');
});
after(() => {
global.spy.restore();
});
it('should undelegate a click event', () => {
let element = document.body;
let event = 'click';
describe('#listenClick', () => {
it('should add a click event listener to the passed selector', () => {
let clipboard = new Clipboard('.btn');
clipboard.undelegateClick();
assert.ok(global.spy.calledOnce);
assert.ok(global.spy.calledWith(element, event));
assert.isObject(clipboard.listener);
});
});
@@ -98,13 +69,22 @@ 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() {
return null;
}
});
clipboard.onClick(global.event);
}
catch(e) {

View File

@@ -1,15 +0,0 @@
var assert = require('chai').assert;
var browserify = require('browserify');
describe('CommonJS', function() {
it('should import the lib in a commonjs env without babel', function(done) {
browserify('./dist/clipboard.js').bundle(function(err) {
assert.equal(err, null);
done();
});
});
});
describe('AMD', function() {
// TODO: Write test case
});