Add modifier key option

The `modifier` option allows the Clipboard API to prevent the creation
of a new instance of `ClipboardAction` if the `click` event object is
not fired with a special key pressed.

It basically functions as a new type of event. The keys 'ctrl',
'shift', 'alt' and 'meta' are supported.
This commit is contained in:
Vitor Cortez 2015-11-03 00:18:05 -03:00
parent db575bb4df
commit 90968ce790
5 changed files with 106 additions and 63 deletions

125
dist/clipboard.js vendored
View File

@ -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');
/**
@ -106,7 +65,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.
*
@ -157,7 +116,7 @@ exports.function = function(value) {
return type === '[object Function]';
};
},{}],5:[function(require,module,exports){
},{}],4:[function(require,module,exports){
var is = require('./is');
var delegate = require('delegate');
@ -254,7 +213,48 @@ 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;
@ -288,24 +288,23 @@ function E () {
E.prototype = {
on: function (name, callback, ctx) {
var e = this.e || (this.e = {});
(e[name] || (e[name] = [])).push({
fn: callback,
ctx: ctx
});
return this;
},
once: function (name, callback, ctx) {
var self = this;
function listener () {
self.off(name, listener);
var fn = function () {
self.off(name, fn);
callback.apply(ctx, arguments);
};
listener._ = callback
return this.on(name, listener, ctx);
return this.on(name, fn, ctx);
},
emit: function (name) {
@ -313,11 +312,11 @@ E.prototype = {
var evtArr = ((this.e || (this.e = {}))[name] || []).slice();
var i = 0;
var len = evtArr.length;
for (i; i < len; i++) {
evtArr[i].fn.apply(evtArr[i].ctx, data);
}
return this;
},
@ -325,22 +324,21 @@ E.prototype = {
var e = this.e || (this.e = {});
var evts = e[name];
var liveEvents = [];
if (evts && callback) {
for (var i = 0, len = evts.length; i < len; i++) {
if (evts[i].fn !== callback && evts[i].fn._ !== callback)
liveEvents.push(evts[i]);
if (evts[i].fn !== callback) liveEvents.push(evts[i]);
}
}
// Remove event from queue to prevent memory leak
// Suggested by https://github.com/lazd
// Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910
(liveEvents.length)
(liveEvents.length)
? e[name] = liveEvents
: delete e[name];
return this;
}
};
@ -644,6 +642,7 @@ var Clipboard = (function (_Emitter) {
this.action = typeof options.action === 'function' ? options.action : this.defaultAction;
this.target = typeof options.target === 'function' ? options.target : this.defaultTarget;
this.text = typeof options.text === 'function' ? options.text : this.defaultText;
this.modifier = typeof options.modifier === 'string' && /^(alt|ctrl|shift|meta){1}$/.test(options.modifier) ? options.modifier : null;
};
/**
@ -669,6 +668,10 @@ var Clipboard = (function (_Emitter) {
this.clipboardAction = null;
}
if (this.modifier) {
if (e[this.modifier + 'Key'] === false) return;
}
this.clipboardAction = new _clipboardAction2['default']({
action: this.action(e.target),
target: this.target(e.target),
@ -738,5 +741,5 @@ function getAttributeValue(suffix, element) {
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)
});

File diff suppressed because one or more lines are too long

View File

@ -29,7 +29,7 @@
"phantomjs-polyfill": "0.0.1",
"uglify-js": "^2.4.24",
"watchify": "^3.4.0",
"bannerify": "Vekat/bannerify#feature-option"
"bannerify": "github:vekat/bannerify#feature-option"
},
"scripts": {
"build": "npm run build-debug && npm run build-min",

View File

@ -27,6 +27,7 @@ class Clipboard extends Emitter {
this.action = (typeof options.action === 'function') ? options.action : this.defaultAction;
this.target = (typeof options.target === 'function') ? options.target : this.defaultTarget;
this.text = (typeof options.text === 'function') ? options.text : this.defaultText;
this.modifier = (typeof options.modifier === 'string' && /^(alt|ctrl|shift|meta){1}$/.test(options.modifier)) ? options.modifier : null;
}
/**
@ -46,6 +47,10 @@ class Clipboard extends Emitter {
this.clipboardAction = null;
}
if (this.modifier) {
if (e[`${this.modifier}Key`] === false) return;
}
this.clipboardAction = new ClipboardAction({
action : this.action(e.target),
target : this.target(e.target),

View File

@ -12,6 +12,14 @@ describe('Clipboard', () => {
global.event = {
target: global.button
};
global.altkeyEvent = {
target: global.button,
altKey: true,
ctrlKey: false,
shiftKey: false,
metaKey: false
}
});
after(() => {
@ -21,6 +29,7 @@ describe('Clipboard', () => {
describe('#resolveOptions', () => {
before(() => {
global.fn = function() {};
global.key = 'alt';
});
it('should set action as a function', () => {
@ -46,6 +55,14 @@ describe('Clipboard', () => {
assert.equal(global.fn, clipboard.text);
});
it('should set modifier key as a string', () => {
let clipboard = new Clipboard('.btn', {
modifier: global.key
});
assert.equal(global.key, clipboard.modifier);
});
});
describe('#listenClick', () => {
@ -63,6 +80,24 @@ describe('Clipboard', () => {
assert.instanceOf(clipboard.clipboardAction, ClipboardAction);
});
it('should not create an instance of ClipboardAction', () => {
let clipboard = new Clipboard('.btn', {
modifier: 'shift'
});
clipboard.onClick(global.altkeyEvent);
assert.equal(clipboard.clipboardAction, null);
});
it('should create an instance of ClipboardAction', () => {
let clipboard = new Clipboard('.btn', {
modifier: 'alt'
});
clipboard.onClick(global.altkeyEvent);
assert.instanceOf(clipboard.clipboardAction, ClipboardAction);
});
it('should throws exception target', done => {
try {
var clipboard = new Clipboard('.btn', {