import { Arr, Cell, Optional } from '@ephox/katamari'; import { Compare, SugarElement, Traverse } from '@ephox/sugar'; import { createEntry, Entry } from './Entry'; import { isList } from './Util'; type Parser = (depth: number, itemSelection: Optional, selectionState: Cell, element: SugarElement) => Entry[]; export interface ItemSelection { readonly start: SugarElement; readonly end: SugarElement; } export interface EntrySet { readonly entries: Entry[]; readonly sourceList: SugarElement; } const parseItem: Parser = (depth: number, itemSelection: Optional, selectionState: Cell, item: SugarElement): Entry[] => Traverse.firstChild(item).filter(isList).fold(() => { // Update selectionState (start) itemSelection.each((selection) => { if (Compare.eq(selection.start, item)) { selectionState.set(true); } }); const currentItemEntry = createEntry(item, depth, selectionState.get()); // Update selectionState (end) itemSelection.each((selection) => { if (Compare.eq(selection.end, item)) { selectionState.set(false); } }); const childListEntries: Entry[] = Traverse.lastChild(item) .filter(isList) .map((list) => parseList(depth, itemSelection, selectionState, list)) .getOr([]); return currentItemEntry.toArray().concat(childListEntries); }, (list) => parseList(depth, itemSelection, selectionState, list)); const parseList: Parser = (depth: number, itemSelection: Optional, selectionState: Cell, list: SugarElement): Entry[] => Arr.bind(Traverse.children(list), (element) => { const parser = isList(element) ? parseList : parseItem; const newDepth = depth + 1; return parser(newDepth, itemSelection, selectionState, element); }); const parseLists = (lists: SugarElement[], itemSelection: Optional): EntrySet[] => { const selectionState = Cell(false); const initialDepth = 0; return Arr.map(lists, (list) => ({ sourceList: list, entries: parseList(initialDepth, itemSelection, selectionState, list) })); }; export { parseLists };