]> git.proxmox.com Git - mirror_xterm.js.git/commitdiff
Refactor into CompositionHelper object
authorDaniel Imms <daimms@microsoft.com>
Wed, 13 Jul 2016 02:14:56 +0000 (19:14 -0700)
committerDaniel Imms <daimms@microsoft.com>
Wed, 13 Jul 2016 02:14:56 +0000 (19:14 -0700)
src/xterm.js

index f2a5b9000e385070aff53620efa735ace118d90c..3b6e2d606dfe587e699120dd42c3561b1779756d 100644 (file)
     };
 
 
+    function CompositionHelper(textarea, compositionView, terminal) {
+      this.textarea = textarea;
+      this.compositionView = compositionView;
+      this.terminal = terminal;
+
+      // Whether input composition is currently happening, eg. via a mobile keyboard, speech input
+      // or IME. This variable determines whether the compositionText should be displayed on the UI.
+      this.isComposing = false;
+
+      // The input currently being composed, eg. via a mobile keyboard, speech input or IME.
+      this.compositionText = null;
+
+      // The position within the input textarea's value of the current composition.
+      this.compositionPosition = { start: null, end: null };
+    }
+
+    CompositionHelper.prototype.compositionstart = function(ev) {
+      this.isComposing = true;
+      this.compositionPosition.start = this.textarea.value.length;
+      this.compositionView.textContent = '';
+      this.compositionView.classList.add('active');
+    };
+
+    CompositionHelper.prototype.compositionupdate = function(ev) {
+      this.compositionPosition.end = this.textarea.value.length - 1;
+      this.compositionView.textContent = ev.data;
+      this.updateCursorPosition();
+    };
+
+    CompositionHelper.prototype.compositionend = function(ev) {
+      this.compositionView.classList.remove('active');
+      this.isComposing = false;
+      // Record composition position here as a new compositionstart event may fire before the
+      // setTimeout executes
+      var currentCompositionPosition = this.compositionPosition;
+
+      // Since composition* events happen before the changes take place in the textarea on most
+      // browsers, use a setTimeout with 0ms time to allow the native compositionend event to
+      // complete. This ensures the correct character is retrieved, this solution was used
+      // because:
+      // - The compositionend event's data property is unreliable, at least on Chromium
+      // - The last compositionupdate event's data property does not always accurately describe
+      //   the character, a counter example being Korean where an ending consonsant can move to
+      //   the following character if the following input is a vowel.
+      var self = this;
+      setTimeout(function () {
+        var input = self.textarea.value.substring(currentCompositionPosition.start, currentCompositionPosition.end);
+        self.terminal.write(input);
+      }, 0);
+    };
+
+    CompositionHelper.prototype.updateCursorPosition = function() {
+      var cursor = document.querySelector('.terminal-cursor');
+      term.compositionView.style.left = cursor.offsetLeft + 'px';
+      term.compositionView.style.top = cursor.offsetTop + 'px';
+    };
+
+
     /**
      * States
      */
        */
       this.isRefreshing = false;
 
-      // Whether input composition is currently happening, eg. via a mobile keyboard, speech input
-      // or IME. This variable determines whether the compositionText should be displayed on the UI.
-      this.isComposing = false;
-
-      // The input currently being composed, eg. via a mobile keyboard, speech input or IME.
-      this.compositionText = null;
-
-      this.compositionPosition = { start: null, end: null };
-
       /**
        * Whether there is a full terminal refresh queued
        */
 
       // TODO: Refactor into a CompositionHelper object
       on(term.textarea, 'compositionstart', function(ev) {
-        this.isComposing = true;
+        term.compositionHelper.compositionstart.bind(term.compositionHelper, ev)();
+        /*this.isComposing = true;
         term.compositionPosition.start = this.value.length;
         term.compositionView.textContent = '';
-        term.compositionView.classList.add('active');
+        term.compositionView.classList.add('active');*/
       });
       on(term.textarea, 'compositionupdate', function(ev) {
-        term.compositionPosition.end = this.value.length - 1;
+        term.compositionHelper.compositionupdate.bind(term.compositionHelper, ev)();
+        /*term.compositionPosition.end = this.value.length - 1;
 
         // Update composition view contents and position
         term.compositionView.textContent = ev.data;
         var cursor = document.querySelector('.terminal-cursor');
         term.compositionView.style.left = cursor.offsetLeft + 'px';
-        term.compositionView.style.top = cursor.offsetTop + 'px';
+        term.compositionView.style.top = cursor.offsetTop + 'px';*/
       });
       on(term.textarea, 'compositionend', function(ev) {
-        term.compositionView.classList.remove('active');
+        term.compositionHelper.compositionend.bind(term.compositionHelper, ev)();
+        /*term.compositionView.classList.remove('active');
         this.isComposing = false;
         var textarea = this;
         // Record composition position here as a new compositionstart event may fire before the
         setTimeout(function () {
           var input = textarea.value.substring(compositionPosition.start, compositionPosition.end);
           term.write(input);
-        }, 0);
+        }, 0);*/
       });
     };
 
         self.emit('blur', {terminal: self});
       }
       this.helperContainer.appendChild(this.textarea);
+
       this.compositionView = document.createElement('div');
       this.compositionView.classList.add('composition-view');
+      this.compositionHelper = new CompositionHelper(this.textarea, this.compositionView, this);
       this.helperContainer.appendChild(this.compositionView);
 
       for (; i < this.rows; i++) {
         this.element.appendChild(this.rowContainer);
       }
 
-      // TODO: Put in a listener?
-      // Update composition view contents and position
-      var cursor = document.querySelector('.terminal-cursor');
-      term.compositionView.style.left = cursor.offsetLeft + 'px';
-      term.compositionView.style.top = cursor.offsetTop + 'px';
+      // TODO: Attach to refresh event instead?
+      term.compositionHelper.updateCursorPosition();
 
       this.emit('refresh', {element: this.element, start: start, end: end});
     };
      * @param {KeyboardEvent} ev The keydown event to be handled.
      */
     Terminal.prototype.keyDown = function(ev) {
-      if (this.isComposing) {
+      if (this.compositionHelper.isComposing) {
         return;
       }