UNPKG

slate-edit-code

Version:

A Slate plugin to handle code blocks editing.

139 lines (111 loc) 4.34 kB
'use strict'; 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;