utils.js 2.8 KB

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