Compare commits

...

14 Commits

Author SHA1 Message Date
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
11 changed files with 402 additions and 333 deletions

View File

@@ -1,6 +1,6 @@
{ {
"name": "clipboard", "name": "clipboard",
"version": "1.5.4", "version": "1.5.6",
"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",

659
dist/clipboard.js vendored
View File

@@ -1,5 +1,5 @@
/*! /*!
* clipboard.js v1.5.4 * clipboard.js v1.5.6
* https://zenorocha.github.io/clipboard.js * https://zenorocha.github.io/clipboard.js
* *
* Licensed MIT © Zeno Rocha * Licensed MIT © Zeno Rocha
@@ -16,48 +16,7 @@ module.exports = function (element, selector, checkYoSelf) {
} }
} }
},{"matches-selector":2}],2:[function(require,module,exports){ },{"matches-selector":5}],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){
var closest = require('closest'); var closest = require('closest');
/** /**
@@ -67,16 +26,17 @@ var closest = require('closest');
* @param {String} selector * @param {String} selector
* @param {String} type * @param {String} type
* @param {Function} callback * @param {Function} callback
* @param {Boolean} useCapture
* @return {Object} * @return {Object}
*/ */
function delegate(element, selector, type, callback) { function delegate(element, selector, type, callback, useCapture) {
var listenerFn = listener.apply(this, arguments); var listenerFn = listener.apply(this, arguments);
element.addEventListener(type, listenerFn); element.addEventListener(type, listenerFn, useCapture);
return { return {
destroy: function() { destroy: function() {
element.removeEventListener(type, listenerFn); element.removeEventListener(type, listenerFn, useCapture);
} }
} }
} }
@@ -102,7 +62,7 @@ function listener(element, selector, type, callback) {
module.exports = delegate; module.exports = delegate;
},{"closest":1}],4:[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.
* *
@@ -147,13 +107,13 @@ exports.string = function(value) {
* @param {Object} value * @param {Object} value
* @return {Boolean} * @return {Boolean}
*/ */
exports.function = function(value) { exports.fn = function(value) {
var type = Object.prototype.toString.call(value); var type = Object.prototype.toString.call(value);
return type === '[object Function]'; return type === '[object Function]';
}; };
},{}],5:[function(require,module,exports){ },{}],4:[function(require,module,exports){
var is = require('./is'); var is = require('./is');
var delegate = require('delegate'); var delegate = require('delegate');
@@ -175,7 +135,7 @@ function listen(target, type, callback) {
throw new TypeError('Second argument must be a String'); 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'); throw new TypeError('Third argument must be a Function');
} }
@@ -250,16 +210,62 @@ function listenSelector(selector, type, callback) {
module.exports = listen; 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) { function select(element) {
var selectedText; var selectedText;
if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') { if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {
element.select(); element.focus();
element.setSelectionRange(0, element.value.length);
selectedText = element.value; selectedText = element.value;
} }
else { else {
if (element.hasAttribute('contenteditable')) {
element.focus();
}
var selection = window.getSelection(); var selection = window.getSelection();
var range = document.createRange(); var range = document.createRange();
@@ -346,24 +352,28 @@ module.exports = E;
},{}],8:[function(require,module,exports){ },{}],8:[function(require,module,exports){
'use strict'; 'use strict';
exports.__esModule = true; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); 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 _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } Object.defineProperty(exports, "__esModule", {
value: true
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } });
var _select = require('select'); var _select = require('select');
var _select2 = _interopRequireDefault(_select); var _select2 = _interopRequireDefault(_select);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/** /**
* Inner class which performs selection from either `text` or `target` * Inner class which performs selection from either `text` or `target`
* properties and then executes copy or cut operations. * properties and then executes copy or cut operations.
*/ */
var ClipboardAction = (function () { var ClipboardAction = function () {
/** /**
* @param {Object} options * @param {Object} options
*/ */
@@ -380,152 +390,171 @@ var ClipboardAction = (function () {
* @param {Object} options * @param {Object} options
*/ */
ClipboardAction.prototype.resolveOptions = function resolveOptions() {
var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
this.action = options.action;
this.emitter = options.emitter;
this.target = options.target;
this.text = options.text;
this.trigger = options.trigger;
this.selectedText = '';
};
/**
* Decides which selection strategy is going to be applied based
* on the existence of `text` and `target` properties.
*/
ClipboardAction.prototype.initSelection = function initSelection() {
if (this.text && this.target) {
throw new Error('Multiple attributes declared, use either "target" or "text"');
} else if (this.text) {
this.selectFake();
} else if (this.target) {
this.selectTarget();
} else {
throw new Error('Missing required attributes, use either "target" or "text"');
}
};
/**
* Creates a fake textarea element, sets its value from `text` property,
* and makes a selection on it.
*/
ClipboardAction.prototype.selectFake = function selectFake() {
var _this = this;
this.removeFake();
this.fakeHandler = document.body.addEventListener('click', function () {
return _this.removeFake();
});
this.fakeElem = document.createElement('textarea');
this.fakeElem.style.position = 'absolute';
this.fakeElem.style.left = '-9999px';
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 = _select2['default'](this.fakeElem);
this.copyText();
};
/**
* Only removes the fake element after another click event, that way
* a user can hit `Ctrl+C` to copy because selection still exists.
*/
ClipboardAction.prototype.removeFake = function removeFake() {
if (this.fakeHandler) {
document.body.removeEventListener('click');
this.fakeHandler = null;
}
if (this.fakeElem) {
document.body.removeChild(this.fakeElem);
this.fakeElem = null;
}
};
/**
* Selects the content from element passed on `target` property.
*/
ClipboardAction.prototype.selectTarget = function selectTarget() {
this.selectedText = _select2['default'](this.target);
this.copyText();
};
/**
* Executes the copy operation based on the current selection.
*/
ClipboardAction.prototype.copyText = function copyText() {
var succeeded = undefined;
try {
succeeded = document.execCommand(this.action);
} catch (err) {
succeeded = false;
}
this.handleResult(succeeded);
};
/**
* Fires an event based on the copy operation result.
* @param {Boolean} succeeded
*/
ClipboardAction.prototype.handleResult = function handleResult(succeeded) {
if (succeeded) {
this.emitter.emit('success', {
action: this.action,
text: this.selectedText,
trigger: this.trigger,
clearSelection: this.clearSelection.bind(this)
});
} else {
this.emitter.emit('error', {
action: this.action,
trigger: this.trigger,
clearSelection: this.clearSelection.bind(this)
});
}
};
/**
* Removes current selection and focus from `target` element.
*/
ClipboardAction.prototype.clearSelection = function clearSelection() {
if (this.target) {
this.target.blur();
}
window.getSelection().removeAllRanges();
};
/**
* Sets the `action` to be performed which can be either 'copy' or 'cut'.
* @param {String} action
*/
/**
* Destroy lifecycle.
*/
ClipboardAction.prototype.destroy = function destroy() {
this.removeFake();
};
_createClass(ClipboardAction, [{ _createClass(ClipboardAction, [{
key: 'resolveOptions',
value: function resolveOptions() {
var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
this.action = options.action;
this.emitter = options.emitter;
this.target = options.target;
this.text = options.text;
this.trigger = options.trigger;
this.selectedText = '';
}
/**
* Decides which selection strategy is going to be applied based
* on the existence of `text` and `target` properties.
*/
}, {
key: 'initSelection',
value: function initSelection() {
if (this.text && this.target) {
throw new Error('Multiple attributes declared, use either "target" or "text"');
} else if (this.text) {
this.selectFake();
} else if (this.target) {
this.selectTarget();
} else {
throw new Error('Missing required attributes, use either "target" or "text"');
}
}
/**
* Creates a fake textarea element, sets its value from `text` property,
* and makes a selection on it.
*/
}, {
key: 'selectFake',
value: function selectFake() {
var _this = this;
var isRTL = document.documentElement.getAttribute('dir') == 'rtl';
this.removeFake();
this.fakeHandler = document.body.addEventListener('click', function () {
return _this.removeFake();
});
this.fakeElem = document.createElement('textarea');
this.fakeElem.style.position = 'absolute';
this.fakeElem.style[isRTL ? 'right' : 'left'] = '-9999px';
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();
}
/**
* Only removes the fake element after another click event, that way
* a user can hit `Ctrl+C` to copy because selection still exists.
*/
}, {
key: 'removeFake',
value: function removeFake() {
if (this.fakeHandler) {
document.body.removeEventListener('click');
this.fakeHandler = null;
}
if (this.fakeElem) {
document.body.removeChild(this.fakeElem);
this.fakeElem = null;
}
}
/**
* Selects the content from element passed on `target` property.
*/
}, {
key: 'selectTarget',
value: function selectTarget() {
this.selectedText = (0, _select2.default)(this.target);
this.copyText();
}
/**
* Executes the copy operation based on the current selection.
*/
}, {
key: 'copyText',
value: function copyText() {
var succeeded = undefined;
try {
succeeded = document.execCommand(this.action);
} catch (err) {
succeeded = false;
}
this.handleResult(succeeded);
}
/**
* Fires an event based on the copy operation result.
* @param {Boolean} succeeded
*/
}, {
key: 'handleResult',
value: function handleResult(succeeded) {
if (succeeded) {
this.emitter.emit('success', {
action: this.action,
text: this.selectedText,
trigger: this.trigger,
clearSelection: this.clearSelection.bind(this)
});
} else {
this.emitter.emit('error', {
action: this.action,
trigger: this.trigger,
clearSelection: this.clearSelection.bind(this)
});
}
}
/**
* Removes current selection and focus from `target` element.
*/
}, {
key: 'clearSelection',
value: function clearSelection() {
if (this.target) {
this.target.blur();
}
window.getSelection().removeAllRanges();
}
/**
* Sets the `action` to be performed which can be either 'copy' or 'cut'.
* @param {String} action
*/
}, {
key: 'destroy',
/**
* Destroy lifecycle.
*/
value: function destroy() {
this.removeFake();
}
}, {
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 ? 'copy' : arguments[0];
@@ -535,12 +564,13 @@ var ClipboardAction = (function () {
if (this._action !== 'copy' && this._action !== 'cut') { if (this._action !== 'copy' && this._action !== 'cut') {
throw new Error('Invalid "action" value, use either "copy" or "cut"'); throw new Error('Invalid "action" value, use either "copy" or "cut"');
} }
}, }
/** /**
* Gets the `action` property. * Gets the `action` property.
* @return {String} * @return {String}
*/ */
,
get: function get() { get: function get() {
return this._action; return this._action;
} }
@@ -550,43 +580,42 @@ var ClipboardAction = (function () {
* that will be have its content copied. * that will be have its content copied.
* @param {Element} target * @param {Element} target
*/ */
}, { }, {
key: 'target', key: 'target',
set: function set(target) { set: function set(target) {
if (target !== undefined) { if (target !== undefined) {
if (target && typeof target === 'object' && target.nodeType === 1) { if (target && (typeof target === 'undefined' ? 'undefined' : _typeof(target)) === 'object' && target.nodeType === 1) {
this._target = target; this._target = target;
} else { } else {
throw new Error('Invalid "target" value, use a valid Element'); throw new Error('Invalid "target" value, use a valid Element');
} }
} }
}, }
/** /**
* Gets the `target` property. * Gets the `target` property.
* @return {String|HTMLElement} * @return {String|HTMLElement}
*/ */
,
get: function get() { get: function get() {
return this._target; return this._target;
} }
}]); }]);
return ClipboardAction; return ClipboardAction;
})(); }();
exports['default'] = ClipboardAction; exports.default = ClipboardAction;
module.exports = exports['default'];
},{"select":6}],9:[function(require,module,exports){ },{"select":6}],9:[function(require,module,exports){
'use strict'; 'use strict';
exports.__esModule = true; 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 _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } Object.defineProperty(exports, "__esModule", {
value: true
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } });
function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var _clipboardAction = require('./clipboard-action'); var _clipboardAction = require('./clipboard-action');
@@ -600,12 +629,20 @@ var _goodListener = require('good-listener');
var _goodListener2 = _interopRequireDefault(_goodListener); var _goodListener2 = _interopRequireDefault(_goodListener);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
/** /**
* Base class which takes one or more elements, adds event listeners to them, * Base class which takes one or more elements, adds event listeners to them,
* and instantiates a new `ClipboardAction` on each click. * and instantiates a new `ClipboardAction` on each click.
*/ */
var Clipboard = (function (_Emitter) { var Clipboard = function (_Emitter) {
_inherits(Clipboard, _Emitter); _inherits(Clipboard, _Emitter);
/** /**
@@ -616,113 +653,130 @@ var Clipboard = (function (_Emitter) {
function Clipboard(trigger, options) { function Clipboard(trigger, options) {
_classCallCheck(this, Clipboard); _classCallCheck(this, Clipboard);
_Emitter.call(this); var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(Clipboard).call(this));
this.resolveOptions(options); _this.resolveOptions(options);
this.listenClick(trigger); _this.listenClick(trigger);
return _this;
} }
/**
* Helper function to retrieve attribute value.
* @param {String} suffix
* @param {Element} element
*/
/** /**
* Defines if attributes would be resolved using internal setter functions * Defines if attributes would be resolved using internal setter functions
* or custom functions that were passed in the constructor. * or custom functions that were passed in the constructor.
* @param {Object} options * @param {Object} options
*/ */
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;
};
/**
* Adds a click event listener to the passed trigger.
* @param {String|HTMLElement|HTMLCollection|NodeList} trigger
*/
Clipboard.prototype.listenClick = function listenClick(trigger) {
var _this = this;
this.listener = _goodListener2['default'](trigger, 'click', function (e) {
return _this.onClick(e);
});
};
/**
* 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(trigger), * Adds a click event listener to the passed trigger.
target: this.target(trigger), * @param {String|HTMLElement|HTMLCollection|NodeList} trigger
text: this.text(trigger), */
trigger: trigger,
emitter: this
});
};
/** }, {
* Default `action` lookup function. key: 'listenClick',
* @param {Element} trigger value: function listenClick(trigger) {
*/ var _this2 = this;
Clipboard.prototype.defaultAction = function defaultAction(trigger) { this.listener = (0, _goodListener2.default)(trigger, 'click', function (e) {
return getAttributeValue('action', trigger); return _this2.onClick(e);
}; });
/**
* Default `target` lookup function.
* @param {Element} trigger
*/
Clipboard.prototype.defaultTarget = function defaultTarget(trigger) {
var selector = getAttributeValue('target', trigger);
if (selector) {
return document.querySelector(selector);
} }
};
/** /**
* Default `text` lookup function. * Defines a new `ClipboardAction` on each click event.
* @param {Element} trigger * @param {Event} e
*/ */
Clipboard.prototype.defaultText = function defaultText(trigger) { }, {
return getAttributeValue('text', trigger); key: 'onClick',
}; value: function onClick(e) {
var trigger = e.delegateTarget || e.currentTarget;
/** if (this.clipboardAction) {
* Destroy lifecycle. 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(); trigger: trigger,
this.clipboardAction = null; emitter: this
});
} }
};
/**
* Default `action` lookup function.
* @param {Element} trigger
*/
}, {
key: 'defaultAction',
value: function defaultAction(trigger) {
return getAttributeValue('action', trigger);
}
/**
* Default `target` lookup function.
* @param {Element} trigger
*/
}, {
key: 'defaultTarget',
value: function defaultTarget(trigger) {
var selector = getAttributeValue('target', trigger);
if (selector) {
return document.querySelector(selector);
}
}
/**
* Default `text` lookup function.
* @param {Element} trigger
*/
}, {
key: 'defaultText',
value: function defaultText(trigger) {
return getAttributeValue('text', trigger);
}
/**
* Destroy lifecycle.
*/
}, {
key: 'destroy',
value: function destroy() {
this.listener.destroy();
if (this.clipboardAction) {
this.clipboardAction.destroy();
this.clipboardAction = null;
}
}
}]);
return Clipboard; return Clipboard;
})(_tinyEmitter2['default']); }(_tinyEmitter2.default);
/**
* Helper function to retrieve attribute value.
* @param {String} suffix
* @param {Element} element
*/
exports.default = Clipboard;
function getAttributeValue(suffix, element) { function getAttributeValue(suffix, element) {
var attribute = 'data-clipboard-' + suffix; var attribute = 'data-clipboard-' + suffix;
@@ -733,8 +787,5 @@ function getAttributeValue(suffix, element) {
return element.getAttribute(attribute); return element.getAttribute(attribute);
} }
exports['default'] = Clipboard; },{"./clipboard-action":8,"good-listener":4,"tiny-emitter":7}]},{},[9])(9)
module.exports = exports['default'];
},{"./clipboard-action":8,"good-listener":5,"tiny-emitter":7}]},{},[9])(9)
}); });

File diff suppressed because one or more lines are too long

View File

@@ -19,7 +19,9 @@ module.exports = function(karma) {
browserify: { browserify: {
debug: true, debug: true,
transform: ['babelify'] transform: [
['babelify', { presets: ['es2015'] }]
]
}, },
browsers: ['PhantomJS'] browsers: ['PhantomJS']

View File

@@ -3,10 +3,10 @@
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.4", version: "1.5.6",
git: "https://github.com/zenorocha/clipboard.js" git: "https://github.com/zenorocha/clipboard.js"
}); });
Package.onUse(function(api) { Package.onUse(function(api) {
api.addFiles("dist/clipboard.min.js", "client"); api.addFiles("dist/clipboard.js", "client");
}); });

View File

@@ -1,6 +1,6 @@
{ {
"name": "clipboard", "name": "clipboard",
"version": "1.5.4", "version": "1.5.6",
"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,37 @@
"cut" "cut"
], ],
"dependencies": { "dependencies": {
"good-listener": "^1.1.4", "good-listener": "^1.1.6",
"select": "^1.0.4", "select": "^1.0.6",
"tiny-emitter": "^1.0.0" "tiny-emitter": "^1.0.0"
}, },
"devDependencies": { "devDependencies": {
"babel": "^5.8.29", "babel": "^6.3.26",
"babelify": "^6.3.0", "babel-cli": "^6.4.5",
"browserify": "^11.2.0", "babel-preset-es2015": "^6.3.13",
"babelify": "^7.2.0",
"bannerify": "Vekat/bannerify#feature-option",
"browserify": "^13.0.0",
"chai": "^3.4.1",
"karma": "^0.13.10", "karma": "^0.13.10",
"karma-browserify": "^4.4.0", "karma-browserify": "^5.0.1",
"karma-chai": "^0.1.0", "karma-chai": "^0.1.0",
"karma-mocha": "^0.2.0", "karma-mocha": "^0.2.0",
"karma-phantomjs-launcher": "^0.2.1", "karma-phantomjs-launcher": "^1.0.0",
"karma-sinon": "^1.0.4", "karma-sinon": "^1.0.4",
"mocha": "^2.3.3", "mocha": "^2.3.3",
"phantomjs-polyfill": "0.0.1", "phantomjs-polyfill": "0.0.1",
"phantomjs-prebuilt": "^2.1.3",
"sinon": "^1.17.2",
"uglify-js": "^2.4.24", "uglify-js": "^2.4.24",
"watchify": "^3.4.0", "watchify": "^3.7.0"
"bannerify": "Vekat/bannerify#feature-option"
}, },
"scripts": { "scripts": {
"build": "npm run build-debug && npm run build-min", "build": "npm run build-debug && npm run build-min",
"build-debug": "browserify src/clipboard.js -s Clipboard -t [babelify --loose all] -p [bannerify --file .banner ] -o dist/clipboard.js", "build-debug": "browserify src/clipboard.js -s Clipboard -t [babelify --presets es2015] -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-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 --loose all] -o dist/clipboard.js -v", "build-watch": "watchify src/clipboard.js -s Clipboard -t [babelify --presets es2015] -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 --presets es2015"
} }
} }

View File

@@ -151,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 ```js
var clipboard = new Clipboard('.btn'); 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` * Inner class which performs selection from either `text` or `target`
* properties and then executes copy or cut operations. * properties and then executes copy or cut operations.
*/ */
class ClipboardAction { export default class ClipboardAction {
/** /**
* @param {Object} options * @param {Object} options
*/ */
@@ -51,13 +51,15 @@ class ClipboardAction {
* and makes a selection on it. * and makes a selection on it.
*/ */
selectFake() { selectFake() {
let isRTL = document.documentElement.getAttribute('dir') == 'rtl';
this.removeFake(); this.removeFake();
this.fakeHandler = document.body.addEventListener('click', () => this.removeFake()); this.fakeHandler = document.body.addEventListener('click', () => this.removeFake());
this.fakeElem = document.createElement('textarea'); this.fakeElem = document.createElement('textarea');
this.fakeElem.style.position = 'absolute'; this.fakeElem.style.position = 'absolute';
this.fakeElem.style.left = '-9999px'; this.fakeElem.style[ isRTL ? 'right' : 'left' ] = '-9999px';
this.fakeElem.style.top = (window.pageYOffset || document.documentElement.scrollTop) + 'px'; this.fakeElem.style.top = (window.pageYOffset || document.documentElement.scrollTop) + 'px';
this.fakeElem.setAttribute('readonly', ''); this.fakeElem.setAttribute('readonly', '');
this.fakeElem.value = this.text; this.fakeElem.value = this.text;
@@ -192,5 +194,3 @@ class ClipboardAction {
this.removeFake(); this.removeFake();
} }
} }
export default ClipboardAction;

View File

@@ -6,7 +6,7 @@ import listen from 'good-listener';
* Base class which takes one or more elements, adds event listeners to them, * Base class which takes one or more elements, adds event listeners to them,
* and instantiates a new `ClipboardAction` on each click. * 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 {String|HTMLElement|HTMLCollection|NodeList} trigger
* @param {Object} options * @param {Object} options
@@ -42,7 +42,7 @@ class Clipboard extends Emitter {
* @param {Event} e * @param {Event} e
*/ */
onClick(e) { onClick(e) {
var trigger = e.delegateTarget || e.currentTarget; let trigger = e.delegateTarget || e.currentTarget;
if (this.clipboardAction) { if (this.clipboardAction) {
this.clipboardAction = null; this.clipboardAction = null;
@@ -113,5 +113,3 @@ function getAttributeValue(suffix, element) {
return element.getAttribute(attribute); return element.getAttribute(attribute);
} }
export default Clipboard;

View File

@@ -57,6 +57,19 @@ describe('ClipboardAction', () => {
done(); 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', () => { describe('#set action', () => {

View File

@@ -77,7 +77,7 @@ describe('Clipboard', () => {
assert.instanceOf(clipboard.clipboardAction, ClipboardAction); assert.instanceOf(clipboard.clipboardAction, ClipboardAction);
}); });
it('should throws exception target', done => { it('should throw an exception when target is invalid', done => {
try { try {
var clipboard = new Clipboard('.btn', { var clipboard = new Clipboard('.btn', {
target: function() { target: function() {