utils.js 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. /**
  2. * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. import Range from '../../../src/model/range';
  6. import TreeWalker from '../../../src/model/treewalker';
  7. import Text from '../../../src/model/text';
  8. import TextProxy from '../../../src/model/textproxy';
  9. /**
  10. * Returns tree structure as a simplified string. Elements are uppercase and characters are lowercase.
  11. * Start and end of an element is marked the same way, by the element's name (in uppercase).
  12. *
  13. * let element = new Element( 'div', [], [ 'abc', new Element( 'p', [], 'foo' ), 'xyz' ] );
  14. * modelUtils.getNodesAndText( element ); // abcPfooPxyz
  15. *
  16. * @param {engine.model.Range} range Range to stringify.
  17. * @returns {String} String representing element inner structure.
  18. */
  19. export function getNodesAndText( range ) {
  20. let txt = '';
  21. const treeWalker = new TreeWalker( { boundaries: range } );
  22. for ( const value of treeWalker ) {
  23. const node = value.item;
  24. const nodeText = node.data;
  25. if ( nodeText ) {
  26. txt += nodeText.toLowerCase();
  27. } else {
  28. txt += node.name.toUpperCase();
  29. }
  30. }
  31. return txt;
  32. }
  33. /**
  34. * Returns a {@link engine.model.Node} or if it starts at given offset, or {@link engine.model.TextProxy} with one
  35. * character, if given offset is occupied by a {@link engine.model.Text}.
  36. *
  37. * @param {engine.model.Element} parent Element from which item will be returned.
  38. * @param {Number} offset Item's offset.
  39. * @returns {engine.model.Node|engine.model.TextProxy}
  40. */
  41. export function itemAt( parent, offset ) {
  42. const index = parent.offsetToIndex( offset );
  43. const node = parent.getChild( index );
  44. if ( node instanceof Text ) {
  45. const offsetInText = offset - node.startOffset;
  46. return new TextProxy( node, offsetInText, 1 );
  47. }
  48. return node;
  49. }
  50. /**
  51. * Returns all text contents that are inside given element and all it's children.
  52. *
  53. * @param {engine.model.Element} element Element from which text will be returned.
  54. * @returns {String} Text contents of the element.
  55. */
  56. export function getText( element ) {
  57. let text = '';
  58. for ( const child of element.getChildren() ) {
  59. if ( child.data ) {
  60. text += child.data;
  61. } else if ( child.name ) {
  62. text += getText( child );
  63. }
  64. }
  65. return text;
  66. }
  67. /**
  68. * Creates a range on given {@link engine.model.Element element} only. The range starts directly before that element
  69. * and ends before the first child of that element.
  70. *
  71. * @param {engine.model.Element} element Element on which range should be created.
  72. * @returns {engine.model.Range}
  73. */
  74. export function createRangeOnElementOnly( element ) {
  75. return Range.createFromParentsAndOffsets( element.parent, element.startOffset, element, 0 );
  76. }