slate-edit-code
Version:
A Slate plugin to handle code blocks editing.
139 lines (111 loc) • 4.34 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _slate = require('slate');
var _slateSchemaViolations = require('slate-schema-violations');
var _immutable = require('immutable');
var _utils = require('../utils');
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
/**
* Create a schema definition with rules to normalize code blocks
*/
function schema(opts) {
var _blocks;
var baseSchema = {
blocks: (_blocks = {}, _defineProperty(_blocks, opts.containerType, {
nodes: [{ types: [opts.lineType] }],
normalize: function normalize(change, violation, context) {
switch (violation) {
case _slateSchemaViolations.CHILD_INVALID:
case _slateSchemaViolations.CHILD_TYPE_INVALID:
return onlyLine(opts, change, context);
default:
return undefined;
}
}
}), _defineProperty(_blocks, opts.lineType, {
nodes: [{ objects: ['text'], min: 1 }],
parent: { types: [opts.containerType] },
normalize: function normalize(change, violation, context) {
switch (violation) {
// This constant does not exist yet in
// official Slate, but exists in GitBook's
// fork. Until the PR is merged, we accept both
// https://github.com/ianstormtaylor/slate/pull/1842
case _slateSchemaViolations.PARENT_INVALID:
case _slateSchemaViolations.PARENT_TYPE_INVALID:
return noOrphanLine(opts, change, context);
default:
return undefined;
}
}
}), _blocks)
};
if (!opts.allowMarks) {
baseSchema.blocks[opts.lineType].marks = [];
}
return baseSchema;
}
/**
* A rule that ensure code blocks only contain lines of code, and no marks
*/
function onlyLine(opts, change, context) {
return change.withoutNormalization(function (c) {
var codeLines = (0, _immutable.List)();
context.node.nodes.forEach(function (node) {
if (node.object === opts.lineType) {
return;
}
if (node.object === 'text') {
if (node.text.length === 0) {
return;
}
codeLines = codeLines.concat((0, _utils.deserializeCode)(opts, node.text).nodes);
}
c.removeNodeByKey(node.key);
});
codeLines.forEach(function (codeLine, index) {
c.insertNodeByKey(context.node.key, index, codeLine);
});
return c;
});
}
/**
* Return a list of group of code lines. Used to wrap them together in
* independent code blocks.
*/
function getSuccessiveCodeLines(opts, nodes) {
var isLine = function isLine(n) {
return n.type === opts.lineType;
};
var nonLines = nodes.takeUntil(isLine);
var afterNonLines = nodes.skip(nonLines.size);
if (afterNonLines.isEmpty()) {
return (0, _immutable.List)();
}
var firstGroup = afterNonLines.takeWhile(isLine);
var restOfNodes = afterNonLines.skip(firstGroup.size);
return (0, _immutable.List)([firstGroup]).concat(getSuccessiveCodeLines(opts, restOfNodes));
}
/**
* A rule that ensure code lines are always children
* of a code block.
*/
function noOrphanLine(opts, change, context) {
var parent = context.parent;
var linesGroup = getSuccessiveCodeLines(opts, parent.nodes);
linesGroup.forEach(function (group) {
var container = _slate.Block.create({ type: opts.containerType, nodes: [] });
var firstLineIndex = parent.nodes.indexOf(group.first());
change.insertNodeByKey(parent.key, firstLineIndex, container, {
normalize: false
});
group.forEach(function (line, index) {
return change.moveNodeByKey(line.key, container.key, index, {
normalize: false
});
});
});
}
exports.default = schema;