@atlaskit/editor-plugin-tasks-and-decisions
Version:
Tasks and decisions plugin for @atlaskit/editor-core
96 lines (95 loc) • 2.72 kB
JavaScript
import { buildReplacementFragment, computeSelectionOffsets, narrowReplacementRange, restoreSelection } from '@atlaskit/editor-common/lists';
import { findFarthestParentNode } from '@atlaskit/editor-common/utils';
import { flattenTaskList, rebuildTaskList } from '../task-list-indentation';
const MAX_TASK_LIST_DEPTH = 6;
export function moveSelectedTaskListItems(tr, indentDelta) {
const {
doc,
selection
} = tr;
const {
schema
} = doc.type;
const {
taskList
} = schema.nodes;
const {
$from,
$to
} = selection;
const rootListResult = findFarthestParentNode(node => node.type === taskList)($from);
if (!rootListResult) {
return null;
}
const rootListStart = rootListResult.pos;
const rootListEnd = rootListStart + rootListResult.node.nodeSize;
const flattenResult = flattenTaskList({
doc,
rootListStart,
rootListEnd,
selectionFrom: $from.pos,
selectionTo: $to.pos,
indentDelta,
maxDepth: MAX_TASK_LIST_DEPTH
});
if (!flattenResult) {
return null;
}
const {
items: flattenedItems,
startIndex,
endIndex
} = flattenResult;
const {
fragment,
contentStartOffsets
} = buildReplacementFragment({
items: flattenedItems,
schema,
rebuildFn: rebuildTaskList,
extractContentFn: (item, s) => {
// Extract task item content for breakout.
// taskItem has inline content, so wrap in a paragraph.
// blockTaskItem already has paragraph children.
const {
blockTaskItem
} = s.nodes;
if (!!blockTaskItem && item.node.type === blockTaskItem) {
// blockTaskItem children are already paragraphs/extensions
const children = [];
item.node.forEach(child => children.push(child));
return children;
}
// Regular taskItem — wrap inline content in a paragraph
return [s.nodes.paragraph.create(null, item.node.content)];
}
});
if (fragment.size === 0) {
return null;
}
// Narrow the replacement to the minimal changed range for collab-friendly
// cursor preservation on unaffected list items.
const narrowed = narrowReplacementRange(tr.doc, rootListStart, rootListEnd, fragment, contentStartOffsets);
tr.replaceWith(narrowed.start, narrowed.end, narrowed.fragment);
const {
from,
to
} = computeSelectionOffsets({
items: flattenedItems,
startIndex,
endIndex,
originalFrom: $from.pos,
originalTo: $to.pos,
contentStartOffsets: narrowed.adjustedContentStartOffsets,
rootListStart: narrowed.start,
docSize: tr.doc.content.size
});
restoreSelection({
tr,
originalSelection: selection,
from,
to
});
tr.scrollIntoView();
return tr;
}