├── images └── 效果图.png ├── index.js ├── src ├── main.js ├── components │ └── jsonDiff │ │ ├── static │ │ ├── vendor │ │ │ ├── codemirror │ │ │ │ ├── placeholder.js │ │ │ │ ├── active-line.js │ │ │ │ ├── matchbrackets.js │ │ │ │ ├── formatting.js │ │ │ │ └── javascript.js │ │ │ └── json-diff │ │ │ │ ├── backbone-events.min.js │ │ │ │ ├── json-diff.js │ │ │ │ ├── json-patch-duplex.min.js │ │ │ │ └── json-source-map.js │ │ ├── index.js │ │ └── css │ │ │ └── codemirror.css │ │ └── index.vue └── App.vue ├── .gitignore ├── package.json ├── README.md └── LICENSE /images/效果图.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qinxm/vue-json-diff/HEAD/images/效果图.png -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | module.exports = require('./src/components/jsonDiff/index.vue'); -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | 4 | Vue.config.productionTip = false 5 | 6 | new Vue({ 7 | render: h => h(App) 8 | }).$mount('#app') 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-json-diff", 3 | "version": "1.0.0", 4 | "description": "A json diff vue component", 5 | "main": "index.js", 6 | "scripts": { 7 | "serve": "vue-cli-service serve" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+ssh://git@github.com/qinxm/vue-json-diff.git" 12 | }, 13 | "keywords": [ 14 | "json", 15 | "diff", 16 | "vue", 17 | "fehelper" 18 | ], 19 | "author": "qinxm", 20 | "license": "ISC", 21 | "bugs": { 22 | "url": "https://github.com/qinxm/vue-json-diff/issues" 23 | }, 24 | "homepage": "https://github.com/qinxm/vue-json-diff#readme", 25 | "dependencies": { 26 | "vue": "^2.6.12" 27 | }, 28 | "devDependencies": { 29 | "@vue/cli-plugin-babel": "~4.5.0", 30 | "@vue/cli-plugin-pwa": "~4.5.0", 31 | "@vue/cli-plugin-router": "~4.5.0", 32 | "@vue/cli-plugin-vuex": "~4.5.0", 33 | "@vue/cli-service": "~4.5.0", 34 | "vue-template-compiler": "^2.6.11" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/components/jsonDiff/static/vendor/codemirror/placeholder.js: -------------------------------------------------------------------------------- 1 | 2 | import CodeMirror from './codemirror.js'; 3 | (function(a){a(CodeMirror)})(function(a){function b(a){a.state.placeholder&&(a.state.placeholder.parentNode.removeChild(a.state.placeholder),a.state.placeholder=null)}function c(a){b(a);var c=a.state.placeholder=document.createElement("pre");c.style.cssText="height: 0; overflow: visible",c.style.direction=a.getOption("direction"),c.className="CodeMirror-placeholder";var d=a.getOption("placeholder");"string"==typeof d&&(d=document.createTextNode(d)),c.appendChild(d),a.display.lineSpace.insertBefore(c,a.display.lineSpace.firstChild)}function d(a){f(a)&&c(a)}function e(a){var d=a.getWrapperElement(),e=f(a);d.className=d.className.replace(" CodeMirror-empty","")+(e?" CodeMirror-empty":""),e?c(a):b(a)}function f(a){return 1===a.lineCount()&&""===a.getLine(0)}a.defineOption("placeholder","",function(c,f,g){var h=g&&g!=a.Init;if(f&&!h)c.on("blur",d),c.on("change",e),c.on("swapDoc",e),e(c);else if(!f&&h){c.off("blur",d),c.off("change",e),c.off("swapDoc",e),b(c);var i=c.getWrapperElement();i.className=i.className.replace(" CodeMirror-empty","")}f&&!c.hasFocus()&&d(c)})}); -------------------------------------------------------------------------------- /src/components/jsonDiff/static/vendor/codemirror/active-line.js: -------------------------------------------------------------------------------- 1 | 2 | import CodeMirror from './codemirror.js'; 3 | (function(a){a(CodeMirror)})(function(a){"use strict";function b(a){for(var b=0;b 2 |
3 | 4 |
5 | 6 | 7 | 69 | -------------------------------------------------------------------------------- /src/components/jsonDiff/static/vendor/codemirror/matchbrackets.js: -------------------------------------------------------------------------------- 1 | import CodeMirror from './codemirror.js'; 2 | (function(a){a(CodeMirror)})(function(a){function b(a,b,d){var e=a.getLineHandle(b.line),f=b.ch-1,i=d&&d.afterCursor;null==i&&(i=/(^| )cm-fat-cursor($| )/.test(a.getWrapperElement().className));var j=!i&&0<=f&&h[e.text.charAt(f)]||h[e.text.charAt(++f)];if(!j)return null;var k=">"==j.charAt(1)?1:-1;if(d&&d.strict&&0i))for(n==b.line&&(o=b.ch-(0>c?1:0));o!=p;o+=c){var q=f.charAt(o);if(l.test(q)&&(void 0===d||a.getTokenTypeAt(g(n,o+1))==d)){var r=h[q];if(">"==r.charAt(1)==0document.documentMode),g=a.Pos,h={"(":")>",")":"(<","[":"]>","]":"[<","{":"}>","}":"{<"};a.defineOption("matchBrackets",!1,function(b,c,d){d&&d!=a.Init&&(b.off("cursorActivity",e),b.state.matchBrackets&&b.state.matchBrackets.currentlyHighlighted&&(b.state.matchBrackets.currentlyHighlighted(),b.state.matchBrackets.currentlyHighlighted=null)),c&&(b.state.matchBrackets="object"==typeof c?c:{},b.on("cursorActivity",e))}),a.defineExtension("matchBrackets",function(){d(this,!0)}),a.defineExtension("findMatchingBracket",function(a,c,d){return(d||"boolean"==typeof c)&&(d?(d.strict=c,c=d):c=c?{strict:!0}:null),b(this,a,c)}),a.defineExtension("scanForBracket",function(a,b,d,e){return c(this,a,b,d,e)})}); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-json-diff 2 | 3 | 基于Fehelper里的jsondiff功能封装的vue组件。 4 | 5 | 推荐浏览器插件:FeHelper--Web前端助手(https://github.com/zxlie/FeHelper) 6 | 7 | 实在太香,忍不住安利! 8 | 9 | ## Links 10 | - Github(https://github.com/qinxm/vue-json-diff) 11 | 12 | ## Usage 13 | 14 | 安装vue-json-diff包,依赖vue 15 | 16 | ``` 17 | npm install vue-json-diff 18 | or 19 | yarn add vue-json-diff 20 | ``` 21 | 22 | vue调用 23 | ``` 24 | 29 | 30 | 92 | ``` 93 | 94 | ## props 95 | 96 | 97 | 属性 | 类型 | 描述 98 | ---|---|--- 99 | jsonSourceLeft | Object/String | 左侧区域展示数据 100 | jsonSourceRight | Object/String | 右侧区域展示数据 101 | showHeading | Boolean | 是否显示顶部对比结果 102 | errorHandler | Function | 错误处理回调方法 103 | diffHandler | Function | 对比结果回调方法 104 | 105 | ## PS ❤️ 106 | 如果喜欢请给个星星,谢谢。 If you like, please give me a star, thank you. 107 | 108 | 如果需要帮助: QQ:1034688013 邮箱: 1034688013@qq.com if you need help: QQ:1034688013 email: 1034688013@qq.com 109 | 110 | 111 | -------------------------------------------------------------------------------- /src/components/jsonDiff/static/vendor/json-diff/backbone-events.min.js: -------------------------------------------------------------------------------- 1 | /*! backbone-events-standalone 0.2.6 2015-05-18 */ 2 | !function(){ 3 | function a(){ 4 | return{keys:Object.keys||function(a){if("object"!=typeof a&&"function"!=typeof a||null===a)throw new TypeError("keys() called on a non-object");var b,c=[];for(b in a)a.hasOwnProperty(b)&&(c[c.length]=b);return c},uniqueId:function(a){var b=++g+"";return a?a+b:b},has:function(a,b){return e.call(a,b)},each:function(a,b,c){if(null!=a)if(d&&a.forEach===d)a.forEach(b,c);else if(a.length===+a.length)for(var e=0,f=a.length;f>e;e++)b.call(c,a[e],e,a);else for(var g in a)this.has(a,g)&&b.call(c,a[g],g,a)},once:function(a){var b,c=!1;return function(){return c?b:(c=!0,b=a.apply(this,arguments),a=null,b)}}}}var b,c=this,d=Array.prototype.forEach,e=Object.prototype.hasOwnProperty,f=Array.prototype.slice,g=0,h=a();b={on:function(a,b,c){if(!j(this,"on",a,[b,c])||!b)return this;this._events||(this._events={});var d=this._events[a]||(this._events[a]=[]);return d.push({callback:b,context:c,ctx:c||this}),this},once:function(a,b,c){if(!j(this,"once",a,[b,c])||!b)return this;var d=this,e=h.once(function(){d.off(a,e),b.apply(this,arguments)});return e._callback=b,this.on(a,e,c)},off:function(a,b,c){var d,e,f,g,i,k,l,m;if(!this._events||!j(this,"off",a,[b,c]))return this;if(!a&&!b&&!c)return this._events={},this;for(g=a?[a]:h.keys(this._events),i=0,k=g.length;k>i;i++)if(a=g[i],f=this._events[a]){if(this._events[a]=d=[],b||c)for(l=0,m=f.length;m>l;l++)e=f[l],(b&&b!==e.callback&&b!==e.callback._callback||c&&c!==e.context)&&d.push(e);d.length||delete this._events[a]}return this},trigger:function(a){if(!this._events)return this;var b=f.call(arguments,1);if(!j(this,"trigger",a,b))return this;var c=this._events[a],d=this._events.all;return c&&k(c,b),d&&k(d,arguments),this},stopListening:function(a,b,c){var d=this._listeners;if(!d)return this;var e=!b&&!c;"object"==typeof b&&(c=this),a&&((d={})[a._listenerId]=a);for(var f in d)d[f].off(b,c,this),e&&delete this._listeners[f];return this}};var i=/\s+/,j=function(a,b,c,d){if(!c)return!0;if("object"==typeof c){for(var e in c)a[b].apply(a,[e,c[e]].concat(d));return!1}if(i.test(c)){for(var f=c.split(i),g=0,h=f.length;h>g;g++)a[b].apply(a,[f[g]].concat(d));return!1}return!0},k=function(a,b){var c,d=-1,e=a.length,f=b[0],g=b[1],h=b[2];switch(b.length){case 0:for(;++d", 29 | newlineAfterToken: function(type, content, textAfter) { 30 | return type == "tag" && />$/.test(content) || /^ -1 && endIndex > -1 && endIndex > startIndex) { 48 | // Take string till comment start 49 | selText = selText.substr(0, startIndex) 50 | // From comment start till comment end 51 | + selText.substring(startIndex + curMode.commentStart.length, endIndex) 52 | // From comment end till string end 53 | + selText.substr(endIndex + curMode.commentEnd.length); 54 | } 55 | cm.replaceRange(selText, from, to); 56 | } 57 | }); 58 | }); 59 | 60 | // Applies automatic mode-aware indentation to the specified range 61 | CodeMirror.defineExtension("autoIndentRange", function (from, to) { 62 | var cmInstance = this; 63 | this.operation(function () { 64 | for (var i = from.line; i <= to.line; i++) { 65 | cmInstance.indentLine(i, "smart"); 66 | } 67 | }); 68 | }); 69 | 70 | // Applies automatic formatting to the specified range 71 | CodeMirror.defineExtension("autoFormatRange", function (from, to) { 72 | var cm = this; 73 | var outer = cm.getMode(), text = cm.getRange(from, to).split("\n"); 74 | var state = CodeMirror.copyState(outer, cm.getTokenAt(from).state); 75 | var tabSize = cm.getOption("tabSize"); 76 | 77 | var out = "", lines = 0, atSol = from.ch == 0; 78 | function newline() { 79 | out += "\n"; 80 | atSol = true; 81 | ++lines; 82 | } 83 | 84 | for (var i = 0; i < text.length; ++i) { 85 | var stream = new CodeMirror.StringStream(text[i], tabSize); 86 | while (!stream.eol()) { 87 | var inner = CodeMirror.innerMode(outer, state); 88 | var style = outer.token(stream, state), cur = stream.current(); 89 | stream.start = stream.pos; 90 | if (!atSol || /\S/.test(cur)) { 91 | out += cur; 92 | atSol = false; 93 | } 94 | if (!atSol && inner.mode.newlineAfterToken && 95 | inner.mode.newlineAfterToken(style, cur, stream.string.slice(stream.pos) || text[i+1] || "", inner.state)) 96 | newline(); 97 | } 98 | if (!stream.pos && outer.blankLine) outer.blankLine(state); 99 | if (!atSol) newline(); 100 | } 101 | 102 | cm.operation(function () { 103 | cm.replaceRange(out, from, to); 104 | for (var cur = from.line + 1, end = from.line + lines; cur <= end; ++cur) 105 | cm.indentLine(cur, "smart"); 106 | cm.setSelection(from, cm.getCursor(false)); 107 | }); 108 | }); 109 | 110 | export default CodeMirror -------------------------------------------------------------------------------- /src/components/jsonDiff/index.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 112 | 113 | 114 | 181 | -------------------------------------------------------------------------------- /src/components/jsonDiff/static/vendor/json-diff/json-diff.js: -------------------------------------------------------------------------------- 1 | // http://json-diff.com/ 2 | 3 | let JsonDiff = (function () { 4 | 5 | function JsonInputView(el, initialText) { 6 | this.el = el; 7 | let codemirror = this.codemirror = CodeMirror.fromTextArea(this.el, { 8 | lineNumbers: true, 9 | mode: { 10 | name: "javascript", 11 | json: true 12 | }, 13 | matchBrackets: true, 14 | theme: 'tomorrow-night' 15 | }); 16 | if (initialText) { 17 | codemirror.setValue(initialText); 18 | } 19 | let self = this; 20 | 21 | codemirror.on('inputRead', function (cm, e) { 22 | debugger 23 | if (e.origin === 'paste') { 24 | autoFormat(); 25 | } 26 | triggerChange(); 27 | }); 28 | codemirror.on('keyup', triggerChange); 29 | codemirror.on('change', triggerChange); 30 | codemirror.on('clear', function () { 31 | console.log(arguments); 32 | }); 33 | 34 | let oldValue = ''; 35 | 36 | function triggerChange() { 37 | debugger 38 | let text = codemirror.getValue(); 39 | console.log(text) 40 | // if (text !== oldValue) { 41 | // self.trigger('change'); 42 | // } 43 | // oldValue = text; 44 | } 45 | 46 | function autoFormat() { 47 | debugger 48 | let totalLines = codemirror.lineCount(); 49 | codemirror.autoFormatRange({ 50 | line: 0, 51 | ch: 0 52 | }, { 53 | line: totalLines 54 | }); 55 | codemirror.setSelection({ 56 | line: 0, 57 | ch: 0 58 | }); 59 | } 60 | } 61 | 62 | JsonInputView.prototype.getText = function () { 63 | return this.codemirror.getValue(); 64 | }; 65 | 66 | JsonInputView.prototype.setText = function (text) { 67 | return this.codemirror.setValue(text); 68 | }; 69 | 70 | JsonInputView.prototype.highlightRemoval = function (diff) { 71 | this._highlight(diff, '#DD4444'); 72 | }; 73 | 74 | JsonInputView.prototype.highlightAddition = function (diff) { 75 | this._highlight(diff, '#4ba2ff'); 76 | }; 77 | 78 | JsonInputView.prototype.highlightChange = function (diff) { 79 | this._highlight(diff, '#E5E833'); 80 | }; 81 | 82 | JsonInputView.prototype._highlight = function (diff, color) { 83 | let pos = getStartAndEndPosOfDiff(this.getText(), diff); 84 | this.codemirror.markText(pos.start, pos.end, { 85 | css: 'background-color: ' + color 86 | }); 87 | }; 88 | 89 | JsonInputView.prototype.clearMarkers = function () { 90 | this.codemirror.getAllMarks().forEach(function (marker) { 91 | marker.clear(); 92 | }); 93 | }; 94 | 95 | function getStartAndEndPosOfDiff(textValue, diff) { 96 | let result = parse(textValue); 97 | let pointers = result.pointers; 98 | let path = diff.path; 99 | let start = { 100 | line: pointers[path].key ? pointers[path].key.line : pointers[path].value.line, 101 | ch: pointers[path].key ? pointers[path].key.column : pointers[path].value.column 102 | }; 103 | let end = { 104 | line: pointers[path].valueEnd.line, 105 | ch: pointers[path].valueEnd.column 106 | }; 107 | 108 | return { 109 | start: start, 110 | end: end 111 | } 112 | } 113 | 114 | function onInputChange() { 115 | // debugger 116 | compareJson(); 117 | } 118 | 119 | let leftInputView = null; 120 | let rightInputView = null; 121 | let errHandler = null; 122 | let diffHandler = null; 123 | 124 | function compareJson() { 125 | leftInputView.clearMarkers(); 126 | rightInputView.clearMarkers(); 127 | let leftText = leftInputView.getText(), 128 | rightText = rightInputView.getText(); 129 | let leftJson, rightJson; 130 | try { 131 | if (leftText) { 132 | leftJson = JSON.parse(leftText); 133 | } 134 | errHandler && errHandler('left', true); 135 | } catch (e) { 136 | console.log('left ==>', e); 137 | } 138 | try { 139 | if (rightText) { 140 | rightJson = JSON.parse(rightText); 141 | } 142 | errHandler && errHandler('right', true); 143 | } catch (e) { 144 | console.log('right ==>', e); 145 | } 146 | 147 | if (!leftJson || !rightJson) { 148 | if (!leftJson && !rightJson) { 149 | errHandler && errHandler('left-right', false); 150 | } else if (!leftJson) { 151 | errHandler && errHandler('left', false); 152 | 153 | } else { 154 | errHandler && errHandler('right', false); 155 | } 156 | 157 | return; 158 | } 159 | let diffs = jsonpatch.compare(leftJson, rightJson); 160 | diffHandler && diffHandler(diffs); 161 | 162 | diffs.forEach(function (diff) { 163 | try { 164 | if (diff.op === 'remove') { 165 | leftInputView.highlightRemoval(diff); 166 | } else if (diff.op === 'add') { 167 | rightInputView.highlightAddition(diff); 168 | } else if (diff.op === 'replace') { 169 | rightInputView.highlightChange(diff); 170 | leftInputView.highlightChange(diff); 171 | } 172 | } catch (e) { 173 | console.warn('error while trying to highlight diff', e); 174 | } 175 | }); 176 | } 177 | 178 | 179 | function init(left, right, errorHandler, dfHandler) { 180 | 181 | errHandler = errorHandler; 182 | diffHandler = dfHandler; 183 | 184 | BackboneEvents.mixin(JsonInputView.prototype); 185 | 186 | leftInputView = new JsonInputView(left, ''); 187 | rightInputView = new JsonInputView(right, ''); 188 | leftInputView.on('change', onInputChange); 189 | rightInputView.on('change', onInputChange); 190 | leftInputView.codemirror.on('scroll', function () { 191 | let scrollInfo = leftInputView.codemirror.getScrollInfo(); 192 | rightInputView.codemirror.scrollTo(scrollInfo.left, scrollInfo.top); 193 | }); 194 | rightInputView.codemirror.on('scroll', function () { 195 | let scrollInfo = rightInputView.codemirror.getScrollInfo(); 196 | leftInputView.codemirror.scrollTo(scrollInfo.left, scrollInfo.top); 197 | }); 198 | } 199 | 200 | return { 201 | init: init, 202 | compareJson: compareJson 203 | } 204 | })(); 205 | -------------------------------------------------------------------------------- /src/components/jsonDiff/static/index.js: -------------------------------------------------------------------------------- 1 | // http://json-diff.com/ 2 | 3 | // import CodeMirror from 'codemirror'; 4 | // import BackboneEvents from 'backbone-events-standalone'; 5 | import CodeMirror from './vendor/codemirror/codemirror.js'; 6 | import BackboneEvents from './vendor/json-diff/backbone-events.min.js'; 7 | 8 | import './vendor/codemirror/javascript.js'; 9 | import './vendor/codemirror/active-line.js'; 10 | import './vendor/codemirror/matchbrackets.js'; 11 | import './vendor/codemirror/formatting.js'; 12 | import './vendor/codemirror/placeholder.js'; 13 | import jsonpatch from './vendor/json-diff/json-patch-duplex.min.js'; 14 | import { parse } from './vendor/json-diff/json-source-map.js' 15 | 16 | 17 | export const JsonDiff = (function () { 18 | function JsonInputView(el, initialText) { 19 | this.el = el; 20 | let codemirror = this.codemirror = CodeMirror.fromTextArea(this.el, { 21 | lineNumbers: true, 22 | mode: { 23 | name: "javascript", 24 | json: true 25 | }, 26 | matchBrackets: true, 27 | theme: 'tomorrow-night' 28 | }); 29 | if (initialText) { 30 | codemirror.setValue(initialText); 31 | } 32 | let self = this; 33 | 34 | codemirror.on('inputRead', function (cm, e) { 35 | if (e.origin === 'paste') { 36 | autoFormat(); 37 | } 38 | triggerChange(); 39 | }); 40 | codemirror.on('keyup', triggerChange); 41 | codemirror.on('change', triggerChange); 42 | codemirror.on('clear', function () { 43 | console.log(arguments); 44 | }); 45 | 46 | let oldValue = ''; 47 | 48 | function triggerChange() { 49 | let text = codemirror.getValue(); 50 | if (text !== oldValue) { 51 | self.trigger('change'); 52 | } 53 | oldValue = text; 54 | 55 | } 56 | 57 | function autoFormat() { 58 | // console.log('autoFormat begin') 59 | let totalLines = codemirror.lineCount(); 60 | codemirror.autoFormatRange({ 61 | line: 0, 62 | ch: 0 63 | }, { 64 | line: totalLines 65 | }); 66 | codemirror.setSelection({ 67 | line: 0, 68 | ch: 0 69 | }); 70 | // console.log('autoFormat end') 71 | } 72 | } 73 | 74 | JsonInputView.prototype.getText = function () { 75 | return this.codemirror.getValue(); 76 | }; 77 | 78 | JsonInputView.prototype.setText = function (text) { 79 | return this.codemirror.setValue(text); 80 | }; 81 | 82 | JsonInputView.prototype.highlightRemoval = function (diff) { 83 | this._highlight(diff, '#DD4444'); 84 | }; 85 | 86 | JsonInputView.prototype.highlightAddition = function (diff) { 87 | this._highlight(diff, '#4ba2ff'); 88 | }; 89 | 90 | JsonInputView.prototype.highlightChange = function (diff) { 91 | this._highlight(diff, '#E5E833'); 92 | }; 93 | 94 | JsonInputView.prototype._highlight = function (diff, color) { 95 | let pos = getStartAndEndPosOfDiff(this.getText(), diff); 96 | this.codemirror.markText(pos.start, pos.end, { 97 | css: 'background-color: ' + color 98 | }); 99 | }; 100 | 101 | JsonInputView.prototype.clearMarkers = function () { 102 | this.codemirror.getAllMarks().forEach(function (marker) { 103 | marker.clear(); 104 | }); 105 | }; 106 | 107 | function getStartAndEndPosOfDiff(textValue, diff) { 108 | let result = parse(textValue); 109 | let pointers = result.pointers; 110 | let path = diff.path; 111 | let start = { 112 | line: pointers[path].key ? pointers[path].key.line : pointers[path].value.line, 113 | ch: pointers[path].key ? pointers[path].key.column : pointers[path].value.column 114 | }; 115 | let end = { 116 | line: pointers[path].valueEnd.line, 117 | ch: pointers[path].valueEnd.column 118 | }; 119 | 120 | return { 121 | start: start, 122 | end: end 123 | } 124 | } 125 | 126 | function onInputChange() { 127 | 128 | compareJson(); 129 | } 130 | 131 | let leftInputView = null; 132 | let rightInputView = null; 133 | let errHandler = null; 134 | let diffHandler = null; 135 | 136 | function compareJson() { 137 | leftInputView.clearMarkers(); 138 | rightInputView.clearMarkers(); 139 | let leftText = leftInputView.getText(), 140 | rightText = rightInputView.getText(); 141 | let leftJson, rightJson; 142 | try { 143 | if (leftText) { 144 | leftJson = JSON.parse(leftText); 145 | } 146 | errHandler && errHandler('left', true); 147 | } catch (e) { 148 | console.log('left ==>', e); 149 | } 150 | try { 151 | if (rightText) { 152 | rightJson = JSON.parse(rightText); 153 | } 154 | errHandler && errHandler('right', true); 155 | } catch (e) { 156 | console.log('right ==>', e); 157 | } 158 | 159 | if (!leftJson || !rightJson) { 160 | if (!leftJson && !rightJson) { 161 | errHandler && errHandler('left-right', false); 162 | } else if (!leftJson) { 163 | errHandler && errHandler('left', false); 164 | 165 | } else { 166 | errHandler && errHandler('right', false); 167 | } 168 | 169 | return; 170 | } 171 | let diffs = jsonpatch.compare(leftJson, rightJson); 172 | diffHandler && diffHandler(diffs); 173 | 174 | diffs.forEach(function (diff) { 175 | try { 176 | if (diff.op === 'remove') { 177 | leftInputView.highlightRemoval(diff); 178 | } else if (diff.op === 'add') { 179 | rightInputView.highlightAddition(diff); 180 | } else if (diff.op === 'replace') { 181 | rightInputView.highlightChange(diff); 182 | leftInputView.highlightChange(diff); 183 | } 184 | } catch (e) { 185 | console.warn('error while trying to highlight diff', e); 186 | } 187 | }); 188 | } 189 | 190 | 191 | function init(left, right, errorHandler, dfHandler) { 192 | 193 | errHandler = errorHandler; 194 | diffHandler = dfHandler; 195 | 196 | BackboneEvents.mixin(JsonInputView.prototype); 197 | 198 | leftInputView = new JsonInputView(left, ''); 199 | rightInputView = new JsonInputView(right, ''); 200 | leftInputView.on('change', onInputChange); 201 | rightInputView.on('change', onInputChange); 202 | leftInputView.codemirror.on('scroll', function () { 203 | let scrollInfo = leftInputView.codemirror.getScrollInfo(); 204 | rightInputView.codemirror.scrollTo(scrollInfo.left, scrollInfo.top); 205 | }); 206 | rightInputView.codemirror.on('scroll', function () { 207 | let scrollInfo = rightInputView.codemirror.getScrollInfo(); 208 | leftInputView.codemirror.scrollTo(scrollInfo.left, scrollInfo.top); 209 | }); 210 | } 211 | 212 | return { 213 | init: init, 214 | compareJson: compareJson 215 | } 216 | })(); -------------------------------------------------------------------------------- /src/components/jsonDiff/static/vendor/json-diff/json-patch-duplex.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * https://github.com/Starcounter-Jack/JSON-Patch 3 | * json-patch-duplex.js version: 0.5.6 4 | * (c) 2013 Joachim Wester 5 | * MIT license 6 | */ 7 | var __extends=this&&this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);a.prototype=null===b?Object.create(b):(c.prototype=b.prototype,new c)},OriginalError=Error,jsonpatch;!function(a){function b(a,c){switch(typeof a){case"undefined":case"boolean":case"string":case"number":return a===c;case"object":if(null===a)return null===c;if(y(a)){if(!y(c)||a.length!==c.length)return!1;for(var d=0,e=a.length;e>d;d++)if(!b(a[d],c[d]))return!1;return!0}var f=r(c),g=f.length;if(r(a).length!==g)return!1;for(var d=0;g>d;d++)if(!b(a[d],c[d]))return!1;return!0;default:return!1}}function c(a){return-1===a.indexOf("/")&&-1===a.indexOf("~")?a:a.replace(/~/g,"~0").replace(/\//g,"~1")}function d(a){for(var b=0,c=v.length;c>b;b++)if(v[b].obj===a)return v[b]}function e(a,b){for(var c=0,d=a.observers.length;d>c;c++)if(a.observers[c].callback===b)return a.observers[c].observer}function f(a,b){for(var c=0,d=a.observers.length;d>c;c++)if(a.observers[c].observer===b)return void a.observers.splice(c,1)}function g(a,b){j(b),clearTimeout(b.next);var c=d(a);f(c,b)}function h(a){return"object"==typeof a?JSON.parse(JSON.stringify(a)):a}function i(a,b){var c,f=[],g=d(a);if(g?c=e(g,b):(g=new w(a),v.push(g)),c)return c;if(c={},g.value=h(a),b){c.callback=b,c.next=null;var i=this.intervals||[100,1e3,1e4,6e4];if(void 0===i.push)throw new OriginalError("jsonpatch.intervals must be an array");var k=0,l=function(){j(c)},m=function(){clearTimeout(c.next),c.next=setTimeout(function(){l(),k=0,c.next=setTimeout(n,i[k++])},0)},n=function(){l(),k==i.length&&(k=i.length-1),c.next=setTimeout(n,i[k++])};"undefined"!=typeof window&&(window.addEventListener?(window.addEventListener("mousedown",m),window.addEventListener("mouseup",m),window.addEventListener("keydown",m)):(document.documentElement.attachEvent("onmousedown",m),document.documentElement.attachEvent("onmouseup",m),document.documentElement.attachEvent("onkeydown",m))),c.next=setTimeout(n,i[k++])}return c.patches=f,c.object=a,g.observers.push(new x(b,c)),c}function j(a){for(var b,c=0,d=v.length;d>c;c++)if(v[c].obj===a.object){b=v[c];break}k(b.value,a.object,a.patches,""),a.patches.length&&m(b.value,a.patches);var e=a.patches;return e.length>0&&(a.patches=[],a.callback&&a.callback(e)),e}function k(a,b,d,e){for(var f=r(b),g=r(a),i=!1,j=!1,l=g.length-1;l>=0;l--){var m=g[l],n=a[m];if(b.hasOwnProperty(m)){var o=b[m];"object"==typeof n&&null!=n&&"object"==typeof o&&null!=o?k(n,o,d,e+"/"+c(m)):n!=o&&(i=!0,d.push({op:"replace",path:e+"/"+c(m),value:h(o)}))}else d.push({op:"remove",path:e+"/"+c(m)}),j=!0}if(j||f.length!=g.length)for(var l=0;lc;){b=a.charCodeAt(c);{if(!(b>=48&&57>=b))return!1;c++}}return!0}function m(a,b,c){for(var d,e,f=!1,g=0,h=b.length;h>g;){d=b[g],g++;for(var i=d.path||"",j=i.split("/"),k=a,m=1,n=j.length,o=void 0;;){if(e=j[m],c&&void 0===o&&(void 0===k[e]?o=j.slice(0,m).join("/"):m==n-1&&(o=d.path),void 0!==o&&this.validator(d,g-1,a,o)),m++,void 0===e&&m>=n){f=u[d.op].call(d,k,e,a);break}if(y(k)){if("-"===e)e=k.length;else{if(c&&!l(e))throw new z("Expected an unsigned base-10 integer value, making the new referenced value the array element with the zero-based index","OPERATION_PATH_ILLEGAL_ARRAY_INDEX",g-1,d.path,d);e=parseInt(e,10)}if(m>=n){if(c&&"add"===d.op&&e>k.length)throw new z("The specified index MUST NOT be greater than the number of elements in the array","OPERATION_VALUE_OUT_OF_BOUNDS",g-1,d.path,d);f=t[d.op].call(d,k,e,a);break}}else if(e&&-1!=e.indexOf("~")&&(e=e.replace(/~1/g,"/").replace(/~0/g,"~")),m>=n){f=s[d.op].call(d,k,e,a);break}k=k[e]}}return f}function n(a,b){var c=[];return k(a,b,c,""),c}function o(a){if(void 0===a)return!0;if("array"==typeof a||"object"==typeof a)for(var b in a)if(o(a[b]))return!0;return!1}function p(b,c,d,e){if("object"!=typeof b||null===b||y(b))throw new z("Operation is not an object","OPERATION_NOT_AN_OBJECT",c,b,d);if(!s[b.op])throw new z("Operation `op` property is not one of operations defined in RFC-6902","OPERATION_OP_INVALID",c,b,d);if("string"!=typeof b.path)throw new z("Operation `path` property is not a string","OPERATION_PATH_INVALID",c,b,d);if(("move"===b.op||"copy"===b.op)&&"string"!=typeof b.from)throw new z("Operation `from` property is not present (applicable in `move` and `copy` operations)","OPERATION_FROM_REQUIRED",c,b,d);if(("add"===b.op||"replace"===b.op||"test"===b.op)&&void 0===b.value)throw new z("Operation `value` property is not present (applicable in `add`, `replace` and `test` operations)","OPERATION_VALUE_REQUIRED",c,b,d);if(("add"===b.op||"replace"===b.op||"test"===b.op)&&o(b.value))throw new z("Operation `value` property is not present (applicable in `add`, `replace` and `test` operations)","OPERATION_VALUE_CANNOT_CONTAIN_UNDEFINED",c,b,d);if(d)if("add"==b.op){var f=b.path.split("/").length,g=e.split("/").length;if(f!==g+1&&f!==g)throw new z("Cannot perform an `add` operation at the desired path","OPERATION_PATH_CANNOT_ADD",c,b,d)}else if("replace"===b.op||"remove"===b.op||"_get"===b.op){if(b.path!==e)throw new z("Cannot perform the operation at a path that does not exist","OPERATION_PATH_UNRESOLVABLE",c,b,d)}else if("move"===b.op||"copy"===b.op){var h={op:"_get",path:b.from,value:void 0},i=a.validate([h],d);if(i&&"OPERATION_PATH_UNRESOLVABLE"===i.name)throw new z("Cannot perform the operation from a path that does not exist","OPERATION_FROM_UNRESOLVABLE",c,b,d)}}function q(a,b){try{if(!y(a))throw new z("Patch sequence must be an array","SEQUENCE_NOT_AN_ARRAY");if(b)b=JSON.parse(JSON.stringify(b)),m.call(this,b,a,!0);else for(var c=0;c