8
0

treeview.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  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 EmitterMixin from '../../utils/emittermixin.js';
  7. import Renderer from './renderer.js';
  8. import DomConverter from './domconverter.js';
  9. import Writer from './writer.js';
  10. import utils from '../../utils/utils.js';
  11. /**
  12. * TreeView class creates an abstract layer over the content editable area.
  13. * It combines the actual tree of view elements, tree of DOM elements,
  14. * {@link core.treeView.DomConverter DOM Converter}, {@link core.treeView.Renderer renderer} and all
  15. * {@link core.treeView.Observer observers}.
  16. *
  17. * If you want to only transform the tree of view elements to the DOM elements you can use the
  18. * {@link core.treeView.DomConverter DomConverter}.
  19. *
  20. * @memberOf core.treeView
  21. * @mixes utils.EmitterMixin
  22. */
  23. export default class TreeView {
  24. /**
  25. * Creates a TreeView instance.
  26. */
  27. constructor() {
  28. /**
  29. * Roots of the DOM tree. Map on the `HTMLElement`s with roots names as keys.
  30. *
  31. * @readonly
  32. * @member {Map} core.treeView.TreeView#domRoots
  33. */
  34. this.domRoots = new Map();
  35. /**
  36. * Set of {@link core.treeView.Observer observers}.
  37. *
  38. * @readonly
  39. * @member {Set.<core.treeView.Observer>} core.treeView.TreeView#observers
  40. */
  41. this.observers = new Set();
  42. /**
  43. * Tree View writer.
  44. *
  45. * @readonly
  46. * @member {core.treeView.Writer} core.treeView.TreeView#writer
  47. */
  48. this.writer = new Writer();
  49. /**
  50. * Instance of the {@link core.treeView.DomConverter domConverter} use by
  51. * {@link core.treeView.TreeView#renderer renderer} and {@link core.treeView.TreeView#observers observers}.
  52. *
  53. * @readonly
  54. * @member {core.treeView.DomConverter} core.treeView.TreeView#domConverter
  55. */
  56. this.domConverter = new DomConverter();
  57. /**
  58. * Roots of the view tree. Map of the {core.treeView.Element view elements} with roots names as keys.
  59. *
  60. * @readonly
  61. * @member {Map} core.treeView.TreeView#viewRoots
  62. */
  63. this.viewRoots = new Map();
  64. /**
  65. * Instance of the {@link core.treeView.TreeView#renderer renderer}.
  66. *
  67. * @readonly
  68. * @member {core.treeView.Renderer} core.treeView.TreeView#renderer
  69. */
  70. this.renderer = new Renderer( this.domConverter );
  71. }
  72. /**
  73. * Adds an observer to the set of observers. This method also {@link core.treeView.Observer#init initializes} and
  74. * {@link core.treeView.Observer#enable enables} the observer.
  75. *
  76. * @param {core.treeView.Observer} observer The observer to add.
  77. */
  78. addObserver( observer ) {
  79. this.observers.add( observer );
  80. observer.init( this );
  81. for ( let [ name, domElement ] of this.domRoots ) {
  82. observer.observe( domElement, name );
  83. }
  84. observer.enable();
  85. }
  86. /**
  87. * Creates a root for the HTMLElement. It adds elements to {@link core.treeView.TreeView#domRoots} and
  88. * {@link core.treeView.TreeView#viewRoots}.
  89. *
  90. * The constructor copies the element name and attributes to create the
  91. * root of the view, but does not copy its children. This means that while
  92. * {@link core.treeView.TreeView#render rendering}, the whole content of this
  93. * root element will be removed but the root name and attributes will be preserved.
  94. *
  95. * @param {HTMLElement} domRoot DOM element in which the tree view should do change.
  96. * @param {String} name Name of the root.
  97. */
  98. createRoot( domRoot, name ) {
  99. const viewRoot = this.domConverter.domToView( domRoot, { bind: true, withChildren: false } );
  100. viewRoot.setTreeView( this );
  101. // Mark changed nodes in the renderer.
  102. viewRoot.on( 'change', ( evt, type, node ) => {
  103. this.renderer.markToSync( type, node );
  104. } );
  105. this.renderer.markToSync( 'CHILDREN', viewRoot );
  106. this.domRoots.set( name, domRoot );
  107. this.viewRoots.set( name, viewRoot );
  108. for ( let observer of this.observers ) {
  109. observer.observe( domRoot, name );
  110. }
  111. }
  112. /**
  113. * Renders all changes. In order to avoid triggering the observers (e.g. mutations) all observers all detached
  114. * before rendering and reattached after that.
  115. */
  116. render() {
  117. for ( let observer of this.observers ) {
  118. observer.disable();
  119. }
  120. this.renderer.render();
  121. for ( let observer of this.observers ) {
  122. observer.enable();
  123. }
  124. }
  125. }
  126. utils.mix( TreeView, EmitterMixin );
  127. /**
  128. * Enum representing type of the change.
  129. *
  130. * Possible values:
  131. *
  132. * * `CHILDREN` - for child list changes,
  133. * * `ATTRIBUTES` - for element attributes changes,
  134. * * `TEXT` - for text nodes changes.
  135. *
  136. * @typedef {String} core.treeView.ChangeType
  137. */