-
Notifications
You must be signed in to change notification settings - Fork 152
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add MutationHandler, reparse entire post when new nodes appear
* adds editor#_reparseSections and editor#_reparsePost * adds RenderTree#isDirty, use it to determine whether to rerender the cursor position after reparsing * tests for changing text and element nodes in the editor dom * Remove editor#reparse and #_reparseCurrentSection fixes #300
- Loading branch information
Showing
8 changed files
with
399 additions
and
131 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
import Set from 'mobiledoc-kit/utils/set'; | ||
import { forEach, filter } from 'mobiledoc-kit/utils/array-utils'; | ||
import assert from 'mobiledoc-kit/utils/assert'; | ||
|
||
const MUTATION = { | ||
NODES_CHANGED: 'childList', | ||
CHARACTER_DATA: 'characterData' | ||
}; | ||
|
||
export default class MutationHandler { | ||
constructor(editor) { | ||
this.editor = editor; | ||
this.renderTree = null; | ||
this._isObserving = false; | ||
|
||
this._observer = new MutationObserver((mutations) => { | ||
this._handleMutations(mutations); | ||
}); | ||
} | ||
|
||
destroy() { | ||
this.stopObserving(); | ||
this._observer = null; | ||
} | ||
|
||
suspendObservation(callback) { | ||
this.stopObserving(); | ||
callback(); | ||
this.startObserving(); | ||
} | ||
|
||
stopObserving() { | ||
if (this._isObserving) { | ||
this._isObserving = false; | ||
this._observer.disconnect(); | ||
} | ||
} | ||
|
||
startObserving() { | ||
if (!this._isObserving) { | ||
let { editor } = this; | ||
assert('Cannot observe un-rendered editor', editor.hasRendered); | ||
|
||
this._isObserving = true; | ||
this.renderTree = editor._renderTree; | ||
|
||
this._observer.observe(editor.element, { | ||
characterData: true, | ||
childList: true, | ||
subtree: true | ||
}); | ||
} | ||
} | ||
|
||
reparsePost() { | ||
this.editor._reparsePost(); | ||
} | ||
|
||
reparseSections(sections) { | ||
this.editor._reparseSections(sections); | ||
} | ||
|
||
/** | ||
* for each mutation: | ||
* * find the target nodes: | ||
* * if nodes changed, target nodes are: | ||
* * added nodes | ||
* * the target from which removed nodes were removed | ||
* * if character data changed | ||
* * target node is the mutation event's target (text node) | ||
* * filter out nodes that are no longer attached (parentNode is null) | ||
* * for each remaining node: | ||
* * find its section, add to sections-to-reparse | ||
* * if no section, reparse all (and break) | ||
*/ | ||
_handleMutations(mutations) { | ||
let reparsePost = false; | ||
let sections = new Set(); | ||
|
||
for (let i = 0; i < mutations.length; i++) { | ||
if (reparsePost) { | ||
break; | ||
} | ||
|
||
let nodes = this._findTargetNodes(mutations[i]); | ||
|
||
for (let j=0; j < nodes.length; j++) { | ||
let section = this._findSectionFromNode(nodes[j]); | ||
if (section) { | ||
sections.add(section); | ||
} else { | ||
reparsePost = true; | ||
break; | ||
} | ||
} | ||
} | ||
|
||
if (reparsePost) { | ||
this.reparsePost(); | ||
} else if (sections.length) { | ||
this.reparseSections(sections.toArray()); | ||
} | ||
} | ||
|
||
_findTargetNodes(mutation) { | ||
let nodes = []; | ||
switch (mutation.type) { | ||
case MUTATION.CHARACTER_DATA: | ||
nodes.push(mutation.target); | ||
break; | ||
case MUTATION.NODES_CHANGED: | ||
forEach(mutation.addedNodes, n => nodes.push(n)); | ||
if (mutation.removedNodes.length) { | ||
nodes.push(mutation.target); | ||
} | ||
break; | ||
} | ||
|
||
let attachedNodes = filter(nodes, node => !!node.parentNode); | ||
return attachedNodes; | ||
} | ||
|
||
_findSectionFromNode(node) { | ||
let rn = this.renderTree.findRenderNodeFromElement(node, (rn) => { | ||
return rn.postNode.isSection; | ||
}); | ||
return rn && rn.postNode; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.