You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					117 lines
				
				3.1 KiB
			
		
		
			
		
	
	
					117 lines
				
				3.1 KiB
			| 
								 
											4 years ago
										 
									 | 
							
								import Parchment from 'parchment';
							 | 
						||
| 
								 | 
							
								import TextBlot from './text';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class Cursor extends Parchment.Embed {
							 | 
						||
| 
								 | 
							
								  static value() {
							 | 
						||
| 
								 | 
							
								    return undefined;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  constructor(domNode, selection) {
							 | 
						||
| 
								 | 
							
								    super(domNode);
							 | 
						||
| 
								 | 
							
								    this.selection = selection;
							 | 
						||
| 
								 | 
							
								    this.textNode = document.createTextNode(Cursor.CONTENTS);
							 | 
						||
| 
								 | 
							
								    this.domNode.appendChild(this.textNode);
							 | 
						||
| 
								 | 
							
								    this._length = 0;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  detach() {
							 | 
						||
| 
								 | 
							
								    // super.detach() will also clear domNode.__blot
							 | 
						||
| 
								 | 
							
								    if (this.parent != null) this.parent.removeChild(this);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  format(name, value) {
							 | 
						||
| 
								 | 
							
								    if (this._length !== 0) {
							 | 
						||
| 
								 | 
							
								      return super.format(name, value);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    let target = this, index = 0;
							 | 
						||
| 
								 | 
							
								    while (target != null && target.statics.scope !== Parchment.Scope.BLOCK_BLOT) {
							 | 
						||
| 
								 | 
							
								      index += target.offset(target.parent);
							 | 
						||
| 
								 | 
							
								      target = target.parent;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (target != null) {
							 | 
						||
| 
								 | 
							
								      this._length = Cursor.CONTENTS.length;
							 | 
						||
| 
								 | 
							
								      target.optimize();
							 | 
						||
| 
								 | 
							
								      target.formatAt(index, Cursor.CONTENTS.length, name, value);
							 | 
						||
| 
								 | 
							
								      this._length = 0;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  index(node, offset) {
							 | 
						||
| 
								 | 
							
								    if (node === this.textNode) return 0;
							 | 
						||
| 
								 | 
							
								    return super.index(node, offset);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  length() {
							 | 
						||
| 
								 | 
							
								    return this._length;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  position() {
							 | 
						||
| 
								 | 
							
								    return [this.textNode, this.textNode.data.length];
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  remove() {
							 | 
						||
| 
								 | 
							
								    super.remove();
							 | 
						||
| 
								 | 
							
								    this.parent = null;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  restore() {
							 | 
						||
| 
								 | 
							
								    if (this.selection.composing || this.parent == null) return;
							 | 
						||
| 
								 | 
							
								    let textNode = this.textNode;
							 | 
						||
| 
								 | 
							
								    let range = this.selection.getNativeRange();
							 | 
						||
| 
								 | 
							
								    let restoreText, start, end;
							 | 
						||
| 
								 | 
							
								    if (range != null && range.start.node === textNode && range.end.node === textNode) {
							 | 
						||
| 
								 | 
							
								      [restoreText, start, end] = [textNode, range.start.offset, range.end.offset];
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    // Link format will insert text outside of anchor tag
							 | 
						||
| 
								 | 
							
								    while (this.domNode.lastChild != null && this.domNode.lastChild !== this.textNode) {
							 | 
						||
| 
								 | 
							
								      this.domNode.parentNode.insertBefore(this.domNode.lastChild, this.domNode);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (this.textNode.data !== Cursor.CONTENTS) {
							 | 
						||
| 
								 | 
							
								      let text = this.textNode.data.split(Cursor.CONTENTS).join('');
							 | 
						||
| 
								 | 
							
								      if (this.next instanceof TextBlot) {
							 | 
						||
| 
								 | 
							
								        restoreText = this.next.domNode;
							 | 
						||
| 
								 | 
							
								        this.next.insertAt(0, text);
							 | 
						||
| 
								 | 
							
								        this.textNode.data = Cursor.CONTENTS;
							 | 
						||
| 
								 | 
							
								      } else {
							 | 
						||
| 
								 | 
							
								        this.textNode.data = text;
							 | 
						||
| 
								 | 
							
								        this.parent.insertBefore(Parchment.create(this.textNode), this);
							 | 
						||
| 
								 | 
							
								        this.textNode = document.createTextNode(Cursor.CONTENTS);
							 | 
						||
| 
								 | 
							
								        this.domNode.appendChild(this.textNode);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    this.remove();
							 | 
						||
| 
								 | 
							
								    if (start != null) {
							 | 
						||
| 
								 | 
							
								      [start, end] = [start, end].map(function(offset) {
							 | 
						||
| 
								 | 
							
								        return Math.max(0, Math.min(restoreText.data.length, offset - 1));
							 | 
						||
| 
								 | 
							
								      });
							 | 
						||
| 
								 | 
							
								      return {
							 | 
						||
| 
								 | 
							
								        startNode: restoreText,
							 | 
						||
| 
								 | 
							
								        startOffset: start,
							 | 
						||
| 
								 | 
							
								        endNode: restoreText,
							 | 
						||
| 
								 | 
							
								        endOffset: end
							 | 
						||
| 
								 | 
							
								      };
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  update(mutations, context) {
							 | 
						||
| 
								 | 
							
								    if (mutations.some((mutation) => {
							 | 
						||
| 
								 | 
							
								      return mutation.type === 'characterData' && mutation.target === this.textNode;
							 | 
						||
| 
								 | 
							
								    })) {
							 | 
						||
| 
								 | 
							
								      let range = this.restore();
							 | 
						||
| 
								 | 
							
								      if (range) context.range = range;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  value() {
							 | 
						||
| 
								 | 
							
								    return '';
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								Cursor.blotName = 'cursor';
							 | 
						||
| 
								 | 
							
								Cursor.className = 'ql-cursor';
							 | 
						||
| 
								 | 
							
								Cursor.tagName = 'span';
							 | 
						||
| 
								 | 
							
								Cursor.CONTENTS = "\uFEFF";   // Zero width no break space
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export default Cursor;
							 |