]> git.proxmox.com Git - mirror_xterm.js.git/blobdiff - src/xterm.js
Merge remote-tracking branch 'upstream/master' into 124_add_textarea_back
[mirror_xterm.js.git] / src / xterm.js
index 7211dde7d8c21e5dc4e19e8e125a3a021b3ee9f2..a6cdd8d4073fee4790ec0fce2b0d395738c85810 100644 (file)
       var self = this;
       function on() {
         var args = Array.prototype.slice.call(arguments);
-        self.removeListener(type, on);
-        return listener.apply(self, args);
+        this.removeListener(type, on);
+        return listener.apply(this, args);
       }
       on.listener = listener;
       return this.on(type, on);
      * Focus the terminal. Delegates focus handling to the terminal's DOM element.
      */
     Terminal.prototype.focus = function() {
-      return this.element.focus();
+      if (document.activeElement === this.textarea) {
+        return;
+      }
+
+      if (this.sendFocus) {
+        this.send('\x1b[I');
+      }
+
+      this.element.classList.add('focus');
+      this.showCursor();
+      this.textarea.focus();
+      Terminal.focus = this;
     };
 
     /**
      * Blur the terminal. Delegates blur handling to the terminal's DOM element.
      */
     Terminal.prototype.blur = function() {
-      return this.element.blur();
+      if (Terminal.focus !== this) {
+        return;
+      }
+
+      this.element.classList.remove('focus');
+      this.cursorState = 0;
+      this.refresh(this.y, this.y);
+      this.textarea.blur();
+      if (this.sendFocus) {
+        this.send('\x1b[0]');
+      }
+      Terminal.focus = null;
     };
 
     /**
      * Initialize default behavior
      */
     Terminal.prototype.initGlobal = function() {
-      Terminal.bindKeys(this);
       Terminal.bindPaste(this);
+      Terminal.bindKeys(this);
       Terminal.bindCopy(this);
-      Terminal.bindCut(this);
-      Terminal.bindDrop(this);
-      Terminal.bindFocus(this);
-      Terminal.bindBlur(this);
-    };
-
-       /**
-        * Clears all selected text, inside the terminal.
-        */
-               Terminal.prototype.clearSelection = function() {
-      var selectionBaseNode = window.getSelection().baseNode;
-
-      if (selectionBaseNode && (this.element.contains(selectionBaseNode.parentElement))) {
-        window.getSelection().removeAllRanges();
-      }
-    };
-
-       /**
-        * This function temporarily enables (leases) the contentEditable value of the terminal, which
-        * should be set back to false within 5 seconds at most.
-        */
-       Terminal.prototype.leaseContentEditable = function (ms, callback) {
-      var term = this;
-
-      term.element.contentEditable = true;
-
-      /**
-       * Blur and re-focus instantly. This is due to a weird focus state on Chrome, when setting
-       * contentEditable to true on a focused element.
-       */
-      term.blur();
-      term.focus();
-
-      setTimeout(function () {
-        term.element.contentEditable = false;
-        if (typeof callback == 'function') {
-          callback.call(term);
-        }
-      }, ms || 5000);
     };
 
     /**
      * contentEditable value set to true.
      */
     Terminal.bindPaste = function(term) {
-      on(term.element, 'paste', function(ev) {
+      on([term.textarea, term.element], 'paste', function(ev) {
+        ev.stopPropagation();
         if (ev.clipboardData) {
           var text = ev.clipboardData.getData('text/plain');
-          term.emit('paste', text, ev);
           term.handler(text);
-          /**
-           * Cancel the paste event, or else things will be pasted twice:
-           *   1. by the terminal handler
-           *   2. by the browser, because of the contentEditable value being true
-           */
-          term.cancel(ev, true);
-
-          /**
-           * After the paste event is completed, always set the contentEditable value to false.
-           */
-          term.element.contentEditable = false;
+          term.textarea.value = '';
+          return term.cancel(ev);
         }
       });
-
-      /**
-       * Hack pasting with keyboard, in order to make it work without contentEditable.
-       * When a user types Ctrl + Shift + V or Shift + Insert on a non Mac or Cmd + V on a Mac,
-       * lease the contentEditable value as true.
-       */
-      on(term.element, 'keydown', function (ev) {
-        var isEditable = term.element.contentEditable === "true";
-
-        /**
-         * If on a Mac, lease the contentEditable value temporarily, when the user presses
-         * the Cmd button, in a keydown event order to paste frictionlessly.
-         */
-        if (term.isMac && ev.metaKey && !isEditable) {
-          term.leaseContentEditable(5000);
-        }
-
-        if (!term.isMac && !isEditable) {
-          if ((ev.keyCode == 45 && ev.shiftKey && !ev.ctrlKey) ||  // Shift + Insert
-              (ev.keyCode == 86 && ev.shiftKey && ev.ctrlKey)) {  // Ctrl + Shict + V
-            term.leaseContentEditable();
-          }
-        }
-      });
-
-      /**
-       * Hack pasting with right-click in order to allow right-click paste, by leasing the
-       * contentEditable value as true.
-       */
-      on(term.element, 'contextmenu', function (ev) {
-        term.leaseContentEditable();
-      });
-    };
-
-
-    /**
-     * Apply key handling to the terminal
-     *
-     * @param {Xterm} term The terminal on which to bind key handling
-     * @static
-     */
-    Terminal.bindKeys = function(term) {
-      on(term.element, 'keydown', function(ev) {
-        term.keyDown(ev);
-      }, true);
-
-      on(term.element, 'keypress', function(ev) {
-        term.keyPress(ev);
-      }, true);
     };
 
     /**
     };
 
     /**
-     * Binds copy functionality to the given terminal.
-     * @static
+     * Apply key handling to the terminal
      */
-    Terminal.bindCopy = function(term) {
-      on(term.element, 'copy', function(ev) {
-        var copiedText = window.getSelection().toString(),
-                       text = Terminal.prepareCopiedTextForClipboard(copiedText);
+    Terminal.bindKeys = function(term) {
+      on(term.element, 'keydown', function(ev) {
+        if (document.activeElement != this) {
+          return;
+         }
+         term.keyDown(ev);
+      }, true);
 
-        ev.clipboardData.setData('text/plain', text);
-        ev.preventDefault();
-      });
-    };
+      on(term.element, 'keypress', function(ev) {
+        if (document.activeElement != this) {
+          return;
+        }
+        term.keyPress(ev);
+      }, true);
 
-       /**
-        * Cancel the cut event completely.
-        * @param {Xterm} term The terminal on which to bind the cut event handling functionality.
-        * @static
-        */
-       Terminal.bindCut = function(term) {
-      on(term.element, 'cut', function (ev) {
-        ev.preventDefault();
-      });
-    };
+      on(term.element, 'keyup', term.focus.bind(term));
 
+      on(term.textarea, 'keydown', function(ev) {
+        term.keyDown(ev);
+      }, true);
 
-    /**
-     * Do not perform the "drop" event. Altering the contents of the
-     * terminal with drag n drop is unwanted behavior.
-        * @param {Xterm} term The terminal on which to bind the drop event handling functionality.
-        * @static
-        */
-    Terminal.bindDrop = function (term) {
-      on(term.element, 'drop', function (ev) {
-        term.cancel(ev, true);
+      on(term.textarea, 'keypress', function(ev) {
+        term.keyPress(ev);
+        // Truncate the textarea's value, since it is not needed
+        this.value = '';
+      }, true);
+
+      on(term.textarea, 'compositionstart', function(ev) {
+        console.log('compositionstart', ev);
+        // TODO: Set a composing flag
+      });
+      on(term.textarea, 'compositionupdate', function(ev) {
+        console.log('compositionupdate', ev);
+        // TODO: Display text being composed in the UI (needs to be handled in keydown)
+      });
+      on(term.textarea, 'compositionend', function(ev) {
+        console.log('compositionend', ev);
+        // TODO: Send composed text to the pty
+        // TODO: Remove composing flag
       });
     };
 
     /**
-     * Cancel click handling on the given terminal
-        * @param {Xterm} term The terminal on which to bind the click event handling functionality.
-        * @static
-        */
-    Terminal.click = function (term) {
-      on(term.element, 'click', function (ev) {
-        term.cancel(ev, true);
+     * Binds copy functionality to the given terminal.
+     * @static
+     */
+    Terminal.bindCopy = function(term) {
+      on(term.element, 'copy', function(ev) {
+        return; // temporary
       });
     };
 
       this.element.classList.add('xterm');
       this.element.classList.add('xterm-theme-' + this.theme);
       this.element.setAttribute('tabindex', 0);
-      this.element.spellcheck = false;
 
       /*
       * Create the container that will hold the lines of the terminal and then
       this.element.appendChild(this.rowContainer);
       this.children = [];
 
+      /*
+      * Create the container that will hold helpers like the textarea for
+      * capturing DOM Events. Then produce the helpers.
+      */
+      this.helperContainer = document.createElement('div');
+      this.helperContainer.classList.add('xterm-helpers');
+      this.element.appendChild(this.helperContainer);
+      this.textarea = document.createElement('textarea');
+      this.textarea.classList.add('xterm-helper-textarea');
+      this.textarea.setAttribute('autocorrect', 'off');
+      this.textarea.setAttribute('autocapitalize', 'off');
+      this.textarea.setAttribute('spellcheck', 'false');
+      this.textarea.tabIndex = 0;
+      this.textarea.onfocus = function() {
+        self.emit('focus', {terminal: self});
+      }
+      this.textarea.onblur = function() {
+        self.emit('blur', {terminal: self});
+      }
+      this.helperContainer.appendChild(this.textarea);
+
       for (; i < this.rows; i++) {
         this.insertRow();
       }
      * @param {KeyboardEvent} ev The keydown event to be handled.
      */
     Terminal.prototype.keyDown = function(ev) {
+      // TODO: Ignore event if currently composing text
+
       var self = this;
       var result = this.evaluateKeyEscapeSequence(ev);
 
     Terminal.prototype.keyPress = function(ev) {
       var key;
 
+      this.cancel(ev);
+
       if (ev.charCode) {
         key = ev.charCode;
       } else if (ev.which == null) {
 
       key = String.fromCharCode(key);
 
-      /**
-       * When a key is pressed and a character is sent to the terminal, then clear any text
-       * selected in the terminal.
-       */
-      if (key) {
-        this.clearSelection();
-      }
-
       this.emit('keypress', key, ev);
       this.emit('key', key, ev);
       this.showCursor();
       this.handler(key);
 
-      this.cancel(ev, true);
-
       return false;
     };