Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

prosemirror-view

Package Overview
Dependencies
Maintainers
1
Versions
282
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

prosemirror-view - npm Package Compare versions

Comparing version 0.15.2 to 0.16.0

11

dist/capturekeys.js

@@ -75,2 +75,4 @@ var ref = require("prosemirror-state");

else { break }
} else if (isBlockNode(node)) {
break
} else {

@@ -111,2 +113,4 @@ var prev = node.previousSibling

else { break }
} else if (isBlockNode(node)) {
break
} else {

@@ -117,3 +121,3 @@ var next = node.nextSibling

moveOffset = Array.prototype.indexOf.call(moveNode.childNodes, next) + 1
next = next.previousSibling
next = next.nextSibling
}

@@ -134,2 +138,7 @@ if (!next) {

function isBlockNode(dom) {
var desc = dom.pmViewDesc
return desc && desc.node && desc.node.isBlock
}
function setSel(sel, node, offset) {

@@ -136,0 +145,0 @@ var range = document.createRange()

80

dist/decoration.js

@@ -8,3 +8,3 @@ function compareObjs(a, b) {

var WidgetType = function WidgetType(widget, options) {
var WidgetType = function(widget, options) {
if (widget.nodeType != 1) {

@@ -21,3 +21,3 @@ var wrap = document.createElement("span")

WidgetType.prototype.map = function map (mapping, span, offset, oldOffset) {
WidgetType.prototype.map = function (mapping, span, offset, oldOffset) {
var ref = mapping.mapResult(span.from + oldOffset);

@@ -29,5 +29,5 @@ var pos = ref.pos;

WidgetType.prototype.valid = function valid () { return true };
WidgetType.prototype.valid = function () { return true };
WidgetType.prototype.eq = function eq (other) {
WidgetType.prototype.eq = function (other) {
return this == other ||

@@ -38,3 +38,3 @@ (other instanceof WidgetType && (this.widget == other.widget || this.options.key) &&

var InlineType = function InlineType(attrs, options) {
var InlineType = function(attrs, options) {
this.options = options || noOptions

@@ -44,3 +44,3 @@ this.attrs = attrs

InlineType.prototype.map = function map (mapping, span, offset, oldOffset) {
InlineType.prototype.map = function (mapping, span, offset, oldOffset) {
var from = mapping.map(span.from + oldOffset, this.options.inclusiveLeft ? -1 : 1) - offset

@@ -51,5 +51,5 @@ var to = mapping.map(span.to + oldOffset, this.options.inclusiveRight ? 1 : -1) - offset

InlineType.prototype.valid = function valid (_, span) { return span.from < span.to };
InlineType.prototype.valid = function (_, span) { return span.from < span.to };
InlineType.prototype.eq = function eq (other) {
InlineType.prototype.eq = function (other) {
return this == other ||

@@ -60,5 +60,5 @@ (other instanceof InlineType && compareObjs(this.attrs, other.attrs) &&

InlineType.is = function is (span) { return span.type instanceof InlineType };
InlineType.is = function (span) { return span.type instanceof InlineType };
var NodeType = function NodeType(attrs, options) {
var NodeType = function(attrs, options) {
this.attrs = attrs

@@ -68,3 +68,3 @@ this.options = options || noOptions

NodeType.prototype.map = function map (mapping, span, offset, oldOffset) {
NodeType.prototype.map = function (mapping, span, offset, oldOffset) {
var from = mapping.mapResult(span.from + oldOffset, 1)

@@ -77,3 +77,3 @@ if (from.deleted) { return null }

NodeType.prototype.valid = function valid (node, span) {
NodeType.prototype.valid = function (node, span) {
var ref = node.content.findIndex(span.from);

@@ -85,3 +85,3 @@ var index = ref.index;

NodeType.prototype.eq = function eq (other) {
NodeType.prototype.eq = function (other) {
return this == other ||

@@ -96,3 +96,3 @@ (other instanceof NodeType && compareObjs(this.attrs, other.attrs) &&

// static members of this class for details.
var Decoration = function Decoration(from, to, type) {
var Decoration = function(from, to, type) {
this.from = from

@@ -105,11 +105,11 @@ this.to = to

Decoration.prototype.copy = function copy (from, to) {
Decoration.prototype.copy = function (from, to) {
return new Decoration(from, to, this.type)
};
Decoration.prototype.eq = function eq (other) {
Decoration.prototype.eq = function (other) {
return this.type.eq(other.type) && this.from == other.from && this.to == other.to
};
Decoration.prototype.map = function map (mapping, offset, oldOffset) {
Decoration.prototype.map = function (mapping, offset, oldOffset) {
return this.type.map(mapping, this, offset, oldOffset)

@@ -135,4 +135,4 @@ };

// and reuse DOM nodes.
Decoration.widget = function widget (pos, widget, options) {
return new Decoration(pos, pos, new WidgetType(widget, options))
Decoration.widget = function (pos, dom, options) {
return new Decoration(pos, pos, new WidgetType(dom, options))
};

@@ -157,3 +157,3 @@

// [`inclusiveLeft`](#view.Decoration^inline^options.inclusiveLeft).
Decoration.inline = function inline (from, to, attrs, options) {
Decoration.inline = function (from, to, attrs, options) {
return new Decoration(from, to, new InlineType(attrs, options))

@@ -166,3 +166,3 @@ };

// node, will receive the given attributes.
Decoration.node = function node (from, to, attrs, options) {
Decoration.node = function (from, to, attrs, options) {
return new Decoration(from, to, new NodeType(attrs, options))

@@ -201,3 +201,3 @@ };

// modified, updates create a new value.
var DecorationSet = function DecorationSet(local, children) {
var DecorationSet = function(local, children) {
this.local = local && local.length ? local : none

@@ -210,3 +210,3 @@ this.children = children && children.length ? children : none

// document.
DecorationSet.create = function create (doc, decorations) {
DecorationSet.create = function (doc, decorations) {
return decorations.length ? buildTree(decorations, doc, 0, noOptions) : empty

@@ -220,3 +220,3 @@ };

// the set are collected.
DecorationSet.prototype.find = function find (start, end) {
DecorationSet.prototype.find = function (start, end) {
var result = []

@@ -227,3 +227,3 @@ this.findInner(start == null ? 0 : start, end == null ? 1e9 : end, result, 0)

DecorationSet.prototype.findInner = function findInner (start, end, result, offset) {
DecorationSet.prototype.findInner = function (start, end, result, offset) {
var this$1 = this;

@@ -254,3 +254,3 @@

// options of that decoration.
DecorationSet.prototype.map = function map (mapping, doc, options) {
DecorationSet.prototype.map = function (mapping, doc, options) {
if (this == empty) { return this }

@@ -260,3 +260,3 @@ return this.mapInner(mapping, doc, 0, 0, options || noOptions)

DecorationSet.prototype.mapInner = function mapInner (mapping, node, offset, oldOffset, options) {
DecorationSet.prototype.mapInner = function (mapping, node, offset, oldOffset, options) {
var this$1 = this;

@@ -281,3 +281,3 @@

// create the appropriate tree structure.
DecorationSet.prototype.add = function add (doc, decorations) {
DecorationSet.prototype.add = function (doc, decorations) {
if (!decorations.length) { return this }

@@ -288,3 +288,3 @@ if (this == empty) { return DecorationSet.create(doc, decorations) }

DecorationSet.prototype.addInner = function addInner (doc, decorations, offset) {
DecorationSet.prototype.addInner = function (doc, decorations, offset) {
var this$1 = this;

@@ -314,3 +314,3 @@

// the ones in the given array.
DecorationSet.prototype.remove = function remove (decorations) {
DecorationSet.prototype.remove = function (decorations) {
if (decorations.length == 0 || this == empty) { return this }

@@ -320,3 +320,3 @@ return this.removeInner(decorations, 0)

DecorationSet.prototype.removeInner = function removeInner (decorations, offset) {
DecorationSet.prototype.removeInner = function (decorations, offset) {
var this$1 = this;

@@ -353,3 +353,3 @@

DecorationSet.prototype.forChild = function forChild (offset, node) {
DecorationSet.prototype.forChild = function (offset, node) {
var this$1 = this;

@@ -380,3 +380,3 @@

DecorationSet.prototype.eq = function eq (other) {
DecorationSet.prototype.eq = function (other) {
var this$1 = this;

@@ -397,7 +397,7 @@

DecorationSet.prototype.locals = function locals (node) {
DecorationSet.prototype.locals = function (node) {
return removeOverlap(this.localsInner(node))
};
DecorationSet.prototype.localsInner = function localsInner (node) {
DecorationSet.prototype.localsInner = function (node) {
var this$1 = this;

@@ -422,7 +422,7 @@

var DecorationGroup = function DecorationGroup(members) {
var DecorationGroup = function(members) {
this.members = members
};
DecorationGroup.prototype.forChild = function forChild (offset, child) {
DecorationGroup.prototype.forChild = function (offset, child) {
var this$1 = this;

@@ -441,3 +441,3 @@

DecorationGroup.prototype.eq = function eq (other) {
DecorationGroup.prototype.eq = function (other) {
var this$1 = this;

@@ -452,3 +452,3 @@

DecorationGroup.prototype.locals = function locals (node) {
DecorationGroup.prototype.locals = function (node) {
var this$1 = this;

@@ -473,3 +473,3 @@

DecorationGroup.from = function from (members) {
DecorationGroup.from = function (members) {
switch (members.length) {

@@ -476,0 +476,0 @@ case 0: return empty

@@ -10,3 +10,3 @@ var ref = require("prosemirror-model");

var DOMChange = function DOMChange(view, id, composing) {
var DOMChange = function(view, id, composing) {
var this$1 = this;

@@ -23,3 +23,3 @@

DOMChange.prototype.addRange = function addRange (from, to) {
DOMChange.prototype.addRange = function (from, to) {
if (this.from == null) {

@@ -34,3 +34,3 @@ this.from = from

DOMChange.prototype.changedRange = function changedRange () {
DOMChange.prototype.changedRange = function () {
if (this.from == null) { return rangeAroundSelection(this.state.selection) }

@@ -42,7 +42,3 @@ var $from = this.state.doc.resolve(this.from), $to = this.state.doc.resolve(this.to)

DOMChange.prototype.read = function read (range) {
readDOMChange(this, this.state, range)
};
DOMChange.prototype.finish = function finish (force) {
DOMChange.prototype.finish = function (force) {
clearTimeout(this.timeout)

@@ -54,6 +50,9 @@ if (this.composing && !force) { return }

this.view.inDOMChange = null
this.read(range)
readDOMChange(this, this.state, range)
// If the reading didn't result in a view update, force one by
// resetting the view to its current state.
if (this.view.docView.dirty) { this.view.updateState(this.view.state) }
};
DOMChange.prototype.compositionEnd = function compositionEnd () {
DOMChange.prototype.compositionEnd = function () {
var this$1 = this;

@@ -67,3 +66,3 @@

DOMChange.start = function start (view, composing) {
DOMChange.start = function (view, composing) {
if (view.inDOMChange) {

@@ -192,2 +191,8 @@ if (composing) {

var parseResult, doc = oldState.doc, view = domChange.view
// If there have been changes since this DOM update started, we must
// map our start and end positions, as well as the new selection
// positions, through them.
var mapping = domChange.mappings.getMapping(view.state)
if (!mapping) { return }
for (;;) {

@@ -205,4 +210,11 @@ parseResult = parseBetween(view, oldState, range.from, range.to)

var change = findDiff(compare.content, parsed.content, range.from, oldState.selection.from)
if (!change) { return false }
if (!change) {
if (parsedSel) {
var sel = resolveSelection(view.state.doc, mapping, parsedSel)
if (!sel.eq(view.state.selection)) { view.props.onAction(sel.action()) }
}
return
}
var $from = parsed.resolveNoCache(change.start - range.from)

@@ -223,15 +235,5 @@ var $to = parsed.resolveNoCache(change.endB - range.from)

var from = change.start, to = change.endA
// If there have been changes since this DOM update started, we must
// map our start and end positions, as well as the new selection
// positions, through them.
var mapping = domChange.mappings.getMapping(view.state), $from1
if (!mapping) { return }
var from = mapping.map(change.start), to = mapping.map(change.endA, -1)
from = mapping.map(from)
to = mapping.map(to)
if (parsedSel) { parsedSel = {anchor: mapping.map(parsedSel.anchor),
head: mapping.map(parsedSel.head)} }
var tr = view.state.tr, handled = false, markChange
var tr = view.state.tr, handled = false, markChange, $from1
if ($from.sameParent($to) && $from.parent.isTextblock && $from.pos != $to.pos) {

@@ -257,8 +259,11 @@ if (change.endA == change.endB &&

{ tr.replace(from, to, parsed.slice(change.start - range.from, change.endB - range.from)) }
if (parsedSel)
{ tr.setSelection(Selection.between(tr.doc.resolve(parsedSel.anchor),
tr.doc.resolve(parsedSel.head))) }
if (parsedSel) { tr.setSelection(resolveSelection(tr.doc, mapping, parsedSel)) }
view.props.onAction(tr.scrollAction())
}
function resolveSelection(doc, mapping, parsedSel) {
return Selection.between(doc.resolve(mapping.map(parsedSel.anchor)),
doc.resolve(mapping.map(parsedSel.head)))
}
// : (Fragment, Fragment) → ?{mark: Mark, type: string}

@@ -265,0 +270,0 @@ // Given two same-length, non-empty fragments of inline content,

@@ -20,3 +20,4 @@ var ref = require("prosemirror-state");

var ref$5 = require("./decoration");
var viewDecorations = ref$5.viewDecorations;var assign;
var viewDecorations = ref$5.viewDecorations;
var Decoration = ref$5.Decoration;var assign;
((assign = require("./decoration"), exports.Decoration = assign.Decoration, exports.DecorationSet = assign.DecorationSet))

@@ -27,3 +28,3 @@

// [props](#view.EditorProps).
var EditorView = function EditorView(place, props) {
var EditorView = function(place, props) {
var this$1 = this;

@@ -49,3 +50,3 @@

// :: dom.Node
// :: dom.Element
// The editable DOM node containing the document. (You probably

@@ -55,9 +56,7 @@ // should not be directly interfering with its child nodes.)

this.updateDOMForProps()
if (place && place.appendChild) { place.appendChild(this.content) }
else if (place) { place(this.content) }
this.docView = docViewDesc(this.state.doc, viewDecorations(this), this.content, this)
this.content.contentEditable = true
this.editable = getEditable(this)
this.docView = docViewDesc(this.state.doc, computeDocDeco(this), viewDecorations(this), this.content, this)

@@ -67,2 +66,5 @@ this.lastSelectedViewDesc = null

initInput(this)
this.pluginViews = []
this.updatePluginViews()
};

@@ -75,3 +77,3 @@

// the view's DOM.
EditorView.prototype.update = function update (props) {
EditorView.prototype.update = function (props) {
this.props = props

@@ -84,3 +86,3 @@ this.updateState(props.state)

// other props.
EditorView.prototype.updateState = function updateState (state) {
EditorView.prototype.updateState = function (state) {
var prev = this.state

@@ -91,19 +93,18 @@ this.state = state

var redrawn = false
var decorations = viewDecorations(this)
var prevEditable = this.editable
this.editable = getEditable(this)
var innerDeco = viewDecorations(this), outerDeco = computeDocDeco(this)
if (!this.docView.matchesNode(state.doc, [], decorations)) {
if (!this.docView.matchesNode(state.doc, outerDeco, innerDeco)) {
stopObserving(this)
this.docView.update(state.doc, [], decorations, this)
this.docView.update(state.doc, outerDeco, innerDeco, this)
startObserving(this)
redrawn = true
}
if (redrawn || !state.selection.eq(prev.selection))
if (!state.selection.eq(prev.selection) || this.selectionReader.domChanged())
{ selectionToDOM(this, state.selection) }
this.updateDOMForProps()
if (prevEditable != this.editable) { this.selectionReader.editableChanged() }
this.updatePluginViews(prev)
// FIXME somehow schedule this relative to ui/update so that it
// doesn't cause extra layout
if (state.scrollToSelection > prev.scrollToSelection || prev.config != state.config)

@@ -113,21 +114,23 @@ { scrollPosIntoView(this, state.selection.head == null ? state.selection.from : state.selection.from) }

EditorView.prototype.updateDOMForProps = function updateDOMForProps () {
EditorView.prototype.destroyPluginViews = function () {
var view
while (view = this.pluginViews.pop()) { if (view.destroy) { view.destroy() } }
};
EditorView.prototype.updatePluginViews = function (prevState) {
var this$1 = this;
var spellcheck = !!this.someProp("spellcheck")
if (spellcheck != this.content.spellcheck) { this.content.spellcheck = spellcheck }
var label = this.someProp("label", function (f) { return f(this$1.state); }) || ""
if (this.content.getAttribute("aria-label") != label) { this.content.setAttribute("aria-label", label) }
var classes = ["ProseMirror", "ProseMirror-content"] // FIXME remove backwards-compat class
if (this.focused) { classes.push("ProseMirror-focused") }
if (this.state.selection.node) { classes.push("ProseMirror-nodeselection") }
this.someProp("class", function (f) {
var cls = f(this$1.state)
if (!cls) { return }
var array = cls.split(" ")
for (var i = 0; i < array.length; i++) { classes.push(array[i]) }
})
var className = classes.sort().join(" ")
if (this.content.className != className) { this.content.className = className }
var plugins = this.state.plugins
if (!prevState || prevState.plugins != plugins) {
this.destroyPluginViews()
for (var i = 0; i < plugins.length; i++) {
var plugin = plugins[i]
if (plugin.options.view) { this$1.pluginViews.push(plugin.options.view(this$1)) }
}
} else {
for (var i$1 = 0; i$1 < this.pluginViews.length; i$1++) {
var pluginView = this$1.pluginViews[i$1]
if (pluginView.update) { pluginView.update(this$1) }
}
}
};

@@ -137,4 +140,4 @@

// Query whether the view has focus.
EditorView.prototype.hasFocus = function hasFocus () {
if (this.content.ownerDocument.activeElement != this.content) { return false }
EditorView.prototype.hasFocus = function () {
if (this.editable && this.content.ownerDocument.activeElement != this.content) { return false }
var sel = this.root.getSelection()

@@ -151,5 +154,5 @@ return sel.rangeCount && this.content.contains(sel.anchorNode.nodeType == 3 ? sel.anchorNode.parentNode : sel.anchorNode)

// directly).
EditorView.prototype.someProp = function someProp (propName, f) {
EditorView.prototype.someProp = function (propName, f) {
var prop = this.props && this.props[propName], value
if (prop && (value = f ? f(prop) : prop)) { return value }
if (prop != null && (value = f ? f(prop) : prop)) { return value }
var plugins = this.state.plugins

@@ -164,5 +167,5 @@ if (plugins) { for (var i = 0; i < plugins.length; i++) {

// Focus the editor.
EditorView.prototype.focus = function focus () {
EditorView.prototype.focus = function () {
selectionToDOM(this, this.state.selection, true)
this.content.focus()
if (this.editable) { this.content.focus() }
};

@@ -193,3 +196,3 @@

// the top level.
EditorView.prototype.posAtCoords = function posAtCoords$1 (coords) { return posAtCoords(this, coords) };
EditorView.prototype.posAtCoords = function (coords) { return posAtCoords(this, coords) };

@@ -200,3 +203,3 @@ // :: (number) → {left: number, right: number, top: number, bottom: number}

// cursor-ish rectangle.
EditorView.prototype.coordsAtPos = function coordsAtPos$1 (pos) { return coordsAtPos(this, pos) };
EditorView.prototype.coordsAtPos = function (pos) { return coordsAtPos(this, pos) };

@@ -210,3 +213,3 @@ // :: (union<"up", "down", "left", "right", "forward", "backward">, ?EditorState) → bool

// isn't a cursor selection.
EditorView.prototype.endOfTextblock = function endOfTextblock$1 (dir, state) {
EditorView.prototype.endOfTextblock = function (dir, state) {
return endOfTextblock(this, state || this.state, dir)

@@ -218,4 +221,6 @@ };

// views](#view.NodeView).
EditorView.prototype.destroy = function destroy () {
EditorView.prototype.destroy = function () {
this.destroyPluginViews()
this.docView.destroy()
this.selectionReader.destroy()
EditorState.removeApplyListener(this.trackState)

@@ -226,3 +231,3 @@ if (this.content.parentNode) { this.content.parentNode.removeChild(this.content) }

// Used for testing.
EditorView.prototype.dispatchEvent = function dispatchEvent$1 (event) {
EditorView.prototype.dispatchEvent = function (event) {
return dispatchEvent(this, event)

@@ -234,2 +239,25 @@ };

function computeDocDeco(view) {
var attrs = Object.create(null)
attrs.class = "ProseMirror" + (view.focused ? " ProseMirror-focused" : "") +
(view.state.selection.node ? " ProseMirror-nodeselection" : "")
attrs.contenteditable = String(view.editable)
view.someProp("attributes", function (value) {
if (typeof value == "function") { value = value(view.state) }
if (value) { for (var attr in value) {
if (attr == "class")
{ attrs.class += " " + value[attr] }
else if (!attrs[attr] && attr != "contenteditable" && attr != "nodeName")
{ attrs[attr] = String(value[attr]) }
} }
})
return [Decoration.node(0, view.state.doc.content.size, attrs)]
}
function getEditable(view) {
return !view.someProp("editable", function (value) { return value(view.state) === false; })
}
// EditorProps:: interface

@@ -333,3 +361,3 @@ //

//
// nodeViews:: ?Object<(node: Node, view: EditorView, getPos: () → number) → NodeView>
// nodeViews:: ?Object<(node: Node, view: EditorView, getPos: () → number, decorations: [Decoration]) → NodeView>
// Allows you to pass custom rendering and behavior logic for nodes

@@ -342,2 +370,8 @@ // and marks. Should map node and mark names to constructor function

//
// `decorations` is an array of node or inline decorations that are
// active around the node. They are automatically drawn in the
// normal way, and you will usually just want to ignore this, but
// they can also be used as a way to provide context information to
// the node view without adding it to the document itself.
//
// clipboardSerializer:: ?DOMSerializer

@@ -353,15 +387,16 @@ // The DOM serializer to use when putting content onto the

//
// spellcheck:: ?bool
// Controls whether the DOM spellcheck attribute is enabled on the
// editable content. Defaults to false.
// editable:: ?(EditorState) → bool
// When this returns false, the content of the view is not directly
// editable.
//
// class:: ?(state: EditorState) → ?string
// Controls the CSS class name of the editor DOM node. Any classes
// returned from this will be added to the default `ProseMirror`
// class.
// attributes:: ?union<Object<string>, (EditorState) → ?Object<string>>
// Control the DOM attributes of the editable element. May be either
// an object or a function going from an editor state to an object.
// By default, the element will get a class `"ProseMirror"`, and
// will have its `contentEditable` attribute determined by the
// [`editable` prop](#view.EditorProps.editable). Additional classes
// provided here will be added to the class. For other attributes,
// the value provided first (as in
// [`someProp`](#view.EditorView.someProp)) will be used.
//
// label:: ?(state: EditorState) → ?string
// Can be used to set an `aria-label` attribute on the editable
// content node.
//
// scrollThreshold:: ?number

@@ -368,0 +403,0 @@ // Determines the distance (in pixels) between the cursor and the

@@ -20,3 +20,3 @@ var ref = require("prosemirror-state");

// to invoke when the event fires.
var handlers = {}
var handlers = {}, editHandlers = {}

@@ -35,3 +35,4 @@ function initInput(view) {

view.content.addEventListener(event, function (event) {
if (eventBelongsToView(view, event) && !view.someProp("handleDOMEvent", function (f) { return f(view, event); }))
if ((view.editable || !(event.type in editHandlers)) &&
eventBelongsToView(view, event) && !view.someProp("handleDOMEvent", function (f) { return f(view, event); }))
{ handler(view, event) }

@@ -61,3 +62,3 @@ })

handlers.keydown = function (view, event) {
editHandlers.keydown = function (view, event) {
if (event.keyCode == 16) { view.shiftKey = true }

@@ -71,7 +72,7 @@ if (view.inDOMChange) { return }

handlers.keyup = function (view, e) {
editHandlers.keyup = function (view, e) {
if (e.keyCode == 16) { view.shiftKey = false }
}
handlers.keypress = function (view, event) {
editHandlers.keypress = function (view, event) {
if (view.inDOMChange || !event.charCode ||

@@ -235,3 +236,3 @@ event.ctrlKey && !event.altKey || browser.mac && event.metaKey) { return }

var MouseDown = function MouseDown(view, pos, event, flushed) {
var MouseDown = function(view, pos, event, flushed) {
this.view = view

@@ -268,3 +269,3 @@ this.pos = pos

MouseDown.prototype.done = function done () {
MouseDown.prototype.done = function () {
this.view.root.removeEventListener("mouseup", this.up)

@@ -279,3 +280,3 @@ this.view.root.removeEventListener("mousemove", this.move)

MouseDown.prototype.up = function up (event) {
MouseDown.prototype.up = function (event) {
this.done()

@@ -293,4 +294,3 @@

} else if (this.flushed) {
this.view.focus()
this.view.props.onAction(Selection.near(this.view.state.doc.resolve(this.pos.pos)).action({origin: "mouse"}))
updateSelection(this.view, Selection.near(this.view.state.doc.resolve(this.pos.pos)), "mouse")
event.preventDefault()

@@ -302,3 +302,3 @@ } else {

MouseDown.prototype.move = function move (event) {
MouseDown.prototype.move = function (event) {
if (!this.allowDefault && (Math.abs(this.x - event.clientX) > 4 ||

@@ -336,3 +336,3 @@ Math.abs(this.y - event.clientY) > 4))

handlers.compositionstart = handlers.compositionupdate = function (view) {
editHandlers.compositionstart = editHandlers.compositionupdate = function (view) {
DOMChange.start(view, true)

@@ -342,3 +342,3 @@ if (view.state.storedMarks) { view.inDOMChange.finish(true) }

handlers.compositionend = function (view, e) {
editHandlers.compositionend = function (view, e) {
if (!view.inDOMChange) {

@@ -368,6 +368,5 @@ // We received a compositionend without having seen any previous

function registerMutations(view, mutations) {
for (var i = 0; i < mutations.length; i++) {
var mut = mutations[i]
if (mut.target == view.content && mut.type == "attributes") { continue }
var desc = view.docView.nearestDesc(mut.target)
if (view.editable) { for (var i = 0; i < mutations.length; i++) {
var mut = mutations[i], desc = view.docView.nearestDesc(mut.target)
if (desc == view.docView && mut.type == "attributes") { continue }
if (!desc || desc.ignoreMutation(mut)) { continue }

@@ -393,8 +392,8 @@

view.inDOMChange.addRange(from, to)
}
} }
}
handlers.input = function (view) { return DOMChange.start(view); }
editHandlers.input = function (view) { return DOMChange.start(view); }
handlers.copy = handlers.cut = function (view, e) {
handlers.copy = editHandlers.cut = function (view, e) {
var sel = view.state.selection, cut = e.type == "cut"

@@ -415,3 +414,3 @@ if (sel.empty) { return }

handlers.paste = function (view, e) {
editHandlers.paste = function (view, e) {
if (!e.clipboardData) {

@@ -431,3 +430,3 @@ if (browser.ie && browser.ie_version <= 11) { DOMChange.start(view) }

var Dragging = function Dragging(state, slice, range, move) {
var Dragging = function(state, slice, range, move) {
this.slice = slice

@@ -473,5 +472,7 @@ this.range = range

handlers.dragover = handlers.dragenter = function (_, e) { return e.preventDefault(); }
editHandlers.dragover = editHandlers.dragenter = function (_, e) { return e.preventDefault(); }
handlers.drop = function (view, e) {
editHandlers.dragleave = function () { return null; }
editHandlers.drop = function (view, e) {
var dragging = view.dragging

@@ -523,1 +524,4 @@ view.dragging = null

}
// Make sure all handlers get registered
for (var prop in editHandlers) { handlers[prop] = editHandlers[prop] }

@@ -10,3 +10,3 @@ var ref = require("prosemirror-state");

// as there is no DOM event for DOM selection changes.
var SelectionReader = function SelectionReader(view) {
var SelectionReader = function(view) {
var this$1 = this;

@@ -21,11 +21,20 @@

view.content.addEventListener("focus", function () { return this$1.poller.receivedFocus(); })
view.content.addEventListener("blur", function () { return this$1.poller.lostFocus(); })
view.content.addEventListener("focus", function () { return this$1.poller.start(); })
view.content.addEventListener("blur", function () { return this$1.poller.stop(); })
if (!view.editable) { this.poller.start() }
};
SelectionReader.prototype.poll = function poll (origin) { this.poller.poll(origin) };
SelectionReader.prototype.destroy = function () { this.poller.stop() };
SelectionReader.prototype.poll = function (origin) { this.poller.poll(origin) };
SelectionReader.prototype.editableChanged = function () {
if (!this.view.editable) { this.poller.start() }
else if (!this.view.hasFocus()) { this.poller.stop() }
};
// : () → bool
// Whether the DOM selection has changed from the last known state.
SelectionReader.prototype.domChanged = function domChanged () {
SelectionReader.prototype.domChanged = function () {
var sel = this.view.root.getSelection()

@@ -37,3 +46,3 @@ return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset ||

// Store the current state of the DOM selection.
SelectionReader.prototype.storeDOMState = function storeDOMState (selection) {
SelectionReader.prototype.storeDOMState = function (selection) {
var sel = this.view.root.getSelection()

@@ -48,3 +57,3 @@ this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset

// current selection state to match.
SelectionReader.prototype.readFromDOM = function readFromDOM (origin) {
SelectionReader.prototype.readFromDOM = function (origin) {
if (!this.view.hasFocus() || this.view.inDOMChange || !this.domChanged()) { return }

@@ -75,72 +84,68 @@

function poller(reader) {
// There's two polling models. On browsers that support the
// selectionchange event (everything except Firefox, basically), we
// register a listener for that whenever the editor is focused.
if ("onselectionchange" in document) { return new (function () {
function anonymous() {
var this$1 = this;
// There's two polling models. On browsers that support the
// selectionchange event (everything except Firefox, basically), we
// register a listener for that whenever the editor is focused.
var SelectionChangePoller = function(reader) {
var this$1 = this;
this.listening = false
this.curOrigin = null
this.originTime = 0
this.listening = false
this.curOrigin = null
this.originTime = 0
this.readFunc = function () { return reader.readFromDOM(this$1.originTime > Date.now() - 50 ? this$1.curOrigin : null); }
}
this.readFunc = function () { return reader.readFromDOM(this$1.originTime > Date.now() - 50 ? this$1.curOrigin : null); }
};
anonymous.prototype.poll = function poll (origin) {
this.curOrigin = origin
this.originTime = Date.now()
};
SelectionChangePoller.prototype.poll = function (origin) {
this.curOrigin = origin
this.originTime = Date.now()
};
anonymous.prototype.receivedFocus = function receivedFocus () {
if (!this.listening) {
document.addEventListener("selectionchange", this.readFunc)
this.listening = true
}
};
SelectionChangePoller.prototype.start = function () {
if (!this.listening) {
document.addEventListener("selectionchange", this.readFunc)
this.listening = true
}
};
anonymous.prototype.lostFocus = function lostFocus () {
if (this.listening) {
document.removeEventListener("selectionchange", this.readFunc)
this.listening = false
}
};
SelectionChangePoller.prototype.stop = function () {
if (this.listening) {
document.removeEventListener("selectionchange", this.readFunc)
this.listening = false
}
};
return anonymous;
}()) }
// On Firefox, we use timeout-based polling.
return new (function () {
function anonymous$1() {
// The timeout ID for the poller when active.
this.polling = null
this.reader = reader
this.pollFunc = this.doPoll.bind(this, null)
}
// On Firefox, we use timeout-based polling.
var TimeoutPoller = function(reader) {
// The timeout ID for the poller when active.
this.polling = null
this.reader = reader
this.pollFunc = this.doPoll.bind(this, null)
};
anonymous$1.prototype.doPoll = function doPoll (origin) {
if (this.reader.view.hasFocus()) {
this.reader.readFromDOM(origin)
this.polling = setTimeout(this.pollFunc, 100)
} else {
this.polling = null
}
};
TimeoutPoller.prototype.doPoll = function (origin) {
var view = this.reader.view
if (view.focused || !view.editable) {
this.reader.readFromDOM(origin)
this.polling = setTimeout(this.pollFunc, 100)
} else {
this.polling = null
}
};
anonymous$1.prototype.poll = function poll (origin) {
clearTimeout(this.polling)
this.polling = setTimeout(origin ? this.doPoll.bind(this, origin) : this.pollFunc, 0)
};
TimeoutPoller.prototype.poll = function (origin) {
clearTimeout(this.polling)
this.polling = setTimeout(origin ? this.doPoll.bind(this, origin) : this.pollFunc, 0)
};
anonymous$1.prototype.receivedFocus = function receivedFocus () {
if (this.polling == null) { this.poll() }
};
TimeoutPoller.prototype.start = function () {
if (this.polling == null) { this.poll() }
};
anonymous$1.prototype.lostFocus = function lostFocus () {
clearTimeout(this.polling)
this.polling = null
};
TimeoutPoller.prototype.stop = function () {
clearTimeout(this.polling)
this.polling = null
};
return anonymous$1;
}())
function poller(reader) {
return new ("onselectionchange" in document ? SelectionChangePoller : TimeoutPoller)(reader)
}

@@ -154,3 +159,3 @@

// See https://bugzilla.mozilla.org/show_bug.cgi?id=921444
else if (browser.gecko) { view.content.focus() }
else if (browser.gecko && view.editable) { view.content.focus() }
}

@@ -157,0 +162,0 @@

var ref = require("prosemirror-transform");
var Mapping = ref.Mapping;
var TrackedRecord = function TrackedRecord(prev, mapping, state) {
var TrackedRecord = function(prev, mapping, state) {
this.prev = prev

@@ -10,7 +10,7 @@ this.mapping = mapping

var TrackMappings = function TrackMappings(state) {
var TrackMappings = function(state) {
this.seen = [new TrackedRecord(null, null, state)]
};
TrackMappings.prototype.find = function find (state) {
TrackMappings.prototype.find = function (state) {
var this$1 = this;

@@ -24,3 +24,3 @@

TrackMappings.prototype.track = function track (old, action, state) {
TrackMappings.prototype.track = function (old, action, state) {
var found = this.seen.length < 200 ? this.find(old) : null

@@ -31,3 +31,3 @@ if (found)

TrackMappings.prototype.getMapping = function getMapping (state) {
TrackMappings.prototype.getMapping = function (state) {
var found = this.find(state)

@@ -34,0 +34,0 @@ if (!found) { return null }

@@ -27,10 +27,11 @@ var ref = require("prosemirror-model");

//
// update:: ?(node: Node, deco: DecorationSet) → bool
// update:: ?(node: Node, decorations: [Decoration]) → bool
// When given, this will be called when the view is updating itself.
// It will be given a node (possibly of a different type), and a
// decoration set (which it may ignore, if it chooses not to support
// decorations), and should return true if it was able to update to
// that node, and false otherwise. If the node view has a
// `contentDOM` property (or no `dom` property), updating its child
// nodes will be handled by ProseMirror.
// It will be given a node (possibly of a different type), and an
// array of active decorations (which are automatically drawn, and
// the node view may ignore if it isn't interested in them), and
// should return true if it was able to update to that node, and
// false otherwise. If the node view has a `contentDOM` property (or
// no `dom` property), updating its child nodes will be handled by
// ProseMirror.
//

@@ -83,3 +84,3 @@ // selectNode:: ?()

// basic structure and shared methods.
var ViewDesc = function ViewDesc(parent, children, dom, contentDOM) {
var ViewDesc = function(parent, children, dom, contentDOM) {
this.parent = parent

@@ -101,6 +102,6 @@ this.children = children

// widget/mark/node.
ViewDesc.prototype.matchesWidget = function matchesWidget () { return false };
ViewDesc.prototype.matchesMark = function matchesMark () { return false };
ViewDesc.prototype.matchesNode = function matchesNode () { return false };
ViewDesc.prototype.matchesHack = function matchesHack () { return false };
ViewDesc.prototype.matchesWidget = function () { return false };
ViewDesc.prototype.matchesMark = function () { return false };
ViewDesc.prototype.matchesNode = function () { return false };
ViewDesc.prototype.matchesHack = function () { return false };

@@ -111,3 +112,3 @@ // : () → ?ParseRule

// parse them.
ViewDesc.prototype.parseRule = function parseRule () { return null };
ViewDesc.prototype.parseRule = function () { return null };

@@ -117,3 +118,3 @@ // : (dom.Event) → bool

// from certain descs.
ViewDesc.prototype.stopEvent = function stopEvent () { return false };
ViewDesc.prototype.stopEvent = function () { return false };

@@ -133,3 +134,3 @@ // The size of the content represented by this desc.

ViewDesc.prototype.destroy = function destroy () {
ViewDesc.prototype.destroy = function () {
var this$1 = this;

@@ -142,3 +143,3 @@

ViewDesc.prototype.posBeforeChild = function posBeforeChild (child) {
ViewDesc.prototype.posBeforeChild = function (child) {
var this$1 = this;

@@ -162,3 +163,3 @@

// : (dom.Node, number, ?number) → number
ViewDesc.prototype.localPosFromDOM = function localPosFromDOM (dom, offset, bias) {
ViewDesc.prototype.localPosFromDOM = function (dom, offset, bias) {
var this$1 = this;

@@ -212,12 +213,15 @@

// this one.
ViewDesc.prototype.nearestDesc = function nearestDesc (dom) {
ViewDesc.prototype.nearestDesc = function (dom) {
var this$1 = this;
for (; dom; dom = dom.parentNode) {
var desc = this$1.getDesc(dom)
if (desc) { return desc }
for (var first = true, cur = dom; cur; cur = cur.parentNode) {
var desc = this$1.getDesc(cur)
if (desc) {
if (first && desc.nodeDOM && !desc.nodeDOM.contains(dom)) { first = false }
else { return desc }
}
}
};
ViewDesc.prototype.getDesc = function getDesc (dom) {
ViewDesc.prototype.getDesc = function (dom) {
var this$1 = this;

@@ -229,3 +233,3 @@

ViewDesc.prototype.posFromDOM = function posFromDOM (dom, offset, bias) {
ViewDesc.prototype.posFromDOM = function (dom, offset, bias) {
var this$1 = this;

@@ -242,3 +246,3 @@

// parent node overrode rendering, there might not be one.)
ViewDesc.prototype.descAt = function descAt (pos) {
ViewDesc.prototype.descAt = function (pos) {
var this$1 = this;

@@ -258,3 +262,3 @@

// : (number, ?bool) → {node: dom.Node, offset: number}
ViewDesc.prototype.domFromPos = function domFromPos (pos, searchDOM) {
ViewDesc.prototype.domFromPos = function (pos, searchDOM) {
var this$1 = this;

@@ -277,3 +281,3 @@

// the offset that corresponds to a given child.
ViewDesc.prototype.findDOMOffset = function findDOMOffset (i, searchDOM) {
ViewDesc.prototype.findDOMOffset = function (i, searchDOM) {
var this$1 = this;

@@ -284,3 +288,5 @@

for (var j = i - 1; j >= 0; j--) {
var found = Array.prototype.indexOf.call(content.childNodes, this$1.children[j].dom)
var child = this$1.children[j]
if (!child.size) { continue }
var found = Array.prototype.indexOf.call(content.childNodes, child.dom)
if (found > -1) { return found + 1 }

@@ -291,3 +297,5 @@ }

for (var j$1 = i; j$1 < this.children.length; j$1++) {
var found$1 = Array.prototype.indexOf.call(content.childNodes, this$1.children[j$1].dom)
var child$1 = this$1.children[j$1]
if (!child$1.size) { continue }
var found$1 = Array.prototype.indexOf.call(content.childNodes, child$1.dom)
if (found$1 > -1) { return found$1 }

@@ -300,3 +308,3 @@ }

// : (number) → dom.Node
ViewDesc.prototype.domAfterPos = function domAfterPos (pos) {
ViewDesc.prototype.domAfterPos = function (pos) {
var ref = this.domFromPos(pos);

@@ -316,3 +324,3 @@ var node = ref.node;

// case we just use whatever domFromPos produces as a best effort.
ViewDesc.prototype.setSelection = function setSelection (anchor, head, root) {
ViewDesc.prototype.setSelection = function (anchor, head, root) {
var this$1 = this;

@@ -350,3 +358,3 @@

// : (dom.MutationRecord) → bool
ViewDesc.prototype.ignoreMutation = function ignoreMutation (_mutation) {
ViewDesc.prototype.ignoreMutation = function (_mutation) {
return !this.contentDOM

@@ -357,3 +365,3 @@ };

// by a DOM change, so that the next update will redraw it.
ViewDesc.prototype.markDirty = function markDirty (from, to) {
ViewDesc.prototype.markDirty = function (from, to) {
var this$1 = this;

@@ -363,3 +371,3 @@

var child = this$1.children[i], end = offset + child.size
if (from < end && to > offset) {
if (offset == end ? from <= end && to >= offset : from < end && to > offset) {
var startInside = offset + child.border, endInside = end - child.border

@@ -397,7 +405,7 @@ if (from >= startInside && to <= endInside) {

WidgetViewDesc.prototype.matchesWidget = function matchesWidget (widget) { return this.dirty == NOT_DIRTY && widget.type == this.widget.type };
WidgetViewDesc.prototype.matchesWidget = function (widget) { return this.dirty == NOT_DIRTY && widget.type == this.widget.type };
WidgetViewDesc.prototype.parseRule = function parseRule () { return {ignore: true} };
WidgetViewDesc.prototype.parseRule = function () { return {ignore: true} };
WidgetViewDesc.prototype.stopEvent = function stopEvent (event) {
WidgetViewDesc.prototype.stopEvent = function (event) {
var stop = this.widget.type.options.stopEvent

@@ -425,3 +433,3 @@ return stop ? stop(event) : false

MarkViewDesc.create = function create (parent, mark, view) {
MarkViewDesc.create = function (parent, mark, view) {
var custom = customNodeViews(view)[mark.type.name]

@@ -433,5 +441,5 @@ var spec = custom && custom(mark, view)

MarkViewDesc.prototype.parseRule = function parseRule () { return {mark: this.mark.type.name, attrs: this.mark.attrs, contentElement: this.contentDOM} };
MarkViewDesc.prototype.parseRule = function () { return {mark: this.mark.type.name, attrs: this.mark.attrs, contentElement: this.contentDOM} };
MarkViewDesc.prototype.matchesMark = function matchesMark (mark) { return this.dirty != NODE_DIRTY && this.mark.eq(mark) };
MarkViewDesc.prototype.matchesMark = function (mark) { return this.dirty != NODE_DIRTY && this.mark.eq(mark) };

@@ -445,4 +453,5 @@ return MarkViewDesc;

var NodeViewDesc = (function (ViewDesc) {
function NodeViewDesc(parent, node, outerDeco, innerDeco, dom, contentDOM, view) {
function NodeViewDesc(parent, node, outerDeco, innerDeco, dom, contentDOM, nodeDOM, view) {
ViewDesc.call(this, parent, node.isLeaf ? nothing : [], dom, contentDOM)
this.nodeDOM = nodeDOM
this.node = node

@@ -469,3 +478,3 @@ this.outerDeco = outerDeco

// never need.)
NodeViewDesc.create = function create (parent, node, outerDeco, innerDeco, view) {
NodeViewDesc.create = function (parent, node, outerDeco, innerDeco, view) {
var custom = customNodeViews(view)[node.type.name], descObj

@@ -475,5 +484,4 @@ var spec = custom && custom(node, view, function () {

// own position)
if (!descObj) { return parent.posAtStart + parent.size }
if (descObj.parent) { return descObj.parent.posBeforeChild(descObj) }
})
if (descObj && descObj.parent) { return descObj.parent.posBeforeChild(descObj) }
}, outerDeco)

@@ -483,17 +491,18 @@ var dom = spec && spec.dom, contentDOM = spec && spec.contentDOM

((assign = DOMSerializer.renderSpec(document, node.type.spec.toDOM(node)), dom = assign.dom, contentDOM = assign.contentDOM)) }
var startDOM = dom
for (var i = 0; i < outerDeco.length; i++)
{ dom = applyOuterDeco(dom, outerDeco[i].type.attrs, node) }
if (!contentDOM && !node.isText) { dom.contentEditable = false }
var nodeDOM = dom
dom = applyOuterDeco(dom, outerDeco, node, !!contentDOM)
if (spec)
{ return descObj = new CustomNodeViewDesc(parent, node, outerDeco, innerDeco, dom, contentDOM, spec, view) }
{ return descObj = new CustomNodeViewDesc(parent, node, outerDeco, innerDeco, dom, contentDOM, nodeDOM, spec, view) }
else if (node.isText)
{ return new TextViewDesc(parent, node, outerDeco, innerDeco, dom, startDOM, view) }
{ return new TextViewDesc(parent, node, outerDeco, innerDeco, dom, nodeDOM, view) }
else
{ return new NodeViewDesc(parent, node, outerDeco, innerDeco, dom, contentDOM, view) }
{ return new NodeViewDesc(parent, node, outerDeco, innerDeco, dom, contentDOM, nodeDOM, view) }
};
NodeViewDesc.prototype.parseRule = function parseRule () { return {node: this.node.type.name, attrs: this.node.attrs, contentElement: this.contentDOM} };
NodeViewDesc.prototype.parseRule = function () { return {node: this.node.type.name, attrs: this.node.attrs, contentElement: this.contentDOM} };
NodeViewDesc.prototype.matchesNode = function matchesNode (node, outerDeco, innerDeco) {
NodeViewDesc.prototype.matchesNode = function (node, outerDeco, innerDeco) {
return this.dirty == NOT_DIRTY && node.eq(this.node) &&

@@ -511,3 +520,5 @@ sameOuterDeco(outerDeco, this.outerDeco) && innerDeco.eq(this.innerDeco)

// `this.children`.
NodeViewDesc.prototype.updateChildren = function updateChildren (view) {
NodeViewDesc.prototype.updateChildren = function (view) {
var this$1 = this;
var updater = new ViewTreeUpdater(this)

@@ -518,3 +529,3 @@ iterDeco(this.node, this.innerDeco, function (widget) {

updater.placeWidget(widget)
}, function (child, outerDeco, innerDeco) {
}, function (child, outerDeco, innerDeco, i) {
// Make sure the wrapping mark descs match the node's marks.

@@ -526,3 +537,3 @@ updater.syncToMarks(child.marks, view)

// Or try updating the next desc to reflect this node.
updater.updateNode(child, outerDeco, innerDeco, view) ||
updater.updateNextNode(child, outerDeco, innerDeco, view, this$1.node.content, i) ||
// Or just add it as a new desc.

@@ -540,3 +551,3 @@ updater.addNode(child, outerDeco, innerDeco, view)

NodeViewDesc.prototype.renderChildren = function renderChildren () {
NodeViewDesc.prototype.renderChildren = function () {
renderDescs(this.contentDOM, this.children, NodeViewDesc.is)

@@ -549,6 +560,6 @@ if (browser.ios) { iosHacks(this.dom) }

// do so and return true.
NodeViewDesc.prototype.update = function update (node, outerDeco, innerDeco, view) {
NodeViewDesc.prototype.update = function (node, outerDeco, innerDeco, view) {
if (this.dirty == NODE_DIRTY ||
!node.sameMarkup(this.node) ||
!sameOuterDeco(outerDeco, this.outerDeco)) { return false }
!node.sameMarkup(this.node)) { return false }
this.updateOuterDeco(outerDeco)
this.node = node

@@ -561,10 +572,19 @@ this.innerDeco = innerDeco

NodeViewDesc.prototype.updateOuterDeco = function (outerDeco) {
if (sameOuterDeco(outerDeco, this.outerDeco)) { return }
var content = !!this.contentDOM, needsWrap = this.nodeDOM.nodeType != 1
this.dom = patchOuterDeco(this.dom, this.nodeDOM,
computeOuterDeco(this.outerDeco, this.node, content, needsWrap),
computeOuterDeco(outerDeco, this.node, content, needsWrap))
this.outerDeco = outerDeco
};
// Mark this node as being the selected node.
NodeViewDesc.prototype.selectNode = function selectNode () {
this.dom.classList.add("ProseMirror-selectednode")
NodeViewDesc.prototype.selectNode = function () {
this.nodeDOM.classList.add("ProseMirror-selectednode")
};
// Remove selected node marking from this node.
NodeViewDesc.prototype.deselectNode = function deselectNode () {
this.dom.classList.remove("ProseMirror-selectednode")
NodeViewDesc.prototype.deselectNode = function () {
this.nodeDOM.classList.remove("ProseMirror-selectednode")
};

@@ -579,4 +599,5 @@

// and used by the view class.
function docViewDesc(doc, deco, dom, view) {
return new NodeViewDesc(null, doc, nothing, deco, dom, dom, view)
function docViewDesc(doc, outerDeco, innerDeco, dom, view) {
applyOuterDeco(dom, outerDeco, doc, true)
return new NodeViewDesc(null, doc, outerDeco, innerDeco, dom, dom, dom, view)
}

@@ -586,5 +607,4 @@ exports.docViewDesc = docViewDesc

var TextViewDesc = (function (NodeViewDesc) {
function TextViewDesc(parent, node, outerDeco, innerDeco, dom, textDOM, view) {
NodeViewDesc.call(this, parent, node, outerDeco, innerDeco, dom, null, view)
this.textDOM = textDOM
function TextViewDesc(parent, node, outerDeco, innerDeco, dom, nodeDOM, view) {
NodeViewDesc.call(this, parent, node, outerDeco, innerDeco, dom, null, nodeDOM, view)
}

@@ -596,12 +616,12 @@

TextViewDesc.prototype.parseRule = function parseRule () {
return {skip: this.textDOM.parentNode}
TextViewDesc.prototype.parseRule = function () {
return {skip: this.nodeDOM.parentNode}
};
TextViewDesc.prototype.update = function update (node, outerDeco) {
TextViewDesc.prototype.update = function (node, outerDeco) {
if (this.dirty == NODE_DIRTY || (this.dirty != NOT_DIRTY && !this.inParent) ||
!node.sameMarkup(this.node) ||
!sameOuterDeco(outerDeco, this.outerDeco)) { return false }
if ((this.dirty != NOT_DIRTY || node.text != this.node.text) && node.text != this.textDOM.nodeValue)
{ this.textDOM.nodeValue = node.text }
!node.sameMarkup(this.node)) { return false }
this.updateOuterDeco(outerDeco)
if ((this.dirty != NOT_DIRTY || node.text != this.node.text) && node.text != this.nodeDOM.nodeValue)
{ this.nodeDOM.nodeValue = node.text }
this.node = node

@@ -612,18 +632,18 @@ this.dirty = NOT_DIRTY

TextViewDesc.prototype.inParent = function inParent () {
TextViewDesc.prototype.inParent = function () {
var parentDOM = this.parent.contentDOM
for (var n = this.textDOM; n; n = n.parentNode) { if (n == parentDOM) { return true } }
for (var n = this.nodeDOM; n; n = n.parentNode) { if (n == parentDOM) { return true } }
return false
};
TextViewDesc.prototype.domFromPos = function domFromPos (pos, searchDOM) {
return {node: this.textDOM, offset: searchDOM ? Math.max(pos, this.textDOM.nodeValue.length) : pos}
TextViewDesc.prototype.domFromPos = function (pos, searchDOM) {
return {node: this.nodeDOM, offset: searchDOM ? Math.max(pos, this.nodeDOM.nodeValue.length) : pos}
};
TextViewDesc.prototype.localPosFromDOM = function localPosFromDOM (dom, offset, bias) {
if (dom == this.textDOM) { return this.posAtStart + Math.min(offset, this.node.text.length) }
TextViewDesc.prototype.localPosFromDOM = function (dom, offset, bias) {
if (dom == this.nodeDOM) { return this.posAtStart + Math.min(offset, this.node.text.length) }
return NodeViewDesc.prototype.localPosFromDOM.call(this, dom, offset, bias)
};
TextViewDesc.prototype.ignoreMutation = function ignoreMutation (mutation) {
TextViewDesc.prototype.ignoreMutation = function (mutation) {
return mutation.type != "characterData"

@@ -637,15 +657,15 @@ };

// around contentEditable terribleness.
var HackViewDesc = (function (ViewDesc) {
function HackViewDesc(parent, type, dom) {
ViewDesc.call(this, parent, nothing, dom, null)
this.type = type
var BRHackViewDesc = (function (ViewDesc) {
function BRHackViewDesc () {
ViewDesc.apply(this, arguments);
}
if ( ViewDesc ) HackViewDesc.__proto__ = ViewDesc;
HackViewDesc.prototype = Object.create( ViewDesc && ViewDesc.prototype );
HackViewDesc.prototype.constructor = HackViewDesc;
HackViewDesc.prototype.parseRule = function parseRule () { return {ignore: true} };
HackViewDesc.prototype.matchesHack = function matchesHack (type) { return this.dirty == NOT_DIRTY && this.type == type };
if ( ViewDesc ) BRHackViewDesc.__proto__ = ViewDesc;
BRHackViewDesc.prototype = Object.create( ViewDesc && ViewDesc.prototype );
BRHackViewDesc.prototype.constructor = BRHackViewDesc;
return HackViewDesc;
BRHackViewDesc.prototype.parseRule = function () { return {ignore: true} };
BRHackViewDesc.prototype.matchesHack = function () { return this.dirty == NOT_DIRTY };
return BRHackViewDesc;
}(ViewDesc));

@@ -657,4 +677,4 @@

var CustomNodeViewDesc = (function (NodeViewDesc) {
function CustomNodeViewDesc(parent, node, outerDeco, innerDeco, dom, contentDOM, spec, view) {
NodeViewDesc.call(this, parent, node, outerDeco, innerDeco, dom, contentDOM, view)
function CustomNodeViewDesc(parent, node, outerDeco, innerDeco, dom, contentDOM, nodeDOM, spec, view) {
NodeViewDesc.call(this, parent, node, outerDeco, innerDeco, dom, contentDOM, nodeDOM, view)
this.spec = spec

@@ -670,5 +690,5 @@ }

// updates the children.
CustomNodeViewDesc.prototype.update = function update (node, outerDeco, innerDeco, view) {
CustomNodeViewDesc.prototype.update = function (node, outerDeco, innerDeco, view) {
if (this.spec.update) {
var result = this.spec.update(node, innerDeco)
var result = this.spec.update(node, outerDeco)
if (result) {

@@ -679,20 +699,22 @@ this.node = node

return result
} else if (!this.contentDOM && !node.isLeaf) {
return false
} else {
return NodeViewDesc.prototype.update.call(this, node, outerDeco, innerDeco, view)
return NodeViewDesc.prototype.update.call(this, node, outerDeco, this.contentDOM ? this.innerDeco : innerDeco, view)
}
};
CustomNodeViewDesc.prototype.selectNode = function selectNode () {
CustomNodeViewDesc.prototype.selectNode = function () {
this.spec.selectNode ? this.spec.selectNode() : NodeViewDesc.prototype.selectNode.call(this)
};
CustomNodeViewDesc.prototype.deselectNode = function deselectNode () {
CustomNodeViewDesc.prototype.deselectNode = function () {
this.spec.deselectNode ? this.spec.deselectNode() : NodeViewDesc.prototype.deselectNode.call(this)
};
CustomNodeViewDesc.prototype.setSelection = function setSelection (anchor, head, root) {
CustomNodeViewDesc.prototype.setSelection = function (anchor, head, root) {
this.spec.setSelection ? this.spec.setSelection(anchor, head, root) : NodeViewDesc.prototype.setSelection.call(this, anchor, head, root)
};
CustomNodeViewDesc.prototype.destroy = function destroy () {
CustomNodeViewDesc.prototype.destroy = function () {
if (this.spec.destroy) { this.spec.destroy() }

@@ -702,7 +724,7 @@ NodeViewDesc.prototype.destroy.call(this)

CustomNodeViewDesc.prototype.stopEvent = function stopEvent (event) {
CustomNodeViewDesc.prototype.stopEvent = function (event) {
return this.spec.stopEvent ? this.spec.stopEvent(event) : false
};
CustomNodeViewDesc.prototype.ignoreMutation = function ignoreMutation (mutation) {
CustomNodeViewDesc.prototype.ignoreMutation = function (mutation) {
return this.spec.ignoreMutation ? this.spec.ignoreMutation(mutation) : NodeViewDesc.prototype.ignoreMutation.call(this, mutation)

@@ -734,21 +756,89 @@ };

// : (dom.Node, Object, Node) → dom.Node
// Apply the extra attributes and potentially add a wrapper for a
// decoration.
function applyOuterDeco(dom, attrs, node) {
if (attrs.nodeName || dom.nodeType != 1) {
var wrap = document.createElement(attrs.nodeName || (node.isInline ? "span" : "div"))
wrap.appendChild(dom)
dom = wrap
var OuterDecoLevel = function(nodeName) {
if (nodeName) { this.nodeName = nodeName }
};
OuterDecoLevel.prototype = Object.create(null)
var noDeco = [new OuterDecoLevel]
function computeOuterDeco(outerDeco, node, hasContent, needsWrap) {
if (hasContent && outerDeco.length == 0) { return noDeco }
var top = needsWrap ? noDeco[0] : new OuterDecoLevel, result = [top]
if (outerDeco.length) {
for (var i = 0; i < outerDeco.length; i++) {
var attrs = outerDeco[i].type.attrs, cur = top
if (!attrs) { continue }
if (attrs.nodeName)
{ result.push(cur = new OuterDecoLevel(attrs.nodeName)) }
for (var name in attrs) {
var val = attrs[name]
if (val == null) { continue }
if (needsWrap && result.length == 1)
{ result.push(cur = top = new OuterDecoLevel(node.isInline ? "span" : "div")) }
if (name == "class") { cur.class = (cur.class ? cur.class + " " : "") + val }
else if (name == "style") { cur.style = (cur.style ? cur.style + ";" : "") + val }
else if (name != "nodeName") { cur[name] = val }
}
}
}
for (var name in attrs) {
var val = attrs[name]
if (name == "class") { (ref = dom.classList).add.apply(ref, val.split(" ")) }
else if (name == "style") { dom.style.cssText += ";" + val }
else if (name != "nodeName") { dom.setAttribute(name, val) }
if (!hasContent && node.isBlock && result.length == 1 && !result[0].nodeName)
{ result.push(new OuterDecoLevel("div")) }
return result
}
function patchOuterDeco(outerDOM, nodeDOM, prevComputed, curComputed) {
// Shortcut for trivial case
if (prevComputed == noDeco && curComputed == noDeco) { return nodeDOM }
var curDOM = nodeDOM
for (var i = 0; i < curComputed.length; i++) {
var deco = curComputed[i], prev = prevComputed[i]
if (i) {
var parent = (void 0)
if (prev && prev.nodeName == deco.nodeName && curDOM != outerDOM &&
(parent = nodeDOM.parentNode) && parent.tagName.toLowerCase() == deco.nodeName) {
curDOM = parent
} else {
parent = document.createElement(deco.nodeName)
parent.appendChild(curDOM)
curDOM = parent
}
}
patchAttributes(curDOM, prev || noDeco[0], deco)
}
return dom
var ref;
return curDOM
}
function patchAttributes(dom, prev, cur) {
for (var name in prev)
{ if (name != "class" && name != "style" && name != "nodeName" && !(name in cur))
{ dom.removeAttribute(name) } }
for (var name$1 in cur)
{ if (name$1 != "class" && name$1 != "style" && name$1 != "nodeName" && cur[name$1] != prev[name$1])
{ dom.setAttribute(name$1, cur[name$1]) } }
if (prev.class != cur.class) {
var prevList = prev.class ? prev.class.split(" ") : nothing
var curList = cur.class ? cur.class.split(" ") : nothing
for (var i = 0; i < prevList.length; i++) { if (curList.indexOf(prevList[i]) == -1)
{ dom.classList.remove(prevList[i]) } }
for (var i$1 = 0; i$1 < curList.length; i$1++) { if (prevList.indexOf(curList[i$1]) == -1)
{ dom.classList.add(curList[i$1]) } }
}
if (prev.style != cur.style) {
var text = dom.style.cssText, found
if (prev.style && (found = text.index(prev.style)) > -1)
{ text = text.slice(0, found) + text.slice(found + prev.style.length) }
dom.style.cssText = text + (cur.style || "")
}
}
function applyOuterDeco(dom, deco, node, hasContent) {
return patchOuterDeco(dom, dom, noDeco, computeOuterDeco(deco, node, hasContent, dom.nodeType != 1))
}
// : ([Decoration], [Decoration]) → bool

@@ -770,3 +860,3 @@ function sameOuterDeco(a, b) {

// the widget and node descs inside of them.
var ViewTreeUpdater = function ViewTreeUpdater(top) {
var ViewTreeUpdater = function(top) {
this.top = top

@@ -785,3 +875,3 @@ // Index into `this.top`'s child array, represents the current

// `this.top`.
ViewTreeUpdater.prototype.destroyBetween = function destroyBetween (start, end) {
ViewTreeUpdater.prototype.destroyBetween = function (start, end) {
var this$1 = this;

@@ -796,3 +886,3 @@

// Destroy all remaining children in `this.top`.
ViewTreeUpdater.prototype.destroyRest = function destroyRest () {
ViewTreeUpdater.prototype.destroyRest = function () {
this.destroyBetween(this.index, this.top.children.length)

@@ -804,3 +894,3 @@ };

// marks, reusing existing mark descs when possible.
ViewTreeUpdater.prototype.syncToMarks = function syncToMarks (marks, view) {
ViewTreeUpdater.prototype.syncToMarks = function (marks, view) {
var this$1 = this;

@@ -840,6 +930,5 @@

// return true when successful.
ViewTreeUpdater.prototype.findNodeMatch = function findNodeMatch (node, outerDeco, innerDeco) {
ViewTreeUpdater.prototype.findNodeMatch = function (node, outerDeco, innerDeco) {
var this$1 = this;
// FIXME think about failure cases where updates will redraw too much
for (var i = this.index, children = this.top.children, e = Math.min(children.length, i + 5); i < e; i++) {

@@ -855,10 +944,21 @@ if (children[i].matchesNode(node, outerDeco, innerDeco)) {

// : (Node, [Decoration], DecorationSet, EditorView) → bool
// Try to update the next node, if any, to the given data.
ViewTreeUpdater.prototype.updateNode = function updateNode (node, outerDeco, innerDeco, view) {
// : (Node, [Decoration], DecorationSet, EditorView, Fragment, number) → bool
// Try to update the next node, if any, to the given data. First
// tries scanning ahead in the siblings fragment to see if the next
// node matches any of those, and if so, doesn't touch it, to avoid
// overwriting nodes that could still be used.
ViewTreeUpdater.prototype.updateNextNode = function (node, outerDeco, innerDeco, view, siblings, index) {
if (this.index == this.top.children.length) { return false }
var next = this.top.children[this.index]
if (!(next instanceof NodeViewDesc && next.update(node, outerDeco, innerDeco, view))) { return false }
this.index++
return true
if (next instanceof NodeViewDesc) {
for (var i = index + 1, e = Math.min(siblings.childCount, i + 5); i < e; i++)
{ if (next.node == siblings.child(i)) { return false } }
var nextDOM = next.dom
if (next.update(node, outerDeco, innerDeco, view)) {
if (next.dom != nextDOM) { this.changed = true }
this.index++
return true
}
}
return false
};

@@ -868,3 +968,3 @@

// Insert the node as a newly created node desc.
ViewTreeUpdater.prototype.addNode = function addNode (node, outerDeco, innerDeco, view) {
ViewTreeUpdater.prototype.addNode = function (node, outerDeco, innerDeco, view) {
this.top.children.splice(this.index++, 0, NodeViewDesc.create(this.top, node, outerDeco, innerDeco, view))

@@ -874,3 +974,3 @@ this.changed = true

ViewTreeUpdater.prototype.placeWidget = function placeWidget (widget) {
ViewTreeUpdater.prototype.placeWidget = function (widget) {
if (this.index < this.top.children.length && this.top.children[this.index].matchesWidget(widget)) {

@@ -886,19 +986,14 @@ this.index++

// contentEditable.
ViewTreeUpdater.prototype.addTextblockHacks = function addTextblockHacks () {
var lastChild = this.top.children[this.index - 1], hack
ViewTreeUpdater.prototype.addTextblockHacks = function () {
var lastChild = this.top.children[this.index - 1]
while (lastChild instanceof MarkViewDesc) { lastChild = lastChild.children[lastChild.children.length - 1] }
if (!lastChild || lastChild.dom.nodeName == "BR")
{ hack = "br" }
else if (this.wrapsInPRE())
{ hack = "newline" }
else if (!(lastChild instanceof TextViewDesc))
{ hack = "text" }
if (hack) {
if (this.index < this.top.children.length && this.top.children[this.index].matchesHack(hack)) {
if (!lastChild || // Empty textblock
!(lastChild instanceof TextViewDesc) ||
/\n$/.test(lastChild.node.text)) {
if (this.index < this.top.children.length && this.top.children[this.index].matchesHack()) {
this.index++
} else {
var dom = document.createElement(hack == "br" ? "br" : "span")
if (hack == "newline") { dom.textContent = "\n" }
this.top.children.splice(this.index++, 0, new HackViewDesc(this.top, hack, dom))
var dom = document.createElement("br")
this.top.children.splice(this.index++, 0, new BRHackViewDesc(this.top, nothing, dom, null))
this.changed = true

@@ -909,10 +1004,2 @@ }

ViewTreeUpdater.prototype.wrapsInPRE = function wrapsInPRE () {
var top = this.top
for (var dom = top.contentDOM;; dom = dom.parentNode) {
if (dom.nodeName == "PRE") { return true }
if (dom == top.dom) { return false }
}
};
// : (ViewDesc, DecorationSet, (Decoration), (Node, [Decoration], DecorationSet))

@@ -929,3 +1016,3 @@ // This function abstracts iterating over the nodes and decorations in

var child = parent.child(i)
onNode(child, locals, deco.forChild(offset, child))
onNode(child, locals, deco.forChild(offset, child), i)
offset += child.nodeSize

@@ -966,3 +1053,3 @@ }

onNode(child$1, active.length ? active.slice() : nothing, deco.forChild(offset, child$1))
onNode(child$1, active.length ? active.slice() : nothing, deco.forChild(offset, child$1), parentIndex - 1)
offset = end

@@ -969,0 +1056,0 @@ }

{
"name": "prosemirror-view",
"version": "0.15.2",
"version": "0.16.0",
"description": "ProseMirror's view component",

@@ -20,8 +20,8 @@ "main": "dist/index.js",

"dependencies": {
"prosemirror-model": "^0.15.0",
"prosemirror-state": "^0.15.0",
"prosemirror-transform": "^0.15.0"
"prosemirror-model": "^0.16.0",
"prosemirror-state": "^0.16.0",
"prosemirror-transform": "^0.16.0"
},
"devDependencies": {
"buble": "~0.14.0",
"buble": "^0.15.1",
"ist": "^1.0.0",

@@ -35,5 +35,5 @@ "mocha": "^3.0.2",

"test-server": "moduleserve test --port 8090",
"build": "rimraf dist && buble -i src -o dist",
"build": "rimraf dist && buble -i src -o dist --no-named-function-expr",
"prepublish": "npm run build"
}
}

@@ -63,2 +63,4 @@ const {Selection, NodeSelection, TextSelection} = require("prosemirror-state")

else break
} else if (isBlockNode(node)) {
break
} else {

@@ -99,2 +101,4 @@ let prev = node.previousSibling

else break
} else if (isBlockNode(node)) {
break
} else {

@@ -105,3 +109,3 @@ let next = node.nextSibling

moveOffset = Array.prototype.indexOf.call(moveNode.childNodes, next) + 1
next = next.previousSibling
next = next.nextSibling
}

@@ -122,2 +126,7 @@ if (!next) {

function isBlockNode(dom) {
let desc = dom.pmViewDesc
return desc && desc.node && desc.node.isBlock
}
function setSel(sel, node, offset) {

@@ -124,0 +133,0 @@ let range = document.createRange()

@@ -124,4 +124,4 @@ function compareObjs(a, b) {

// and reuse DOM nodes.
static widget(pos, widget, options) {
return new Decoration(pos, pos, new WidgetType(widget, options))
static widget(pos, dom, options) {
return new Decoration(pos, pos, new WidgetType(dom, options))
}

@@ -128,0 +128,0 @@

@@ -34,6 +34,2 @@ const {Fragment, DOMParser} = require("prosemirror-model")

read(range) {
readDOMChange(this, this.state, range)
}
finish(force) {

@@ -46,3 +42,6 @@ clearTimeout(this.timeout)

this.view.inDOMChange = null
this.read(range)
readDOMChange(this, this.state, range)
// If the reading didn't result in a view update, force one by
// resetting the view to its current state.
if (this.view.docView.dirty) this.view.updateState(this.view.state)
}

@@ -177,2 +176,8 @@

let parseResult, doc = oldState.doc, view = domChange.view
// If there have been changes since this DOM update started, we must
// map our start and end positions, as well as the new selection
// positions, through them.
let mapping = domChange.mappings.getMapping(view.state)
if (!mapping) return
for (;;) {

@@ -189,4 +194,11 @@ parseResult = parseBetween(view, oldState, range.from, range.to)

let change = findDiff(compare.content, parsed.content, range.from, oldState.selection.from)
if (!change) return false
if (!change) {
if (parsedSel) {
let sel = resolveSelection(view.state.doc, mapping, parsedSel)
if (!sel.eq(view.state.selection)) view.props.onAction(sel.action())
}
return
}
let $from = parsed.resolveNoCache(change.start - range.from)

@@ -207,15 +219,5 @@ let $to = parsed.resolveNoCache(change.endB - range.from)

let from = change.start, to = change.endA
// If there have been changes since this DOM update started, we must
// map our start and end positions, as well as the new selection
// positions, through them.
let mapping = domChange.mappings.getMapping(view.state), $from1
if (!mapping) return
let from = mapping.map(change.start), to = mapping.map(change.endA, -1)
from = mapping.map(from)
to = mapping.map(to)
if (parsedSel) parsedSel = {anchor: mapping.map(parsedSel.anchor),
head: mapping.map(parsedSel.head)}
let tr = view.state.tr, handled = false, markChange
let tr = view.state.tr, handled = false, markChange, $from1
if ($from.sameParent($to) && $from.parent.isTextblock && $from.pos != $to.pos) {

@@ -241,8 +243,11 @@ if (change.endA == change.endB &&

tr.replace(from, to, parsed.slice(change.start - range.from, change.endB - range.from))
if (parsedSel)
tr.setSelection(Selection.between(tr.doc.resolve(parsedSel.anchor),
tr.doc.resolve(parsedSel.head)))
if (parsedSel) tr.setSelection(resolveSelection(tr.doc, mapping, parsedSel))
view.props.onAction(tr.scrollAction())
}
function resolveSelection(doc, mapping, parsedSel) {
return Selection.between(doc.resolve(mapping.map(parsedSel.anchor)),
doc.resolve(mapping.map(parsedSel.head)))
}
// : (Fragment, Fragment) → ?{mark: Mark, type: string}

@@ -249,0 +254,0 @@ // Given two same-length, non-empty fragments of inline content,

@@ -7,3 +7,3 @@ const {EditorState} = require("prosemirror-state")

const {SelectionReader, selectionToDOM} = require("./selection")
const {viewDecorations} = require("./decoration")
const {viewDecorations, Decoration} = require("./decoration")

@@ -40,3 +40,3 @@ ;({Decoration: exports.Decoration, DecorationSet: exports.DecorationSet} = require("./decoration"))

// :: dom.Node
// :: dom.Element
// The editable DOM node containing the document. (You probably

@@ -46,9 +46,7 @@ // should not be directly interfering with its child nodes.)

this.updateDOMForProps()
if (place && place.appendChild) place.appendChild(this.content)
else if (place) place(this.content)
this.docView = docViewDesc(this.state.doc, viewDecorations(this), this.content, this)
this.content.contentEditable = true
this.editable = getEditable(this)
this.docView = docViewDesc(this.state.doc, computeDocDeco(this), viewDecorations(this), this.content, this)

@@ -58,2 +56,5 @@ this.lastSelectedViewDesc = null

initInput(this)
this.pluginViews = []
this.updatePluginViews()
}

@@ -78,19 +79,18 @@

let redrawn = false
let decorations = viewDecorations(this)
let prevEditable = this.editable
this.editable = getEditable(this)
let innerDeco = viewDecorations(this), outerDeco = computeDocDeco(this)
if (!this.docView.matchesNode(state.doc, [], decorations)) {
if (!this.docView.matchesNode(state.doc, outerDeco, innerDeco)) {
stopObserving(this)
this.docView.update(state.doc, [], decorations, this)
this.docView.update(state.doc, outerDeco, innerDeco, this)
startObserving(this)
redrawn = true
}
if (redrawn || !state.selection.eq(prev.selection))
if (!state.selection.eq(prev.selection) || this.selectionReader.domChanged())
selectionToDOM(this, state.selection)
this.updateDOMForProps()
if (prevEditable != this.editable) this.selectionReader.editableChanged()
this.updatePluginViews(prev)
// FIXME somehow schedule this relative to ui/update so that it
// doesn't cause extra layout
if (state.scrollToSelection > prev.scrollToSelection || prev.config != state.config)

@@ -100,19 +100,21 @@ scrollPosIntoView(this, state.selection.head == null ? state.selection.from : state.selection.from)

updateDOMForProps() {
let spellcheck = !!this.someProp("spellcheck")
if (spellcheck != this.content.spellcheck) this.content.spellcheck = spellcheck
let label = this.someProp("label", f => f(this.state)) || ""
if (this.content.getAttribute("aria-label") != label) this.content.setAttribute("aria-label", label)
destroyPluginViews() {
let view
while (view = this.pluginViews.pop()) if (view.destroy) view.destroy()
}
let classes = ["ProseMirror", "ProseMirror-content"] // FIXME remove backwards-compat class
if (this.focused) classes.push("ProseMirror-focused")
if (this.state.selection.node) classes.push("ProseMirror-nodeselection")
this.someProp("class", f => {
let cls = f(this.state)
if (!cls) return
let array = cls.split(" ")
for (let i = 0; i < array.length; i++) classes.push(array[i])
})
let className = classes.sort().join(" ")
if (this.content.className != className) this.content.className = className
updatePluginViews(prevState) {
let plugins = this.state.plugins
if (!prevState || prevState.plugins != plugins) {
this.destroyPluginViews()
for (let i = 0; i < plugins.length; i++) {
let plugin = plugins[i]
if (plugin.options.view) this.pluginViews.push(plugin.options.view(this))
}
} else {
for (let i = 0; i < this.pluginViews.length; i++) {
let pluginView = this.pluginViews[i]
if (pluginView.update) pluginView.update(this)
}
}
}

@@ -123,3 +125,3 @@

hasFocus() {
if (this.content.ownerDocument.activeElement != this.content) return false
if (this.editable && this.content.ownerDocument.activeElement != this.content) return false
let sel = this.root.getSelection()

@@ -138,3 +140,3 @@ return sel.rangeCount && this.content.contains(sel.anchorNode.nodeType == 3 ? sel.anchorNode.parentNode : sel.anchorNode)

let prop = this.props && this.props[propName], value
if (prop && (value = f ? f(prop) : prop)) return value
if (prop != null && (value = f ? f(prop) : prop)) return value
let plugins = this.state.plugins

@@ -151,3 +153,3 @@ if (plugins) for (let i = 0; i < plugins.length; i++) {

selectionToDOM(this, this.state.selection, true)
this.content.focus()
if (this.editable) this.content.focus()
}

@@ -199,3 +201,5 @@

destroy() {
this.destroyPluginViews()
this.docView.destroy()
this.selectionReader.destroy()
EditorState.removeApplyListener(this.trackState)

@@ -212,2 +216,25 @@ if (this.content.parentNode) this.content.parentNode.removeChild(this.content)

function computeDocDeco(view) {
let attrs = Object.create(null)
attrs.class = "ProseMirror" + (view.focused ? " ProseMirror-focused" : "") +
(view.state.selection.node ? " ProseMirror-nodeselection" : "")
attrs.contenteditable = String(view.editable)
view.someProp("attributes", value => {
if (typeof value == "function") value = value(view.state)
if (value) for (let attr in value) {
if (attr == "class")
attrs.class += " " + value[attr]
else if (!attrs[attr] && attr != "contenteditable" && attr != "nodeName")
attrs[attr] = String(value[attr])
}
})
return [Decoration.node(0, view.state.doc.content.size, attrs)]
}
function getEditable(view) {
return !view.someProp("editable", value => value(view.state) === false)
}
// EditorProps:: interface

@@ -311,3 +338,3 @@ //

//
// nodeViews:: ?Object<(node: Node, view: EditorView, getPos: () → number) → NodeView>
// nodeViews:: ?Object<(node: Node, view: EditorView, getPos: () → number, decorations: [Decoration]) → NodeView>
// Allows you to pass custom rendering and behavior logic for nodes

@@ -320,2 +347,8 @@ // and marks. Should map node and mark names to constructor function

//
// `decorations` is an array of node or inline decorations that are
// active around the node. They are automatically drawn in the
// normal way, and you will usually just want to ignore this, but
// they can also be used as a way to provide context information to
// the node view without adding it to the document itself.
//
// clipboardSerializer:: ?DOMSerializer

@@ -331,15 +364,16 @@ // The DOM serializer to use when putting content onto the

//
// spellcheck:: ?bool
// Controls whether the DOM spellcheck attribute is enabled on the
// editable content. Defaults to false.
// editable:: ?(EditorState) → bool
// When this returns false, the content of the view is not directly
// editable.
//
// class:: ?(state: EditorState) → ?string
// Controls the CSS class name of the editor DOM node. Any classes
// returned from this will be added to the default `ProseMirror`
// class.
// attributes:: ?union<Object<string>, (EditorState) → ?Object<string>>
// Control the DOM attributes of the editable element. May be either
// an object or a function going from an editor state to an object.
// By default, the element will get a class `"ProseMirror"`, and
// will have its `contentEditable` attribute determined by the
// [`editable` prop](#view.EditorProps.editable). Additional classes
// provided here will be added to the class. For other attributes,
// the value provided first (as in
// [`someProp`](#view.EditorView.someProp)) will be used.
//
// label:: ?(state: EditorState) → ?string
// Can be used to set an `aria-label` attribute on the editable
// content node.
//
// scrollThreshold:: ?number

@@ -346,0 +380,0 @@ // Determines the distance (in pixels) between the cursor and the

@@ -11,3 +11,3 @@ const {Selection, NodeSelection, TextSelection} = require("prosemirror-state")

// to invoke when the event fires.
const handlers = {}
const handlers = {}, editHandlers = {}

@@ -26,3 +26,4 @@ function initInput(view) {

view.content.addEventListener(event, event => {
if (eventBelongsToView(view, event) && !view.someProp("handleDOMEvent", f => f(view, event)))
if ((view.editable || !(event.type in editHandlers)) &&
eventBelongsToView(view, event) && !view.someProp("handleDOMEvent", f => f(view, event)))
handler(view, event)

@@ -50,3 +51,3 @@ })

handlers.keydown = (view, event) => {
editHandlers.keydown = (view, event) => {
if (event.keyCode == 16) view.shiftKey = true

@@ -60,7 +61,7 @@ if (view.inDOMChange) return

handlers.keyup = (view, e) => {
editHandlers.keyup = (view, e) => {
if (e.keyCode == 16) view.shiftKey = false
}
handlers.keypress = (view, event) => {
editHandlers.keypress = (view, event) => {
if (view.inDOMChange || !event.charCode ||

@@ -268,4 +269,3 @@ event.ctrlKey && !event.altKey || browser.mac && event.metaKey) return

} else if (this.flushed) {
this.view.focus()
this.view.props.onAction(Selection.near(this.view.state.doc.resolve(this.pos.pos)).action({origin: "mouse"}))
updateSelection(this.view, Selection.near(this.view.state.doc.resolve(this.pos.pos)), "mouse")
event.preventDefault()

@@ -311,3 +311,3 @@ } else {

handlers.compositionstart = handlers.compositionupdate = view => {
editHandlers.compositionstart = editHandlers.compositionupdate = view => {
DOMChange.start(view, true)

@@ -317,3 +317,3 @@ if (view.state.storedMarks) view.inDOMChange.finish(true)

handlers.compositionend = (view, e) => {
editHandlers.compositionend = (view, e) => {
if (!view.inDOMChange) {

@@ -343,6 +343,5 @@ // We received a compositionend without having seen any previous

function registerMutations(view, mutations) {
for (let i = 0; i < mutations.length; i++) {
let mut = mutations[i]
if (mut.target == view.content && mut.type == "attributes") continue
let desc = view.docView.nearestDesc(mut.target)
if (view.editable) for (let i = 0; i < mutations.length; i++) {
let mut = mutations[i], desc = view.docView.nearestDesc(mut.target)
if (desc == view.docView && mut.type == "attributes") continue
if (!desc || desc.ignoreMutation(mut)) continue

@@ -371,5 +370,5 @@

handlers.input = view => DOMChange.start(view)
editHandlers.input = view => DOMChange.start(view)
handlers.copy = handlers.cut = (view, e) => {
handlers.copy = editHandlers.cut = (view, e) => {
let sel = view.state.selection, cut = e.type == "cut"

@@ -390,3 +389,3 @@ if (sel.empty) return

handlers.paste = (view, e) => {
editHandlers.paste = (view, e) => {
if (!e.clipboardData) {

@@ -449,5 +448,7 @@ if (browser.ie && browser.ie_version <= 11) DOMChange.start(view)

handlers.dragover = handlers.dragenter = (_, e) => e.preventDefault()
editHandlers.dragover = editHandlers.dragenter = (_, e) => e.preventDefault()
handlers.drop = (view, e) => {
editHandlers.dragleave = () => null
editHandlers.drop = (view, e) => {
let dragging = view.dragging

@@ -496,1 +497,4 @@ view.dragging = null

}
// Make sure all handlers get registered
for (let prop in editHandlers) handlers[prop] = editHandlers[prop]

@@ -17,8 +17,17 @@ const {Selection, NodeSelection} = require("prosemirror-state")

view.content.addEventListener("focus", () => this.poller.receivedFocus())
view.content.addEventListener("blur", () => this.poller.lostFocus())
view.content.addEventListener("focus", () => this.poller.start())
view.content.addEventListener("blur", () => this.poller.stop())
if (!view.editable) this.poller.start()
}
destroy() { this.poller.stop() }
poll(origin) { this.poller.poll(origin) }
editableChanged() {
if (!this.view.editable) this.poller.start()
else if (!this.view.hasFocus()) this.poller.stop()
}
// : () → bool

@@ -70,68 +79,72 @@ // Whether the DOM selection has changed from the last known state.

function poller(reader) {
// There's two polling models. On browsers that support the
// selectionchange event (everything except Firefox, basically), we
// register a listener for that whenever the editor is focused.
if ("onselectionchange" in document) return new class {
constructor() {
this.listening = false
this.curOrigin = null
this.originTime = 0
// There's two polling models. On browsers that support the
// selectionchange event (everything except Firefox, basically), we
// register a listener for that whenever the editor is focused.
class SelectionChangePoller {
constructor(reader) {
this.listening = false
this.curOrigin = null
this.originTime = 0
this.readFunc = () => reader.readFromDOM(this.originTime > Date.now() - 50 ? this.curOrigin : null)
}
this.readFunc = () => reader.readFromDOM(this.originTime > Date.now() - 50 ? this.curOrigin : null)
}
poll(origin) {
this.curOrigin = origin
this.originTime = Date.now()
}
poll(origin) {
this.curOrigin = origin
this.originTime = Date.now()
}
receivedFocus() {
if (!this.listening) {
document.addEventListener("selectionchange", this.readFunc)
this.listening = true
}
start() {
if (!this.listening) {
document.addEventListener("selectionchange", this.readFunc)
this.listening = true
}
}
lostFocus() {
if (this.listening) {
document.removeEventListener("selectionchange", this.readFunc)
this.listening = false
}
stop() {
if (this.listening) {
document.removeEventListener("selectionchange", this.readFunc)
this.listening = false
}
}
// On Firefox, we use timeout-based polling.
return new class {
constructor() {
// The timeout ID for the poller when active.
this.polling = null
this.reader = reader
this.pollFunc = this.doPoll.bind(this, null)
}
}
doPoll(origin) {
if (this.reader.view.hasFocus()) {
this.reader.readFromDOM(origin)
this.polling = setTimeout(this.pollFunc, 100)
} else {
this.polling = null
}
}
// On Firefox, we use timeout-based polling.
class TimeoutPoller {
constructor(reader) {
// The timeout ID for the poller when active.
this.polling = null
this.reader = reader
this.pollFunc = this.doPoll.bind(this, null)
}
poll(origin) {
clearTimeout(this.polling)
this.polling = setTimeout(origin ? this.doPoll.bind(this, origin) : this.pollFunc, 0)
doPoll(origin) {
let view = this.reader.view
if (view.focused || !view.editable) {
this.reader.readFromDOM(origin)
this.polling = setTimeout(this.pollFunc, 100)
} else {
this.polling = null
}
}
receivedFocus() {
if (this.polling == null) this.poll()
}
poll(origin) {
clearTimeout(this.polling)
this.polling = setTimeout(origin ? this.doPoll.bind(this, origin) : this.pollFunc, 0)
}
lostFocus() {
clearTimeout(this.polling)
this.polling = null
}
start() {
if (this.polling == null) this.poll()
}
stop() {
clearTimeout(this.polling)
this.polling = null
}
}
function poller(reader) {
return new ("onselectionchange" in document ? SelectionChangePoller : TimeoutPoller)(reader)
}
function selectionToDOM(view, sel, takeFocus) {

@@ -143,3 +156,3 @@ syncNodeSelection(view, sel)

// See https://bugzilla.mozilla.org/show_bug.cgi?id=921444
else if (browser.gecko) view.content.focus()
else if (browser.gecko && view.editable) view.content.focus()
}

@@ -146,0 +159,0 @@

@@ -26,10 +26,11 @@ const {DOMSerializer} = require("prosemirror-model")

//
// update:: ?(node: Node, deco: DecorationSet) → bool
// update:: ?(node: Node, decorations: [Decoration]) → bool
// When given, this will be called when the view is updating itself.
// It will be given a node (possibly of a different type), and a
// decoration set (which it may ignore, if it chooses not to support
// decorations), and should return true if it was able to update to
// that node, and false otherwise. If the node view has a
// `contentDOM` property (or no `dom` property), updating its child
// nodes will be handled by ProseMirror.
// It will be given a node (possibly of a different type), and an
// array of active decorations (which are automatically drawn, and
// the node view may ignore if it isn't interested in them), and
// should return true if it was able to update to that node, and
// false otherwise. If the node view has a `contentDOM` property (or
// no `dom` property), updating its child nodes will be handled by
// ProseMirror.
//

@@ -197,5 +198,8 @@ // selectNode:: ?()

nearestDesc(dom) {
for (; dom; dom = dom.parentNode) {
let desc = this.getDesc(dom)
if (desc) return desc
for (let first = true, cur = dom; cur; cur = cur.parentNode) {
let desc = this.getDesc(cur)
if (desc) {
if (first && desc.nodeDOM && !desc.nodeDOM.contains(dom)) first = false
else return desc
}
}

@@ -252,3 +256,5 @@ }

for (let j = i - 1; j >= 0; j--) {
let found = Array.prototype.indexOf.call(content.childNodes, this.children[j].dom)
let child = this.children[j]
if (!child.size) continue
let found = Array.prototype.indexOf.call(content.childNodes, child.dom)
if (found > -1) return found + 1

@@ -259,3 +265,5 @@ }

for (let j = i; j < this.children.length; j++) {
let found = Array.prototype.indexOf.call(content.childNodes, this.children[j].dom)
let child = this.children[j]
if (!child.size) continue
let found = Array.prototype.indexOf.call(content.childNodes, child.dom)
if (found > -1) return found

@@ -321,3 +329,3 @@ }

let child = this.children[i], end = offset + child.size
if (from < end && to > offset) {
if (offset == end ? from <= end && to >= offset : from < end && to > offset) {
let startInside = offset + child.border, endInside = end - child.border

@@ -390,4 +398,5 @@ if (from >= startInside && to <= endInside) {

// : (?ViewDesc, Node, [Decoration], DecorationSet, dom.Node, ?dom.Node, EditorView)
constructor(parent, node, outerDeco, innerDeco, dom, contentDOM, view) {
constructor(parent, node, outerDeco, innerDeco, dom, contentDOM, nodeDOM, view) {
super(parent, node.isLeaf ? nothing : [], dom, contentDOM)
this.nodeDOM = nodeDOM
this.node = node

@@ -413,18 +422,18 @@ this.outerDeco = outerDeco

// own position)
if (!descObj) return parent.posAtStart + parent.size
if (descObj.parent) return descObj.parent.posBeforeChild(descObj)
})
if (descObj && descObj.parent) return descObj.parent.posBeforeChild(descObj)
}, outerDeco)
let dom = spec && spec.dom, contentDOM = spec && spec.contentDOM
if (!dom) ({dom, contentDOM} = DOMSerializer.renderSpec(document, node.type.spec.toDOM(node)))
let startDOM = dom
for (let i = 0; i < outerDeco.length; i++)
dom = applyOuterDeco(dom, outerDeco[i].type.attrs, node)
if (!contentDOM && !node.isText) dom.contentEditable = false
let nodeDOM = dom
dom = applyOuterDeco(dom, outerDeco, node, !!contentDOM)
if (spec)
return descObj = new CustomNodeViewDesc(parent, node, outerDeco, innerDeco, dom, contentDOM, spec, view)
return descObj = new CustomNodeViewDesc(parent, node, outerDeco, innerDeco, dom, contentDOM, nodeDOM, spec, view)
else if (node.isText)
return new TextViewDesc(parent, node, outerDeco, innerDeco, dom, startDOM, view)
return new TextViewDesc(parent, node, outerDeco, innerDeco, dom, nodeDOM, view)
else
return new NodeViewDesc(parent, node, outerDeco, innerDeco, dom, contentDOM, view)
return new NodeViewDesc(parent, node, outerDeco, innerDeco, dom, contentDOM, nodeDOM, view)
}

@@ -453,3 +462,3 @@

updater.placeWidget(widget)
}, (child, outerDeco, innerDeco) => {
}, (child, outerDeco, innerDeco, i) => {
// Make sure the wrapping mark descs match the node's marks.

@@ -461,3 +470,3 @@ updater.syncToMarks(child.marks, view)

// Or try updating the next desc to reflect this node.
updater.updateNode(child, outerDeco, innerDeco, view) ||
updater.updateNextNode(child, outerDeco, innerDeco, view, this.node.content, i) ||
// Or just add it as a new desc.

@@ -485,4 +494,4 @@ updater.addNode(child, outerDeco, innerDeco, view)

if (this.dirty == NODE_DIRTY ||
!node.sameMarkup(this.node) ||
!sameOuterDeco(outerDeco, this.outerDeco)) return false
!node.sameMarkup(this.node)) return false
this.updateOuterDeco(outerDeco)
this.node = node

@@ -495,5 +504,14 @@ this.innerDeco = innerDeco

updateOuterDeco(outerDeco) {
if (sameOuterDeco(outerDeco, this.outerDeco)) return
let content = !!this.contentDOM, needsWrap = this.nodeDOM.nodeType != 1
this.dom = patchOuterDeco(this.dom, this.nodeDOM,
computeOuterDeco(this.outerDeco, this.node, content, needsWrap),
computeOuterDeco(outerDeco, this.node, content, needsWrap))
this.outerDeco = outerDeco
}
// Mark this node as being the selected node.
selectNode() {
this.dom.classList.add("ProseMirror-selectednode")
this.nodeDOM.classList.add("ProseMirror-selectednode")
}

@@ -503,3 +521,3 @@

deselectNode() {
this.dom.classList.remove("ProseMirror-selectednode")
this.nodeDOM.classList.remove("ProseMirror-selectednode")
}

@@ -510,4 +528,5 @@ }

// and used by the view class.
function docViewDesc(doc, deco, dom, view) {
return new NodeViewDesc(null, doc, nothing, deco, dom, dom, view)
function docViewDesc(doc, outerDeco, innerDeco, dom, view) {
applyOuterDeco(dom, outerDeco, doc, true)
return new NodeViewDesc(null, doc, outerDeco, innerDeco, dom, dom, dom, view)
}

@@ -517,9 +536,8 @@ exports.docViewDesc = docViewDesc

class TextViewDesc extends NodeViewDesc {
constructor(parent, node, outerDeco, innerDeco, dom, textDOM, view) {
super(parent, node, outerDeco, innerDeco, dom, null, view)
this.textDOM = textDOM
constructor(parent, node, outerDeco, innerDeco, dom, nodeDOM, view) {
super(parent, node, outerDeco, innerDeco, dom, null, nodeDOM, view)
}
parseRule() {
return {skip: this.textDOM.parentNode}
return {skip: this.nodeDOM.parentNode}
}

@@ -529,6 +547,6 @@

if (this.dirty == NODE_DIRTY || (this.dirty != NOT_DIRTY && !this.inParent) ||
!node.sameMarkup(this.node) ||
!sameOuterDeco(outerDeco, this.outerDeco)) return false
if ((this.dirty != NOT_DIRTY || node.text != this.node.text) && node.text != this.textDOM.nodeValue)
this.textDOM.nodeValue = node.text
!node.sameMarkup(this.node)) return false
this.updateOuterDeco(outerDeco)
if ((this.dirty != NOT_DIRTY || node.text != this.node.text) && node.text != this.nodeDOM.nodeValue)
this.nodeDOM.nodeValue = node.text
this.node = node

@@ -541,3 +559,3 @@ this.dirty = NOT_DIRTY

let parentDOM = this.parent.contentDOM
for (let n = this.textDOM; n; n = n.parentNode) if (n == parentDOM) return true
for (let n = this.nodeDOM; n; n = n.parentNode) if (n == parentDOM) return true
return false

@@ -547,7 +565,7 @@ }

domFromPos(pos, searchDOM) {
return {node: this.textDOM, offset: searchDOM ? Math.max(pos, this.textDOM.nodeValue.length) : pos}
return {node: this.nodeDOM, offset: searchDOM ? Math.max(pos, this.nodeDOM.nodeValue.length) : pos}
}
localPosFromDOM(dom, offset, bias) {
if (dom == this.textDOM) return this.posAtStart + Math.min(offset, this.node.text.length)
if (dom == this.nodeDOM) return this.posAtStart + Math.min(offset, this.node.text.length)
return super.localPosFromDOM(dom, offset, bias)

@@ -563,9 +581,5 @@ }

// around contentEditable terribleness.
class HackViewDesc extends ViewDesc {
constructor(parent, type, dom) {
super(parent, nothing, dom, null)
this.type = type
}
class BRHackViewDesc extends ViewDesc {
parseRule() { return {ignore: true} }
matchesHack(type) { return this.dirty == NOT_DIRTY && this.type == type }
matchesHack() { return this.dirty == NOT_DIRTY }
}

@@ -578,4 +592,4 @@

// : (?ViewDesc, Node, [Decoration], DecorationSet, dom.Node, ?dom.Node, NodeView, EditorView)
constructor(parent, node, outerDeco, innerDeco, dom, contentDOM, spec, view) {
super(parent, node, outerDeco, innerDeco, dom, contentDOM, view)
constructor(parent, node, outerDeco, innerDeco, dom, contentDOM, nodeDOM, spec, view) {
super(parent, node, outerDeco, innerDeco, dom, contentDOM, nodeDOM, view)
this.spec = spec

@@ -589,3 +603,3 @@ }

if (this.spec.update) {
let result = this.spec.update(node, innerDeco)
let result = this.spec.update(node, outerDeco)
if (result) {

@@ -596,4 +610,6 @@ this.node = node

return result
} else if (!this.contentDOM && !node.isLeaf) {
return false
} else {
return super.update(node, outerDeco, innerDeco, view)
return super.update(node, outerDeco, this.contentDOM ? this.innerDeco : innerDeco, view)
}

@@ -648,20 +664,91 @@ }

// : (dom.Node, Object, Node) → dom.Node
// Apply the extra attributes and potentially add a wrapper for a
// decoration.
function applyOuterDeco(dom, attrs, node) {
if (attrs.nodeName || dom.nodeType != 1) {
let wrap = document.createElement(attrs.nodeName || (node.isInline ? "span" : "div"))
wrap.appendChild(dom)
dom = wrap
class OuterDecoLevel {
constructor(nodeName) {
if (nodeName) this.nodeName = nodeName
}
for (let name in attrs) {
let val = attrs[name]
if (name == "class") dom.classList.add(...val.split(" "))
else if (name == "style") dom.style.cssText += ";" + val
else if (name != "nodeName") dom.setAttribute(name, val)
}
OuterDecoLevel.prototype = Object.create(null)
const noDeco = [new OuterDecoLevel]
function computeOuterDeco(outerDeco, node, hasContent, needsWrap) {
if (hasContent && outerDeco.length == 0) return noDeco
let top = needsWrap ? noDeco[0] : new OuterDecoLevel, result = [top]
if (outerDeco.length) {
for (let i = 0; i < outerDeco.length; i++) {
let attrs = outerDeco[i].type.attrs, cur = top
if (!attrs) continue
if (attrs.nodeName)
result.push(cur = new OuterDecoLevel(attrs.nodeName))
for (let name in attrs) {
let val = attrs[name]
if (val == null) continue
if (needsWrap && result.length == 1)
result.push(cur = top = new OuterDecoLevel(node.isInline ? "span" : "div"))
if (name == "class") cur.class = (cur.class ? cur.class + " " : "") + val
else if (name == "style") cur.style = (cur.style ? cur.style + ";" : "") + val
else if (name != "nodeName") cur[name] = val
}
}
}
return dom
if (!hasContent && node.isBlock && result.length == 1 && !result[0].nodeName)
result.push(new OuterDecoLevel("div"))
return result
}
function patchOuterDeco(outerDOM, nodeDOM, prevComputed, curComputed) {
// Shortcut for trivial case
if (prevComputed == noDeco && curComputed == noDeco) return nodeDOM
let curDOM = nodeDOM
for (let i = 0; i < curComputed.length; i++) {
let deco = curComputed[i], prev = prevComputed[i]
if (i) {
let parent
if (prev && prev.nodeName == deco.nodeName && curDOM != outerDOM &&
(parent = nodeDOM.parentNode) && parent.tagName.toLowerCase() == deco.nodeName) {
curDOM = parent
} else {
parent = document.createElement(deco.nodeName)
parent.appendChild(curDOM)
curDOM = parent
}
}
patchAttributes(curDOM, prev || noDeco[0], deco)
}
return curDOM
}
function patchAttributes(dom, prev, cur) {
for (let name in prev)
if (name != "class" && name != "style" && name != "nodeName" && !(name in cur))
dom.removeAttribute(name)
for (let name in cur)
if (name != "class" && name != "style" && name != "nodeName" && cur[name] != prev[name])
dom.setAttribute(name, cur[name])
if (prev.class != cur.class) {
let prevList = prev.class ? prev.class.split(" ") : nothing
let curList = cur.class ? cur.class.split(" ") : nothing
for (let i = 0; i < prevList.length; i++) if (curList.indexOf(prevList[i]) == -1)
dom.classList.remove(prevList[i])
for (let i = 0; i < curList.length; i++) if (prevList.indexOf(curList[i]) == -1)
dom.classList.add(curList[i])
}
if (prev.style != cur.style) {
let text = dom.style.cssText, found
if (prev.style && (found = text.index(prev.style)) > -1)
text = text.slice(0, found) + text.slice(found + prev.style.length)
dom.style.cssText = text + (cur.style || "")
}
}
function applyOuterDeco(dom, deco, node, hasContent) {
return patchOuterDeco(dom, dom, noDeco, computeOuterDeco(deco, node, hasContent, dom.nodeType != 1))
}
// : ([Decoration], [Decoration]) → bool

@@ -748,3 +835,2 @@ function sameOuterDeco(a, b) {

findNodeMatch(node, outerDeco, innerDeco) {
// FIXME think about failure cases where updates will redraw too much
for (let i = this.index, children = this.top.children, e = Math.min(children.length, i + 5); i < e; i++) {

@@ -760,10 +846,21 @@ if (children[i].matchesNode(node, outerDeco, innerDeco)) {

// : (Node, [Decoration], DecorationSet, EditorView) → bool
// Try to update the next node, if any, to the given data.
updateNode(node, outerDeco, innerDeco, view) {
// : (Node, [Decoration], DecorationSet, EditorView, Fragment, number) → bool
// Try to update the next node, if any, to the given data. First
// tries scanning ahead in the siblings fragment to see if the next
// node matches any of those, and if so, doesn't touch it, to avoid
// overwriting nodes that could still be used.
updateNextNode(node, outerDeco, innerDeco, view, siblings, index) {
if (this.index == this.top.children.length) return false
let next = this.top.children[this.index]
if (!(next instanceof NodeViewDesc && next.update(node, outerDeco, innerDeco, view))) return false
this.index++
return true
if (next instanceof NodeViewDesc) {
for (let i = index + 1, e = Math.min(siblings.childCount, i + 5); i < e; i++)
if (next.node == siblings.child(i)) return false
let nextDOM = next.dom
if (next.update(node, outerDeco, innerDeco, view)) {
if (next.dom != nextDOM) this.changed = true
this.index++
return true
}
}
return false
}

@@ -790,18 +887,13 @@

addTextblockHacks() {
let lastChild = this.top.children[this.index - 1], hack
let lastChild = this.top.children[this.index - 1]
while (lastChild instanceof MarkViewDesc) lastChild = lastChild.children[lastChild.children.length - 1]
if (!lastChild || lastChild.dom.nodeName == "BR")
hack = "br"
else if (this.wrapsInPRE())
hack = "newline"
else if (!(lastChild instanceof TextViewDesc))
hack = "text"
if (hack) {
if (this.index < this.top.children.length && this.top.children[this.index].matchesHack(hack)) {
if (!lastChild || // Empty textblock
!(lastChild instanceof TextViewDesc) ||
/\n$/.test(lastChild.node.text)) {
if (this.index < this.top.children.length && this.top.children[this.index].matchesHack()) {
this.index++
} else {
let dom = document.createElement(hack == "br" ? "br" : "span")
if (hack == "newline") dom.textContent = "\n"
this.top.children.splice(this.index++, 0, new HackViewDesc(this.top, hack, dom))
let dom = document.createElement("br")
this.top.children.splice(this.index++, 0, new BRHackViewDesc(this.top, nothing, dom, null))
this.changed = true

@@ -811,10 +903,2 @@ }

}
wrapsInPRE() {
let top = this.top
for (let dom = top.contentDOM;; dom = dom.parentNode) {
if (dom.nodeName == "PRE") return true
if (dom == top.dom) return false
}
}
}

@@ -833,3 +917,3 @@

let child = parent.child(i)
onNode(child, locals, deco.forChild(offset, child))
onNode(child, locals, deco.forChild(offset, child), i)
offset += child.nodeSize

@@ -870,3 +954,3 @@ }

onNode(child, active.length ? active.slice() : nothing, deco.forChild(offset, child))
onNode(child, active.length ? active.slice() : nothing, deco.forChild(offset, child), parentIndex - 1)
offset = end

@@ -873,0 +957,0 @@ }

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc