| Server IP : 34.87.99.72 / Your IP : 216.73.217.31 Web Server : Apache/2.4.46 (Unix) OpenSSL/1.1.1n System : Linux zlock-bitnami-lamp-prod-v2-vm 4.19.0-16-cloud-amd64 #1 SMP Debian 4.19.181-1 (2021-03-19) x86_64 User : bitnami ( 1000) PHP Version : 7.4.18 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : OFF Directory : /home/bitnami/htdocs/app/node_modules/prosemirror-model/src/ |
Upload File : |
import {Fragment} from "./fragment"
// ReplaceError:: class extends Error
// Error type raised by [`Node.replace`](#model.Node.replace) when
// given an invalid replacement.
export function ReplaceError(message) {
let err = Error.call(this, message)
err.__proto__ = ReplaceError.prototype
return err
}
ReplaceError.prototype = Object.create(Error.prototype)
ReplaceError.prototype.constructor = ReplaceError
ReplaceError.prototype.name = "ReplaceError"
// ::- A slice represents a piece cut out of a larger document. It
// stores not only a fragment, but also the depth up to which nodes on
// both side are ‘open’ (cut through).
export class Slice {
// :: (Fragment, number, number)
// Create a slice. When specifying a non-zero open depth, you must
// make sure that there are nodes of at least that depth at the
// appropriate side of the fragment—i.e. if the fragment is an empty
// paragraph node, `openStart` and `openEnd` can't be greater than 1.
//
// It is not necessary for the content of open nodes to conform to
// the schema's content constraints, though it should be a valid
// start/end/middle for such a node, depending on which sides are
// open.
constructor(content, openStart, openEnd) {
// :: Fragment The slice's content.
this.content = content
// :: number The open depth at the start.
this.openStart = openStart
// :: number The open depth at the end.
this.openEnd = openEnd
}
// :: number
// The size this slice would add when inserted into a document.
get size() {
return this.content.size - this.openStart - this.openEnd
}
insertAt(pos, fragment) {
let content = insertInto(this.content, pos + this.openStart, fragment, null)
return content && new Slice(content, this.openStart, this.openEnd)
}
removeBetween(from, to) {
return new Slice(removeRange(this.content, from + this.openStart, to + this.openStart), this.openStart, this.openEnd)
}
// :: (Slice) → bool
// Tests whether this slice is equal to another slice.
eq(other) {
return this.content.eq(other.content) && this.openStart == other.openStart && this.openEnd == other.openEnd
}
toString() {
return this.content + "(" + this.openStart + "," + this.openEnd + ")"
}
// :: () → ?Object
// Convert a slice to a JSON-serializable representation.
toJSON() {
if (!this.content.size) return null
let json = {content: this.content.toJSON()}
if (this.openStart > 0) json.openStart = this.openStart
if (this.openEnd > 0) json.openEnd = this.openEnd
return json
}
// :: (Schema, ?Object) → Slice
// Deserialize a slice from its JSON representation.
static fromJSON(schema, json) {
if (!json) return Slice.empty
let openStart = json.openStart || 0, openEnd = json.openEnd || 0
if (typeof openStart != "number" || typeof openEnd != "number")
throw new RangeError("Invalid input for Slice.fromJSON")
return new Slice(Fragment.fromJSON(schema, json.content), openStart, openEnd)
}
// :: (Fragment, ?bool) → Slice
// Create a slice from a fragment by taking the maximum possible
// open value on both side of the fragment.
static maxOpen(fragment, openIsolating=true) {
let openStart = 0, openEnd = 0
for (let n = fragment.firstChild; n && !n.isLeaf && (openIsolating || !n.type.spec.isolating); n = n.firstChild) openStart++
for (let n = fragment.lastChild; n && !n.isLeaf && (openIsolating || !n.type.spec.isolating); n = n.lastChild) openEnd++
return new Slice(fragment, openStart, openEnd)
}
}
function removeRange(content, from, to) {
let {index, offset} = content.findIndex(from), child = content.maybeChild(index)
let {index: indexTo, offset: offsetTo} = content.findIndex(to)
if (offset == from || child.isText) {
if (offsetTo != to && !content.child(indexTo).isText) throw new RangeError("Removing non-flat range")
return content.cut(0, from).append(content.cut(to))
}
if (index != indexTo) throw new RangeError("Removing non-flat range")
return content.replaceChild(index, child.copy(removeRange(child.content, from - offset - 1, to - offset - 1)))
}
function insertInto(content, dist, insert, parent) {
let {index, offset} = content.findIndex(dist), child = content.maybeChild(index)
if (offset == dist || child.isText) {
if (parent && !parent.canReplace(index, index, insert)) return null
return content.cut(0, dist).append(insert).append(content.cut(dist))
}
let inner = insertInto(child.content, dist - offset - 1, insert)
return inner && content.replaceChild(index, child.copy(inner))
}
// :: Slice
// The empty slice.
Slice.empty = new Slice(Fragment.empty, 0, 0)
export function replace($from, $to, slice) {
if (slice.openStart > $from.depth)
throw new ReplaceError("Inserted content deeper than insertion position")
if ($from.depth - slice.openStart != $to.depth - slice.openEnd)
throw new ReplaceError("Inconsistent open depths")
return replaceOuter($from, $to, slice, 0)
}
function replaceOuter($from, $to, slice, depth) {
let index = $from.index(depth), node = $from.node(depth)
if (index == $to.index(depth) && depth < $from.depth - slice.openStart) {
let inner = replaceOuter($from, $to, slice, depth + 1)
return node.copy(node.content.replaceChild(index, inner))
} else if (!slice.content.size) {
return close(node, replaceTwoWay($from, $to, depth))
} else if (!slice.openStart && !slice.openEnd && $from.depth == depth && $to.depth == depth) { // Simple, flat case
let parent = $from.parent, content = parent.content
return close(parent, content.cut(0, $from.parentOffset).append(slice.content).append(content.cut($to.parentOffset)))
} else {
let {start, end} = prepareSliceForReplace(slice, $from)
return close(node, replaceThreeWay($from, start, end, $to, depth))
}
}
function checkJoin(main, sub) {
if (!sub.type.compatibleContent(main.type))
throw new ReplaceError("Cannot join " + sub.type.name + " onto " + main.type.name)
}
function joinable($before, $after, depth) {
let node = $before.node(depth)
checkJoin(node, $after.node(depth))
return node
}
function addNode(child, target) {
let last = target.length - 1
if (last >= 0 && child.isText && child.sameMarkup(target[last]))
target[last] = child.withText(target[last].text + child.text)
else
target.push(child)
}
function addRange($start, $end, depth, target) {
let node = ($end || $start).node(depth)
let startIndex = 0, endIndex = $end ? $end.index(depth) : node.childCount
if ($start) {
startIndex = $start.index(depth)
if ($start.depth > depth) {
startIndex++
} else if ($start.textOffset) {
addNode($start.nodeAfter, target)
startIndex++
}
}
for (let i = startIndex; i < endIndex; i++) addNode(node.child(i), target)
if ($end && $end.depth == depth && $end.textOffset)
addNode($end.nodeBefore, target)
}
function close(node, content) {
if (!node.type.validContent(content))
throw new ReplaceError("Invalid content for node " + node.type.name)
return node.copy(content)
}
function replaceThreeWay($from, $start, $end, $to, depth) {
let openStart = $from.depth > depth && joinable($from, $start, depth + 1)
let openEnd = $to.depth > depth && joinable($end, $to, depth + 1)
let content = []
addRange(null, $from, depth, content)
if (openStart && openEnd && $start.index(depth) == $end.index(depth)) {
checkJoin(openStart, openEnd)
addNode(close(openStart, replaceThreeWay($from, $start, $end, $to, depth + 1)), content)
} else {
if (openStart)
addNode(close(openStart, replaceTwoWay($from, $start, depth + 1)), content)
addRange($start, $end, depth, content)
if (openEnd)
addNode(close(openEnd, replaceTwoWay($end, $to, depth + 1)), content)
}
addRange($to, null, depth, content)
return new Fragment(content)
}
function replaceTwoWay($from, $to, depth) {
let content = []
addRange(null, $from, depth, content)
if ($from.depth > depth) {
let type = joinable($from, $to, depth + 1)
addNode(close(type, replaceTwoWay($from, $to, depth + 1)), content)
}
addRange($to, null, depth, content)
return new Fragment(content)
}
function prepareSliceForReplace(slice, $along) {
let extra = $along.depth - slice.openStart, parent = $along.node(extra)
let node = parent.copy(slice.content)
for (let i = extra - 1; i >= 0; i--)
node = $along.node(i).copy(Fragment.from(node))
return {start: node.resolveNoCache(slice.openStart + extra),
end: node.resolveNoCache(node.content.size - slice.openEnd - extra)}
}