diff --git a/Jakefile.js b/Jakefile.js index d6112ac..1a2cdfc 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -21,7 +21,7 @@ var JSONEDITOR = './jsoneditor.js', */ desc('Execute all tasks'); task('default', ['clear', 'build', 'minify', 'zip', 'webapp', 'chromeapp'], function () { - console.log('Done'); + console.log('Done'); }); /** @@ -29,7 +29,7 @@ task('default', ['clear', 'build', 'minify', 'zip', 'webapp', 'chromeapp'], func */ desc('Clear the build directory'); task('clear', function () { - jake.rmRf(BUILD); + jake.rmRf(BUILD); }); /** @@ -37,54 +37,54 @@ task('clear', function () { */ desc('Build the library'); task('build', ['clear'], function () { - var jsoneditorSrc = './jsoneditor/'; - // concatenate the javascript files - concat({ - src: [ - jsoneditorSrc + 'js/jsoneditor.js', - jsoneditorSrc + 'js/treeeditor.js', - jsoneditorSrc + 'js/texteditor.js', - jsoneditorSrc + 'js/node.js', - jsoneditorSrc + 'js/appendnode.js', - jsoneditorSrc + 'js/contextmenu.js', - jsoneditorSrc + 'js/history.js', - jsoneditorSrc + 'js/modebox.js', - jsoneditorSrc + 'js/searchbox.js', - jsoneditorSrc + 'js/highlighter.js', - jsoneditorSrc + 'js/util.js', - jsoneditorSrc + 'js/module.js' - ], - dest: JSONEDITOR, - header: read(jsoneditorSrc +'js/header.js') + '\n' + - '(function () {\n', - separator: '\n', - footer: '\n})();\n' - }); + var jsoneditorSrc = './jsoneditor/'; + // concatenate the javascript files + concat({ + src: [ + jsoneditorSrc + 'js/jsoneditor.js', + jsoneditorSrc + 'js/treeeditor.js', + jsoneditorSrc + 'js/texteditor.js', + jsoneditorSrc + 'js/node.js', + jsoneditorSrc + 'js/appendnode.js', + jsoneditorSrc + 'js/contextmenu.js', + jsoneditorSrc + 'js/history.js', + jsoneditorSrc + 'js/modebox.js', + jsoneditorSrc + 'js/searchbox.js', + jsoneditorSrc + 'js/highlighter.js', + jsoneditorSrc + 'js/util.js', + jsoneditorSrc + 'js/module.js' + ], + dest: JSONEDITOR, + header: read(jsoneditorSrc +'js/header.js') + '\n' + + '(function () {\n', + separator: '\n', + footer: '\n})();\n' + }); - // update version number and stuff in the javascript files - replacePlaceholders(JSONEDITOR); - console.log('Created ' + JSONEDITOR); + // update version number and stuff in the javascript files + replacePlaceholders(JSONEDITOR); + console.log('Created ' + JSONEDITOR); - // concatenate and stringify the css files - concat({ - src: [ - jsoneditorSrc + 'css/jsoneditor.css', - jsoneditorSrc + 'css/contextmenu.css', - jsoneditorSrc + 'css/menu.css', - jsoneditorSrc + 'css/searchbox.css' - ], - dest: JSONEDITOR_CSS, - separator: '\n' - }); - console.log('Created ' + JSONEDITOR_CSS); + // concatenate and stringify the css files + concat({ + src: [ + jsoneditorSrc + 'css/jsoneditor.css', + jsoneditorSrc + 'css/contextmenu.css', + jsoneditorSrc + 'css/menu.css', + jsoneditorSrc + 'css/searchbox.css' + ], + dest: JSONEDITOR_CSS, + separator: '\n' + }); + console.log('Created ' + JSONEDITOR_CSS); - // minify the css file - write(JSONEDITOR_CSS_MIN, new CleanCSS().minify(String(read(JSONEDITOR_CSS)))); + // minify the css file + write(JSONEDITOR_CSS_MIN, new CleanCSS().minify(String(read(JSONEDITOR_CSS)))); - // create a folder img and copy the icons - jake.mkdirP('./img'); - jake.cpR(jsoneditorSrc + 'css/img/jsoneditor-icons.png', './img/'); - console.log('Copied jsoneditor-icons.png to ./img/'); + // create a folder img and copy the icons + jake.mkdirP('./img'); + jake.cpR(jsoneditorSrc + 'css/img/jsoneditor-icons.png', './img/'); + console.log('Copied jsoneditor-icons.png to ./img/'); }); /** @@ -92,18 +92,18 @@ task('build', ['clear'], function () { */ desc('Minify the library'); task('minify', ['build'], function () { - // minify javascript - minify({ - src: JSONEDITOR, - dest: JSONEDITOR_MIN, - header: read('./jsoneditor/js/header.js'), - separator: '\n' - }); + // minify javascript + minify({ + src: JSONEDITOR, + dest: JSONEDITOR_MIN, + header: read('./jsoneditor/js/header.js'), + separator: '\n' + }); - // update version number and stuff in the javascript files - replacePlaceholders(JSONEDITOR_MIN); + // update version number and stuff in the javascript files + replacePlaceholders(JSONEDITOR_MIN); - console.log('Created ' + JSONEDITOR_MIN); + console.log('Created ' + JSONEDITOR_MIN); }); /** @@ -111,50 +111,50 @@ task('minify', ['build'], function () { */ desc('Zip the library'); task('zip', ['build', 'minify'], {async: true}, function () { - var zipfolder = BUILD + '/lib'; - var pkg = 'jsoneditor-' + version(); - var zipfile = zipfolder + '/' + pkg + '.zip'; - jake.mkdirP(zipfolder); + var zipfolder = BUILD + '/lib'; + var pkg = 'jsoneditor-' + version(); + var zipfile = zipfolder + '/' + pkg + '.zip'; + jake.mkdirP(zipfolder); - var output = fs.createWriteStream(zipfile); - var archive = archiver('zip'); + var output = fs.createWriteStream(zipfile); + var archive = archiver('zip'); - archive.on('error', function(err) { - throw err; - }); + archive.on('error', function(err) { + throw err; + }); - archive.pipe(output); + archive.pipe(output); - var filelist = new jake.FileList(); - filelist.include([ - 'README.md', - 'NOTICE', - 'LICENSE', - 'HISTORY.md', - JSONEDITOR, - JSONEDITOR_CSS, - JSONEDITOR_MIN, - JSONEDITOR_CSS_MIN, - 'img/*.*', - 'lib/**/*.*', - 'docs/**/*.*', - 'examples/**/*.*' - ]); - var files = filelist.toArray(); - files.forEach(function (file) { - archive.append(fs.createReadStream(file), { - name: pkg + '/' + file - }) - }); + var filelist = new jake.FileList(); + filelist.include([ + 'README.md', + 'NOTICE', + 'LICENSE', + 'HISTORY.md', + JSONEDITOR, + JSONEDITOR_CSS, + JSONEDITOR_MIN, + JSONEDITOR_CSS_MIN, + 'img/*.*', + 'lib/**/*.*', + 'docs/**/*.*', + 'examples/**/*.*' + ]); + var files = filelist.toArray(); + files.forEach(function (file) { + archive.append(fs.createReadStream(file), { + name: pkg + '/' + file + }) + }); - archive.finalize(function(err, written) { - if (err) { - throw err; - } + archive.finalize(function(err, written) { + if (err) { + throw err; + } - console.log('Zipped ' + zipfile); - complete(); - }); + console.log('Zipped ' + zipfile); + complete(); + }); }); /** @@ -162,107 +162,107 @@ task('zip', ['build', 'minify'], {async: true}, function () { */ desc('Build web app'); task('webapp', ['build', 'minify'], function () { - var webAppSrc = './app/web/'; - var libSrc = './lib/'; - var webApp = BUILD + '/app/web/'; - var webAppLib = webApp + 'lib/'; - var webAppAce = webAppLib + 'ace/'; - var webAppImg = webApp + 'img/'; - var appJs = webApp + 'app.js'; - var appCss = webApp + 'app.css'; - var appCssMin = webApp + 'app-min.css'; - var appJsMin = webApp + 'app-min.js'; + var webAppSrc = './app/web/'; + var libSrc = './lib/'; + var webApp = BUILD + '/app/web/'; + var webAppLib = webApp + 'lib/'; + var webAppAce = webAppLib + 'ace/'; + var webAppImg = webApp + 'img/'; + var appJs = webApp + 'app.js'; + var appCss = webApp + 'app.css'; + var appCssMin = webApp + 'app-min.css'; + var appJsMin = webApp + 'app-min.js'; - // create directories - // TODO: should be created automatically... - jake.mkdirP(webApp); - jake.mkdirP(webAppLib); - jake.mkdirP(webAppLib + 'ace/'); - jake.mkdirP(webAppLib + 'jsoneditor/'); - jake.mkdirP(webAppLib + 'jsoneditor/img/'); - jake.mkdirP(webAppLib + 'jsonlint/'); - jake.mkdirP(webAppImg); + // create directories + // TODO: should be created automatically... + jake.mkdirP(webApp); + jake.mkdirP(webAppLib); + jake.mkdirP(webAppLib + 'ace/'); + jake.mkdirP(webAppLib + 'jsoneditor/'); + jake.mkdirP(webAppLib + 'jsoneditor/img/'); + jake.mkdirP(webAppLib + 'jsonlint/'); + jake.mkdirP(webAppImg); - // concatenate the javascript files - concat({ - src: [ - webAppSrc + 'queryparams.js', - webAppSrc + 'ajax.js', - webAppSrc + 'fileretriever.js', - webAppSrc + 'notify.js', - webAppSrc + 'splitter.js', - webAppSrc + 'app.js' - ], - dest: appJs, - separator: '\n' - }); + // concatenate the javascript files + concat({ + src: [ + webAppSrc + 'queryparams.js', + webAppSrc + 'ajax.js', + webAppSrc + 'fileretriever.js', + webAppSrc + 'notify.js', + webAppSrc + 'splitter.js', + webAppSrc + 'app.js' + ], + dest: appJs, + separator: '\n' + }); - // minify javascript - minify({ - src: appJs, - dest: appJsMin - }); + // minify javascript + minify({ + src: appJs, + dest: appJsMin + }); - // concatenate the css files - concat({ - src: [ - webAppSrc + 'fileretriever.css', - webAppSrc + 'app.css' - ], - dest: appCss, - separator: '\n' - }); + // concatenate the css files + concat({ + src: [ + webAppSrc + 'fileretriever.css', + webAppSrc + 'app.css' + ], + dest: appCss, + separator: '\n' + }); - // minify css file - write(appCssMin, new CleanCSS().minify(String(read(appCss)))); + // minify css file + write(appCssMin, new CleanCSS().minify(String(read(appCss)))); - // remove non minified javascript and css file - fs.unlinkSync(appJs); - fs.unlinkSync(appCss); + // remove non minified javascript and css file + fs.unlinkSync(appJs); + fs.unlinkSync(appCss); - // copy files - jake.cpR('./README.md', webApp); - jake.cpR('./HISTORY.md', webApp); - jake.cpR('./NOTICE', webApp); - jake.cpR('./LICENSE', webApp); - jake.cpR('./LICENSE', webApp); - jake.cpR(webAppSrc + 'cache.manifest', webApp); - jake.cpR(webAppSrc + 'robots.txt', webApp); - jake.cpR(webAppSrc + 'datapolicy.txt', webApp); - jake.cpR(webAppSrc + 'index.html', webApp); - jake.cpR(webAppSrc + 'favicon.ico', webApp); - jake.cpR(webAppSrc + 'fileretriever.php', webApp); - jake.cpR(webAppSrc + 'googlea47c4a0b36d11021.html', webApp); - jake.cpR(webAppSrc + 'img/logo.png', webAppImg); - jake.cpR(webAppSrc + 'img/header_background.png', webAppImg); - jake.cpR(webAppSrc + 'doc/', webApp); + // copy files + jake.cpR('./README.md', webApp); + jake.cpR('./HISTORY.md', webApp); + jake.cpR('./NOTICE', webApp); + jake.cpR('./LICENSE', webApp); + jake.cpR('./LICENSE', webApp); + jake.cpR(webAppSrc + 'cache.manifest', webApp); + jake.cpR(webAppSrc + 'robots.txt', webApp); + jake.cpR(webAppSrc + 'datapolicy.txt', webApp); + jake.cpR(webAppSrc + 'index.html', webApp); + jake.cpR(webAppSrc + 'favicon.ico', webApp); + jake.cpR(webAppSrc + 'fileretriever.php', webApp); + jake.cpR(webAppSrc + 'googlea47c4a0b36d11021.html', webApp); + jake.cpR(webAppSrc + 'img/logo.png', webAppImg); + jake.cpR(webAppSrc + 'img/header_background.png', webAppImg); + jake.cpR(webAppSrc + 'doc/', webApp); - // update date and verison in index.html - replacePlaceholders(webApp + 'index.html'); - replacePlaceholders(webApp + 'index.html'); // TODO: fix bug in replace, should replace all occurrences - replacePlaceholders(webApp + 'cache.manifest'); + // update date and verison in index.html + replacePlaceholders(webApp + 'index.html'); + replacePlaceholders(webApp + 'index.html'); // TODO: fix bug in replace, should replace all occurrences + replacePlaceholders(webApp + 'cache.manifest'); - // concatenate and copy ace files - concat({ - src: [ - libSrc + 'ace/ace.js', - libSrc + 'ace/mode-json.js', - libSrc + 'ace/theme-textmate.js', - libSrc + 'ace/theme-jsoneditor.js', - libSrc + 'ace/ext-searchbox.js' - ], - dest: webAppAce + 'ace-min.js', - separator: '\n' - }); - jake.cpR(libSrc + 'ace/worker-json.js', webAppAce); + // concatenate and copy ace files + concat({ + src: [ + libSrc + 'ace/ace.js', + libSrc + 'ace/mode-json.js', + libSrc + 'ace/theme-textmate.js', + libSrc + 'ace/theme-jsoneditor.js', + libSrc + 'ace/ext-searchbox.js' + ], + dest: webAppAce + 'ace-min.js', + separator: '\n' + }); + jake.cpR(libSrc + 'ace/worker-json.js', webAppAce); - // copy json lint file - jake.cpR(libSrc + 'jsonlint/jsonlint.js', webAppLib + 'jsonlint/') + // copy json lint file + jake.cpR(libSrc + 'jsonlint/jsonlint.js', webAppLib + 'jsonlint/') - // copy jsoneditor files - jake.cpR(JSONEDITOR_MIN, webAppLib + 'jsoneditor/'); - jake.cpR(JSONEDITOR_CSS_MIN, webAppLib + 'jsoneditor/'); - jake.cpR('img', webAppLib + 'jsoneditor/'); + // copy jsoneditor files + jake.cpR(JSONEDITOR_MIN, webAppLib + 'jsoneditor/'); + jake.cpR(JSONEDITOR_CSS_MIN, webAppLib + 'jsoneditor/'); + jake.cpR('img', webAppLib + 'jsoneditor/'); }); @@ -271,38 +271,38 @@ task('webapp', ['build', 'minify'], function () { */ desc('Build chrome app'); task('chromeapp', {async: true}, function () { - var folder = BUILD + '/app/'; - var file = folder + 'chrome.zip'; - jake.mkdirP(folder); + var folder = BUILD + '/app/'; + var file = folder + 'chrome.zip'; + jake.mkdirP(folder); - var output = fs.createWriteStream(file); - var archive = archiver('zip'); + var output = fs.createWriteStream(file); + var archive = archiver('zip'); - archive.on('error', function(err) { - throw err; - }); + archive.on('error', function(err) { + throw err; + }); - // create a temporary manifest file with version number - var manifestTmp = folder + 'manifest.json.tmp'; - jake.cpR('./app/chrome/manifest.json', manifestTmp); - replacePlaceholders(manifestTmp); + // create a temporary manifest file with version number + var manifestTmp = folder + 'manifest.json.tmp'; + jake.cpR('./app/chrome/manifest.json', manifestTmp); + replacePlaceholders(manifestTmp); - archive.pipe(output); - archive.append(fs.createReadStream(manifestTmp), {name: 'manifest.json'}); - archive.append(fs.createReadStream('./app/web/img/icon_16.png'), {name: 'icon_16.png'}); - archive.append(fs.createReadStream('./app/web/img/icon_128.png'), {name: 'icon_128.png'}); + archive.pipe(output); + archive.append(fs.createReadStream(manifestTmp), {name: 'manifest.json'}); + archive.append(fs.createReadStream('./app/web/img/icon_16.png'), {name: 'icon_16.png'}); + archive.append(fs.createReadStream('./app/web/img/icon_128.png'), {name: 'icon_128.png'}); - // cleanup temporary manifest file - fs.unlinkSync(manifestTmp); + // cleanup temporary manifest file + fs.unlinkSync(manifestTmp); - archive.finalize(function(err, written) { - if (err) { - throw err; - } + archive.finalize(function(err, written) { + if (err) { + throw err; + } - console.log('Created chrome app ' + file); - complete(); - }); + console.log('Created chrome app ' + file); + complete(); + }); }); /** @@ -310,11 +310,11 @@ task('chromeapp', {async: true}, function () { * @param {String} filename */ var replacePlaceholders = function (filename) { - replace({ - replacements: [ - {pattern: '@@date', replacement: today()}, - {pattern: '@@version', replacement: version()} - ], - src: filename - }); + replace({ + replacements: [ + {pattern: '@@date', replacement: today()}, + {pattern: '@@version', replacement: version()} + ], + src: filename + }); }; diff --git a/app/chrome/manifest.json b/app/chrome/manifest.json index 614666d..a7d1bcf 100644 --- a/app/chrome/manifest.json +++ b/app/chrome/manifest.json @@ -1,25 +1,25 @@ { - "manifest_version": 2, - "name": "JSON Editor", - "version": "@@version", - "description": "JSON Editor is a tool to view, edit, and format JSON. It shows your data in an editable treeview and in a code editor.", - "app": { - "urls": [ - "http://jsoneditoronline.org/", - "http://jsoneditoronline.org/index.html", - "http://jsoneditoronline.org/changelog.txt", - "http://jsoneditoronline.org/NOTICE" - ], - "launch": { - "web_url": "http://jsoneditoronline.org/index.html" - } - }, - "icons": { - "16": "icon_16.png", - "128": "icon_128.png" - }, - "permissions": [ - "unlimitedStorage" + "manifest_version": 2, + "name": "JSON Editor", + "version": "@@version", + "description": "JSON Editor is a tool to view, edit, and format JSON. It shows your data in an editable treeview and in a code editor.", + "app": { + "urls": [ + "http://jsoneditoronline.org/", + "http://jsoneditoronline.org/index.html", + "http://jsoneditoronline.org/changelog.txt", + "http://jsoneditoronline.org/NOTICE" ], - "offline_enabled": true + "launch": { + "web_url": "http://jsoneditoronline.org/index.html" + } + }, + "icons": { + "16": "icon_16.png", + "128": "icon_128.png" + }, + "permissions": [ + "unlimitedStorage" + ], + "offline_enabled": true } diff --git a/app/web/ajax.js b/app/web/ajax.js index f442f6a..e5f23fc 100644 --- a/app/web/ajax.js +++ b/app/web/ajax.js @@ -1,43 +1,43 @@ /** * ajax - * Utility to perform ajax get and post requests. Supported browsers: + * Utility to perform ajax get and post requests. Supported browsers: * Chrome, Firefox, Opera, Safari, Internet Explorer 7+. */ var ajax = (function () { - function fetch (method, url, body, headers, callback) { - try { - var xhr = new XMLHttpRequest(); - xhr.onreadystatechange = function() { - if (xhr.readyState == 4) { - callback(xhr.responseText, xhr.status); - } - }; - xhr.open(method, url, true); - if (headers) { - for (var name in headers) { - if (headers.hasOwnProperty(name)) { - xhr.setRequestHeader(name, headers[name]); - } - } - } - xhr.send(body); + function fetch (method, url, body, headers, callback) { + try { + var xhr = new XMLHttpRequest(); + xhr.onreadystatechange = function() { + if (xhr.readyState == 4) { + callback(xhr.responseText, xhr.status); } - catch (err) { - callback(err, 0); + }; + xhr.open(method, url, true); + if (headers) { + for (var name in headers) { + if (headers.hasOwnProperty(name)) { + xhr.setRequestHeader(name, headers[name]); + } } + } + xhr.send(body); } + catch (err) { + callback(err, 0); + } + } - function get (url, headers, callback) { - fetch('GET', url, null, headers, callback); - } + function get (url, headers, callback) { + fetch('GET', url, null, headers, callback); + } - function post (url, body, headers, callback) { - fetch('POST', url, body, headers, callback) - } + function post (url, body, headers, callback) { + fetch('POST', url, body, headers, callback) + } - return { - 'fetch': fetch, - 'get': get, - 'post': post - } + return { + 'fetch': fetch, + 'get': get, + 'post': post + } })(); diff --git a/app/web/app.css b/app/web/app.css index a97f5a9..a27519b 100644 --- a/app/web/app.css +++ b/app/web/app.css @@ -1,292 +1,292 @@ body, html { - font-family: arial, sans-serif; - font-size: 11pt; + font-family: arial, sans-serif; + font-size: 11pt; - width: 100%; - height: 100%; - margin: 0; - padding: 0; + width: 100%; + height: 100%; + margin: 0; + padding: 0; - overflow: hidden; + overflow: hidden; } span.header-light { - color: gray; + color: gray; } #header { - width: 100%; - height: 40px; - /* TODO - overflow: hidden; - */ + width: 100%; + height: 40px; + /* TODO + overflow: hidden; + */ - background: #4D4D4D url('img/header_background.png'); - color: white; + background: #4D4D4D url('img/header_background.png'); + color: white; } #logo { - height: 32px; - margin: 4px 10px; - border: none; + height: 32px; + margin: 4px 10px; + border: none; } #menu { - position: absolute; - top: 5px; - right: 15px; - font-size: 11pt; + position: absolute; + top: 5px; + right: 15px; + font-size: 11pt; } #menu ul { - list-style: none; - margin: 0; - padding: 0; - clear: both; + list-style: none; + margin: 0; + padding: 0; + clear: both; } #menu ul li { - color: #e6e6e6; - background: none; - border: none; - border-right: 1px solid #737373; - height: 30px; - padding: 0; - margin: 0; - float: left; - position: relative; + color: #e6e6e6; + background: none; + border: none; + border-right: 1px solid #737373; + height: 30px; + padding: 0; + margin: 0; + float: left; + position: relative; - text-decoration: none; + text-decoration: none; } #menu ul li:first-child { - border-left: 1px solid #737373; + border-left: 1px solid #737373; } #menu ul li:hover { - color: white; - background-color: #737373; + color: white; + background-color: #737373; } #menu ul li ul { - display: none; + display: none; } #menu ul li:hover > ul { - display: block; + display: block; } #menu ul li ul { - position: absolute; - top: 30px; - left: 0; - z-index: 999; + position: absolute; + top: 30px; + left: 0; + z-index: 999; - background: #f5f5f5; - border: 1px solid lightgray; - box-shadow: 0 0 15px rgba(128, 128, 128, 0.5); + background: #f5f5f5; + border: 1px solid lightgray; + box-shadow: 0 0 15px rgba(128, 128, 128, 0.5); } #menu ul li ul li { - color: #737373; - background: none; - border: none; - margin: 0; - padding: 0; + color: #737373; + background: none; + border: none; + margin: 0; + padding: 0; } #menu ul li ul li:first-child { - border-left: none; + border-left: none; } #menu ul li ul li:hover { - background-color: white; + background-color: white; } #menu a { - padding: 6px 10px; - display: block; - cursor: pointer; - text-decoration: none; - color: white; + padding: 6px 10px; + display: block; + cursor: pointer; + text-decoration: none; + color: white; } #menu ul li ul li a { - color: #737373; - width: 80px; + color: #737373; + width: 80px; } #openMenuButton { - font-size: 75%; - margin-left: 2px; + font-size: 75%; + margin-left: 2px; } #menu #open { - cursor: default; + cursor: default; } /* TODO: enable the menu with keys (when openMenuButton is active) */ #auto { - width: 100%; - height: 100%; + width: 100%; + height: 100%; - margin: -40px 0 -24px 0; - padding: 40px 0 24px 0; + margin: -40px 0 -24px 0; + padding: 40px 0 24px 0; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; - overflow: hidden; + overflow: hidden; } #contents { - width: 100%; - height: 100%; - overflow: hidden; + width: 100%; + height: 100%; + overflow: hidden; } #codeEditor, #treeEditor { - height: 100%; - width: 400px; + height: 100%; + width: 400px; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; } #codeEditor { - float: left; - padding: 15px 0 15px 15px; + float: left; + padding: 15px 0 15px 15px; } #treeEditor { - float: left; - padding: 15px 15px 15px 0; + float: left; + padding: 15px 15px 15px 0; } #splitter { - text-align: center; - float: left; - height: 100%; - padding: 15px; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; + text-align: center; + float: left; + height: 100%; + padding: 15px; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; } #splitter #buttons { - margin: 0 0 15px 0; + margin: 0 0 15px 0; } #splitter #toTree { - margin: 40px 0 0 0 ; + margin: 40px 0 0 0 ; } #splitter #toCode { - margin: 20px 0 0 0 ; + margin: 20px 0 0 0 ; } #splitter #drag { - font-size: 32px; - color: lightgray; - border-radius: 3px; - min-width: 24px; - cursor: col-resize; + font-size: 32px; + color: lightgray; + border-radius: 3px; + min-width: 24px; + cursor: col-resize; } #splitter #drag:hover, #splitter #drag.active { - color: gray; - background-color: #f5f5f5; + color: gray; + background-color: #f5f5f5; } #footer { - width: 100%; - height: 23px; - font-size: 10pt; + width: 100%; + height: 23px; + font-size: 10pt; - overflow: hidden; - color: #BFBFBF; - border-top: 1px solid lightgray; - text-align: center; - background-color: #F5F5F5; + overflow: hidden; + color: #BFBFBF; + border-top: 1px solid lightgray; + text-align: center; + background-color: #F5F5F5; } #footer-inner { - margin: 4px; + margin: 4px; } a.header { - color: white; - text-decoration: none; + color: white; + text-decoration: none; } a.footer { - color: #BFBFBF; - text-decoration: none; + color: #BFBFBF; + text-decoration: none; } a.footer:hover { - color: red; - text-decoration: underline; + color: red; + text-decoration: underline; } #ad { - float: right; - right: 15px; - padding: 15px 0 15px 0; - position: relative; + float: right; + right: 15px; + padding: 15px 0 15px 0; + position: relative; } #chromeAppInfo { - line-height: normal; - padding: 0 5px 20px 5px; + line-height: normal; + padding: 0 5px 20px 5px; } div.error, div.notification { - border-radius: 2px; - padding: 5px; - margin: 5px; - box-shadow: 0 0 15px rgba(128, 128, 128, 0.5); + border-radius: 2px; + padding: 5px; + margin: 5px; + box-shadow: 0 0 15px rgba(128, 128, 128, 0.5); - /* TODO: add some transition effect */ + /* TODO: add some transition effect */ } div.error { - color: red; - background-color: #FFC0CB; - border: 1px solid red; + color: red; + background-color: #FFC0CB; + border: 1px solid red; } div.notification { - color: #1a1a1a; - background-color: #FFFFAB; - border: 1px solid #e6d600; + color: #1a1a1a; + background-color: #FFFFAB; + border: 1px solid #e6d600; } pre.error { - margin: 0 0 10px 0; - white-space: pre-wrap; - font-family: droid sans mono, monospace, courier new, courier, sans-serif; - font-size: 10pt; + margin: 0 0 10px 0; + white-space: pre-wrap; + font-family: droid sans mono, monospace, courier new, courier, sans-serif; + font-size: 10pt; } a.error { - color: red; - font-size: 8pt; + color: red; + font-size: 8pt; } button.convert { - cursor: default; - padding: 2px; + cursor: default; + padding: 2px; } div.convert-right, div.convert-left { - width: 24px; - height: 24px; - margin: 0; + width: 24px; + height: 24px; + margin: 0; } div.convert-right { - background: url('lib/jsoneditor/img/jsoneditor-icons.png') -0 -48px; + background: url('lib/jsoneditor/img/jsoneditor-icons.png') -0 -48px; } div.convert-left { - background: url('lib/jsoneditor/img/jsoneditor-icons.png') -24px -48px; + background: url('lib/jsoneditor/img/jsoneditor-icons.png') -24px -48px; } diff --git a/app/web/app.js b/app/web/app.js index 85c07e6..668a2e4 100644 --- a/app/web/app.js +++ b/app/web/app.js @@ -39,24 +39,24 @@ var app = {}; * Get the JSON from the code editor and load it in the tree editor */ app.CodeToTree = function() { - try { - treeEditor.set(codeEditor.get()); - } - catch (err) { - app.notify.showError(app.formatError(err)); - } + try { + treeEditor.set(codeEditor.get()); + } + catch (err) { + app.notify.showError(app.formatError(err)); + } }; /** * Get the JSON from the tree editor and load it into the code editor */ app.treeToCode = function () { - try { - codeEditor.set(treeEditor.get()); - } - catch (err) { - app.notify.showError(app.formatError(err)); - } + try { + codeEditor.set(treeEditor.get()); + } + catch (err) { + app.notify.showError(app.formatError(err)); + } }; /** @@ -64,139 +64,139 @@ app.treeToCode = function () { */ // TODO: split the method load in multiple methods, it is too large app.load = function() { - try { - // notification handler - app.notify = new Notify(); + try { + // notification handler + app.notify = new Notify(); - // retriever for loading/saving files - app.retriever = new FileRetriever({ - scriptUrl: 'fileretriever.php', - notify: app.notify - }); + // retriever for loading/saving files + app.retriever = new FileRetriever({ + scriptUrl: 'fileretriever.php', + notify: app.notify + }); - // default json document - var json = { - "array": [1, 2, 3], - "boolean": true, - "null": null, - "number": 123, - "object": {"a": "b", "c": "d", "e": "f"}, - "string": "Hello World" - }; + // default json document + var json = { + "array": [1, 2, 3], + "boolean": true, + "null": null, + "number": 123, + "object": {"a": "b", "c": "d", "e": "f"}, + "string": "Hello World" + }; - // load url if query parameters contains a url - if (window.QueryParams) { - var qp = new QueryParams(); - var url = qp.getValue('url'); - if (url) { - json = {}; - app.openUrl(url); - } - } - - // Store whether tree editor or code editor is last changed - app.lastChanged = undefined; - - // code editor - var container = document.getElementById("codeEditor"); - codeEditor = new jsoneditor.JSONEditor(container, { - mode: 'code', - change: function () { - app.lastChanged = codeEditor; - }, - error: function (err) { - app.notify.showError(app.formatError(err)); - } - }); - codeEditor.set(json); - - // tree editor - container = document.getElementById("treeEditor"); - treeEditor = new jsoneditor.JSONEditor(container, { - mode: 'tree', - change: function () { - app.lastChanged = treeEditor; - }, - error: function (err) { - app.notify.showError(app.formatError(err)); - } - }); - treeEditor.set(json); - // TODO: automatically synchronize data of code and tree editor? (tree editor should keep its state though) - - // splitter - app.splitter = new Splitter({ - container: document.getElementById('drag'), - change: function () { - app.resize(); - } - }); - - // button Code-to-Tree - var toTree = document.getElementById('toTree'); - toTree.onclick = function () { - this.focus(); - app.CodeToTree(); - }; - - // button Tree-to-Code - var toCode = document.getElementById('toCode'); - toCode.onclick = function () { - this.focus(); - app.treeToCode(); - }; - - // web page resize handler - jsoneditor.util.addEventListener(window, 'resize', app.resize); - - // clear button - var domClear = document.getElementById('clear'); - domClear.onclick = app.clearFile; - - /* TODO: enable clicking on open to execute the default, "open file" - // open button - var domOpen = document.getElementById('open'); - var domOpenMenuButton = document.getElementById('openMenuButton'); - domOpen.onclick = function (event) { - var target = event.target || event.srcElement; - if (target == domOpenMenuButton || - (event.offsetX > domOpen.offsetWidth - domOpenMenuButton.offsetWidth)) { - // clicked on the menu button - } - else { - app.openFile(); - } - }; - */ - - // menu button open file - var domMenuOpenFile = document.getElementById('menuOpenFile'); - domMenuOpenFile.onclick = function (event) { - app.openFile(); - event.stopPropagation(); - event.preventDefault(); - }; - - // menu button open url - var domMenuOpenUrl = document.getElementById('menuOpenUrl'); - domMenuOpenUrl.onclick = function (event) { - app.openUrl(); - event.stopPropagation(); - event.preventDefault(); - }; - - // save button - var domSave = document.getElementById('save'); - domSave.onclick = app.saveFile; - - // set focus on the code editor - codeEditor.focus(); - - // enforce FireFox to not do spell checking on any input field - document.body.spellcheck = false; - } catch (err) { - app.notify.showError(err); + // load url if query parameters contains a url + if (window.QueryParams) { + var qp = new QueryParams(); + var url = qp.getValue('url'); + if (url) { + json = {}; + app.openUrl(url); + } } + + // Store whether tree editor or code editor is last changed + app.lastChanged = undefined; + + // code editor + var container = document.getElementById("codeEditor"); + codeEditor = new jsoneditor.JSONEditor(container, { + mode: 'code', + change: function () { + app.lastChanged = codeEditor; + }, + error: function (err) { + app.notify.showError(app.formatError(err)); + } + }); + codeEditor.set(json); + + // tree editor + container = document.getElementById("treeEditor"); + treeEditor = new jsoneditor.JSONEditor(container, { + mode: 'tree', + change: function () { + app.lastChanged = treeEditor; + }, + error: function (err) { + app.notify.showError(app.formatError(err)); + } + }); + treeEditor.set(json); + // TODO: automatically synchronize data of code and tree editor? (tree editor should keep its state though) + + // splitter + app.splitter = new Splitter({ + container: document.getElementById('drag'), + change: function () { + app.resize(); + } + }); + + // button Code-to-Tree + var toTree = document.getElementById('toTree'); + toTree.onclick = function () { + this.focus(); + app.CodeToTree(); + }; + + // button Tree-to-Code + var toCode = document.getElementById('toCode'); + toCode.onclick = function () { + this.focus(); + app.treeToCode(); + }; + + // web page resize handler + jsoneditor.util.addEventListener(window, 'resize', app.resize); + + // clear button + var domClear = document.getElementById('clear'); + domClear.onclick = app.clearFile; + + /* TODO: enable clicking on open to execute the default, "open file" + // open button + var domOpen = document.getElementById('open'); + var domOpenMenuButton = document.getElementById('openMenuButton'); + domOpen.onclick = function (event) { + var target = event.target || event.srcElement; + if (target == domOpenMenuButton || + (event.offsetX > domOpen.offsetWidth - domOpenMenuButton.offsetWidth)) { + // clicked on the menu button + } + else { + app.openFile(); + } + }; + */ + + // menu button open file + var domMenuOpenFile = document.getElementById('menuOpenFile'); + domMenuOpenFile.onclick = function (event) { + app.openFile(); + event.stopPropagation(); + event.preventDefault(); + }; + + // menu button open url + var domMenuOpenUrl = document.getElementById('menuOpenUrl'); + domMenuOpenUrl.onclick = function (event) { + app.openUrl(); + event.stopPropagation(); + event.preventDefault(); + }; + + // save button + var domSave = document.getElementById('save'); + domSave.onclick = app.saveFile; + + // set focus on the code editor + codeEditor.focus(); + + // enforce FireFox to not do spell checking on any input field + document.body.spellcheck = false; + } catch (err) { + app.notify.showError(err); + } }; /** @@ -205,29 +205,29 @@ app.load = function() { * @param {String} data */ app.openCallback = function (err, data) { - if (!err) { - if (data != null) { - codeEditor.setText(data); - try { - var json = jsoneditor.util.parse(data); - treeEditor.set(json); - } - catch (err) { - treeEditor.set({}); - app.notify.showError(app.formatError(err)); - } - } - } - else { - app.notify.showError(err); + if (!err) { + if (data != null) { + codeEditor.setText(data); + try { + var json = jsoneditor.util.parse(data); + treeEditor.set(json); + } + catch (err) { + treeEditor.set({}); + app.notify.showError(app.formatError(err)); + } } + } + else { + app.notify.showError(err); + } }; /** * Open a file explorer to select a file and open the file */ app.openFile = function() { - app.retriever.loadFile(app.openCallback); + app.retriever.loadFile(app.openCallback); }; /** @@ -236,37 +236,37 @@ app.openFile = function() { * @param {String} [url] */ app.openUrl = function (url) { - if (!url) { - app.retriever.loadUrlDialog(app.openCallback); - } - else { - app.retriever.loadUrl(url, app.openCallback); - } + if (!url) { + app.retriever.loadUrlDialog(app.openCallback); + } + else { + app.retriever.loadUrl(url, app.openCallback); + } }; /** * Open a file explorer to save the file. */ app.saveFile = function () { - // first synchronize both editors contents - if (app.lastChanged == treeEditor) { - app.treeToCode(); - } - /* TODO: also sync from code to tree editor? will clear the history ... - if (app.lastChanged == codeEditor) { - app.CodeToEditor(); - } - */ - app.lastChanged = undefined; + // first synchronize both editors contents + if (app.lastChanged == treeEditor) { + app.treeToCode(); + } + /* TODO: also sync from code to tree editor? will clear the history ... + if (app.lastChanged == codeEditor) { + app.CodeToEditor(); + } + */ + app.lastChanged = undefined; - // save the text from the code editor - // TODO: show a 'saving...' notification - var data = codeEditor.getText(); - app.retriever.saveFile(data, function (err) { - if (err) { - app.notify.showError(err); - } - }); + // save the text from the code editor + // TODO: show a 'saving...' notification + var data = codeEditor.getText(); + app.retriever.saveFile(data, function (err) { + if (err) { + app.notify.showError(err); + } + }); }; /** @@ -275,102 +275,102 @@ app.saveFile = function () { * @returns {string} */ app.formatError = function (err) { - var message = '
' + err.toString() + ''; - if (typeof(jsonlint) != 'undefined') { - message += - '' + - 'validated by jsonlint' + - ''; - } - return message; + var message = '
' + err.toString() + ''; + if (typeof(jsonlint) != 'undefined') { + message += + '' + + 'validated by jsonlint' + + ''; + } + return message; }; /** * Clear the current file */ app.clearFile = function () { - var json = {}; - codeEditor.set(json); - treeEditor.set(json); + var json = {}; + codeEditor.set(json); + treeEditor.set(json); }; app.resize = function() { - var domMenu = document.getElementById('menu'); - var domTreeEditor = document.getElementById('treeEditor'); - var domCodeEditor = document.getElementById('codeEditor'); - var domSplitter = document.getElementById('splitter'); - var domSplitterButtons = document.getElementById('buttons'); - var domSplitterDrag = document.getElementById('drag'); - var domAd = document.getElementById('ad'); + var domMenu = document.getElementById('menu'); + var domTreeEditor = document.getElementById('treeEditor'); + var domCodeEditor = document.getElementById('codeEditor'); + var domSplitter = document.getElementById('splitter'); + var domSplitterButtons = document.getElementById('buttons'); + var domSplitterDrag = document.getElementById('drag'); + var domAd = document.getElementById('ad'); - var margin = 15; - var width = (window.innerWidth || document.body.offsetWidth || - document.documentElement.offsetWidth); - var adWidth = domAd ? domAd.clientWidth : 0; + var margin = 15; + var width = (window.innerWidth || document.body.offsetWidth || + document.documentElement.offsetWidth); + var adWidth = domAd ? domAd.clientWidth : 0; + if (adWidth) { + width -= (adWidth + margin); + } + + if (app.splitter) { + app.splitter.setWidth(width); + + // calculate horizontal splitter position + var value = app.splitter.getValue(); + var showCodeEditor = (value > 0); + var showTreeEditor = (value < 1); + var showButtons = showCodeEditor && showTreeEditor; + domSplitterButtons.style.display = showButtons ? '' : 'none'; + + var splitterWidth = domSplitter.clientWidth; + var splitterLeft; + if (!showCodeEditor) { + // code editor not visible + splitterLeft = 0; + domSplitterDrag.innerHTML = '›'; + domSplitterDrag.title = 'Drag right to show the code editor'; + } + else if (!showTreeEditor) { + // tree editor not visible + splitterLeft = width * value - splitterWidth; + domSplitterDrag.innerHTML = '‹'; + domSplitterDrag.title = 'Drag left to show the tree editor'; + } + else { + // both tree and code editor visible + splitterLeft = width * value - splitterWidth / 2; + + // TODO: find a character with vertical dots that works on IE8 too, or use an image + var isIE8 = (jsoneditor.util.getInternetExplorerVersion() == 8); + domSplitterDrag.innerHTML = (!isIE8) ? '⋮' : '|'; + domSplitterDrag.title = 'Drag left or right to change the width of the panels'; + } + + // resize code editor + domCodeEditor.style.display = (value == 0) ? 'none' : ''; + domCodeEditor.style.width = Math.max(Math.round(splitterLeft), 0) + 'px'; + codeEditor.resize(); + + // resize the splitter + domSplitterDrag.style.height = (domSplitter.clientHeight - + domSplitterButtons.clientHeight - 2 * margin - + (showButtons ? margin : 0)) + 'px'; + domSplitterDrag.style.lineHeight = domSplitterDrag.style.height; + + // resize tree editor + // the width has a -1 to prevent the width from being just half a pixel + // wider than the window, causing the content elements to wrap... + domTreeEditor.style.display = (value == 1) ? 'none' : ''; + domTreeEditor.style.left = Math.round(splitterLeft + splitterWidth) + 'px'; + domTreeEditor.style.width = Math.max(Math.round(width - splitterLeft - splitterWidth - 2), 0) + 'px'; + } + + // align main menu with ads + if (domMenu) { if (adWidth) { - width -= (adWidth + margin); + domMenu.style.right = (margin + (adWidth + margin)) + 'px'; } - - if (app.splitter) { - app.splitter.setWidth(width); - - // calculate horizontal splitter position - var value = app.splitter.getValue(); - var showCodeEditor = (value > 0); - var showTreeEditor = (value < 1); - var showButtons = showCodeEditor && showTreeEditor; - domSplitterButtons.style.display = showButtons ? '' : 'none'; - - var splitterWidth = domSplitter.clientWidth; - var splitterLeft; - if (!showCodeEditor) { - // code editor not visible - splitterLeft = 0; - domSplitterDrag.innerHTML = '›'; - domSplitterDrag.title = 'Drag right to show the code editor'; - } - else if (!showTreeEditor) { - // tree editor not visible - splitterLeft = width * value - splitterWidth; - domSplitterDrag.innerHTML = '‹'; - domSplitterDrag.title = 'Drag left to show the tree editor'; - } - else { - // both tree and code editor visible - splitterLeft = width * value - splitterWidth / 2; - - // TODO: find a character with vertical dots that works on IE8 too, or use an image - var isIE8 = (jsoneditor.util.getInternetExplorerVersion() == 8); - domSplitterDrag.innerHTML = (!isIE8) ? '⋮' : '|'; - domSplitterDrag.title = 'Drag left or right to change the width of the panels'; - } - - // resize code editor - domCodeEditor.style.display = (value == 0) ? 'none' : ''; - domCodeEditor.style.width = Math.max(Math.round(splitterLeft), 0) + 'px'; - codeEditor.resize(); - - // resize the splitter - domSplitterDrag.style.height = (domSplitter.clientHeight - - domSplitterButtons.clientHeight - 2 * margin - - (showButtons ? margin : 0)) + 'px'; - domSplitterDrag.style.lineHeight = domSplitterDrag.style.height; - - // resize tree editor - // the width has a -1 to prevent the width from being just half a pixel - // wider than the window, causing the content elements to wrap... - domTreeEditor.style.display = (value == 1) ? 'none' : ''; - domTreeEditor.style.left = Math.round(splitterLeft + splitterWidth) + 'px'; - domTreeEditor.style.width = Math.max(Math.round(width - splitterLeft - splitterWidth - 2), 0) + 'px'; - } - - // align main menu with ads - if (domMenu) { - if (adWidth) { - domMenu.style.right = (margin + (adWidth + margin)) + 'px'; - } - else { - domMenu.style.right = margin + 'px'; - } + else { + domMenu.style.right = margin + 'px'; } + } }; diff --git a/app/web/beta/index.html b/app/web/beta/index.html index 973d86a..5b2adab 100644 --- a/app/web/beta/index.html +++ b/app/web/beta/index.html @@ -1,17 +1,17 @@ -
- There is currently no beta version available. -
- ++ There is currently no beta version available. +
+- JSON Editor Online is a web-based tool to view, edit, and format JSON. - It shows your data side by side in a clear, editable treeview and in - a code editor. -
-- Supported browsers: Chrome, Firefox, Safari, Opera, Internet Explorer 8+. -
-- Website: - http://jsoneditoronline.org. -
-- Contents: -
-+ JSON Editor Online is a web-based tool to view, edit, and format JSON. + It shows your data side by side in a clear, editable treeview and in + a code editor. +
++ Supported browsers: Chrome, Firefox, Safari, Opera, Internet Explorer 8+. +
++ Website: + http://jsoneditoronline.org. +
++ Contents: +
+- The applications main menu contains options to clear, load and save the - JSON contents of the application. Files can be loaded from disk or url, - and can be saved to disk. Please note that due to security restrictions, - the application can only open files from public websites, not from an - intranet. The data policy is described - here. -
- ++ The applications main menu contains options to clear, load and save the + JSON contents of the application. Files can be loaded from disk or url, + and can be saved to disk. Please note that due to security restrictions, + the application can only open files from public websites, not from an + intranet. The data policy is described + here. +
+ -- The application contains two panels: a code editor on the left, - and a Tree Editor on the right. -
-- There is a splitter between the two panels, allowing to change the - width of both panels according to ones needs. - To copy the contents from one panel to an other, the two copy buttons - between the panels can be used. -
- ++ The application contains two panels: a code editor on the left, + and a Tree Editor on the right. +
++ There is a splitter between the two panels, allowing to change the + width of both panels according to ones needs. + To copy the contents from one panel to an other, the two copy buttons + between the panels can be used. +
+ -- The code editor displays JSON data in a code editor. - The editor is capable of formatting, compacting, and inspecting JSON. -
- -- The menu of the code editor contains the following buttons: -
-+ The code editor displays JSON data in a code editor. + The editor is capable of formatting, compacting, and inspecting JSON. +
+ ++ The menu of the code editor contains the following buttons: +
+- The Tree editor displays the JSON data in an editable tree. - The editor makes it easy to create, duplicate, remove fields, - and to edit the contents of the fields. -
- -- The menu of the tree editor contains the following functions: -
-+ The Tree editor displays the JSON data in an editable tree. + The editor makes it easy to create, duplicate, remove fields, + and to edit the contents of the fields. +
+ ++ The menu of the tree editor contains the following functions: +
+- The field values in the editor are editable input fields. - The fields can be dragged up and down using the dragarea - - on the left side of the fields. When a field is the last item of the - childs of an array or object, the field can also be dragged horizontally - to move it in or out of the array or object. -
- -- Right from the dragarea is a button - - to open the actions menu. - Depending on the type of field, the following functionality is - available in the actions menu: -
-+ The field values in the editor are editable input fields. + The fields can be dragged up and down using the dragarea + + on the left side of the fields. When a field is the last item of the + childs of an array or object, the field can also be dragged horizontally + to move it in or out of the array or object. +
+ ++ Right from the dragarea is a button + + to open the actions menu. + Depending on the type of field, the following functionality is + available in the actions menu: +
+- The tree editor supports shortcut keys for all available actions. - The editor can be used by just a keyboard. - The following short cut keys are available: -
++ The tree editor supports shortcut keys for all available actions. + The editor can be used by just a keyboard. + The following short cut keys are available: +
-Key | Description |
---|---|
Alt+Arrows | Move the caret up/down/left/right between fields |
Shift+Alt+Arrows | Move field up/down/left/right |
Key | Description |
---|---|
Alt+Arrows | Move the caret up/down/left/right between fields |
Shift+Alt+Arrows | Move field up/down/left/right |
Ctrl+D | Duplicate field |
Ctrl+Del | Remove field |
Ctrl+Enter | Open link when on a field containing an url |
Ctrl+Ins | Insert a new field with type auto |
Ctrl+Shift+Ins | Append a new field with type auto |
Ctrl+E | Expand or collapse field |
Alt+End | Move the caret to the last field |
Ctrl+F | Find |
F3, Ctrl+G | Find next |
Shift+F3, Ctrl+Shift+G | Find previous |
Alt+Home | Move the caret to the first field |
Ctrl+M | Show actions menu |
Ctrl+Z | Undo last action |
Ctrl+Shift+Z | Redo |
- - -
- ++ + +
+ - + // get json + document.getElementById('getJSON').onclick = function () { + var json = editor.get(); + alert(JSON.stringify(json, null, 2)); + }; + diff --git a/examples/02_viewer.html b/examples/02_viewer.html index 66a6092..be0306c 100644 --- a/examples/02_viewer.html +++ b/examples/02_viewer.html @@ -1,40 +1,40 @@ - - - + + + -- This editor is read-only (mode='viewer'). -
- ++ This editor is read-only (mode='viewer'). +
+ - + var editor = new jsoneditor.JSONEditor(container, options, json); + diff --git a/examples/03_switch_mode.html b/examples/03_switch_mode.html index 9dde5fc..be9f146 100644 --- a/examples/03_switch_mode.html +++ b/examples/03_switch_mode.html @@ -1,70 +1,70 @@ - + - - - + + + - - - - - + + + + + - - + + - + #jsoneditor { + width: 500px; + height: 500px; + } +
- Switch editor mode using the mode box.
- Note that the mode can be changed programmatically as well using the method
- editor.setMode(mode)
, try it in the console of your browser.
+ Switch editor mode using the mode box.
+ Note that the mode can be changed programmatically as well using the method
+ editor.setMode(mode)
, try it in the console of your browser.
- - -
- ++ + +
+ diff --git a/examples/requirejs_demo/scripts/main.js b/examples/requirejs_demo/scripts/main.js index 382d51f..6727839 100644 --- a/examples/requirejs_demo/scripts/main.js +++ b/examples/requirejs_demo/scripts/main.js @@ -1,25 +1,25 @@ var module = '../../../jsoneditor'; require([module], function (jsoneditor) { - // create the editor - var container = document.getElementById('jsoneditor'); - var editor = new jsoneditor.JSONEditor(container); + // create the editor + var container = document.getElementById('jsoneditor'); + var editor = new jsoneditor.JSONEditor(container); - // set json - document.getElementById('setJSON').onclick = function () { - var json = { - 'array': [1, 2, 3], - 'boolean': true, - 'null': null, - 'number': 123, - 'object': {'a': 'b', 'c': 'd'}, - 'string': 'Hello World' - }; - editor.set(json); + // set json + document.getElementById('setJSON').onclick = function () { + var json = { + 'array': [1, 2, 3], + 'boolean': true, + 'null': null, + 'number': 123, + 'object': {'a': 'b', 'c': 'd'}, + 'string': 'Hello World' }; + editor.set(json); + }; - // get json - document.getElementById('getJSON').onclick = function () { - var json = editor.get(); - alert(JSON.stringify(json, null, 2)); - }; + // get json + document.getElementById('getJSON').onclick = function () { + var json = editor.get(); + alert(JSON.stringify(json, null, 2)); + }; }); diff --git a/jsoneditor-min.js b/jsoneditor-min.js index 11bebbe..914c43e 100644 --- a/jsoneditor-min.js +++ b/jsoneditor-min.js @@ -30,5 +30,5 @@ * @version 2.4.0-SNAPSHOT * @date 2013-11-15 */ -!function(){function e(t,i,o){if(!(this instanceof e))throw new Error('JSONEditor constructor called without "new".');var n=util.getInternetExplorerVersion();if(-1!=n&&9>n)throw new Error("Unsupported browser, IE9 or newer required. Please install the newest version of your browser.");arguments.length&&this._create(t,i,o)}function t(e,i,o){if(!(this instanceof t))throw new Error('TreeEditor constructor called without "new".');this._create(e,i,o)}function i(e,t,o){if(!(this instanceof i))throw new Error('TextEditor constructor called without "new".');this._create(e,t,o)}function o(e,t){this.editor=e,this.dom={},this.expanded=!1,t&&t instanceof Object?(this.setField(t.field,t.fieldEditable),this.setValue(t.value,t.type)):(this.setField(""),this.setValue(null))}function n(e){this.editor=e,this.dom={}}function s(e,t){function i(e,t,n){n.forEach(function(n){if("separator"==n.type){var s=document.createElement("div");s.className="separator",a=document.createElement("li"),a.appendChild(s),e.appendChild(a)}else{var r={},a=document.createElement("li");e.appendChild(a);var l=document.createElement("button");if(l.className=n.className,r.button=l,n.title&&(l.title=n.title),n.click&&(l.onclick=function(){o.hide(),n.click()}),a.appendChild(l),n.submenu){var d=document.createElement("div");d.className="icon",l.appendChild(d),l.appendChild(document.createTextNode(n.text));var h;if(n.click){l.className+=" default";var c=document.createElement("button");r.buttonExpand=c,c.className="expand",c.innerHTML='',a.appendChild(c),n.submenuTitle&&(c.title=n.submenuTitle),h=c}else{var u=document.createElement("div");u.className="expand",l.appendChild(u),h=l}h.onclick=function(){o._onExpandItem(r),h.focus()};var p=[];r.subItems=p;var f=document.createElement("ul");r.ul=f,f.className="menu",f.style.height="0",a.appendChild(f),i(f,p,n.submenu)}else l.innerHTML=''+n.text;t.push(r)}})}this.dom={};var o=this,n=this.dom;this.anchor=void 0,this.items=e,this.eventListeners={},this.selection=void 0,this.visibleSubmenu=void 0,this.onClose=t?t.close:void 0;var s=document.createElement("div");s.className="jsoneditor-contextmenu",n.menu=s;var r=document.createElement("ul");r.className="menu",s.appendChild(r),n.list=r,n.items=[];var a=document.createElement("button");n.focusButton=a;var l=document.createElement("li");l.style.overflow="hidden",l.style.height="0",l.appendChild(a),r.appendChild(l),i(r,this.dom.items,e),this.maxHeight=0,e.forEach(function(t){var i=24*(e.length+(t.submenu?t.submenu.length:0));o.maxHeight=Math.max(o.maxHeight,i)})}function r(e){this.editor=e,this.clear(),this.actions={editField:{undo:function(e){e.node.updateField(e.oldValue)},redo:function(e){e.node.updateField(e.newValue)}},editValue:{undo:function(e){e.node.updateValue(e.oldValue)},redo:function(e){e.node.updateValue(e.newValue)}},appendNode:{undo:function(e){e.parent.removeChild(e.node)},redo:function(e){e.parent.appendChild(e.node)}},insertBeforeNode:{undo:function(e){e.parent.removeChild(e.node)},redo:function(e){e.parent.insertBefore(e.node,e.beforeNode)}},insertAfterNode:{undo:function(e){e.parent.removeChild(e.node)},redo:function(e){e.parent.insertAfter(e.node,e.afterNode)}},removeNode:{undo:function(e){var t=e.parent,i=t.childs[e.index]||t.append;t.insertBefore(e.node,i)},redo:function(e){e.parent.removeChild(e.node)}},duplicateNode:{undo:function(e){e.parent.removeChild(e.clone)},redo:function(e){e.parent.insertAfter(e.clone,e.node)}},changeType:{undo:function(e){e.node.changeType(e.oldType)},redo:function(e){e.node.changeType(e.newType)}},moveNode:{undo:function(e){e.startParent.moveTo(e.node,e.startIndex)},redo:function(e){e.endParent.moveTo(e.node,e.endIndex)}},sort:{undo:function(e){var t=e.node;t.hideChilds(),t.sort=e.oldSort,t.childs=e.oldChilds,t.showChilds()},redo:function(e){var t=e.node;t.hideChilds(),t.sort=e.newSort,t.childs=e.newChilds,t.showChilds()}}}}function a(e,t,i){function o(t){e.setMode(t);var i=e.dom&&e.dom.modeBox;i&&i.focus()}for(var n={code:{text:"Code",title:"Switch to code highlighter",click:function(){o("code")}},form:{text:"Form",title:"Switch to form editor",click:function(){o("form")}},text:{text:"Text",title:"Switch to plain text editor",click:function(){o("text")}},tree:{text:"Tree",title:"Switch to tree editor",click:function(){o("tree")}},view:{text:"View",title:"Switch to tree view",click:function(){o("view")}}},r=[],a=0;awith hasChildNodes()==false is - // rendered with a new line. Note that a
with
- // hasChildNodes()==true is rendered without a new line
- // Other browsers always ensure there is a
inside the
, - // and if not, the
does not render a new line - return buffer.flush(); + if (child.nodeName == 'DIV' || child.nodeName == 'P') { + var prevChild = childNodes[i - 1]; + var prevName = prevChild ? prevChild.nodeName : undefined; + if (prevName && prevName != 'DIV' && prevName != 'P' && prevName != 'BR') { + innerText += '\n'; + buffer.flush(); } + innerText += util.getInnerText(child, buffer); + buffer.set('\n'); + } + else if (child.nodeName == 'BR') { + innerText += buffer.flush(); + buffer.set('\n'); + } + else { + innerText += util.getInnerText(child, buffer); + } } - // br or unknown - return ''; + return innerText; + } + else { + if (element.nodeName == 'P' && util.getInternetExplorerVersion() != -1) { + // On Internet Explorer, a
with hasChildNodes()==false is + // rendered with a new line. Note that a
with
+ // hasChildNodes()==true is rendered without a new line
+ // Other browsers always ensure there is a
inside the
, + // and if not, the
does not render a new line + return buffer.flush(); + } + } + + // br or unknown + return ''; }; /** @@ -5905,21 +5905,21 @@ util.getInnerText = function getInnerText(element, buffer) { * @return {Number} Internet Explorer version, or -1 in case of an other browser */ util.getInternetExplorerVersion = function getInternetExplorerVersion() { - if (_ieVersion == -1) { - var rv = -1; // Return value assumes failure. - if (navigator.appName == 'Microsoft Internet Explorer') - { - var ua = navigator.userAgent; - var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})"); - if (re.exec(ua) != null) { - rv = parseFloat( RegExp.$1 ); - } - } - - _ieVersion = rv; + if (_ieVersion == -1) { + var rv = -1; // Return value assumes failure. + if (navigator.appName == 'Microsoft Internet Explorer') + { + var ua = navigator.userAgent; + var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})"); + if (re.exec(ua) != null) { + rv = parseFloat( RegExp.$1 ); + } } - return _ieVersion; + _ieVersion = rv; + } + + return _ieVersion; }; /** @@ -5947,19 +5947,19 @@ var _ieVersion = -1; * @return {function} the created event listener */ util.addEventListener = function addEventListener(element, action, listener, useCapture) { - if (element.addEventListener) { - if (useCapture === undefined) - useCapture = false; + if (element.addEventListener) { + if (useCapture === undefined) + useCapture = false; - if (action === "mousewheel" && util.isFirefox()) { - action = "DOMMouseScroll"; // For Firefox - } - - element.addEventListener(action, listener, useCapture); - return listener; - } else { - throw new Error('missing function addEventListener'); + if (action === "mousewheel" && util.isFirefox()) { + action = "DOMMouseScroll"; // For Firefox } + + element.addEventListener(action, listener, useCapture); + return listener; + } else { + throw new Error('missing function addEventListener'); + } }; /** @@ -5970,77 +5970,77 @@ util.addEventListener = function addEventListener(element, action, listener, use * @param {boolean} [useCapture] false by default */ util.removeEventListener = function removeEventListener(element, action, listener, useCapture) { - if (element.removeEventListener) { - if (useCapture === undefined) - useCapture = false; + if (element.removeEventListener) { + if (useCapture === undefined) + useCapture = false; - if (action === "mousewheel" && util.isFirefox()) { - action = "DOMMouseScroll"; // For Firefox - } - - element.removeEventListener(action, listener, useCapture); - } else { - throw new Error('missing function removeEventListener'); + if (action === "mousewheel" && util.isFirefox()) { + action = "DOMMouseScroll"; // For Firefox } + + element.removeEventListener(action, listener, useCapture); + } else { + throw new Error('missing function removeEventListener'); + } }; // module exports var jsoneditor = { - 'JSONEditor': JSONEditor, - 'JSONFormatter': function () { - throw new Error('JSONFormatter is deprecated. ' + - 'Use JSONEditor with mode "text" or "code" instead'); - }, - 'util': util + 'JSONEditor': JSONEditor, + 'JSONFormatter': function () { + throw new Error('JSONFormatter is deprecated. ' + + 'Use JSONEditor with mode "text" or "code" instead'); + }, + 'util': util }; /** * load jsoneditor.css */ var loadCss = function () { - // find the script named 'jsoneditor.js' or 'jsoneditor-min.js' or - // 'jsoneditor.min.js', and use its path to find the css file to be - // loaded. - var scripts = document.getElementsByTagName('script'); - for (var s = 0; s < scripts.length; s++) { - var src = scripts[s].src; - if (/(^|\/)jsoneditor([-\.]min)?.js$/.test(src)) { - var jsFile = src.split('?')[0]; - var cssFile = jsFile.substring(0, jsFile.length - 2) + 'css'; + // find the script named 'jsoneditor.js' or 'jsoneditor-min.js' or + // 'jsoneditor.min.js', and use its path to find the css file to be + // loaded. + var scripts = document.getElementsByTagName('script'); + for (var s = 0; s < scripts.length; s++) { + var src = scripts[s].src; + if (/(^|\/)jsoneditor([-\.]min)?.js$/.test(src)) { + var jsFile = src.split('?')[0]; + var cssFile = jsFile.substring(0, jsFile.length - 2) + 'css'; - // load css file - var link = document.createElement('link'); - link.type = 'text/css'; - link.rel = 'stylesheet'; - link.href = cssFile; - document.getElementsByTagName('head')[0].appendChild(link); + // load css file + var link = document.createElement('link'); + link.type = 'text/css'; + link.rel = 'stylesheet'; + link.href = cssFile; + document.getElementsByTagName('head')[0].appendChild(link); - break; - } + break; } + } }; /** * CommonJS module exports */ if (typeof(module) != 'undefined' && typeof(exports) != 'undefined') { - loadCss(); - module.exports = exports = jsoneditor; + loadCss(); + module.exports = exports = jsoneditor; } /** * AMD module exports */ if (typeof(require) != 'undefined' && typeof(define) != 'undefined') { - loadCss(); - define(function () { - return jsoneditor; - }); + loadCss(); + define(function () { + return jsoneditor; + }); } else { - // attach the module to the window, load as a regular javascript file - window['jsoneditor'] = jsoneditor; + // attach the module to the window, load as a regular javascript file + window['jsoneditor'] = jsoneditor; } diff --git a/jsoneditor/css/contextmenu.css b/jsoneditor/css/contextmenu.css index d916037..3cd9661 100644 --- a/jsoneditor/css/contextmenu.css +++ b/jsoneditor/css/contextmenu.css @@ -2,81 +2,81 @@ /* ContextMenu - main menu */ .jsoneditor-contextmenu { - position: fixed; - z-index: 99999; + position: fixed; + z-index: 99999; } .jsoneditor-contextmenu ul { - position: relative; - left: 0; - top: 0; - width: 124px; + position: relative; + left: 0; + top: 0; + width: 124px; - background: white; - border: 1px solid #d3d3d3; - box-shadow: 2px 2px 12px rgba(128, 128, 128, 0.3); + background: white; + border: 1px solid #d3d3d3; + box-shadow: 2px 2px 12px rgba(128, 128, 128, 0.3); - list-style: none; - margin: 0; - padding: 0; + list-style: none; + margin: 0; + padding: 0; } .jsoneditor-contextmenu ul li button { - padding: 0; - margin: 0; - width: 124px; - height: 24px; - border: none; - cursor: pointer; - color: #4d4d4d; - background: transparent; + padding: 0; + margin: 0; + width: 124px; + height: 24px; + border: none; + cursor: pointer; + color: #4d4d4d; + background: transparent; - line-height: 26px; - text-align: left; + line-height: 26px; + text-align: left; } /* Fix button padding in firefox */ .jsoneditor-contextmenu ul li button::-moz-focus-inner { - padding: 0; - border: 0; + padding: 0; + border: 0; } .jsoneditor-contextmenu ul li button:hover, .jsoneditor-contextmenu ul li button:focus { - color: #1a1a1a; - background-color: #f5f5f5; - outline: none; + color: #1a1a1a; + background-color: #f5f5f5; + outline: none; } .jsoneditor-contextmenu ul li button.default { - width: 92px; + width: 92px; } .jsoneditor-contextmenu ul li button.expand { - float: right; - width: 32px; - height: 24px; - border-left: 1px solid #e5e5e5; + float: right; + width: 32px; + height: 24px; + border-left: 1px solid #e5e5e5; } .jsoneditor-contextmenu div.icon { - float: left; - width: 24px; - height: 24px; - border: none; - padding: 0; - margin: 0; - background-image: url('img/jsoneditor-icons.png'); + float: left; + width: 24px; + height: 24px; + border: none; + padding: 0; + margin: 0; + background-image: url('img/jsoneditor-icons.png'); } .jsoneditor-contextmenu ul li button div.expand { - float: right; - width: 24px; - height: 24px; - padding: 0; - margin: 0 4px 0 0; - background: url('img/jsoneditor-icons.png') 0 -72px; - opacity: 0.4; + float: right; + width: 24px; + height: 24px; + padding: 0; + margin: 0 4px 0 0; + background: url('img/jsoneditor-icons.png') 0 -72px; + opacity: 0.4; } .jsoneditor-contextmenu ul li button:hover div.expand, @@ -84,141 +84,141 @@ .jsoneditor-contextmenu ul li.selected div.expand, .jsoneditor-contextmenu ul li button.expand:hover div.expand, .jsoneditor-contextmenu ul li button.expand:focus div.expand { - opacity: 1; + opacity: 1; } .jsoneditor-contextmenu .separator { - height: 0; - border-top: 1px solid #e5e5e5; - padding-top: 5px; - margin-top: 5px; + height: 0; + border-top: 1px solid #e5e5e5; + padding-top: 5px; + margin-top: 5px; } .jsoneditor-contextmenu button.remove > .icon { - background-position: -24px -24px; + background-position: -24px -24px; } .jsoneditor-contextmenu button.remove:hover > .icon, .jsoneditor-contextmenu button.remove:focus > .icon { - background-position: -24px 0; + background-position: -24px 0; } .jsoneditor-contextmenu button.append > .icon { - background-position: 0 -24px; + background-position: 0 -24px; } .jsoneditor-contextmenu button.append:hover > .icon, .jsoneditor-contextmenu button.append:focus > .icon { - background-position: 0 0; + background-position: 0 0; } .jsoneditor-contextmenu button.insert > .icon { - background-position: 0 -24px; + background-position: 0 -24px; } .jsoneditor-contextmenu button.insert:hover > .icon, .jsoneditor-contextmenu button.insert:focus > .icon { - background-position: 0 0; + background-position: 0 0; } .jsoneditor-contextmenu button.duplicate > .icon { - background-position: -48px -24px; + background-position: -48px -24px; } .jsoneditor-contextmenu button.duplicate:hover > .icon, .jsoneditor-contextmenu button.duplicate:focus > .icon { - background-position: -48px 0; + background-position: -48px 0; } .jsoneditor-contextmenu button.sort-asc > .icon { - background-position: -168px -24px; + background-position: -168px -24px; } .jsoneditor-contextmenu button.sort-asc:hover > .icon, .jsoneditor-contextmenu button.sort-asc:focus > .icon { - background-position: -168px 0; + background-position: -168px 0; } .jsoneditor-contextmenu button.sort-desc > .icon { - background-position: -192px -24px; + background-position: -192px -24px; } .jsoneditor-contextmenu button.sort-desc:hover > .icon, .jsoneditor-contextmenu button.sort-desc:focus > .icon { - background-position: -192px 0; + background-position: -192px 0; } /* ContextMenu - sub menu */ .jsoneditor-contextmenu ul li .selected { - background-color: #D5DDF6; + background-color: #D5DDF6; } .jsoneditor-contextmenu ul li { - overflow: hidden; + overflow: hidden; } .jsoneditor-contextmenu ul li ul { - display: none; - position: relative; - left: -10px; - top: 0; + display: none; + position: relative; + left: -10px; + top: 0; - border: none; - box-shadow: inset 0 0 10px rgba(128, 128, 128, 0.5); - padding: 0 10px; + border: none; + box-shadow: inset 0 0 10px rgba(128, 128, 128, 0.5); + padding: 0 10px; - /* TODO: transition is not supported on IE8-9 */ - -webkit-transition: all 0.3s ease-out; - -moz-transition: all 0.3s ease-out; - -o-transition: all 0.3s ease-out; - transition: all 0.3s ease-out; + /* TODO: transition is not supported on IE8-9 */ + -webkit-transition: all 0.3s ease-out; + -moz-transition: all 0.3s ease-out; + -o-transition: all 0.3s ease-out; + transition: all 0.3s ease-out; } .jsoneditor-contextmenu ul li.selected ul { } .jsoneditor-contextmenu ul li ul li button { - padding-left: 24px; + padding-left: 24px; } .jsoneditor-contextmenu ul li ul li button:hover, .jsoneditor-contextmenu ul li ul li button:focus { - background-color: #f5f5f5; + background-color: #f5f5f5; } .jsoneditor-contextmenu button.type-string > .icon { - background-position: -144px -24px; + background-position: -144px -24px; } .jsoneditor-contextmenu button.type-string:hover > .icon, .jsoneditor-contextmenu button.type-string:focus > .icon, .jsoneditor-contextmenu button.type-string.selected > .icon{ - background-position: -144px 0; + background-position: -144px 0; } .jsoneditor-contextmenu button.type-auto > .icon { - background-position: -120px -24px; + background-position: -120px -24px; } .jsoneditor-contextmenu button.type-auto:hover > .icon, .jsoneditor-contextmenu button.type-auto:focus > .icon, .jsoneditor-contextmenu button.type-auto.selected > .icon { - background-position: -120px 0; + background-position: -120px 0; } .jsoneditor-contextmenu button.type-object > .icon { - background-position: -72px -24px; + background-position: -72px -24px; } .jsoneditor-contextmenu button.type-object:hover > .icon, .jsoneditor-contextmenu button.type-object:focus > .icon, .jsoneditor-contextmenu button.type-object.selected > .icon{ - background-position: -72px 0; + background-position: -72px 0; } .jsoneditor-contextmenu button.type-array > .icon { - background-position: -96px -24px; + background-position: -96px -24px; } .jsoneditor-contextmenu button.type-array:hover > .icon, .jsoneditor-contextmenu button.type-array:focus > .icon, .jsoneditor-contextmenu button.type-array.selected > .icon{ - background-position: -96px 0; + background-position: -96px 0; } .jsoneditor-contextmenu button.type-modes > .icon { - background-image: none; - width: 6px; + background-image: none; + width: 6px; } diff --git a/jsoneditor/css/jsoneditor.css b/jsoneditor/css/jsoneditor.css index a0a9e86..50ddc91 100644 --- a/jsoneditor/css/jsoneditor.css +++ b/jsoneditor/css/jsoneditor.css @@ -2,60 +2,60 @@ .jsoneditor .field, .jsoneditor .value, .jsoneditor .readonly { - border: 1px solid transparent; - min-height: 16px; - min-width: 32px; - padding: 2px; - margin: 1px; - word-wrap: break-word; - float: left; + border: 1px solid transparent; + min-height: 16px; + min-width: 32px; + padding: 2px; + margin: 1px; + word-wrap: break-word; + float: left; } /* adjust margin of p elements inside editable divs, needed for Opera, IE */ .jsoneditor .field p, .jsoneditor .value p { - margin: 0; + margin: 0; } .jsoneditor .value { - word-break: break-word; + word-break: break-word; } .jsoneditor .readonly { - min-width: 16px; - color: gray; + min-width: 16px; + color: gray; } .jsoneditor .empty { - border-color: lightgray; - border-style: dashed; - border-radius: 2px; + border-color: lightgray; + border-style: dashed; + border-radius: 2px; } .jsoneditor .field.empty { - background-image: url('img/jsoneditor-icons.png'); - background-position: 0 -144px; + background-image: url('img/jsoneditor-icons.png'); + background-position: 0 -144px; } .jsoneditor .value.empty { - background-image: url('img/jsoneditor-icons.png'); - background-position: -48px -144px; + background-image: url('img/jsoneditor-icons.png'); + background-position: -48px -144px; } .jsoneditor .value.url { - color: green; - text-decoration: underline; + color: green; + text-decoration: underline; } .jsoneditor a.value.url:hover, .jsoneditor a.value.url:focus { - color: red; + color: red; } .jsoneditor .separator { - padding: 3px 0; - vertical-align: top; - color: gray; + padding: 3px 0; + vertical-align: top; + color: gray; } .jsoneditor .field[contenteditable=true]:focus, @@ -64,9 +64,9 @@ .jsoneditor .value[contenteditable=true]:hover, .jsoneditor .field.highlight, .jsoneditor .value.highlight { - background-color: #FFFFAB; - border: 1px solid yellow; - border-radius: 2px; + background-color: #FFFFAB; + border: 1px solid yellow; + border-radius: 2px; } .jsoneditor .field.highlight-active, @@ -75,141 +75,141 @@ .jsoneditor .value.highlight-active, .jsoneditor .value.highlight-active:focus, .jsoneditor .value.highlight-active:hover { - background-color: #ffee00; - border: 1px solid #ffc700; - border-radius: 2px; + background-color: #ffee00; + border: 1px solid #ffc700; + border-radius: 2px; } .jsoneditor div.tree button { - width: 24px; - height: 24px; - padding: 0; - margin: 0; - border: none; - cursor: pointer; - background: transparent url('img/jsoneditor-icons.png'); + width: 24px; + height: 24px; + padding: 0; + margin: 0; + border: none; + cursor: pointer; + background: transparent url('img/jsoneditor-icons.png'); } .jsoneditor div.tree button.collapsed { - background-position: 0 -48px; + background-position: 0 -48px; } .jsoneditor div.tree button.expanded { - background-position: 0 -72px; + background-position: 0 -72px; } .jsoneditor div.tree button.contextmenu { - background-position: -48px -72px; + background-position: -48px -72px; } .jsoneditor div.tree button.contextmenu:hover, .jsoneditor div.tree button.contextmenu:focus, .jsoneditor div.tree button.contextmenu.selected { - background-position: -48px -48px; + background-position: -48px -48px; } .jsoneditor div.tree *:focus { - outline: none; + outline: none; } .jsoneditor div.tree button:focus { - /* TODO: nice outline for buttons with focus - outline: #97B0F8 solid 2px; - box-shadow: 0 0 8px #97B0F8; - */ - background-color: #f5f5f5; - outline: #e5e5e5 solid 1px; + /* TODO: nice outline for buttons with focus + outline: #97B0F8 solid 2px; + box-shadow: 0 0 8px #97B0F8; + */ + background-color: #f5f5f5; + outline: #e5e5e5 solid 1px; } .jsoneditor div.tree button.invisible { - visibility: hidden; - background: none; + visibility: hidden; + background: none; } .jsoneditor { - color: #1A1A1A; - border: 1px solid #97B0F8; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; + color: #1A1A1A; + border: 1px solid #97B0F8; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; - width: 100%; - height: 100%; - overflow: auto; - position: relative; - padding: 0; - line-height: 100%; + width: 100%; + height: 100%; + overflow: auto; + position: relative; + padding: 0; + line-height: 100%; } .jsoneditor div.tree table.tree { - border-collapse: collapse; - border-spacing: 0; - width: 100%; - margin: 0; + border-collapse: collapse; + border-spacing: 0; + width: 100%; + margin: 0; } .jsoneditor div.outer { - width: 100%; - height: 100%; - margin: -35px 0 0 0; - padding: 35px 0 0 0; + width: 100%; + height: 100%; + margin: -35px 0 0 0; + padding: 35px 0 0 0; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; - overflow: hidden; + overflow: hidden; } .jsoneditor div.tree { - width: 100%; - height: 100%; - position: relative; - overflow: auto; + width: 100%; + height: 100%; + position: relative; + overflow: auto; } .jsoneditor textarea.text { - width: 100%; - height: 100%; - margin: 0; + width: 100%; + height: 100%; + margin: 0; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; - border: none; - background-color: white; - resize: none; + border: none; + background-color: white; + resize: none; } .jsoneditor tr.highlight { - background-color: #FFFFAB; + background-color: #FFFFAB; } .jsoneditor div.tree button.dragarea { - background: url('img/jsoneditor-icons.png') -72px -72px; - cursor: move; + background: url('img/jsoneditor-icons.png') -72px -72px; + cursor: move; } .jsoneditor div.tree button.dragarea:hover, .jsoneditor div.tree button.dragarea:focus { - background-position: -72px -48px; + background-position: -72px -48px; } .jsoneditor tr, .jsoneditor th, .jsoneditor td { - padding: 0; - margin: 0; + padding: 0; + margin: 0; } .jsoneditor td { - vertical-align: top; + vertical-align: top; } .jsoneditor td.tree { - vertical-align: top; + vertical-align: top; } .jsoneditor .field, @@ -217,7 +217,7 @@ .jsoneditor td, .jsoneditor th, .jsoneditor textarea { - font-family: droid sans mono, monospace, courier new, courier, sans-serif; - font-size: 10pt; - color: #1A1A1A; + font-family: droid sans mono, monospace, courier new, courier, sans-serif; + font-size: 10pt; + color: #1A1A1A; } diff --git a/jsoneditor/css/menu.css b/jsoneditor/css/menu.css index 510997c..67096ef 100644 --- a/jsoneditor/css/menu.css +++ b/jsoneditor/css/menu.css @@ -1,99 +1,99 @@ .jsoneditor .menu { - width: 100%; - height: 35px; - padding: 2px; - margin: 0; - overflow: hidden; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; + width: 100%; + height: 35px; + padding: 2px; + margin: 0; + overflow: hidden; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; - color: #1A1A1A; - background-color: #D5DDF6; - border-bottom: 1px solid #97B0F8; + color: #1A1A1A; + background-color: #D5DDF6; + border-bottom: 1px solid #97B0F8; } .jsoneditor .menu button { - width: 26px; - height: 26px; - margin: 2px; - padding: 0; - border-radius: 2px; - border: 1px solid #aec0f8; - background: #e3eaf6 url('img/jsoneditor-icons.png'); - color: #4D4D4D; - opacity: 0.8; + width: 26px; + height: 26px; + margin: 2px; + padding: 0; + border-radius: 2px; + border: 1px solid #aec0f8; + background: #e3eaf6 url('img/jsoneditor-icons.png'); + color: #4D4D4D; + opacity: 0.8; - font-family: arial, sans-serif; - font-size: 10pt; + font-family: arial, sans-serif; + font-size: 10pt; - float: left; + float: left; } .jsoneditor .menu button:hover { - background-color: #f0f2f5; + background-color: #f0f2f5; } .jsoneditor .menu button:active { - background-color: #ffffff; + background-color: #ffffff; } .jsoneditor .menu button:disabled { - background-color: #e3eaf6; + background-color: #e3eaf6; } .jsoneditor .menu button.collapse-all { - background-position: 0 -96px; + background-position: 0 -96px; } .jsoneditor .menu button.expand-all { - background-position: 0 -120px; + background-position: 0 -120px; } .jsoneditor .menu button.undo { - background-position: -24px -96px; + background-position: -24px -96px; } .jsoneditor .menu button.undo:disabled { - background-position: -24px -120px; + background-position: -24px -120px; } .jsoneditor .menu button.redo { - background-position: -48px -96px; + background-position: -48px -96px; } .jsoneditor .menu button.redo:disabled { - background-position: -48px -120px; + background-position: -48px -120px; } .jsoneditor .menu button.compact { - background-position: -72px -96px; + background-position: -72px -96px; } .jsoneditor .menu button.format { - background-position: -72px -120px; + background-position: -72px -120px; } .jsoneditor .menu button.modes { - background-image: none; - width: auto; - padding-left: 6px; - padding-right: 6px; + background-image: none; + width: auto; + padding-left: 6px; + padding-right: 6px; } .jsoneditor .menu button.separator { - margin-left: 10px; + margin-left: 10px; } .jsoneditor .menu a { - font-family: arial, sans-serif; - font-size: 10pt; - color: #97B0F8; - vertical-align: middle; + font-family: arial, sans-serif; + font-size: 10pt; + color: #97B0F8; + vertical-align: middle; } .jsoneditor .menu a:hover { - color: red; + color: red; } .jsoneditor .menu a.poweredBy { - font-size: 8pt; - position: absolute; - right: 0; - top: 0; - padding: 10px; + font-size: 8pt; + position: absolute; + right: 0; + top: 0; + padding: 10px; } /* TODO: css for button:disabled is not supported by IE8 */ diff --git a/jsoneditor/css/searchbox.css b/jsoneditor/css/searchbox.css index 3a2e95c..8ba1e51 100644 --- a/jsoneditor/css/searchbox.css +++ b/jsoneditor/css/searchbox.css @@ -1,73 +1,73 @@ .jsoneditor .search input, .jsoneditor .search .results { - font-family: arial, sans-serif; - font-size: 10pt; - color: #1A1A1A; + font-family: arial, sans-serif; + font-size: 10pt; + color: #1A1A1A; } .jsoneditor .search { - position: absolute; - right: 2px; - top: 2px; + position: absolute; + right: 2px; + top: 2px; } .jsoneditor .search .frame { - border: 1px solid #97B0F8; - background-color: white; - padding: 0 2px; - margin: 0; + border: 1px solid #97B0F8; + background-color: white; + padding: 0 2px; + margin: 0; } .jsoneditor .search .frame table { - border-collapse: collapse; + border-collapse: collapse; } .jsoneditor .search input { - width: 120px; - border: none; - outline: none; - margin: 1px; + width: 120px; + border: none; + outline: none; + margin: 1px; } .jsoneditor .search .results { - color: #4d4d4d; - padding-right: 5px; - line-height: 24px; + color: #4d4d4d; + padding-right: 5px; + line-height: 24px; } .jsoneditor .search button { - width: 16px; - height: 24px; - padding: 0; - margin: 0; - border: none; - background: url('img/jsoneditor-icons.png'); - vertical-align: top; + width: 16px; + height: 24px; + padding: 0; + margin: 0; + border: none; + background: url('img/jsoneditor-icons.png'); + vertical-align: top; } .jsoneditor .search button:hover { - background-color: transparent; + background-color: transparent; } .jsoneditor .search button.refresh { - width: 18px; - background-position: -99px -73px; + width: 18px; + background-position: -99px -73px; } .jsoneditor .search button.next { - cursor: pointer; - background-position: -124px -73px; + cursor: pointer; + background-position: -124px -73px; } .jsoneditor .search button.next:hover { - background-position: -124px -49px; + background-position: -124px -49px; } .jsoneditor .search button.previous { - cursor: pointer; - background-position: -148px -73px; - margin-right: 2px; + cursor: pointer; + background-position: -148px -73px; + margin-right: 2px; } .jsoneditor .search button.previous:hover { - background-position: -148px -49px; + background-position: -148px -49px; } diff --git a/jsoneditor/js/appendnode.js b/jsoneditor/js/appendnode.js index f4309c5..f3d796d 100644 --- a/jsoneditor/js/appendnode.js +++ b/jsoneditor/js/appendnode.js @@ -6,9 +6,9 @@ * end of the list with childs for an object or array */ function AppendNode (editor) { - /** @type {TreeEditor} */ - this.editor = editor; - this.dom = {}; + /** @type {TreeEditor} */ + this.editor = editor; + this.dom = {}; } AppendNode.prototype = new Node(); @@ -18,89 +18,89 @@ AppendNode.prototype = new Node(); * @return {Element} dom TR element */ AppendNode.prototype.getDom = function () { - // TODO: implement a new solution for the append node - var dom = this.dom; + // TODO: implement a new solution for the append node + var dom = this.dom; - if (dom.tr) { - return dom.tr; - } + if (dom.tr) { + return dom.tr; + } - // a row for the append button - var trAppend = document.createElement('tr'); - trAppend.node = this; - dom.tr = trAppend; + // a row for the append button + var trAppend = document.createElement('tr'); + trAppend.node = this; + dom.tr = trAppend; - // TODO: consistent naming + // TODO: consistent naming - if (this.editor.mode.edit) { - // a cell for the dragarea column - dom.tdDrag = document.createElement('td'); + if (this.editor.mode.edit) { + // a cell for the dragarea column + dom.tdDrag = document.createElement('td'); - // create context menu - var tdMenu = document.createElement('td'); - dom.tdMenu = tdMenu; - var menu = document.createElement('button'); - menu.className = 'contextmenu'; - menu.title = 'Click to open the actions menu (Ctrl+M)'; - dom.menu = menu; - tdMenu.appendChild(dom.menu); - } + // create context menu + var tdMenu = document.createElement('td'); + dom.tdMenu = tdMenu; + var menu = document.createElement('button'); + menu.className = 'contextmenu'; + menu.title = 'Click to open the actions menu (Ctrl+M)'; + dom.menu = menu; + tdMenu.appendChild(dom.menu); + } - // a cell for the contents (showing text 'empty') - var tdAppend = document.createElement('td'); - var domText = document.createElement('div'); - domText.innerHTML = '(empty)'; - domText.className = 'readonly'; - tdAppend.appendChild(domText); - dom.td = tdAppend; - dom.text = domText; + // a cell for the contents (showing text 'empty') + var tdAppend = document.createElement('td'); + var domText = document.createElement('div'); + domText.innerHTML = '(empty)'; + domText.className = 'readonly'; + tdAppend.appendChild(domText); + dom.td = tdAppend; + dom.text = domText; - this.updateDom(); + this.updateDom(); - return trAppend; + return trAppend; }; /** * Update the HTML dom of the Node */ AppendNode.prototype.updateDom = function () { - var dom = this.dom; - var tdAppend = dom.td; - if (tdAppend) { - tdAppend.style.paddingLeft = (this.getLevel() * 24 + 26) + 'px'; - // TODO: not so nice hard coded offset - } + var dom = this.dom; + var tdAppend = dom.td; + if (tdAppend) { + tdAppend.style.paddingLeft = (this.getLevel() * 24 + 26) + 'px'; + // TODO: not so nice hard coded offset + } - var domText = dom.text; - if (domText) { - domText.innerHTML = '(empty ' + this.parent.type + ')'; - } + var domText = dom.text; + if (domText) { + domText.innerHTML = '(empty ' + this.parent.type + ')'; + } - // attach or detach the contents of the append node: - // hide when the parent has childs, show when the parent has no childs - var trAppend = dom.tr; - if (!this.isVisible()) { - if (dom.tr.firstChild) { - if (dom.tdDrag) { - trAppend.removeChild(dom.tdDrag); - } - if (dom.tdMenu) { - trAppend.removeChild(dom.tdMenu); - } - trAppend.removeChild(tdAppend); - } + // attach or detach the contents of the append node: + // hide when the parent has childs, show when the parent has no childs + var trAppend = dom.tr; + if (!this.isVisible()) { + if (dom.tr.firstChild) { + if (dom.tdDrag) { + trAppend.removeChild(dom.tdDrag); + } + if (dom.tdMenu) { + trAppend.removeChild(dom.tdMenu); + } + trAppend.removeChild(tdAppend); } - else { - if (!dom.tr.firstChild) { - if (dom.tdDrag) { - trAppend.appendChild(dom.tdDrag); - } - if (dom.tdMenu) { - trAppend.appendChild(dom.tdMenu); - } - trAppend.appendChild(tdAppend); - } + } + else { + if (!dom.tr.firstChild) { + if (dom.tdDrag) { + trAppend.appendChild(dom.tdDrag); + } + if (dom.tdMenu) { + trAppend.appendChild(dom.tdMenu); + } + trAppend.appendChild(tdAppend); } + } }; /** @@ -109,7 +109,7 @@ AppendNode.prototype.updateDom = function () { * @return {boolean} isVisible */ AppendNode.prototype.isVisible = function () { - return (this.parent.childs.length == 0); + return (this.parent.childs.length == 0); }; /** @@ -119,57 +119,57 @@ AppendNode.prototype.isVisible = function () { * is being closed. */ AppendNode.prototype.showContextMenu = function (anchor, onClose) { - var node = this; - var titles = Node.TYPE_TITLES; - var items = [ - // create append button + var node = this; + var titles = Node.TYPE_TITLES; + var items = [ + // create append button + { + 'text': 'Append', + 'title': 'Append a new field with type \'auto\' (Ctrl+Shift+Ins)', + 'submenuTitle': 'Select the type of the field to be appended', + 'className': 'insert', + 'click': function () { + node._onAppend('', '', 'auto'); + }, + 'submenu': [ { - 'text': 'Append', - 'title': 'Append a new field with type \'auto\' (Ctrl+Shift+Ins)', - 'submenuTitle': 'Select the type of the field to be appended', - 'className': 'insert', - 'click': function () { - node._onAppend('', '', 'auto'); - }, - 'submenu': [ - { - 'text': 'Auto', - 'className': 'type-auto', - 'title': titles.auto, - 'click': function () { - node._onAppend('', '', 'auto'); - } - }, - { - 'text': 'Array', - 'className': 'type-array', - 'title': titles.array, - 'click': function () { - node._onAppend('', []); - } - }, - { - 'text': 'Object', - 'className': 'type-object', - 'title': titles.object, - 'click': function () { - node._onAppend('', {}); - } - }, - { - 'text': 'String', - 'className': 'type-string', - 'title': titles.string, - 'click': function () { - node._onAppend('', '', 'string'); - } - } - ] + 'text': 'Auto', + 'className': 'type-auto', + 'title': titles.auto, + 'click': function () { + node._onAppend('', '', 'auto'); + } + }, + { + 'text': 'Array', + 'className': 'type-array', + 'title': titles.array, + 'click': function () { + node._onAppend('', []); + } + }, + { + 'text': 'Object', + 'className': 'type-object', + 'title': titles.object, + 'click': function () { + node._onAppend('', {}); + } + }, + { + 'text': 'String', + 'className': 'type-string', + 'title': titles.string, + 'click': function () { + node._onAppend('', '', 'string'); + } } - ]; + ] + } + ]; - var menu = new ContextMenu(items, {close: onClose}); - menu.show(anchor); + var menu = new ContextMenu(items, {close: onClose}); + menu.show(anchor); }; /** @@ -177,35 +177,35 @@ AppendNode.prototype.showContextMenu = function (anchor, onClose) { * @param {Event} event */ AppendNode.prototype.onEvent = function (event) { - var type = event.type; - var target = event.target || event.srcElement; - var dom = this.dom; + var type = event.type; + var target = event.target || event.srcElement; + var dom = this.dom; - // highlight the append nodes parent - var menu = dom.menu; - if (target == menu) { - if (type == 'mouseover') { - this.editor.highlighter.highlight(this.parent); - } - else if (type == 'mouseout') { - this.editor.highlighter.unhighlight(); - } + // highlight the append nodes parent + var menu = dom.menu; + if (target == menu) { + if (type == 'mouseover') { + this.editor.highlighter.highlight(this.parent); } + else if (type == 'mouseout') { + this.editor.highlighter.unhighlight(); + } + } - // context menu events - if (type == 'click' && target == dom.menu) { - var highlighter = this.editor.highlighter; - highlighter.highlight(this.parent); - highlighter.lock(); - util.addClassName(dom.menu, 'selected'); - this.showContextMenu(dom.menu, function () { - util.removeClassName(dom.menu, 'selected'); - highlighter.unlock(); - highlighter.unhighlight(); - }); - } + // context menu events + if (type == 'click' && target == dom.menu) { + var highlighter = this.editor.highlighter; + highlighter.highlight(this.parent); + highlighter.lock(); + util.addClassName(dom.menu, 'selected'); + this.showContextMenu(dom.menu, function () { + util.removeClassName(dom.menu, 'selected'); + highlighter.unlock(); + highlighter.unhighlight(); + }); + } - if (type == 'keydown') { - this.onKeyDown(event); - } + if (type == 'keydown') { + this.onKeyDown(event); + } }; diff --git a/jsoneditor/js/contextmenu.js b/jsoneditor/js/contextmenu.js index a04f55c..90a0393 100644 --- a/jsoneditor/js/contextmenu.js +++ b/jsoneditor/js/contextmenu.js @@ -8,138 +8,138 @@ * @constructor */ function ContextMenu (items, options) { - this.dom = {}; + this.dom = {}; - var me = this; - var dom = this.dom; - this.anchor = undefined; - this.items = items; - this.eventListeners = {}; - this.selection = undefined; // holds the selection before the menu was opened - this.visibleSubmenu = undefined; - this.onClose = options ? options.close : undefined; + var me = this; + var dom = this.dom; + this.anchor = undefined; + this.items = items; + this.eventListeners = {}; + this.selection = undefined; // holds the selection before the menu was opened + this.visibleSubmenu = undefined; + this.onClose = options ? options.close : undefined; - // create a container element - var menu = document.createElement('div'); - menu.className = 'jsoneditor-contextmenu'; - dom.menu = menu; + // create a container element + var menu = document.createElement('div'); + menu.className = 'jsoneditor-contextmenu'; + dom.menu = menu; - // create a list to hold the menu items - var list = document.createElement('ul'); - list.className = 'menu'; - menu.appendChild(list); - dom.list = list; - dom.items = []; // list with all buttons + // create a list to hold the menu items + var list = document.createElement('ul'); + list.className = 'menu'; + menu.appendChild(list); + dom.list = list; + dom.items = []; // list with all buttons - // create a (non-visible) button to set the focus to the menu - var focusButton = document.createElement('button'); - dom.focusButton = focusButton; - var li = document.createElement('li'); - li.style.overflow = 'hidden'; - li.style.height = '0'; - li.appendChild(focusButton); - list.appendChild(li); + // create a (non-visible) button to set the focus to the menu + var focusButton = document.createElement('button'); + dom.focusButton = focusButton; + var li = document.createElement('li'); + li.style.overflow = 'hidden'; + li.style.height = '0'; + li.appendChild(focusButton); + list.appendChild(li); - function createMenuItems (list, domItems, items) { - items.forEach(function (item) { - if (item.type == 'separator') { - // create a separator - var separator = document.createElement('div'); - separator.className = 'separator'; - li = document.createElement('li'); - li.appendChild(separator); - list.appendChild(li); - } - else { - var domItem = {}; - - // create a menu item - var li = document.createElement('li'); - list.appendChild(li); - - // create a button in the menu item - var button = document.createElement('button'); - button.className = item.className; - domItem.button = button; - if (item.title) { - button.title = item.title; - } - if (item.click) { - button.onclick = function () { - me.hide(); - item.click(); - }; - } - li.appendChild(button); - - // create the contents of the button - if (item.submenu) { - // add the icon to the button - var divIcon = document.createElement('div'); - divIcon.className = 'icon'; - button.appendChild(divIcon); - button.appendChild(document.createTextNode(item.text)); - - var buttonSubmenu; - if (item.click) { - // submenu and a button with a click handler - button.className += ' default'; - - var buttonExpand = document.createElement('button'); - domItem.buttonExpand = buttonExpand; - buttonExpand.className = 'expand'; - buttonExpand.innerHTML = '
'; - li.appendChild(buttonExpand); - if (item.submenuTitle) { - buttonExpand.title = item.submenuTitle; - } - - buttonSubmenu = buttonExpand; - } - else { - // submenu and a button without a click handler - var divExpand = document.createElement('div'); - divExpand.className = 'expand'; - button.appendChild(divExpand); - - buttonSubmenu = button; - } - - // attach a handler to expand/collapse the submenu - buttonSubmenu.onclick = function () { - me._onExpandItem(domItem); - buttonSubmenu.focus(); - }; - - // create the submenu - var domSubItems = []; - domItem.subItems = domSubItems; - var ul = document.createElement('ul'); - domItem.ul = ul; - ul.className = 'menu'; - ul.style.height = '0'; - li.appendChild(ul); - createMenuItems(ul, domSubItems, item.submenu); - } - else { - // no submenu, just a button with clickhandler - button.innerHTML = '' + item.text; - } - - domItems.push(domItem); - } - }); - } - createMenuItems(list, this.dom.items, items); - - // TODO: when the editor is small, show the submenu on the right instead of inline? - - // calculate the max height of the menu with one submenu expanded - this.maxHeight = 0; // height in pixels + function createMenuItems (list, domItems, items) { items.forEach(function (item) { - var height = (items.length + (item.submenu ? item.submenu.length : 0)) * 24; - me.maxHeight = Math.max(me.maxHeight, height); + if (item.type == 'separator') { + // create a separator + var separator = document.createElement('div'); + separator.className = 'separator'; + li = document.createElement('li'); + li.appendChild(separator); + list.appendChild(li); + } + else { + var domItem = {}; + + // create a menu item + var li = document.createElement('li'); + list.appendChild(li); + + // create a button in the menu item + var button = document.createElement('button'); + button.className = item.className; + domItem.button = button; + if (item.title) { + button.title = item.title; + } + if (item.click) { + button.onclick = function () { + me.hide(); + item.click(); + }; + } + li.appendChild(button); + + // create the contents of the button + if (item.submenu) { + // add the icon to the button + var divIcon = document.createElement('div'); + divIcon.className = 'icon'; + button.appendChild(divIcon); + button.appendChild(document.createTextNode(item.text)); + + var buttonSubmenu; + if (item.click) { + // submenu and a button with a click handler + button.className += ' default'; + + var buttonExpand = document.createElement('button'); + domItem.buttonExpand = buttonExpand; + buttonExpand.className = 'expand'; + buttonExpand.innerHTML = ''; + li.appendChild(buttonExpand); + if (item.submenuTitle) { + buttonExpand.title = item.submenuTitle; + } + + buttonSubmenu = buttonExpand; + } + else { + // submenu and a button without a click handler + var divExpand = document.createElement('div'); + divExpand.className = 'expand'; + button.appendChild(divExpand); + + buttonSubmenu = button; + } + + // attach a handler to expand/collapse the submenu + buttonSubmenu.onclick = function () { + me._onExpandItem(domItem); + buttonSubmenu.focus(); + }; + + // create the submenu + var domSubItems = []; + domItem.subItems = domSubItems; + var ul = document.createElement('ul'); + domItem.ul = ul; + ul.className = 'menu'; + ul.style.height = '0'; + li.appendChild(ul); + createMenuItems(ul, domSubItems, item.submenu); + } + else { + // no submenu, just a button with clickhandler + button.innerHTML = '' + item.text; + } + + domItems.push(domItem); + } }); + } + createMenuItems(list, this.dom.items, items); + + // TODO: when the editor is small, show the submenu on the right instead of inline? + + // calculate the max height of the menu with one submenu expanded + this.maxHeight = 0; // height in pixels + items.forEach(function (item) { + var height = (items.length + (item.submenu ? item.submenu.length : 0)) * 24; + me.maxHeight = Math.max(me.maxHeight, height); + }); } /** @@ -148,25 +148,25 @@ function ContextMenu (items, options) { * @private */ ContextMenu.prototype._getVisibleButtons = function () { - var buttons = []; - var me = this; - this.dom.items.forEach(function (item) { - buttons.push(item.button); - if (item.buttonExpand) { - buttons.push(item.buttonExpand); + var buttons = []; + var me = this; + this.dom.items.forEach(function (item) { + buttons.push(item.button); + if (item.buttonExpand) { + buttons.push(item.buttonExpand); + } + if (item.subItems && item == me.expandedItem) { + item.subItems.forEach(function (subItem) { + buttons.push(subItem.button); + if (subItem.buttonExpand) { + buttons.push(subItem.buttonExpand); } - if (item.subItems && item == me.expandedItem) { - item.subItems.forEach(function (subItem) { - buttons.push(subItem.button); - if (subItem.buttonExpand) { - buttons.push(subItem.buttonExpand); - } - // TODO: change to fully recursive method - }); - } - }); + // TODO: change to fully recursive method + }); + } + }); - return buttons; + return buttons; }; // currently displayed context menu, a singleton. We may only have one visible context menu @@ -177,96 +177,96 @@ ContextMenu.visibleMenu = undefined; * @param {HTMLElement} anchor */ ContextMenu.prototype.show = function (anchor) { - this.hide(); + this.hide(); - // calculate whether the menu fits below the anchor - var windowHeight = window.innerHeight; - var anchorHeight = anchor.offsetHeight; - var menuHeight = this.maxHeight; + // calculate whether the menu fits below the anchor + var windowHeight = window.innerHeight; + var anchorHeight = anchor.offsetHeight; + var menuHeight = this.maxHeight; - // position the menu - var left = util.getAbsoluteLeft(anchor); - var top = util.getAbsoluteTop(anchor); - if (top + anchorHeight + menuHeight < windowHeight) { - // display the menu below the anchor - this.dom.menu.style.left = left + 'px'; - this.dom.menu.style.top = (top + anchorHeight) + 'px'; - this.dom.menu.style.bottom = ''; - } - else { - // display the menu above the anchor - this.dom.menu.style.left = left + 'px'; - this.dom.menu.style.top = ''; - this.dom.menu.style.bottom = (windowHeight - top) + 'px'; - } + // position the menu + var left = util.getAbsoluteLeft(anchor); + var top = util.getAbsoluteTop(anchor); + if (top + anchorHeight + menuHeight < windowHeight) { + // display the menu below the anchor + this.dom.menu.style.left = left + 'px'; + this.dom.menu.style.top = (top + anchorHeight) + 'px'; + this.dom.menu.style.bottom = ''; + } + else { + // display the menu above the anchor + this.dom.menu.style.left = left + 'px'; + this.dom.menu.style.top = ''; + this.dom.menu.style.bottom = (windowHeight - top) + 'px'; + } - // attach the menu to the document - document.body.appendChild(this.dom.menu); + // attach the menu to the document + document.body.appendChild(this.dom.menu); - // create and attach event listeners - var me = this; - var list = this.dom.list; - this.eventListeners.mousedown = util.addEventListener( - document, 'mousedown', function (event) { - // hide menu on click outside of the menu - var target = event.target; - if ((target != list) && !me._isChildOf(target, list)) { - me.hide(); - event.stopPropagation(); - event.preventDefault(); - } - }); - this.eventListeners.mousewheel = util.addEventListener( - document, 'mousewheel', function (event) { - // block scrolling when context menu is visible - event.stopPropagation(); - event.preventDefault(); - }); - this.eventListeners.keydown = util.addEventListener( - document, 'keydown', function (event) { - me._onKeyDown(event); - }); + // create and attach event listeners + var me = this; + var list = this.dom.list; + this.eventListeners.mousedown = util.addEventListener( + document, 'mousedown', function (event) { + // hide menu on click outside of the menu + var target = event.target; + if ((target != list) && !me._isChildOf(target, list)) { + me.hide(); + event.stopPropagation(); + event.preventDefault(); + } + }); + this.eventListeners.mousewheel = util.addEventListener( + document, 'mousewheel', function (event) { + // block scrolling when context menu is visible + event.stopPropagation(); + event.preventDefault(); + }); + this.eventListeners.keydown = util.addEventListener( + document, 'keydown', function (event) { + me._onKeyDown(event); + }); - // move focus to the first button in the context menu - this.selection = util.getSelection(); - this.anchor = anchor; - setTimeout(function () { - me.dom.focusButton.focus(); - }, 0); + // move focus to the first button in the context menu + this.selection = util.getSelection(); + this.anchor = anchor; + setTimeout(function () { + me.dom.focusButton.focus(); + }, 0); - if (ContextMenu.visibleMenu) { - ContextMenu.visibleMenu.hide(); - } - ContextMenu.visibleMenu = this; + if (ContextMenu.visibleMenu) { + ContextMenu.visibleMenu.hide(); + } + ContextMenu.visibleMenu = this; }; /** * Hide the context menu if visible */ ContextMenu.prototype.hide = function () { - // remove the menu from the DOM - if (this.dom.menu.parentNode) { - this.dom.menu.parentNode.removeChild(this.dom.menu); - if (this.onClose) { - this.onClose(); - } + // remove the menu from the DOM + if (this.dom.menu.parentNode) { + this.dom.menu.parentNode.removeChild(this.dom.menu); + if (this.onClose) { + this.onClose(); } + } - // remove all event listeners - // all event listeners are supposed to be attached to document. - for (var name in this.eventListeners) { - if (this.eventListeners.hasOwnProperty(name)) { - var fn = this.eventListeners[name]; - if (fn) { - util.removeEventListener(document, name, fn); - } - delete this.eventListeners[name]; - } + // remove all event listeners + // all event listeners are supposed to be attached to document. + for (var name in this.eventListeners) { + if (this.eventListeners.hasOwnProperty(name)) { + var fn = this.eventListeners[name]; + if (fn) { + util.removeEventListener(document, name, fn); + } + delete this.eventListeners[name]; } + } - if (ContextMenu.visibleMenu == this) { - ContextMenu.visibleMenu = undefined; - } + if (ContextMenu.visibleMenu == this) { + ContextMenu.visibleMenu = undefined; + } }; /** @@ -276,37 +276,37 @@ ContextMenu.prototype.hide = function () { * @private */ ContextMenu.prototype._onExpandItem = function (domItem) { - var me = this; - var alreadyVisible = (domItem == this.expandedItem); + var me = this; + var alreadyVisible = (domItem == this.expandedItem); - // hide the currently visible submenu - var expandedItem = this.expandedItem; - if (expandedItem) { - //var ul = expandedItem.ul; - expandedItem.ul.style.height = '0'; - expandedItem.ul.style.padding = ''; - setTimeout(function () { - if (me.expandedItem != expandedItem) { - expandedItem.ul.style.display = ''; - util.removeClassName(expandedItem.ul.parentNode, 'selected'); - } - }, 300); // timeout duration must match the css transition duration - this.expandedItem = undefined; - } + // hide the currently visible submenu + var expandedItem = this.expandedItem; + if (expandedItem) { + //var ul = expandedItem.ul; + expandedItem.ul.style.height = '0'; + expandedItem.ul.style.padding = ''; + setTimeout(function () { + if (me.expandedItem != expandedItem) { + expandedItem.ul.style.display = ''; + util.removeClassName(expandedItem.ul.parentNode, 'selected'); + } + }, 300); // timeout duration must match the css transition duration + this.expandedItem = undefined; + } - if (!alreadyVisible) { - var ul = domItem.ul; - ul.style.display = 'block'; - var height = ul.clientHeight; // force a reflow in Firefox - setTimeout(function () { - if (me.expandedItem == domItem) { - ul.style.height = (ul.childNodes.length * 24) + 'px'; - ul.style.padding = '5px 10px'; - } - }, 0); - util.addClassName(ul.parentNode, 'selected'); - this.expandedItem = domItem; - } + if (!alreadyVisible) { + var ul = domItem.ul; + ul.style.display = 'block'; + var height = ul.clientHeight; // force a reflow in Firefox + setTimeout(function () { + if (me.expandedItem == domItem) { + ul.style.height = (ul.childNodes.length * 24) + 'px'; + ul.style.padding = '5px 10px'; + } + }, 0); + util.addClassName(ul.parentNode, 'selected'); + this.expandedItem = domItem; + } }; /** @@ -315,107 +315,107 @@ ContextMenu.prototype._onExpandItem = function (domItem) { * @private */ ContextMenu.prototype._onKeyDown = function (event) { - var target = event.target; - var keynum = event.which; - var handled = false; - var buttons, targetIndex, prevButton, nextButton; + var target = event.target; + var keynum = event.which; + var handled = false; + var buttons, targetIndex, prevButton, nextButton; - if (keynum == 27) { // ESC - // hide the menu on ESC key + if (keynum == 27) { // ESC + // hide the menu on ESC key - // restore previous selection and focus - if (this.selection) { - util.setSelection(this.selection); - } - if (this.anchor) { - this.anchor.focus(); - } + // restore previous selection and focus + if (this.selection) { + util.setSelection(this.selection); + } + if (this.anchor) { + this.anchor.focus(); + } - this.hide(); + this.hide(); + handled = true; + } + else if (keynum == 9) { // Tab + if (!event.shiftKey) { // Tab + buttons = this._getVisibleButtons(); + targetIndex = buttons.indexOf(target); + if (targetIndex == buttons.length - 1) { + // move to first button + buttons[0].focus(); handled = true; + } } - else if (keynum == 9) { // Tab - if (!event.shiftKey) { // Tab - buttons = this._getVisibleButtons(); - targetIndex = buttons.indexOf(target); - if (targetIndex == buttons.length - 1) { - // move to first button - buttons[0].focus(); - handled = true; - } - } - else { // Shift+Tab - buttons = this._getVisibleButtons(); - targetIndex = buttons.indexOf(target); - if (targetIndex == 0) { - // move to last button - buttons[buttons.length - 1].focus(); - handled = true; - } - } - } - else if (keynum == 37) { // Arrow Left - if (target.className == 'expand') { - buttons = this._getVisibleButtons(); - targetIndex = buttons.indexOf(target); - prevButton = buttons[targetIndex - 1]; - if (prevButton) { - prevButton.focus(); - } - } + else { // Shift+Tab + buttons = this._getVisibleButtons(); + targetIndex = buttons.indexOf(target); + if (targetIndex == 0) { + // move to last button + buttons[buttons.length - 1].focus(); handled = true; + } } - else if (keynum == 38) { // Arrow Up - buttons = this._getVisibleButtons(); - targetIndex = buttons.indexOf(target); - prevButton = buttons[targetIndex - 1]; - if (prevButton && prevButton.className == 'expand') { - // skip expand button - prevButton = buttons[targetIndex - 2]; - } - if (!prevButton) { - // move to last button - prevButton = buttons[buttons.length - 1]; - } - if (prevButton) { - prevButton.focus(); - } - handled = true; + } + else if (keynum == 37) { // Arrow Left + if (target.className == 'expand') { + buttons = this._getVisibleButtons(); + targetIndex = buttons.indexOf(target); + prevButton = buttons[targetIndex - 1]; + if (prevButton) { + prevButton.focus(); + } } - else if (keynum == 39) { // Arrow Right - buttons = this._getVisibleButtons(); - targetIndex = buttons.indexOf(target); - nextButton = buttons[targetIndex + 1]; - if (nextButton && nextButton.className == 'expand') { - nextButton.focus(); - } - handled = true; + handled = true; + } + else if (keynum == 38) { // Arrow Up + buttons = this._getVisibleButtons(); + targetIndex = buttons.indexOf(target); + prevButton = buttons[targetIndex - 1]; + if (prevButton && prevButton.className == 'expand') { + // skip expand button + prevButton = buttons[targetIndex - 2]; } - else if (keynum == 40) { // Arrow Down - buttons = this._getVisibleButtons(); - targetIndex = buttons.indexOf(target); - nextButton = buttons[targetIndex + 1]; - if (nextButton && nextButton.className == 'expand') { - // skip expand button - nextButton = buttons[targetIndex + 2]; - } - if (!nextButton) { - // move to first button - nextButton = buttons[0]; - } - if (nextButton) { - nextButton.focus(); - handled = true; - } - handled = true; + if (!prevButton) { + // move to last button + prevButton = buttons[buttons.length - 1]; } - // TODO: arrow left and right + if (prevButton) { + prevButton.focus(); + } + handled = true; + } + else if (keynum == 39) { // Arrow Right + buttons = this._getVisibleButtons(); + targetIndex = buttons.indexOf(target); + nextButton = buttons[targetIndex + 1]; + if (nextButton && nextButton.className == 'expand') { + nextButton.focus(); + } + handled = true; + } + else if (keynum == 40) { // Arrow Down + buttons = this._getVisibleButtons(); + targetIndex = buttons.indexOf(target); + nextButton = buttons[targetIndex + 1]; + if (nextButton && nextButton.className == 'expand') { + // skip expand button + nextButton = buttons[targetIndex + 2]; + } + if (!nextButton) { + // move to first button + nextButton = buttons[0]; + } + if (nextButton) { + nextButton.focus(); + handled = true; + } + handled = true; + } + // TODO: arrow left and right - if (handled) { - event.stopPropagation(); - event.preventDefault(); - } + if (handled) { + event.stopPropagation(); + event.preventDefault(); + } }; /** @@ -425,14 +425,14 @@ ContextMenu.prototype._onKeyDown = function (event) { * @return {boolean} isChild */ ContextMenu.prototype._isChildOf = function (child, parent) { - var e = child.parentNode; - while (e) { - if (e == parent) { - return true; - } - e = e.parentNode; + var e = child.parentNode; + while (e) { + if (e == parent) { + return true; } + e = e.parentNode; + } - return false; + return false; }; diff --git a/jsoneditor/js/highlighter.js b/jsoneditor/js/highlighter.js index b321256..ab6311f 100644 --- a/jsoneditor/js/highlighter.js +++ b/jsoneditor/js/highlighter.js @@ -4,7 +4,7 @@ * @constructor Highlighter */ function Highlighter () { - this.locked = false; + this.locked = false; } /** @@ -12,23 +12,23 @@ function Highlighter () { * @param {Node} node */ Highlighter.prototype.highlight = function (node) { - if (this.locked) { - return; + if (this.locked) { + return; + } + + if (this.node != node) { + // unhighlight current node + if (this.node) { + this.node.setHighlight(false); } - if (this.node != node) { - // unhighlight current node - if (this.node) { - this.node.setHighlight(false); - } + // highlight new node + this.node = node; + this.node.setHighlight(true); + } - // highlight new node - this.node = node; - this.node.setHighlight(true); - } - - // cancel any current timeout - this._cancelUnhighlight(); + // cancel any current timeout + this._cancelUnhighlight(); }; /** @@ -36,23 +36,23 @@ Highlighter.prototype.highlight = function (node) { * Will be done after a delay */ Highlighter.prototype.unhighlight = function () { - if (this.locked) { - return; - } + if (this.locked) { + return; + } - var me = this; - if (this.node) { - this._cancelUnhighlight(); + var me = this; + if (this.node) { + this._cancelUnhighlight(); - // do the unhighlighting after a small delay, to prevent re-highlighting - // the same node when moving from the drag-icon to the contextmenu-icon - // or vice versa. - this.unhighlightTimer = setTimeout(function () { - me.node.setHighlight(false); - me.node = undefined; - me.unhighlightTimer = undefined; - }, 0); - } + // do the unhighlighting after a small delay, to prevent re-highlighting + // the same node when moving from the drag-icon to the contextmenu-icon + // or vice versa. + this.unhighlightTimer = setTimeout(function () { + me.node.setHighlight(false); + me.node = undefined; + me.unhighlightTimer = undefined; + }, 0); + } }; /** @@ -60,10 +60,10 @@ Highlighter.prototype.unhighlight = function () { * @private */ Highlighter.prototype._cancelUnhighlight = function () { - if (this.unhighlightTimer) { - clearTimeout(this.unhighlightTimer); - this.unhighlightTimer = undefined; - } + if (this.unhighlightTimer) { + clearTimeout(this.unhighlightTimer); + this.unhighlightTimer = undefined; + } }; /** @@ -71,12 +71,12 @@ Highlighter.prototype._cancelUnhighlight = function () { * methods highlight and unhighlight do not work while locked. */ Highlighter.prototype.lock = function () { - this.locked = true; + this.locked = true; }; /** * Unlock highlighting or unhighlighting nodes */ Highlighter.prototype.unlock = function () { - this.locked = false; + this.locked = false; }; diff --git a/jsoneditor/js/history.js b/jsoneditor/js/history.js index 0876f72..390e32f 100644 --- a/jsoneditor/js/history.js +++ b/jsoneditor/js/history.js @@ -4,105 +4,105 @@ * @param {JSONEditor} editor */ function History (editor) { - this.editor = editor; - this.clear(); + this.editor = editor; + this.clear(); - // map with all supported actions - this.actions = { - 'editField': { - 'undo': function (params) { - params.node.updateField(params.oldValue); - }, - 'redo': function (params) { - params.node.updateField(params.newValue); - } - }, - 'editValue': { - 'undo': function (params) { - params.node.updateValue(params.oldValue); - }, - 'redo': function (params) { - params.node.updateValue(params.newValue); - } - }, - 'appendNode': { - 'undo': function (params) { - params.parent.removeChild(params.node); - }, - 'redo': function (params) { - params.parent.appendChild(params.node); - } - }, - 'insertBeforeNode': { - 'undo': function (params) { - params.parent.removeChild(params.node); - }, - 'redo': function (params) { - params.parent.insertBefore(params.node, params.beforeNode); - } - }, - 'insertAfterNode': { - 'undo': function (params) { - params.parent.removeChild(params.node); - }, - 'redo': function (params) { - params.parent.insertAfter(params.node, params.afterNode); - } - }, - 'removeNode': { - 'undo': function (params) { - var parent = params.parent; - var beforeNode = parent.childs[params.index] || parent.append; - parent.insertBefore(params.node, beforeNode); - }, - 'redo': function (params) { - params.parent.removeChild(params.node); - } - }, - 'duplicateNode': { - 'undo': function (params) { - params.parent.removeChild(params.clone); - }, - 'redo': function (params) { - params.parent.insertAfter(params.clone, params.node); - } - }, - 'changeType': { - 'undo': function (params) { - params.node.changeType(params.oldType); - }, - 'redo': function (params) { - params.node.changeType(params.newType); - } - }, - 'moveNode': { - 'undo': function (params) { - params.startParent.moveTo(params.node, params.startIndex); - }, - 'redo': function (params) { - params.endParent.moveTo(params.node, params.endIndex); - } - }, - 'sort': { - 'undo': function (params) { - var node = params.node; - node.hideChilds(); - node.sort = params.oldSort; - node.childs = params.oldChilds; - node.showChilds(); - }, - 'redo': function (params) { - var node = params.node; - node.hideChilds(); - node.sort = params.newSort; - node.childs = params.newChilds; - node.showChilds(); - } - } + // map with all supported actions + this.actions = { + 'editField': { + 'undo': function (params) { + params.node.updateField(params.oldValue); + }, + 'redo': function (params) { + params.node.updateField(params.newValue); + } + }, + 'editValue': { + 'undo': function (params) { + params.node.updateValue(params.oldValue); + }, + 'redo': function (params) { + params.node.updateValue(params.newValue); + } + }, + 'appendNode': { + 'undo': function (params) { + params.parent.removeChild(params.node); + }, + 'redo': function (params) { + params.parent.appendChild(params.node); + } + }, + 'insertBeforeNode': { + 'undo': function (params) { + params.parent.removeChild(params.node); + }, + 'redo': function (params) { + params.parent.insertBefore(params.node, params.beforeNode); + } + }, + 'insertAfterNode': { + 'undo': function (params) { + params.parent.removeChild(params.node); + }, + 'redo': function (params) { + params.parent.insertAfter(params.node, params.afterNode); + } + }, + 'removeNode': { + 'undo': function (params) { + var parent = params.parent; + var beforeNode = parent.childs[params.index] || parent.append; + parent.insertBefore(params.node, beforeNode); + }, + 'redo': function (params) { + params.parent.removeChild(params.node); + } + }, + 'duplicateNode': { + 'undo': function (params) { + params.parent.removeChild(params.clone); + }, + 'redo': function (params) { + params.parent.insertAfter(params.clone, params.node); + } + }, + 'changeType': { + 'undo': function (params) { + params.node.changeType(params.oldType); + }, + 'redo': function (params) { + params.node.changeType(params.newType); + } + }, + 'moveNode': { + 'undo': function (params) { + params.startParent.moveTo(params.node, params.startIndex); + }, + 'redo': function (params) { + params.endParent.moveTo(params.node, params.endIndex); + } + }, + 'sort': { + 'undo': function (params) { + var node = params.node; + node.hideChilds(); + node.sort = params.oldSort; + node.childs = params.oldChilds; + node.showChilds(); + }, + 'redo': function (params) { + var node = params.node; + node.hideChilds(); + node.sort = params.newSort; + node.childs = params.newChilds; + node.showChilds(); + } + } - // TODO: restore the original caret position and selection with each undo - // TODO: implement history for actions "expand", "collapse", "scroll", "setDocument" - }; + // TODO: restore the original caret position and selection with each undo + // TODO: implement history for actions "expand", "collapse", "scroll", "setDocument" + }; } /** @@ -123,31 +123,31 @@ History.prototype.onChange = function () {}; * needed to undo or redo the action. */ History.prototype.add = function (action, params) { - this.index++; - this.history[this.index] = { - 'action': action, - 'params': params, - 'timestamp': new Date() - }; + this.index++; + this.history[this.index] = { + 'action': action, + 'params': params, + 'timestamp': new Date() + }; - // remove redo actions which are invalid now - if (this.index < this.history.length - 1) { - this.history.splice(this.index + 1, this.history.length - this.index - 1); - } + // remove redo actions which are invalid now + if (this.index < this.history.length - 1) { + this.history.splice(this.index + 1, this.history.length - this.index - 1); + } - // fire onchange event - this.onChange(); + // fire onchange event + this.onChange(); }; /** * Clear history */ History.prototype.clear = function () { - this.history = []; - this.index = -1; + this.history = []; + this.index = -1; - // fire onchange event - this.onChange(); + // fire onchange event + this.onChange(); }; /** @@ -155,7 +155,7 @@ History.prototype.clear = function () { * @return {Boolean} canUndo */ History.prototype.canUndo = function () { - return (this.index >= 0); + return (this.index >= 0); }; /** @@ -163,56 +163,56 @@ History.prototype.canUndo = function () { * @return {Boolean} canRedo */ History.prototype.canRedo = function () { - return (this.index < this.history.length - 1); + return (this.index < this.history.length - 1); }; /** * Undo the last action */ History.prototype.undo = function () { - if (this.canUndo()) { - var obj = this.history[this.index]; - if (obj) { - var action = this.actions[obj.action]; - if (action && action.undo) { - action.undo(obj.params); - if (obj.params.oldSelection) { - this.editor.setSelection(obj.params.oldSelection); - } - } - else { - util.log('Error: unknown action "' + obj.action + '"'); - } + if (this.canUndo()) { + var obj = this.history[this.index]; + if (obj) { + var action = this.actions[obj.action]; + if (action && action.undo) { + action.undo(obj.params); + if (obj.params.oldSelection) { + this.editor.setSelection(obj.params.oldSelection); } - this.index--; - - // fire onchange event - this.onChange(); + } + else { + util.log('Error: unknown action "' + obj.action + '"'); + } } + this.index--; + + // fire onchange event + this.onChange(); + } }; /** * Redo the last action */ History.prototype.redo = function () { - if (this.canRedo()) { - this.index++; + if (this.canRedo()) { + this.index++; - var obj = this.history[this.index]; - if (obj) { - var action = this.actions[obj.action]; - if (action && action.redo) { - action.redo(obj.params); - if (obj.params.newSelection) { - this.editor.setSelection(obj.params.newSelection); - } - } - else { - util.log('Error: unknown action "' + obj.action + '"'); - } + var obj = this.history[this.index]; + if (obj) { + var action = this.actions[obj.action]; + if (action && action.redo) { + action.redo(obj.params); + if (obj.params.newSelection) { + this.editor.setSelection(obj.params.newSelection); } - - // fire onchange event - this.onChange(); + } + else { + util.log('Error: unknown action "' + obj.action + '"'); + } } + + // fire onchange event + this.onChange(); + } }; diff --git a/jsoneditor/js/jsoneditor.js b/jsoneditor/js/jsoneditor.js index 3330693..43c4564 100644 --- a/jsoneditor/js/jsoneditor.js +++ b/jsoneditor/js/jsoneditor.js @@ -25,20 +25,20 @@ * @param {Object | undefined} json JSON object */ function JSONEditor (container, options, json) { - if (!(this instanceof JSONEditor)) { - throw new Error('JSONEditor constructor called without "new".'); - } + if (!(this instanceof JSONEditor)) { + throw new Error('JSONEditor constructor called without "new".'); + } - // check for unsupported browser (IE8 and older) - var ieVersion = util.getInternetExplorerVersion(); - if (ieVersion != -1 && ieVersion < 9) { - throw new Error('Unsupported browser, IE9 or newer required. ' + - 'Please install the newest version of your browser.'); - } + // check for unsupported browser (IE8 and older) + var ieVersion = util.getInternetExplorerVersion(); + if (ieVersion != -1 && ieVersion < 9) { + throw new Error('Unsupported browser, IE9 or newer required. ' + + 'Please install the newest version of your browser.'); + } - if (arguments.length) { - this._create(container, options, json); - } + if (arguments.length) { + this._create(container, options, json); + } } /** @@ -66,12 +66,12 @@ JSONEditor.modes = {}; * @private */ JSONEditor.prototype._create = function (container, options, json) { - this.container = container; - this.options = options || {}; - this.json = json || {}; + this.container = container; + this.options = options || {}; + this.json = json || {}; - var mode = this.options.mode || 'tree'; - this.setMode(mode); + var mode = this.options.mode || 'tree'; + this.setMode(mode); }; /** @@ -85,7 +85,7 @@ JSONEditor.prototype._delete = function () {}; * @param {Object | undefined} json JSON data */ JSONEditor.prototype.set = function (json) { - this.json = json; + this.json = json; }; /** @@ -93,7 +93,7 @@ JSONEditor.prototype.set = function (json) { * @returns {Object} json */ JSONEditor.prototype.get = function () { - return this.json; + return this.json; }; /** @@ -101,7 +101,7 @@ JSONEditor.prototype.get = function () { * @param {String | undefined} jsonText */ JSONEditor.prototype.setText = function (jsonText) { - this.json = util.parse(jsonText); + this.json = util.parse(jsonText); }; /** @@ -109,7 +109,7 @@ JSONEditor.prototype.setText = function (jsonText) { * @returns {String} jsonText */ JSONEditor.prototype.getText = function () { - return JSON.stringify(this.json); + return JSON.stringify(this.json); }; /** @@ -117,10 +117,10 @@ JSONEditor.prototype.getText = function () { * @param {String | undefined} name */ JSONEditor.prototype.setName = function (name) { - if (!this.options) { - this.options = {}; - } - this.options.name = name; + if (!this.options) { + this.options = {}; + } + this.options.name = name; }; /** @@ -128,7 +128,7 @@ JSONEditor.prototype.setName = function (name) { * @return {String | undefined} name */ JSONEditor.prototype.getName = function () { - return this.options && this.options.name; + return this.options && this.options.name; }; /** @@ -138,56 +138,56 @@ JSONEditor.prototype.getName = function () { * 'text', and 'code'. */ JSONEditor.prototype.setMode = function (mode) { - var container = this.container, - options = util.extend({}, this.options), - data, - name; + var container = this.container, + options = util.extend({}, this.options), + data, + name; - options.mode = mode; - var config = JSONEditor.modes[mode]; - if (config) { + options.mode = mode; + var config = JSONEditor.modes[mode]; + if (config) { + try { + if (config.data == 'text') { + // text + name = this.getName(); + data = this.getText(); + + this._delete(); + util.clear(this); + util.extend(this, config.editor.prototype); + this._create(container, options); + + this.setName(name); + this.setText(data); + } + else { + // json + name = this.getName(); + data = this.get(); + + this._delete(); + util.clear(this); + util.extend(this, config.editor.prototype); + this._create(container, options); + + this.setName(name); + this.set(data); + } + + if (typeof config.load === 'function') { try { - if (config.data == 'text') { - // text - name = this.getName(); - data = this.getText(); - - this._delete(); - util.clear(this); - util.extend(this, config.editor.prototype); - this._create(container, options); - - this.setName(name); - this.setText(data); - } - else { - // json - name = this.getName(); - data = this.get(); - - this._delete(); - util.clear(this); - util.extend(this, config.editor.prototype); - this._create(container, options); - - this.setName(name); - this.set(data); - } - - if (typeof config.load === 'function') { - try { - config.load.call(this); - } - catch (err) {} - } - } - catch (err) { - this._onError(err); + config.load.call(this); } + catch (err) {} + } } - else { - throw new Error('Unknown mode "' + options.mode + '"'); + catch (err) { + this._onError(err); } + } + else { + throw new Error('Unknown mode "' + options.mode + '"'); + } }; /** @@ -197,17 +197,17 @@ JSONEditor.prototype.setMode = function (mode) { * @private */ JSONEditor.prototype._onError = function(err) { - // TODO: onError is deprecated since version 2.2.0. cleanup some day - if (typeof this.onError === 'function') { - util.log('WARNING: JSONEditor.onError is deprecated. ' + - 'Use options.error instead.'); - this.onError(err); - } + // TODO: onError is deprecated since version 2.2.0. cleanup some day + if (typeof this.onError === 'function') { + util.log('WARNING: JSONEditor.onError is deprecated. ' + + 'Use options.error instead.'); + this.onError(err); + } - if (this.options && typeof this.options.error === 'function') { - this.options.error(err); - } - else { - throw err; - } + if (this.options && typeof this.options.error === 'function') { + this.options.error(err); + } + else { + throw err; + } }; diff --git a/jsoneditor/js/modebox.js b/jsoneditor/js/modebox.js index 756072e..8b25ba6 100644 --- a/jsoneditor/js/modebox.js +++ b/jsoneditor/js/modebox.js @@ -6,89 +6,89 @@ * @returns {HTMLElement} box */ function createModeBox(editor, modes, current) { - /** - * Switch the mode of the editor - * @param {String} mode - */ - function switchMode(mode) { - // switch mode - editor.setMode(mode); + /** + * Switch the mode of the editor + * @param {String} mode + */ + function switchMode(mode) { + // switch mode + editor.setMode(mode); - // restore focus on mode box - var modeBox = editor.dom && editor.dom.modeBox; - if (modeBox) { - modeBox.focus(); - } + // restore focus on mode box + var modeBox = editor.dom && editor.dom.modeBox; + if (modeBox) { + modeBox.focus(); + } + } + + // available modes + var availableModes = { + code: { + 'text': 'Code', + 'title': 'Switch to code highlighter', + 'click': function () { + switchMode('code') + } + }, + form: { + 'text': 'Form', + 'title': 'Switch to form editor', + 'click': function () { + switchMode('form'); + } + }, + text: { + 'text': 'Text', + 'title': 'Switch to plain text editor', + 'click': function () { + switchMode('text'); + } + }, + tree: { + 'text': 'Tree', + 'title': 'Switch to tree editor', + 'click': function () { + switchMode('tree'); + } + }, + view: { + 'text': 'View', + 'title': 'Switch to tree view', + 'click': function () { + switchMode('view'); + } + } + }; + + // list the selected modes + var items = []; + for (var i = 0; i < modes.length; i++) { + var mode = modes[i]; + var item = availableModes[mode]; + if (!item) { + throw new Error('Unknown mode "' + mode + '"'); } - // available modes - var availableModes = { - code: { - 'text': 'Code', - 'title': 'Switch to code highlighter', - 'click': function () { - switchMode('code') - } - }, - form: { - 'text': 'Form', - 'title': 'Switch to form editor', - 'click': function () { - switchMode('form'); - } - }, - text: { - 'text': 'Text', - 'title': 'Switch to plain text editor', - 'click': function () { - switchMode('text'); - } - }, - tree: { - 'text': 'Tree', - 'title': 'Switch to tree editor', - 'click': function () { - switchMode('tree'); - } - }, - view: { - 'text': 'View', - 'title': 'Switch to tree view', - 'click': function () { - switchMode('view'); - } - } - }; + item.className = 'type-modes' + ((current == mode) ? ' selected' : ''); + items.push(item); + } - // list the selected modes - var items = []; - for (var i = 0; i < modes.length; i++) { - var mode = modes[i]; - var item = availableModes[mode]; - if (!item) { - throw new Error('Unknown mode "' + mode + '"'); - } + // retrieve the title of current mode + var currentMode = availableModes[current]; + if (!currentMode) { + throw new Error('Unknown mode "' + current + '"'); + } + var currentTitle = currentMode.text; - item.className = 'type-modes' + ((current == mode) ? ' selected' : ''); - items.push(item); - } + // create the html element + var box = document.createElement('button'); + box.className = 'modes separator'; + box.innerHTML = currentTitle + ' ▾'; + box.title = 'Switch editor mode'; + box.onclick = function () { + var menu = new ContextMenu(items); + menu.show(box); + }; - // retrieve the title of current mode - var currentMode = availableModes[current]; - if (!currentMode) { - throw new Error('Unknown mode "' + current + '"'); - } - var currentTitle = currentMode.text; - - // create the html element - var box = document.createElement('button'); - box.className = 'modes separator'; - box.innerHTML = currentTitle + ' ▾'; - box.title = 'Switch editor mode'; - box.onclick = function () { - var menu = new ContextMenu(items); - menu.show(box); - }; - - return box; + return box; } diff --git a/jsoneditor/js/module.js b/jsoneditor/js/module.js index cf0187e..7fba20b 100644 --- a/jsoneditor/js/module.js +++ b/jsoneditor/js/module.js @@ -1,58 +1,58 @@ // module exports var jsoneditor = { - 'JSONEditor': JSONEditor, - 'JSONFormatter': function () { - throw new Error('JSONFormatter is deprecated. ' + - 'Use JSONEditor with mode "text" or "code" instead'); - }, - 'util': util + 'JSONEditor': JSONEditor, + 'JSONFormatter': function () { + throw new Error('JSONFormatter is deprecated. ' + + 'Use JSONEditor with mode "text" or "code" instead'); + }, + 'util': util }; /** * load jsoneditor.css */ var loadCss = function () { - // find the script named 'jsoneditor.js' or 'jsoneditor-min.js' or - // 'jsoneditor.min.js', and use its path to find the css file to be - // loaded. - var scripts = document.getElementsByTagName('script'); - for (var s = 0; s < scripts.length; s++) { - var src = scripts[s].src; - if (/(^|\/)jsoneditor([-\.]min)?.js$/.test(src)) { - var jsFile = src.split('?')[0]; - var cssFile = jsFile.substring(0, jsFile.length - 2) + 'css'; + // find the script named 'jsoneditor.js' or 'jsoneditor-min.js' or + // 'jsoneditor.min.js', and use its path to find the css file to be + // loaded. + var scripts = document.getElementsByTagName('script'); + for (var s = 0; s < scripts.length; s++) { + var src = scripts[s].src; + if (/(^|\/)jsoneditor([-\.]min)?.js$/.test(src)) { + var jsFile = src.split('?')[0]; + var cssFile = jsFile.substring(0, jsFile.length - 2) + 'css'; - // load css file - var link = document.createElement('link'); - link.type = 'text/css'; - link.rel = 'stylesheet'; - link.href = cssFile; - document.getElementsByTagName('head')[0].appendChild(link); + // load css file + var link = document.createElement('link'); + link.type = 'text/css'; + link.rel = 'stylesheet'; + link.href = cssFile; + document.getElementsByTagName('head')[0].appendChild(link); - break; - } + break; } + } }; /** * CommonJS module exports */ if (typeof(module) != 'undefined' && typeof(exports) != 'undefined') { - loadCss(); - module.exports = exports = jsoneditor; + loadCss(); + module.exports = exports = jsoneditor; } /** * AMD module exports */ if (typeof(require) != 'undefined' && typeof(define) != 'undefined') { - loadCss(); - define(function () { - return jsoneditor; - }); + loadCss(); + define(function () { + return jsoneditor; + }); } else { - // attach the module to the window, load as a regular javascript file - window['jsoneditor'] = jsoneditor; + // attach the module to the window, load as a regular javascript file + window['jsoneditor'] = jsoneditor; } diff --git a/jsoneditor/js/node.js b/jsoneditor/js/node.js index 797501b..eb0e3e4 100644 --- a/jsoneditor/js/node.js +++ b/jsoneditor/js/node.js @@ -10,19 +10,19 @@ * 'object', or 'string'. */ function Node (editor, params) { - /** @type {TreeEditor} */ - this.editor = editor; - this.dom = {}; - this.expanded = false; + /** @type {TreeEditor} */ + this.editor = editor; + this.dom = {}; + this.expanded = false; - if(params && (params instanceof Object)) { - this.setField(params.field, params.fieldEditable); - this.setValue(params.value, params.type); - } - else { - this.setField(''); - this.setValue(null); - } + if(params && (params instanceof Object)) { + this.setField(params.field, params.fieldEditable); + this.setValue(params.value, params.type); + } + else { + this.setField(''); + this.setValue(null); + } }; /** @@ -30,7 +30,7 @@ function Node (editor, params) { * @param {Node} parent */ Node.prototype.setParent = function(parent) { - this.parent = parent; + this.parent = parent; }; /** @@ -39,8 +39,8 @@ Node.prototype.setParent = function(parent) { * @param {boolean} [fieldEditable] */ Node.prototype.setField = function(field, fieldEditable) { - this.field = field; - this.fieldEditable = (fieldEditable == true); + this.field = field; + this.fieldEditable = (fieldEditable == true); }; /** @@ -48,11 +48,11 @@ Node.prototype.setField = function(field, fieldEditable) { * @return {String} */ Node.prototype.getField = function() { - if (this.field === undefined) { - this._getDomField(); - } + if (this.field === undefined) { + this._getDomField(); + } - return this.field; + return this.field; }; /** @@ -62,80 +62,80 @@ Node.prototype.getField = function() { * 'array', 'object', or 'string' */ Node.prototype.setValue = function(value, type) { - var childValue, child; + var childValue, child; - // first clear all current childs (if any) - var childs = this.childs; - if (childs) { - while (childs.length) { - this.removeChild(childs[0]); - } + // first clear all current childs (if any) + var childs = this.childs; + if (childs) { + while (childs.length) { + this.removeChild(childs[0]); } + } - // TODO: remove the DOM of this Node + // TODO: remove the DOM of this Node - this.type = this._getType(value); + this.type = this._getType(value); - // check if type corresponds with the provided type - if (type && type != this.type) { - if (type == 'string' && this.type == 'auto') { - this.type = type; - } - else { - throw new Error('Type mismatch: ' + - 'cannot cast value of type "' + this.type + - ' to the specified type "' + type + '"'); - } - } - - if (this.type == 'array') { - // array - this.childs = []; - for (var i = 0, iMax = value.length; i < iMax; i++) { - childValue = value[i]; - if (childValue !== undefined && !(childValue instanceof Function)) { - // ignore undefined and functions - child = new Node(this.editor, { - 'value': childValue - }); - this.appendChild(child); - } - } - this.value = ''; - } - else if (this.type == 'object') { - // object - this.childs = []; - for (var childField in value) { - if (value.hasOwnProperty(childField)) { - childValue = value[childField]; - if (childValue !== undefined && !(childValue instanceof Function)) { - // ignore undefined and functions - child = new Node(this.editor, { - 'field': childField, - 'value': childValue - }); - this.appendChild(child); - } - } - } - this.value = ''; + // check if type corresponds with the provided type + if (type && type != this.type) { + if (type == 'string' && this.type == 'auto') { + this.type = type; } else { - // value - this.childs = undefined; - this.value = value; - /* TODO - if (typeof(value) == 'string') { - var escValue = JSON.stringify(value); - this.value = escValue.substring(1, escValue.length - 1); - util.log('check', value, this.value); - } - else { - this.value = value; - } - */ + throw new Error('Type mismatch: ' + + 'cannot cast value of type "' + this.type + + ' to the specified type "' + type + '"'); } + } + + if (this.type == 'array') { + // array + this.childs = []; + for (var i = 0, iMax = value.length; i < iMax; i++) { + childValue = value[i]; + if (childValue !== undefined && !(childValue instanceof Function)) { + // ignore undefined and functions + child = new Node(this.editor, { + 'value': childValue + }); + this.appendChild(child); + } + } + this.value = ''; + } + else if (this.type == 'object') { + // object + this.childs = []; + for (var childField in value) { + if (value.hasOwnProperty(childField)) { + childValue = value[childField]; + if (childValue !== undefined && !(childValue instanceof Function)) { + // ignore undefined and functions + child = new Node(this.editor, { + 'field': childField, + 'value': childValue + }); + this.appendChild(child); + } + } + } + this.value = ''; + } + else { + // value + this.childs = undefined; + this.value = value; + /* TODO + if (typeof(value) == 'string') { + var escValue = JSON.stringify(value); + this.value = escValue.substring(1, escValue.length - 1); + util.log('check', value, this.value); + } + else { + this.value = value; + } + */ + } }; /** @@ -143,29 +143,29 @@ Node.prototype.setValue = function(value, type) { * @return {*} value */ Node.prototype.getValue = function() { - //var childs, i, iMax; + //var childs, i, iMax; - if (this.type == 'array') { - var arr = []; - this.childs.forEach (function (child) { - arr.push(child.getValue()); - }); - return arr; + if (this.type == 'array') { + var arr = []; + this.childs.forEach (function (child) { + arr.push(child.getValue()); + }); + return arr; + } + else if (this.type == 'object') { + var obj = {}; + this.childs.forEach (function (child) { + obj[child.getField()] = child.getValue(); + }); + return obj; + } + else { + if (this.value === undefined) { + this._getDomValue(); } - else if (this.type == 'object') { - var obj = {}; - this.childs.forEach (function (child) { - obj[child.getField()] = child.getValue(); - }); - return obj; - } - else { - if (this.value === undefined) { - this._getDomValue(); - } - return this.value; - } + return this.value; + } }; /** @@ -173,7 +173,7 @@ Node.prototype.getValue = function() { * @return {Number} level */ Node.prototype.getLevel = function() { - return (this.parent ? this.parent.getLevel() + 1 : 0); + return (this.parent ? this.parent.getLevel() + 1 : 0); }; /** @@ -183,31 +183,31 @@ Node.prototype.getLevel = function() { * @return {Node} clone */ Node.prototype.clone = function() { - var clone = new Node(this.editor); - clone.type = this.type; - clone.field = this.field; - clone.fieldInnerText = this.fieldInnerText; - clone.fieldEditable = this.fieldEditable; - clone.value = this.value; - clone.valueInnerText = this.valueInnerText; - clone.expanded = this.expanded; + var clone = new Node(this.editor); + clone.type = this.type; + clone.field = this.field; + clone.fieldInnerText = this.fieldInnerText; + clone.fieldEditable = this.fieldEditable; + clone.value = this.value; + clone.valueInnerText = this.valueInnerText; + clone.expanded = this.expanded; - if (this.childs) { - // an object or array - var cloneChilds = []; - this.childs.forEach(function (child) { - var childClone = child.clone(); - childClone.setParent(clone); - cloneChilds.push(childClone); - }); - clone.childs = cloneChilds; - } - else { - // a value - clone.childs = undefined; - } + if (this.childs) { + // an object or array + var cloneChilds = []; + this.childs.forEach(function (child) { + var childClone = child.clone(); + childClone.setParent(clone); + cloneChilds.push(childClone); + }); + clone.childs = cloneChilds; + } + else { + // a value + clone.childs = undefined; + } - return clone; + return clone; }; /** @@ -216,23 +216,23 @@ Node.prototype.clone = function() { * true, all childs will be expanded recursively */ Node.prototype.expand = function(recurse) { - if (!this.childs) { - return; - } + if (!this.childs) { + return; + } - // set this node expanded - this.expanded = true; - if (this.dom.expand) { - this.dom.expand.className = 'expanded'; - } + // set this node expanded + this.expanded = true; + if (this.dom.expand) { + this.dom.expand.className = 'expanded'; + } - this.showChilds(); + this.showChilds(); - if (recurse != false) { - this.childs.forEach(function (child) { - child.expand(recurse); - }); - } + if (recurse != false) { + this.childs.forEach(function (child) { + child.expand(recurse); + }); + } }; /** @@ -241,70 +241,70 @@ Node.prototype.expand = function(recurse) { * true, all childs will be collapsed recursively */ Node.prototype.collapse = function(recurse) { - if (!this.childs) { - return; - } + if (!this.childs) { + return; + } - this.hideChilds(); + this.hideChilds(); - // collapse childs in case of recurse - if (recurse != false) { - this.childs.forEach(function (child) { - child.collapse(recurse); - }); + // collapse childs in case of recurse + if (recurse != false) { + this.childs.forEach(function (child) { + child.collapse(recurse); + }); - } + } - // make this node collapsed - if (this.dom.expand) { - this.dom.expand.className = 'collapsed'; - } - this.expanded = false; + // make this node collapsed + if (this.dom.expand) { + this.dom.expand.className = 'collapsed'; + } + this.expanded = false; }; /** * Recursively show all childs when they are expanded */ Node.prototype.showChilds = function() { - var childs = this.childs; - if (!childs) { - return; + var childs = this.childs; + if (!childs) { + return; + } + if (!this.expanded) { + return; + } + + var tr = this.dom.tr; + var table = tr ? tr.parentNode : undefined; + if (table) { + // show row with append button + var append = this.getAppend(); + var nextTr = tr.nextSibling; + if (nextTr) { + table.insertBefore(append, nextTr); } - if (!this.expanded) { - return; + else { + table.appendChild(append); } - var tr = this.dom.tr; - var table = tr ? tr.parentNode : undefined; - if (table) { - // show row with append button - var append = this.getAppend(); - var nextTr = tr.nextSibling; - if (nextTr) { - table.insertBefore(append, nextTr); - } - else { - table.appendChild(append); - } - - // show childs - this.childs.forEach(function (child) { - table.insertBefore(child.getDom(), append); - child.showChilds(); - }); - } + // show childs + this.childs.forEach(function (child) { + table.insertBefore(child.getDom(), append); + child.showChilds(); + }); + } }; /** * Hide the node with all its childs */ Node.prototype.hide = function() { - var tr = this.dom.tr; - var table = tr ? tr.parentNode : undefined; - if (table) { - table.removeChild(tr); - } - this.hideChilds(); + var tr = this.dom.tr; + var table = tr ? tr.parentNode : undefined; + if (table) { + table.removeChild(tr); + } + this.hideChilds(); }; @@ -312,24 +312,24 @@ Node.prototype.hide = function() { * Recursively hide all childs */ Node.prototype.hideChilds = function() { - var childs = this.childs; - if (!childs) { - return; - } - if (!this.expanded) { - return; - } + var childs = this.childs; + if (!childs) { + return; + } + if (!this.expanded) { + return; + } - // hide append row - var append = this.getAppend(); - if (append.parentNode) { - append.parentNode.removeChild(append); - } + // hide append row + var append = this.getAppend(); + if (append.parentNode) { + append.parentNode.removeChild(append); + } - // hide childs - this.childs.forEach(function (child) { - child.hide(); - }); + // hide childs + this.childs.forEach(function (child) { + child.hide(); + }); }; @@ -339,30 +339,30 @@ Node.prototype.hideChilds = function() { * @param {Node} node */ Node.prototype.appendChild = function(node) { - if (this._hasChilds()) { - // adjust the link to the parent - node.setParent(this); - node.fieldEditable = (this.type == 'object'); - if (this.type == 'array') { - node.index = this.childs.length; - } - this.childs.push(node); - - if (this.expanded) { - // insert into the DOM, before the appendRow - var newTr = node.getDom(); - var appendTr = this.getAppend(); - var table = appendTr ? appendTr.parentNode : undefined; - if (appendTr && table) { - table.insertBefore(newTr, appendTr); - } - - node.showChilds(); - } - - this.updateDom({'updateIndexes': true}); - node.updateDom({'recurse': true}); + if (this._hasChilds()) { + // adjust the link to the parent + node.setParent(this); + node.fieldEditable = (this.type == 'object'); + if (this.type == 'array') { + node.index = this.childs.length; } + this.childs.push(node); + + if (this.expanded) { + // insert into the DOM, before the appendRow + var newTr = node.getDom(); + var appendTr = this.getAppend(); + var table = appendTr ? appendTr.parentNode : undefined; + if (appendTr && table) { + table.insertBefore(newTr, appendTr); + } + + node.showChilds(); + } + + this.updateDom({'updateIndexes': true}); + node.updateDom({'recurse': true}); + } }; @@ -373,31 +373,31 @@ Node.prototype.appendChild = function(node) { * @param {Node} beforeNode */ Node.prototype.moveBefore = function(node, beforeNode) { - if (this._hasChilds()) { - // create a temporary row, to prevent the scroll position from jumping - // when removing the node - var tbody = (this.dom.tr) ? this.dom.tr.parentNode : undefined; - if (tbody) { - var trTemp = document.createElement('tr'); - trTemp.style.height = tbody.clientHeight + 'px'; - tbody.appendChild(trTemp); - } - - if (node.parent) { - node.parent.removeChild(node); - } - - if (beforeNode instanceof AppendNode) { - this.appendChild(node); - } - else { - this.insertBefore(node, beforeNode); - } - - if (tbody) { - tbody.removeChild(trTemp); - } + if (this._hasChilds()) { + // create a temporary row, to prevent the scroll position from jumping + // when removing the node + var tbody = (this.dom.tr) ? this.dom.tr.parentNode : undefined; + if (tbody) { + var trTemp = document.createElement('tr'); + trTemp.style.height = tbody.clientHeight + 'px'; + tbody.appendChild(trTemp); } + + if (node.parent) { + node.parent.removeChild(node); + } + + if (beforeNode instanceof AppendNode) { + this.appendChild(node); + } + else { + this.insertBefore(node, beforeNode); + } + + if (tbody) { + tbody.removeChild(trTemp); + } + } }; /** @@ -408,17 +408,17 @@ Node.prototype.moveBefore = function(node, beforeNode) { * @param {Number} index */ Node.prototype.moveTo = function (node, index) { - if (node.parent == this) { - // same parent - var currentIndex = this.childs.indexOf(node); - if (currentIndex < index) { - // compensate the index for removal of the node itself - index++; - } + if (node.parent == this) { + // same parent + var currentIndex = this.childs.indexOf(node); + if (currentIndex < index) { + // compensate the index for removal of the node itself + index++; } + } - var beforeNode = this.childs[index] || this.append; - this.moveBefore(node, beforeNode); + var beforeNode = this.childs[index] || this.append; + this.moveBefore(node, beforeNode); }; /** @@ -428,43 +428,43 @@ Node.prototype.moveTo = function (node, index) { * @param {Node} beforeNode */ Node.prototype.insertBefore = function(node, beforeNode) { - if (this._hasChilds()) { - if (beforeNode == this.append) { - // append to the child nodes + if (this._hasChilds()) { + if (beforeNode == this.append) { + // append to the child nodes - // adjust the link to the parent - node.setParent(this); - node.fieldEditable = (this.type == 'object'); - this.childs.push(node); - } - else { - // insert before a child node - var index = this.childs.indexOf(beforeNode); - if (index == -1) { - throw new Error('Node not found'); - } - - // adjust the link to the parent - node.setParent(this); - node.fieldEditable = (this.type == 'object'); - this.childs.splice(index, 0, node); - } - - if (this.expanded) { - // insert into the DOM - var newTr = node.getDom(); - var nextTr = beforeNode.getDom(); - var table = nextTr ? nextTr.parentNode : undefined; - if (nextTr && table) { - table.insertBefore(newTr, nextTr); - } - - node.showChilds(); - } - - this.updateDom({'updateIndexes': true}); - node.updateDom({'recurse': true}); + // adjust the link to the parent + node.setParent(this); + node.fieldEditable = (this.type == 'object'); + this.childs.push(node); } + else { + // insert before a child node + var index = this.childs.indexOf(beforeNode); + if (index == -1) { + throw new Error('Node not found'); + } + + // adjust the link to the parent + node.setParent(this); + node.fieldEditable = (this.type == 'object'); + this.childs.splice(index, 0, node); + } + + if (this.expanded) { + // insert into the DOM + var newTr = node.getDom(); + var nextTr = beforeNode.getDom(); + var table = nextTr ? nextTr.parentNode : undefined; + if (nextTr && table) { + table.insertBefore(newTr, nextTr); + } + + node.showChilds(); + } + + this.updateDom({'updateIndexes': true}); + node.updateDom({'recurse': true}); + } }; /** @@ -474,16 +474,16 @@ Node.prototype.insertBefore = function(node, beforeNode) { * @param {Node} afterNode */ Node.prototype.insertAfter = function(node, afterNode) { - if (this._hasChilds()) { - var index = this.childs.indexOf(afterNode); - var beforeNode = this.childs[index + 1]; - if (beforeNode) { - this.insertBefore(node, beforeNode); - } - else { - this.appendChild(node); - } + if (this._hasChilds()) { + var index = this.childs.indexOf(afterNode); + var beforeNode = this.childs[index + 1]; + if (beforeNode) { + this.insertBefore(node, beforeNode); } + else { + this.appendChild(node); + } + } }; /** @@ -494,73 +494,73 @@ Node.prototype.insertAfter = function(node, afterNode) { * @return {Node[]} results Array with nodes containing the search text */ Node.prototype.search = function(text) { - var results = []; - var index; - var search = text ? text.toLowerCase() : undefined; + var results = []; + var index; + var search = text ? text.toLowerCase() : undefined; - // delete old search data - delete this.searchField; - delete this.searchValue; + // delete old search data + delete this.searchField; + delete this.searchValue; - // search in field - if (this.field != undefined) { - var field = String(this.field).toLowerCase(); - index = field.indexOf(search); - if (index != -1) { - this.searchField = true; - results.push({ - 'node': this, - 'elem': 'field' - }); - } - - // update dom - this._updateDomField(); + // search in field + if (this.field != undefined) { + var field = String(this.field).toLowerCase(); + index = field.indexOf(search); + if (index != -1) { + this.searchField = true; + results.push({ + 'node': this, + 'elem': 'field' + }); } - // search in value - if (this._hasChilds()) { - // array, object + // update dom + this._updateDomField(); + } - // search the nodes childs - if (this.childs) { - var childResults = []; - this.childs.forEach(function (child) { - childResults = childResults.concat(child.search(text)); - }); - results = results.concat(childResults); - } + // search in value + if (this._hasChilds()) { + // array, object - // update dom - if (search != undefined) { - var recurse = false; - if (childResults.length == 0) { - this.collapse(recurse); - } - else { - this.expand(recurse); - } - } - } - else { - // string, auto - if (this.value != undefined ) { - var value = String(this.value).toLowerCase(); - index = value.indexOf(search); - if (index != -1) { - this.searchValue = true; - results.push({ - 'node': this, - 'elem': 'value' - }); - } - } - - // update dom - this._updateDomValue(); + // search the nodes childs + if (this.childs) { + var childResults = []; + this.childs.forEach(function (child) { + childResults = childResults.concat(child.search(text)); + }); + results = results.concat(childResults); } - return results; + // update dom + if (search != undefined) { + var recurse = false; + if (childResults.length == 0) { + this.collapse(recurse); + } + else { + this.expand(recurse); + } + } + } + else { + // string, auto + if (this.value != undefined ) { + var value = String(this.value).toLowerCase(); + index = value.indexOf(search); + if (index != -1) { + this.searchValue = true; + results.push({ + 'node': this, + 'elem': 'value' + }); + } + } + + // update dom + this._updateDomValue(); + } + + return results; }; /** @@ -569,19 +569,19 @@ Node.prototype.search = function(text) { * @param {function(boolean)} [callback] */ Node.prototype.scrollTo = function(callback) { - if (!this.dom.tr || !this.dom.tr.parentNode) { - // if the node is not visible, expand its parents - var parent = this.parent; - var recurse = false; - while (parent) { - parent.expand(recurse); - parent = parent.parent; - } + if (!this.dom.tr || !this.dom.tr.parentNode) { + // if the node is not visible, expand its parents + var parent = this.parent; + var recurse = false; + while (parent) { + parent.expand(recurse); + parent = parent.parent; } + } - if (this.dom.tr && this.dom.tr.parentNode) { - this.editor.scrollTo(this.dom.tr.offsetTop, callback); - } + if (this.dom.tr && this.dom.tr.parentNode) { + this.editor.scrollTo(this.dom.tr.offsetTop, callback); + } }; @@ -595,78 +595,78 @@ Node.focusElement = undefined; * 'expand', 'field', 'value' (default) */ Node.prototype.focus = function(elementName) { - Node.focusElement = elementName; + Node.focusElement = elementName; - if (this.dom.tr && this.dom.tr.parentNode) { - var dom = this.dom; + if (this.dom.tr && this.dom.tr.parentNode) { + var dom = this.dom; - switch (elementName) { - case 'drag': - if (dom.drag) { - dom.drag.focus(); - } - else { - dom.menu.focus(); - } - break; - - case 'menu': - dom.menu.focus(); - break; - - case 'expand': - if (this._hasChilds()) { - dom.expand.focus(); - } - else if (dom.field && this.fieldEditable) { - dom.field.focus(); - util.selectContentEditable(dom.field); - } - else if (dom.value && !this._hasChilds()) { - dom.value.focus(); - util.selectContentEditable(dom.value); - } - else { - dom.menu.focus(); - } - break; - - case 'field': - if (dom.field && this.fieldEditable) { - dom.field.focus(); - util.selectContentEditable(dom.field); - } - else if (dom.value && !this._hasChilds()) { - dom.value.focus(); - util.selectContentEditable(dom.value); - } - else if (this._hasChilds()) { - dom.expand.focus(); - } - else { - dom.menu.focus(); - } - break; - - case 'value': - default: - if (dom.value && !this._hasChilds()) { - dom.value.focus(); - util.selectContentEditable(dom.value); - } - else if (dom.field && this.fieldEditable) { - dom.field.focus(); - util.selectContentEditable(dom.field); - } - else if (this._hasChilds()) { - dom.expand.focus(); - } - else { - dom.menu.focus(); - } - break; + switch (elementName) { + case 'drag': + if (dom.drag) { + dom.drag.focus(); } + else { + dom.menu.focus(); + } + break; + + case 'menu': + dom.menu.focus(); + break; + + case 'expand': + if (this._hasChilds()) { + dom.expand.focus(); + } + else if (dom.field && this.fieldEditable) { + dom.field.focus(); + util.selectContentEditable(dom.field); + } + else if (dom.value && !this._hasChilds()) { + dom.value.focus(); + util.selectContentEditable(dom.value); + } + else { + dom.menu.focus(); + } + break; + + case 'field': + if (dom.field && this.fieldEditable) { + dom.field.focus(); + util.selectContentEditable(dom.field); + } + else if (dom.value && !this._hasChilds()) { + dom.value.focus(); + util.selectContentEditable(dom.value); + } + else if (this._hasChilds()) { + dom.expand.focus(); + } + else { + dom.menu.focus(); + } + break; + + case 'value': + default: + if (dom.value && !this._hasChilds()) { + dom.value.focus(); + util.selectContentEditable(dom.value); + } + else if (dom.field && this.fieldEditable) { + dom.field.focus(); + util.selectContentEditable(dom.field); + } + else if (this._hasChilds()) { + dom.expand.focus(); + } + else { + dom.menu.focus(); + } + break; } + } }; /** @@ -674,18 +674,18 @@ Node.prototype.focus = function(elementName) { * @param {Element} editableDiv */ Node.select = function(editableDiv) { - setTimeout(function () { - util.selectContentEditable(editableDiv); - }, 0); + setTimeout(function () { + util.selectContentEditable(editableDiv); + }, 0); }; /** * Update the values from the DOM field and value of this node */ Node.prototype.blur = function() { - // retrieve the actual field and value from the DOM. - this._getDomValue(false); - this._getDomField(false); + // retrieve the actual field and value from the DOM. + this._getDomValue(false); + this._getDomField(false); }; /** @@ -696,16 +696,16 @@ Node.prototype.blur = function() { * @private */ Node.prototype._duplicate = function(node) { - var clone = node.clone(); + var clone = node.clone(); - /* TODO: adjust the field name (to prevent equal field names) - if (this.type == 'object') { - } - */ + /* TODO: adjust the field name (to prevent equal field names) + if (this.type == 'object') { + } + */ - this.insertAfter(clone, node); + this.insertAfter(clone, node); - return clone; + return clone; }; /** @@ -715,21 +715,21 @@ Node.prototype._duplicate = function(node) { * @return {boolean} containsNode */ Node.prototype.containsNode = function(node) { - if (this == node) { + if (this == node) { + return true; + } + + var childs = this.childs; + if (childs) { + // TODO: use the js5 Array.some() here? + for (var i = 0, iMax = childs.length; i < iMax; i++) { + if (childs[i].containsNode(node)) { return true; + } } + } - var childs = this.childs; - if (childs) { - // TODO: use the js5 Array.some() here? - for (var i = 0, iMax = childs.length; i < iMax; i++) { - if (childs[i].containsNode(node)) { - return true; - } - } - } - - return false; + return false; }; /** @@ -741,37 +741,37 @@ Node.prototype.containsNode = function(node) { * @private */ Node.prototype._move = function(node, beforeNode) { - if (node == beforeNode) { - // nothing to do... - return; - } + if (node == beforeNode) { + // nothing to do... + return; + } - // check if this node is not a child of the node to be moved here - if (node.containsNode(this)) { - throw new Error('Cannot move a field into a child of itself'); - } + // check if this node is not a child of the node to be moved here + if (node.containsNode(this)) { + throw new Error('Cannot move a field into a child of itself'); + } - // remove the original node - if (node.parent) { - node.parent.removeChild(node); - } + // remove the original node + if (node.parent) { + node.parent.removeChild(node); + } - // create a clone of the node - var clone = node.clone(); - node.clearDom(); + // create a clone of the node + var clone = node.clone(); + node.clearDom(); - // insert or append the node - if (beforeNode) { - this.insertBefore(clone, beforeNode); - } - else { - this.appendChild(clone); - } + // insert or append the node + if (beforeNode) { + this.insertBefore(clone, beforeNode); + } + else { + this.appendChild(clone); + } - /* TODO: adjust the field name (to prevent equal field names) - if (this.type == 'object') { - } - */ + /* TODO: adjust the field name (to prevent equal field names) + if (this.type == 'object') { + } + */ }; /** @@ -782,25 +782,25 @@ Node.prototype._move = function(node, beforeNode) { * else undefined */ Node.prototype.removeChild = function(node) { - if (this.childs) { - var index = this.childs.indexOf(node); + if (this.childs) { + var index = this.childs.indexOf(node); - if (index != -1) { - node.hide(); + if (index != -1) { + node.hide(); - // delete old search results - delete node.searchField; - delete node.searchValue; + // delete old search results + delete node.searchField; + delete node.searchValue; - var removedNode = this.childs.splice(index, 1)[0]; + var removedNode = this.childs.splice(index, 1)[0]; - this.updateDom({'updateIndexes': true}); + this.updateDom({'updateIndexes': true}); - return removedNode; - } + return removedNode; } + } - return undefined; + return undefined; }; /** @@ -811,7 +811,7 @@ Node.prototype.removeChild = function(node) { * @private */ Node.prototype._remove = function (node) { - this.removeChild(node); + this.removeChild(node); }; /** @@ -819,100 +819,100 @@ Node.prototype._remove = function (node) { * @param {String} newType */ Node.prototype.changeType = function (newType) { - var oldType = this.type; + var oldType = this.type; - if (oldType == newType) { - // type is not changed - return; - } + if (oldType == newType) { + // type is not changed + return; + } - if ((newType == 'string' || newType == 'auto') && - (oldType == 'string' || oldType == 'auto')) { - // this is an easy change - this.type = newType; + if ((newType == 'string' || newType == 'auto') && + (oldType == 'string' || oldType == 'auto')) { + // this is an easy change + this.type = newType; + } + else { + // change from array to object, or from string/auto to object/array + var table = this.dom.tr ? this.dom.tr.parentNode : undefined; + var lastTr; + if (this.expanded) { + lastTr = this.getAppend(); } else { - // change from array to object, or from string/auto to object/array - var table = this.dom.tr ? this.dom.tr.parentNode : undefined; - var lastTr; - if (this.expanded) { - lastTr = this.getAppend(); + lastTr = this.getDom(); + } + var nextTr = (lastTr && lastTr.parentNode) ? lastTr.nextSibling : undefined; + + // hide current field and all its childs + this.hide(); + this.clearDom(); + + // adjust the field and the value + this.type = newType; + + // adjust childs + if (newType == 'object') { + if (!this.childs) { + this.childs = []; + } + + this.childs.forEach(function (child, index) { + child.clearDom(); + delete child.index; + child.fieldEditable = true; + if (child.field == undefined) { + child.field = ''; } - else { - lastTr = this.getDom(); - } - var nextTr = (lastTr && lastTr.parentNode) ? lastTr.nextSibling : undefined; + }); - // hide current field and all its childs - this.hide(); - this.clearDom(); + if (oldType == 'string' || oldType == 'auto') { + this.expanded = true; + } + } + else if (newType == 'array') { + if (!this.childs) { + this.childs = []; + } - // adjust the field and the value - this.type = newType; + this.childs.forEach(function (child, index) { + child.clearDom(); + child.fieldEditable = false; + child.index = index; + }); - // adjust childs - if (newType == 'object') { - if (!this.childs) { - this.childs = []; - } - - this.childs.forEach(function (child, index) { - child.clearDom(); - delete child.index; - child.fieldEditable = true; - if (child.field == undefined) { - child.field = ''; - } - }); - - if (oldType == 'string' || oldType == 'auto') { - this.expanded = true; - } - } - else if (newType == 'array') { - if (!this.childs) { - this.childs = []; - } - - this.childs.forEach(function (child, index) { - child.clearDom(); - child.fieldEditable = false; - child.index = index; - }); - - if (oldType == 'string' || oldType == 'auto') { - this.expanded = true; - } - } - else { - this.expanded = false; - } - - // create new DOM - if (table) { - if (nextTr) { - table.insertBefore(this.getDom(), nextTr); - } - else { - table.appendChild(this.getDom()); - } - } - this.showChilds(); + if (oldType == 'string' || oldType == 'auto') { + this.expanded = true; + } + } + else { + this.expanded = false; } - if (newType == 'auto' || newType == 'string') { - // cast value to the correct type - if (newType == 'string') { - this.value = String(this.value); - } - else { - this.value = this._stringCast(String(this.value)); - } + // create new DOM + if (table) { + if (nextTr) { + table.insertBefore(this.getDom(), nextTr); + } + else { + table.appendChild(this.getDom()); + } + } + this.showChilds(); + } - this.focus(); + if (newType == 'auto' || newType == 'string') { + // cast value to the correct type + if (newType == 'string') { + this.value = String(this.value); + } + else { + this.value = this._stringCast(String(this.value)); } - this.updateDom({'updateIndexes': true}); + this.focus(); + } + + this.updateDom({'updateIndexes': true}); }; /** @@ -922,41 +922,41 @@ Node.prototype.changeType = function (newType) { * @private */ Node.prototype._getDomValue = function(silent) { - if (this.dom.value && this.type != 'array' && this.type != 'object') { - this.valueInnerText = util.getInnerText(this.dom.value); - } + if (this.dom.value && this.type != 'array' && this.type != 'object') { + this.valueInnerText = util.getInnerText(this.dom.value); + } - if (this.valueInnerText != undefined) { - try { - // retrieve the value - var value; - if (this.type == 'string') { - value = this._unescapeHTML(this.valueInnerText); - } - else { - var str = this._unescapeHTML(this.valueInnerText); - value = this._stringCast(str); - } - if (value !== this.value) { - var oldValue = this.value; - this.value = value; - this.editor._onAction('editValue', { - 'node': this, - 'oldValue': oldValue, - 'newValue': value, - 'oldSelection': this.editor.selection, - 'newSelection': this.editor.getSelection() - }); - } - } - catch (err) { - this.value = undefined; - // TODO: sent an action with the new, invalid value? - if (silent != true) { - throw err; - } - } + if (this.valueInnerText != undefined) { + try { + // retrieve the value + var value; + if (this.type == 'string') { + value = this._unescapeHTML(this.valueInnerText); + } + else { + var str = this._unescapeHTML(this.valueInnerText); + value = this._stringCast(str); + } + if (value !== this.value) { + var oldValue = this.value; + this.value = value; + this.editor._onAction('editValue', { + 'node': this, + 'oldValue': oldValue, + 'newValue': value, + 'oldSelection': this.editor.selection, + 'newSelection': this.editor.getSelection() + }); + } } + catch (err) { + this.value = undefined; + // TODO: sent an action with the new, invalid value? + if (silent != true) { + throw err; + } + } + } }; /** @@ -967,86 +967,86 @@ Node.prototype._getDomValue = function(silent) { * @private */ Node.prototype._updateDomValue = function () { - var domValue = this.dom.value; - if (domValue) { - // set text color depending on value type - // TODO: put colors in css - var v = this.value; - var t = (this.type == 'auto') ? util.type(v) : this.type; - var isUrl = (t == 'string' && util.isUrl(v)); - var color = ''; - if (isUrl && !this.editor.mode.edit) { - color = ''; - } - else if (t == 'string') { - color = 'green'; - } - else if (t == 'number') { - color = 'red'; - } - else if (t == 'boolean') { - color = 'darkorange'; - } - else if (this._hasChilds()) { - color = ''; - } - else if (v === null) { - color = '#004ED0'; // blue - } - else { - // invalid value - color = 'black'; - } - domValue.style.color = color; - - // make background color light-gray when empty - var isEmpty = (String(this.value) == '' && this.type != 'array' && this.type != 'object'); - if (isEmpty) { - util.addClassName(domValue, 'empty'); - } - else { - util.removeClassName(domValue, 'empty'); - } - - // underline url - if (isUrl) { - util.addClassName(domValue, 'url'); - } - else { - util.removeClassName(domValue, 'url'); - } - - // update title - if (t == 'array' || t == 'object') { - var count = this.childs ? this.childs.length : 0; - domValue.title = this.type + ' containing ' + count + ' items'; - } - else if (t == 'string' && util.isUrl(v)) { - if (this.editor.mode.edit) { - domValue.title = 'Ctrl+Click or Ctrl+Enter to open url in new window'; - } - } - else { - domValue.title = ''; - } - - // highlight when there is a search result - if (this.searchValueActive) { - util.addClassName(domValue, 'highlight-active'); - } - else { - util.removeClassName(domValue, 'highlight-active'); - } - if (this.searchValue) { - util.addClassName(domValue, 'highlight'); - } - else { - util.removeClassName(domValue, 'highlight'); - } - - // strip formatting from the contents of the editable div - util.stripFormatting(domValue); + var domValue = this.dom.value; + if (domValue) { + // set text color depending on value type + // TODO: put colors in css + var v = this.value; + var t = (this.type == 'auto') ? util.type(v) : this.type; + var isUrl = (t == 'string' && util.isUrl(v)); + var color = ''; + if (isUrl && !this.editor.mode.edit) { + color = ''; } + else if (t == 'string') { + color = 'green'; + } + else if (t == 'number') { + color = 'red'; + } + else if (t == 'boolean') { + color = 'darkorange'; + } + else if (this._hasChilds()) { + color = ''; + } + else if (v === null) { + color = '#004ED0'; // blue + } + else { + // invalid value + color = 'black'; + } + domValue.style.color = color; + + // make background color light-gray when empty + var isEmpty = (String(this.value) == '' && this.type != 'array' && this.type != 'object'); + if (isEmpty) { + util.addClassName(domValue, 'empty'); + } + else { + util.removeClassName(domValue, 'empty'); + } + + // underline url + if (isUrl) { + util.addClassName(domValue, 'url'); + } + else { + util.removeClassName(domValue, 'url'); + } + + // update title + if (t == 'array' || t == 'object') { + var count = this.childs ? this.childs.length : 0; + domValue.title = this.type + ' containing ' + count + ' items'; + } + else if (t == 'string' && util.isUrl(v)) { + if (this.editor.mode.edit) { + domValue.title = 'Ctrl+Click or Ctrl+Enter to open url in new window'; + } + } + else { + domValue.title = ''; + } + + // highlight when there is a search result + if (this.searchValueActive) { + util.addClassName(domValue, 'highlight-active'); + } + else { + util.removeClassName(domValue, 'highlight-active'); + } + if (this.searchValue) { + util.addClassName(domValue, 'highlight'); + } + else { + util.removeClassName(domValue, 'highlight'); + } + + // strip formatting from the contents of the editable div + util.stripFormatting(domValue); + } }; /** @@ -1057,34 +1057,34 @@ Node.prototype._updateDomValue = function () { * @private */ Node.prototype._updateDomField = function () { - var domField = this.dom.field; - if (domField) { - // make backgound color lightgray when empty - var isEmpty = (String(this.field) == '' && this.parent.type != 'array'); - if (isEmpty) { - util.addClassName(domField, 'empty'); - } - else { - util.removeClassName(domField, 'empty'); - } - - // highlight when there is a search result - if (this.searchFieldActive) { - util.addClassName(domField, 'highlight-active'); - } - else { - util.removeClassName(domField, 'highlight-active'); - } - if (this.searchField) { - util.addClassName(domField, 'highlight'); - } - else { - util.removeClassName(domField, 'highlight'); - } - - // strip formatting from the contents of the editable div - util.stripFormatting(domField); + var domField = this.dom.field; + if (domField) { + // make backgound color lightgray when empty + var isEmpty = (String(this.field) == '' && this.parent.type != 'array'); + if (isEmpty) { + util.addClassName(domField, 'empty'); } + else { + util.removeClassName(domField, 'empty'); + } + + // highlight when there is a search result + if (this.searchFieldActive) { + util.addClassName(domField, 'highlight-active'); + } + else { + util.removeClassName(domField, 'highlight-active'); + } + if (this.searchField) { + util.addClassName(domField, 'highlight'); + } + else { + util.removeClassName(domField, 'highlight'); + } + + // strip formatting from the contents of the editable div + util.stripFormatting(domField); + } }; /** @@ -1094,45 +1094,45 @@ Node.prototype._updateDomField = function () { * @private */ Node.prototype._getDomField = function(silent) { - if (this.dom.field && this.fieldEditable) { - this.fieldInnerText = util.getInnerText(this.dom.field); - } + if (this.dom.field && this.fieldEditable) { + this.fieldInnerText = util.getInnerText(this.dom.field); + } - if (this.fieldInnerText != undefined) { - try { - var field = this._unescapeHTML(this.fieldInnerText); + if (this.fieldInnerText != undefined) { + try { + var field = this._unescapeHTML(this.fieldInnerText); - if (field !== this.field) { - var oldField = this.field; - this.field = field; - this.editor._onAction('editField', { - 'node': this, - 'oldValue': oldField, - 'newValue': field, - 'oldSelection': this.editor.selection, - 'newSelection': this.editor.getSelection() - }); - } - } - catch (err) { - this.field = undefined; - // TODO: sent an action here, with the new, invalid value? - if (silent != true) { - throw err; - } - } + if (field !== this.field) { + var oldField = this.field; + this.field = field; + this.editor._onAction('editField', { + 'node': this, + 'oldValue': oldField, + 'newValue': field, + 'oldSelection': this.editor.selection, + 'newSelection': this.editor.getSelection() + }); + } } + catch (err) { + this.field = undefined; + // TODO: sent an action here, with the new, invalid value? + if (silent != true) { + throw err; + } + } + } }; /** * Clear the dom of the node */ Node.prototype.clearDom = function() { - // TODO: hide the node first? - //this.hide(); - // TODO: recursively clear dom? + // TODO: hide the node first? + //this.hide(); + // TODO: recursively clear dom? - this.dom = {}; + this.dom = {}; }; /** @@ -1141,46 +1141,46 @@ Node.prototype.clearDom = function() { * @return {Element} tr HTML DOM TR Element */ Node.prototype.getDom = function() { - var dom = this.dom; - if (dom.tr) { - return dom.tr; - } - - // create row - dom.tr = document.createElement('tr'); - dom.tr.node = this; - - if (this.editor.mode.edit) { - // create draggable area - var tdDrag = document.createElement('td'); - if (this.parent) { - var domDrag = document.createElement('button'); - dom.drag = domDrag; - domDrag.className = 'dragarea'; - domDrag.title = 'Drag to move this field (Alt+Shift+Arrows)'; - tdDrag.appendChild(domDrag); - } - dom.tr.appendChild(tdDrag); - - // create context menu - var tdMenu = document.createElement('td'); - var menu = document.createElement('button'); - dom.menu = menu; - menu.className = 'contextmenu'; - menu.title = 'Click to open the actions menu (Ctrl+M)'; - tdMenu.appendChild(dom.menu); - dom.tr.appendChild(tdMenu); - } - - // create tree and field - var tdField = document.createElement('td'); - dom.tr.appendChild(tdField); - dom.tree = this._createDomTree(); - tdField.appendChild(dom.tree); - - this.updateDom({'updateIndexes': true}); - + var dom = this.dom; + if (dom.tr) { return dom.tr; + } + + // create row + dom.tr = document.createElement('tr'); + dom.tr.node = this; + + if (this.editor.mode.edit) { + // create draggable area + var tdDrag = document.createElement('td'); + if (this.parent) { + var domDrag = document.createElement('button'); + dom.drag = domDrag; + domDrag.className = 'dragarea'; + domDrag.title = 'Drag to move this field (Alt+Shift+Arrows)'; + tdDrag.appendChild(domDrag); + } + dom.tr.appendChild(tdDrag); + + // create context menu + var tdMenu = document.createElement('td'); + var menu = document.createElement('button'); + dom.menu = menu; + menu.className = 'contextmenu'; + menu.title = 'Click to open the actions menu (Ctrl+M)'; + tdMenu.appendChild(dom.menu); + dom.tr.appendChild(tdMenu); + } + + // create tree and field + var tdField = document.createElement('td'); + dom.tr.appendChild(tdField); + dom.tree = this._createDomTree(); + tdField.appendChild(dom.tree); + + this.updateDom({'updateIndexes': true}); + + return dom.tr; }; /** @@ -1189,32 +1189,32 @@ Node.prototype.getDom = function() { * @private */ Node.prototype._onDragStart = function (event) { - var node = this; - if (!this.mousemove) { - this.mousemove = util.addEventListener(document, 'mousemove', - function (event) { - node._onDrag(event); - }); - } + var node = this; + if (!this.mousemove) { + this.mousemove = util.addEventListener(document, 'mousemove', + function (event) { + node._onDrag(event); + }); + } - if (!this.mouseup) { - this.mouseup = util.addEventListener(document, 'mouseup', - function (event ) { - node._onDragEnd(event); - }); - } + if (!this.mouseup) { + this.mouseup = util.addEventListener(document, 'mouseup', + function (event ) { + node._onDragEnd(event); + }); + } - this.editor.highlighter.lock(); - this.drag = { - 'oldCursor': document.body.style.cursor, - 'startParent': this.parent, - 'startIndex': this.parent.childs.indexOf(this), - 'mouseX': event.pageX, - 'level': this.getLevel() - }; - document.body.style.cursor = 'move'; + this.editor.highlighter.lock(); + this.drag = { + 'oldCursor': document.body.style.cursor, + 'startParent': this.parent, + 'startIndex': this.parent.childs.indexOf(this), + 'mouseX': event.pageX, + 'level': this.getLevel() + }; + document.body.style.cursor = 'move'; - event.preventDefault(); + event.preventDefault(); }; /** @@ -1223,140 +1223,140 @@ Node.prototype._onDragStart = function (event) { * @private */ Node.prototype._onDrag = function (event) { - // TODO: this method has grown too large. Split it in a number of methods - var mouseY = event.pageY; - var mouseX = event.pageX; + // TODO: this method has grown too large. Split it in a number of methods + var mouseY = event.pageY; + var mouseX = event.pageX; - var trThis, trPrev, trNext, trFirst, trLast, trRoot; - var nodePrev, nodeNext; - var topThis, topPrev, topFirst, heightThis, bottomNext, heightNext; - var moved = false; + var trThis, trPrev, trNext, trFirst, trLast, trRoot; + var nodePrev, nodeNext; + var topThis, topPrev, topFirst, heightThis, bottomNext, heightNext; + var moved = false; - // TODO: add an ESC option, which resets to the original position + // TODO: add an ESC option, which resets to the original position - // move up/down - trThis = this.dom.tr; - topThis = util.getAbsoluteTop(trThis); - heightThis = trThis.offsetHeight; - if (mouseY < topThis) { - // move up - trPrev = trThis; - do { - trPrev = trPrev.previousSibling; - nodePrev = Node.getNodeFromTarget(trPrev); - topPrev = trPrev ? util.getAbsoluteTop(trPrev) : 0; - } - while (trPrev && mouseY < topPrev); - - if (nodePrev && !nodePrev.parent) { - nodePrev = undefined; - } - - if (!nodePrev) { - // move to the first node - trRoot = trThis.parentNode.firstChild; - trPrev = trRoot ? trRoot.nextSibling : undefined; - nodePrev = Node.getNodeFromTarget(trPrev); - if (nodePrev == this) { - nodePrev = undefined; - } - } - - if (nodePrev) { - // check if mouseY is really inside the found node - trPrev = nodePrev.dom.tr; - topPrev = trPrev ? util.getAbsoluteTop(trPrev) : 0; - if (mouseY > topPrev + heightThis) { - nodePrev = undefined; - } - } - - if (nodePrev) { - nodePrev.parent.moveBefore(this, nodePrev); - moved = true; - } + // move up/down + trThis = this.dom.tr; + topThis = util.getAbsoluteTop(trThis); + heightThis = trThis.offsetHeight; + if (mouseY < topThis) { + // move up + trPrev = trThis; + do { + trPrev = trPrev.previousSibling; + nodePrev = Node.getNodeFromTarget(trPrev); + topPrev = trPrev ? util.getAbsoluteTop(trPrev) : 0; } - else { - // move down - trLast = (this.expanded && this.append) ? this.append.getDom() : this.dom.tr; - trFirst = trLast ? trLast.nextSibling : undefined; - if (trFirst) { - topFirst = util.getAbsoluteTop(trFirst); - trNext = trFirst; - do { - nodeNext = Node.getNodeFromTarget(trNext); - if (trNext) { - bottomNext = trNext.nextSibling ? - util.getAbsoluteTop(trNext.nextSibling) : 0; - heightNext = trNext ? (bottomNext - topFirst) : 0; + while (trPrev && mouseY < topPrev); - if (nodeNext.parent.childs.length == 1 && nodeNext.parent.childs[0] == this) { - // We are about to remove the last child of this parent, - // which will make the parents appendNode visible. - topThis += 24 - 1; - // TODO: dangerous to suppose the height of the appendNode a constant of 24-1 px. - } - } - - trNext = trNext.nextSibling; - } - while (trNext && mouseY > topThis + heightNext); - - if (nodeNext && nodeNext.parent) { - // calculate the desired level - var diffX = (mouseX - this.drag.mouseX); - var diffLevel = Math.round(diffX / 24 / 2); - var level = this.drag.level + diffLevel; // desired level - var levelNext = nodeNext.getLevel(); // level to be - - // find the best fitting level (move upwards over the append nodes) - trPrev = nodeNext.dom.tr.previousSibling; - while (levelNext < level && trPrev) { - nodePrev = Node.getNodeFromTarget(trPrev); - if (nodePrev == this || nodePrev._isChildOf(this)) { - // neglect itself and its childs - } - else if (nodePrev instanceof AppendNode) { - var childs = nodePrev.parent.childs; - if (childs.length > 1 || - (childs.length == 1 && childs[0] != this)) { - // non-visible append node of a list of childs - // consisting of not only this node (else the - // append node will change into a visible "empty" - // text when removing this node). - nodeNext = Node.getNodeFromTarget(trPrev); - levelNext = nodeNext.getLevel(); - } - else { - break; - } - } - else { - break; - } - - trPrev = trPrev.previousSibling; - } - - // move the node when its position is changed - if (trLast.nextSibling != nodeNext.dom.tr) { - nodeNext.parent.moveBefore(this, nodeNext); - moved = true; - } - } - } + if (nodePrev && !nodePrev.parent) { + nodePrev = undefined; } - if (moved) { - // update the dragging parameters when moved - this.drag.mouseX = mouseX; - this.drag.level = this.getLevel(); + if (!nodePrev) { + // move to the first node + trRoot = trThis.parentNode.firstChild; + trPrev = trRoot ? trRoot.nextSibling : undefined; + nodePrev = Node.getNodeFromTarget(trPrev); + if (nodePrev == this) { + nodePrev = undefined; + } } - // auto scroll when hovering around the top of the editor - this.editor.startAutoScroll(mouseY); + if (nodePrev) { + // check if mouseY is really inside the found node + trPrev = nodePrev.dom.tr; + topPrev = trPrev ? util.getAbsoluteTop(trPrev) : 0; + if (mouseY > topPrev + heightThis) { + nodePrev = undefined; + } + } - event.preventDefault(); + if (nodePrev) { + nodePrev.parent.moveBefore(this, nodePrev); + moved = true; + } + } + else { + // move down + trLast = (this.expanded && this.append) ? this.append.getDom() : this.dom.tr; + trFirst = trLast ? trLast.nextSibling : undefined; + if (trFirst) { + topFirst = util.getAbsoluteTop(trFirst); + trNext = trFirst; + do { + nodeNext = Node.getNodeFromTarget(trNext); + if (trNext) { + bottomNext = trNext.nextSibling ? + util.getAbsoluteTop(trNext.nextSibling) : 0; + heightNext = trNext ? (bottomNext - topFirst) : 0; + + if (nodeNext.parent.childs.length == 1 && nodeNext.parent.childs[0] == this) { + // We are about to remove the last child of this parent, + // which will make the parents appendNode visible. + topThis += 24 - 1; + // TODO: dangerous to suppose the height of the appendNode a constant of 24-1 px. + } + } + + trNext = trNext.nextSibling; + } + while (trNext && mouseY > topThis + heightNext); + + if (nodeNext && nodeNext.parent) { + // calculate the desired level + var diffX = (mouseX - this.drag.mouseX); + var diffLevel = Math.round(diffX / 24 / 2); + var level = this.drag.level + diffLevel; // desired level + var levelNext = nodeNext.getLevel(); // level to be + + // find the best fitting level (move upwards over the append nodes) + trPrev = nodeNext.dom.tr.previousSibling; + while (levelNext < level && trPrev) { + nodePrev = Node.getNodeFromTarget(trPrev); + if (nodePrev == this || nodePrev._isChildOf(this)) { + // neglect itself and its childs + } + else if (nodePrev instanceof AppendNode) { + var childs = nodePrev.parent.childs; + if (childs.length > 1 || + (childs.length == 1 && childs[0] != this)) { + // non-visible append node of a list of childs + // consisting of not only this node (else the + // append node will change into a visible "empty" + // text when removing this node). + nodeNext = Node.getNodeFromTarget(trPrev); + levelNext = nodeNext.getLevel(); + } + else { + break; + } + } + else { + break; + } + + trPrev = trPrev.previousSibling; + } + + // move the node when its position is changed + if (trLast.nextSibling != nodeNext.dom.tr) { + nodeNext.parent.moveBefore(this, nodeNext); + moved = true; + } + } + } + } + + if (moved) { + // update the dragging parameters when moved + this.drag.mouseX = mouseX; + this.drag.level = this.getLevel(); + } + + // auto scroll when hovering around the top of the editor + this.editor.startAutoScroll(mouseY); + + event.preventDefault(); }; /** @@ -1365,35 +1365,35 @@ Node.prototype._onDrag = function (event) { * @private */ Node.prototype._onDragEnd = function (event) { - var params = { - 'node': this, - 'startParent': this.drag.startParent, - 'startIndex': this.drag.startIndex, - 'endParent': this.parent, - 'endIndex': this.parent.childs.indexOf(this) - }; - if ((params.startParent != params.endParent) || - (params.startIndex != params.endIndex)) { - // only register this action if the node is actually moved to another place - this.editor._onAction('moveNode', params); - } + var params = { + 'node': this, + 'startParent': this.drag.startParent, + 'startIndex': this.drag.startIndex, + 'endParent': this.parent, + 'endIndex': this.parent.childs.indexOf(this) + }; + if ((params.startParent != params.endParent) || + (params.startIndex != params.endIndex)) { + // only register this action if the node is actually moved to another place + this.editor._onAction('moveNode', params); + } - document.body.style.cursor = this.drag.oldCursor; - this.editor.highlighter.unlock(); - delete this.drag; + document.body.style.cursor = this.drag.oldCursor; + this.editor.highlighter.unlock(); + delete this.drag; - if (this.mousemove) { - util.removeEventListener(document, 'mousemove', this.mousemove); - delete this.mousemove;} - if (this.mouseup) { - util.removeEventListener(document, 'mouseup', this.mouseup); - delete this.mouseup; - } + if (this.mousemove) { + util.removeEventListener(document, 'mousemove', this.mousemove); + delete this.mousemove;} + if (this.mouseup) { + util.removeEventListener(document, 'mouseup', this.mouseup); + delete this.mouseup; + } - // Stop any running auto scroll - this.editor.stopAutoScroll(); + // Stop any running auto scroll + this.editor.stopAutoScroll(); - event.preventDefault(); + event.preventDefault(); }; /** @@ -1403,15 +1403,15 @@ Node.prototype._onDragEnd = function (event) { * @private */ Node.prototype._isChildOf = function (node) { - var n = this.parent; - while (n) { - if (n == node) { - return true; - } - n = n.parent; + var n = this.parent; + while (n) { + if (n == node) { + return true; } + n = n.parent; + } - return false; + return false; }; /** @@ -1420,7 +1420,7 @@ Node.prototype._isChildOf = function (node) { * @private */ Node.prototype._createDomField = function () { - return document.createElement('div'); + return document.createElement('div'); }; /** @@ -1429,19 +1429,19 @@ Node.prototype._createDomField = function () { * @param {boolean} highlight */ Node.prototype.setHighlight = function (highlight) { - if (this.dom.tr) { - this.dom.tr.className = (highlight ? 'highlight' : ''); + if (this.dom.tr) { + this.dom.tr.className = (highlight ? 'highlight' : ''); - if (this.append) { - this.append.setHighlight(highlight); - } - - if (this.childs) { - this.childs.forEach(function (child) { - child.setHighlight(highlight); - }); - } + if (this.append) { + this.append.setHighlight(highlight); } + + if (this.childs) { + this.childs.forEach(function (child) { + child.setHighlight(highlight); + }); + } + } }; /** @@ -1450,8 +1450,8 @@ Node.prototype.setHighlight = function (highlight) { * @param {String | Number | Boolean | null} value */ Node.prototype.updateValue = function (value) { - this.value = value; - this.updateDom(); + this.value = value; + this.updateDom(); }; /** @@ -1459,8 +1459,8 @@ Node.prototype.updateValue = function (value) { * @param {String} field */ Node.prototype.updateField = function (field) { - this.field = field; - this.updateDom(); + this.field = field; + this.updateDom(); }; /** @@ -1474,80 +1474,80 @@ Node.prototype.updateField = function (field) { * default. */ Node.prototype.updateDom = function (options) { - // update level indentation - var domTree = this.dom.tree; - if (domTree) { - domTree.style.marginLeft = this.getLevel() * 24 + 'px'; + // update level indentation + var domTree = this.dom.tree; + if (domTree) { + domTree.style.marginLeft = this.getLevel() * 24 + 'px'; + } + + // update field + var domField = this.dom.field; + if (domField) { + if (this.fieldEditable == true) { + // parent is an object + domField.contentEditable = this.editor.mode.edit; + domField.spellcheck = false; + domField.className = 'field'; + } + else { + // parent is an array this is the root node + domField.className = 'readonly'; } - // update field - var domField = this.dom.field; - if (domField) { - if (this.fieldEditable == true) { - // parent is an object - domField.contentEditable = this.editor.mode.edit; - domField.spellcheck = false; - domField.className = 'field'; - } - else { - // parent is an array this is the root node - domField.className = 'readonly'; - } - - var field; - if (this.index != undefined) { - field = this.index; - } - else if (this.field != undefined) { - field = this.field; - } - else if (this._hasChilds()) { - field = this.type; - } - else { - field = ''; - } - domField.innerHTML = this._escapeHTML(field); + var field; + if (this.index != undefined) { + field = this.index; } - - // update value - var domValue = this.dom.value; - if (domValue) { - var count = this.childs ? this.childs.length : 0; - if (this.type == 'array') { - domValue.innerHTML = '[' + count + ']'; - } - else if (this.type == 'object') { - domValue.innerHTML = '{' + count + '}'; - } - else { - domValue.innerHTML = this._escapeHTML(this.value); - } + else if (this.field != undefined) { + field = this.field; } - - // update field and value - this._updateDomField(); - this._updateDomValue(); - - // update childs indexes - if (options && options.updateIndexes == true) { - // updateIndexes is true or undefined - this._updateDomIndexes(); + else if (this._hasChilds()) { + field = this.type; } - - if (options && options.recurse == true) { - // recurse is true or undefined. update childs recursively - if (this.childs) { - this.childs.forEach(function (child) { - child.updateDom(options); - }); - } + else { + field = ''; } + domField.innerHTML = this._escapeHTML(field); + } - // update row with append button - if (this.append) { - this.append.updateDom(); + // update value + var domValue = this.dom.value; + if (domValue) { + var count = this.childs ? this.childs.length : 0; + if (this.type == 'array') { + domValue.innerHTML = '[' + count + ']'; } + else if (this.type == 'object') { + domValue.innerHTML = '{' + count + '}'; + } + else { + domValue.innerHTML = this._escapeHTML(this.value); + } + } + + // update field and value + this._updateDomField(); + this._updateDomValue(); + + // update childs indexes + if (options && options.updateIndexes == true) { + // updateIndexes is true or undefined + this._updateDomIndexes(); + } + + if (options && options.recurse == true) { + // recurse is true or undefined. update childs recursively + if (this.childs) { + this.childs.forEach(function (child) { + child.updateDom(options); + }); + } + } + + // update row with append button + if (this.append) { + this.append.updateDom(); + } }; /** @@ -1557,30 +1557,30 @@ Node.prototype.updateDom = function (options) { * @private */ Node.prototype._updateDomIndexes = function () { - var domValue = this.dom.value; - var childs = this.childs; - if (domValue && childs) { - if (this.type == 'array') { - childs.forEach(function (child, index) { - child.index = index; - var childField = child.dom.field; - if (childField) { - childField.innerHTML = index; - } - }); - } - else if (this.type == 'object') { - childs.forEach(function (child) { - if (child.index != undefined) { - delete child.index; - - if (child.field == undefined) { - child.field = ''; - } - } - }); + var domValue = this.dom.value; + var childs = this.childs; + if (domValue && childs) { + if (this.type == 'array') { + childs.forEach(function (child, index) { + child.index = index; + var childField = child.dom.field; + if (childField) { + childField.innerHTML = index; } + }); } + else if (this.type == 'object') { + childs.forEach(function (child) { + if (child.index != undefined) { + delete child.index; + + if (child.field == undefined) { + child.field = ''; + } + } + }); + } + } }; /** @@ -1588,38 +1588,38 @@ Node.prototype._updateDomIndexes = function () { * @private */ Node.prototype._createDomValue = function () { - var domValue; + var domValue; - if (this.type == 'array') { - domValue = document.createElement('div'); - domValue.className = 'readonly'; - domValue.innerHTML = '[...]'; - } - else if (this.type == 'object') { - domValue = document.createElement('div'); - domValue.className = 'readonly'; - domValue.innerHTML = '{...}'; + if (this.type == 'array') { + domValue = document.createElement('div'); + domValue.className = 'readonly'; + domValue.innerHTML = '[...]'; + } + else if (this.type == 'object') { + domValue = document.createElement('div'); + domValue.className = 'readonly'; + domValue.innerHTML = '{...}'; + } + else { + if (!this.editor.mode.edit && util.isUrl(this.value)) { + // create a link in case of read-only editor and value containing an url + domValue = document.createElement('a'); + domValue.className = 'value'; + domValue.href = this.value; + domValue.target = '_blank'; + domValue.innerHTML = this._escapeHTML(this.value); } else { - if (!this.editor.mode.edit && util.isUrl(this.value)) { - // create a link in case of read-only editor and value containing an url - domValue = document.createElement('a'); - domValue.className = 'value'; - domValue.href = this.value; - domValue.target = '_blank'; - domValue.innerHTML = this._escapeHTML(this.value); - } - else { - // create and editable or read-only div - domValue = document.createElement('div'); - domValue.contentEditable = !this.editor.mode.view; - domValue.spellcheck = false; - domValue.className = 'value'; - domValue.innerHTML = this._escapeHTML(this.value); - } + // create and editable or read-only div + domValue = document.createElement('div'); + domValue.contentEditable = !this.editor.mode.view; + domValue.spellcheck = false; + domValue.className = 'value'; + domValue.innerHTML = this._escapeHTML(this.value); } + } - return domValue; + return domValue; }; /** @@ -1628,20 +1628,20 @@ Node.prototype._createDomValue = function () { * @private */ Node.prototype._createDomExpandButton = function () { - // create expand button - var expand = document.createElement('button'); - if (this._hasChilds()) { - expand.className = this.expanded ? 'expanded' : 'collapsed'; - expand.title = - 'Click to expand/collapse this field (Ctrl+E). \n' + - 'Ctrl+Click to expand/collapse including all childs.'; - } - else { - expand.className = 'invisible'; - expand.title = ''; - } + // create expand button + var expand = document.createElement('button'); + if (this._hasChilds()) { + expand.className = this.expanded ? 'expanded' : 'collapsed'; + expand.title = + 'Click to expand/collapse this field (Ctrl+E). \n' + + 'Ctrl+Click to expand/collapse including all childs.'; + } + else { + expand.className = 'invisible'; + expand.title = ''; + } - return expand; + return expand; }; @@ -1651,50 +1651,50 @@ Node.prototype._createDomExpandButton = function () { * @private */ Node.prototype._createDomTree = function () { - var dom = this.dom; - var domTree = document.createElement('table'); - var tbody = document.createElement('tbody'); - domTree.style.borderCollapse = 'collapse'; // TODO: put in css - domTree.className = 'values'; - domTree.appendChild(tbody); - var tr = document.createElement('tr'); - tbody.appendChild(tr); + var dom = this.dom; + var domTree = document.createElement('table'); + var tbody = document.createElement('tbody'); + domTree.style.borderCollapse = 'collapse'; // TODO: put in css + domTree.className = 'values'; + domTree.appendChild(tbody); + var tr = document.createElement('tr'); + tbody.appendChild(tr); - // create expand button - var tdExpand = document.createElement('td'); - tdExpand.className = 'tree'; - tr.appendChild(tdExpand); - dom.expand = this._createDomExpandButton(); - tdExpand.appendChild(dom.expand); - dom.tdExpand = tdExpand; + // create expand button + var tdExpand = document.createElement('td'); + tdExpand.className = 'tree'; + tr.appendChild(tdExpand); + dom.expand = this._createDomExpandButton(); + tdExpand.appendChild(dom.expand); + dom.tdExpand = tdExpand; - // create the field - var tdField = document.createElement('td'); - tdField.className = 'tree'; - tr.appendChild(tdField); - dom.field = this._createDomField(); - tdField.appendChild(dom.field); - dom.tdField = tdField; + // create the field + var tdField = document.createElement('td'); + tdField.className = 'tree'; + tr.appendChild(tdField); + dom.field = this._createDomField(); + tdField.appendChild(dom.field); + dom.tdField = tdField; - // create a separator - var tdSeparator = document.createElement('td'); - tdSeparator.className = 'tree'; - tr.appendChild(tdSeparator); - if (this.type != 'object' && this.type != 'array') { - tdSeparator.appendChild(document.createTextNode(':')); - tdSeparator.className = 'separator'; - } - dom.tdSeparator = tdSeparator; + // create a separator + var tdSeparator = document.createElement('td'); + tdSeparator.className = 'tree'; + tr.appendChild(tdSeparator); + if (this.type != 'object' && this.type != 'array') { + tdSeparator.appendChild(document.createTextNode(':')); + tdSeparator.className = 'separator'; + } + dom.tdSeparator = tdSeparator; - // create the value - var tdValue = document.createElement('td'); - tdValue.className = 'tree'; - tr.appendChild(tdValue); - dom.value = this._createDomValue(); - tdValue.appendChild(dom.value); - dom.tdValue = tdValue; + // create the value + var tdValue = document.createElement('td'); + tdValue.className = 'tree'; + tr.appendChild(tdValue); + dom.value = this._createDomValue(); + tdValue.appendChild(dom.value); + dom.tdValue = tdValue; - return domTree; + return domTree; }; /** @@ -1702,183 +1702,183 @@ Node.prototype._createDomTree = function () { * @param {Event} event */ Node.prototype.onEvent = function (event) { - var type = event.type, - target = event.target || event.srcElement, - dom = this.dom, - node = this, - focusNode, - expandable = this._hasChilds(); + var type = event.type, + target = event.target || event.srcElement, + dom = this.dom, + node = this, + focusNode, + expandable = this._hasChilds(); - // check if mouse is on menu or on dragarea. - // If so, highlight current row and its childs - if (target == dom.drag || target == dom.menu) { - if (type == 'mouseover') { - this.editor.highlighter.highlight(this); + // check if mouse is on menu or on dragarea. + // If so, highlight current row and its childs + if (target == dom.drag || target == dom.menu) { + if (type == 'mouseover') { + this.editor.highlighter.highlight(this); + } + else if (type == 'mouseout') { + this.editor.highlighter.unhighlight(); + } + } + + // drag events + if (type == 'mousedown' && target == dom.drag) { + this._onDragStart(event); + } + + // context menu events + if (type == 'click' && target == dom.menu) { + var highlighter = node.editor.highlighter; + highlighter.highlight(node); + highlighter.lock(); + util.addClassName(dom.menu, 'selected'); + this.showContextMenu(dom.menu, function () { + util.removeClassName(dom.menu, 'selected'); + highlighter.unlock(); + highlighter.unhighlight(); + }); + } + + // expand events + if (type == 'click' && target == dom.expand) { + if (expandable) { + var recurse = event.ctrlKey; // with ctrl-key, expand/collapse all + this._onExpand(recurse); + } + } + + // value events + var domValue = dom.value; + if (target == domValue) { + //noinspection FallthroughInSwitchStatementJS + switch (type) { + case 'focus': + focusNode = this; + break; + + case 'blur': + case 'change': + this._getDomValue(true); + this._updateDomValue(); + if (this.value) { + domValue.innerHTML = this._escapeHTML(this.value); } - else if (type == 'mouseout') { - this.editor.highlighter.unhighlight(); + break; + + case 'input': + this._getDomValue(true); + this._updateDomValue(); + break; + + case 'keydown': + case 'mousedown': + this.editor.selection = this.editor.getSelection(); + break; + + case 'click': + if (event.ctrlKey && this.editor.mode.edit) { + if (util.isUrl(this.value)) { + window.open(this.value, '_blank'); + } } - } + break; - // drag events - if (type == 'mousedown' && target == dom.drag) { - this._onDragStart(event); - } + case 'keyup': + this._getDomValue(true); + this._updateDomValue(); + break; - // context menu events - if (type == 'click' && target == dom.menu) { - var highlighter = node.editor.highlighter; - highlighter.highlight(node); - highlighter.lock(); - util.addClassName(dom.menu, 'selected'); - this.showContextMenu(dom.menu, function () { - util.removeClassName(dom.menu, 'selected'); - highlighter.unlock(); - highlighter.unhighlight(); - }); + case 'cut': + case 'paste': + setTimeout(function () { + node._getDomValue(true); + node._updateDomValue(); + }, 1); + break; } + } - // expand events - if (type == 'click' && target == dom.expand) { - if (expandable) { - var recurse = event.ctrlKey; // with ctrl-key, expand/collapse all - this._onExpand(recurse); + // field events + var domField = dom.field; + if (target == domField) { + switch (type) { + case 'focus': + focusNode = this; + break; + + case 'blur': + case 'change': + this._getDomField(true); + this._updateDomField(); + if (this.field) { + domField.innerHTML = this._escapeHTML(this.field); } + break; + + case 'input': + this._getDomField(true); + this._updateDomField(); + break; + + case 'keydown': + case 'mousedown': + this.editor.selection = this.editor.getSelection(); + break; + + case 'keyup': + this._getDomField(true); + this._updateDomField(); + break; + + case 'cut': + case 'paste': + setTimeout(function () { + node._getDomField(true); + node._updateDomField(); + }, 1); + break; } + } - // value events - var domValue = dom.value; - if (target == domValue) { - //noinspection FallthroughInSwitchStatementJS - switch (type) { - case 'focus': - focusNode = this; - break; - - case 'blur': - case 'change': - this._getDomValue(true); - this._updateDomValue(); - if (this.value) { - domValue.innerHTML = this._escapeHTML(this.value); - } - break; - - case 'input': - this._getDomValue(true); - this._updateDomValue(); - break; - - case 'keydown': - case 'mousedown': - this.editor.selection = this.editor.getSelection(); - break; - - case 'click': - if (event.ctrlKey && this.editor.mode.edit) { - if (util.isUrl(this.value)) { - window.open(this.value, '_blank'); - } - } - break; - - case 'keyup': - this._getDomValue(true); - this._updateDomValue(); - break; - - case 'cut': - case 'paste': - setTimeout(function () { - node._getDomValue(true); - node._updateDomValue(); - }, 1); - break; + // focus + // when clicked in whitespace left or right from the field or value, set focus + var domTree = dom.tree; + if (target == domTree.parentNode) { + switch (type) { + case 'click': + var left = (event.offsetX != undefined) ? + (event.offsetX < (this.getLevel() + 1) * 24) : + (event.pageX < util.getAbsoluteLeft(dom.tdSeparator));// for FF + if (left || expandable) { + // node is expandable when it is an object or array + if (domField) { + util.setEndOfContentEditable(domField); + domField.focus(); + } } - } - - // field events - var domField = dom.field; - if (target == domField) { - switch (type) { - case 'focus': - focusNode = this; - break; - - case 'blur': - case 'change': - this._getDomField(true); - this._updateDomField(); - if (this.field) { - domField.innerHTML = this._escapeHTML(this.field); - } - break; - - case 'input': - this._getDomField(true); - this._updateDomField(); - break; - - case 'keydown': - case 'mousedown': - this.editor.selection = this.editor.getSelection(); - break; - - case 'keyup': - this._getDomField(true); - this._updateDomField(); - break; - - case 'cut': - case 'paste': - setTimeout(function () { - node._getDomField(true); - node._updateDomField(); - }, 1); - break; + else { + if (domValue) { + util.setEndOfContentEditable(domValue); + domValue.focus(); + } } + break; } - - // focus - // when clicked in whitespace left or right from the field or value, set focus - var domTree = dom.tree; - if (target == domTree.parentNode) { - switch (type) { - case 'click': - var left = (event.offsetX != undefined) ? - (event.offsetX < (this.getLevel() + 1) * 24) : - (event.pageX < util.getAbsoluteLeft(dom.tdSeparator));// for FF - if (left || expandable) { - // node is expandable when it is an object or array - if (domField) { - util.setEndOfContentEditable(domField); - domField.focus(); - } - } - else { - if (domValue) { - util.setEndOfContentEditable(domValue); - domValue.focus(); - } - } - break; - } - } - if ((target == dom.tdExpand && !expandable) || target == dom.tdField || - target == dom.tdSeparator) { - switch (type) { - case 'click': - if (domField) { - util.setEndOfContentEditable(domField); - domField.focus(); - } - break; + } + if ((target == dom.tdExpand && !expandable) || target == dom.tdField || + target == dom.tdSeparator) { + switch (type) { + case 'click': + if (domField) { + util.setEndOfContentEditable(domField); + domField.focus(); } + break; } + } - if (type == 'keydown') { - this.onKeyDown(event); - } + if (type == 'keydown') { + this.onKeyDown(event); + } }; /** @@ -1886,199 +1886,199 @@ Node.prototype.onEvent = function (event) { * @param {Event} event */ Node.prototype.onKeyDown = function (event) { - var keynum = event.which || event.keyCode; - var target = event.target || event.srcElement; - var ctrlKey = event.ctrlKey; - var shiftKey = event.shiftKey; - var altKey = event.altKey; - var handled = false; - var prevNode, nextNode, nextDom, nextDom2; + var keynum = event.which || event.keyCode; + var target = event.target || event.srcElement; + var ctrlKey = event.ctrlKey; + var shiftKey = event.shiftKey; + var altKey = event.altKey; + var handled = false; + var prevNode, nextNode, nextDom, nextDom2; - // util.log(ctrlKey, keynum, event.charCode); // TODO: cleanup - if (keynum == 13) { // Enter - if (target == this.dom.value) { - if (!this.editor.mode.edit || event.ctrlKey) { - if (util.isUrl(this.value)) { - window.open(this.value, '_blank'); - handled = true; - } - } - } - else if (target == this.dom.expand) { - var expandable = this._hasChilds(); - if (expandable) { - var recurse = event.ctrlKey; // with ctrl-key, expand/collapse all - this._onExpand(recurse); - target.focus(); - handled = true; - } + // util.log(ctrlKey, keynum, event.charCode); // TODO: cleanup + if (keynum == 13) { // Enter + if (target == this.dom.value) { + if (!this.editor.mode.edit || event.ctrlKey) { + if (util.isUrl(this.value)) { + window.open(this.value, '_blank'); + handled = true; } + } } - else if (keynum == 68) { // D - if (ctrlKey) { // Ctrl+D - this._onDuplicate(); - handled = true; - } + else if (target == this.dom.expand) { + var expandable = this._hasChilds(); + if (expandable) { + var recurse = event.ctrlKey; // with ctrl-key, expand/collapse all + this._onExpand(recurse); + target.focus(); + handled = true; + } } - else if (keynum == 69) { // E - if (ctrlKey) { // Ctrl+E and Ctrl+Shift+E - this._onExpand(shiftKey); // recurse = shiftKey - target.focus(); // TODO: should restore focus in case of recursing expand (which takes DOM offline) - handled = true; - } + } + else if (keynum == 68) { // D + if (ctrlKey) { // Ctrl+D + this._onDuplicate(); + handled = true; } - else if (keynum == 77) { // M - if (ctrlKey) { // Ctrl+M - this.showContextMenu(target); - handled = true; - } + } + else if (keynum == 69) { // E + if (ctrlKey) { // Ctrl+E and Ctrl+Shift+E + this._onExpand(shiftKey); // recurse = shiftKey + target.focus(); // TODO: should restore focus in case of recursing expand (which takes DOM offline) + handled = true; } - else if (keynum == 46) { // Del - if (ctrlKey) { // Ctrl+Del - this._onRemove(); - handled = true; - } + } + else if (keynum == 77) { // M + if (ctrlKey) { // Ctrl+M + this.showContextMenu(target); + handled = true; } - else if (keynum == 45) { // Ins - if (ctrlKey && !shiftKey) { // Ctrl+Ins - this._onInsertBefore(); - handled = true; - } - else if (ctrlKey && shiftKey) { // Ctrl+Shift+Ins - this._onInsertAfter(); - handled = true; - } + } + else if (keynum == 46) { // Del + if (ctrlKey) { // Ctrl+Del + this._onRemove(); + handled = true; } - else if (keynum == 35) { // End - if (altKey) { // Alt+End - // find the last node - var lastNode = this._lastNode(); - if (lastNode) { - lastNode.focus(Node.focusElement || this._getElementName(target)); - } - handled = true; - } + } + else if (keynum == 45) { // Ins + if (ctrlKey && !shiftKey) { // Ctrl+Ins + this._onInsertBefore(); + handled = true; } - else if (keynum == 36) { // Home - if (altKey) { // Alt+Home - // find the first node - var firstNode = this._firstNode(); - if (firstNode) { - firstNode.focus(Node.focusElement || this._getElementName(target)); - } - handled = true; - } + else if (ctrlKey && shiftKey) { // Ctrl+Shift+Ins + this._onInsertAfter(); + handled = true; } - else if (keynum == 37) { // Arrow Left - if (altKey && !shiftKey) { // Alt + Arrow Left - // move to left element - var prevElement = this._previousElement(target); - if (prevElement) { - this.focus(this._getElementName(prevElement)); - } - handled = true; - } - else if (altKey && shiftKey) { // Alt + Shift Arrow left - if (this.expanded) { - var appendDom = this.getAppend(); - nextDom = appendDom ? appendDom.nextSibling : undefined; - } - else { - var dom = this.getDom(); - nextDom = dom.nextSibling; - } - if (nextDom) { - nextNode = Node.getNodeFromTarget(nextDom); - nextDom2 = nextDom.nextSibling; - nextNode2 = Node.getNodeFromTarget(nextDom2); - if (nextNode && nextNode instanceof AppendNode && - !(this.parent.childs.length == 1) && - nextNode2 && nextNode2.parent) { - nextNode2.parent.moveBefore(this, nextNode2); - this.focus(Node.focusElement || this._getElementName(target)); - } - } - } + } + else if (keynum == 35) { // End + if (altKey) { // Alt+End + // find the last node + var lastNode = this._lastNode(); + if (lastNode) { + lastNode.focus(Node.focusElement || this._getElementName(target)); + } + handled = true; } - else if (keynum == 38) { // Arrow Up - if (altKey && !shiftKey) { // Alt + Arrow Up - // find the previous node - prevNode = this._previousNode(); - if (prevNode) { - prevNode.focus(Node.focusElement || this._getElementName(target)); - } - handled = true; - } - else if (altKey && shiftKey) { // Alt + Shift + Arrow Up - // find the previous node - prevNode = this._previousNode(); - if (prevNode && prevNode.parent) { - prevNode.parent.moveBefore(this, prevNode); - this.focus(Node.focusElement || this._getElementName(target)); - } - handled = true; - } + } + else if (keynum == 36) { // Home + if (altKey) { // Alt+Home + // find the first node + var firstNode = this._firstNode(); + if (firstNode) { + firstNode.focus(Node.focusElement || this._getElementName(target)); + } + handled = true; } - else if (keynum == 39) { // Arrow Right - if (altKey && !shiftKey) { // Alt + Arrow Right - // move to right element - var nextElement = this._nextElement(target); - if (nextElement) { - this.focus(this._getElementName(nextElement)); - } - handled = true; - } - else if (altKey && shiftKey) { // Alt + Shift Arrow Right - dom = this.getDom(); - var prevDom = dom.previousSibling; - if (prevDom) { - prevNode = Node.getNodeFromTarget(prevDom); - if (prevNode && prevNode.parent && - (prevNode instanceof AppendNode) - && !prevNode.isVisible()) { - prevNode.parent.moveBefore(this, prevNode); - this.focus(Node.focusElement || this._getElementName(target)); - } - } - } + } + else if (keynum == 37) { // Arrow Left + if (altKey && !shiftKey) { // Alt + Arrow Left + // move to left element + var prevElement = this._previousElement(target); + if (prevElement) { + this.focus(this._getElementName(prevElement)); + } + handled = true; } - else if (keynum == 40) { // Arrow Down - if (altKey && !shiftKey) { // Alt + Arrow Down - // find the next node - nextNode = this._nextNode(); - if (nextNode) { - nextNode.focus(Node.focusElement || this._getElementName(target)); - } - handled = true; - } - else if (altKey && shiftKey) { // Alt + Shift + Arrow Down - // find the 2nd next node and move before that one - if (this.expanded) { - nextNode = this.append ? this.append._nextNode() : undefined; - } - else { - nextNode = this._nextNode(); - } - nextDom = nextNode ? nextNode.getDom() : undefined; - if (this.parent.childs.length == 1) { - nextDom2 = nextDom; - } - else { - nextDom2 = nextDom ? nextDom.nextSibling : undefined; - } - var nextNode2 = Node.getNodeFromTarget(nextDom2); - if (nextNode2 && nextNode2.parent) { - nextNode2.parent.moveBefore(this, nextNode2); - this.focus(Node.focusElement || this._getElementName(target)); - } - handled = true; + else if (altKey && shiftKey) { // Alt + Shift Arrow left + if (this.expanded) { + var appendDom = this.getAppend(); + nextDom = appendDom ? appendDom.nextSibling : undefined; + } + else { + var dom = this.getDom(); + nextDom = dom.nextSibling; + } + if (nextDom) { + nextNode = Node.getNodeFromTarget(nextDom); + nextDom2 = nextDom.nextSibling; + nextNode2 = Node.getNodeFromTarget(nextDom2); + if (nextNode && nextNode instanceof AppendNode && + !(this.parent.childs.length == 1) && + nextNode2 && nextNode2.parent) { + nextNode2.parent.moveBefore(this, nextNode2); + this.focus(Node.focusElement || this._getElementName(target)); } + } } + } + else if (keynum == 38) { // Arrow Up + if (altKey && !shiftKey) { // Alt + Arrow Up + // find the previous node + prevNode = this._previousNode(); + if (prevNode) { + prevNode.focus(Node.focusElement || this._getElementName(target)); + } + handled = true; + } + else if (altKey && shiftKey) { // Alt + Shift + Arrow Up + // find the previous node + prevNode = this._previousNode(); + if (prevNode && prevNode.parent) { + prevNode.parent.moveBefore(this, prevNode); + this.focus(Node.focusElement || this._getElementName(target)); + } + handled = true; + } + } + else if (keynum == 39) { // Arrow Right + if (altKey && !shiftKey) { // Alt + Arrow Right + // move to right element + var nextElement = this._nextElement(target); + if (nextElement) { + this.focus(this._getElementName(nextElement)); + } + handled = true; + } + else if (altKey && shiftKey) { // Alt + Shift Arrow Right + dom = this.getDom(); + var prevDom = dom.previousSibling; + if (prevDom) { + prevNode = Node.getNodeFromTarget(prevDom); + if (prevNode && prevNode.parent && + (prevNode instanceof AppendNode) + && !prevNode.isVisible()) { + prevNode.parent.moveBefore(this, prevNode); + this.focus(Node.focusElement || this._getElementName(target)); + } + } + } + } + else if (keynum == 40) { // Arrow Down + if (altKey && !shiftKey) { // Alt + Arrow Down + // find the next node + nextNode = this._nextNode(); + if (nextNode) { + nextNode.focus(Node.focusElement || this._getElementName(target)); + } + handled = true; + } + else if (altKey && shiftKey) { // Alt + Shift + Arrow Down + // find the 2nd next node and move before that one + if (this.expanded) { + nextNode = this.append ? this.append._nextNode() : undefined; + } + else { + nextNode = this._nextNode(); + } + nextDom = nextNode ? nextNode.getDom() : undefined; + if (this.parent.childs.length == 1) { + nextDom2 = nextDom; + } + else { + nextDom2 = nextDom ? nextDom.nextSibling : undefined; + } + var nextNode2 = Node.getNodeFromTarget(nextDom2); + if (nextNode2 && nextNode2.parent) { + nextNode2.parent.moveBefore(this, nextNode2); + this.focus(Node.focusElement || this._getElementName(target)); + } + handled = true; + } + } - if (handled) { - event.preventDefault(); - event.stopPropagation(); - } + if (handled) { + event.preventDefault(); + event.stopPropagation(); + } }; /** @@ -2087,26 +2087,26 @@ Node.prototype.onKeyDown = function (event) { * @private */ Node.prototype._onExpand = function (recurse) { - if (recurse) { - // Take the table offline - var table = this.dom.tr.parentNode; // TODO: not nice to access the main table like this - var frame = table.parentNode; - var scrollTop = frame.scrollTop; - frame.removeChild(table); - } + if (recurse) { + // Take the table offline + var table = this.dom.tr.parentNode; // TODO: not nice to access the main table like this + var frame = table.parentNode; + var scrollTop = frame.scrollTop; + frame.removeChild(table); + } - if (this.expanded) { - this.collapse(recurse); - } - else { - this.expand(recurse); - } + if (this.expanded) { + this.collapse(recurse); + } + else { + this.expand(recurse); + } - if (recurse) { - // Put the table online again - frame.appendChild(table); - frame.scrollTop = scrollTop; - } + if (recurse) { + // Put the table online again + frame.appendChild(table); + frame.scrollTop = scrollTop; + } }; /** @@ -2114,34 +2114,34 @@ Node.prototype._onExpand = function (recurse) { * @private */ Node.prototype._onRemove = function() { - this.editor.highlighter.unhighlight(); - var childs = this.parent.childs; - var index = childs.indexOf(this); + this.editor.highlighter.unhighlight(); + var childs = this.parent.childs; + var index = childs.indexOf(this); - // adjust the focus - var oldSelection = this.editor.getSelection(); - if (childs[index + 1]) { - childs[index + 1].focus(); - } - else if (childs[index - 1]) { - childs[index - 1].focus(); - } - else { - this.parent.focus(); - } - var newSelection = this.editor.getSelection(); + // adjust the focus + var oldSelection = this.editor.getSelection(); + if (childs[index + 1]) { + childs[index + 1].focus(); + } + else if (childs[index - 1]) { + childs[index - 1].focus(); + } + else { + this.parent.focus(); + } + var newSelection = this.editor.getSelection(); - // remove the node - this.parent._remove(this); + // remove the node + this.parent._remove(this); - // store history action - this.editor._onAction('removeNode', { - 'node': this, - 'parent': this.parent, - 'index': index, - 'oldSelection': oldSelection, - 'newSelection': newSelection - }); + // store history action + this.editor._onAction('removeNode', { + 'node': this, + 'parent': this.parent, + 'index': index, + 'oldSelection': oldSelection, + 'newSelection': newSelection + }); }; /** @@ -2149,18 +2149,18 @@ Node.prototype._onRemove = function() { * @private */ Node.prototype._onDuplicate = function() { - var oldSelection = this.editor.getSelection(); - var clone = this.parent._duplicate(this); - clone.focus(); - var newSelection = this.editor.getSelection(); + var oldSelection = this.editor.getSelection(); + var clone = this.parent._duplicate(this); + clone.focus(); + var newSelection = this.editor.getSelection(); - this.editor._onAction('duplicateNode', { - 'node': this, - 'clone': clone, - 'parent': this.parent, - 'oldSelection': oldSelection, - 'newSelection': newSelection - }); + this.editor._onAction('duplicateNode', { + 'node': this, + 'clone': clone, + 'parent': this.parent, + 'oldSelection': oldSelection, + 'newSelection': newSelection + }); }; /** @@ -2171,26 +2171,26 @@ Node.prototype._onDuplicate = function() { * @private */ Node.prototype._onInsertBefore = function (field, value, type) { - var oldSelection = this.editor.getSelection(); + var oldSelection = this.editor.getSelection(); - var newNode = new Node(this.editor, { - 'field': (field != undefined) ? field : '', - 'value': (value != undefined) ? value : '', - 'type': type - }); - newNode.expand(true); - this.parent.insertBefore(newNode, this); - this.editor.highlighter.unhighlight(); - newNode.focus('field'); - var newSelection = this.editor.getSelection(); + var newNode = new Node(this.editor, { + 'field': (field != undefined) ? field : '', + 'value': (value != undefined) ? value : '', + 'type': type + }); + newNode.expand(true); + this.parent.insertBefore(newNode, this); + this.editor.highlighter.unhighlight(); + newNode.focus('field'); + var newSelection = this.editor.getSelection(); - this.editor._onAction('insertBeforeNode', { - 'node': newNode, - 'beforeNode': this, - 'parent': this.parent, - 'oldSelection': oldSelection, - 'newSelection': newSelection - }); + this.editor._onAction('insertBeforeNode', { + 'node': newNode, + 'beforeNode': this, + 'parent': this.parent, + 'oldSelection': oldSelection, + 'newSelection': newSelection + }); }; /** @@ -2201,26 +2201,26 @@ Node.prototype._onInsertBefore = function (field, value, type) { * @private */ Node.prototype._onInsertAfter = function (field, value, type) { - var oldSelection = this.editor.getSelection(); + var oldSelection = this.editor.getSelection(); - var newNode = new Node(this.editor, { - 'field': (field != undefined) ? field : '', - 'value': (value != undefined) ? value : '', - 'type': type - }); - newNode.expand(true); - this.parent.insertAfter(newNode, this); - this.editor.highlighter.unhighlight(); - newNode.focus('field'); - var newSelection = this.editor.getSelection(); + var newNode = new Node(this.editor, { + 'field': (field != undefined) ? field : '', + 'value': (value != undefined) ? value : '', + 'type': type + }); + newNode.expand(true); + this.parent.insertAfter(newNode, this); + this.editor.highlighter.unhighlight(); + newNode.focus('field'); + var newSelection = this.editor.getSelection(); - this.editor._onAction('insertAfterNode', { - 'node': newNode, - 'afterNode': this, - 'parent': this.parent, - 'oldSelection': oldSelection, - 'newSelection': newSelection - }); + this.editor._onAction('insertAfterNode', { + 'node': newNode, + 'afterNode': this, + 'parent': this.parent, + 'oldSelection': oldSelection, + 'newSelection': newSelection + }); }; /** @@ -2231,25 +2231,25 @@ Node.prototype._onInsertAfter = function (field, value, type) { * @private */ Node.prototype._onAppend = function (field, value, type) { - var oldSelection = this.editor.getSelection(); + var oldSelection = this.editor.getSelection(); - var newNode = new Node(this.editor, { - 'field': (field != undefined) ? field : '', - 'value': (value != undefined) ? value : '', - 'type': type - }); - newNode.expand(true); - this.parent.appendChild(newNode); - this.editor.highlighter.unhighlight(); - newNode.focus('field'); - var newSelection = this.editor.getSelection(); + var newNode = new Node(this.editor, { + 'field': (field != undefined) ? field : '', + 'value': (value != undefined) ? value : '', + 'type': type + }); + newNode.expand(true); + this.parent.appendChild(newNode); + this.editor.highlighter.unhighlight(); + newNode.focus('field'); + var newSelection = this.editor.getSelection(); - this.editor._onAction('appendNode', { - 'node': newNode, - 'parent': this.parent, - 'oldSelection': oldSelection, - 'newSelection': newSelection - }); + this.editor._onAction('appendNode', { + 'node': newNode, + 'parent': this.parent, + 'oldSelection': oldSelection, + 'newSelection': newSelection + }); }; /** @@ -2258,20 +2258,20 @@ Node.prototype._onAppend = function (field, value, type) { * @private */ Node.prototype._onChangeType = function (newType) { - var oldType = this.type; - if (newType != oldType) { - var oldSelection = this.editor.getSelection(); - this.changeType(newType); - var newSelection = this.editor.getSelection(); + var oldType = this.type; + if (newType != oldType) { + var oldSelection = this.editor.getSelection(); + this.changeType(newType); + var newSelection = this.editor.getSelection(); - this.editor._onAction('changeType', { - 'node': this, - 'oldType': oldType, - 'newType': newType, - 'oldSelection': oldSelection, - 'newSelection': newSelection - }); - } + this.editor._onAction('changeType', { + 'node': this, + 'oldType': oldType, + 'newType': newType, + 'oldSelection': oldSelection, + 'newSelection': newSelection + }); + } }; /** @@ -2281,35 +2281,35 @@ Node.prototype._onChangeType = function (newType) { * @private */ Node.prototype._onSort = function (direction) { - if (this._hasChilds()) { - var order = (direction == 'desc') ? -1 : 1; - var prop = (this.type == 'array') ? 'value': 'field'; - this.hideChilds(); + if (this._hasChilds()) { + var order = (direction == 'desc') ? -1 : 1; + var prop = (this.type == 'array') ? 'value': 'field'; + this.hideChilds(); - var oldChilds = this.childs; - var oldSort = this.sort; + var oldChilds = this.childs; + var oldSort = this.sort; - // copy the array (the old one will be kept for an undo action - this.childs = this.childs.concat(); + // copy the array (the old one will be kept for an undo action + this.childs = this.childs.concat(); - // sort the arrays - this.childs.sort(function (a, b) { - if (a[prop] > b[prop]) return order; - if (a[prop] < b[prop]) return -order; - return 0; - }); - this.sort = (order == 1) ? 'asc' : 'desc'; + // sort the arrays + this.childs.sort(function (a, b) { + if (a[prop] > b[prop]) return order; + if (a[prop] < b[prop]) return -order; + return 0; + }); + this.sort = (order == 1) ? 'asc' : 'desc'; - this.editor._onAction('sort', { - 'node': this, - 'oldChilds': oldChilds, - 'oldSort': oldSort, - 'newChilds': this.childs, - 'newSort': this.sort - }); + this.editor._onAction('sort', { + 'node': this, + 'oldChilds': oldChilds, + 'oldSort': oldSort, + 'newChilds': this.childs, + 'newSort': this.sort + }); - this.showChilds(); - } + this.showChilds(); + } }; /** @@ -2317,11 +2317,11 @@ Node.prototype._onSort = function (direction) { * @return {HTMLElement | undefined} buttonAppend or undefined when inapplicable */ Node.prototype.getAppend = function () { - if (!this.append) { - this.append = new AppendNode(this.editor); - this.append.setParent(this); - } - return this.append.getDom(); + if (!this.append) { + this.append = new AppendNode(this.editor); + this.append.setParent(this); + } + return this.append.getDom(); }; /** @@ -2331,14 +2331,14 @@ Node.prototype.getAppend = function () { * @static */ Node.getNodeFromTarget = function (target) { - while (target) { - if (target.node) { - return target.node; - } - target = target.parentNode; + while (target) { + if (target.node) { + return target.node; } + target = target.parentNode; + } - return undefined; + return undefined; }; /** @@ -2347,18 +2347,18 @@ Node.getNodeFromTarget = function (target) { * @private */ Node.prototype._previousNode = function () { - var prevNode = null; - var dom = this.getDom(); - if (dom && dom.parentNode) { - // find the previous field - var prevDom = dom; - do { - prevDom = prevDom.previousSibling; - prevNode = Node.getNodeFromTarget(prevDom); - } - while (prevDom && (prevNode instanceof AppendNode && !prevNode.isVisible())); + var prevNode = null; + var dom = this.getDom(); + if (dom && dom.parentNode) { + // find the previous field + var prevDom = dom; + do { + prevDom = prevDom.previousSibling; + prevNode = Node.getNodeFromTarget(prevDom); } - return prevNode; + while (prevDom && (prevNode instanceof AppendNode && !prevNode.isVisible())); + } + return prevNode; }; /** @@ -2367,19 +2367,19 @@ Node.prototype._previousNode = function () { * @private */ Node.prototype._nextNode = function () { - var nextNode = null; - var dom = this.getDom(); - if (dom && dom.parentNode) { - // find the previous field - var nextDom = dom; - do { - nextDom = nextDom.nextSibling; - nextNode = Node.getNodeFromTarget(nextDom); - } - while (nextDom && (nextNode instanceof AppendNode && !nextNode.isVisible())); + var nextNode = null; + var dom = this.getDom(); + if (dom && dom.parentNode) { + // find the previous field + var nextDom = dom; + do { + nextDom = nextDom.nextSibling; + nextNode = Node.getNodeFromTarget(nextDom); } + while (nextDom && (nextNode instanceof AppendNode && !nextNode.isVisible())); + } - return nextNode; + return nextNode; }; /** @@ -2388,14 +2388,14 @@ Node.prototype._nextNode = function () { * @private */ Node.prototype._firstNode = function () { - var firstNode = null; - var dom = this.getDom(); - if (dom && dom.parentNode) { - var firstDom = dom.parentNode.firstChild; - firstNode = Node.getNodeFromTarget(firstDom); - } + var firstNode = null; + var dom = this.getDom(); + if (dom && dom.parentNode) { + var firstDom = dom.parentNode.firstChild; + firstNode = Node.getNodeFromTarget(firstDom); + } - return firstNode; + return firstNode; }; /** @@ -2404,17 +2404,17 @@ Node.prototype._firstNode = function () { * @private */ Node.prototype._lastNode = function () { - var lastNode = null; - var dom = this.getDom(); - if (dom && dom.parentNode) { - var lastDom = dom.parentNode.lastChild; - lastNode = Node.getNodeFromTarget(lastDom); - while (lastDom && (lastNode instanceof AppendNode && !lastNode.isVisible())) { - lastDom = lastDom.previousSibling; - lastNode = Node.getNodeFromTarget(lastDom); - } + var lastNode = null; + var dom = this.getDom(); + if (dom && dom.parentNode) { + var lastDom = dom.parentNode.lastChild; + lastNode = Node.getNodeFromTarget(lastDom); + while (lastDom && (lastNode instanceof AppendNode && !lastNode.isVisible())) { + lastDom = lastDom.previousSibling; + lastNode = Node.getNodeFromTarget(lastDom); } - return lastNode; + } + return lastNode; }; /** @@ -2424,29 +2424,29 @@ Node.prototype._lastNode = function () { * @private */ Node.prototype._previousElement = function (elem) { - var dom = this.dom; - // noinspection FallthroughInSwitchStatementJS - switch (elem) { - case dom.value: - if (this.fieldEditable) { - return dom.field; - } - // intentional fall through - case dom.field: - if (this._hasChilds()) { - return dom.expand; - } - // intentional fall through - case dom.expand: - return dom.menu; - case dom.menu: - if (dom.drag) { - return dom.drag; - } - // intentional fall through - default: - return null; - } + var dom = this.dom; + // noinspection FallthroughInSwitchStatementJS + switch (elem) { + case dom.value: + if (this.fieldEditable) { + return dom.field; + } + // intentional fall through + case dom.field: + if (this._hasChilds()) { + return dom.expand; + } + // intentional fall through + case dom.expand: + return dom.menu; + case dom.menu: + if (dom.drag) { + return dom.drag; + } + // intentional fall through + default: + return null; + } }; /** @@ -2456,28 +2456,28 @@ Node.prototype._previousElement = function (elem) { * @private */ Node.prototype._nextElement = function (elem) { - var dom = this.dom; - // noinspection FallthroughInSwitchStatementJS - switch (elem) { - case dom.drag: - return dom.menu; - case dom.menu: - if (this._hasChilds()) { - return dom.expand; - } - // intentional fall through - case dom.expand: - if (this.fieldEditable) { - return dom.field; - } - // intentional fall through - case dom.field: - if (!this._hasChilds()) { - return dom.value; - } - default: - return null; - } + var dom = this.dom; + // noinspection FallthroughInSwitchStatementJS + switch (elem) { + case dom.drag: + return dom.menu; + case dom.menu: + if (this._hasChilds()) { + return dom.expand; + } + // intentional fall through + case dom.expand: + if (this.fieldEditable) { + return dom.field; + } + // intentional fall through + case dom.field: + if (!this._hasChilds()) { + return dom.value; + } + default: + return null; + } }; /** @@ -2489,15 +2489,15 @@ Node.prototype._nextElement = function (elem) { * @private */ Node.prototype._getElementName = function (element) { - var dom = this.dom; - for (var name in dom) { - if (dom.hasOwnProperty(name)) { - if (dom[name] == element) { - return name; - } - } + var dom = this.dom; + for (var name in dom) { + if (dom.hasOwnProperty(name)) { + if (dom[name] == element) { + return name; + } } - return null; + } + return null; }; /** @@ -2507,21 +2507,21 @@ Node.prototype._getElementName = function (element) { * @private */ Node.prototype._hasChilds = function () { - return this.type == 'array' || this.type == 'object'; + return this.type == 'array' || this.type == 'object'; }; // titles with explanation for the different types Node.TYPE_TITLES = { - 'auto': 'Field type "auto". ' + - 'The field type is automatically determined from the value ' + - 'and can be a string, number, boolean, or null.', - 'object': 'Field type "object". ' + - 'An object contains an unordered set of key/value pairs.', - 'array': 'Field type "array". ' + - 'An array contains an ordered collection of values.', - 'string': 'Field type "string". ' + - 'Field type is not determined from the value, ' + - 'but always returned as string.' + 'auto': 'Field type "auto". ' + + 'The field type is automatically determined from the value ' + + 'and can be a string, number, boolean, or null.', + 'object': 'Field type "object". ' + + 'An object contains an unordered set of key/value pairs.', + 'array': 'Field type "array". ' + + 'An array contains an ordered collection of values.', + 'string': 'Field type "string". ' + + 'Field type is not determined from the value, ' + + 'but always returned as string.' }; /** @@ -2531,206 +2531,206 @@ Node.TYPE_TITLES = { * is being closed. */ Node.prototype.showContextMenu = function (anchor, onClose) { - var node = this; - var titles = Node.TYPE_TITLES; - var items = []; + var node = this; + var titles = Node.TYPE_TITLES; + var items = []; + items.push({ + 'text': 'Type', + 'title': 'Change the type of this field', + 'className': 'type-' + this.type, + 'submenu': [ + { + 'text': 'Auto', + 'className': 'type-auto' + + (this.type == 'auto' ? ' selected' : ''), + 'title': titles.auto, + 'click': function () { + node._onChangeType('auto'); + } + }, + { + 'text': 'Array', + 'className': 'type-array' + + (this.type == 'array' ? ' selected' : ''), + 'title': titles.array, + 'click': function () { + node._onChangeType('array'); + } + }, + { + 'text': 'Object', + 'className': 'type-object' + + (this.type == 'object' ? ' selected' : ''), + 'title': titles.object, + 'click': function () { + node._onChangeType('object'); + } + }, + { + 'text': 'String', + 'className': 'type-string' + + (this.type == 'string' ? ' selected' : ''), + 'title': titles.string, + 'click': function () { + node._onChangeType('string'); + } + } + ] + }); + + if (this._hasChilds()) { + var direction = ((this.sort == 'asc') ? 'desc': 'asc'); items.push({ - 'text': 'Type', - 'title': 'Change the type of this field', - 'className': 'type-' + this.type, - 'submenu': [ - { - 'text': 'Auto', - 'className': 'type-auto' + - (this.type == 'auto' ? ' selected' : ''), - 'title': titles.auto, - 'click': function () { - node._onChangeType('auto'); - } - }, - { - 'text': 'Array', - 'className': 'type-array' + - (this.type == 'array' ? ' selected' : ''), - 'title': titles.array, - 'click': function () { - node._onChangeType('array'); - } - }, - { - 'text': 'Object', - 'className': 'type-object' + - (this.type == 'object' ? ' selected' : ''), - 'title': titles.object, - 'click': function () { - node._onChangeType('object'); - } - }, - { - 'text': 'String', - 'className': 'type-string' + - (this.type == 'string' ? ' selected' : ''), - 'title': titles.string, - 'click': function () { - node._onChangeType('string'); - } - } - ] + 'text': 'Sort', + 'title': 'Sort the childs of this ' + this.type, + 'className': 'sort-' + direction, + 'click': function () { + node._onSort(direction); + }, + 'submenu': [ + { + 'text': 'Ascending', + 'className': 'sort-asc', + 'title': 'Sort the childs of this ' + this.type + ' in ascending order', + 'click': function () { + node._onSort('asc'); + } + }, + { + 'text': 'Descending', + 'className': 'sort-desc', + 'title': 'Sort the childs of this ' + this.type +' in descending order', + 'click': function () { + node._onSort('desc'); + } + } + ] + }); + } + + if (this.parent && this.parent._hasChilds()) { + // create a separator + items.push({ + 'type': 'separator' }); - if (this._hasChilds()) { - var direction = ((this.sort == 'asc') ? 'desc': 'asc'); - items.push({ - 'text': 'Sort', - 'title': 'Sort the childs of this ' + this.type, - 'className': 'sort-' + direction, + // create append button (for last child node only) + var childs = node.parent.childs; + if (node == childs[childs.length - 1]) { + items.push({ + 'text': 'Append', + 'title': 'Append a new field with type \'auto\' after this field (Ctrl+Shift+Ins)', + 'submenuTitle': 'Select the type of the field to be appended', + 'className': 'append', + 'click': function () { + node._onAppend('', '', 'auto'); + }, + 'submenu': [ + { + 'text': 'Auto', + 'className': 'type-auto', + 'title': titles.auto, 'click': function () { - node._onSort(direction); - }, - 'submenu': [ - { - 'text': 'Ascending', - 'className': 'sort-asc', - 'title': 'Sort the childs of this ' + this.type + ' in ascending order', - 'click': function () { - node._onSort('asc'); - } - }, - { - 'text': 'Descending', - 'className': 'sort-desc', - 'title': 'Sort the childs of this ' + this.type +' in descending order', - 'click': function () { - node._onSort('desc'); - } - } - ] - }); + node._onAppend('', '', 'auto'); + } + }, + { + 'text': 'Array', + 'className': 'type-array', + 'title': titles.array, + 'click': function () { + node._onAppend('', []); + } + }, + { + 'text': 'Object', + 'className': 'type-object', + 'title': titles.object, + 'click': function () { + node._onAppend('', {}); + } + }, + { + 'text': 'String', + 'className': 'type-string', + 'title': titles.string, + 'click': function () { + node._onAppend('', '', 'string'); + } + } + ] + }); } - if (this.parent && this.parent._hasChilds()) { - // create a separator - items.push({ - 'type': 'separator' - }); - - // create append button (for last child node only) - var childs = node.parent.childs; - if (node == childs[childs.length - 1]) { - items.push({ - 'text': 'Append', - 'title': 'Append a new field with type \'auto\' after this field (Ctrl+Shift+Ins)', - 'submenuTitle': 'Select the type of the field to be appended', - 'className': 'append', - 'click': function () { - node._onAppend('', '', 'auto'); - }, - 'submenu': [ - { - 'text': 'Auto', - 'className': 'type-auto', - 'title': titles.auto, - 'click': function () { - node._onAppend('', '', 'auto'); - } - }, - { - 'text': 'Array', - 'className': 'type-array', - 'title': titles.array, - 'click': function () { - node._onAppend('', []); - } - }, - { - 'text': 'Object', - 'className': 'type-object', - 'title': titles.object, - 'click': function () { - node._onAppend('', {}); - } - }, - { - 'text': 'String', - 'className': 'type-string', - 'title': titles.string, - 'click': function () { - node._onAppend('', '', 'string'); - } - } - ] - }); + // create insert button + items.push({ + 'text': 'Insert', + 'title': 'Insert a new field with type \'auto\' before this field (Ctrl+Ins)', + 'submenuTitle': 'Select the type of the field to be inserted', + 'className': 'insert', + 'click': function () { + node._onInsertBefore('', '', 'auto'); + }, + 'submenu': [ + { + 'text': 'Auto', + 'className': 'type-auto', + 'title': titles.auto, + 'click': function () { + node._onInsertBefore('', '', 'auto'); + } + }, + { + 'text': 'Array', + 'className': 'type-array', + 'title': titles.array, + 'click': function () { + node._onInsertBefore('', []); + } + }, + { + 'text': 'Object', + 'className': 'type-object', + 'title': titles.object, + 'click': function () { + node._onInsertBefore('', {}); + } + }, + { + 'text': 'String', + 'className': 'type-string', + 'title': titles.string, + 'click': function () { + node._onInsertBefore('', '', 'string'); + } } + ] + }); - // create insert button - items.push({ - 'text': 'Insert', - 'title': 'Insert a new field with type \'auto\' before this field (Ctrl+Ins)', - 'submenuTitle': 'Select the type of the field to be inserted', - 'className': 'insert', - 'click': function () { - node._onInsertBefore('', '', 'auto'); - }, - 'submenu': [ - { - 'text': 'Auto', - 'className': 'type-auto', - 'title': titles.auto, - 'click': function () { - node._onInsertBefore('', '', 'auto'); - } - }, - { - 'text': 'Array', - 'className': 'type-array', - 'title': titles.array, - 'click': function () { - node._onInsertBefore('', []); - } - }, - { - 'text': 'Object', - 'className': 'type-object', - 'title': titles.object, - 'click': function () { - node._onInsertBefore('', {}); - } - }, - { - 'text': 'String', - 'className': 'type-string', - 'title': titles.string, - 'click': function () { - node._onInsertBefore('', '', 'string'); - } - } - ] - }); + // create duplicate button + items.push({ + 'text': 'Duplicate', + 'title': 'Duplicate this field (Ctrl+D)', + 'className': 'duplicate', + 'click': function () { + node._onDuplicate(); + } + }); - // create duplicate button - items.push({ - 'text': 'Duplicate', - 'title': 'Duplicate this field (Ctrl+D)', - 'className': 'duplicate', - 'click': function () { - node._onDuplicate(); - } - }); + // create remove button + items.push({ + 'text': 'Remove', + 'title': 'Remove this field (Ctrl+Del)', + 'className': 'remove', + 'click': function () { + node._onRemove(); + } + }); + } - // create remove button - items.push({ - 'text': 'Remove', - 'title': 'Remove this field (Ctrl+Del)', - 'className': 'remove', - 'click': function () { - node._onRemove(); - } - }); - } - - var menu = new ContextMenu(items, {close: onClose}); - menu.show(anchor); + var menu = new ContextMenu(items, {close: onClose}); + menu.show(anchor); }; /** @@ -2740,17 +2740,17 @@ Node.prototype.showContextMenu = function (anchor, onClose) { * @private */ Node.prototype._getType = function(value) { - if (value instanceof Array) { - return 'array'; - } - if (value instanceof Object) { - return 'object'; - } - if (typeof(value) == 'string' && typeof(this._stringCast(value)) != 'string') { - return 'string'; - } + if (value instanceof Array) { + return 'array'; + } + if (value instanceof Object) { + return 'object'; + } + if (typeof(value) == 'string' && typeof(this._stringCast(value)) != 'string') { + return 'string'; + } - return 'auto'; + return 'auto'; }; /** @@ -2761,28 +2761,28 @@ Node.prototype._getType = function(value) { * @private */ Node.prototype._stringCast = function(str) { - var lower = str.toLowerCase(), - num = Number(str), // will nicely fail with '123ab' - numFloat = parseFloat(str); // will nicely fail with ' ' + var lower = str.toLowerCase(), + num = Number(str), // will nicely fail with '123ab' + numFloat = parseFloat(str); // will nicely fail with ' ' - if (str == '') { - return ''; - } - else if (lower == 'null') { - return null; - } - else if (lower == 'true') { - return true; - } - else if (lower == 'false') { - return false; - } - else if (!isNaN(num) && !isNaN(numFloat)) { - return num; - } - else { - return str; - } + if (str == '') { + return ''; + } + else if (lower == 'null') { + return null; + } + else if (lower == 'true') { + return true; + } + else if (lower == 'false') { + return false; + } + else if (!isNaN(num) && !isNaN(numFloat)) { + return num; + } + else { + return str; + } }; /** @@ -2792,15 +2792,15 @@ Node.prototype._stringCast = function(str) { * @private */ Node.prototype._escapeHTML = function (text) { - var htmlEscaped = String(text) - .replace(//g, '>') - .replace(/ /g, ' ') // replace double space with an nbsp and space - .replace(/^ /, ' ') // space at start - .replace(/ $/, ' '); // space at end + var htmlEscaped = String(text) + .replace(//g, '>') + .replace(/ /g, ' ') // replace double space with an nbsp and space + .replace(/^ /, ' ') // space at start + .replace(/ $/, ' '); // space at end - var json = JSON.stringify(htmlEscaped); - return json.substring(1, json.length - 1); + var json = JSON.stringify(htmlEscaped); + return json.substring(1, json.length - 1); }; /** @@ -2810,12 +2810,12 @@ Node.prototype._escapeHTML = function (text) { * @private */ Node.prototype._unescapeHTML = function (escapedText) { - var json = '"' + this._escapeJSON(escapedText) + '"'; - var htmlEscaped = util.parse(json); - return htmlEscaped - .replace(/</g, '<') - .replace(/>/g, '>') - .replace(/ /g, ' '); + var json = '"' + this._escapeJSON(escapedText) + '"'; + var htmlEscaped = util.parse(json); + return htmlEscaped + .replace(/</g, '<') + .replace(/>/g, '>') + .replace(/ /g, ' '); }; /** @@ -2828,32 +2828,32 @@ Node.prototype._unescapeHTML = function (escapedText) { * @private */ Node.prototype._escapeJSON = function (text) { - // TODO: replace with some smart regex (only when a new solution is faster!) - var escaped = ''; - var i = 0, iMax = text.length; - while (i < iMax) { - var c = text.charAt(i); - if (c == '\n') { - escaped += '\\n'; - } - else if (c == '\\') { - escaped += c; - i++; - - c = text.charAt(i); - if ('"\\/bfnrtu'.indexOf(c) == -1) { - escaped += '\\'; // no valid escape character - } - escaped += c; - } - else if (c == '"') { - escaped += '\\"'; - } - else { - escaped += c; - } - i++; + // TODO: replace with some smart regex (only when a new solution is faster!) + var escaped = ''; + var i = 0, iMax = text.length; + while (i < iMax) { + var c = text.charAt(i); + if (c == '\n') { + escaped += '\\n'; } + else if (c == '\\') { + escaped += c; + i++; - return escaped; + c = text.charAt(i); + if ('"\\/bfnrtu'.indexOf(c) == -1) { + escaped += '\\'; // no valid escape character + } + escaped += c; + } + else if (c == '"') { + escaped += '\\"'; + } + else { + escaped += c; + } + i++; + } + + return escaped; }; diff --git a/jsoneditor/js/searchbox.js b/jsoneditor/js/searchbox.js index 4e9f366..3ce3640 100644 --- a/jsoneditor/js/searchbox.js +++ b/jsoneditor/js/searchbox.js @@ -6,97 +6,97 @@ * create the search box */ function SearchBox (editor, container) { - var searchBox = this; + var searchBox = this; - this.editor = editor; - this.timeout = undefined; - this.delay = 200; // ms - this.lastText = undefined; + this.editor = editor; + this.timeout = undefined; + this.delay = 200; // ms + this.lastText = undefined; - this.dom = {}; - this.dom.container = container; + this.dom = {}; + this.dom.container = container; - var table = document.createElement('table'); - this.dom.table = table; - table.className = 'search'; - container.appendChild(table); - var tbody = document.createElement('tbody'); - this.dom.tbody = tbody; - table.appendChild(tbody); - var tr = document.createElement('tr'); - tbody.appendChild(tr); + var table = document.createElement('table'); + this.dom.table = table; + table.className = 'search'; + container.appendChild(table); + var tbody = document.createElement('tbody'); + this.dom.tbody = tbody; + table.appendChild(tbody); + var tr = document.createElement('tr'); + tbody.appendChild(tr); - var td = document.createElement('td'); - tr.appendChild(td); - var results = document.createElement('div'); - this.dom.results = results; - results.className = 'results'; - td.appendChild(results); + var td = document.createElement('td'); + tr.appendChild(td); + var results = document.createElement('div'); + this.dom.results = results; + results.className = 'results'; + td.appendChild(results); - td = document.createElement('td'); - tr.appendChild(td); - var divInput = document.createElement('div'); - this.dom.input = divInput; - divInput.className = 'frame'; - divInput.title = 'Search fields and values'; - td.appendChild(divInput); + td = document.createElement('td'); + tr.appendChild(td); + var divInput = document.createElement('div'); + this.dom.input = divInput; + divInput.className = 'frame'; + divInput.title = 'Search fields and values'; + td.appendChild(divInput); - // table to contain the text input and search button - var tableInput = document.createElement('table'); - divInput.appendChild(tableInput); - var tbodySearch = document.createElement('tbody'); - tableInput.appendChild(tbodySearch); - tr = document.createElement('tr'); - tbodySearch.appendChild(tr); + // table to contain the text input and search button + var tableInput = document.createElement('table'); + divInput.appendChild(tableInput); + var tbodySearch = document.createElement('tbody'); + tableInput.appendChild(tbodySearch); + tr = document.createElement('tr'); + tbodySearch.appendChild(tr); - var refreshSearch = document.createElement('button'); - refreshSearch.className = 'refresh'; - td = document.createElement('td'); - td.appendChild(refreshSearch); - tr.appendChild(td); + var refreshSearch = document.createElement('button'); + refreshSearch.className = 'refresh'; + td = document.createElement('td'); + td.appendChild(refreshSearch); + tr.appendChild(td); - var search = document.createElement('input'); - this.dom.search = search; - search.oninput = function (event) { - searchBox._onDelayedSearch(event); - }; - search.onchange = function (event) { // For IE 9 - searchBox._onSearch(event); - }; - search.onkeydown = function (event) { - searchBox._onKeyDown(event); - }; - search.onkeyup = function (event) { - searchBox._onKeyUp(event); - }; - refreshSearch.onclick = function (event) { - search.select(); - }; + var search = document.createElement('input'); + this.dom.search = search; + search.oninput = function (event) { + searchBox._onDelayedSearch(event); + }; + search.onchange = function (event) { // For IE 9 + searchBox._onSearch(event); + }; + search.onkeydown = function (event) { + searchBox._onKeyDown(event); + }; + search.onkeyup = function (event) { + searchBox._onKeyUp(event); + }; + refreshSearch.onclick = function (event) { + search.select(); + }; - // TODO: ESC in FF restores the last input, is a FF bug, https://bugzilla.mozilla.org/show_bug.cgi?id=598819 - td = document.createElement('td'); - td.appendChild(search); - tr.appendChild(td); + // TODO: ESC in FF restores the last input, is a FF bug, https://bugzilla.mozilla.org/show_bug.cgi?id=598819 + td = document.createElement('td'); + td.appendChild(search); + tr.appendChild(td); - var searchNext = document.createElement('button'); - searchNext.title = 'Next result (Enter)'; - searchNext.className = 'next'; - searchNext.onclick = function () { - searchBox.next(); - }; - td = document.createElement('td'); - td.appendChild(searchNext); - tr.appendChild(td); + var searchNext = document.createElement('button'); + searchNext.title = 'Next result (Enter)'; + searchNext.className = 'next'; + searchNext.onclick = function () { + searchBox.next(); + }; + td = document.createElement('td'); + td.appendChild(searchNext); + tr.appendChild(td); - var searchPrevious = document.createElement('button'); - searchPrevious.title = 'Previous result (Shift+Enter)'; - searchPrevious.className = 'previous'; - searchPrevious.onclick = function () { - searchBox.previous(); - }; - td = document.createElement('td'); - td.appendChild(searchPrevious); - tr.appendChild(td); + var searchPrevious = document.createElement('button'); + searchPrevious.title = 'Previous result (Shift+Enter)'; + searchPrevious.className = 'previous'; + searchPrevious.onclick = function () { + searchBox.previous(); + }; + td = document.createElement('td'); + td.appendChild(searchPrevious); + tr.appendChild(td); } /** @@ -105,13 +105,13 @@ function SearchBox (editor, container) { * focus is false by default. */ SearchBox.prototype.next = function(focus) { - if (this.results != undefined) { - var index = (this.resultIndex != undefined) ? this.resultIndex + 1 : 0; - if (index > this.results.length - 1) { - index = 0; - } - this._setActiveResult(index, focus); + if (this.results != undefined) { + var index = (this.resultIndex != undefined) ? this.resultIndex + 1 : 0; + if (index > this.results.length - 1) { + index = 0; } + this._setActiveResult(index, focus); + } }; /** @@ -120,14 +120,14 @@ SearchBox.prototype.next = function(focus) { * focus is false by default. */ SearchBox.prototype.previous = function(focus) { - if (this.results != undefined) { - var max = this.results.length - 1; - var index = (this.resultIndex != undefined) ? this.resultIndex - 1 : max; - if (index < 0) { - index = max; - } - this._setActiveResult(index, focus); + if (this.results != undefined) { + var max = this.results.length - 1; + var index = (this.resultIndex != undefined) ? this.resultIndex - 1 : max; + if (index < 0) { + index = max; } + this._setActiveResult(index, focus); + } }; /** @@ -138,46 +138,46 @@ SearchBox.prototype.previous = function(focus) { * @private */ SearchBox.prototype._setActiveResult = function(index, focus) { - // de-activate current active result - if (this.activeResult) { - var prevNode = this.activeResult.node; - var prevElem = this.activeResult.elem; - if (prevElem == 'field') { - delete prevNode.searchFieldActive; - } - else { - delete prevNode.searchValueActive; - } - prevNode.updateDom(); - } - - if (!this.results || !this.results[index]) { - // out of range, set to undefined - this.resultIndex = undefined; - this.activeResult = undefined; - return; - } - - this.resultIndex = index; - - // set new node active - var node = this.results[this.resultIndex].node; - var elem = this.results[this.resultIndex].elem; - if (elem == 'field') { - node.searchFieldActive = true; + // de-activate current active result + if (this.activeResult) { + var prevNode = this.activeResult.node; + var prevElem = this.activeResult.elem; + if (prevElem == 'field') { + delete prevNode.searchFieldActive; } else { - node.searchValueActive = true; + delete prevNode.searchValueActive; } - this.activeResult = this.results[this.resultIndex]; - node.updateDom(); + prevNode.updateDom(); + } - // TODO: not so nice that the focus is only set after the animation is finished - node.scrollTo(function () { - if (focus) { - node.focus(elem); - } - }); + if (!this.results || !this.results[index]) { + // out of range, set to undefined + this.resultIndex = undefined; + this.activeResult = undefined; + return; + } + + this.resultIndex = index; + + // set new node active + var node = this.results[this.resultIndex].node; + var elem = this.results[this.resultIndex].elem; + if (elem == 'field') { + node.searchFieldActive = true; + } + else { + node.searchValueActive = true; + } + this.activeResult = this.results[this.resultIndex]; + node.updateDom(); + + // TODO: not so nice that the focus is only set after the animation is finished + node.scrollTo(function () { + if (focus) { + node.focus(elem); + } + }); }; /** @@ -185,10 +185,10 @@ SearchBox.prototype._setActiveResult = function(index, focus) { * @private */ SearchBox.prototype._clearDelay = function() { - if (this.timeout != undefined) { - clearTimeout(this.timeout); - delete this.timeout; - } + if (this.timeout != undefined) { + clearTimeout(this.timeout); + delete this.timeout; + } }; /** @@ -198,14 +198,14 @@ SearchBox.prototype._clearDelay = function() { * @private */ SearchBox.prototype._onDelayedSearch = function (event) { - // execute the search after a short delay (reduces the number of - // search actions while typing in the search text box) - this._clearDelay(); - var searchBox = this; - this.timeout = setTimeout(function (event) { - searchBox._onSearch(event); - }, - this.delay); + // execute the search after a short delay (reduces the number of + // search actions while typing in the search text box) + this._clearDelay(); + var searchBox = this; + this.timeout = setTimeout(function (event) { + searchBox._onSearch(event); + }, + this.delay); }; /** @@ -217,29 +217,29 @@ SearchBox.prototype._onDelayedSearch = function (event) { * @private */ SearchBox.prototype._onSearch = function (event, forceSearch) { - this._clearDelay(); + this._clearDelay(); - var value = this.dom.search.value; - var text = (value.length > 0) ? value : undefined; - if (text != this.lastText || forceSearch) { - // only search again when changed - this.lastText = text; - this.results = this.editor.search(text); - this._setActiveResult(undefined); + var value = this.dom.search.value; + var text = (value.length > 0) ? value : undefined; + if (text != this.lastText || forceSearch) { + // only search again when changed + this.lastText = text; + this.results = this.editor.search(text); + this._setActiveResult(undefined); - // display search results - if (text != undefined) { - var resultCount = this.results.length; - switch (resultCount) { - case 0: this.dom.results.innerHTML = 'no results'; break; - case 1: this.dom.results.innerHTML = '1 result'; break; - default: this.dom.results.innerHTML = resultCount + ' results'; break; - } - } - else { - this.dom.results.innerHTML = ''; - } + // display search results + if (text != undefined) { + var resultCount = this.results.length; + switch (resultCount) { + case 0: this.dom.results.innerHTML = 'no results'; break; + case 1: this.dom.results.innerHTML = '1 result'; break; + default: this.dom.results.innerHTML = resultCount + ' results'; break; + } } + else { + this.dom.results.innerHTML = ''; + } + } }; /** @@ -248,29 +248,29 @@ SearchBox.prototype._onSearch = function (event, forceSearch) { * @private */ SearchBox.prototype._onKeyDown = function (event) { - var keynum = event.which; - if (keynum == 27) { // ESC - this.dom.search.value = ''; // clear search - this._onSearch(event); - event.preventDefault(); - event.stopPropagation(); + var keynum = event.which; + if (keynum == 27) { // ESC + this.dom.search.value = ''; // clear search + this._onSearch(event); + event.preventDefault(); + event.stopPropagation(); + } + else if (keynum == 13) { // Enter + if (event.ctrlKey) { + // force to search again + this._onSearch(event, true); } - else if (keynum == 13) { // Enter - if (event.ctrlKey) { - // force to search again - this._onSearch(event, true); - } - else if (event.shiftKey) { - // move to the previous search result - this.previous(); - } - else { - // move to the next search result - this.next(); - } - event.preventDefault(); - event.stopPropagation(); + else if (event.shiftKey) { + // move to the previous search result + this.previous(); } + else { + // move to the next search result + this.next(); + } + event.preventDefault(); + event.stopPropagation(); + } }; /** @@ -279,8 +279,8 @@ SearchBox.prototype._onKeyDown = function (event) { * @private */ SearchBox.prototype._onKeyUp = function (event) { - var keynum = event.keyCode; - if (keynum != 27 && keynum != 13) { // !show and !Enter - this._onDelayedSearch(event); // For IE 9 - } + var keynum = event.keyCode; + if (keynum != 27 && keynum != 13) { // !show and !Enter + this._onDelayedSearch(event); // For IE 9 + } }; diff --git a/jsoneditor/js/texteditor.js b/jsoneditor/js/texteditor.js index 1f5e5f4..3ebd5b7 100644 --- a/jsoneditor/js/texteditor.js +++ b/jsoneditor/js/texteditor.js @@ -13,11 +13,11 @@ * @param {JSON | String} [json] initial contents of the formatter */ function TextEditor(container, options, json) { - if (!(this instanceof TextEditor)) { - throw new Error('TextEditor constructor called without "new".'); - } + if (!(this instanceof TextEditor)) { + throw new Error('TextEditor constructor called without "new".'); + } - this._create(container, options, json); + this._create(container, options, json); } /** @@ -29,153 +29,153 @@ function TextEditor(container, options, json) { * @private */ TextEditor.prototype._create = function (container, options, json) { - // read options - options = options || {}; - this.options = options; - if (options.indentation) { - this.indentation = Number(options.indentation); + // read options + options = options || {}; + this.options = options; + if (options.indentation) { + this.indentation = Number(options.indentation); + } + else { + this.indentation = 2; // number of spaces + } + this.mode = (options.mode == 'code') ? 'code' : 'text'; + if (this.mode == 'code') { + // verify whether Ace editor is available and supported + if (typeof ace === 'undefined') { + this.mode = 'text'; + util.log('WARNING: Cannot load code editor, Ace library not loaded. ' + + 'Falling back to plain text editor'); } - else { - this.indentation = 4; // number of spaces + } + + var me = this; + this.container = container; + this.dom = {}; + this.editor = undefined; // ace code editor + this.textarea = undefined; // plain text editor (fallback when Ace is not available) + + this.width = container.clientWidth; + this.height = container.clientHeight; + + this.frame = document.createElement('div'); + this.frame.className = 'jsoneditor'; + this.frame.onclick = function (event) { + // prevent default submit action when TextEditor is located inside a form + event.preventDefault(); + }; + + // create menu + this.menu = document.createElement('div'); + this.menu.className = 'menu'; + this.frame.appendChild(this.menu); + + // create format button + var buttonFormat = document.createElement('button'); + buttonFormat.className = 'format'; + buttonFormat.title = 'Format JSON data, with proper indentation and line feeds'; + this.menu.appendChild(buttonFormat); + buttonFormat.onclick = function () { + try { + me.format(); } - this.mode = (options.mode == 'code') ? 'code' : 'text'; - if (this.mode == 'code') { - // verify whether Ace editor is available and supported - if (typeof ace === 'undefined') { - this.mode = 'text'; - util.log('WARNING: Cannot load code editor, Ace library not loaded. ' + - 'Falling back to plain text editor'); - } + catch (err) { + me._onError(err); } + }; - var me = this; - this.container = container; - this.dom = {}; - this.editor = undefined; // ace code editor - this.textarea = undefined; // plain text editor (fallback when Ace is not available) + // create compact button + var buttonCompact = document.createElement('button'); + buttonCompact.className = 'compact'; + buttonCompact.title = 'Compact JSON data, remove all whitespaces'; + this.menu.appendChild(buttonCompact); + buttonCompact.onclick = function () { + try { + me.compact(); + } + catch (err) { + me._onError(err); + } + }; - this.width = container.clientWidth; - this.height = container.clientHeight; + // create mode box + if (this.options && this.options.modes && this.options.modes.length) { + var modeBox = createModeBox(this, this.options.modes, this.options.mode); + this.menu.appendChild(modeBox); + this.dom.modeBox = modeBox; + } - this.frame = document.createElement('div'); - this.frame.className = 'jsoneditor'; - this.frame.onclick = function (event) { - // prevent default submit action when TextEditor is located inside a form - event.preventDefault(); + this.content = document.createElement('div'); + this.content.className = 'outer'; + this.frame.appendChild(this.content); + + this.container.appendChild(this.frame); + + if (this.mode == 'code') { + this.editorDom = document.createElement('div'); + this.editorDom.style.height = '100%'; // TODO: move to css + this.editorDom.style.width = '100%'; // TODO: move to css + this.content.appendChild(this.editorDom); + + var editor = ace.edit(this.editorDom); + editor.setTheme('ace/theme/jsoneditor'); + editor.setShowPrintMargin(false); + editor.setFontSize(13); + editor.getSession().setMode('ace/mode/json'); + editor.getSession().setUseSoftTabs(true); + editor.getSession().setUseWrapMode(true); + this.editor = editor; + + var poweredBy = document.createElement('a'); + poweredBy.appendChild(document.createTextNode('powered by ace')); + poweredBy.href = 'http://ace.ajax.org'; + poweredBy.target = '_blank'; + poweredBy.className = 'poweredBy'; + poweredBy.onclick = function () { + // TODO: this anchor falls below the margin of the content, + // therefore the normal a.href does not work. We use a click event + // for now, but this should be fixed. + window.open(poweredBy.href, poweredBy.target); }; + this.menu.appendChild(poweredBy); - // create menu - this.menu = document.createElement('div'); - this.menu.className = 'menu'; - this.frame.appendChild(this.menu); - - // create format button - var buttonFormat = document.createElement('button'); - buttonFormat.className = 'format'; - buttonFormat.title = 'Format JSON data, with proper indentation and line feeds'; - this.menu.appendChild(buttonFormat); - buttonFormat.onclick = function () { - try { - me.format(); - } - catch (err) { - me._onError(err); - } - }; - - // create compact button - var buttonCompact = document.createElement('button'); - buttonCompact.className = 'compact'; - buttonCompact.title = 'Compact JSON data, remove all whitespaces'; - this.menu.appendChild(buttonCompact); - buttonCompact.onclick = function () { - try { - me.compact(); - } - catch (err) { - me._onError(err); - } - }; - - // create mode box - if (this.options && this.options.modes && this.options.modes.length) { - var modeBox = createModeBox(this, this.options.modes, this.options.mode); - this.menu.appendChild(modeBox); - this.dom.modeBox = modeBox; + if (options.change) { + // register onchange event + editor.on('change', function () { + options.change(); + }); } + } + else { + // load a plain text textarea + var textarea = document.createElement('textarea'); + textarea.className = 'text'; + textarea.spellcheck = false; + this.content.appendChild(textarea); + this.textarea = textarea; - this.content = document.createElement('div'); - this.content.className = 'outer'; - this.frame.appendChild(this.content); - - this.container.appendChild(this.frame); - - if (this.mode == 'code') { - this.editorDom = document.createElement('div'); - this.editorDom.style.height = '100%'; // TODO: move to css - this.editorDom.style.width = '100%'; // TODO: move to css - this.content.appendChild(this.editorDom); - - var editor = ace.edit(this.editorDom); - editor.setTheme('ace/theme/jsoneditor'); - editor.setShowPrintMargin(false); - editor.setFontSize(13); - editor.getSession().setMode('ace/mode/json'); - editor.getSession().setUseSoftTabs(true); - editor.getSession().setUseWrapMode(true); - this.editor = editor; - - var poweredBy = document.createElement('a'); - poweredBy.appendChild(document.createTextNode('powered by ace')); - poweredBy.href = 'http://ace.ajax.org'; - poweredBy.target = '_blank'; - poweredBy.className = 'poweredBy'; - poweredBy.onclick = function () { - // TODO: this anchor falls below the margin of the content, - // therefore the normal a.href does not work. We use a click event - // for now, but this should be fixed. - window.open(poweredBy.href, poweredBy.target); - }; - this.menu.appendChild(poweredBy); - - if (options.change) { - // register onchange event - editor.on('change', function () { - options.change(); - }); + if (options.change) { + // register onchange event + if (this.textarea.oninput === null) { + this.textarea.oninput = function () { + options.change(); } - } - else { - // load a plain text textarea - var textarea = document.createElement('textarea'); - textarea.className = 'text'; - textarea.spellcheck = false; - this.content.appendChild(textarea); - this.textarea = textarea; - - if (options.change) { - // register onchange event - if (this.textarea.oninput === null) { - this.textarea.oninput = function () { - options.change(); - } - } - else { - // oninput is undefined. For IE8- - this.textarea.onchange = function () { - options.change(); - } - } + } + else { + // oninput is undefined. For IE8- + this.textarea.onchange = function () { + options.change(); } + } } + } - // load initial json object or string - if (typeof(json) == 'string') { - this.setText(json); - } - else { - this.set(json); - } + // load initial json object or string + if (typeof(json) == 'string') { + this.setText(json); + } + else { + this.set(json); + } }; /** @@ -183,9 +183,9 @@ TextEditor.prototype._create = function (container, options, json) { * @private */ TextEditor.prototype._delete = function () { - if (this.frame && this.container && this.frame.parentNode == this.container) { - this.container.removeChild(this.frame); - } + if (this.frame && this.container && this.frame.parentNode == this.container) { + this.container.removeChild(this.frame); + } }; /** @@ -195,57 +195,57 @@ TextEditor.prototype._delete = function () { * @private */ TextEditor.prototype._onError = function(err) { - // TODO: onError is deprecated since version 2.2.0. cleanup some day - if (typeof this.onError === 'function') { - util.log('WARNING: JSONEditor.onError is deprecated. ' + - 'Use options.error instead.'); - this.onError(err); - } + // TODO: onError is deprecated since version 2.2.0. cleanup some day + if (typeof this.onError === 'function') { + util.log('WARNING: JSONEditor.onError is deprecated. ' + + 'Use options.error instead.'); + this.onError(err); + } - if (this.options && typeof this.options.error === 'function') { - this.options.error(err); - } - else { - throw err; - } + if (this.options && typeof this.options.error === 'function') { + this.options.error(err); + } + else { + throw err; + } }; /** * Compact the code in the formatter */ TextEditor.prototype.compact = function () { - var json = util.parse(this.getText()); - this.setText(JSON.stringify(json)); + var json = util.parse(this.getText()); + this.setText(JSON.stringify(json)); }; /** * Format the code in the formatter */ TextEditor.prototype.format = function () { - var json = util.parse(this.getText()); - this.setText(JSON.stringify(json, null, this.indentation)); + var json = util.parse(this.getText()); + this.setText(JSON.stringify(json, null, this.indentation)); }; /** * Set focus to the formatter */ TextEditor.prototype.focus = function () { - if (this.textarea) { - this.textarea.focus(); - } - if (this.editor) { - this.editor.focus(); - } + if (this.textarea) { + this.textarea.focus(); + } + if (this.editor) { + this.editor.focus(); + } }; /** * Resize the formatter */ TextEditor.prototype.resize = function () { - if (this.editor) { - var force = false; - this.editor.resize(force); - } + if (this.editor) { + var force = false; + this.editor.resize(force); + } }; /** @@ -253,7 +253,7 @@ TextEditor.prototype.resize = function () { * @param {Object} json */ TextEditor.prototype.set = function(json) { - this.setText(JSON.stringify(json, null, this.indentation)); + this.setText(JSON.stringify(json, null, this.indentation)); }; /** @@ -261,7 +261,7 @@ TextEditor.prototype.set = function(json) { * @return {Object} json */ TextEditor.prototype.get = function() { - return util.parse(this.getText()); + return util.parse(this.getText()); }; /** @@ -269,13 +269,13 @@ TextEditor.prototype.get = function() { * @return {String} jsonText */ TextEditor.prototype.getText = function() { - if (this.textarea) { - return this.textarea.value; - } - if (this.editor) { - return this.editor.getValue(); - } - return ''; + if (this.textarea) { + return this.textarea.value; + } + if (this.editor) { + return this.editor.getValue(); + } + return ''; }; /** @@ -283,22 +283,22 @@ TextEditor.prototype.getText = function() { * @param {String} jsonText */ TextEditor.prototype.setText = function(jsonText) { - if (this.textarea) { - this.textarea.value = jsonText; - } - if (this.editor) { - this.editor.setValue(jsonText, -1); - } + if (this.textarea) { + this.textarea.value = jsonText; + } + if (this.editor) { + this.editor.setValue(jsonText, -1); + } }; // register modes at the JSONEditor JSONEditor.modes.text = { - editor: TextEditor, - data: 'text', - load: TextEditor.prototype.format + editor: TextEditor, + data: 'text', + load: TextEditor.prototype.format }; JSONEditor.modes.code = { - editor: TextEditor, - data: 'text', - load: TextEditor.prototype.format + editor: TextEditor, + data: 'text', + load: TextEditor.prototype.format }; diff --git a/jsoneditor/js/treeeditor.js b/jsoneditor/js/treeeditor.js index dd78f1a..a407278 100644 --- a/jsoneditor/js/treeeditor.js +++ b/jsoneditor/js/treeeditor.js @@ -15,11 +15,11 @@ * @param {Object | undefined} json JSON object */ function TreeEditor(container, options, json) { - if (!(this instanceof TreeEditor)) { - throw new Error('TreeEditor constructor called without "new".'); - } + if (!(this instanceof TreeEditor)) { + throw new Error('TreeEditor constructor called without "new".'); + } - this._create(container, options, json); + this._create(container, options, json); } /** @@ -30,24 +30,24 @@ function TreeEditor(container, options, json) { * @private */ TreeEditor.prototype._create = function (container, options, json) { - if (!container) { - throw new Error('No container element provided.'); - } - this.container = container; - this.dom = {}; - this.highlighter = new Highlighter(); - this.selection = undefined; // will hold the last input selection + if (!container) { + throw new Error('No container element provided.'); + } + this.container = container; + this.dom = {}; + this.highlighter = new Highlighter(); + this.selection = undefined; // will hold the last input selection - this._setOptions(options); + this._setOptions(options); - if (this.options.history && !this.mode.view) { - this.history = new History(this); - } + if (this.options.history && !this.mode.view) { + this.history = new History(this); + } - this._createFrame(); - this._createTable(); + this._createFrame(); + this._createTable(); - this.set(json || {}); + this.set(json || {}); }; /** @@ -55,9 +55,9 @@ TreeEditor.prototype._create = function (container, options, json) { * @private */ TreeEditor.prototype._delete = function () { - if (this.frame && this.container && this.frame.parentNode == this.container) { - this.container.removeChild(this.frame); - } + if (this.frame && this.container && this.frame.parentNode == this.container) { + this.container.removeChild(this.frame); + } }; /** @@ -66,50 +66,50 @@ TreeEditor.prototype._delete = function () { * @private */ TreeEditor.prototype._setOptions = function (options) { - this.options = { - search: true, - history: true, - mode: 'tree', - name: undefined // field name of root node - }; + this.options = { + search: true, + history: true, + mode: 'tree', + name: undefined // field name of root node + }; - // copy all options - if (options) { - for (var prop in options) { - if (options.hasOwnProperty(prop)) { - this.options[prop] = options[prop]; - } - } - - // check for deprecated options - if (options['enableSearch']) { - // deprecated since version 1.6.0, 2012-11-03 - this.options.search = options['enableSearch']; - util.log('WARNING: Option "enableSearch" is deprecated. Use "search" instead.'); - } - if (options['enableHistory']) { - // deprecated since version 1.6.0, 2012-11-03 - this.options.history = options['enableHistory']; - util.log('WARNING: Option "enableHistory" is deprecated. Use "history" instead.'); - } - if (options['mode'] == 'editor') { - // deprecated since version 2.2.0, 2013-04-30 - this.options.mode = 'tree'; - util.log('WARNING: Mode "editor" is deprecated. Use "tree" instead.'); - } - if (options['mode'] == 'viewer') { - // deprecated since version 2.2.0, 2013-04-30 - this.options.mode = 'view'; - util.log('WARNING: Mode "viewer" is deprecated. Use "view" instead.'); - } + // copy all options + if (options) { + for (var prop in options) { + if (options.hasOwnProperty(prop)) { + this.options[prop] = options[prop]; + } } - // interpret the mode options - this.mode = { - edit: (this.options.mode != 'view' && this.options.mode != 'form'), - view: (this.options.mode == 'view'), - form: (this.options.mode == 'form') - }; + // check for deprecated options + if (options['enableSearch']) { + // deprecated since version 1.6.0, 2012-11-03 + this.options.search = options['enableSearch']; + util.log('WARNING: Option "enableSearch" is deprecated. Use "search" instead.'); + } + if (options['enableHistory']) { + // deprecated since version 1.6.0, 2012-11-03 + this.options.history = options['enableHistory']; + util.log('WARNING: Option "enableHistory" is deprecated. Use "history" instead.'); + } + if (options['mode'] == 'editor') { + // deprecated since version 2.2.0, 2013-04-30 + this.options.mode = 'tree'; + util.log('WARNING: Mode "editor" is deprecated. Use "tree" instead.'); + } + if (options['mode'] == 'viewer') { + // deprecated since version 2.2.0, 2013-04-30 + this.options.mode = 'view'; + util.log('WARNING: Mode "viewer" is deprecated. Use "view" instead.'); + } + } + + // interpret the mode options + this.mode = { + edit: (this.options.mode != 'view' && this.options.mode != 'form'), + view: (this.options.mode == 'view'), + form: (this.options.mode == 'form') + }; }; // node currently being edited @@ -122,40 +122,40 @@ TreeEditor.focusNode = undefined; * Can also be set using setName(name). */ TreeEditor.prototype.set = function (json, name) { - // adjust field name for root node - if (name) { - // TODO: deprecated since version 2.2.0. Cleanup some day. - util.log('Warning: second parameter "name" is deprecated. ' + - 'Use setName(name) instead.'); - this.options.name = name; - } + // adjust field name for root node + if (name) { + // TODO: deprecated since version 2.2.0. Cleanup some day. + util.log('Warning: second parameter "name" is deprecated. ' + + 'Use setName(name) instead.'); + this.options.name = name; + } - // verify if json is valid JSON, ignore when a function - if (json instanceof Function || (json === undefined)) { - this.clear(); - } - else { - this.content.removeChild(this.table); // Take the table offline + // verify if json is valid JSON, ignore when a function + if (json instanceof Function || (json === undefined)) { + this.clear(); + } + else { + this.content.removeChild(this.table); // Take the table offline - // replace the root node - var params = { - 'field': this.options.name, - 'value': json - }; - var node = new Node(this, params); - this._setRoot(node); + // replace the root node + var params = { + 'field': this.options.name, + 'value': json + }; + var node = new Node(this, params); + this._setRoot(node); - // expand - var recurse = false; - this.node.expand(recurse); + // expand + var recurse = false; + this.node.expand(recurse); - this.content.appendChild(this.table); // Put the table online again - } + this.content.appendChild(this.table); // Put the table online again + } - // TODO: maintain history, store last state and previous document - if (this.history) { - this.history.clear(); - } + // TODO: maintain history, store last state and previous document + if (this.history) { + this.history.clear(); + } }; /** @@ -163,17 +163,17 @@ TreeEditor.prototype.set = function (json, name) { * @return {Object | undefined} json */ TreeEditor.prototype.get = function () { - // remove focus from currently edited node - if (TreeEditor.focusNode) { - TreeEditor.focusNode.blur(); - } + // remove focus from currently edited node + if (TreeEditor.focusNode) { + TreeEditor.focusNode.blur(); + } - if (this.node) { - return this.node.getValue(); - } - else { - return undefined; - } + if (this.node) { + return this.node.getValue(); + } + else { + return undefined; + } }; /** @@ -181,7 +181,7 @@ TreeEditor.prototype.get = function () { * @return {String} jsonText */ TreeEditor.prototype.getText = function() { - return JSON.stringify(this.get()); + return JSON.stringify(this.get()); }; /** @@ -189,7 +189,7 @@ TreeEditor.prototype.getText = function() { * @param {String} jsonText */ TreeEditor.prototype.setText = function(jsonText) { - this.set(util.parse(jsonText)); + this.set(util.parse(jsonText)); }; /** @@ -197,10 +197,10 @@ TreeEditor.prototype.setText = function(jsonText) { * @param {String | undefined} name */ TreeEditor.prototype.setName = function (name) { - this.options.name = name; - if (this.node) { - this.node.updateField(this.options.name); - } + this.options.name = name; + if (this.node) { + this.node.updateField(this.options.name); + } }; /** @@ -208,18 +208,18 @@ TreeEditor.prototype.setName = function (name) { * @return {String | undefined} name */ TreeEditor.prototype.getName = function () { - return this.options.name; + return this.options.name; }; /** * Remove the root node from the editor */ TreeEditor.prototype.clear = function () { - if (this.node) { - this.node.collapse(); - this.tbody.removeChild(this.node.getDom()); - delete this.node; - } + if (this.node) { + this.node.collapse(); + this.tbody.removeChild(this.node.getDom()); + delete this.node; + } }; /** @@ -228,12 +228,12 @@ TreeEditor.prototype.clear = function () { * @private */ TreeEditor.prototype._setRoot = function (node) { - this.clear(); + this.clear(); - this.node = node; + this.node = node; - // append to the dom - this.tbody.appendChild(node.getDom()); + // append to the dom + this.tbody.appendChild(node.getDom()); }; /** @@ -249,39 +249,39 @@ TreeEditor.prototype._setRoot = function (node) { * 'value') */ TreeEditor.prototype.search = function (text) { - var results; - if (this.node) { - this.content.removeChild(this.table); // Take the table offline - results = this.node.search(text); - this.content.appendChild(this.table); // Put the table online again - } - else { - results = []; - } + var results; + if (this.node) { + this.content.removeChild(this.table); // Take the table offline + results = this.node.search(text); + this.content.appendChild(this.table); // Put the table online again + } + else { + results = []; + } - return results; + return results; }; /** * Expand all nodes */ TreeEditor.prototype.expandAll = function () { - if (this.node) { - this.content.removeChild(this.table); // Take the table offline - this.node.expand(); - this.content.appendChild(this.table); // Put the table online again - } + if (this.node) { + this.content.removeChild(this.table); // Take the table offline + this.node.expand(); + this.content.appendChild(this.table); // Put the table online again + } }; /** * Collapse all nodes */ TreeEditor.prototype.collapseAll = function () { - if (this.node) { - this.content.removeChild(this.table); // Take the table offline - this.node.collapse(); - this.content.appendChild(this.table); // Put the table online again - } + if (this.node) { + this.content.removeChild(this.table); // Take the table offline + this.node.collapse(); + this.content.appendChild(this.table); // Put the table online again + } }; /** @@ -299,20 +299,20 @@ TreeEditor.prototype.collapseAll = function () { * @private */ TreeEditor.prototype._onAction = function (action, params) { - // add an action to the history - if (this.history) { - this.history.add(action, params); - } + // add an action to the history + if (this.history) { + this.history.add(action, params); + } - // trigger the onChange callback - if (this.options.change) { - try { - this.options.change(); - } - catch (err) { - util.log('Error in change callback: ', err); - } + // trigger the onChange callback + if (this.options.change) { + try { + this.options.change(); } + catch (err) { + util.log('Error in change callback: ', err); + } + } }; /** @@ -321,53 +321,53 @@ TreeEditor.prototype._onAction = function (action, params) { * @param {Number} mouseY Absolute mouse position in pixels */ TreeEditor.prototype.startAutoScroll = function (mouseY) { - var me = this; - var content = this.content; - var top = util.getAbsoluteTop(content); - var height = content.clientHeight; - var bottom = top + height; - var margin = 24; - var interval = 50; // ms + var me = this; + var content = this.content; + var top = util.getAbsoluteTop(content); + var height = content.clientHeight; + var bottom = top + height; + var margin = 24; + var interval = 50; // ms - if ((mouseY < top + margin) && content.scrollTop > 0) { - this.autoScrollStep = ((top + margin) - mouseY) / 3; - } - else if (mouseY > bottom - margin && - height + content.scrollTop < content.scrollHeight) { - this.autoScrollStep = ((bottom - margin) - mouseY) / 3; - } - else { - this.autoScrollStep = undefined; - } + if ((mouseY < top + margin) && content.scrollTop > 0) { + this.autoScrollStep = ((top + margin) - mouseY) / 3; + } + else if (mouseY > bottom - margin && + height + content.scrollTop < content.scrollHeight) { + this.autoScrollStep = ((bottom - margin) - mouseY) / 3; + } + else { + this.autoScrollStep = undefined; + } - if (this.autoScrollStep) { - if (!this.autoScrollTimer) { - this.autoScrollTimer = setInterval(function () { - if (me.autoScrollStep) { - content.scrollTop -= me.autoScrollStep; - } - else { - me.stopAutoScroll(); - } - }, interval); + if (this.autoScrollStep) { + if (!this.autoScrollTimer) { + this.autoScrollTimer = setInterval(function () { + if (me.autoScrollStep) { + content.scrollTop -= me.autoScrollStep; } + else { + me.stopAutoScroll(); + } + }, interval); } - else { - this.stopAutoScroll(); - } + } + else { + this.stopAutoScroll(); + } }; /** * Stop auto scrolling. Only applicable when scrolling */ TreeEditor.prototype.stopAutoScroll = function () { - if (this.autoScrollTimer) { - clearTimeout(this.autoScrollTimer); - delete this.autoScrollTimer; - } - if (this.autoScrollStep) { - delete this.autoScrollStep; - } + if (this.autoScrollTimer) { + clearTimeout(this.autoScrollTimer); + delete this.autoScrollTimer; + } + if (this.autoScrollStep) { + delete this.autoScrollStep; + } }; @@ -381,20 +381,20 @@ TreeEditor.prototype.stopAutoScroll = function () { * {Number} scrollTop Scroll position */ TreeEditor.prototype.setSelection = function (selection) { - if (!selection) { - return; - } + if (!selection) { + return; + } - if ('scrollTop' in selection && this.content) { - // TODO: animated scroll - this.content.scrollTop = selection.scrollTop; - } - if (selection.range) { - util.setSelectionOffset(selection.range); - } - if (selection.dom) { - selection.dom.focus(); - } + if ('scrollTop' in selection && this.content) { + // TODO: animated scroll + this.content.scrollTop = selection.scrollTop; + } + if (selection.range) { + util.setSelectionOffset(selection.range); + } + if (selection.dom) { + selection.dom.focus(); + } }; /** @@ -406,11 +406,11 @@ TreeEditor.prototype.setSelection = function (selection) { * {Number} scrollTop Scroll position */ TreeEditor.prototype.getSelection = function () { - return { - dom: TreeEditor.domFocus, - scrollTop: this.content ? this.content.scrollTop : 0, - range: util.getSelectionOffset() - }; + return { + dom: TreeEditor.domFocus, + scrollTop: this.content ? this.content.scrollTop : 0, + range: util.getSelectionOffset() + }; }; /** @@ -423,50 +423,50 @@ TreeEditor.prototype.getSelection = function () { * when not. */ TreeEditor.prototype.scrollTo = function (top, callback) { - var content = this.content; - if (content) { - var editor = this; - // cancel any running animation - if (editor.animateTimeout) { - clearTimeout(editor.animateTimeout); - delete editor.animateTimeout; - } - if (editor.animateCallback) { - editor.animateCallback(false); - delete editor.animateCallback; - } - - // calculate final scroll position - var height = content.clientHeight; - var bottom = content.scrollHeight - height; - var finalScrollTop = Math.min(Math.max(top - height / 4, 0), bottom); - - // animate towards the new scroll position - var animate = function () { - var scrollTop = content.scrollTop; - var diff = (finalScrollTop - scrollTop); - if (Math.abs(diff) > 3) { - content.scrollTop += diff / 3; - editor.animateCallback = callback; - editor.animateTimeout = setTimeout(animate, 50); - } - else { - // finished - if (callback) { - callback(true); - } - content.scrollTop = finalScrollTop; - delete editor.animateTimeout; - delete editor.animateCallback; - } - }; - animate(); + var content = this.content; + if (content) { + var editor = this; + // cancel any running animation + if (editor.animateTimeout) { + clearTimeout(editor.animateTimeout); + delete editor.animateTimeout; } - else { + if (editor.animateCallback) { + editor.animateCallback(false); + delete editor.animateCallback; + } + + // calculate final scroll position + var height = content.clientHeight; + var bottom = content.scrollHeight - height; + var finalScrollTop = Math.min(Math.max(top - height / 4, 0), bottom); + + // animate towards the new scroll position + var animate = function () { + var scrollTop = content.scrollTop; + var diff = (finalScrollTop - scrollTop); + if (Math.abs(diff) > 3) { + content.scrollTop += diff / 3; + editor.animateCallback = callback; + editor.animateTimeout = setTimeout(animate, 50); + } + else { + // finished if (callback) { - callback(false); + callback(true); } + content.scrollTop = finalScrollTop; + delete editor.animateTimeout; + delete editor.animateCallback; + } + }; + animate(); + } + else { + if (callback) { + callback(false); } + } }; /** @@ -474,109 +474,109 @@ TreeEditor.prototype.scrollTo = function (top, callback) { * @private */ TreeEditor.prototype._createFrame = function () { - // create the frame - this.frame = document.createElement('div'); - this.frame.className = 'jsoneditor'; - this.container.appendChild(this.frame); + // create the frame + this.frame = document.createElement('div'); + this.frame.className = 'jsoneditor'; + this.container.appendChild(this.frame); - // create one global event listener to handle all events from all nodes - var editor = this; - var onEvent = function (event) { - editor._onEvent(event); - }; - this.frame.onclick = function (event) { - var target = event.target;// || event.srcElement; + // create one global event listener to handle all events from all nodes + var editor = this; + var onEvent = function (event) { + editor._onEvent(event); + }; + this.frame.onclick = function (event) { + var target = event.target;// || event.srcElement; - onEvent(event); + onEvent(event); - // prevent default submit action of buttons when TreeEditor is located - // inside a form - if (target.nodeName == 'BUTTON') { - event.preventDefault(); - } - }; - this.frame.oninput = onEvent; - this.frame.onchange = onEvent; - this.frame.onkeydown = onEvent; - this.frame.onkeyup = onEvent; - this.frame.oncut = onEvent; - this.frame.onpaste = onEvent; - this.frame.onmousedown = onEvent; - this.frame.onmouseup = onEvent; - this.frame.onmouseover = onEvent; - this.frame.onmouseout = onEvent; - // Note: focus and blur events do not propagate, therefore they defined - // using an eventListener with useCapture=true - // see http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html - util.addEventListener(this.frame, 'focus', onEvent, true); - util.addEventListener(this.frame, 'blur', onEvent, true); - this.frame.onfocusin = onEvent; // for IE - this.frame.onfocusout = onEvent; // for IE - - // create menu - this.menu = document.createElement('div'); - this.menu.className = 'menu'; - this.frame.appendChild(this.menu); - - // create expand all button - var expandAll = document.createElement('button'); - expandAll.className = 'expand-all'; - expandAll.title = 'Expand all fields'; - expandAll.onclick = function () { - editor.expandAll(); - }; - this.menu.appendChild(expandAll); - - // create expand all button - var collapseAll = document.createElement('button'); - collapseAll.title = 'Collapse all fields'; - collapseAll.className = 'collapse-all'; - collapseAll.onclick = function () { - editor.collapseAll(); - }; - this.menu.appendChild(collapseAll); - - // create undo/redo buttons - if (this.history) { - // create undo button - var undo = document.createElement('button'); - undo.className = 'undo separator'; - undo.title = 'Undo last action (Ctrl+Z)'; - undo.onclick = function () { - editor._onUndo(); - }; - this.menu.appendChild(undo); - this.dom.undo = undo; - - // create redo button - var redo = document.createElement('button'); - redo.className = 'redo'; - redo.title = 'Redo (Ctrl+Shift+Z)'; - redo.onclick = function () { - editor._onRedo(); - }; - this.menu.appendChild(redo); - this.dom.redo = redo; - - // register handler for onchange of history - this.history.onChange = function () { - undo.disabled = !editor.history.canUndo(); - redo.disabled = !editor.history.canRedo(); - }; - this.history.onChange(); + // prevent default submit action of buttons when TreeEditor is located + // inside a form + if (target.nodeName == 'BUTTON') { + event.preventDefault(); } + }; + this.frame.oninput = onEvent; + this.frame.onchange = onEvent; + this.frame.onkeydown = onEvent; + this.frame.onkeyup = onEvent; + this.frame.oncut = onEvent; + this.frame.onpaste = onEvent; + this.frame.onmousedown = onEvent; + this.frame.onmouseup = onEvent; + this.frame.onmouseover = onEvent; + this.frame.onmouseout = onEvent; + // Note: focus and blur events do not propagate, therefore they defined + // using an eventListener with useCapture=true + // see http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html + util.addEventListener(this.frame, 'focus', onEvent, true); + util.addEventListener(this.frame, 'blur', onEvent, true); + this.frame.onfocusin = onEvent; // for IE + this.frame.onfocusout = onEvent; // for IE - // create mode box - if (this.options && this.options.modes && this.options.modes.length) { - var modeBox = createModeBox(this, this.options.modes, this.options.mode); - this.menu.appendChild(modeBox); - this.dom.modeBox = modeBox; - } + // create menu + this.menu = document.createElement('div'); + this.menu.className = 'menu'; + this.frame.appendChild(this.menu); - // create search box - if (this.options.search) { - this.searchBox = new SearchBox(this, this.menu); - } + // create expand all button + var expandAll = document.createElement('button'); + expandAll.className = 'expand-all'; + expandAll.title = 'Expand all fields'; + expandAll.onclick = function () { + editor.expandAll(); + }; + this.menu.appendChild(expandAll); + + // create expand all button + var collapseAll = document.createElement('button'); + collapseAll.title = 'Collapse all fields'; + collapseAll.className = 'collapse-all'; + collapseAll.onclick = function () { + editor.collapseAll(); + }; + this.menu.appendChild(collapseAll); + + // create undo/redo buttons + if (this.history) { + // create undo button + var undo = document.createElement('button'); + undo.className = 'undo separator'; + undo.title = 'Undo last action (Ctrl+Z)'; + undo.onclick = function () { + editor._onUndo(); + }; + this.menu.appendChild(undo); + this.dom.undo = undo; + + // create redo button + var redo = document.createElement('button'); + redo.className = 'redo'; + redo.title = 'Redo (Ctrl+Shift+Z)'; + redo.onclick = function () { + editor._onRedo(); + }; + this.menu.appendChild(redo); + this.dom.redo = redo; + + // register handler for onchange of history + this.history.onChange = function () { + undo.disabled = !editor.history.canUndo(); + redo.disabled = !editor.history.canRedo(); + }; + this.history.onChange(); + } + + // create mode box + if (this.options && this.options.modes && this.options.modes.length) { + var modeBox = createModeBox(this, this.options.modes, this.options.mode); + this.menu.appendChild(modeBox); + this.dom.modeBox = modeBox; + } + + // create search box + if (this.options.search) { + this.searchBox = new SearchBox(this, this.menu); + } }; /** @@ -584,15 +584,15 @@ TreeEditor.prototype._createFrame = function () { * @private */ TreeEditor.prototype._onUndo = function () { - if (this.history) { - // undo last action - this.history.undo(); + if (this.history) { + // undo last action + this.history.undo(); - // trigger change callback - if (this.options.change) { - this.options.change(); - } + // trigger change callback + if (this.options.change) { + this.options.change(); } + } }; /** @@ -600,15 +600,15 @@ TreeEditor.prototype._onUndo = function () { * @private */ TreeEditor.prototype._onRedo = function () { - if (this.history) { - // redo last action - this.history.redo(); + if (this.history) { + // redo last action + this.history.redo(); - // trigger change callback - if (this.options.change) { - this.options.change(); - } + // trigger change callback + if (this.options.change) { + this.options.change(); } + } }; /** @@ -617,20 +617,20 @@ TreeEditor.prototype._onRedo = function () { * @private */ TreeEditor.prototype._onEvent = function (event) { - var target = event.target; + var target = event.target; - if (event.type == 'keydown') { - this._onKeyDown(event); - } + if (event.type == 'keydown') { + this._onKeyDown(event); + } - if (event.type == 'focus') { - TreeEditor.domFocus = target; - } + if (event.type == 'focus') { + TreeEditor.domFocus = target; + } - var node = Node.getNodeFromTarget(target); - if (node) { - node.onEvent(event); - } + var node = Node.getNodeFromTarget(target); + if (node) { + node.onEvent(event); + } }; /** @@ -639,56 +639,56 @@ TreeEditor.prototype._onEvent = function (event) { * @private */ TreeEditor.prototype._onKeyDown = function (event) { - var keynum = event.which || event.keyCode; - var ctrlKey = event.ctrlKey; - var shiftKey = event.shiftKey; - var handled = false; + var keynum = event.which || event.keyCode; + var ctrlKey = event.ctrlKey; + var shiftKey = event.shiftKey; + var handled = false; - if (keynum == 9) { // Tab or Shift+Tab - setTimeout(function () { - // select all text when moving focus to an editable div - util.selectContentEditable(TreeEditor.domFocus); - }, 0); + if (keynum == 9) { // Tab or Shift+Tab + setTimeout(function () { + // select all text when moving focus to an editable div + util.selectContentEditable(TreeEditor.domFocus); + }, 0); + } + + if (this.searchBox) { + if (ctrlKey && keynum == 70) { // Ctrl+F + this.searchBox.dom.search.focus(); + this.searchBox.dom.search.select(); + handled = true; } + else if (keynum == 114 || (ctrlKey && keynum == 71)) { // F3 or Ctrl+G + var focus = true; + if (!shiftKey) { + // select next search result (F3 or Ctrl+G) + this.searchBox.next(focus); + } + else { + // select previous search result (Shift+F3 or Ctrl+Shift+G) + this.searchBox.previous(focus); + } - if (this.searchBox) { - if (ctrlKey && keynum == 70) { // Ctrl+F - this.searchBox.dom.search.focus(); - this.searchBox.dom.search.select(); - handled = true; - } - else if (keynum == 114 || (ctrlKey && keynum == 71)) { // F3 or Ctrl+G - var focus = true; - if (!shiftKey) { - // select next search result (F3 or Ctrl+G) - this.searchBox.next(focus); - } - else { - // select previous search result (Shift+F3 or Ctrl+Shift+G) - this.searchBox.previous(focus); - } - - handled = true; - } + handled = true; } + } - if (this.history) { - if (ctrlKey && !shiftKey && keynum == 90) { // Ctrl+Z - // undo - this._onUndo(); - handled = true; - } - else if (ctrlKey && shiftKey && keynum == 90) { // Ctrl+Shift+Z - // redo - this._onRedo(); - handled = true; - } + if (this.history) { + if (ctrlKey && !shiftKey && keynum == 90) { // Ctrl+Z + // undo + this._onUndo(); + handled = true; } + else if (ctrlKey && shiftKey && keynum == 90) { // Ctrl+Shift+Z + // redo + this._onRedo(); + handled = true; + } + } - if (handled) { - event.preventDefault(); - event.stopPropagation(); - } + if (handled) { + event.preventDefault(); + event.stopPropagation(); + } }; /** @@ -696,59 +696,59 @@ TreeEditor.prototype._onKeyDown = function (event) { * @private */ TreeEditor.prototype._createTable = function () { - var contentOuter = document.createElement('div'); - contentOuter.className = 'outer'; - this.contentOuter = contentOuter; + var contentOuter = document.createElement('div'); + contentOuter.className = 'outer'; + this.contentOuter = contentOuter; - this.content = document.createElement('div'); - this.content.className = 'tree'; - contentOuter.appendChild(this.content); + this.content = document.createElement('div'); + this.content.className = 'tree'; + contentOuter.appendChild(this.content); - this.table = document.createElement('table'); - this.table.className = 'tree'; - this.content.appendChild(this.table); + this.table = document.createElement('table'); + this.table.className = 'tree'; + this.content.appendChild(this.table); - // create colgroup where the first two columns don't have a fixed - // width, and the edit columns do have a fixed width - var col; - this.colgroupContent = document.createElement('colgroup'); - if (this.mode.edit) { - col = document.createElement('col'); - col.width = "24px"; - this.colgroupContent.appendChild(col); - } + // create colgroup where the first two columns don't have a fixed + // width, and the edit columns do have a fixed width + var col; + this.colgroupContent = document.createElement('colgroup'); + if (this.mode.edit) { col = document.createElement('col'); col.width = "24px"; this.colgroupContent.appendChild(col); - col = document.createElement('col'); - this.colgroupContent.appendChild(col); - this.table.appendChild(this.colgroupContent); + } + col = document.createElement('col'); + col.width = "24px"; + this.colgroupContent.appendChild(col); + col = document.createElement('col'); + this.colgroupContent.appendChild(col); + this.table.appendChild(this.colgroupContent); - this.tbody = document.createElement('tbody'); - this.table.appendChild(this.tbody); + this.tbody = document.createElement('tbody'); + this.table.appendChild(this.tbody); - this.frame.appendChild(contentOuter); + this.frame.appendChild(contentOuter); }; // register modes at the JSONEditor JSONEditor.modes.tree = { - editor: TreeEditor, - data: 'json' + editor: TreeEditor, + data: 'json' }; JSONEditor.modes.view = { - editor: TreeEditor, - data: 'json' + editor: TreeEditor, + data: 'json' }; JSONEditor.modes.form = { - editor: TreeEditor, - data: 'json' + editor: TreeEditor, + data: 'json' }; // Deprecated modes (deprecated since version 2.2.0) JSONEditor.modes.editor = { - editor: TreeEditor, - data: 'json' + editor: TreeEditor, + data: 'json' }; JSONEditor.modes.viewer = { - editor: TreeEditor, - data: 'json' + editor: TreeEditor, + data: 'json' }; diff --git a/jsoneditor/js/util.js b/jsoneditor/js/util.js index 902192a..d648fcd 100644 --- a/jsoneditor/js/util.js +++ b/jsoneditor/js/util.js @@ -7,14 +7,14 @@ util = {}; * @param {String} jsonString */ util.parse = function parse(jsonString) { - try { - return JSON.parse(jsonString); - } - catch (err) { - // try to throw a more detailed error message using validate - util.validate(jsonString); - throw err; - } + try { + return JSON.parse(jsonString); + } + catch (err) { + // try to throw a more detailed error message using validate + util.validate(jsonString); + throw err; + } }; /** @@ -25,12 +25,12 @@ util.parse = function parse(jsonString) { * @throws Error */ util.validate = function validate(jsonString) { - if (typeof(jsonlint) != 'undefined') { - jsonlint.parse(jsonString); - } - else { - JSON.parse(jsonString); - } + if (typeof(jsonlint) != 'undefined') { + jsonlint.parse(jsonString); + } + else { + JSON.parse(jsonString); + } }; /** @@ -40,12 +40,12 @@ util.validate = function validate(jsonString) { * @return {Object} a */ util.extend = function extend(a, b) { - for (var prop in b) { - if (b.hasOwnProperty(prop)) { - a[prop] = b[prop]; - } + for (var prop in b) { + if (b.hasOwnProperty(prop)) { + a[prop] = b[prop]; } - return a; + } + return a; }; /** @@ -54,12 +54,12 @@ util.extend = function extend(a, b) { * @return {Object} a */ util.clear = function clear (a) { - for (var prop in a) { - if (a.hasOwnProperty(prop)) { - delete a[prop]; - } + for (var prop in a) { + if (a.hasOwnProperty(prop)) { + delete a[prop]; } - return a; + } + return a; }; /** @@ -67,9 +67,9 @@ util.clear = function clear (a) { * @param {...*} args */ util.log = function log (args) { - if (typeof console !== 'undefined' && typeof console.log === 'function') { - console.log.apply(console, arguments); - } + if (typeof console !== 'undefined' && typeof console.log === 'function') { + console.log.apply(console, arguments); + } }; /** @@ -78,29 +78,29 @@ util.log = function log (args) { * @return {String} type */ util.type = function type (object) { - if (object === null) { - return 'null'; - } - if (object === undefined) { - return 'undefined'; - } - if ((object instanceof Number) || (typeof object === 'number')) { - return 'number'; - } - if ((object instanceof String) || (typeof object === 'string')) { - return 'string'; - } - if ((object instanceof Boolean) || (typeof object === 'boolean')) { - return 'boolean'; - } - if ((object instanceof RegExp) || (typeof object === 'regexp')) { - return 'regexp'; - } - if (Array.isArray(object)) { - return 'array'; - } + if (object === null) { + return 'null'; + } + if (object === undefined) { + return 'undefined'; + } + if ((object instanceof Number) || (typeof object === 'number')) { + return 'number'; + } + if ((object instanceof String) || (typeof object === 'string')) { + return 'string'; + } + if ((object instanceof Boolean) || (typeof object === 'boolean')) { + return 'boolean'; + } + if ((object instanceof RegExp) || (typeof object === 'regexp')) { + return 'regexp'; + } + if (Array.isArray(object)) { + return 'array'; + } - return 'object'; + return 'object'; }; /** @@ -110,8 +110,8 @@ util.type = function type (object) { */ var isUrlRegex = /^https?:\/\/\S+$/; util.isUrl = function isUrl (text) { - return (typeof text == 'string' || text instanceof String) && - isUrlRegex.test(text); + return (typeof text == 'string' || text instanceof String) && + isUrlRegex.test(text); }; /** @@ -121,15 +121,15 @@ util.isUrl = function isUrl (text) { * in the browser page. */ util.getAbsoluteLeft = function getAbsoluteLeft(elem) { - var left = elem.offsetLeft; - var body = document.body; - var e = elem.offsetParent; - while (e != null && elem != body) { - left += e.offsetLeft; - left -= e.scrollLeft; - e = e.offsetParent; - } - return left; + var left = elem.offsetLeft; + var body = document.body; + var e = elem.offsetParent; + while (e != null && elem != body) { + left += e.offsetLeft; + left -= e.scrollLeft; + e = e.offsetParent; + } + return left; }; /** @@ -139,15 +139,15 @@ util.getAbsoluteLeft = function getAbsoluteLeft(elem) { * in the browser page. */ util.getAbsoluteTop = function getAbsoluteTop(elem) { - var top = elem.offsetTop; - var body = document.body; - var e = elem.offsetParent; - while (e != null && e != body) { - top += e.offsetTop; - top -= e.scrollTop; - e = e.offsetParent; - } - return top; + var top = elem.offsetTop; + var body = document.body; + var e = elem.offsetParent; + while (e != null && e != body) { + top += e.offsetTop; + top -= e.scrollTop; + e = e.offsetParent; + } + return top; }; /** @@ -156,11 +156,11 @@ util.getAbsoluteTop = function getAbsoluteTop(elem) { * @param {String} className */ util.addClassName = function addClassName(elem, className) { - var classes = elem.className.split(' '); - if (classes.indexOf(className) == -1) { - classes.push(className); // add the class to the array - elem.className = classes.join(' '); - } + var classes = elem.className.split(' '); + if (classes.indexOf(className) == -1) { + classes.push(className); // add the class to the array + elem.className = classes.join(' '); + } }; /** @@ -169,12 +169,12 @@ util.addClassName = function addClassName(elem, className) { * @param {String} className */ util.removeClassName = function removeClassName(elem, className) { - var classes = elem.className.split(' '); - var index = classes.indexOf(className); - if (index != -1) { - classes.splice(index, 1); // remove the class from the array - elem.className = classes.join(' '); - } + var classes = elem.className.split(' '); + var index = classes.indexOf(className); + if (index != -1) { + classes.splice(index, 1); // remove the class from the array + elem.className = classes.join(' '); + } }; /** @@ -183,30 +183,30 @@ util.removeClassName = function removeClassName(elem, className) { * @param {Element} divElement */ util.stripFormatting = function stripFormatting(divElement) { - var childs = divElement.childNodes; - for (var i = 0, iMax = childs.length; i < iMax; i++) { - var child = childs[i]; + var childs = divElement.childNodes; + for (var i = 0, iMax = childs.length; i < iMax; i++) { + var child = childs[i]; - // remove the style - if (child.style) { - // TODO: test if child.attributes does contain style - child.removeAttribute('style'); - } - - // remove all attributes - var attributes = child.attributes; - if (attributes) { - for (var j = attributes.length - 1; j >= 0; j--) { - var attribute = attributes[j]; - if (attribute.specified == true) { - child.removeAttribute(attribute.name); - } - } - } - - // recursively strip childs - util.stripFormatting(child); + // remove the style + if (child.style) { + // TODO: test if child.attributes does contain style + child.removeAttribute('style'); } + + // remove all attributes + var attributes = child.attributes; + if (attributes) { + for (var j = attributes.length - 1; j >= 0; j--) { + var attribute = attributes[j]; + if (attribute.specified == true) { + child.removeAttribute(attribute.name); + } + } + } + + // recursively strip childs + util.stripFormatting(child); + } }; /** @@ -217,15 +217,15 @@ util.stripFormatting = function stripFormatting(divElement) { * @param {Element} contentEditableElement A content editable div */ util.setEndOfContentEditable = function setEndOfContentEditable(contentEditableElement) { - var range, selection; - if(document.createRange) { - range = document.createRange();//Create a range (a range is a like the selection but invisible) - range.selectNodeContents(contentEditableElement);//Select the entire contents of the element with the range - range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start - selection = window.getSelection();//get the selection object (allows you to change selection) - selection.removeAllRanges();//remove any selections already made - selection.addRange(range);//make the range you have just created the visible selection - } + var range, selection; + if(document.createRange) { + range = document.createRange();//Create a range (a range is a like the selection but invisible) + range.selectNodeContents(contentEditableElement);//Select the entire contents of the element with the range + range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start + selection = window.getSelection();//get the selection object (allows you to change selection) + selection.removeAllRanges();//remove any selections already made + selection.addRange(range);//make the range you have just created the visible selection + } }; /** @@ -234,18 +234,18 @@ util.setEndOfContentEditable = function setEndOfContentEditable(contentEditableE * @param {Element} contentEditableElement A content editable div */ util.selectContentEditable = function selectContentEditable(contentEditableElement) { - if (!contentEditableElement || contentEditableElement.nodeName != 'DIV') { - return; - } + if (!contentEditableElement || contentEditableElement.nodeName != 'DIV') { + return; + } - var sel, range; - if (window.getSelection && document.createRange) { - range = document.createRange(); - range.selectNodeContents(contentEditableElement); - sel = window.getSelection(); - sel.removeAllRanges(); - sel.addRange(range); - } + var sel, range; + if (window.getSelection && document.createRange) { + range = document.createRange(); + range.selectNodeContents(contentEditableElement); + sel = window.getSelection(); + sel.removeAllRanges(); + sel.addRange(range); + } }; /** @@ -254,13 +254,13 @@ util.selectContentEditable = function selectContentEditable(contentEditableEleme * @return {Range | TextRange | null} range */ util.getSelection = function getSelection() { - if (window.getSelection) { - var sel = window.getSelection(); - if (sel.getRangeAt && sel.rangeCount) { - return sel.getRangeAt(0); - } + if (window.getSelection) { + var sel = window.getSelection(); + if (sel.getRangeAt && sel.rangeCount) { + return sel.getRangeAt(0); } - return null; + } + return null; }; /** @@ -269,13 +269,13 @@ util.getSelection = function getSelection() { * @param {Range | TextRange | null} range */ util.setSelection = function setSelection(range) { - if (range) { - if (window.getSelection) { - var sel = window.getSelection(); - sel.removeAllRanges(); - sel.addRange(range); - } + if (range) { + if (window.getSelection) { + var sel = window.getSelection(); + sel.removeAllRanges(); + sel.addRange(range); } + } }; /** @@ -288,18 +288,18 @@ util.setSelection = function setSelection(range) { * Returns null if no text selection is found */ util.getSelectionOffset = function getSelectionOffset() { - var range = util.getSelection(); + var range = util.getSelection(); - if (range && 'startOffset' in range && 'endOffset' in range && - range.startContainer && (range.startContainer == range.endContainer)) { - return { - startOffset: range.startOffset, - endOffset: range.endOffset, - container: range.startContainer.parentNode - }; - } + if (range && 'startOffset' in range && 'endOffset' in range && + range.startContainer && (range.startContainer == range.endContainer)) { + return { + startOffset: range.startOffset, + endOffset: range.endOffset, + container: range.startContainer.parentNode + }; + } - return null; + return null; }; /** @@ -310,18 +310,18 @@ util.getSelectionOffset = function getSelectionOffset() { * {Number} endOffset */ util.setSelectionOffset = function setSelectionOffset(params) { - if (document.createRange && window.getSelection) { - var selection = window.getSelection(); - if(selection) { - var range = document.createRange(); - // TODO: do not suppose that the first child of the container is a textnode, - // but recursively find the textnodes - range.setStart(params.container.firstChild, params.startOffset); - range.setEnd(params.container.firstChild, params.endOffset); + if (document.createRange && window.getSelection) { + var selection = window.getSelection(); + if(selection) { + var range = document.createRange(); + // TODO: do not suppose that the first child of the container is a textnode, + // but recursively find the textnodes + range.setStart(params.container.firstChild, params.startOffset); + range.setEnd(params.container.firstChild, params.endOffset); - util.setSelection(range); - } + util.setSelection(range); } + } }; /** @@ -331,68 +331,68 @@ util.setSelectionOffset = function setSelectionOffset(params) { * @return {String} innerText */ util.getInnerText = function getInnerText(element, buffer) { - var first = (buffer == undefined); - if (first) { - buffer = { - 'text': '', - 'flush': function () { - var text = this.text; - this.text = ''; - return text; - }, - 'set': function (text) { - this.text = text; - } - }; - } + var first = (buffer == undefined); + if (first) { + buffer = { + 'text': '', + 'flush': function () { + var text = this.text; + this.text = ''; + return text; + }, + 'set': function (text) { + this.text = text; + } + }; + } - // text node - if (element.nodeValue) { - return buffer.flush() + element.nodeValue; - } + // text node + if (element.nodeValue) { + return buffer.flush() + element.nodeValue; + } - // divs or other HTML elements - if (element.hasChildNodes()) { - var childNodes = element.childNodes; - var innerText = ''; + // divs or other HTML elements + if (element.hasChildNodes()) { + var childNodes = element.childNodes; + var innerText = ''; - for (var i = 0, iMax = childNodes.length; i < iMax; i++) { - var child = childNodes[i]; + for (var i = 0, iMax = childNodes.length; i < iMax; i++) { + var child = childNodes[i]; - if (child.nodeName == 'DIV' || child.nodeName == 'P') { - var prevChild = childNodes[i - 1]; - var prevName = prevChild ? prevChild.nodeName : undefined; - if (prevName && prevName != 'DIV' && prevName != 'P' && prevName != 'BR') { - innerText += '\n'; - buffer.flush(); - } - innerText += util.getInnerText(child, buffer); - buffer.set('\n'); - } - else if (child.nodeName == 'BR') { - innerText += buffer.flush(); - buffer.set('\n'); - } - else { - innerText += util.getInnerText(child, buffer); - } - } - - return innerText; - } - else { - if (element.nodeName == 'P' && util.getInternetExplorerVersion() != -1) { - // On Internet Explorer, awith hasChildNodes()==false is - // rendered with a new line. Note that a
with
- // hasChildNodes()==true is rendered without a new line
- // Other browsers always ensure there is a
inside the
, - // and if not, the
does not render a new line - return buffer.flush(); + if (child.nodeName == 'DIV' || child.nodeName == 'P') { + var prevChild = childNodes[i - 1]; + var prevName = prevChild ? prevChild.nodeName : undefined; + if (prevName && prevName != 'DIV' && prevName != 'P' && prevName != 'BR') { + innerText += '\n'; + buffer.flush(); } + innerText += util.getInnerText(child, buffer); + buffer.set('\n'); + } + else if (child.nodeName == 'BR') { + innerText += buffer.flush(); + buffer.set('\n'); + } + else { + innerText += util.getInnerText(child, buffer); + } } - // br or unknown - return ''; + return innerText; + } + else { + if (element.nodeName == 'P' && util.getInternetExplorerVersion() != -1) { + // On Internet Explorer, a
with hasChildNodes()==false is + // rendered with a new line. Note that a
with
+ // hasChildNodes()==true is rendered without a new line
+ // Other browsers always ensure there is a
inside the
, + // and if not, the
does not render a new line
+ return buffer.flush();
+ }
+ }
+
+ // br or unknown
+ return '';
};
/**
@@ -402,21 +402,21 @@ util.getInnerText = function getInnerText(element, buffer) {
* @return {Number} Internet Explorer version, or -1 in case of an other browser
*/
util.getInternetExplorerVersion = function getInternetExplorerVersion() {
- if (_ieVersion == -1) {
- var rv = -1; // Return value assumes failure.
- if (navigator.appName == 'Microsoft Internet Explorer')
- {
- var ua = navigator.userAgent;
- var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
- if (re.exec(ua) != null) {
- rv = parseFloat( RegExp.$1 );
- }
- }
-
- _ieVersion = rv;
+ if (_ieVersion == -1) {
+ var rv = -1; // Return value assumes failure.
+ if (navigator.appName == 'Microsoft Internet Explorer')
+ {
+ var ua = navigator.userAgent;
+ var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
+ if (re.exec(ua) != null) {
+ rv = parseFloat( RegExp.$1 );
+ }
}
- return _ieVersion;
+ _ieVersion = rv;
+ }
+
+ return _ieVersion;
};
/**
@@ -444,19 +444,19 @@ var _ieVersion = -1;
* @return {function} the created event listener
*/
util.addEventListener = function addEventListener(element, action, listener, useCapture) {
- if (element.addEventListener) {
- if (useCapture === undefined)
- useCapture = false;
+ if (element.addEventListener) {
+ if (useCapture === undefined)
+ useCapture = false;
- if (action === "mousewheel" && util.isFirefox()) {
- action = "DOMMouseScroll"; // For Firefox
- }
-
- element.addEventListener(action, listener, useCapture);
- return listener;
- } else {
- throw new Error('missing function addEventListener');
+ if (action === "mousewheel" && util.isFirefox()) {
+ action = "DOMMouseScroll"; // For Firefox
}
+
+ element.addEventListener(action, listener, useCapture);
+ return listener;
+ } else {
+ throw new Error('missing function addEventListener');
+ }
};
/**
@@ -467,16 +467,16 @@ util.addEventListener = function addEventListener(element, action, listener, use
* @param {boolean} [useCapture] false by default
*/
util.removeEventListener = function removeEventListener(element, action, listener, useCapture) {
- if (element.removeEventListener) {
- if (useCapture === undefined)
- useCapture = false;
+ if (element.removeEventListener) {
+ if (useCapture === undefined)
+ useCapture = false;
- if (action === "mousewheel" && util.isFirefox()) {
- action = "DOMMouseScroll"; // For Firefox
- }
-
- element.removeEventListener(action, listener, useCapture);
- } else {
- throw new Error('missing function removeEventListener');
+ if (action === "mousewheel" && util.isFirefox()) {
+ action = "DOMMouseScroll"; // For Firefox
}
+
+ element.removeEventListener(action, listener, useCapture);
+ } else {
+ throw new Error('missing function removeEventListener');
+ }
};
diff --git a/misc/screenshots/description.json b/misc/screenshots/description.json
index 6957da6..c9789e4 100644
--- a/misc/screenshots/description.json
+++ b/misc/screenshots/description.json
@@ -1,17 +1,17 @@
{
- "Name": "JSON Editor Online",
- "Website": "http://jsoneditoronline.org",
- "Version": 2.0,
- "Free": true,
- "Description": "JSON Editor Online is a web-based tool to view, edit, and format JSON. It shows your data side by side in a clear, editable treeview and in a code editor.",
- "Features": [
- "View and edit JSON side by side in treeview and a code editor.",
- "Edit, add, move, remove, and duplicate fields and values.",
- "Change type of values.",
- "Colorized values, color depends of the value type.",
- "Search & highlight text in the treeview.",
- "Undo and redo all actions.",
- "Load and save file and urls.",
- "Format, compact, and inspect JSON in the code editor."
- ]
+ "Name": "JSON Editor Online",
+ "Website": "http://jsoneditoronline.org",
+ "Version": 2.0,
+ "Free": true,
+ "Description": "JSON Editor Online is a web-based tool to view, edit, and format JSON. It shows your data side by side in a clear, editable treeview and in a code editor.",
+ "Features": [
+ "View and edit JSON side by side in treeview and a code editor.",
+ "Edit, add, move, remove, and duplicate fields and values.",
+ "Change type of values.",
+ "Colorized values, color depends of the value type.",
+ "Search & highlight text in the treeview.",
+ "Undo and redo all actions.",
+ "Load and save file and urls.",
+ "Format, compact, and inspect JSON in the code editor."
+ ]
}
\ No newline at end of file
diff --git a/package.json b/package.json
index c4987ee..67b9ed2 100644
--- a/package.json
+++ b/package.json
@@ -1,29 +1,29 @@
{
- "name": "jsoneditor",
- "version": "2.4.0-SNAPSHOT",
- "main": "jsoneditor.js",
- "description": "A web-based tool to view, edit and format JSON",
- "tags": [
- "json",
- "editor",
- "viewer",
- "formatter"
- ],
- "author": "Jos de Jong