https://www.mediawiki.org/wiki/Special:Code/MediaWiki/112755

Revision: 112755
Author:   inez
Date:     2012-03-01 01:28:39 +0000 (Thu, 01 Mar 2012)
Log Message:
-----------
Migreate text input method from playground to ce and ce demo

Modified Paths:
--------------
    trunk/extensions/VisualEditor/modules/ve/ce/ve.es.Surface.js

Modified: trunk/extensions/VisualEditor/modules/ve/ce/ve.es.Surface.js
===================================================================
--- trunk/extensions/VisualEditor/modules/ve/ce/ve.es.Surface.js        
2012-03-01 01:21:55 UTC (rev 112754)
+++ trunk/extensions/VisualEditor/modules/ve/ce/ve.es.Surface.js        
2012-03-01 01:28:39 UTC (rev 112755)
@@ -19,66 +19,74 @@
        this.model = model;
        this.documentView = new ve.es.DocumentNode( this.model.getDocument(), 
this );
        this.contextView = null;
-       this.clipboard = {};
        this.$ = $container
                .addClass( 'es-surfaceView' )
                .append( this.documentView.$ );
        this.emitUpdateTimeout = undefined;
-       this.node = null;
 
        // Events
        this.documentView.$.bind( {
                'focus': function( e ) {
+                       _this.documentOnFocus();
                        $document.unbind( '.ce-surfaceView' );
                        $document.bind( {
                                'keydown.ce-surfaceView': function( e ) {
-                                       return _this.onKeyDown( e );
+//                                     return _this.onKeyDown( e );
                                },
                        } );
-                       _this.setNode();
                },
                'blur': function( e ) {
+                       _this.documentOnBlur();
                        $document.unbind( '.ce-surfaceView' );
                }
        } );
 
        this.$.mousedown( function(e) {
-               return _this.onMouseDown( e );
+//             return _this.onMouseDown( e );
        } );
 
+       // Initialization
+       this.documentView.renderContent();
+
        // Prevent dragging text
        this.$.bind('dragover drop', function(e) {
                e.preventDefault();
        });
 
-       /*
-       this.model.getDocument().on( 'update', function() {
-               _this.emitUpdate( 25 );
-       } );
+       this.poll = {
+               interval: null,
+               frequency: 100,
+               node: null,
+               prevText: null,
+               prevHash: null,
+               prevOffset: null,
+               compositionStart: null,
+               compositionEnd: null
+       };
 
-       this.$.mousedown( function( e ) {
-               return _this.onMouseDown( e );
+       document.addEventListener( 'compositionstart', function( e ) {
+               _this.onCompositionStart( e );
        } );
-
-       this.$.mouseup( function( e ) {
-               //var selection = _this.getSelection();
-               //_this.showFakeCursorAt(selection.start);
+       document.addEventListener( 'compositionend', function( e ) {
+               _this.onCompositionEnd( e );
        } );
+};
 
-       this.$.on('paste', function( e ) {
-               _this.onPaste( e );
-       } );
+/* Methods */
 
-       this.$.on('cut copy', function( e ) {
-               _this.onCutCopy( e );
-       } );
-       */
+ve.es.Surface.prototype.onCompositionStart = function( e ) {
+       this.stopPolling();
 
-       // Initialization
-       this.documentView.renderContent();
+       var rangySel = rangy.getSelection();
+       this.poll.compositionStart = this.getOffset( rangySel.anchorNode, 
rangySel.anchorOffset, false );
 };
 
-/* Methods */
+ve.es.Surface.prototype.onCompositionEnd = function( e ) {
+       var rangySel = rangy.getSelection();
+       this.poll.compositionEnd = this.getOffset( rangySel.focusNode, 
rangySel.focusOffset, false );
+       
+       this.startPolling();
+};
 
 ve.es.Surface.prototype.attachContextView = function( contextView ) {
        this.contextView = contextView;
@@ -88,104 +96,117 @@
        return this.model;
 };
 
-ve.es.Surface.prototype.onKeyDown = function( e ) {
-       switch ( e.keyCode ) {
-               // Page up
-               case 33:
-               // Page down
-               case 34:
-               // Home
-               case 36:
-               // End
-               case 35:
-               // Up arrow
-               case 38:
-               // Down arrow
-               case 40:
-                       this.setNode();
-                       break;
-               // Left arrow
-               case 37:
-                       this.setNode( 'left' );
-                       break;
-               // Right arrow
-               case 39:
-                       this.setNode( 'right' );
-                       break;
+ve.es.Surface.prototype.documentOnFocus = function() {
+       this.startPolling();
+};
+
+ve.es.Surface.prototype.documentOnBlur = function() {
+       this.stopPolling();
+};
+
+ve.es.Surface.prototype.startPolling = function() {
+       if ( this.poll.interval === null ) {
+               var _this = this;
+               this.poll.interval = setInterval( function() {
+                       _this.pollContent();
+               }, this.poll.frequency );
+               this.pollContent();
        }
 };
 
-ve.es.Surface.prototype.onMouseDown = function( e ) {
-       this.setNode();
+ve.es.Surface.prototype.stopPolling = function() {
+       if ( this.poll.interval !== null ) {
+               clearInterval( this.poll.interval );
+               this.poll.interval = null;
+       }
 };
 
-ve.es.Surface.prototype.setNode = function( direction ) {
-       var _this = this;
-       
-       setTimeout( function() {
-               var rangySelection = rangy.getSelection();
+ve.es.Surface.prototype.pollContent = function() {
+       if ( this.poll.compositionStart !== null && this.poll.compositionEnd 
!== null ) {
+               var     text = ve.es.Surface.getDOMText2( this.poll.node ),
+                       hash = ve.es.Surface.getDOMHash( this.poll.node ),
+                       localOffset = this.poll.compositionEnd;
+               this.poll.compositionStart = null;
+               this.poll.compositionEnd = null;
+       } else {
+               var rangySel = rangy.getSelection();
 
-               if ( rangySelection.anchorNode === _this.node ) {
+               if ( rangySel.anchorNode === null ) {
                        return;
                }
 
-               if ( rangySelection.anchorNode.nodeType !== 3 ) {
-                       if ( _this.node === null ) {
-                               throw "Value of this.node shouldn't be a null";
-                       }
-                       if ( direction !== 'left' && direction !== 'right' ) {
-                               throw "At this point value of direction should 
be 'left' or 'right'";
-                       }
-                       var     oldOffset = _this.getOffset( _this.node, 0 ),
-                               newOffset;
+               var     node = this.getLeafNode( rangySel.anchorNode )[0],
+                       text = ve.es.Surface.getDOMText2( node ),
+                       hash = ve.es.Surface.getDOMHash( node );
 
-                       if ( direction === 'left' ) {
-                               newOffset = 
_this.documentView.model.getRelativeContentOffset( oldOffset, -1 );
-                       } else if ( direction === 'right' ) {
-                               newOffset = 
_this.documentView.model.getRelativeContentOffset( oldOffset + 
_this.node.length, 1 );
-                       }
-                       _this.showCursorAt( newOffset );
-                       _this.setNode();
+               if ( rangySel.anchorNode !== rangySel.focusNode || 
rangySel.anchorOffset !== rangySel.focusOffset ) {
+                       var localOffset = null;
+               } else {
+                       var localOffset = this.getOffset( rangySel.anchorNode, 
rangySel.anchorOffset, false );
+               }
+
+               if ( node !== this.poll.node ) {
+                       this.poll.node = node;
+                       this.poll.prevText = text;
+                       this.poll.prevHash = hash;
+                       this.poll.prevOffset = localOffset;
                        return;
                }
+       }
 
-               _this.node = rangySelection.anchorNode;
-               
-               console.log(_this.node); 
-       }, 0 );
-};
+       if ( text !== this.poll.prevText ) {
+               var     nodeOffset = this.documentView.getOffsetFromNode( $( 
this.poll.node ).data( 'view' ) ),
+                       lengthDiff = text.length - this.poll.prevText.length,
+                       offsetDiff = ( localOffset !== null && 
this.poll.prevOffset !== null ) ? localOffset - this.poll.prevOffset : null;
 
-ve.es.Surface.prototype.getSelection = function() {
-       var selection = rangy.getSelection();
-
-       if ( selection.anchorNode === selection.focusNode && 
selection.anchorOffset === selection.focusOffset ) {
-               // cursor
-               var offset = this.getOffset( selection.anchorNode, 
selection.anchorOffset );
-               return new ve.Range( offset, offset );
-       } else {
-               // selection            
-               var offset1 = this.getOffset( selection.anchorNode, 
selection.anchorOffset );
-               var offset2 = this.getOffset( selection.focusNode, 
selection.focusOffset );
-               return new ve.Range( offset1, offset2 );
+               if ( lengthDiff === offsetDiff && this.poll.prevText.substring( 
0, this.poll.prevOffset ) === text.substring( 0, this.poll.prevOffset ) ) {
+                       var newData = text.substring( this.poll.prevOffset, 
localOffset ).split( '' );
+                       var annotations = 
this.model.getDocument().getAnnotationsFromOffset( nodeOffset + 1 + 
this.poll.prevOffset - 1 );
+                       ve.dm.DocumentNode.addAnnotationsToData( newData, 
annotations );
+                       this.model.transact( 
this.documentView.model.prepareInsertion(
+                               nodeOffset + 1 + this.poll.prevOffset,
+                               newData
+                       ) );
+               } else {
+                       var     sameFromLeft = 0,
+                               sameFromRight = 0,
+                               l = text.length > this.poll.prevText.length ? 
this.poll.prevText.length : text.length;
+                       while ( sameFromLeft < l && 
this.poll.prevText[sameFromLeft] == text[sameFromLeft] ) {
+                               ++sameFromLeft;
+                       }
+                       l = l - sameFromLeft;
+            while ( sameFromRight < l && 
this.poll.prevText[this.poll.prevText.length - 1 - sameFromRight] == 
text[text.length - 1 - sameFromRight] ) {
+                ++sameFromRight;
+                       }
+                       this.model.transact( 
this.documentView.model.prepareRemoval( new ve.Range(
+                               nodeOffset + 1 + sameFromLeft,
+                               nodeOffset + 1 + this.poll.prevText.length - 
sameFromRight
+                       ) ) );
+                       var newData = text.substring( sameFromLeft, text.length 
- sameFromRight ).split( '' ); 
+                       var annotations = 
this.model.getDocument().getAnnotationsFromOffset( nodeOffset + 1 + 
sameFromLeft - 1 );
+                       ve.dm.DocumentNode.addAnnotationsToData( newData, 
annotations );
+                       this.model.transact( 
this.documentView.model.prepareInsertion(
+                               nodeOffset + 1 + sameFromLeft,
+                               newData
+                       ) );
+               }
+               this.poll.prevText = text;
        }
-};
-
-ve.es.Surface.prototype.getOffset = function( localNode, localOffset ) {
-       var $node = $( localNode );
-       
-       if ( $node.hasClass( 'ce-leafNode' ) ) {
-               return this.documentView.getOffsetFromNode( $node.data('view') 
) + 1;
+       if ( hash !== this.poll.prevHash ) {
+               // TODO: redisplay cursor in correct position (with setTimeout)
+               this.getLeafNode( this.poll.node ).data( 'view' 
).renderContent();
+               this.poll.prevHash = hash;
        }
        
-       while( !$node.hasClass( 'ce-leafNode' ) ) {
-               $node = $node.parent();
-       }
-       
-       var current = [$node.contents(), 0];
-       var stack = [current];
-       
-       var offset = 0;
-       
+       this.poll.prevOffset = localOffset;
+};
+
+ve.es.Surface.prototype.getOffset = function( elem, offset, global ) {
+       var     $leafNode = this.getLeafNode( elem ),
+               current = [$leafNode.contents(), 0],
+               stack = [current],
+               localOffset = 0;
+
        while ( stack.length > 0 ) {
                if ( current[1] >= current[0].length ) {
                        stack.pop();
@@ -196,18 +217,18 @@
                var $item = current[0].eq( current[1] );
                
                if ( item.nodeType === 3 ) {
-                       if ( item === localNode ) {
-                               offset += localOffset;
+                       if ( item === elem ) {
+                               localOffset += offset;
                                break;
                        } else {
-                               offset += item.textContent.length;
+                               localOffset += item.textContent.length;
                        }
                } else if ( item.nodeType === 1 ) {
-                       if ( $( item ).attr('contentEditable') === "false" ) {
+                       if ( $( item ).attr( 'contentEditable' ) === "false" ) {
                                offset += 1;
                        } else {
-                               if ( item === localNode ) {
-                                       offset += localOffset;
+                               if ( item === elem ) {
+                                       localOffset += offset;
                                        break;
                                }
                        
@@ -219,8 +240,11 @@
                }
                current[1]++;
        }
-
-       return this.documentView.getOffsetFromNode( $node.data('view') ) + 1 + 
offset;
+       if ( global === true ) {
+               return this.documentView.getOffsetFromNode( $leafNode.data( 
'view' ) ) + 1 + localOffset;
+       } else {
+               return localOffset;
+       }
 };
 
 ve.es.Surface.prototype.showCursorAt = function( offset ) {
@@ -271,232 +295,61 @@
        sel.addRange(range);
 };
 
-/*
-ve.es.Surface.prototype.onCutCopy = function( e ) {
-       var _this = this,
-               key = rangy.getSelection().getRangeAt(0).toString().replace(/( 
|\r\n|\n|\r|\t)/gm,"");
-
-       _this.clipboard[key] = ve.copyArray( _this.documentView.model.getData( 
_this.getSelection() ) );
-
-       if ( event.type == 'cut' ) {
-               setTimeout( function() {
-                       document.execCommand('undo', false, false);
-               
-                       var selection = _this.getSelection();
-                       var tx = _this.model.getDocument().prepareRemoval( 
selection );
-                       _this.model.transact( tx );
-                       _this.showCursorAt( selection.start );
-               }, 1 );
+ve.es.Surface.prototype.getLeafNode = function( elem ) {
+       var     $node = $( elem );
+       while( !$node.hasClass( 'ce-leafNode' ) ) {
+               $node = $node.parent();
        }
+       return $node;
 };
-
-ve.es.Surface.prototype.onPaste = function( e ) {
-       var _this = this,
-               insertionPoint = _this.getSelection().start;
-       
-       $('#paste').html('').show().css('top', 
$(window).scrollTop()).css('left', $(window).scrollLeft()).focus();
-       
-       setTimeout( function() {
-               var key = $('#paste').hide().text().replace(/( 
|\r\n|\n|\r|\t)/gm,"");
-
-               if ( _this.clipboard[key] ) {
-                       var tx = _this.documentView.model.prepareInsertion( 
insertionPoint, _this.clipboard[key]);
-                       _this.model.transact( tx );
-                       _this.showCursorAt(insertionPoint + 
_this.clipboard[key].length);
-               } else {
-                       alert('i can only handle copy/paste from hybrid 
surface. sorry. :(');
-               }
                
-       }, 1 );
+ve.es.Surface.getDOMText2 = function( elem ) {
+       // TODO: there must be some better way to write this regex replace
+       var regex = new RegExp("[" + String.fromCharCode(32) + 
String.fromCharCode(160) + "]", "g");            
+       return ve.es.Surface.getDOMText( elem ).replace( regex, " " );
 };
-               
-ve.es.Surface.prototype.onMouseDown = function( e ) {
-       if ( this.worker !== null ) {
-               clearInterval( this.worker );
-       }
 
-       var _this = this;
-       
-       setTimeout( function() {
-               _this.node = rangy.getSelection().anchorNode;
-               var prevText = _this.node.textContent;
-               _this.worker = setInterval( function() {
+ve.es.Surface.getDOMText = function( elem ) {
+    var nodeType = elem.nodeType,
+        ret = '';
 
-                       if ( ( _this.node.previousSibling !== null && 
_this.node.previousSibling.nodeType === 3 ) || ( _this.node.nextSibling !== 
null && _this.node.nextSibling.nodeType === 3 ) ) {
-                               console.log("!");
-                               var start = _this.getSelection().start;
-                               _this.node.parentNode.normalize();
-                               _this.showCursorAt( start );
-                               _this.node = rangy.getSelection().anchorNode;
-                       }
-                       
-                       
-                       var text = _this.node.textContent;
-
-                       if ( text === prevText ) {
-                               return;
-                       }
-                       
-                       var nodeOffset = _this.getOffset( _this.node, 0 );
-
-            var sameFromLeft = 0,
-                sameFromRight = 0,
-                l = prevText.length;
-
-            while ( sameFromLeft < l && prevText[sameFromLeft] == 
text[sameFromLeft] ) {
-                ++sameFromLeft;
-                       }
-                       if ( prevText.length > sameFromLeft ) {
-                               l = l - sameFromLeft;
-                   while ( sameFromRight < l && prevText[prevText.length - 1 - 
sameFromRight] == text[text.length - 1 - sameFromRight] ) {
-                       ++sameFromRight;
-                               }
-                       }
-                       
-            if ( sameFromLeft + sameFromRight !== prevText.length ) {
-               // delete
-               var range = new ve.Range( nodeOffset + sameFromLeft, nodeOffset 
+ prevText.length - sameFromRight );
-               var tx = _this.model.getDocument().prepareRemoval( range );
-               _this.model.transact( tx );
+    if ( nodeType === 1 || nodeType === 9 ) {
+        // Use textContent || innerText for elements
+        if ( typeof elem.textContent === 'string' ) {
+            return elem.textContent;
+        } else if ( typeof elem.innerText === 'string' ) {
+            // Replace IE's carriage returns
+            return elem.innerText.replace( /\r\n/g, '' );
+        } else {
+            // Traverse it's children
+            for ( elem = elem.firstChild; elem; elem = elem.nextSibling) {
+                ret += ve.es.Surface.getDOMText( elem );
             }
-            
-            if ( sameFromLeft + sameFromRight !== text.length ) {
-                               // insert
-               var data = text.split('').slice(sameFromLeft, text.length - 
sameFromRight);
-               var annotations = 
_this.model.getDocument().getAnnotationsFromOffset( nodeOffset + sameFromLeft - 
1 );
-               ve.dm.DocumentNode.addAnnotationsToData( data, annotations );
-               var tx = _this.documentView.model.prepareInsertion( nodeOffset 
+ sameFromLeft, data);
-               _this.model.transact( tx );
-            }                  
+        }
+    } else if ( nodeType === 3 || nodeType === 4 ) {
+        return elem.nodeValue;
+    }
 
-                       prevText = text;
-               }, 50 );
-       }, 1 );
+    return ret;
 };
 
-ve.es.Surface.prototype.emitUpdate = function( delay ) {
-       if ( delay ) {
-               if ( this.emitUpdateTimeout !== undefined ) {
-                       return;
-               }
-               var _this = this;
-               this.emitUpdateTimeout = setTimeout( function() {
-                       _this.emit( 'update' ); 
-                       _this.emitUpdateTimeout = undefined;
-               }, delay );
-       } else {
-               this.emit( 'update' );  
-       }
-};
+ve.es.Surface.getDOMHash = function( elem ) {
+    var nodeType = elem.nodeType,
+       nodeName = elem.nodeName,
+        ret = '';
 
-ve.es.Surface.prototype.showCursorAt = function( offset ) {
-       var $node = this.documentView.getNodeFromOffset( offset ).$;
-       var current = [$node.contents(), 0];
-       var stack = [current];
-       var node;
-       var localOffset;
-       
-       var index = 1 + this.documentView.getOffsetFromNode( $node.data('view') 
);
-               
-       while ( stack.length > 0 ) {
-               if ( current[1] >= current[0].length ) {
-                       stack.pop();
-                       current = stack[ stack.length - 1 ];
-                       continue;
-               }
-               var item = current[0][current[1]];
-               var $item = current[0].eq( current[1] );
-               
-               if ( item.nodeType === 3 ) {
-                       var length = item.textContent.length;
-                       if ( offset >= index && offset <= index + length ) {
-                               node = item;
-                               localOffset = offset - index;
-                               break;
-                       } else {
-                               index += length;
-                       }
-               } else if ( item.nodeType === 1 ) {
-                       if ( $( item ).attr('contentEditable') === "false" ) {
-                               index += 1;
-                       } else {
-                               stack.push( [$item.contents(), 0] );
-                               current[1]++;
-                               current = stack[stack.length-1];
-                               continue;
-                       }
-               }
-               current[1]++;
+       if ( nodeType === 3 || nodeType === 4 ) {
+               return '#';
+       } else if ( nodeType === 1 || nodeType === 9 ) {
+               ret += '<' + nodeName + '>';
+               for ( elem = elem.firstChild; elem; elem = elem.nextSibling) {
+               ret += ve.es.Surface.getDOMHash( elem );
+        }
+        ret += '</' + nodeName + '>';
        }
-       var range = document.createRange();
-       range.collapsed = true;
-       range.setStart(node, localOffset);
-
-       var sel = window.getSelection();
-       sel.removeAllRanges();
-       sel.addRange(range);
+       return ret;
 };
 
-ve.es.Surface.prototype.showFakeCursorAt = function( offset ) {
-       var _this = this;
-
-       var $node = _this.documentView.getNodeFromOffset( offset ).$;
-       var current = [$node.contents(), 0];
-       var stack = [current];
-       var node;
-       var localOffset;
-       
-       var index = 1 + _this.documentView.getOffsetFromNode( 
$node.data('view') );
-
-       while ( stack.length > 0 ) {
-               if ( current[1] >= current[0].length ) {
-                       stack.pop();
-                       current = stack[ stack.length - 1 ];
-                       continue;
-               }
-               var item = current[0][current[1]];
-               var $item = current[0].eq( current[1] );
-               
-               if ( item.nodeType === 3 ) {
-                       var length = item.textContent.length;
-                       if ( offset >= index && offset <= index + length ) {
-                               node = item;
-                               localOffset = offset - index;
-                               break;
-                       } else {
-                               index += length;
-                       }
-               } else if ( item.nodeType === 1 ) {
-                       if ( $( item ).attr('contentEditable') === "false" ) {
-                               index += 1;
-                       } else {
-                               stack.push( [$item.contents(), 0] );
-                               current[1]++;
-                               current = stack[stack.length-1];
-                               continue;
-                       }
-               }
-               current[1]++;
-       }
-
-       // Delay by 3 seconds - just for demo
-       setTimeout(function() {
-               var sel = rangy.getSelection();
-               var range1 = sel.getRangeAt(0);                 
-               var range2 = rangy.createRange();
-               
-               range2.setStart(node, localOffset);
-       
-               sel.setSingleRange(range2);
-               
-               var position = rangy.getSelection().getStartDocumentPos();
-               $('#fake-cursor').css('top', position.y).css('left', 
position.x);
-               
-               sel.setSingleRange(range1);
-       }, 3000);
-}
-*/
-
 /* Inheritance */
 
 ve.extendClass( ve.es.Surface, ve.EventEmitter );


_______________________________________________
MediaWiki-CVS mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-cvs

Reply via email to