element.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. /**
  2. * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. 'use strict';
  6. import ViewText from './text.js';
  7. import Node from './node.js';
  8. import utils from '../utils.js';
  9. import langUtils from '../lib/lodash/lang.js';
  10. export default class Element extends Node {
  11. constructor( name, attrs, children ) {
  12. super();
  13. /**
  14. * @readolny
  15. */
  16. this.name = name;
  17. if ( langUtils.isPlainObject( attrs ) ) {
  18. this._attrs = utils.objectToMap( attrs );
  19. } else {
  20. this._attrs = new Map( attrs );
  21. }
  22. this._children = [];
  23. if ( children ) {
  24. this.insertChildren( 0, children );
  25. }
  26. this.domElement = null;
  27. }
  28. setDomElement( domElement ) {
  29. this.domElement = domElement;
  30. Element._domToViewMapping.set( domElement, this );
  31. }
  32. // Note that created elements will not have coresponding DOM elements created it these did not exist before.
  33. static createFromDom( domElement ) {
  34. let viewElement = this.getCorespondingElement( domElement );
  35. if ( viewElement ) {
  36. return viewElement;
  37. }
  38. if ( domElement instanceof Text ) {
  39. return new ViewText( domElement.data );
  40. } else {
  41. viewElement = new Element( domElement.name );
  42. const attrs = domElement.attributes;
  43. for ( let i = attrs.length - 1; i >= 0; i-- ) {
  44. viewElement.setAttr( attrs[ i ].name, attrs[ i ].value );
  45. }
  46. for ( let childView of viewElement.getChildren() ) {
  47. domElement.appendChild( this.createFromDom( childView ) );
  48. }
  49. return domElement;
  50. }
  51. }
  52. // Coresponding elements exists only for rendered elementes.
  53. static getCorespondingElement( domElement ) {
  54. return this._domToViewMapping.get( domElement );
  55. }
  56. getChildren() {
  57. return this._children[ Symbol.iterator ]();
  58. }
  59. getChild( index ) {
  60. return this._children[ index ];
  61. }
  62. getChildCount() {
  63. return this._children.length;
  64. }
  65. getChildIndex( node ) {
  66. return this._children.indexOf( node );
  67. }
  68. insertChildren( index, nodes ) {
  69. this.markToSync( 'CHILDREN_NEED_UPDATE' );
  70. if ( !utils.isIterable( nodes ) ) {
  71. nodes = [ nodes ];
  72. }
  73. for ( let node of nodes ) {
  74. node.parent = this;
  75. this._children.splice( index, 0, node );
  76. index++;
  77. }
  78. }
  79. removeChildren( index, number ) {
  80. this.markToSync( 'CHILDREN_NEED_UPDATE' );
  81. for ( let i = index; i < index + number; i++ ) {
  82. this._children[ i ].parent = null;
  83. }
  84. return new this._children.splice( index, number );
  85. }
  86. getAttrKeys() {
  87. return this._attrs.keys();
  88. }
  89. getAttr( key ) {
  90. return this._attrs.get( key );
  91. }
  92. hasAttr( key ) {
  93. return this._attrs.has( key );
  94. }
  95. setAttr( key, value ) {
  96. this.markToSync( 'ATTRIBUTES_NEED_UPDATE' );
  97. this._attrs.set( key, value );
  98. }
  99. cloneDOMAttrs( element ) {
  100. this.markToSync( 'ATTRIBUTES_NEED_UPDATE' );
  101. for ( let i = element.attributes.length - 1; i >= 0; i-- ) {
  102. let attr = element.attributes[ i ];
  103. this.setAttr( attr.name, attr.value );
  104. }
  105. }
  106. removeAttr( key ) {
  107. this.markToSync( 'ATTRIBUTES_NEED_UPDATE' );
  108. return this._attrs.delete( key );
  109. }
  110. }
  111. Element._domToViewMapping = new WeakMap();