forked from zenorocha/clipboard.js
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
407 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,237 @@ | ||
/** | ||
* Inner class which performs selection from either `text` or `target` | ||
* properties and then executes copy or cut operations. | ||
*/ | ||
'use strict'; | ||
|
||
exports.__esModule = true; | ||
|
||
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); | ||
|
||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
|
||
var ClipboardAction = (function () { | ||
/** | ||
* @param {Object} options | ||
*/ | ||
|
||
function ClipboardAction(options) { | ||
_classCallCheck(this, ClipboardAction); | ||
|
||
this.resolveOptions(options); | ||
this.initSelection(); | ||
} | ||
|
||
/** | ||
* Defines base properties passed from constructor. | ||
* @param {Object} options | ||
*/ | ||
|
||
ClipboardAction.prototype.resolveOptions = function resolveOptions() { | ||
var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; | ||
|
||
this.action = options.action; | ||
this.emitter = options.emitter; | ||
this.target = options.target; | ||
this.text = options.text; | ||
this.trigger = options.trigger; | ||
|
||
this.selectedText = ''; | ||
}; | ||
|
||
/** | ||
* Decides which selection strategy is going to be applied based | ||
* on the existence of `text` and `target` properties. | ||
*/ | ||
|
||
ClipboardAction.prototype.initSelection = function initSelection() { | ||
if (this.text && this.target) { | ||
throw new Error('Multiple attributes declared, use either "target" or "text"'); | ||
} else if (this.text) { | ||
this.selectFake(); | ||
} else if (this.target) { | ||
this.selectTarget(); | ||
} else { | ||
throw new Error('Missing required attributes, use either "target" or "text"'); | ||
} | ||
}; | ||
|
||
/** | ||
* Creates a fake textarea element, sets its value from `text` property, | ||
* and makes a selection on it. | ||
*/ | ||
|
||
ClipboardAction.prototype.selectFake = function selectFake() { | ||
var _this = this; | ||
|
||
this.removeFake(); | ||
|
||
this.fakeHandler = document.body.addEventListener('click', function () { | ||
return _this.removeFake(); | ||
}); | ||
|
||
this.fakeElem = document.createElement('textarea'); | ||
this.fakeElem.style.position = 'absolute'; | ||
this.fakeElem.style.left = '-9999px'; | ||
this.fakeElem.style.top = document.body.scrollTop + 'px'; | ||
this.fakeElem.setAttribute('readonly', ''); | ||
this.fakeElem.value = this.text; | ||
this.selectedText = this.text; | ||
|
||
document.body.appendChild(this.fakeElem); | ||
|
||
this.fakeElem.select(); | ||
this.copyText(); | ||
}; | ||
|
||
/** | ||
* Only removes the fake element after another click event, that way | ||
* an user can hit `Ctrl+C` to copy because selection still exists. | ||
*/ | ||
|
||
ClipboardAction.prototype.removeFake = function removeFake() { | ||
if (this.fakeHandler) { | ||
document.body.removeEventListener('click'); | ||
this.fakeHandler = null; | ||
} | ||
|
||
if (this.fakeElem) { | ||
document.body.removeChild(this.fakeElem); | ||
this.fakeElem = null; | ||
} | ||
}; | ||
|
||
/** | ||
* Selects the content from element passed on `target` property. | ||
*/ | ||
|
||
ClipboardAction.prototype.selectTarget = function selectTarget() { | ||
if (this.target.nodeName === 'INPUT' || this.target.nodeName === 'TEXTAREA') { | ||
this.target.select(); | ||
this.selectedText = this.target.value; | ||
} else { | ||
var range = document.createRange(); | ||
var selection = window.getSelection(); | ||
|
||
range.selectNodeContents(this.target); | ||
selection.addRange(range); | ||
this.selectedText = selection.toString(); | ||
} | ||
|
||
this.copyText(); | ||
}; | ||
|
||
/** | ||
* Executes the copy operation based on the current selection. | ||
*/ | ||
|
||
ClipboardAction.prototype.copyText = function copyText() { | ||
var succeeded = undefined; | ||
|
||
try { | ||
succeeded = document.execCommand(this.action); | ||
} catch (err) { | ||
succeeded = false; | ||
} | ||
|
||
this.handleResult(succeeded); | ||
}; | ||
|
||
/** | ||
* Fires an event based on the copy operation result. | ||
* @param {Boolean} succeeded | ||
*/ | ||
|
||
ClipboardAction.prototype.handleResult = function handleResult(succeeded) { | ||
if (succeeded) { | ||
this.emitter.emit('success', { | ||
action: this.action, | ||
text: this.selectedText, | ||
trigger: this.trigger, | ||
clearSelection: this.clearSelection.bind(this) | ||
}); | ||
} else { | ||
this.emitter.emit('error', { | ||
action: this.action, | ||
trigger: this.trigger, | ||
clearSelection: this.clearSelection.bind(this) | ||
}); | ||
} | ||
}; | ||
|
||
/** | ||
* Removes current selection and focus from `target` element. | ||
*/ | ||
|
||
ClipboardAction.prototype.clearSelection = function clearSelection() { | ||
if (this.target) { | ||
this.target.blur(); | ||
} | ||
|
||
window.getSelection().removeAllRanges(); | ||
}; | ||
|
||
/** | ||
* Sets the `action` to be performed which can be either 'copy' or 'cut'. | ||
* @param {String} action | ||
*/ | ||
|
||
/** | ||
* Destroy lifecycle. | ||
*/ | ||
|
||
ClipboardAction.prototype.destroy = function destroy() { | ||
this.removeFake(); | ||
}; | ||
|
||
_createClass(ClipboardAction, [{ | ||
key: 'action', | ||
set: function set() { | ||
var action = arguments.length <= 0 || arguments[0] === undefined ? 'copy' : arguments[0]; | ||
|
||
this._action = action; | ||
|
||
if (this._action !== 'copy' && this._action !== 'cut') { | ||
throw new Error('Invalid "action" value, use either "copy" or "cut"'); | ||
} | ||
}, | ||
|
||
/** | ||
* Gets the `action` property. | ||
* @return {String} | ||
*/ | ||
get: function get() { | ||
return this._action; | ||
} | ||
|
||
/** | ||
* Sets the `target` property using an element | ||
* that will be have its content copied. | ||
* @param {Element} target | ||
*/ | ||
}, { | ||
key: 'target', | ||
set: function set(target) { | ||
if (target !== undefined) { | ||
if (target && typeof target === 'object' && target.nodeType === 1) { | ||
this._target = target; | ||
} else { | ||
throw new Error('Invalid "target" value, use a valid Element'); | ||
} | ||
} | ||
}, | ||
|
||
/** | ||
* Gets the `target` property. | ||
* @return {String|HTMLElement} | ||
*/ | ||
get: function get() { | ||
return this._target; | ||
} | ||
}]); | ||
|
||
return ClipboardAction; | ||
})(); | ||
|
||
exports['default'] = ClipboardAction; | ||
module.exports = exports['default']; |
Oops, something went wrong.