Text selection, range management, and cursor positioning utilities with cross-browser selection handling, position calculations, and comprehensive range operations.
Core selection operations for getting and setting text selections in browser windows.
/**
* Get current selection from window
* @param win - Window to get selection from
* @returns Current selection if one exists
*/
function get(win: SugarElement<Window>): Optional<SimSelection>;
/**
* Set selection in window
* @param win - Window to set selection in
* @param selection - Selection to apply
*/
function set(win: SugarElement<Window>, selection: SimSelection): void;
/**
* Clear selection in window
* @param win - Window to clear selection from
*/
function clear(win: SugarElement<Window>): void;
/**
* Get selection from element's owner window
* @param element - Element to get selection context from
* @returns Current selection if one exists
*/
function getFromElement(element: SugarElement<Node>): Optional<SimSelection>;
/**
* Set selection using element's owner window
* @param element - Element providing selection context
* @param selection - Selection to apply
*/
function setToElement(element: SugarElement<Node>, selection: SimSelection): void;Usage Examples:
import { WindowSelection, SugarElement } from "@ephox/sugar";
const win = SugarElement.fromDom(window);
// Get current selection
const currentSelection = WindowSelection.get(win);
currentSelection.each(selection => {
console.log('Found selection');
});
// Set new selection
const newSelection = SimSelection.exact(
startElement, 0,
endElement, 5
);
WindowSelection.set(win, newSelection);
// Clear selection
WindowSelection.clear(win);Simplified range representation for cross-browser compatibility.
/**
* Create simple range object
* @param start - Starting element
* @param soffset - Starting offset within element
* @param finish - Ending element
* @param foffset - Ending offset within element
* @returns Range object
*/
function create(
start: SugarElement<Node>,
soffset: number,
finish: SugarElement<Node>,
foffset: number
): SimRange;
interface SimRange {
readonly start: SugarElement<Node>;
readonly soffset: number;
readonly finish: SugarElement<Node>;
readonly foffset: number;
}Usage Examples:
import { SimRange, SugarElement } from "@ephox/sugar";
const startElement = SugarElement.fromText('Hello world');
const endElement = SugarElement.fromText('Goodbye');
// Create range from start of first text to end of second
const range = SimRange.create(startElement, 0, endElement, 7);
console.log('Range starts at:', range.start.dom.textContent);
console.log('Range starts at offset:', range.soffset);
console.log('Range ends at:', range.finish.dom.textContent);
console.log('Range ends at offset:', range.foffset);Unified selection interface handling multiple selection types with pattern matching.
/**
* Create selection from DOM Range object
* @param rng - Native DOM Range
* @returns SimSelection wrapping the range
*/
function domRange(rng: Range): SimSelection;
/**
* Create selection from relative positions
* @param startSitu - Starting position
* @param finishSitu - Ending position
* @returns SimSelection for relative positions
*/
function relative(startSitu: Situ, finishSitu: Situ): SimSelection;
/**
* Create selection from exact element positions
* @param start - Starting element
* @param soffset - Starting offset
* @param finish - Ending element
* @param foffset - Ending offset
* @returns SimSelection for exact positions
*/
function exact(
start: SugarElement<Node>,
soffset: number,
finish: SugarElement<Node>,
foffset: number
): SimSelection;
/**
* Create selection from SimRange object
* @param simRange - Range object to convert
* @returns SimSelection wrapping the range
*/
function exactFromRange(simRange: SimRange): SimSelection;
/**
* Get window associated with selection
* @param selection - Selection to get window for
* @returns Window element for the selection
*/
function getWin(selection: SimSelection): SugarElement<Window>;
interface SimSelection {
/** Pattern matching for different selection types */
fold: <U>(
domRange: (rng: Range) => U,
relative: (startSitu: Situ, finishSitu: Situ) => U,
exact: (start: SugarElement<Node>, soffset: number, finish: SugarElement<Node>, foffset: number) => U
) => U;
/** Alternative pattern matching syntax */
match: <U>(branches: {
domRange: (rng: Range) => U;
relative: (startSitu: Situ, finishSitu: Situ) => U;
exact: (start: SugarElement<Node>, soffset: number, finish: SugarElement<Node>, foffset: number) => U;
}) => U;
/** Debug logging */
log: (label: string) => void;
}Usage Examples:
import { SimSelection, SugarElement } from "@ephox/sugar";
// Create different types of selections
const domSelection = SimSelection.domRange(document.getSelection().getRangeAt(0));
const exactSelection = SimSelection.exact(startEl, 0, endEl, 5);
// Use pattern matching to handle different selection types
exactSelection.fold(
(domRange) => {
console.log('DOM Range:', domRange.toString());
return 'dom';
},
(startSitu, finishSitu) => {
console.log('Relative selection');
return 'relative';
},
(start, soffset, finish, foffset) => {
console.log(`Exact: ${start.dom.textContent}[${soffset}] to ${finish.dom.textContent}[${foffset}]`);
return 'exact';
}
);
// Alternative match syntax
const selectionType = exactSelection.match({
domRange: () => 'native-range',
relative: () => 'relative-position',
exact: () => 'exact-position'
});Position objects representing locations before, on, or after elements.
/**
* Create position before an element
* @param element - Element to position before
* @returns Position object
*/
function before(element: SugarElement<Node>): Situ;
/**
* Create position at specific offset within element
* @param element - Element containing the position
* @param offset - Offset within the element
* @returns Position object
*/
function on(element: SugarElement<Node>, offset: number): Situ;
/**
* Create position after an element
* @param element - Element to position after
* @returns Position object
*/
function after(element: SugarElement<Node>): Situ;
/**
* Pattern match on position type
* @param subject - Position to match on
* @param onBefore - Handler for before positions
* @param onOn - Handler for on positions
* @param onAfter - Handler for after positions
* @returns Result of handler function
*/
function cata<U>(
subject: Situ,
onBefore: (element: SugarElement<Node>) => U,
onOn: (element: SugarElement<Node>, offset: number) => U,
onAfter: (element: SugarElement<Node>) => U
): U;
/**
* Get element from position
* @param situ - Position to extract element from
* @returns Element referenced by position
*/
function getStart(situ: Situ): SugarElement<Node>;
interface Situ {
/** Pattern matching for position types */
fold: <U>(
before: (element: SugarElement<Node>) => U,
on: (element: SugarElement<Node>, offset: number) => U,
after: (element: SugarElement<Node>) => U
) => U;
/** Alternative pattern matching syntax */
match: <U>(branches: {
before: (element: SugarElement<Node>) => U;
on: (element: SugarElement<Node>, offset: number) => U;
after: (element: SugarElement<Node>) => U;
}) => U;
/** Debug logging */
log: (label: string) => void;
}Usage Examples:
import { Situ, SugarElement } from "@ephox/sugar";
const element = SugarElement.fromTag('p');
// Create different position types
const beforePos = Situ.before(element);
const onPos = Situ.on(element, 5);
const afterPos = Situ.after(element);
// Use pattern matching
const description = onPos.fold(
(el) => `Before ${el.dom.tagName}`,
(el, offset) => `At offset ${offset} in ${el.dom.tagName}`,
(el) => `After ${el.dom.tagName}`
);
// Extract element from position
const posElement = Situ.getStart(onPos);
console.log('Position element:', posElement.dom.tagName);
// Use in selection creation
const selection = SimSelection.relative(beforePos, afterPos);Geometric utilities for selection bounds and element positioning.
/**
* Get bounding rectangle for selection
* @param selection - Selection to get bounds for
* @returns Rectangle bounds if calculable
*/
function getBounds(selection: SimSelection): Optional<StructRect>;
/**
* Get bounding rectangle for range
* @param range - Range to get bounds for
* @returns Rectangle bounds if calculable
*/
function getRangeRect(range: SimRange): Optional<StructRect>;
/**
* Get bounding rectangle for element
* @param element - Element to get bounds for
* @returns Element's bounding rectangle
*/
function getElementRect(element: SugarElement<Element>): StructRect;
interface StructRect {
left: () => number;
top: () => number;
right: () => number;
bottom: () => number;
width: () => number;
height: () => number;
}
interface RawRect {
left: number;
top: number;
right: number;
bottom: number;
width: number;
height: number;
}
/**
* Convert structured rectangle to raw object
* @param sr - Structured rectangle
* @returns Raw rectangle object
*/
function toRaw(sr: StructRect): RawRect;Usage Examples:
import { Edge, RawRect, StructRect, SugarElement } from "@ephox/sugar";
// Get selection bounds
const selection = WindowSelection.get(window);
selection.each(sel => {
const bounds = SelectionBounds.getBounds(sel);
bounds.each(rect => {
const raw = Rect.toRaw(rect);
console.log(`Selection bounds: ${raw.width}x${raw.height} at (${raw.left}, ${raw.top})`);
});
});
// Get element bounds
const element = SugarElement.fromTag('div');
const elementRect = SelectionBounds.getElementRect(element);
console.log(`Element dimensions: ${elementRect.width()}x${elementRect.height()}`);Advanced selection operations and manipulations.
/**
* Expand selection to word boundaries
* @param selection - Selection to expand
* @returns Expanded selection
*/
function expandToWord(selection: SimSelection): SimSelection;
/**
* Collapse selection to start position
* @param selection - Selection to collapse
* @returns Collapsed selection at start
*/
function collapseToStart(selection: SimSelection): SimSelection;
/**
* Collapse selection to end position
* @param selection - Selection to collapse
* @returns Collapsed selection at end
*/
function collapseToEnd(selection: SimSelection): SimSelection;
/**
* Check if selection is collapsed (zero width)
* @param selection - Selection to check
* @returns True if selection has zero width
*/
function isCollapsed(selection: SimSelection): boolean;
/**
* Get text content of selection
* @param selection - Selection to extract text from
* @returns Text content within selection
*/
function getText(selection: SimSelection): string;
/**
* Replace selection content with text
* @param selection - Selection to replace
* @param text - Text to insert
* @returns New selection after replacement
*/
function replaceWith(selection: SimSelection, text: string): SimSelection;
/**
* Delete selection content
* @param selection - Selection to delete
* @returns New collapsed selection after deletion
*/
function deleteContents(selection: SimSelection): SimSelection;Convert between different range representations.
/**
* Convert SimSelection to native DOM Range
* @param selection - Selection to convert
* @returns Native DOM Range object
*/
function toRange(selection: SimSelection): Range;
/**
* Convert native DOM Range to SimSelection
* @param range - Native range to convert
* @returns SimSelection wrapping the range
*/
function fromRange(range: Range): SimSelection;
/**
* Convert SimRange to SimSelection
* @param simRange - Simple range to convert
* @returns SimSelection for the range
*/
function fromSimRange(simRange: SimRange): SimSelection;
/**
* Convert SimSelection to SimRange (if possible)
* @param selection - Selection to convert
* @returns Simple range if selection can be converted
*/
function toSimRange(selection: SimSelection): Optional<SimRange>;// Core selection types
interface SimRange {
readonly start: SugarElement<Node>;
readonly soffset: number;
readonly finish: SugarElement<Node>;
readonly foffset: number;
}
interface SimSelection {
fold: <U>(
domRange: (rng: Range) => U,
relative: (startSitu: Situ, finishSitu: Situ) => U,
exact: (start: SugarElement<Node>, soffset: number, finish: SugarElement<Node>, foffset: number) => U
) => U;
match: <U>(branches: {
domRange: (rng: Range) => U;
relative: (startSitu: Situ, finishSitu: Situ) => U;
exact: (start: SugarElement<Node>, soffset: number, finish: SugarElement<Node>, foffset: number) => U;
}) => U;
log: (label: string) => void;
}
interface Situ {
fold: <U>(
before: (element: SugarElement<Node>) => U,
on: (element: SugarElement<Node>, offset: number) => U,
after: (element: SugarElement<Node>) => U
) => U;
match: <U>(branches: {
before: (element: SugarElement<Node>) => U;
on: (element: SugarElement<Node>, offset: number) => U;
after: (element: SugarElement<Node>) => U;
}) => U;
log: (label: string) => void;
}
// Rectangle types for bounds calculation
interface StructRect {
left: () => number;
top: () => number;
right: () => number;
bottom: () => number;
width: () => number;
height: () => number;
}
interface RawRect {
left: number;
top: number;
right: number;
bottom: number;
width: number;
height: number;
}