changeoperation.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  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/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.operation.ChangeOperation
  11. */
  12. class ChangeOperation extends Operation {
  13. /**
  14. * Creates a change operation.
  15. *
  16. * If only the new attribute is set, then it will be inserted. Note that in all nodes in ranges there must be
  17. * no attributes with the same key as the new attribute.
  18. *
  19. * If only the old attribute is set, then 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, then the operation will change the attribute value. Note 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 the operation should be applied.
  26. * @param {document.Attribute|null} oldAttr Attribute to be removed. If `null`, then the operation just inserts a new attribute.
  27. * @param {document.Attribute|null} newAttr Attribute to be added. If `null`, then the operation just removes the attribute.
  28. * @param {Number} baseVersion {@link document.Document#version} on which the 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. Set to `null` if operation inserts a new attribute.
  42. *
  43. * @readonly
  44. * @type {document.Attribute|null}
  45. */
  46. this.oldAttr = oldAttr;
  47. /**
  48. * New attribute. Set to `null` if operation removes the attribute.
  49. *
  50. * @readonly
  51. * @type {document.Attribute|null}
  52. */
  53. this.newAttr = newAttr;
  54. }
  55. _execute() {
  56. var oldAttr = this.oldAttr;
  57. var newAttr = this.newAttr;
  58. var value;
  59. if ( oldAttr !== null && newAttr !== null && oldAttr.key != newAttr.key ) {
  60. /**
  61. * Old and new attributes should have the same keys.
  62. *
  63. * @error operation-change-different-keys
  64. * @param {document.Attribute} oldAttr
  65. * @param {document.Attribute} newAttr
  66. */
  67. throw new CKEditorError(
  68. 'operation-change-different-keys: Old and new attributes should have the same keys.',
  69. { oldAttr: oldAttr, newAttr: newAttr } );
  70. }
  71. // Remove or change.
  72. if ( oldAttr !== null ) {
  73. for ( value of this.range ) {
  74. if ( !value.node.hasAttr( oldAttr ) ) {
  75. /**
  76. * The attribute which should be removed does not exists for the given node.
  77. *
  78. * @error operation-change-no-attr-to-remove
  79. * @param {document.Node} node
  80. * @param {document.Attribute} attr
  81. */
  82. throw new CKEditorError(
  83. 'operation-change-no-attr-to-remove: The attribute which should be removed does not exists for given node.',
  84. { node: value.node, attr: oldAttr } );
  85. }
  86. // There is no use in removing attribute if we will overwrite it later.
  87. // Still it is profitable to run through the loop to check if all nodes in the range has old attribute.
  88. if ( newAttr === null ) {
  89. value.node.removeAttr( oldAttr.key );
  90. }
  91. }
  92. }
  93. // Insert or change.
  94. if ( newAttr !== null ) {
  95. for ( value of this.range ) {
  96. if ( oldAttr === null && value.node.hasAttr( newAttr.key ) ) {
  97. /**
  98. * The attribute with given key already exists for the given node.
  99. *
  100. * @error operation-change-attr-exists
  101. * @param {document.Node} node
  102. * @param {document.Attribute} attr
  103. */
  104. throw new CKEditorError(
  105. 'operation-change-attr-exists: The attribute with given key already exists.',
  106. { node: value.node, attr: newAttr } );
  107. }
  108. value.node.setAttr( newAttr );
  109. }
  110. }
  111. }
  112. getReversed() {
  113. return new ChangeOperation( this.range, this.newAttr, this.oldAttr, this.baseVersion + 1 );
  114. }
  115. }
  116. return ChangeOperation;
  117. } );