prosemirror-model
Advanced tools
Comparing version 0.13.0 to 0.14.0
@@ -124,3 +124,3 @@ var ref = require("./fragment"); | ||
var max = ref.max; | ||
if (min != 0 && nodeTypes[0].hasRequiredAttrs(attrSet)) | ||
if (min != 0 && (nodeTypes[0].hasRequiredAttrs(attrSet) || nodeTypes[0].isText)) | ||
{ throw new SyntaxError("Node type " + types[0] + " in type " + nodeType.name + | ||
@@ -196,3 +196,4 @@ " is required, but has non-optional attributes") } | ||
ContentElement.prototype.defaultType = function defaultType () { | ||
return this.nodeTypes[0].defaultAttrs && this.nodeTypes[0] | ||
var first = this.nodeTypes[0] | ||
if (!(first.hasRequiredAttrs() || first.isText)) { return first } | ||
}; | ||
@@ -350,3 +351,3 @@ | ||
var type = elt.nodeTypes[j] | ||
if (!type.hasRequiredAttrs(attrs)) { found.push({type: type, attrs: attrs}) } | ||
if (!type.hasRequiredAttrs(attrs) && !type.isText) { found.push({type: type, attrs: attrs}) } | ||
} } | ||
@@ -353,0 +354,0 @@ if (this$1.resolveValue(elt.min) > count) { break } |
@@ -34,2 +34,6 @@ var ref = require("./fragment"); | ||
// | ||
// skip:: ?bool | ||
// When true, ignore the node that matches this rule, but do parse | ||
// its content. | ||
// | ||
// attrs:: ?Object | ||
@@ -56,2 +60,7 @@ // Attributes for the node or mark created by this rule. When | ||
// | ||
// getContent:: ?(dom.Node) → Fragment | ||
// Can be used to override the content of a matched node. Will be | ||
// called, and its result used, instead of parsing the node's child | ||
// node. | ||
// | ||
// preserveWhitespace:: ?bool | ||
@@ -302,12 +311,5 @@ // Controls whether whitespace should be preserved when parsing the | ||
ParseContext.prototype.addDOM = function addDOM (dom) { | ||
var this$1 = this; | ||
if (dom.nodeType == 3) { | ||
this.addTextNode(dom) | ||
} else if (dom.nodeType != 1 || dom.hasAttribute("pm-ignore")) { | ||
// Ignore | ||
} else if (dom.hasAttribute("pm-decoration")) { | ||
for (var child = dom.firstChild; child; child = child.nextSibling) | ||
{ this$1.addDOM(child) } | ||
} else { | ||
} else if (dom.nodeType == 1) { | ||
var style = dom.getAttribute("style") | ||
@@ -341,3 +343,3 @@ if (style) { this.addElementWithStyles(parseStyles(style), dom) } | ||
// : (dom.Node) | ||
// : (dom.Element) | ||
// Try to find a handler for the given tag and use that to parse. If | ||
@@ -348,12 +350,12 @@ // none is found, the element's content nodes are added directly. | ||
if (listTags.hasOwnProperty(name)) { normalizeList(dom) } | ||
// Ignore trailing BR nodes, which browsers create during editing | ||
if (this.options.editableContent && name == "br" && !dom.nextSibling) { return } | ||
if (!this.parseNodeType(dom, name)) { | ||
if (ignoreTags.hasOwnProperty(name)) { | ||
this.findInside(dom) | ||
} else { | ||
var sync = blockTags.hasOwnProperty(name) && this.top | ||
this.addAll(dom) | ||
if (sync) { this.sync(sync) } | ||
} | ||
var rule = (this.options.ruleFromNode && this.options.ruleFromNode(dom)) || this.parser.matchTag(dom) | ||
if (rule ? rule.ignore : ignoreTags.hasOwnProperty(name)) { | ||
this.findInside(dom) | ||
} else if (!rule || rule.skip) { | ||
if (rule && rule.skip.nodeType) { dom = rule.skip } | ||
var sync = blockTags.hasOwnProperty(name) && this.top | ||
this.addAll(dom) | ||
if (sync) { this.sync(sync) } | ||
} else { | ||
this.addElementByRule(dom, rule) | ||
} | ||
@@ -379,23 +381,28 @@ }; | ||
// (dom.Node, string) → bool | ||
// : (dom.Element, ParseRule) → bool | ||
// Look up a handler for the given node. If none are found, return | ||
// false. Otherwise, apply it, use its return value to drive the way | ||
// the node's content is wrapped, and return true. | ||
ParseContext.prototype.parseNodeType = function parseNodeType (dom) { | ||
var rule = (this.options.ruleFromNode && this.options.ruleFromNode(dom)) || this.parser.matchTag(dom) | ||
if (!rule) { return false } | ||
if (rule.ignore) { return true } | ||
ParseContext.prototype.addElementByRule = function addElementByRule (dom, rule) { | ||
var this$1 = this; | ||
var sync, before, nodeType, markType | ||
var sync, before, nodeType, markType, mark | ||
if (rule.node) { | ||
nodeType = this.parser.schema.nodes[rule.node] | ||
if (nodeType.isLeaf) { this.insertNode(nodeType.create(rule.attrs)) } | ||
if (nodeType.isLeaf) { this.insertNode(nodeType.create(rule.attrs, null, this.marks)) } | ||
else { sync = this.enter(nodeType, rule.attrs, rule.preserveWhitespace) && this.top } | ||
} else { | ||
markType = this.parser.schema.marks[rule.mark] | ||
before = this.addMark(markType.create(rule.attrs)) | ||
before = this.addMark(mark = markType.create(rule.attrs)) | ||
} | ||
if (rule.mark || !nodeType.isLeaf) { | ||
var contentDOM = (rule.contentElement && dom.querySelector(rule.contentElement)) || dom | ||
if (nodeType && nodeType.isLeaf) { | ||
this.findInside(dom) | ||
} else if (rule.getContent) { | ||
this.findInside(dom) | ||
rule.getContent(dom).forEach(function (node) { return this$1.insertNode(mark ? node.mark(mark.addToSet(node.marks)) : node); }) | ||
} else { | ||
var contentDOM = rule.contentElement | ||
if (typeof contentDOM == "string") { contentDOM = dom.querySelector(contentDOM) } | ||
if (!contentDOM) { contentDOM = dom } | ||
this.findAround(dom, contentDOM, true) | ||
@@ -406,4 +413,2 @@ this.addAll(contentDOM, sync) | ||
this.findAround(dom, contentDOM, true) | ||
} else { | ||
this.findInside(dom) | ||
} | ||
@@ -410,0 +415,0 @@ return true |
@@ -322,3 +322,3 @@ var ref = require("./node"); | ||
// parseDOM:: ?[ParseRule] | ||
// Associates DOM parser information with this node, which an be | ||
// Associates DOM parser information with this node, which can be | ||
// used by [`DOMParser.fromSchema`](#model.DOMParser^fromSchema) to | ||
@@ -325,0 +325,0 @@ // automatically derive a parser. The `node` field in the rules is |
@@ -91,10 +91,11 @@ // DOMOutputSpec:: interface | ||
DOMSerializer.prototype.renderStructure = function renderStructure (structure, node, options) { | ||
var this$1 = this; | ||
// :: (dom.Document, DOMOutputSpec) → {dom: dom.Node, contentDOM: ?dom.Node} | ||
// Render an [output spec](##model.DOMOutputSpec). | ||
DOMSerializer.renderSpec = function renderSpec (doc, structure) { | ||
if (typeof structure == "string") | ||
{ return doc(options).createTextNode(structure) } | ||
{ return {dom: doc.createTextNode(structure)} } | ||
if (structure.nodeType != null) | ||
{ return structure } | ||
var dom = doc(options).createElement(structure[0]), attrs = structure[1], start = 1 | ||
{ return {dom: structure} } | ||
var dom = doc.createElement(structure[0]), contentDOM = null | ||
var attrs = structure[1], start = 1 | ||
if (attrs && typeof attrs == "object" && attrs.nodeType == null && !Array.isArray(attrs)) { | ||
@@ -110,14 +111,32 @@ start = 2 | ||
if (child === 0) { | ||
if (!node || node.isLeaf) | ||
{ throw new RangeError("Content hole not allowed in a mark or leaf node spec (must produce a single node)") } | ||
if (i < structure.length - 1 || i > start) | ||
{ throw new RangeError("Content hole must be the only child of its parent node") } | ||
if (options.onContent) | ||
{ options.onContent(node, dom, options) } | ||
else | ||
{ this$1.serializeFragment(node.content, options, dom) } | ||
return {dom: dom, contentDOM: dom} | ||
} else { | ||
dom.appendChild(this$1.renderStructure(child, node, options)) | ||
var ref = DOMSerializer.renderSpec(doc, child); | ||
var inner = ref.dom; | ||
var innerContent = ref.contentDOM; | ||
dom.appendChild(inner) | ||
if (innerContent) { | ||
if (contentDOM) { throw new RangeError("Multiple content holes") } | ||
contentDOM = innerContent | ||
} | ||
} | ||
} | ||
return {dom: dom, contentDOM: contentDOM} | ||
}; | ||
DOMSerializer.prototype.renderStructure = function renderStructure (structure, node, options) { | ||
var ref = DOMSerializer.renderSpec(doc(options), structure); | ||
var dom = ref.dom; | ||
var contentDOM = ref.contentDOM; | ||
if (node && !node.isLeaf) { | ||
if (!contentDOM) { throw new RangeError("No content hole in template for non-leaf node") } | ||
if (options.onContent) | ||
{ options.onContent(node, contentDOM, options) } | ||
else | ||
{ this.serializeFragment(node.content, options, contentDOM) } | ||
} else if (contentDOM) { | ||
throw new RangeError("Content hole not allowed in a mark or leaf node spec") | ||
} | ||
return dom | ||
@@ -124,0 +143,0 @@ }; |
{ | ||
"name": "prosemirror-model", | ||
"version": "0.13.0", | ||
"version": "0.14.0", | ||
"description": "ProseMirror's document model", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
@@ -107,3 +107,3 @@ const {Fragment} = require("./fragment") | ||
let {min, max} = parseRepeat(nodeType, repeat) | ||
if (min != 0 && nodeTypes[0].hasRequiredAttrs(attrSet)) | ||
if (min != 0 && (nodeTypes[0].hasRequiredAttrs(attrSet) || nodeTypes[0].isText)) | ||
throw new SyntaxError("Node type " + types[0] + " in type " + nodeType.name + | ||
@@ -173,3 +173,4 @@ " is required, but has non-optional attributes") | ||
defaultType() { | ||
return this.nodeTypes[0].defaultAttrs && this.nodeTypes[0] | ||
let first = this.nodeTypes[0] | ||
if (!(first.hasRequiredAttrs() || first.isText)) return first | ||
} | ||
@@ -312,3 +313,3 @@ | ||
let type = elt.nodeTypes[j] | ||
if (!type.hasRequiredAttrs(attrs)) found.push({type, attrs}) | ||
if (!type.hasRequiredAttrs(attrs) && !type.isText) found.push({type, attrs}) | ||
} | ||
@@ -315,0 +316,0 @@ if (this.resolveValue(elt.min) > count) break |
@@ -31,2 +31,6 @@ const {Fragment} = require("./fragment") | ||
// | ||
// skip:: ?bool | ||
// When true, ignore the node that matches this rule, but do parse | ||
// its content. | ||
// | ||
// attrs:: ?Object | ||
@@ -53,2 +57,7 @@ // Attributes for the node or mark created by this rule. When | ||
// | ||
// getContent:: ?(dom.Node) → Fragment | ||
// Can be used to override the content of a matched node. Will be | ||
// called, and its result used, instead of parsing the node's child | ||
// node. | ||
// | ||
// preserveWhitespace:: ?bool | ||
@@ -294,8 +303,3 @@ // Controls whether whitespace should be preserved when parsing the | ||
this.addTextNode(dom) | ||
} else if (dom.nodeType != 1 || dom.hasAttribute("pm-ignore")) { | ||
// Ignore | ||
} else if (dom.hasAttribute("pm-decoration")) { | ||
for (let child = dom.firstChild; child; child = child.nextSibling) | ||
this.addDOM(child) | ||
} else { | ||
} else if (dom.nodeType == 1) { | ||
let style = dom.getAttribute("style") | ||
@@ -329,3 +333,3 @@ if (style) this.addElementWithStyles(parseStyles(style), dom) | ||
// : (dom.Node) | ||
// : (dom.Element) | ||
// Try to find a handler for the given tag and use that to parse. If | ||
@@ -336,12 +340,12 @@ // none is found, the element's content nodes are added directly. | ||
if (listTags.hasOwnProperty(name)) normalizeList(dom) | ||
// Ignore trailing BR nodes, which browsers create during editing | ||
if (this.options.editableContent && name == "br" && !dom.nextSibling) return | ||
if (!this.parseNodeType(dom, name)) { | ||
if (ignoreTags.hasOwnProperty(name)) { | ||
this.findInside(dom) | ||
} else { | ||
let sync = blockTags.hasOwnProperty(name) && this.top | ||
this.addAll(dom) | ||
if (sync) this.sync(sync) | ||
} | ||
let rule = (this.options.ruleFromNode && this.options.ruleFromNode(dom)) || this.parser.matchTag(dom) | ||
if (rule ? rule.ignore : ignoreTags.hasOwnProperty(name)) { | ||
this.findInside(dom) | ||
} else if (!rule || rule.skip) { | ||
if (rule && rule.skip.nodeType) dom = rule.skip | ||
let sync = blockTags.hasOwnProperty(name) && this.top | ||
this.addAll(dom) | ||
if (sync) this.sync(sync) | ||
} else { | ||
this.addElementByRule(dom, rule) | ||
} | ||
@@ -365,23 +369,26 @@ } | ||
// (dom.Node, string) → bool | ||
// : (dom.Element, ParseRule) → bool | ||
// Look up a handler for the given node. If none are found, return | ||
// false. Otherwise, apply it, use its return value to drive the way | ||
// the node's content is wrapped, and return true. | ||
parseNodeType(dom) { | ||
let rule = (this.options.ruleFromNode && this.options.ruleFromNode(dom)) || this.parser.matchTag(dom) | ||
if (!rule) return false | ||
if (rule.ignore) return true | ||
let sync, before, nodeType, markType | ||
addElementByRule(dom, rule) { | ||
let sync, before, nodeType, markType, mark | ||
if (rule.node) { | ||
nodeType = this.parser.schema.nodes[rule.node] | ||
if (nodeType.isLeaf) this.insertNode(nodeType.create(rule.attrs)) | ||
if (nodeType.isLeaf) this.insertNode(nodeType.create(rule.attrs, null, this.marks)) | ||
else sync = this.enter(nodeType, rule.attrs, rule.preserveWhitespace) && this.top | ||
} else { | ||
markType = this.parser.schema.marks[rule.mark] | ||
before = this.addMark(markType.create(rule.attrs)) | ||
before = this.addMark(mark = markType.create(rule.attrs)) | ||
} | ||
if (rule.mark || !nodeType.isLeaf) { | ||
let contentDOM = (rule.contentElement && dom.querySelector(rule.contentElement)) || dom | ||
if (nodeType && nodeType.isLeaf) { | ||
this.findInside(dom) | ||
} else if (rule.getContent) { | ||
this.findInside(dom) | ||
rule.getContent(dom).forEach(node => this.insertNode(mark ? node.mark(mark.addToSet(node.marks)) : node)) | ||
} else { | ||
let contentDOM = rule.contentElement | ||
if (typeof contentDOM == "string") contentDOM = dom.querySelector(contentDOM) | ||
if (!contentDOM) contentDOM = dom | ||
this.findAround(dom, contentDOM, true) | ||
@@ -392,4 +399,2 @@ this.addAll(contentDOM, sync) | ||
this.findAround(dom, contentDOM, true) | ||
} else { | ||
this.findInside(dom) | ||
} | ||
@@ -396,0 +401,0 @@ return true |
@@ -308,3 +308,3 @@ const {Node, TextNode} = require("./node") | ||
// parseDOM:: ?[ParseRule] | ||
// Associates DOM parser information with this node, which an be | ||
// Associates DOM parser information with this node, which can be | ||
// used by [`DOMParser.fromSchema`](#model.DOMParser^fromSchema) to | ||
@@ -311,0 +311,0 @@ // automatically derive a parser. The `node` field in the rules is |
@@ -86,8 +86,11 @@ // DOMOutputSpec:: interface | ||
renderStructure(structure, node, options) { | ||
// :: (dom.Document, DOMOutputSpec) → {dom: dom.Node, contentDOM: ?dom.Node} | ||
// Render an [output spec](##model.DOMOutputSpec). | ||
static renderSpec(doc, structure) { | ||
if (typeof structure == "string") | ||
return doc(options).createTextNode(structure) | ||
return {dom: doc.createTextNode(structure)} | ||
if (structure.nodeType != null) | ||
return structure | ||
let dom = doc(options).createElement(structure[0]), attrs = structure[1], start = 1 | ||
return {dom: structure} | ||
let dom = doc.createElement(structure[0]), contentDOM = null | ||
let attrs = structure[1], start = 1 | ||
if (attrs && typeof attrs == "object" && attrs.nodeType == null && !Array.isArray(attrs)) { | ||
@@ -103,14 +106,28 @@ start = 2 | ||
if (child === 0) { | ||
if (!node || node.isLeaf) | ||
throw new RangeError("Content hole not allowed in a mark or leaf node spec (must produce a single node)") | ||
if (i < structure.length - 1 || i > start) | ||
throw new RangeError("Content hole must be the only child of its parent node") | ||
if (options.onContent) | ||
options.onContent(node, dom, options) | ||
else | ||
this.serializeFragment(node.content, options, dom) | ||
return {dom, contentDOM: dom} | ||
} else { | ||
dom.appendChild(this.renderStructure(child, node, options)) | ||
let {dom: inner, contentDOM: innerContent} = DOMSerializer.renderSpec(doc, child) | ||
dom.appendChild(inner) | ||
if (innerContent) { | ||
if (contentDOM) throw new RangeError("Multiple content holes") | ||
contentDOM = innerContent | ||
} | ||
} | ||
} | ||
return {dom, contentDOM} | ||
} | ||
renderStructure(structure, node, options) { | ||
let {dom, contentDOM} = DOMSerializer.renderSpec(doc(options), structure) | ||
if (node && !node.isLeaf) { | ||
if (!contentDOM) throw new RangeError("No content hole in template for non-leaf node") | ||
if (options.onContent) | ||
options.onContent(node, contentDOM, options) | ||
else | ||
this.serializeFragment(node.content, options, contentDOM) | ||
} else if (contentDOM) { | ||
throw new RangeError("Content hole not allowed in a mark or leaf node spec") | ||
} | ||
return dom | ||
@@ -117,0 +134,0 @@ } |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
232804
5521