@lyra/form-builder
Version:
Lyra form builder
232 lines (203 loc) • 7.84 kB
JavaScript
'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;
}