import { SDataArray } from 's-array'; import S, { DataSignal } from 's-js'; import Sortable from 'sortablejs'; /** * One-way binds the given data-signal array to react to UI changes in the given HTML element (note the currying). */ export function sortableBindSarray(sArray: SDataArray, sortableOptions?: {[name: string]: any}): (element: HTMLElement) => void { return (element) => { // noinspection JSUnusedGlobalSymbols Sortable.create(element, { ...sortableOptions, onEnd: (event: Sortable.SortableEvent) => { // It's unclear whether oldIndex or newIndex are ever undefined. However, this is the current type declaration // in @types/sortablejs. if (event.oldIndex === undefined || event.newIndex === undefined || event.newIndex === event.oldIndex) { return; } const from: number = event.oldIndex; const to: number = event.newIndex; S.freeze(() => { const item: T = sArray()[from]; sArray.splice(from, 1); sArray.splice(to, 0, item); }); }, }); }; } /** * Two-way binds the given `number` data signal with the given `` element (note the currying). */ export function bindNumber(signal: DataSignal): (element: HTMLInputElement) => void { return (element) => { S(() => element.valueAsNumber = signal()); const event = 'input'; element.addEventListener(event, valueListener, false); S.cleanup(() => element.removeEventListener(event, valueListener)); function valueListener() { const current: number = S.sample(signal); const updated: number = element.valueAsNumber; if (current !== updated) { signal(updated); } return true; } }; } /** * Two-way binds the given `string` data signal with the given `` element (note the currying). */ export function bindString(signal: DataSignal): (element: HTMLInputElement | HTMLSelectElement) => void { return (element) => { S(() => element.value = signal()); const event = 'input'; element.addEventListener(event, valueListener, false); S.cleanup(() => element.removeEventListener(event, valueListener)); function valueListener(): boolean { const current: string = S.sample(signal); const updated: string = element.value; if (current !== updated) { signal(updated); } return true; } }; } /** * Two-way binds the given data signal with the given `input` element (note the currying): The element is checked if * and only if the data signal has the given “on”-value. */ export function bindToOnValue(signal: DataSignal, onValue: T): (element: HTMLInputElement) => void { return (element) => { S(() => element.checked = signal() === onValue); const event = 'change'; element.addEventListener(event, radioListener, false); S.cleanup(() => element.removeEventListener(event, radioListener)); function radioListener(): boolean { if (element.checked) { signal(onValue); } return true; } }; } /** * Two-way binds the given data signal with the given 'multiple' `