/** * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license */ import Range from '../../../src/model/range'; import Position from '../../../src/model/position'; import TreeWalker from '../../../src/model/treewalker'; import Text from '../../../src/model/text'; import TextProxy from '../../../src/model/textproxy'; /** * Returns tree structure as a simplified string. Elements are uppercase and characters are lowercase. * Start and end of an element is marked the same way, by the element's name (in uppercase). * * let element = new Element( 'div', [], [ 'abc', new Element( 'p', [], 'foo' ), 'xyz' ] ); * modelUtils.getNodesAndText( element ); // abcPfooPxyz * * @param {engine.model.Range} range Range to stringify. * @returns {String} String representing element inner structure. */ export function getNodesAndText( range ) { let txt = ''; const treeWalker = new TreeWalker( { boundaries: range } ); for ( const value of treeWalker ) { const node = value.item; const nodeText = node.data; if ( nodeText ) { txt += nodeText.toLowerCase(); } else { txt += node.name.toUpperCase(); } } return txt; } /** * Returns a {@link engine.model.Node} or if it starts at given offset, or {@link engine.model.TextProxy} with one * character, if given offset is occupied by a {@link engine.model.Text}. * * @param {engine.model.Element} parent Element from which item will be returned. * @param {Number} offset Item's offset. * @returns {engine.model.Node|engine.model.TextProxy} */ export function itemAt( parent, offset ) { const index = parent.offsetToIndex( offset ); const node = parent.getChild( index ); if ( node instanceof Text ) { const offsetInText = offset - node.startOffset; return new TextProxy( node, offsetInText, 1 ); } return node; } /** * Returns all text contents that are inside given element and all it's children. * * @param {engine.model.Element} element Element from which text will be returned. * @returns {String} Text contents of the element. */ export function getText( element ) { let text = ''; for ( const child of element.getChildren() ) { if ( child.data ) { text += child.data; } else if ( child.name ) { text += getText( child ); } } return text; } /** * Creates a range on given {@link engine.model.Element element} only. The range starts directly before that element * and ends before the first child of that element. * * @param {engine.model.Element} element Element on which range should be created. * @returns {engine.model.Range} */ export function createRangeOnElementOnly( element ) { return new Range( Position._createAt( element.parent, element.startOffset ), Position._createAt( element, 0 ) ); }