UNPKG

3.41 kBJavaScriptView Raw
1import Emitter from 'tiny-emitter';
2import listen from 'good-listener';
3import ClipboardAction from './clipboard-action';
4
5/**
6 * Helper function to retrieve attribute value.
7 * @param {String} suffix
8 * @param {Element} element
9 */
10function getAttributeValue(suffix, element) {
11 const attribute = `data-clipboard-${suffix}`;
12
13 if (!element.hasAttribute(attribute)) {
14 return;
15 }
16
17 return element.getAttribute(attribute);
18}
19
20/**
21 * Base class which takes one or more elements, adds event listeners to them,
22 * and instantiates a new `ClipboardAction` on each click.
23 */
24class Clipboard extends Emitter {
25 /**
26 * @param {String|HTMLElement|HTMLCollection|NodeList} trigger
27 * @param {Object} options
28 */
29 constructor(trigger, options) {
30 super();
31
32 this.resolveOptions(options);
33 this.listenClick(trigger);
34 }
35
36 /**
37 * Defines if attributes would be resolved using internal setter functions
38 * or custom functions that were passed in the constructor.
39 * @param {Object} options
40 */
41 resolveOptions(options = {}) {
42 this.action =
43 typeof options.action === 'function'
44 ? options.action
45 : this.defaultAction;
46 this.target =
47 typeof options.target === 'function'
48 ? options.target
49 : this.defaultTarget;
50 this.text =
51 typeof options.text === 'function' ? options.text : this.defaultText;
52 this.container =
53 typeof options.container === 'object' ? options.container : document.body;
54 }
55
56 /**
57 * Adds a click event listener to the passed trigger.
58 * @param {String|HTMLElement|HTMLCollection|NodeList} trigger
59 */
60 listenClick(trigger) {
61 this.listener = listen(trigger, 'click', (e) => this.onClick(e));
62 }
63
64 /**
65 * Defines a new `ClipboardAction` on each click event.
66 * @param {Event} e
67 */
68 onClick(e) {
69 const trigger = e.delegateTarget || e.currentTarget;
70
71 if (this.clipboardAction) {
72 this.clipboardAction = null;
73 }
74
75 this.clipboardAction = new ClipboardAction({
76 action: this.action(trigger),
77 target: this.target(trigger),
78 text: this.text(trigger),
79 container: this.container,
80 trigger,
81 emitter: this,
82 });
83 }
84
85 /**
86 * Default `action` lookup function.
87 * @param {Element} trigger
88 */
89 defaultAction(trigger) {
90 return getAttributeValue('action', trigger);
91 }
92
93 /**
94 * Default `target` lookup function.
95 * @param {Element} trigger
96 */
97 defaultTarget(trigger) {
98 const selector = getAttributeValue('target', trigger);
99
100 if (selector) {
101 return document.querySelector(selector);
102 }
103 }
104
105 /**
106 * Returns the support of the given action, or all actions if no action is
107 * given.
108 * @param {String} [action]
109 */
110 static isSupported(action = ['copy', 'cut']) {
111 const actions = typeof action === 'string' ? [action] : action;
112 let support = !!document.queryCommandSupported;
113
114 actions.forEach((action) => {
115 support = support && !!document.queryCommandSupported(action);
116 });
117
118 return support;
119 }
120
121 /**
122 * Default `text` lookup function.
123 * @param {Element} trigger
124 */
125 defaultText(trigger) {
126 return getAttributeValue('text', trigger);
127 }
128
129 /**
130 * Destroy lifecycle.
131 */
132 destroy() {
133 this.listener.destroy();
134
135 if (this.clipboardAction) {
136 this.clipboardAction.destroy();
137 this.clipboardAction = null;
138 }
139 }
140}
141
142export default Clipboard;