Handles attributes with getters/setters and breaks code into two classes

This commit is contained in:
Zeno Rocha
2015-09-24 15:09:34 -07:00
parent e72ce02c87
commit 56dd1aac22
3 changed files with 143 additions and 119 deletions

123
src/clipboard-action.js Normal file
View File

@ -0,0 +1,123 @@
var CustomEvent = require('custom-event');
export default class ClipboardAction {
constructor(options) {
this.action = options.action;
this.target = options.target;
this.text = options.text;
this.trigger = options.trigger;
this.selectedText = '';
if (this.text) {
this.selectValue();
}
else if (this.target) {
this.selectTarget();
}
}
selectValue() {
let fake = document.createElement('input');
fake.style.position = 'absolute';
fake.style.left = '-9999px';
fake.value = this.text;
this.selectedText = this.text;
document.body.appendChild(fake);
fake.select();
this.copyText();
document.body.removeChild(fake);
}
selectTarget() {
if (this.target.nodeName === 'INPUT' || this.target.nodeName === 'TEXTAREA') {
this.target.select();
this.selectedText = this.target.value;
}
else {
let range = document.createRange();
let selection = window.getSelection();
range.selectNodeContents(this.target);
selection.addRange(range);
this.selectedText = selection.toString();
}
this.copyText();
}
copyText() {
let succeeded;
try {
succeeded = document.execCommand(this.action);
}
catch (err) {
succeeded = false;
}
this.handleResult(succeeded);
}
handleResult(succeeded) {
if (succeeded) {
this.fireEvent('success', {
action: this.action,
text: this.selectedText,
clearSelection: this.clearSelection.bind(this)
});
}
else {
this.fireEvent('error', {
action: this.action,
clearSelection: this.clearSelection.bind(this)
});
}
}
clearSelection() {
if (this.target) {
this.target.blur();
}
window.getSelection().removeAllRanges();
}
fireEvent(type, detail) {
let event = new CustomEvent(type, {
detail: detail
});
this.trigger.dispatchEvent(event);
}
set action(action) {
this._action = action || 'copy';
if (this._action !== 'copy' && this._action !== 'cut') {
throw new Error('Invalid "data-action" value, use either "copy" or "cut"');
}
}
get action() {
return this._action;
}
set target(target) {
if (target) {
this._target = document.getElementById(target);
if (!this._target) {
throw new Error('Invalid "data-target" selector, use a value that matches an ID');
}
}
}
get target() {
return this._target;
}
}

View File

@ -1,134 +1,35 @@
var CustomEvent = require('custom-event');
var ClipboardAction = require('./clipboard-action');
export default class Clipboard {
constructor(triggers) {
this.triggers = document.querySelectorAll(triggers);
if (!this.triggers.length) {
throw new Error('No matches were found for the provided selector');
}
[].forEach.call(this.triggers, (trigger) => this.bind(trigger));
}
bind(trigger) {
trigger.addEventListener('click', (e) => this.validate(e));
trigger.addEventListener('click', (e) => this.initialize(e));
}
validate(e) {
let trigger = e.currentTarget;
let action = trigger.getAttribute('data-action') || 'copy';
let target = trigger.getAttribute('data-target');
let text = trigger.getAttribute('data-text');
if (action !== 'copy' && action !== 'cut') {
throw new Error('Invalid "data-action" value, use either "copy" or "cut"');
}
if (!target && !text) {
throw new Error('Missing required attributes, use either "data-target" or "data-text"');
}
if (target) {
target = document.getElementById(target);
if (!target) throw new Error('Invalid "data-target" selector, use a value that matches an ID');
}
new ClipboardAction(action, target, text, trigger);
}
}
class ClipboardAction {
constructor(action, target, text, trigger) {
this.action = action;
this.target = target;
this.text = text;
this.trigger = trigger;
this.selectedText = '';
if (this.text) {
this.selectValue();
}
else if (this.target) {
this.selectTarget();
}
}
selectValue() {
let fake = document.createElement('input');
fake.style.position = 'absolute';
fake.style.left = '-9999px';
fake.value = this.text;
this.selectedText = this.text;
document.body.appendChild(fake);
fake.select();
this.copyText();
document.body.removeChild(fake);
}
selectTarget() {
if (this.target.nodeName === 'INPUT' || this.target.nodeName === 'TEXTAREA') {
this.target.select();
this.selectedText = this.target.value;
}
else {
let range = document.createRange();
let selection = window.getSelection();
range.selectNodeContents(this.target);
selection.addRange(range);
this.selectedText = selection.toString();
}
this.copyText();
}
copyText() {
let succeeded;
try {
succeeded = document.execCommand(this.action);
}
catch (err) {
succeeded = false;
}
this.handleResult(succeeded);
}
handleResult(succeeded) {
if (succeeded) {
this.fireEvent('success', {
action: this.action,
text: this.selectedText
});
this.clearSelection();
}
else {
this.fireEvent('error', `Cannot execute ${this.action} operation`);
}
}
clearSelection() {
if (this.target) {
this.target.blur();
}
window.getSelection().removeAllRanges();
}
fireEvent(type, detail) {
let event = new CustomEvent(type, {
detail: detail
initialize(e) {
new ClipboardAction({
action : e.currentTarget.getAttribute('data-action'),
target : e.currentTarget.getAttribute('data-target'),
text : e.currentTarget.getAttribute('data-text'),
trigger : e.currentTarget
});
}
this.trigger.dispatchEvent(event);
set triggers(triggers) {
if (!triggers.length) {
throw new Error('No matches were found for the provided selector');
}
this._triggers = triggers;
}
get triggers() {
return this._triggers;
}
}