8
0

converter.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  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 ViewElement from './element.js';
  8. const _domToViewMapping = new WeakMap();
  9. const _viewToDomMapping = new WeakMap();
  10. const converter = {
  11. bindElements: function( domElement, viewElement ) {
  12. _domToViewMapping.set( domElement, viewElement );
  13. _viewToDomMapping.set( viewElement, domElement );
  14. },
  15. compareNodes: function( domNode, viewNode ) {
  16. // Elements.
  17. if ( domNode instanceof HTMLElement && viewNode instanceof ViewElement ) {
  18. return domNode === converter.getCorespondingDomElement( viewNode );
  19. }
  20. // Texts.
  21. else if ( domNode instanceof Text && viewNode instanceof ViewText ) {
  22. return domNode.data === viewNode.getText();
  23. }
  24. // Not matching types.
  25. return false;
  26. },
  27. cloneDomAttrs: function( domElement, viewElement ) {
  28. for ( let i = domElement.attributes.length - 1; i >= 0; i-- ) {
  29. let attr = domElement.attributes[ i ];
  30. viewElement.setAttr( attr.name, attr.value );
  31. }
  32. },
  33. // viewToDom do bind elements
  34. viewToDom: function( viewNode, domDocument ) {
  35. if ( viewNode instanceof ViewText ) {
  36. return domDocument.createTextNode( viewNode.getText() );
  37. } else {
  38. if ( converter.getCorespondingDom( viewNode ) ) {
  39. return converter.getCorespondingDom( viewNode );
  40. }
  41. const domElement = domDocument.createElement( viewNode.name );
  42. converter.bindElements( domElement, viewNode );
  43. for ( let key of viewNode.getAttrKeys() ) {
  44. domElement.setAttribute( key, viewNode.getAttr( key ) );
  45. }
  46. for ( let childView of viewNode.getChildren() ) {
  47. domElement.appendChild( converter.viewToDom( childView, domDocument ) );
  48. }
  49. return domElement;
  50. }
  51. },
  52. // Note that created elements will not have coresponding DOM elements created it these did not exist before.
  53. // domToView do not bind elements
  54. domToView: function( domElement ) {
  55. let viewElement = converter.getCorespondingView( domElement );
  56. if ( viewElement ) {
  57. return viewElement;
  58. }
  59. if ( domElement instanceof Text ) {
  60. return new ViewText( domElement.data );
  61. } else {
  62. viewElement = new ViewElement( domElement.tagName.toLowerCase() );
  63. const attrs = domElement.attributes;
  64. for ( let i = attrs.length - 1; i >= 0; i-- ) {
  65. viewElement.setAttr( attrs[ i ].name, attrs[ i ].value );
  66. }
  67. for ( let i = 0, len = domElement.childNodes.length; i < len; i++ ) {
  68. let domChild = domElement.childNodes[ i ];
  69. viewElement.appendChildren( converter.domToView( domChild ) );
  70. }
  71. return viewElement;
  72. }
  73. },
  74. getCorespondingView: function( domNode ) {
  75. if ( domNode instanceof HTMLElement ) {
  76. return converter.getCorespondingViewElement( domNode );
  77. } else {
  78. return converter.getCorespondingViewText( domNode );
  79. }
  80. },
  81. // Coresponding elements exists only for rendered elementes.
  82. getCorespondingViewElement: function( domElement ) {
  83. return _domToViewMapping.get( domElement );
  84. },
  85. getCorespondingViewText: function( domText ) {
  86. const previousSibling = domText.previousSibling;
  87. if ( previousSibling ) {
  88. const viewElement = converter.getCorespondingView( previousSibling );
  89. if ( viewElement ) {
  90. return viewElement.getNextSibling();
  91. }
  92. } else {
  93. const viewElement = converter.getCorespondingView( domText.parentElement );
  94. if ( viewElement ) {
  95. return viewElement.getChild( 0 );
  96. }
  97. }
  98. return null;
  99. },
  100. getCorespondingDom: function( viewNode ) {
  101. if ( viewNode instanceof ViewElement ) {
  102. return converter.getCorespondingDomElement( viewNode );
  103. } else {
  104. return converter.getCorespondingDomText( viewNode );
  105. }
  106. },
  107. getCorespondingDomElement: function( viewElement ) {
  108. return _viewToDomMapping.get( viewElement );
  109. },
  110. getCorespondingDomText: function( viewText ) {
  111. const previousSibling = viewText.getPreviousSibling();
  112. if ( previousSibling && converter.getCorespondingDom( previousSibling ) ) {
  113. return converter.getCorespondingDom( previousSibling ).nextSibling;
  114. }
  115. if ( !previousSibling && converter.getCorespondingDom( viewText.parent ) ) {
  116. return converter.getCorespondingDom( viewText.parent ).childNodes[ 0 ];
  117. }
  118. return null;
  119. },
  120. };
  121. export default converter;