util.js 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. 'use strict';
  2. function dirtyReporter() {
  3. const dirty = new Map();
  4. const onchanges = [];
  5. function add(obj, value) {
  6. const saved = dirty.get(obj);
  7. if (!saved) {
  8. dirty.set(obj, {type: 'add', newValue: value});
  9. } else if (saved.type === 'remove') {
  10. if (saved.savedValue === value) {
  11. dirty.delete(obj);
  12. } else {
  13. saved.newValue = value;
  14. saved.type = 'modify';
  15. }
  16. }
  17. }
  18. function remove(obj, value) {
  19. const saved = dirty.get(obj);
  20. if (!saved) {
  21. dirty.set(obj, {type: 'remove', savedValue: value});
  22. } else if (saved.type === 'add') {
  23. dirty.delete(obj);
  24. } else if (saved.type === 'modify') {
  25. saved.type = 'remove';
  26. }
  27. }
  28. function modify(obj, oldValue, newValue) {
  29. const saved = dirty.get(obj);
  30. if (!saved) {
  31. if (oldValue !== newValue) {
  32. dirty.set(obj, {type: 'modify', savedValue: oldValue, newValue});
  33. }
  34. } else if (saved.type === 'modify') {
  35. if (saved.savedValue === newValue) {
  36. dirty.delete(obj);
  37. } else {
  38. saved.newValue = newValue;
  39. }
  40. } else if (saved.type === 'add') {
  41. saved.newValue = newValue;
  42. }
  43. }
  44. function clear(obj) {
  45. if (obj === undefined) {
  46. dirty.clear();
  47. } else {
  48. dirty.delete(obj);
  49. }
  50. }
  51. function isDirty() {
  52. return dirty.size > 0;
  53. }
  54. function onChange(cb) {
  55. // make sure the callback doesn't throw
  56. onchanges.push(cb);
  57. }
  58. function wrap(obj) {
  59. for (const key of ['add', 'remove', 'modify', 'clear']) {
  60. obj[key] = trackChange(obj[key]);
  61. }
  62. return obj;
  63. }
  64. function emitChange() {
  65. for (const cb of onchanges) {
  66. cb();
  67. }
  68. }
  69. function trackChange(fn) {
  70. return function () {
  71. const dirty = isDirty();
  72. const result = fn.apply(null, arguments);
  73. if (dirty !== isDirty()) {
  74. emitChange();
  75. }
  76. return result;
  77. };
  78. }
  79. function has(key) {
  80. return dirty.has(key);
  81. }
  82. return wrap({add, remove, modify, clear, isDirty, onChange, has});
  83. }