json-diff.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. // http://json-diff.com/
  2. let JsonDiff = (function () {
  3. function JsonInputView(el, initialText) {
  4. this.el = el;
  5. let codemirror = this.codemirror = CodeMirror.fromTextArea(this.el, {
  6. lineNumbers: true,
  7. mode: {
  8. name: "javascript",
  9. json: true
  10. },
  11. matchBrackets: true,
  12. theme: 'tomorrow-night'
  13. });
  14. if (initialText) {
  15. codemirror.setValue(initialText);
  16. }
  17. let self = this;
  18. codemirror.on('inputRead', function (cm, e) {
  19. if (e.origin === 'paste') {
  20. autoFormat();
  21. }
  22. triggerChange();
  23. });
  24. codemirror.on('keyup', triggerChange);
  25. codemirror.on('change', triggerChange);
  26. codemirror.on('clear', function () {
  27. console.log(arguments);
  28. });
  29. let oldValue = '';
  30. function triggerChange() {
  31. let text = codemirror.getValue();
  32. if (text !== oldValue) {
  33. self.trigger('change');
  34. }
  35. oldValue = text;
  36. }
  37. function autoFormat() {
  38. let totalLines = codemirror.lineCount();
  39. codemirror.autoFormatRange({
  40. line: 0,
  41. ch: 0
  42. }, {
  43. line: totalLines
  44. });
  45. codemirror.setSelection({
  46. line: 0,
  47. ch: 0
  48. });
  49. }
  50. }
  51. JsonInputView.prototype.getText = function () {
  52. return this.codemirror.getValue();
  53. };
  54. JsonInputView.prototype.setText = function (text) {
  55. return this.codemirror.setValue(text);
  56. };
  57. JsonInputView.prototype.highlightRemoval = function (diff) {
  58. this._highlight(diff, '#DD4444');
  59. };
  60. JsonInputView.prototype.highlightAddition = function (diff) {
  61. this._highlight(diff, '#4ba2ff');
  62. };
  63. JsonInputView.prototype.highlightChange = function (diff) {
  64. this._highlight(diff, '#E5E833');
  65. };
  66. JsonInputView.prototype._highlight = function (diff, color) {
  67. let pos = getStartAndEndPosOfDiff(this.getText(), diff);
  68. this.codemirror.markText(pos.start, pos.end, {
  69. css: 'background-color: ' + color
  70. });
  71. };
  72. JsonInputView.prototype.clearMarkers = function () {
  73. this.codemirror.getAllMarks().forEach(function (marker) {
  74. marker.clear();
  75. });
  76. };
  77. function getStartAndEndPosOfDiff(textValue, diff) {
  78. let result = parse(textValue);
  79. let pointers = result.pointers;
  80. let path = diff.path;
  81. let start = {
  82. line: pointers[path].key ? pointers[path].key.line : pointers[path].value.line,
  83. ch: pointers[path].key ? pointers[path].key.column : pointers[path].value.column
  84. };
  85. let end = {
  86. line: pointers[path].valueEnd.line,
  87. ch: pointers[path].valueEnd.column
  88. };
  89. return {
  90. start: start,
  91. end: end
  92. }
  93. }
  94. function onInputChange() {
  95. compareJson();
  96. }
  97. let leftInputView = null;
  98. let rightInputView = null;
  99. let errHandler = null;
  100. let diffHandler = null;
  101. function compareJson() {
  102. leftInputView.clearMarkers();
  103. rightInputView.clearMarkers();
  104. let leftText = leftInputView.getText(),
  105. rightText = rightInputView.getText();
  106. let leftJson, rightJson;
  107. try {
  108. if (leftText) {
  109. leftJson = JSON.parse(leftText);
  110. }
  111. errHandler && errHandler('left', true);
  112. } catch (e) {
  113. console.log('left ==>', e);
  114. }
  115. try {
  116. if (rightText) {
  117. rightJson = JSON.parse(rightText);
  118. }
  119. errHandler && errHandler('right', true);
  120. } catch (e) {
  121. console.log('right ==>', e);
  122. }
  123. if (!leftJson || !rightJson) {
  124. if (!leftJson && !rightJson) {
  125. errHandler && errHandler('left-right', false);
  126. } else if (!leftJson) {
  127. errHandler && errHandler('left', false);
  128. } else {
  129. errHandler && errHandler('right', false);
  130. }
  131. return;
  132. }
  133. let diffs = jsonpatch.compare(leftJson, rightJson);
  134. diffHandler && diffHandler(diffs);
  135. diffs.forEach(function (diff) {
  136. try {
  137. if (diff.op === 'remove') {
  138. leftInputView.highlightRemoval(diff);
  139. } else if (diff.op === 'add') {
  140. rightInputView.highlightAddition(diff);
  141. } else if (diff.op === 'replace') {
  142. rightInputView.highlightChange(diff);
  143. leftInputView.highlightChange(diff);
  144. }
  145. } catch (e) {
  146. console.warn('error while trying to highlight diff', e);
  147. }
  148. });
  149. }
  150. function init(left, right, errorHandler, dfHandler) {
  151. errHandler = errorHandler;
  152. diffHandler = dfHandler;
  153. BackboneEvents.mixin(JsonInputView.prototype);
  154. leftInputView = new JsonInputView(left, '');
  155. rightInputView = new JsonInputView(right, '');
  156. leftInputView.on('change', onInputChange);
  157. rightInputView.on('change', onInputChange);
  158. leftInputView.codemirror.on('scroll', function () {
  159. let scrollInfo = leftInputView.codemirror.getScrollInfo();
  160. rightInputView.codemirror.scrollTo(scrollInfo.left, scrollInfo.top);
  161. });
  162. rightInputView.codemirror.on('scroll', function () {
  163. let scrollInfo = rightInputView.codemirror.getScrollInfo();
  164. leftInputView.codemirror.scrollTo(scrollInfo.left, scrollInfo.top);
  165. });
  166. }
  167. return {
  168. init: init
  169. }
  170. })();