UNPKG

jsondiffpatch

Version:
637 lines (594 loc) 20.1 kB
(function demo() { var getExampleJson = function() { var data = { name: 'South America', summary: 'South America (Spanish: América del Sur, Sudamérica or \n' + 'Suramérica; Portuguese: América do Sul; Quechua and Aymara: \n' + 'Urin Awya Yala; Guarani: Ñembyamérika; Dutch: Zuid-Amerika; \n' + 'French: Amérique du Sud) is a continent situated in the \n' + 'Western Hemisphere, mostly in the Southern Hemisphere, with \n' + 'a relatively small portion in the Northern Hemisphere. \n' + 'The continent is also considered a subcontinent of the \n' + 'Americas.[2][3] It is bordered on the west by the Pacific \n' + 'Ocean and on the north and east by the Atlantic Ocean; \n' + 'North America and the Caribbean Sea lie to the northwest. \n' + 'It includes twelve countries: Argentina, Bolivia, Brazil, \n' + 'Chile, Colombia, Ecuador, Guyana, Paraguay, Peru, Suriname, \n' + 'Uruguay, and Venezuela. The South American nations that \n' + 'border the Caribbean Sea—including Colombia, Venezuela, \n' + 'Guyana, Suriname, as well as French Guiana, which is an \n' + 'overseas region of France—are also known as Caribbean South \n' + 'America. South America has an area of 17,840,000 square \n' + 'kilometers (6,890,000 sq mi). Its population as of 2005 \n' + 'has been estimated at more than 371,090,000. South America \n' + 'ranks fourth in area (after Asia, Africa, and North America) \n' + 'and fifth in population (after Asia, Africa, Europe, and \n' + 'North America). The word America was coined in 1507 by \n' + 'cartographers Martin Waldseemüller and Matthias Ringmann, \n' + 'after Amerigo Vespucci, who was the first European to \n' + 'suggest that the lands newly discovered by Europeans were \n' + 'not India, but a New World unknown to Europeans.', surface: 17840000, timezone: [-4, -2], demographics: { population: 385742554, largestCities: ['São Paulo', 'Buenos Aires', 'Rio de Janeiro', 'Lima', 'Bogotá'] }, languages: ['spanish', 'portuguese', 'english', 'dutch', 'french', 'quechua', 'guaraní', 'aimara', 'mapudungun' ], countries: [{ name: 'Argentina', capital: 'Buenos Aires', independence: new Date(1816, 6, 9), unasur: true }, { name: 'Bolivia', capital: 'La Paz', independence: new Date(1825, 7, 6), unasur: true }, { name: 'Brazil', capital: 'Brasilia', independence: new Date(1822, 8, 7), unasur: true }, { name: 'Chile', capital: 'Santiago', independence: new Date(1818, 1, 12), unasur: true }, { name: 'Colombia', capital: 'Bogotá', independence: new Date(1810, 6, 20), unasur: true }, { name: 'Ecuador', capital: 'Quito', independence: new Date(1809, 7, 10), unasur: true }, { name: 'Guyana', capital: 'Georgetown', independence: new Date(1966, 4, 26), unasur: true }, { name: 'Paraguay', capital: 'Asunción', independence: new Date(1811, 4, 14), unasur: true }, { name: 'Peru', capital: 'Lima', independence: new Date(1821, 6, 28), unasur: true }, { name: 'Suriname', capital: 'Paramaribo', independence: new Date(1975, 10, 25), unasur: true }, { name: 'Uruguay', capital: 'Montevideo', independence: new Date(1825, 7, 25), unasur: true }, { name: 'Venezuela', capital: 'Caracas', independence: new Date(1811, 6, 5), unasur: true }] }; var json = [JSON.stringify(data, null, 2)]; data.summary = data.summary.replace('Brazil', 'Brasil').replace('also known as', 'a.k.a.'); data.languages[2] = 'inglés'; data.countries.pop(); data.countries.pop(); data.countries[0].capital = 'Rawson'; data.countries.push({ name: 'Antártida', unasur: false }); // modify and move data.countries[4].population = 42888594; data.countries.splice(11, 0, data.countries.splice(4, 1)[0]); data.countries.splice(2, 0, data.countries.splice(7, 1)[0]); delete data.surface; data.spanishName = 'Sudamérica'; data.demographics.population += 2342; json.push(JSON.stringify(data, null, 2)); return json; }; /* global jsondiffpatch */ var instance = jsondiffpatch.create({ objectHash: function(obj, index) { if (typeof obj._id !== 'undefined') { return obj._id; } if (typeof obj.id !== 'undefined') { return obj.id; } if (typeof obj.name !== 'undefined') { return obj.name; } return '$$index:' + index; } }); var dom = { addClass: function(el, className) { if (el.classList) { el.classList.add(className); } else { el.className += ' ' + className; } }, removeClass: function(el, className) { if (el.classList) { el.classList.remove(className); } else { el.className = el.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' '); } }, text: function(el, text) { if (typeof el.textContent !== 'undefined') { if (typeof text === 'undefined') { return el.textContent; } el.textContent = text; } else { if (typeof text === 'undefined') { return el.innerText; } el.innerText = text; } }, on: function(el, eventName, handler) { if (el.addEventListener) { el.addEventListener(eventName, handler); } else { el.attachEvent('on' + eventName, handler); } }, ready: function(fn) { if (document.addEventListener) { document.addEventListener('DOMContentLoaded', fn); } else { document.attachEvent('onreadystatechange', function() { if (document.readyState === 'interactive') { fn(); } }); } }, getJson: function(url, callback) { var request = new XMLHttpRequest(); request.open('GET', url, true); request.onreadystatechange = function() { if (this.readyState === 4) { var data; try { data = JSON.parse(this.responseText, jsondiffpatch.dateReviver); } catch (parseError) { callback('parse error: ' + parseError); } if (this.status >= 200 && this.status < 400) { callback(null, data); } else { callback(new Error('request failed'), data); } } }; request.send(); request = null; }, runScriptTags: function(el) { var scripts = el.querySelectorAll('script'); for (var i = 0; i < scripts.length; i++) { var s = scripts[i]; /* jshint evil: true */ eval(s.innerHTML); } } }; var trim = function(str) { return str.replace(/^\s+|\s+$/g, ''); }; var JsonArea = function JsonArea(element) { this.element = element; this.container = element.parentNode; var self = this; var prettifyButton = this.container.querySelector('.prettyfy'); if (prettifyButton) { dom.on(prettifyButton, 'click', function() { self.prettyfy(); }); } }; JsonArea.prototype.error = function(err) { var errorElement = this.container.querySelector('.error-message'); if (!err) { dom.removeClass(this.container, 'json-error'); errorElement.innerHTML = ''; return; } errorElement.innerHTML = err + ''; dom.addClass(this.container, 'json-error'); }; JsonArea.prototype.getValue = function() { if (!this.editor) { return this.element.value; } return this.editor.getValue(); }; JsonArea.prototype.parse = function() { var txt = trim(this.getValue()); try { this.error(false); if (/^\d+(.\d+)?(e[\+\-]?\d+)?$/i.test(txt) || /^(true|false)$/.test(txt) || /^["].*["]$/.test(txt) || /^[\{\[](.|\n)*[\}\]]$/.test(txt)) { return JSON.parse(txt, jsondiffpatch.dateReviver); } return this.getValue(); } catch (err) { this.error(err); throw err; } }; JsonArea.prototype.setValue = function(value) { if (!this.editor) { this.element.value = value; return; } this.editor.setValue(value); }; JsonArea.prototype.prettyfy = function() { var value = this.parse(); var prettyJson = typeof value === 'string' ? value : JSON.stringify(value, null, 2); this.setValue(prettyJson); }; /* global CodeMirror */ JsonArea.prototype.makeEditor = function(readOnly) { if (typeof CodeMirror === 'undefined') { return; } this.editor = CodeMirror.fromTextArea(this.element, { mode: 'javascript', json: true, readOnly: readOnly }); if (!readOnly) { this.editor.on('change', compare); } }; var areas = { left: new JsonArea(document.getElementById('json-input-left')), right: new JsonArea(document.getElementById('json-input-right')), delta: new JsonArea(document.getElementById('json-delta')) }; var compare = function() { var left, right, error; document.getElementById('results').style.display = 'none'; try { left = areas.left.parse(); } catch (err) { error = err; } try { right = areas.right.parse(); } catch (err) { error = err; } areas.delta.error(false); if (error) { areas.delta.setValue(''); return; } var selectedType = getSelectedDeltaType(); var visualdiff = document.getElementById('visualdiff'); var annotateddiff = document.getElementById('annotateddiff'); var jsondifflength = document.getElementById('jsondifflength'); try { var delta = instance.diff(left, right); if (typeof delta === 'undefined') { switch (selectedType) { case 'visual': visualdiff.innerHTML = 'no diff'; break; case 'annotated': annotateddiff.innerHTML = 'no diff'; break; case 'json': areas.delta.setValue('no diff'); jsondifflength.innerHTML = '0'; break; } } else { switch (selectedType) { case 'visual': visualdiff.innerHTML = jsondiffpatch.formatters.html.format(delta, left); if (!document.getElementById('showunchanged').checked) { jsondiffpatch.formatters.html.hideUnchanged(); } dom.runScriptTags(visualdiff); break; case 'annotated': annotateddiff.innerHTML = jsondiffpatch.formatters.annotated.format(delta); break; case 'json': areas.delta.setValue(JSON.stringify(delta, null, 2)); jsondifflength.innerHTML = (Math.round(JSON.stringify(delta).length / 102.4) / 10.0) + ''; break; } } } catch (err) { jsondifflength.innerHTML = '0'; visualdiff.innerHTML = ''; annotateddiff.innerHTML = ''; areas.delta.setValue(''); areas.delta.error(err); if (typeof console !== 'undefined' && console.error) { console.error(err); console.error(err.stack); } } document.getElementById('results').style.display = ''; }; areas.left.makeEditor(); areas.right.makeEditor(); dom.on(areas.left.element, 'change', compare); dom.on(areas.right.element, 'change', compare); dom.on(areas.left.element, 'keyup', compare); dom.on(areas.right.element, 'keyup', compare); var getSelectedDeltaType = function() { if (document.getElementById('show-delta-type-visual').checked) { return 'visual'; } if (document.getElementById('show-delta-type-annotated').checked) { return 'annotated'; } if (document.getElementById('show-delta-type-json').checked) { return 'json'; } }; var showSelectedDeltaType = function() { var type = getSelectedDeltaType(); document.getElementById('delta-panel-visual').style.display = type === 'visual' ? '' : 'none'; document.getElementById('delta-panel-annotated').style.display = type === 'annotated' ? '' : 'none'; document.getElementById('delta-panel-json').style.display = type === 'json' ? '' : 'none'; compare(); }; dom.on(document.getElementById('show-delta-type-visual'), 'click', showSelectedDeltaType); dom.on(document.getElementById('show-delta-type-annotated'), 'click', showSelectedDeltaType); dom.on(document.getElementById('show-delta-type-json'), 'click', showSelectedDeltaType); dom.on(document.getElementById('swap'), 'click', function() { var leftValue = areas.left.getValue(); areas.left.setValue(areas.right.getValue()); areas.right.setValue(leftValue); compare(); }); dom.on(document.getElementById('clear'), 'click', function() { areas.left.setValue(''); areas.right.setValue(''); compare(); }); dom.on(document.getElementById('showunchanged'), 'change', function() { jsondiffpatch.formatters.html.showUnchanged(document.getElementById('showunchanged').checked, null, 800); }); dom.ready(function(){ setTimeout(compare); }, 1); var load = {}; load.data = function(data) { data = data || {}; dom.text(document.getElementById('description'), data.description || ''); if (data.url && trim(data.url).substr(0, 10) !== 'javascript') { document.getElementById('external-link').setAttribute('href', data.url); document.getElementById('external-link').style.display = ''; } else { document.getElementById('external-link').style.display = 'none'; } var leftValue = data.left ? (data.left.content || data.left) : ''; areas.left.setValue(leftValue); var rightValue = data.right ? (data.right.content || data.right) : ''; areas.right.setValue(rightValue); dom.text(document.getElementById('json-panel-left').querySelector('h2'), (data.left && data.left.name) || 'left.json'); dom.text(document.getElementById('json-panel-right').querySelector('h2'), (data.right && data.right.name) || 'right.json'); document.getElementById('json-panel-left').querySelector('h2').setAttribute( 'title', (data.left && data.left.fullname) || ''); document.getElementById('json-panel-right').querySelector('h2').setAttribute( 'title', (data.right && data.right.fullname) || ''); if (data.error) { areas.left.setValue('ERROR LOADING: ' + data.error); areas.right.setValue(''); } }; load.gist = function(id) { dom.getJson('https://api.github.com/gists/' + id, function(error, data) { if (error) { var message = error + ((data && data.message) ? data.message : ''); load.data({ error: message }); return; } var filenames = []; for (var filename in data.files) { var file = data.files[filename]; if (file.language === 'JSON') { filenames.push(filename); } } filenames.sort(); var files = [ data.files[filenames[0]], data.files[filenames[1]] ]; /*jshint camelcase: false */ load.data({ url: data.html_url, description: data.description, left: { name: files[0].filename, content: files[0].content }, right: { name: files[1].filename, content: files[1].content } }); }); }; load.leftright = function(description, leftValue, rightValue) { try { description = decodeURIComponent(description || ''); leftValue = decodeURIComponent(leftValue); rightValue = decodeURIComponent(rightValue); var urlmatch = /https?:\/\/.*\/([^\/]+\.json)(?:[\?#].*)?/; var dataLoaded = { description: description, left: {}, right: {} }; var loadIfReady = function() { if (typeof dataLoaded.left.content !== 'undefined' && typeof dataLoaded.right.content !== 'undefined') { load.data(dataLoaded); } }; if (urlmatch.test(leftValue)) { dataLoaded.left.name = urlmatch.exec(leftValue)[1]; dataLoaded.left.fullname = leftValue; dom.getJson(leftValue, function(error, data) { if (error) { dataLoaded.left.content = error + ((data && data.message) ? data.message : ''); } else { dataLoaded.left.content = JSON.stringify(data, null, 2); } loadIfReady(); }); } else { dataLoaded.left.content = leftValue; } if (urlmatch.test(rightValue)) { dataLoaded.right.name = urlmatch.exec(rightValue)[1]; dataLoaded.right.fullname = rightValue; dom.getJson(rightValue, function(error, data) { if (error) { dataLoaded.right.content = error + ((data && data.message) ? data.message : ''); } else { dataLoaded.right.content = JSON.stringify(data, null, 2); } loadIfReady(); }); } else { dataLoaded.right.content = rightValue; } loadIfReady(); } catch (err) { load({ error: err }); } }; load.key = function(key) { var matchers = { gist: /^(?:https?:\/\/)?(?:gist\.github\.com\/)?(?:[\w0-9\-a-f]+\/)?([0-9a-f]+)$/i, leftright: /^(?:desc=(.*)?&)?left=(.*)&right=(.*)&?$/i, }; for (var loader in matchers) { var match = matchers[loader].exec(key); if (match) { return load[loader].apply(load, match.slice(1)); } } load.data({ error: 'unsupported source: ' + key }); }; var urlQuery = /^[^?]*\?([^\#]+)/.exec(document.location.href); if (urlQuery) { load.key(urlQuery[1]); } else { var exampleJson = getExampleJson(); load.data({ left: exampleJson[0], right: exampleJson[1] }); } dom.on(document.getElementById('examples'), 'change', function() { var example = trim(this.value); switch (example) { case 'text': var exampleJson = getExampleJson(); load.data({ left: { name: 'left.txt', content: JSON.parse(exampleJson[0]).summary }, right: { name: 'right.txt', content: JSON.parse(exampleJson[1]).summary } }); break; case 'gist': document.location = '?benjamine/9188826'; break; case 'moving': document.location = '?desc=moving%20around&left=' + encodeURIComponent(JSON.stringify([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])) + '&right=' + encodeURIComponent(JSON.stringify([10, 0, 1, 7, 2, 4, 5, 6, 88, 9, 3])); break; case 'query': document.location = '?desc=encoded%20in%20url&left=' + /* jshint quotmark: false */ encodeURIComponent(JSON.stringify({ "don't": "abuse", "with": ["large", "urls"] })) + '&right=' + encodeURIComponent(JSON.stringify({ "don't": "use", "with": [">", 2, "KB urls"] })); break; case 'urls': document.location = '?desc=http%20raw%20file%20urls&left=' + encodeURIComponent('https://rawgithub.com/benjamine/JsonDiffPatch/' + 'c83e942971c627f61ef874df3cfdd50a95f1c5a2/package.json') + '&right=' + encodeURIComponent('https://rawgithub.com/benjamine/JsonDiffPatch/master/package.json'); break; default: document.location = '?'; break; } }); })();