UNPKG

@lyra/form-builder

Version:
232 lines (203 loc) 7.84 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; exports.setBlockStyle = setBlockStyle; exports.toggleMark = toggleMark; exports.toggleListItem = toggleListItem; exports.expandToFocusedWord = expandToFocusedWord; exports.expandToNode = expandToNode; exports.removeSpan = removeSpan; exports.createFormBuilderSpan = createFormBuilderSpan; exports.removeAnnotationFromSpan = removeAnnotationFromSpan; exports.insertBlockObject = insertBlockObject; exports.insertInlineObject = insertInlineObject; var _slate = require('slate'); var _blockTools = require('@lyra/block-tools'); var _randomKey = require('./randomKey'); var _randomKey2 = _interopRequireDefault(_randomKey); var _changeToPatches = require('./changeToPatches'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function setBlockStyle(change, styleName) { var _change$value = change.value; const selection = _change$value.selection, startBlock = _change$value.startBlock, endBlock = _change$value.endBlock; // If a single block is selected partially, split block conditionally // (selection in start, middle or end of text) if (startBlock === endBlock && selection.isExpanded && !(selection.hasStartAtStartOf(startBlock) && selection.hasEndAtEndOf(startBlock))) { const hasTextBefore = !selection.hasStartAtStartOf(startBlock); const hasTextAfter = !selection.hasEndAtEndOf(startBlock); if (hasTextAfter) { const extendForward = selection.isForward ? selection.focusOffset - selection.anchorOffset : selection.anchorOffset - selection.focusOffset; change.collapseToStart().splitBlock().moveForward().extendForward(extendForward).collapseToEnd().splitBlock().collapseToStartOfPreviousText(); } else if (hasTextBefore) { change.collapseToStart().splitBlock().moveForward(); } else { change.collapseToEnd().splitBlock().select(selection); } } // Do the actual style transform, only acting on type contentBlock change.value.blocks.forEach(blk => { const newData = _extends({}, blk.data.toObject(), { style: styleName }); if (blk.type === 'contentBlock') { change.setNodeByKey(blk.key, { data: newData }); } }); change.focus(); return change; } function toggleMark(change, mark, editor) { change.toggleMark(mark); change.focus(); return change; } function toggleListItem(change, listItemName) { const blocks = change.value.blocks; if (blocks.length === 0) { return change; } const active = blocks.some(block => block.data.get('listItem') === listItemName); blocks.forEach(block => { const data = block.data ? block.data.toObject() : {}; if (active) { delete data.listItem; } else { data.listItem = listItemName; data.level = data.level || 1; } change.setNodeByKey(block.key, { data: data }); }); change.focus(); return change; } function expandToFocusedWord(change) { var _change$value2 = change.value; const focusText = _change$value2.focusText, focusOffset = _change$value2.focusOffset; const charsBefore = focusText.characters.slice(0, focusOffset); const charsAfter = focusText.characters.slice(focusOffset, -1); const isEmpty = obj => obj.get('text').match(/\s/g); const whiteSpaceBeforeIndex = charsBefore.reverse().findIndex(obj => isEmpty(obj)); const newStartOffset = whiteSpaceBeforeIndex > -1 ? charsBefore.size - whiteSpaceBeforeIndex : -1; const whiteSpaceAfterIndex = charsAfter.findIndex(obj => isEmpty(obj)); const newEndOffset = charsBefore.size + (whiteSpaceAfterIndex > -1 ? whiteSpaceAfterIndex : charsAfter.size + 1); // Not near any word, abort if (newStartOffset === newEndOffset) { return undefined; } // Select and highlight current word return change.moveOffsetsTo(newStartOffset, newEndOffset).focus(); } function expandToNode(change, node) { return change().moveToRangeOf(node).focus(); } function removeSpan(change, spanNode) { if (Array.isArray(spanNode)) { spanNode.forEach(node => { change.unwrapInlineByKey(node.key); }); change.focus(); } else if (spanNode) { change.unwrapInlineByKey(spanNode.key).focus(); } else { // Apply on current selection change.unwrapInline('span').focus(); } return change; } function createFormBuilderSpan(change, annotationName, key, originalSelection) { const value = change.value; const selection = value.selection; if (!selection.isExpanded) { expandToFocusedWord(change); } const span = { isVoid: false, type: 'span', object: 'inline', data: undefined, key: key }; change.unwrapInline('span').wrapInline(span); const currentSpan = value.inlines.filter(inline => inline.key === key).first(); const data = { annotations: currentSpan ? currentSpan.data.get('annotations') || {} : {}, focusedAnnotationName: annotationName, originalSelection: originalSelection }; data.annotations[annotationName] = { _type: annotationName, _key: key }; change.setInlines({ data: data }); return change; } function removeAnnotationFromSpan(change, spanNode, annotationType) { const annotations = spanNode.data.get('annotations'); if (!annotations) { return undefined; } // Remove the whole span if this annotation is the only one left if (Object.keys(annotations).length === 1 && annotations[annotationType]) { const originalSelection = spanNode.data.get('originalSelection'); change.call(removeSpan, spanNode); if (originalSelection) { change.select(originalSelection); } change.focus(); return change; } // If several annotations, remove only this one and leave the span node intact Object.keys(annotations).forEach(name => { if (annotations[name]._type === annotationType) { delete annotations[name]; } }); const data = _extends({}, spanNode.data.toObject(), { focusedAnnotationName: undefined, annotations: annotations, originalSelection: undefined }); change.setNodeByKey(spanNode.key, { data }); return change; } function insertBlockObject(change, type) { const key = (0, _randomKey2.default)(12); const block = _slate.Block.create({ type: type.name, isVoid: true, key: key, data: { _key: key, value: { _type: type.name, _key: key } } }); change.insertBlock(block).collapseToEndOfBlock(); return change; } function insertInlineObject(change, objectType, blockContentType) { const key = (0, _randomKey2.default)(12); const inline = { type: objectType.name, isVoid: true, key: key, data: { _key: key, value: { _type: objectType.name, _key: key, _oldKey: key } } }; change.insertInline(inline); const value = change.value; const focusBlock = value.focusBlock; const appliedBlocks = (0, _blockTools.editorValueToBlocks)({ document: { nodes: [focusBlock.toJSON(_changeToPatches.VALUE_TO_JSON_OPTS)] } }, blockContentType); const newBlock = _slate.Block.fromJSON((0, _blockTools.blocksToEditorValue)(appliedBlocks, blockContentType).document.nodes[0]); const inlineObject = newBlock.nodes.find(node => node.data && node.data.get('value') && node.data.get('value')._oldKey === key); const newData = inlineObject.data.toObject(); delete newData.value._oldKey; change.replaceNodeByKey(focusBlock.key, newBlock.toJSON(_changeToPatches.VALUE_TO_JSON_OPTS)); change.setNodeByKey(inlineObject.key, { data: newData }); change.collapseToEndOf(inlineObject); return change; }