| import extend from 'extend'; | 
| import Delta from 'quill-delta'; | 
| import Parchment from 'parchment'; | 
| import Break from './break'; | 
| import Inline from './inline'; | 
| import TextBlot from './text'; | 
|   | 
|   | 
| const NEWLINE_LENGTH = 1; | 
|   | 
|   | 
| class BlockEmbed extends Parchment.Embed { | 
|   attach() { | 
|     super.attach(); | 
|     this.attributes = new Parchment.Attributor.Store(this.domNode); | 
|   } | 
|   | 
|   delta() { | 
|     return new Delta().insert(this.value(), extend(this.formats(), this.attributes.values())); | 
|   } | 
|   | 
|   format(name, value) { | 
|     let attribute = Parchment.query(name, Parchment.Scope.BLOCK_ATTRIBUTE); | 
|     if (attribute != null) { | 
|       this.attributes.attribute(attribute, value); | 
|     } | 
|   } | 
|   | 
|   formatAt(index, length, name, value) { | 
|     this.format(name, value); | 
|   } | 
|   | 
|   insertAt(index, value, def) { | 
|     if (typeof value === 'string' && value.endsWith('\n')) { | 
|       let block = Parchment.create(Block.blotName); | 
|       this.parent.insertBefore(block, index === 0 ? this : this.next); | 
|       block.insertAt(0, value.slice(0, -1)); | 
|     } else { | 
|       super.insertAt(index, value, def); | 
|     } | 
|   } | 
| } | 
| BlockEmbed.scope = Parchment.Scope.BLOCK_BLOT; | 
| // It is important for cursor behavior BlockEmbeds use tags that are block level elements | 
|   | 
|   | 
| class Block extends Parchment.Block { | 
|   constructor(domNode) { | 
|     super(domNode); | 
|     this.cache = {}; | 
|   } | 
|   | 
|   delta() { | 
|     if (this.cache.delta == null) { | 
|       this.cache.delta = this.descendants(Parchment.Leaf).reduce((delta, leaf) => { | 
|         if (leaf.length() === 0) { | 
|           return delta; | 
|         } else { | 
|           return delta.insert(leaf.value(), bubbleFormats(leaf)); | 
|         } | 
|       }, new Delta()).insert('\n', bubbleFormats(this)); | 
|     } | 
|     return this.cache.delta; | 
|   } | 
|   | 
|   deleteAt(index, length) { | 
|     super.deleteAt(index, length); | 
|     this.cache = {}; | 
|   } | 
|   | 
|   formatAt(index, length, name, value) { | 
|     if (length <= 0) return; | 
|     if (Parchment.query(name, Parchment.Scope.BLOCK)) { | 
|       if (index + length === this.length()) { | 
|         this.format(name, value); | 
|       } | 
|     } else { | 
|       super.formatAt(index, Math.min(length, this.length() - index - 1), name, value); | 
|     } | 
|     this.cache = {}; | 
|   } | 
|   | 
|   insertAt(index, value, def) { | 
|     if (def != null) return super.insertAt(index, value, def); | 
|     if (value.length === 0) return; | 
|     let lines = value.split('\n'); | 
|     let text = lines.shift(); | 
|     if (text.length > 0) { | 
|       if (index < this.length() - 1 || this.children.tail == null) { | 
|         super.insertAt(Math.min(index, this.length() - 1), text); | 
|       } else { | 
|         this.children.tail.insertAt(this.children.tail.length(), text); | 
|       } | 
|       this.cache = {}; | 
|     } | 
|     let block = this; | 
|     lines.reduce(function(index, line) { | 
|       block = block.split(index, true); | 
|       block.insertAt(0, line); | 
|       return line.length; | 
|     }, index + text.length); | 
|   } | 
|   | 
|   insertBefore(blot, ref) { | 
|     let head = this.children.head; | 
|     super.insertBefore(blot, ref); | 
|     if (head instanceof Break) { | 
|       head.remove(); | 
|     } | 
|     this.cache = {}; | 
|   } | 
|   | 
|   length() { | 
|     if (this.cache.length == null) { | 
|       this.cache.length = super.length() + NEWLINE_LENGTH; | 
|     } | 
|     return this.cache.length; | 
|   } | 
|   | 
|   moveChildren(target, ref) { | 
|     super.moveChildren(target, ref); | 
|     this.cache = {}; | 
|   } | 
|   | 
|   optimize(context) { | 
|     super.optimize(context); | 
|     this.cache = {}; | 
|   } | 
|   | 
|   path(index) { | 
|     return super.path(index, true); | 
|   } | 
|   | 
|   removeChild(child) { | 
|     super.removeChild(child); | 
|     this.cache = {}; | 
|   } | 
|   | 
|   split(index, force = false) { | 
|     if (force && (index === 0 || index >= this.length() - NEWLINE_LENGTH)) { | 
|       let clone = this.clone(); | 
|       if (index === 0) { | 
|         this.parent.insertBefore(clone, this); | 
|         return this; | 
|       } else { | 
|         this.parent.insertBefore(clone, this.next); | 
|         return clone; | 
|       } | 
|     } else { | 
|       let next = super.split(index, force); | 
|       this.cache = {}; | 
|       return next; | 
|     } | 
|   } | 
| } | 
| Block.blotName = 'block'; | 
| Block.tagName = 'P'; | 
| Block.defaultChild = 'break'; | 
| Block.allowedChildren = [Inline, Parchment.Embed, TextBlot]; | 
|   | 
|   | 
| function bubbleFormats(blot, formats = {}) { | 
|   if (blot == null) return formats; | 
|   if (typeof blot.formats === 'function') { | 
|     formats = extend(formats, blot.formats()); | 
|   } | 
|   if (blot.parent == null || blot.parent.blotName == 'scroll' || blot.parent.statics.scope !== blot.statics.scope) { | 
|     return formats; | 
|   } | 
|   return bubbleFormats(blot.parent, formats); | 
| } | 
|   | 
|   | 
| export { bubbleFormats, BlockEmbed, Block as default }; |