Index: trunk/extensions/VisualEditor/demos/ce/index.php |
— | — | @@ -125,6 +125,8 @@ |
126 | 126 | <script src="../../modules/ve/ce/ve.ce.LeafNode.js"></script> |
127 | 127 | <script src="../../modules/ve/ce/ve.ce.Content.js"></script> |
128 | 128 | <script src="../../modules/ve/ce/ve.ce.Surface.js"></script> |
| 129 | + <script src="../../modules/ve/ce/ve.ce.CursorObserver.js"></script> |
| 130 | + <script src="../../modules/ve/ce/ve.ce.ContentObserver.js"></script> |
129 | 131 | |
130 | 132 | <script src="../../modules/ve/ce/nodes/ve.ce.DocumentNode.js"></script> |
131 | 133 | <script src="../../modules/ve/ce/nodes/ve.ce.HeadingNode.js"></script> |
Index: trunk/extensions/VisualEditor/modules/ve/ce/ve.ce.CursorObserver.js |
— | — | @@ -0,0 +1,95 @@ |
| 2 | +ve.ce.CursorObserver = function( documentView ) {
|
| 3 | + // Inheritance
|
| 4 | + ve.EventEmitter.call( this );
|
| 5 | +
|
| 6 | + this.documentView = documentView;
|
| 7 | + this.anchorNode = null;
|
| 8 | + this.anchorOffset = null;
|
| 9 | + this.focusNode = null;
|
| 10 | + this.focusOffset = null;
|
| 11 | +};
|
| 12 | +
|
| 13 | +ve.ce.CursorObserver.prototype.update = function() {
|
| 14 | + var _this = this;
|
| 15 | +
|
| 16 | + setTimeout( function() {
|
| 17 | + if ( !_this.documentView.$.is(':focus') ) {
|
| 18 | + if ( _this.anchorNode !== null
|
| 19 | + || _this.anchorOffset !== null
|
| 20 | + || _this.focusNode !== null
|
| 21 | + || _this.focusOffset !== null ) {
|
| 22 | + _this.anchorNode = _this.anchorOffset = _this.focusNode = _this.focusOffset = null;
|
| 23 | + _this.emit( 'change', null )
|
| 24 | + }
|
| 25 | + } else {
|
| 26 | + var rangySel = rangy.getSelection(),
|
| 27 | + range;
|
| 28 | + if ( rangySel.anchorNode !== _this.anchorNode
|
| 29 | + || rangySel.anchorOffset !== _this.anchorOffset
|
| 30 | + || rangySel.focusNode !== _this.focusNode
|
| 31 | + || rangySel.focusOffset !== _this.focusOffset ) {
|
| 32 | + _this.anchorNode = rangySel.anchorNode;
|
| 33 | + _this.anchorOffset = rangySel.anchorOffset;
|
| 34 | + _this.focusNode = rangySel.focusNode;
|
| 35 | + _this.focusOffset = rangySel.focusOffset;
|
| 36 | +
|
| 37 | + if ( rangySel.isCollapsed ) {
|
| 38 | + range = new ve.Range( _this.getOffset( _this.anchorNode, _this.anchorOffset ) );
|
| 39 | + } else {
|
| 40 | + range = new ve.Range(
|
| 41 | + _this.getOffset( _this.anchorNode, _this.anchorOffset ),
|
| 42 | + _this.getOffset( _this.focusNode, _this.focusOffset )
|
| 43 | + );
|
| 44 | + }
|
| 45 | + _this.emit( 'change', range )
|
| 46 | + }
|
| 47 | + }
|
| 48 | + }, 0 );
|
| 49 | +};
|
| 50 | +
|
| 51 | +ve.ce.CursorObserver.prototype.getOffset = function( selectionNode, selectionOffset ) {
|
| 52 | + var $leafNode = ve.ce.Surface.getLeafNode( selectionNode ),
|
| 53 | + current = [$leafNode.contents(), 0],
|
| 54 | + stack = [current],
|
| 55 | + offset = 0;
|
| 56 | +
|
| 57 | + while ( stack.length > 0 ) {
|
| 58 | + if ( current[1] >= current[0].length ) {
|
| 59 | + stack.pop();
|
| 60 | + current = stack[ stack.length - 1 ];
|
| 61 | + continue;
|
| 62 | + }
|
| 63 | + var item = current[0][current[1]];
|
| 64 | + var $item = current[0].eq( current[1] );
|
| 65 | +
|
| 66 | + if ( item.nodeType === 3 ) {
|
| 67 | + if ( item === selectionNode ) {
|
| 68 | + offset += selectionOffset;
|
| 69 | + break;
|
| 70 | + } else {
|
| 71 | + offset += item.textContent.length;
|
| 72 | + }
|
| 73 | + } else if ( item.nodeType === 1 ) {
|
| 74 | + if ( $( item ).attr( 'contentEditable' ) === 'false' ) {
|
| 75 | + offset += 1;
|
| 76 | + } else {
|
| 77 | + if ( item === selectionNode ) {
|
| 78 | + offset += selectionOffset;
|
| 79 | + break;
|
| 80 | + }
|
| 81 | + stack.push( [$item.contents(), 0] );
|
| 82 | + current[1]++;
|
| 83 | + current = stack[stack.length-1];
|
| 84 | + continue;
|
| 85 | + }
|
| 86 | + }
|
| 87 | + current[1]++;
|
| 88 | + }
|
| 89 | + return this.documentView.getOffsetFromNode(
|
| 90 | + $leafNode.data( 'view' )
|
| 91 | + ) + 1 + offset;
|
| 92 | +};
|
| 93 | +
|
| 94 | +/* Inheritance */
|
| 95 | +
|
| 96 | +ve.extendClass( ve.ce.CursorObserver , ve.EventEmitter ); |
\ No newline at end of file |
Index: trunk/extensions/VisualEditor/modules/ve/ce/ve.ce.ContentObserver.js |
— | — | @@ -0,0 +1,54 @@ |
| 2 | +ve.ce.ContentObserver = function( documentView ) {
|
| 3 | + // Inheritance
|
| 4 | + ve.EventEmitter.call( this );
|
| 5 | +
|
| 6 | + this.$node = null;
|
| 7 | + this.interval = null;
|
| 8 | + this.frequency = 100;
|
| 9 | + this.prevText = null;
|
| 10 | + this.prevHash = null;
|
| 11 | +};
|
| 12 | +
|
| 13 | +ve.ce.ContentObserver.prototype.setElement = function( $node ) {
|
| 14 | + if ( this.$node !== $node ) {
|
| 15 | + this.stop();
|
| 16 | +
|
| 17 | + this.$node = $node;
|
| 18 | + this.prevText = ve.ce.Surface.getDOMText2( this.$node[0] );
|
| 19 | + this.prevHash = ve.ce.Surface.getDOMHash( this.$node[0] );
|
| 20 | +
|
| 21 | + this.start();
|
| 22 | + }
|
| 23 | +};
|
| 24 | +
|
| 25 | +ve.ce.ContentObserver.prototype.stop = function() {
|
| 26 | + if ( this.interval !== null ) {
|
| 27 | + clearInterval( this.interval );
|
| 28 | + this.interval = null;
|
| 29 | + this.poll();
|
| 30 | + this.$node = null;
|
| 31 | + }
|
| 32 | +};
|
| 33 | +
|
| 34 | +ve.ce.ContentObserver.prototype.start = function() {
|
| 35 | + this.poll();
|
| 36 | + var _this = this;
|
| 37 | + setTimeout( function() { _this.poll(); }, 0);
|
| 38 | + this.interval = setInterval( function() { _this.poll(); }, this.frequency );
|
| 39 | +};
|
| 40 | +
|
| 41 | +ve.ce.ContentObserver.prototype.poll = function() {
|
| 42 | + console.log(this.$node[0]);
|
| 43 | + var text = ve.ce.Surface.getDOMText2( this.$node[0] );
|
| 44 | + var hash = ve.ce.Surface.getDOMHash( this.$node[0] );
|
| 45 | +
|
| 46 | + if ( text !== this.prevText || hash !== this.prevHash ) {
|
| 47 | + this.emit('change');
|
| 48 | + this.prevText = text;
|
| 49 | + this.prevHash = hash;
|
| 50 | + }
|
| 51 | +};
|
| 52 | +
|
| 53 | +/* Inheritance */
|
| 54 | +
|
| 55 | +ve.extendClass( ve.ce.ContentObserver , ve.EventEmitter ); |
\ No newline at end of file |