diff --git a/bin/jsond b/bin/jsond new file mode 100644 index 0000000..6b8f4d3 --- /dev/null +++ b/bin/jsond @@ -0,0 +1,9 @@ +#!/usr/bin/env node + +var sys = require("sys"), + fs = require("fs"), + argv = require('optimist').argv, + colors = require("colors"), + jsond = require("../js/lib/jsond"); + +// To-Do: seperate rendering to provision for nodejs output using colors etc. \ No newline at end of file diff --git a/css/json-diff.css b/css/json-diff.css index 04dc054..3ef0bca 100644 --- a/css/json-diff.css +++ b/css/json-diff.css @@ -1,5 +1,12 @@ body { - background-color: lightblue; + color: #333; + + background: #eeeeee; /* old browsers */ + background: -moz-linear-gradient(top, #eeeeee 0%, #cccccc 100%); /* firefox */ + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#eeeeee), color-stop(100%,#cccccc)); /* webkit */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#eeeeee', endColorstr='#cccccc',GradientType=0 ); /* ie */ + + font-family:Arial, Helvetica, sans-serif; } #results li > span, #results ul > span { @@ -18,11 +25,11 @@ body { margin-left: -15px; padding-top: 0px; margin-top: 0px; - background: url(open.png) no-repeat 2px 5px; + background: url(../img/open.png) no-repeat 2px 5px; list-style-type: none; } #results ul[closed="yes"] { - background: url(closed.png) no-repeat 2px 5px; + background: url(../img/closed.png) no-repeat 2px 5px; } #results ul[closed="yes"] > * { display: none; @@ -53,15 +60,67 @@ textarea { } .contentbox { - border: 1px dashed black; - background-color: white; + + -moz-box-shadow: 2px 2px 3px #666; + -webkit-box-shadow: 2px 2px 3px #666; + box-shadow: 2px 2px 3px #666; + + + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + border-radius: 3px; + + background: #eeeeee; /* old browsers */ + background: -moz-linear-gradient(top, #eeeeee 0%, #cccccc 100%); /* firefox */ + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#eeeeee), color-stop(100%,#cccccc)); /* webkit */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#eeeeee', endColorstr='#cccccc',GradientType=0 ); /* ie */ + + border: 1px solid #666; + + color: #666; padding: 15px; margin: 10px; } -h2 { +input[type=button] { + cursor:pointer; + height:35px; + font-size: 14px; + padding:0 -8px; + + background: #7d7e7d; /* old browsers */ + background: -moz-linear-gradient(top, #7d7e7d 0%, #0e0e0e 100%); /* firefox */ + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#7d7e7d), color-stop(100%,#0e0e0e)); /* webkit */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#7d7e7d', endColorstr='#0e0e0e',GradientType=0 ); /* ie */ + + color: #eee; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + border-radius: 3px; + border:#666 1px solid; +} + +textarea { + border: 1px solid #666; + + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + border-radius: 3px; + + margin-top: 10px; + margin-bottom: 10px; + background: #EDEDED; /* old browsers */ + background: -moz-linear-gradient(top, #EDEDED 0%, #f6f6f6 47%, #FFFFFF 100%); /* firefox */ + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#EDEDED), color-stop(47%,#f6f6f6), color-stop(100%,#FFFFFF)); /* webkit */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#EDEDED', endColorstr='#FFFFFF',GradientType=0 ); /* ie */ +} + +h1 { text-align: center; - margin: 0px;; + margin: 0px; + font-size: 35px; + color: #666; + text-shadow: #515151 1px 1px 1px; } #results { diff --git a/img/bg.jpg b/img/bg.jpg new file mode 100644 index 0000000..260fa20 Binary files /dev/null and b/img/bg.jpg differ diff --git a/img/closed.png b/img/closed.png new file mode 100644 index 0000000..147c717 Binary files /dev/null and b/img/closed.png differ diff --git a/img/open.png b/img/open.png new file mode 100644 index 0000000..1d48c6a Binary files /dev/null and b/img/open.png differ diff --git a/index.html b/index.html index 5cf1f0a..aeb3686 100644 --- a/index.html +++ b/index.html @@ -4,14 +4,8 @@ - -

Courtesy of tlrobinson. -
- This version differs in that it supports null values,
- downplays the significance of changed properties with the key key,
- and provides links to jump from one change to the next.

- -

JSON Diff

+ +

json-diff

-
-

About

-

JSON Diff is a simple way to visualize and compare JSON.

-

Known Issues

- -
-
-
-

- © 2006-2010 Thomas Robinson. Some rights reserved.

- - - + + diff --git a/js/app.js b/js/app.js index e246325..541866a 100644 --- a/js/app.js +++ b/js/app.js @@ -55,30 +55,58 @@ if(!window.console){ Init: function() { - console.log('>>> Init()'); - - document.addEventListener("click", this.clickHandler, false); - - jsonBoxA = document.getElementById("jsonA"); - jsonBoxB = document.getElementById("jsonB"); - - jsonDiff.feedback = this.markChanged; + var self = this; - this.populteSamples(); - this.startCompare(); - } - - populteSamples: function() { + window.onload = function() { + + console.log('>>> Init()'); + + document.addEventListener("click", self.clickHandler, false); + + jsonBoxA = document.getElementById("jsonA"); + jsonBoxB = document.getElementById("jsonB"); + + function populateValues(a, b) { + jsonBoxA.value = JSON.stringify(a); + jsonBoxB.value = JSON.stringify(b); + } + + function populateResults(results) { + console.log(results) + } + + document.getElementById("swap").addEventListener("click", function() { + jsond.swap(populateValues); + }, false); + + document.getElementById("clear").addEventListener("click", function() { + jsond.clear(populateValues); + }, false); + + document.getElementById("compare").addEventListener("click", function() { + jsond.compare(JSON.parse(jsonBoxA.value), JSON.parse(jsonBoxB.value), "root", populateResults); + }, false); + + jsond.feedback = self.markChanged; + + self.assignSamples(); + self.startCompare(); + + }; + + }, + + assignSamples: function() { console.log('>>> populateSamples()'); - jsonBoxA.value = JSON.stringify(samples.a); - jsonBoxB.value = JSON.stringify(samples.b); + jsonBoxA.value = JSON.stringify(jsond.a = samples.a); + jsonBoxB.value = JSON.stringify(jsond.b = samples.b); }, startCompare: function () { - + console.log('>>> startCompare()'); var objA, objB; n = 0; @@ -101,7 +129,7 @@ if(!window.console){ while (results.firstChild) results.removeChild(results.firstChild); - jsonDiff.compareTree(objA, objB, "root", results); + jsond.compare(objA, objB, "root", results); }, markChanged: function(node) { @@ -113,7 +141,7 @@ if(!window.console){ n += 1; var nextNode = document.createElement('a'); nextNode.setAttribute('href', '#change-' + n); - nextNode.appendChild(document.createTextNode('↓ next change ↓')) + nextNode.appendChild(document.createTextNode('↓ next change ↓')); node.appendChild(nextNode); }, diff --git a/js/lib/jsond.js b/js/lib/jsond.js new file mode 100644 index 0000000..ff082d8 --- /dev/null +++ b/js/lib/jsond.js @@ -0,0 +1,130 @@ + +var jsond = (typeof exports !== "undefined" ? exports : window).jsond = (function(){ + + function isArray(value) { + return value && typeof value === "object" && value.constructor === Array; + } + + function typeofReal(value) { + return isArray(value) ? "array": value === null ? 'null' : typeof value; + } + + function getType(value) { + (typeA === "object" || typeA === "array") ? "": String(a) + " "; + } + + return { + + version: "0.0.1", + + a: [], // first structure + b: [], // second structure + + feedback: function() { + }, + + swap: function(fn) { + console.log('>>> swapBoxes()'); + this.a = [this.b, this.b = this.a][0]; + fn(this.a, this.b); + }, + + clear: function(fn) { + console.log('>>> clearValues()'); + this.a = this.b = {}; + fn(this.a, this.b); + }, + + compare: function(a, b, name, fn) { + + // To-Do: a and/or b should accept a uri or a json structure. + // To-Do: this DOM manipulation should be seperated into logic and rendering so that it works with nodejs. + + var self = this; + + var typeA = typeofReal(a); + var typeB = typeofReal(b); + + console.log('>>> compare(a=(', typeA, ')', a, + ', b=(', typeB, ')', b, + ', name=(', typeof name, ')', name, + ', results=(', typeof results, ')', results, ')'); + + var typeSpanA = document.createElement("span"); + typeSpanA.appendChild(document.createTextNode("(" + typeA + ")")) + typeSpanA.setAttribute("class", "typeName"); + + var typeSpanB = document.createElement("span"); + typeSpanB.appendChild(document.createTextNode("(" + typeB + ")")) + typeSpanB.setAttribute("class", "typeName"); + + var aString = (typeA === "object" || typeA === "array") ? "": String(a) + " "; + var bString = (typeB === "object" || typeB === "array") ? "": String(b) + " "; + + var leafNode = document.createElement("span"); + leafNode.appendChild(document.createTextNode(name)); + if (a === undefined) + { + leafNode.setAttribute("class", "added"); + leafNode.appendChild(document.createTextNode(": " + bString)); + leafNode.appendChild(typeSpanB); + self.feedback(leafNode); + } + else if (b === undefined) + { + leafNode.setAttribute("class", "removed"); + leafNode.appendChild(document.createTextNode(": " + aString)); + leafNode.appendChild(typeSpanA); + self.feedback(leafNode); + } + else if (typeA !== typeB || (typeA !== "object" && typeA !== "array" && a !== b)) + { + leafNode.setAttribute("class", "changed"); + leafNode.appendChild(document.createTextNode(": " + aString)); + leafNode.appendChild(typeSpanA); + leafNode.appendChild(document.createTextNode(" => " + bString)); + leafNode.appendChild(typeSpanB); + + if (name === 'key') leafNode.setAttribute('class', 'changed key'); + else self.feedback(leafNode); + } + else + { + leafNode.appendChild(document.createTextNode(": " + aString)); + leafNode.appendChild(typeSpanA); + } + + if (typeA === "object" || typeA === "array" || typeB === "object" || typeB === "array") + { + var keys = []; + for (var i in a) keys.push(i); + for (var i in b) keys.push(i); + keys.sort(); + + var listNode = document.createElement("ul"); + listNode.appendChild(leafNode); + + for (var i = 0; i < keys.length; i++) + { + if (keys[i] === keys[i - 1]) + continue; + + var li = document.createElement("li"); + listNode.appendChild(li); + + self.compare(a && a[keys[i]], b && b[keys[i]], keys[i], li); + } + + results.appendChild(listNode); + } + else + { + results.appendChild(leafNode); + } + + } + + }; + +})(); + diff --git a/package.json b/package.json new file mode 100644 index 0000000..75933c2 --- /dev/null +++ b/package.json @@ -0,0 +1,23 @@ +{ + "name": "jsond", + "description": "compare json with a web interface/CLI or API", + "version": "0.0.1", + "author": "hij1nx ", + "contributors": [ + { "name": "hij1nx", "email": "hi1jnx.dev@gmail.com" }, + { "name": "Tom Robinson", "email": "tlr@gmail.com" }, + { "name": "Sami Samhuri", "email": "samisamhuri@gmail.com" } + ], + "repository": { + "type": "git", + "url": "https://github.com/samsonjs/json-diff" + }, + "keywords": ["cli", "json", "diff", "tools"], + "dependencies": { + "optimist": ">= 0.0.6", + "colors": ">= 0.3.0" + }, + "bin": { "forever": "./bin/jsond" }, + "main": "./lib/jsond", + "engines": { "node": ">= 0.2.0" } +}