8
0

attributeelement.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. /**
  2. * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. /**
  6. * @module engine/view/attributeelement
  7. */
  8. import Element from './element';
  9. // Default attribute priority.
  10. const DEFAULT_PRIORITY = 10;
  11. /**
  12. * Attributes are elements which define document presentation. They are mostly elements like `<b>` or `<span>`.
  13. * Attributes can be broken and merged by the {@link module:engine/view/writer~writer view writer}.
  14. *
  15. * Editing engine does not define fixed HTML DTD. This is why the type of the {@link module:engine/view/element~Element} need to
  16. * be defined by the feature developer. Creating an element you should use {@link module:engine/view/containerelement~ContainerElement}
  17. * class or `AttributeElement`.
  18. *
  19. * @extends module:engine/view/element~Element
  20. */
  21. export default class AttributeElement extends Element {
  22. /**
  23. * Creates a attribute element.
  24. *
  25. * @see module:engine/view/element~Element
  26. */
  27. constructor( name, attrs, children ) {
  28. super( name, attrs, children );
  29. /**
  30. * Element priority. Attributes have to have the same priority to be
  31. * {@link module:engine/view/element~Element#isSimilar similar}. Setting different priorities on similar
  32. * nodes may prevent merging, e.g. two `<abbr>` nodes next each other shouldn't be merged.
  33. *
  34. * @member {Number}
  35. */
  36. this.priority = DEFAULT_PRIORITY;
  37. /**
  38. * Returns block {@link module:engine/view/filler filler} offset or `null` if block filler is not needed.
  39. *
  40. * @method #getFillerOffset
  41. * @returns {Number|null} Block filler offset or `null` if block filler is not needed.
  42. */
  43. this.getFillerOffset = getFillerOffset;
  44. }
  45. /**
  46. * @inheritDoc
  47. */
  48. is( type, name = null ) {
  49. if ( !name ) {
  50. return type == 'attributeElement' || super.is( type );
  51. } else {
  52. return ( type == 'attributeElement' && name == this.name ) || super.is( type, name );
  53. }
  54. }
  55. /**
  56. * Clones provided element with priority.
  57. *
  58. * @param {Boolean} deep If set to `true` clones element and all its children recursively. When set to `false`,
  59. * element will be cloned without any children.
  60. * @returns {module:engine/view/attributeelement~AttributeElement} Clone of this element.
  61. */
  62. clone( deep ) {
  63. const cloned = super.clone( deep );
  64. // Clone priority too.
  65. cloned.priority = this.priority;
  66. return cloned;
  67. }
  68. /**
  69. * Checks if this element is similar to other element.
  70. * Both elements should have the same name, attributes and priority to be considered as similar.
  71. * Two similar elements can contain different set of children nodes.
  72. *
  73. * @param {module:engine/view/element~Element} otherElement
  74. * @returns {Boolean}
  75. */
  76. isSimilar( otherElement ) {
  77. return super.isSimilar( otherElement ) && this.priority == otherElement.priority;
  78. }
  79. }
  80. /**
  81. * Default attribute priority.
  82. *
  83. * @member {Number} module:engine/view/attributeelement~AttributeElement.DEFAULT_PRIORITY
  84. */
  85. AttributeElement.DEFAULT_PRIORITY = DEFAULT_PRIORITY;
  86. // Returns block {@link module:engine/view/filler~Filler filler} offset or `null` if block filler is not needed.
  87. //
  88. // @returns {Number|null} Block filler offset or `null` if block filler is not needed.
  89. function getFillerOffset() {
  90. // <b>foo</b> does not need filler.
  91. if ( nonUiChildrenCount( this ) ) {
  92. return null;
  93. }
  94. let element = this.parent;
  95. // <p><b></b></p> needs filler -> <p><b><br></b></p>
  96. while ( element && element.is( 'attributeElement' ) ) {
  97. if ( nonUiChildrenCount( element ) > 1 ) {
  98. return null;
  99. }
  100. element = element.parent;
  101. }
  102. if ( !element || nonUiChildrenCount( element ) > 1 ) {
  103. return null;
  104. }
  105. return 0;
  106. }
  107. // Returns total count of children that are not {@link module:engine/view/uielement~UIElement UIElements}.
  108. //
  109. // @param {module:engine/view/element~Element} element
  110. // @return {Number}
  111. function nonUiChildrenCount( element ) {
  112. return Array.from( element.getChildren() ).filter( element => !element.is( 'uiElement' ) ).length;
  113. }