import Emitter from 'tiny-emitter';
|
import listen from 'good-listener';
|
import ClipboardAction from './clipboard-action';
|
|
/**
|
* Helper function to retrieve attribute value.
|
* @param {String} suffix
|
* @param {Element} element
|
*/
|
function getAttributeValue(suffix, element) {
|
const attribute = `data-clipboard-${suffix}`;
|
|
if (!element.hasAttribute(attribute)) {
|
return;
|
}
|
|
return element.getAttribute(attribute);
|
}
|
|
/**
|
* 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 {
|
/**
|
* @param {String|HTMLElement|HTMLCollection|NodeList} trigger
|
* @param {Object} options
|
*/
|
constructor(trigger, options) {
|
super();
|
|
this.resolveOptions(options);
|
this.listenClick(trigger);
|
}
|
|
/**
|
* Defines if attributes would be resolved using internal setter functions
|
* or custom functions that were passed in the constructor.
|
* @param {Object} options
|
*/
|
resolveOptions(options = {}) {
|
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.container =
|
typeof options.container === 'object' ? options.container : document.body;
|
}
|
|
/**
|
* Adds a click event listener to the passed trigger.
|
* @param {String|HTMLElement|HTMLCollection|NodeList} trigger
|
*/
|
listenClick(trigger) {
|
this.listener = listen(trigger, 'click', (e) => this.onClick(e));
|
}
|
|
/**
|
* Defines a new `ClipboardAction` on each click event.
|
* @param {Event} e
|
*/
|
onClick(e) {
|
const trigger = e.delegateTarget || e.currentTarget;
|
|
if (this.clipboardAction) {
|
this.clipboardAction = null;
|
}
|
|
this.clipboardAction = new ClipboardAction({
|
action: this.action(trigger),
|
target: this.target(trigger),
|
text: this.text(trigger),
|
container: this.container,
|
trigger,
|
emitter: this,
|
});
|
}
|
|
/**
|
* Default `action` lookup function.
|
* @param {Element} trigger
|
*/
|
defaultAction(trigger) {
|
return getAttributeValue('action', trigger);
|
}
|
|
/**
|
* Default `target` lookup function.
|
* @param {Element} trigger
|
*/
|
defaultTarget(trigger) {
|
const selector = getAttributeValue('target', trigger);
|
|
if (selector) {
|
return document.querySelector(selector);
|
}
|
}
|
|
/**
|
* Returns the support of the given action, or all actions if no action is
|
* given.
|
* @param {String} [action]
|
*/
|
static isSupported(action = ['copy', 'cut']) {
|
const actions = typeof action === 'string' ? [action] : action;
|
let support = !!document.queryCommandSupported;
|
|
actions.forEach((action) => {
|
support = support && !!document.queryCommandSupported(action);
|
});
|
|
return support;
|
}
|
|
/**
|
* Default `text` lookup function.
|
* @param {Element} trigger
|
*/
|
defaultText(trigger) {
|
return getAttributeValue('text', trigger);
|
}
|
|
/**
|
* Destroy lifecycle.
|
*/
|
destroy() {
|
this.listener.destroy();
|
|
if (this.clipboardAction) {
|
this.clipboardAction.destroy();
|
this.clipboardAction = null;
|
}
|
}
|
}
|
|
export default Clipboard;
|