diff --git a/demos/ce/index.php b/demos/ce/index.php
index 13de83ee36..75dddb787d 100644
--- a/demos/ce/index.php
+++ b/demos/ce/index.php
@@ -125,8 +125,7 @@ include( '../../modules/sandbox/base.php' );
-
-
+
diff --git a/modules/ve/ce/ve.ce.Surface.js b/modules/ve/ce/ve.ce.Surface.js
index 4b6a300cba..cf7cc55de8 100644
--- a/modules/ve/ce/ve.ce.Surface.js
+++ b/modules/ve/ce/ve.ce.Surface.js
@@ -28,18 +28,30 @@ ve.ce.Surface = function( $container, model ) {
this.clipboard = {};
this.autoRender = false;
+ // Content Observer
+ this.surfaceObserver = new ve.ce.SurfaceObserver( this.documentView );
+ this.surfaceObserver.on( 'cursor', function( info ) {
+ //console.log("cursor", info);
+ } )
+
// Events
this.documentView.$.bind( {
'focus': function( e ) {
+ _this.surfaceObserver.updateCursor( true );
_this.documentOnFocus();
$document.unbind( '.ce-surfaceView' );
$document.bind( {
'keydown.ce-surfaceView': function( e ) {
+ _this.surfaceObserver.updateCursor( true );
return _this.onKeyDown( e );
+ },
+ 'mousemove.ce-surfaceView': function( e ) {
+ _this.surfaceObserver.updateCursor( true );
}
} );
},
'blur': function( e ) {
+ _this.surfaceObserver.updateCursor( true );
_this.documentOnBlur();
$document.unbind( '.ce-surfaceView' );
}
@@ -53,7 +65,8 @@ ve.ce.Surface = function( $container, model ) {
_this.onPaste( e );
} )
.on( 'mousedown', function( e ) {
- return _this.onMouseDown( e );
+ _this.surfaceObserver.updateCursor( true );
+ return _this.onMouseDown( e );
} )
.on( 'compositionstart', function( e ) {
console.log('comp start');
@@ -324,6 +337,7 @@ ve.ce.Surface.prototype.clearPollData = function() {
};
ve.ce.Surface.prototype.pollContent = function() {
+ return;
var localOffset, text, hash;
if ( this.poll.compositionStart !== null && this.poll.compositionEnd !== null ) {
@@ -634,6 +648,10 @@ ve.ce.Surface.prototype.showSelection = function( range ) {
};
ve.ce.Surface.prototype.getLeafNode = function( elem ) {
+ return ve.ce.Surface.getLeafNode( elem );
+};
+
+ve.ce.Surface.getLeafNode = function( elem ) {
var $node = $( elem );
while( !$node.hasClass( 'ce-leafNode' ) ) {
$node = $node.parent();
diff --git a/modules/ve/ce/ve.ce.SurfaceObserver.js b/modules/ve/ce/ve.ce.SurfaceObserver.js
new file mode 100644
index 0000000000..c0418e2720
--- /dev/null
+++ b/modules/ve/ce/ve.ce.SurfaceObserver.js
@@ -0,0 +1,166 @@
+ve.ce.SurfaceObserver = function( documentView ) {
+ // Inheritance
+ ve.EventEmitter.call( this );
+
+ this.documentView = documentView;
+
+ this.anchorNode = null;
+ this.anchorOffset = null;
+ this.focusNode = null;
+ this.focusOffset = null;
+ this.range = null;
+
+ this.$node = null;
+ this.interval = null;
+ this.frequency = 100;
+ this.prevText = null;
+ this.prevHash = null;
+ this.prevRange = null;
+
+ var _this = this;
+
+ this.on( 'select', function( range ) {
+ if ( range !== null && range.getLength() === 0 ) {
+ var node = _this.documentView.getNodeFromOffset( range.start );
+ _this.setNode( node.$ );
+ } else {
+ _this.stop();
+ }
+ } );
+};
+
+ve.ce.SurfaceObserver.prototype.setNode = function( $node ) {
+ if ( this.$node !== $node ) {
+ this.stop();
+
+ this.$node = $node;
+ this.prevText = ve.ce.Surface.getDOMText2( this.$node[0] );
+ this.prevHash = ve.ce.Surface.getDOMHash( this.$node[0] );
+
+ this.start();
+ }
+};
+
+ve.ce.SurfaceObserver.prototype.stop = function() {
+ if ( this.interval !== null ) {
+ clearInterval( this.interval );
+ this.interval = null;
+ this.poll();
+ }
+};
+
+ve.ce.SurfaceObserver.prototype.start = function() {
+ this.poll();
+ var _this = this;
+ setTimeout( function() {_this.poll(); }, 0);
+ this.interval = setInterval( function() { _this.poll(); }, this.frequency );
+};
+
+ve.ce.SurfaceObserver.prototype.poll = function() {
+ var text = ve.ce.Surface.getDOMText2( this.$node[0] );
+ var hash = ve.ce.Surface.getDOMHash( this.$node[0] );
+
+ if ( text !== this.prevText || hash !== this.prevHash ) {
+ console.log(1);
+ this.emit('change', {
+ $node: this.$node,
+ prevText: this.prevText,
+ text: text,
+ prevHash: this.prevHash,
+ hash: hash
+ } );
+ this.prevText = text;
+ this.prevHash = hash;
+ }
+};
+
+ve.ce.SurfaceObserver.prototype.updateCursor = function( async ) {
+ if ( async ) {
+ var _this = this;
+ setTimeout( function() {
+ _this.updateCursor ( false );
+ }, 0 );
+ } else {
+ if ( !this.documentView.$.is(':focus') ) {
+ if (
+ this.anchorNode !== null ||
+ this.anchorOffset !== null ||
+ this.focusNode !== null ||
+ this.focusOffset !== null
+ ) {
+ this.anchorNode = this.anchorOffset = this.focusNode = this.focusOffset = null;
+ this.range = null;
+ this.emit( 'select', this.range );
+ }
+ } else {
+ var rangySel = rangy.getSelection();
+ if (
+ rangySel.anchorNode !== this.anchorNode ||
+ rangySel.anchorOffset !== this.anchorOffset ||
+ rangySel.focusNode !== this.focusNode ||
+ rangySel.focusOffset !== this.focusOffset
+ ) {
+ this.anchorNode = rangySel.anchorNode;
+ this.anchorOffset = rangySel.anchorOffset;
+ this.focusNode = rangySel.focusNode;
+ this.focusOffset = rangySel.focusOffset;
+ if ( rangySel.isCollapsed ) {
+ this.range = new ve.Range( this.getOffset( this.anchorNode, this.anchorOffset ) );
+ } else {
+ this.range = new ve.Range(
+ this.getOffset( this.anchorNode, this.anchorOffset ),
+ this.getOffset( this.focusNode, this.focusOffset )
+ );
+ }
+ this.emit( 'select', this.range );
+ }
+ }
+ }
+};
+
+ve.ce.SurfaceObserver.prototype.getOffset = function( selectionNode, selectionOffset ) {
+ var $leafNode = ve.ce.Surface.getLeafNode( selectionNode ),
+ current = [$leafNode.contents(), 0],
+ stack = [current],
+ offset = 0;
+
+ 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 ) {
+ if ( item === selectionNode ) {
+ offset += selectionOffset;
+ break;
+ } else {
+ offset += item.textContent.length;
+ }
+ } else if ( item.nodeType === 1 ) {
+ if ( $( item ).attr( 'contentEditable' ) === 'false' ) {
+ offset += 1;
+ } else {
+ if ( item === selectionNode ) {
+ offset += selectionOffset;
+ break;
+ }
+ stack.push( [$item.contents(), 0] );
+ current[1]++;
+ current = stack[stack.length-1];
+ continue;
+ }
+ }
+ current[1]++;
+ }
+ return this.documentView.getOffsetFromNode(
+ $leafNode.data( 'view' )
+ ) + 1 + offset;
+};
+
+/* Inheritance */
+
+ve.extendClass( ve.ce.SurfaceObserver , ve.EventEmitter );
\ No newline at end of file