123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315 |
- /**
- * Creates a textarea that stays hidden on the page and gets focused when user presses CTRL while not having a form
- * input focused.
- * In future we may implement a better driver when better APIs are available.
- *
- * @constructor
- * @private
- */
- var instance;
- function copyPaste() {
- if (!instance) {
- instance = new CopyPasteClass();
- } else if (instance.hasBeenDestroyed()){
- instance.init();
- }
- instance.refCounter++;
- return instance;
- }
- if (typeof exports !== 'undefined') {
- module.exports = copyPaste;
- }
- function CopyPasteClass() {
- this.refCounter = 0;
- this.init();
- }
- CopyPasteClass.prototype.init = function () {
- var
- style,
- parent;
- this.copyCallbacks = [];
- this.cutCallbacks = [];
- this.pasteCallbacks = [];
- // this.listenerElement = document.documentElement;
- parent = document.body;
- if (document.getElementById('CopyPasteDiv')) {
- this.elDiv = document.getElementById('CopyPasteDiv');
- this.elTextarea = this.elDiv.firstChild;
- } else {
- this.elDiv = document.createElement('div');
- this.elDiv.id = 'CopyPasteDiv';
- style = this.elDiv.style;
- style.position = 'fixed';
- style.top = '-10000px';
- style.left = '-10000px';
- parent.appendChild(this.elDiv);
- this.elTextarea = document.createElement('textarea');
- this.elTextarea.className = 'copyPaste';
- this.elTextarea.onpaste = function(event) {
- var clipboardContents,
- temp;
- if ('WebkitAppearance' in document.documentElement.style) { // chrome and safari
- clipboardContents = event.clipboardData.getData("Text");
- // Safari adds an additional newline to copied text
- if (navigator.userAgent.indexOf('Safari') !== -1 && navigator.userAgent.indexOf('Chrome') === -1) {
- temp = clipboardContents.split('\n');
- if (temp[temp.length - 1] === '') {
- temp.pop();
- }
- clipboardContents = temp.join('\n');
- }
- this.value = clipboardContents;
- event.preventDefault();
- }
- };
- style = this.elTextarea.style;
- style.width = '10000px';
- style.height = '10000px';
- style.overflow = 'hidden';
- this.elDiv.appendChild(this.elTextarea);
- if (typeof style.opacity !== 'undefined') {
- style.opacity = 0;
- }
- }
- this.onKeyDownRef = this.onKeyDown.bind(this);
- document.documentElement.addEventListener('keydown', this.onKeyDownRef, false);
- };
- /**
- * Call method on every key down event
- *
- * @param {Event} event
- */
- CopyPasteClass.prototype.onKeyDown = function(event) {
- var _this = this,
- isCtrlDown = false;
- function isActiveElementEditable() {
- var element = document.activeElement;
- if (element.shadowRoot && element.shadowRoot.activeElement) {
- element = element.shadowRoot.activeElement;
- }
- return ['INPUT', 'SELECT', 'TEXTAREA'].indexOf(element.nodeName) > -1 || element.contentEditable === 'true';
- }
- // mac
- if (event.metaKey) {
- isCtrlDown = true;
- }
- // pc
- else if (event.ctrlKey && navigator.userAgent.indexOf('Mac') === -1) {
- isCtrlDown = true;
- }
- if (isCtrlDown) {
- // this is needed by fragmentSelection in Handsontable. Ignore copypaste.js behavior if fragment of cell text is selected
- if (document.activeElement !== this.elTextarea && (this.getSelectionText() !== '' || isActiveElementEditable())) {
- return;
- }
- this.selectNodeText(this.elTextarea);
- setTimeout(function() {
- if (document.activeElement !== _this.elTextarea) {
- _this.selectNodeText(_this.elTextarea);
- }
- }, 0);
- }
- if (event.isImmediatePropagationEnabled !== false && isCtrlDown &&
- (event.keyCode === 67 ||
- event.keyCode === 86 ||
- event.keyCode === 88)) {
- // works in all browsers, incl. Opera < 12.12
- if (event.keyCode === 88) {
- setTimeout(function () {
- _this.triggerCut(event);
- }, 0);
- } else if (event.keyCode === 86) {
- setTimeout(function () {
- _this.triggerPaste(event);
- }, 0);
- }
- }
- };
- //http://jsperf.com/textara-selection
- //http://stackoverflow.com/questions/1502385/how-can-i-make-this-code-work-in-ie
- /**
- * Select all text contains in passed node element
- *
- * @param {Element} element
- */
- CopyPasteClass.prototype.selectNodeText = function(element) {
- if (element) {
- element.select();
- }
- };
- //http://stackoverflow.com/questions/5379120/get-the-highlighted-selected-text
- /**
- * Get selection text
- *
- * @returns {String}
- */
- CopyPasteClass.prototype.getSelectionText = function() {
- var text = '';
- if (window.getSelection) {
- text = window.getSelection().toString();
- } else if (document.selection && document.selection.type !== 'Control') {
- text = document.selection.createRange().text;
- }
- return text;
- };
- /**
- * Make string copyable
- *
- * @param {String} string
- */
- CopyPasteClass.prototype.copyable = function(string) {
- if (typeof string !== 'string' && string.toString === void 0) {
- throw new Error('copyable requires string parameter');
- }
- this.elTextarea.value = string;
- this.selectNodeText(this.elTextarea);
- };
- /*CopyPasteClass.prototype.onCopy = function (fn) {
- this.copyCallbacks.push(fn);
- };*/
- /**
- * Add function callback to onCut event
- *
- * @param {Function} callback
- */
- CopyPasteClass.prototype.onCut = function(callback) {
- this.cutCallbacks.push(callback);
- };
- /**
- * Add function callback to onPaste event
- *
- * @param {Function} callback
- */
- CopyPasteClass.prototype.onPaste = function(callback) {
- this.pasteCallbacks.push(callback);
- };
- /**
- * Remove callback from all events
- *
- * @param {Function} callback
- * @returns {Boolean}
- */
- CopyPasteClass.prototype.removeCallback = function(callback) {
- var i, len;
- for (i = 0, len = this.copyCallbacks.length; i < len; i++) {
- if (this.copyCallbacks[i] === callback) {
- this.copyCallbacks.splice(i, 1);
- return true;
- }
- }
- for (i = 0, len = this.cutCallbacks.length; i < len; i++) {
- if (this.cutCallbacks[i] === callback) {
- this.cutCallbacks.splice(i, 1);
- return true;
- }
- }
- for (i = 0, len = this.pasteCallbacks.length; i < len; i++) {
- if (this.pasteCallbacks[i] === callback) {
- this.pasteCallbacks.splice(i, 1);
- return true;
- }
- }
- return false;
- };
- /**
- * Trigger cut event
- *
- * @param {DOMEvent} event
- */
- CopyPasteClass.prototype.triggerCut = function(event) {
- var _this = this;
- if (_this.cutCallbacks) {
- setTimeout(function () {
- for (var i = 0, len = _this.cutCallbacks.length; i < len; i++) {
- _this.cutCallbacks[i](event);
- }
- }, 50);
- }
- };
- /**
- * Trigger paste event
- *
- * @param {DOMEvent} event
- * @param {String} string
- */
- CopyPasteClass.prototype.triggerPaste = function(event, string) {
- var _this = this;
- if (_this.pasteCallbacks) {
- setTimeout(function () {
- var val = string || _this.elTextarea.value;
- for (var i = 0, len = _this.pasteCallbacks.length; i < len; i++) {
- _this.pasteCallbacks[i](val, event);
- }
- }, 50);
- }
- };
- /**
- * Destroy instance
- */
- CopyPasteClass.prototype.destroy = function() {
- if (!this.hasBeenDestroyed() && --this.refCounter === 0) {
- if (this.elDiv && this.elDiv.parentNode) {
- this.elDiv.parentNode.removeChild(this.elDiv);
- this.elDiv = null;
- this.elTextarea = null;
- }
- document.documentElement.removeEventListener('keydown', this.onKeyDownRef);
- this.onKeyDownRef = null;
- }
- };
- /**
- * Check if instance has been destroyed
- *
- * @returns {Boolean}
- */
- CopyPasteClass.prototype.hasBeenDestroyed = function() {
- return !this.refCounter;
- };
|