8
0

changeoperation.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. /**
  2. * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. 'use strict';
  6. CKEDITOR.define( [ 'document/operation', 'ckeditorerror' ], function( Operation, CKEditorError ) {
  7. /**
  8. * Operation to change nodes attribute. Using this class you can add, remove or change value of the attribute.
  9. *
  10. * @class document.ChangeOperation
  11. */
  12. class ChangeOperation extends Operation {
  13. /**
  14. * Creates a change operation.
  15. *
  16. * If only new attribute is set it will be inserted. Note that there must be no attributes with the same key as
  17. * a new attribute in all nodes in ranges.
  18. *
  19. * If only old attribute is set it will be removed. Note that this attribute must be present in all nodes in
  20. * ranges.
  21. *
  22. * If both new and old attributes are set the operation will change the attribute value. Node that both new and
  23. * old attributes have to have the same key and the old attribute must be present in all nodes in ranges.
  24. *
  25. * @param {document.Range} range Range on which operation should be applied.
  26. * @param {document.Attribute|null} oldAttr Attribute to be removed. Null if operation just inserts a new attribute.
  27. * @param {document.Attribute|null} newAttr Attribute to be added. Null if operation just removes an attribute.
  28. * @param {Number} baseVersion {@link document.Document#version} on which operation can be applied.
  29. * @constructor
  30. */
  31. constructor( range, oldAttr, newAttr, baseVersion ) {
  32. super( baseVersion );
  33. /**
  34. * Range on which operation should be applied.
  35. *
  36. * @readonly
  37. * @type {document.Range}
  38. */
  39. this.range = range;
  40. /**
  41. * Old attribute to change. Null if operation inserts new attribute.
  42. *
  43. * @readonly
  44. * @type {document.Attribute|null}
  45. */
  46. this.oldAttr = oldAttr;
  47. /**
  48. * New attribute. Null if operation removes attribute.
  49. *
  50. * @readonly
  51. * @type {document.Attribute|null}
  52. */
  53. this.newAttr = newAttr;
  54. }
  55. /**
  56. * Execute operation.
  57. *
  58. * @protected
  59. */
  60. _execute() {
  61. var oldAttr = this.oldAttr;
  62. var newAttr = this.newAttr;
  63. var value;
  64. if ( oldAttr !== null && newAttr !== null && oldAttr.key != newAttr.key ) {
  65. /**
  66. * Old and new attributes should have the same keys.
  67. *
  68. * @error operation-change-different-keys
  69. * @param {document.ChangeOperation} changeOperation
  70. * @param {document.Attribute} oldAttr
  71. * @param {document.Attribute} newAttr
  72. */
  73. throw new CKEditorError(
  74. 'operation-change-different-keys: Old and new attributes should have the same keys.',
  75. { changeOperation: this, oldAttr: oldAttr, newAttr: newAttr } );
  76. }
  77. // Remove or change.
  78. if ( oldAttr !== null ) {
  79. for ( value of this.range ) {
  80. if ( !value.node.hasAttr( oldAttr ) ) {
  81. /**
  82. * The attribute which should be removed does not exists for given node.
  83. *
  84. * @error operation-change-no-attr-to-remove
  85. * @param {document.ChangeOperation} changeOperation
  86. * @param {document.Node} node
  87. * @param {document.Attribute} attr
  88. */
  89. throw new CKEditorError(
  90. 'operation-change-no-attr-to-remove: The attribute which should be removed does not exists for given node.',
  91. { changeOperation: this, node: value.node, attr: oldAttr } );
  92. }
  93. // There is no use in removing attribute if we will overwrite it later.
  94. // Still it is profitable to run throw the loop to check if all nodes in the range has old attribute.
  95. if ( newAttr === null ) {
  96. value.node.removeAttr( oldAttr.key );
  97. }
  98. }
  99. }
  100. // Insert or change.
  101. if ( newAttr !== null ) {
  102. for ( value of this.range ) {
  103. if ( oldAttr === null && value.node.hasAttr( newAttr.key ) ) {
  104. /**
  105. * The attribute with given key already exists for given node.
  106. *
  107. * @error operation-change-attr-exists
  108. * @param {document.ChangeOperation} changeOperation
  109. * @param {document.Node} node
  110. * @param {document.Attribute} attr
  111. */
  112. throw new CKEditorError(
  113. 'operation-change-attr-exists: The attribute with given key already exists.',
  114. { changeOperation: this, node: value.node, attr: newAttr } );
  115. }
  116. value.node.setAttr( newAttr );
  117. }
  118. }
  119. }
  120. /**
  121. * Creates an reverse change operation.
  122. *
  123. * @returns {document.ChangeOperation} Reverse operation.
  124. */
  125. reverseOperation() {
  126. return new ChangeOperation( this.range, this.newAttr, this.oldAttr, this.baseVersion + 1 );
  127. }
  128. }
  129. return ChangeOperation;
  130. } );