Skip to content

Commit 88678d7

Browse files
johnsenpedercdll
authored andcommitted
Container option (zenorocha#368)
* Allow container option to fix bugs related to bootstrap modals etc. * Updated readme to reflect addition of container option * Name link * Removed test log * Remove unwanted whitespace * Refactored description
1 parent 99313e0 commit 88678d7

File tree

7 files changed

+69
-23
lines changed

7 files changed

+69
-23
lines changed

dist/clipboard.js

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ var DOCUMENT_NODE_TYPE = 9;
1010
/**
1111
* A polyfill for Element.matches()
1212
*/
13-
if (typeof Element !== 'undefined' && !Element.prototype.matches) {
13+
if (Element && !Element.prototype.matches) {
1414
var proto = Element.prototype;
1515

1616
proto.matches = proto.matchesSelector ||
@@ -420,6 +420,7 @@ module.exports = E;
420420
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
421421

422422
this.action = options.action;
423+
this.container = options.container;
423424
this.emitter = options.emitter;
424425
this.target = options.target;
425426
this.text = options.text;
@@ -448,7 +449,7 @@ module.exports = E;
448449
this.fakeHandlerCallback = function () {
449450
return _this.removeFake();
450451
};
451-
this.fakeHandler = document.body.addEventListener('click', this.fakeHandlerCallback) || true;
452+
this.fakeHandler = this.container.addEventListener('click', this.fakeHandlerCallback) || true;
452453

453454
this.fakeElem = document.createElement('textarea');
454455
// Prevent zooming on iOS
@@ -467,7 +468,7 @@ module.exports = E;
467468
this.fakeElem.setAttribute('readonly', '');
468469
this.fakeElem.value = this.text;
469470

470-
document.body.appendChild(this.fakeElem);
471+
this.container.appendChild(this.fakeElem);
471472

472473
this.selectedText = (0, _select2.default)(this.fakeElem);
473474
this.copyText();
@@ -476,13 +477,13 @@ module.exports = E;
476477
key: 'removeFake',
477478
value: function removeFake() {
478479
if (this.fakeHandler) {
479-
document.body.removeEventListener('click', this.fakeHandlerCallback);
480+
this.container.removeEventListener('click', this.fakeHandlerCallback);
480481
this.fakeHandler = null;
481482
this.fakeHandlerCallback = null;
482483
}
483484

484485
if (this.fakeElem) {
485-
document.body.removeChild(this.fakeElem);
486+
this.container.removeChild(this.fakeElem);
486487
this.fakeElem = null;
487488
}
488489
}
@@ -601,6 +602,12 @@ module.exports = E;
601602
};
602603
}
603604

605+
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
606+
return typeof obj;
607+
} : function (obj) {
608+
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
609+
};
610+
604611
function _classCallCheck(instance, Constructor) {
605612
if (!(instance instanceof Constructor)) {
606613
throw new TypeError("Cannot call a class as a function");
@@ -681,6 +688,7 @@ module.exports = E;
681688
this.action = typeof options.action === 'function' ? options.action : this.defaultAction;
682689
this.target = typeof options.target === 'function' ? options.target : this.defaultTarget;
683690
this.text = typeof options.text === 'function' ? options.text : this.defaultText;
691+
this.container = _typeof(options.container) === 'object' ? options.container : document.body;
684692
}
685693
}, {
686694
key: 'listenClick',
@@ -704,6 +712,7 @@ module.exports = E;
704712
action: this.action(trigger),
705713
target: this.target(trigger),
706714
text: this.text(trigger),
715+
container: this.container,
707716
trigger: trigger,
708717
emitter: this
709718
});

dist/clipboard.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

readme.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,15 @@ new Clipboard('.btn', {
145145
});
146146
```
147147

148+
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.
149+
See [Issue #155 (comment)](https://github.com/zenorocha/clipboard.js/issues/155#issuecomment-273124130)
150+
151+
```js
152+
new Clipboard('.btn', {
153+
container: document.getElementById('#modal')
154+
});
155+
```
156+
148157
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.
149158

150159
```js

src/clipboard-action.js

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,12 @@ class ClipboardAction {
1818
* @param {Object} options
1919
*/
2020
resolveOptions(options = {}) {
21-
this.action = options.action;
22-
this.emitter = options.emitter;
23-
this.target = options.target;
24-
this.text = options.text;
25-
this.trigger = options.trigger;
21+
this.action = options.action;
22+
this.container = options.container;
23+
this.emitter = options.emitter;
24+
this.target = options.target;
25+
this.text = options.text;
26+
this.trigger = options.trigger;
2627

2728
this.selectedText = '';
2829
}
@@ -50,7 +51,7 @@ class ClipboardAction {
5051
this.removeFake();
5152

5253
this.fakeHandlerCallback = () => this.removeFake();
53-
this.fakeHandler = document.body.addEventListener('click', this.fakeHandlerCallback) || true;
54+
this.fakeHandler = this.container.addEventListener('click', this.fakeHandlerCallback) || true;
5455

5556
this.fakeElem = document.createElement('textarea');
5657
// Prevent zooming on iOS
@@ -69,7 +70,7 @@ class ClipboardAction {
6970
this.fakeElem.setAttribute('readonly', '');
7071
this.fakeElem.value = this.text;
7172

72-
document.body.appendChild(this.fakeElem);
73+
this.container.appendChild(this.fakeElem);
7374

7475
this.selectedText = select(this.fakeElem);
7576
this.copyText();
@@ -81,13 +82,13 @@ class ClipboardAction {
8182
*/
8283
removeFake() {
8384
if (this.fakeHandler) {
84-
document.body.removeEventListener('click', this.fakeHandlerCallback);
85+
this.container.removeEventListener('click', this.fakeHandlerCallback);
8586
this.fakeHandler = null;
8687
this.fakeHandlerCallback = null;
8788
}
8889

8990
if (this.fakeElem) {
90-
document.body.removeChild(this.fakeElem);
91+
this.container.removeChild(this.fakeElem);
9192
this.fakeElem = null;
9293
}
9394
}

src/clipboard.js

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,10 @@ class Clipboard extends Emitter {
2424
* @param {Object} options
2525
*/
2626
resolveOptions(options = {}) {
27-
this.action = (typeof options.action === 'function') ? options.action : this.defaultAction;
28-
this.target = (typeof options.target === 'function') ? options.target : this.defaultTarget;
29-
this.text = (typeof options.text === 'function') ? options.text : this.defaultText;
27+
this.action = (typeof options.action === 'function') ? options.action : this.defaultAction;
28+
this.target = (typeof options.target === 'function') ? options.target : this.defaultTarget;
29+
this.text = (typeof options.text === 'function') ? options.text : this.defaultText;
30+
this.container = (typeof options.container === 'object') ? options.container : document.body;
3031
}
3132

3233
/**
@@ -49,11 +50,12 @@ class Clipboard extends Emitter {
4950
}
5051

5152
this.clipboardAction = new ClipboardAction({
52-
action : this.action(trigger),
53-
target : this.target(trigger),
54-
text : this.text(trigger),
55-
trigger,
56-
emitter : this
53+
action : this.action(trigger),
54+
target : this.target(trigger),
55+
text : this.text(trigger),
56+
container : this.container,
57+
trigger : trigger,
58+
emitter : this
5759
});
5860
}
5961

test/clipboard-action.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,12 @@ describe('ClipboardAction', () => {
2222
it('should set base properties', () => {
2323
let clip = new ClipboardAction({
2424
emitter: new Emitter(),
25+
container: document.body,
2526
text: 'foo'
2627
});
2728

2829
assert.property(clip, 'action');
30+
assert.property(clip, 'container');
2931
assert.property(clip, 'emitter');
3032
assert.property(clip, 'target');
3133
assert.property(clip, 'text');
@@ -41,6 +43,7 @@ describe('ClipboardAction', () => {
4143

4244
let clip = new ClipboardAction({
4345
emitter: new Emitter(),
46+
container: document.body,
4447
text: 'foo'
4548
});
4649

@@ -82,6 +85,7 @@ describe('ClipboardAction', () => {
8285
it('should create a fake element and select its value', () => {
8386
let clip = new ClipboardAction({
8487
emitter: new Emitter(),
88+
container: document.body,
8589
text: 'blah'
8690
});
8791

@@ -93,6 +97,7 @@ describe('ClipboardAction', () => {
9397
it('should remove a temporary fake element', () => {
9498
let clip = new ClipboardAction({
9599
emitter: new Emitter(),
100+
container: document.body,
96101
text: 'blah'
97102
});
98103

@@ -106,6 +111,7 @@ describe('ClipboardAction', () => {
106111
it('should select text from editable element', () => {
107112
let clip = new ClipboardAction({
108113
emitter: new Emitter(),
114+
container: document.body,
109115
target: document.querySelector('#input')
110116
});
111117

@@ -115,6 +121,7 @@ describe('ClipboardAction', () => {
115121
it('should select text from non-editable element', () => {
116122
let clip = new ClipboardAction({
117123
emitter: new Emitter(),
124+
container: document.body,
118125
target: document.querySelector('#paragraph')
119126
});
120127

@@ -166,6 +173,7 @@ describe('ClipboardAction', () => {
166173
it('should fire a success event with certain properties', done => {
167174
let clip = new ClipboardAction({
168175
emitter: new Emitter(),
176+
container: document.body,
169177
target: document.querySelector('#input')
170178
});
171179

@@ -184,6 +192,7 @@ describe('ClipboardAction', () => {
184192
it('should fire a error event with certain properties', done => {
185193
let clip = new ClipboardAction({
186194
emitter: new Emitter(),
195+
container: document.body,
187196
target: document.querySelector('#input')
188197
});
189198

@@ -203,6 +212,7 @@ describe('ClipboardAction', () => {
203212
it('should remove focus from target and text selection', () => {
204213
let clip = new ClipboardAction({
205214
emitter: new Emitter(),
215+
container: document.body,
206216
target: document.querySelector('#input')
207217
});
208218

@@ -220,6 +230,7 @@ describe('ClipboardAction', () => {
220230
it('should destroy an existing fake element', () => {
221231
let clip = new ClipboardAction({
222232
emitter: new Emitter(),
233+
container: document.body,
223234
text: 'blah'
224235
});
225236

test/clipboard.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,20 @@ describe('Clipboard', () => {
5252

5353
assert.equal(global.fn, clipboard.text);
5454
});
55+
56+
it('should set container as an object', () => {
57+
let clipboard = new Clipboard('.btn', {
58+
container: document.body
59+
});
60+
61+
assert.equal(document.body, clipboard.container);
62+
});
63+
64+
it('should set container as body by default', () => {
65+
let clipboard = new Clipboard('.btn');
66+
67+
assert.equal(document.body, clipboard.container);
68+
});
5569
});
5670

5771
describe('#listenClick', () => {

0 commit comments

Comments
 (0)