Splitted jsoneditor.js and jsoneditor.css into multiple source files. Rearranged the folders a little, and updated the build script.

This commit is contained in:
josdejong 2013-01-01 20:54:07 +01:00
parent c5e405542e
commit 2a64d5315e
27 changed files with 5551 additions and 5371 deletions

2
NOTICE
View File

@ -1,7 +1,7 @@
JSON Editor Online
http://jsoneditoronline.org
Copyright (C) 2011-2012 Jos de Jong
Copyright (C) 2011-2013 Jos de Jong
Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -23,10 +23,10 @@
* License for the specific language governing permissions and limitations under
* the License.
*
* Copyright (C) 2011-2012 Jos de Jong, http://jsoneditoronline.org
* Copyright (C) 2011-2013 Jos de Jong, http://jsoneditoronline.org
*
* @author Jos de Jong, <wjosdejong@gmail.com>
* @date 2012-11-03
* @date 2013-01-01
*/

View File

@ -57,10 +57,10 @@
* License for the specific language governing permissions and limitations under
* the License.
*
* Copyright (c) 2012 Jos de Jong, http://jsoneditoronline.org
* Copyright (c) 2013 Jos de Jong, http://jsoneditoronline.org
*
* @author Jos de Jong, <wjosdejong@gmail.com>
* @date 2012-11-03
* @date 2013-01-01
*/
var FileRetriever = function (options) {
// set options and variables

View File

@ -34,10 +34,10 @@
License for the specific language governing permissions and limitations under
the License.
Copyright (C) 2011-2012 Jos de Jong, http://jsoneditoronline.org
Copyright (C) 2011-2013 Jos de Jong, http://jsoneditoronline.org
@author Jos de Jong, <wjosdejong@gmail.com>
@date 2012-11-03
@date 2013-01-01
-->
<meta name="description" content="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 formatted plain text.">
@ -165,7 +165,7 @@
&bull;
<a href="datapolicy.txt" target="_blank" class="footer">Data policy</a>
&bull;
<a href="NOTICE" target="_blank" class="footer">Copyright 2011-2012 Jos de Jong</a>
<a href="NOTICE" target="_blank" class="footer">Copyright 2011-2013 Jos de Jong</a>
</div>
</div>

View File

@ -33,10 +33,10 @@
License for the specific language governing permissions and limitations under
the License.
Copyright (C) 2011-2012 Jos de Jong, http://jsoneditoronline.org
Copyright (C) 2011-2013 Jos de Jong, http://jsoneditoronline.org
@author Jos de Jong, <wjosdejong@gmail.com>
@date 2012-11-03
@date 2013-01-01
-->
<meta name="description" content="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 formatted plain text.">
@ -47,12 +47,23 @@
<link href="app.css" rel="stylesheet" type="text/css">
<link href="fileretriever.css" rel="stylesheet" type="text/css">
<link href="../../jsoneditor/jsoneditor.css" rel="stylesheet" type="text/css">
<link href="../../jsoneditor/css/jsoneditor.css" rel="stylesheet" type="text/css">
<link href="../../jsoneditor/css/menu.css" rel="stylesheet" type="text/css">
<link href="../../jsoneditor/css/searchbox.css" rel="stylesheet" type="text/css">
<link href="../../jsoneditor/css/contextmenu.css" rel="stylesheet" type="text/css">
<!-- TODO: droid font
<link href='http://fonts.googleapis.com/css?family=Droid+Sans+Mono' rel='stylesheet' type='text/css'>
-->
<script type="text/javascript" src="../../jsoneditor/jsoneditor.js"></script>
<script type="text/javascript" src="../../jsoneditor/js/jsoneditor.js"></script>
<script type="text/javascript" src="../../jsoneditor/js/jsonformatter.js"></script>
<script type="text/javascript" src="../../jsoneditor/js/node.js"></script>
<script type="text/javascript" src="../../jsoneditor/js/appendnode.js"></script>
<script type="text/javascript" src="../../jsoneditor/js/contextmenu.js"></script>
<script type="text/javascript" src="../../jsoneditor/js/history.js"></script>
<script type="text/javascript" src="../../jsoneditor/js/searchbox.js"></script>
<script type="text/javascript" src="../../jsoneditor/js/highlighter.js"></script>
<script type="text/javascript" src="../../jsoneditor/js/util.js"></script>
<script type="text/javascript" src="queryparams.js"></script>
<script type="text/javascript" src="ajax.js"></script>
<script type="text/javascript" src="fileretriever.js"></script>
@ -63,10 +74,10 @@
<style type="text/css">
div.convert-right {
background: url('../../jsoneditor/img/jsoneditor-icons.png') -0 -48px;
background: url('../../jsoneditor/css/img/jsoneditor-icons.png') -0 -48px;
}
div.convert-left {
background: url('../../jsoneditor/img/jsoneditor-icons.png') -24px -48px;
background: url('../../jsoneditor/css/img/jsoneditor-icons.png') -24px -48px;
}
</style>
</head>
@ -191,7 +202,7 @@
&bull;
<a href="datapolicy.txt" target="_blank" class="footer">Data policy</a>
&bull;
<a href="../../NOTICE" target="_blank" class="footer">Copyright 2011-2012 Jos de Jong</a>
<a href="../../NOTICE" target="_blank" class="footer">Copyright 2011-2013 Jos de Jong</a>
</div>
</div>

View File

@ -9,11 +9,14 @@
<property name="compressor" value="tools/yuicompressor-2.4.7.jar" />
<!-- directories -->
<property name="root" location="" />
<property name="lib" location="build/lib" />
<property name="web_app" location="build/app/web" />
<property name="chrome_app" location="build/app/chrome" />
<property name="web_app_src" location="app/web" />
<property name="lib" location="build/lib" />
<property name="web_app" location="build/app/web" />
<property name="chrome_app" location="build/app/chrome" />
<property name="web_app_src" location="app/web" />
<property name="src" location="jsoneditor" />
<property name="js_src" location="jsoneditor/js" />
<property name="css_src" location="jsoneditor/css" />
<property name="img_src" location="jsoneditor/css/img" />
<property name="jsoneditor" location="${lib}/${package}-${version}" />
<property name="jsoneditor_min" location="${lib}/${package}-${version}.min" />
@ -22,43 +25,72 @@
<delete dir="${jsoneditor_min}" />
<!-- copy all files for the non-minified jsoneditor -->
<copy file="${root}/LICENSE" todir="${jsoneditor}" />
<copy file="${root}/NOTICE" todir="${jsoneditor}" />
<copy file="${root}/README.md" todir="${jsoneditor}" />
<copy file="${root}/changelog.txt" todir="${jsoneditor}" />
<copy file="${root}/demo.html" todir="${jsoneditor}" />
<copy file="${root}/jsoneditor/jsoneditor.js" todir="${jsoneditor}/jsoneditor" />
<copy file="${root}/jsoneditor/jsoneditor.css" todir="${jsoneditor}/jsoneditor" />
<copy file="${root}/jsoneditor/img/jsoneditor-icons.png" todir="${jsoneditor}/jsoneditor/img" />
<copy file="README.md" todir="${jsoneditor}" />
<copy file="LICENSE" todir="${jsoneditor}" />
<copy file="NOTICE" todir="${jsoneditor}" />
<copy file="changelog.txt" todir="${jsoneditor}" />
<copy todir="${jsoneditor}/examples">
<fileset dir="${src}/examples"/>
</copy>
<copy file="${img_src}/jsoneditor-icons.png" todir="${jsoneditor}/img" />
<!-- copy all files for the minified jsoneditor -->
<copy file="${root}/LICENSE" todir="${jsoneditor_min}" />
<copy file="${root}/NOTICE" todir="${jsoneditor_min}" />
<copy file="${root}/README.md" todir="${jsoneditor_min}" />
<copy file="${root}/changelog.txt" todir="${jsoneditor_min}" />
<copy file="${root}/demo.html" todir="${jsoneditor_min}" />
<copy file="${root}/jsoneditor/img/jsoneditor-icons.png" todir="${jsoneditor_min}/jsoneditor/img" />
<copy file="README.md" todir="${jsoneditor_min}" />
<copy file="LICENSE" todir="${jsoneditor_min}" />
<copy file="NOTICE" todir="${jsoneditor_min}" />
<copy file="changelog.txt" todir="${jsoneditor_min}" />
<copy todir="${jsoneditor_min}/examples">
<fileset dir="${src}/examples"/>
</copy>
<replace dir="${jsoneditor_min}/examples" value="jsoneditor-min.js">
<include name="**/*.html"/>
<replacetoken>jsoneditor.js</replacetoken>
</replace>
<replace dir="${jsoneditor_min}/examples" value="jsoneditor-min.css">
<include name="**/*.html"/>
<replacetoken>jsoneditor.css</replacetoken>
</replace>
<copy file="${img_src}/jsoneditor-icons.png" todir="${jsoneditor_min}/img" />
<!-- concatenate the javascript and css app files -->
<concat destfile="${jsoneditor}/jsoneditor.js">
<fileset dir="${js_src}" includes="jsoneditor.js"/>
<fileset dir="${js_src}" includes="jsonformatter.js"/>
<fileset dir="${js_src}" includes="node.js"/>
<fileset dir="${js_src}" includes="appendnode.js"/>
<fileset dir="${js_src}" includes="contextmenu.js"/>
<fileset dir="${js_src}" includes="history.js"/>
<fileset dir="${js_src}" includes="searchbox.js"/>
<fileset dir="${js_src}" includes="highlighter.js"/>
<fileset dir="${js_src}" includes="util.js"/>
</concat>
<concat destfile="${jsoneditor}/jsoneditor.css">
<fileset dir="${css_src}" includes="jsoneditor.css"/>
<fileset dir="${css_src}" includes="menu.css"/>
<fileset dir="${css_src}" includes="contextmenu.css"/>
<fileset dir="${css_src}" includes="searchbox.css"/>
</concat>
<!-- minify the jsoneditor files -->
<java jar="${compressor}" dir="jsoneditor" fork="true" failonerror="true">
<java jar="${compressor}" dir="${jsoneditor}/" fork="true" failonerror="true">
<arg value="-o"/>
<arg value="${jsoneditor_min}/jsoneditor/jsoneditor-min.js"/>
<arg value="${jsoneditor_min}/jsoneditor-min.js"/>
<arg value="jsoneditor.js"/>
</java>
<java jar="${compressor}" dir="jsoneditor" fork="true" failonerror="true">
<java jar="${compressor}" dir="${jsoneditor}" fork="true" failonerror="true">
<arg value="-o"/>
<arg value="${jsoneditor_min}/jsoneditor/jsoneditor-min.css"/>
<arg value="${jsoneditor_min}/jsoneditor-min.css"/>
<arg value="jsoneditor.css"/>
</java>
<!-- create a zip file with non-minified jsoneditor -->
<zip destfile="${lib}/${package}-${version}.zip">
<fileset dir="${jsoneditor}" includes="**" />
<fileset dir="${lib}" includes="${package}-${version}/*" />
</zip>
<!-- create a zip file with minified jsoneditor -->
<zip destfile="${lib}/${package}-${version}.min.zip">
<fileset dir="${jsoneditor_min}" includes="**" />
<fileset dir="${lib}" includes="${package}-${version}.min/*" />
</zip>
</target>
@ -94,9 +126,9 @@
<copy file="${web_app_src}/img/header_background.png" todir="${web_app}/img" />
<copy file="${web_app_src}/lib/jsonlint/jsonlint.js" todir="${web_app}/lib/jsonlint" />
<copy file="${jsoneditor_min}/jsoneditor/jsoneditor-min.js" todir="${web_app}/lib/jsoneditor" />
<copy file="${jsoneditor_min}/jsoneditor/jsoneditor-min.css" todir="${web_app}/lib/jsoneditor" />
<copy file="${jsoneditor_min}/jsoneditor/img/jsoneditor-icons.png" todir="${web_app}/lib/jsoneditor/img" />
<copy file="${jsoneditor_min}/jsoneditor-min.js" todir="${web_app}/lib/jsoneditor" />
<copy file="${jsoneditor_min}/jsoneditor-min.css" todir="${web_app}/lib/jsoneditor" />
<copy file="${jsoneditor_min}/img/jsoneditor-icons.png" todir="${web_app}/lib/jsoneditor/img" />
<!-- minify the javascript files -->
<java jar="${compressor}" dir="${web_app}" fork="true" failonerror="true">

View File

@ -0,0 +1,219 @@
/* _______________________________ MAIN MENU ________________________________ */
div.jsoneditor-contextmenu {
position: absolute;
}
div.jsoneditor-contextmenu ul {
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);
z-index: 1;
list-style: none;
margin: 0;
padding: 0;
}
div.jsoneditor-contextmenu ul li button {
padding: 0;
margin: 0;
width: 124px;
height: 24px;
border: none;
cursor: pointer;
color: #4d4d4d;
background: transparent;
line-height: 24px;
text-align: left;
}
/* Fix button padding in firefox */
div.jsoneditor-contextmenu ul li button::-moz-focus-inner {
padding: 0;
border: 0;
}
div.jsoneditor-contextmenu ul li button:hover {
color: #1a1a1a;
background-color: #f5f5f5;
}
div.jsoneditor-contextmenu ul li button.default {
width: 92px;
}
div.jsoneditor-contextmenu ul li button.expand {
float: right;
width: 32px;
height: 24px;
border-left: 1px solid #e5e5e5;
}
div.jsoneditor-contextmenu div.icon {
float: left;
width: 24px;
height: 24px;
border: none;
padding: 0;
margin: 0;
background-image: url('img/jsoneditor-icons.png');
}
div.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;
}
div.jsoneditor-contextmenu ul li button:hover div.expand,
div.jsoneditor-contextmenu ul li.selected div.expand,
div.jsoneditor-contextmenu ul li button.expand:hover div.expand {
opacity: 1;
}
div.jsoneditor-contextmenu .separator {
height: 0;
border-top: 1px solid #e5e5e5;
padding-top: 5px;
margin-top: 5px;
}
button.jsoneditor-remove > .icon {
background-position: -24px -24px;
}
button.jsoneditor-remove:hover > .icon {
background-position: -24px 0;
}
button.jsoneditor-append > .icon {
background-position: 0 -24px;
}
button.jsoneditor-append:hover > .icon {
background-position: 0 0;
}
button.jsoneditor-insert > .icon {
background-position: 0 -24px;
}
button.jsoneditor-insert:hover > .icon {
background-position: 0 0;
}
button.jsoneditor-insert-above > .icon {
background-position: -24px -24px;
}
button.jsoneditor-insert-above:hover > .icon {
background-position: -24px 0;
}
button.jsoneditor-insert-below > .icon {
background-position: -48px -24px;
}
button.jsoneditor-insert-below:hover > .icon {
background-position: -48px 0;
}
button.jsoneditor-duplicate > .icon {
background-position: -48px -24px;
}
button.jsoneditor-duplicate:hover > .icon {
background-position: -48px 0;
}
button.jsoneditor-sort-asc > .icon {
background-position: -168px -24px;
}
button.jsoneditor-sort-asc:hover > .icon {
background-position: -168px 0;
}
button.jsoneditor-sort-desc > .icon {
background-position: -192px -24px;
}
button.jsoneditor-sort-desc:hover > .icon {
background-position: -192px 0;
}
/* ____________________________ CONTEXT SUB MENU ____________________________ */
div.jsoneditor-contextmenu ul li ul li .selected {
background-color: #D5DDF6;
}
div.jsoneditor-contextmenu ul li {
overflow: hidden;
}
div.jsoneditor-contextmenu ul li ul {
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;
/* 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;
}
div.jsoneditor-contextmenu ul li.selected ul {
}
div.jsoneditor-contextmenu ul li ul li button {
padding-left: 24px;
}
div.jsoneditor-contextmenu ul li ul li button:hover {
background-color: #f5f5f5;
}
button.jsoneditor-type-string > .icon {
background-position: -144px -24px;
}
button.jsoneditor-type-string:hover > .icon,
button.jsoneditor-type-string.selected > .icon{
background-position: -144px 0;
}
button.jsoneditor-type-auto > .icon {
background-position: -120px -24px;
}
button.jsoneditor-type-auto:hover > .icon,
button.jsoneditor-type-auto.selected > .icon {
background-position: -120px 0;
}
button.jsoneditor-type-object > .icon {
background-position: -72px -24px;
}
button.jsoneditor-type-object:hover > .icon,
button.jsoneditor-type-object.selected > .icon{
background-position: -72px 0;
}
button.jsoneditor-type-array > .icon {
background-position: -96px -24px;
}
button.jsoneditor-type-array:hover > .icon,
button.jsoneditor-type-array.selected > .icon{
background-position: -96px 0;
}

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -0,0 +1,235 @@
.jsoneditor-field, .jsoneditor-value, .jsoneditor-field-readonly, .jsoneditor-readonly {
border: 1px solid transparent;
min-height: 16px;
min-width: 24px;
padding: 2px;
margin: 1px;
outline: none;
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;
}
.jsoneditor-value {
word-break: break-word;
}
.jsoneditor-empty {
background-color: #E5E5E5;
border-radius: 2px;
}
.jsoneditor-separator {
padding: 3px 0;
vertical-align: top;
}
.jsoneditor-value:focus, .jsoneditor-field:focus,
.jsoneditor-value:hover, .jsoneditor-field:hover,
.jsoneditor-search-highlight {
background-color: #FFFFAB;
border: 1px solid yellow;
border-radius: 2px;
}
.jsoneditor-search-highlight-active,
.jsoneditor-search-highlight-active:focus,
.jsoneditor-search-highlight-active:hover {
background-color: #ffee00;
border: 1px solid #ffc700;
border-radius: 2px;
}
.jsoneditor-field-readonly:hover {
border: 1px solid white;
}
.jsoneditor-readonly {
color: gray;
}
button.jsoneditor-collapsed, button.jsoneditor-expanded,
button.jsoneditor-invisible, button.jsoneditor-dragarea,
button.jsoneditor-contextmenu, button.jsoneditor-append {
width: 24px;
height: 24px;
padding: 0;
margin: 0;
border: none;
cursor: pointer;
background-color: transparent;
background-image: url('img/jsoneditor-icons.png');
}
/* TODO: no global settings
button:disabled {
color: #808080;
}
*/
td.jsoneditor-nochilds {
color: gray;
}
button.jsoneditor-collapsed {
background-position: 0 -48px;
}
button.jsoneditor-expanded {
background-position: 0 -72px;
}
.jsoneditor-contextmenu {
position: relative;
background-position: -48px -72px;
}
.jsoneditor-contextmenu:hover, .jsoneditor-contextmenu:focus {
background-position: -48px -48px;
}
button.jsoneditor-invisible {
visibility: hidden;
background: none;
}
button.jsoneditor-collapsed, button.jsoneditor-expanded,
button.jsoneditor-invisible {
float: left;
}
div.jsoneditor-frame {
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;
}
table.jsoneditor-table {
border-collapse: collapse;
border-spacing: 0;
width: 100%;
margin: 0;
}
div.jsoneditor-content-outer, div.jsonformatter-content {
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;
overflow: hidden;
}
div.jsoneditor-content {
width: 100%;
height: 100%;
position: relative;
overflow: auto;
}
textarea.jsonformatter-textarea {
width: 100%;
height: 100%;
margin: 0;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
border: none;
background-color: white;
resize: none;
}
tr.jsoneditor-tr-highlight {
background-color: #FFFFAB;
}
button.jsoneditor-dragarea {
width: 24px;
height: 24px;
/*
margin: 3px 0;
background: url('img/dots_gray.gif') top center;
background-repeat: repeat-y;
*/
background: url('img/jsoneditor-icons.png') -72px -72px;
display: block;
cursor: move;
}
button.jsoneditor-dragarea:hover, .jsoneditor-dragarea:focus {
background-position: -72px -48px;
}
/* TODO: do not change global tr, th, td */
tr, th, td {
padding: 0;
margin: 0;
}
td.jsoneditor-td {
vertical-align: top;
}
td.jsoneditor-td {
padding: 0;
}
td.jsoneditor-td-edit {
background-color: #F5F5F5;
padding: 0;
}
td.jsoneditor-td-tree {
vertical-align: top;
}
td.jsoneditor-droparea {
height: 24px;
border-top: 1px dashed gray;
border-bottom: 1px dashed gray;
background-color: #FFFF80;
}
.jsoneditor-field, .jsoneditor-value, .jsoneditor-td, .jsoneditor-th,
.jsoneditor-type, .jsonformatter-textarea {
font-family: droid sans mono, monospace, courier new, courier, sans-serif;
font-size: 10pt;
color: #1A1A1A;
}
div.jsoneditor-contextmenu button,
input.jsoneditor-search, div.jsoneditor-search-results {
font-family: arial, sans-serif;
font-size: 10pt;
color: #1A1A1A;
}
.jsoneditor-hidden-focus {
position: absolute;
left: -1000px;
top: -1000px;
border: none;
outline: none;
}
/* TODO: drastically cleanup the css, improve/simplify naming and cascading */

64
jsoneditor/css/menu.css Normal file
View File

@ -0,0 +1,64 @@
/* __________________________ JSONEDITOR TOP MENU ___________________________ */
div.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;
color: #1A1A1A;
background-color: #D5DDF6;
border-bottom: 1px solid #97B0F8;
}
button.jsoneditor-menu {
width: 26px;
height: 26px;
margin: 2px;
padding: 2px;
border-radius: 2px;
border: 1px solid #aec0f8;
background: #e3eaf6 url('img/jsoneditor-icons.png');
}
button.jsoneditor-menu:hover {
background-color: #f0f2f5;
}
button.jsoneditor-menu:active {
background-color: #ffffff;
}
button.jsoneditor-menu:disabled {
background-color: #e3eaf6;
}
button.jsoneditor-collapse-all {
background-position: 0 -96px;
}
button.jsoneditor-expand-all {
background-position: 0 -120px;
}
button.jsoneditor-undo {
background-position: -24px -96px;
}
button.jsoneditor-undo:disabled {
background-position: -24px -120px;
}
button.jsoneditor-redo {
background-position: -48px -96px;
}
button.jsoneditor-redo:disabled {
background-position: -48px -120px;
}
/* TODO: css for button:disabled is not supported by IE8 */
button.jsoneditor-compact {
background-position: -72px -96px;
}
button.jsoneditor-format {
background-position: -72px -120px;
}

View File

@ -0,0 +1,62 @@
table.jsoneditor-search {
position: absolute;
right: 2px;
top: 2px;
}
table.jsoneditor-search-input {
border-collapse: collapse;
}
div.jsoneditor-search {
border: 1px solid #97B0F8;
background-color: white;
padding: 0 2px;
margin: 0;
}
input.jsoneditor-search {
width: 120px;
border: none;
outline: none;
margin: 1px;
}
div.jsoneditor-search-results {
color: #4d4d4d;
padding-right: 5px;
}
button.jsoneditor-search-refresh, button.jsoneditor-search-next,
button.jsoneditor-search-previous {
width: 16px;
height: 24px;
padding: 0;
margin: 0;
border: none;
background: url('img/jsoneditor-icons.png');
vertical-align: top;
}
button.jsoneditor-search-refresh {
width: 18px;
background-position: -99px -73px;
}
button.jsoneditor-search-next {
cursor: pointer;
background-position: -124px -73px;
}
button.jsoneditor-search-next:hover {
background-position: -124px -49px;
}
button.jsoneditor-search-previous {
cursor: pointer;
background-position: -148px -73px;
margin-right: 2px;
}
button.jsoneditor-search-previous:hover {
background-position: -148px -49px;
}

View File

@ -1,8 +1,8 @@
<!DOCTYPE HTML>
<html>
<head>
<link rel="stylesheet" type="text/css" href="jsoneditor/jsoneditor.css">
<script type="text/javascript" src="jsoneditor/jsoneditor.js"></script>
<link rel="stylesheet" type="text/css" href="../jsoneditor.css">
<script type="text/javascript" src="../jsoneditor.js"></script>
<style type="text/css">
body {font: 11pt sans-serif;}
</style>

224
jsoneditor/js/appendnode.js Normal file
View File

@ -0,0 +1,224 @@
/**
* @license
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* Copyright (c) 2011-2013 Jos de Jong, http://jsoneditoronline.org
*
* @author Jos de Jong, <wjosdejong@gmail.com>
*/
/**
* @constructor JSONEditor.AppendNode
* @extends JSONEditor.Node
* @param {JSONEditor} editor
* Create a new AppendNode. This is a special node which is created at the
* end of the list with childs for an object or array
*/
JSONEditor.AppendNode = function (editor) {
this.editor = editor;
this.dom = {};
};
JSONEditor.AppendNode.prototype = new JSONEditor.Node();
/**
* Return a table row with an append button.
* @return {Element} dom TR element
*/
JSONEditor.AppendNode.prototype.getDom = function () {
// TODO: do not create the DOM for the appendNode when in viewer mode
// TODO: implement a new solution for the append node
var dom = this.dom;
if (dom.tr) {
return dom.tr;
}
// a row for the append button
var trAppend = document.createElement('tr');
trAppend.node = this;
dom.tr = trAppend;
// when in viewer mode, don't create the contents for the append node
// but return here.
if (!this.editor.editable) {
return trAppend;
}
// TODO: consistent naming
// a cell for the dragarea column
var tdDrag = document.createElement('td');
tdDrag.className = 'jsoneditor-td';
dom.tdDrag = tdDrag;
// create context menu
var tdMenu = document.createElement('td');
tdMenu.className = 'jsoneditor-td';
var menu = document.createElement('button');
menu.className = 'jsoneditor-contextmenu';
dom.menu = menu;
dom.tdMenu = tdMenu;
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 = 'jsoneditor-readonly';
tdAppend.appendChild(domText);
tdAppend.className = 'jsoneditor-td';
dom.td = tdAppend;
dom.text = domText;
this.updateDom();
return trAppend;
};
/**
* Update the HTML dom of the Node
*/
JSONEditor.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 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) {
trAppend.removeChild(dom.tdDrag);
trAppend.removeChild(dom.tdMenu);
trAppend.removeChild(tdAppend);
}
}
else {
if (!dom.tr.firstChild) {
trAppend.appendChild(dom.tdDrag);
trAppend.appendChild(dom.tdMenu);
trAppend.appendChild(tdAppend);
}
}
};
/**
* Check whether the AppendNode is currently visible.
* the AppendNode is visible when its parent has no childs (i.e. is empty).
* @return {boolean} isVisible
*/
JSONEditor.AppendNode.prototype.isVisible = function () {
return (this.parent.childs.length == 0);
};
/**
* Show a contextmenu for this node
* @param {function} [onClose] Callback method called when the context menu
* is being closed.
*/
JSONEditor.AppendNode.prototype.showContextMenu = function (onClose) {
var node = this;
var titles = JSONEditor.Node.TYPE_TITLES;
var items = [
// create append button
{
'text': 'Append',
'title': 'Append a new node with type \'auto\'',
'submenuTitle': 'Select the type of the node to be appended',
'className': 'jsoneditor-insert',
'click': function () {
node._onAppend('field', 'value', 'auto');
},
'submenu': [
{
'text': 'Auto',
'className': 'jsoneditor-type-auto',
'title': titles.auto,
'click': function () {
node._onAppend('field', 'value', 'auto');
}
},
{
'text': 'Array',
'className': 'jsoneditor-type-array',
'title': titles.array,
'click': function () {
node._onAppend('field', []);
}
},
{
'text': 'Object',
'className': 'jsoneditor-type-object',
'title': titles.object,
'click': function () {
node._onAppend('field', {});
}
},
{
'text': 'String',
'className': 'jsoneditor-type-string',
'title': titles.string,
'click': function () {
// TODO: settings type string does not work, will become auto
node._onAppend('field', 'value', 'string');
}
}
]
}
];
var menu = new JSONEditor.ContextMenu(items, {close: onClose});
menu.show(this.dom.menu);
};
/**
* Handle an event. The event is catched centrally by the editor
* @param {Event} event
*/
JSONEditor.AppendNode.prototype.onEvent = function (event) {
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();
}
}
// context menu events
if (type == 'click' && target == dom.menu) {
var highlighter = this.editor.highlighter;
highlighter.highlight(this.parent);
highlighter.lock();
this.showContextMenu(function () {
highlighter.unlock();
highlighter.unhighlight();
});
}
};

View File

@ -0,0 +1,272 @@
/**
* @license
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* Copyright (c) 2011-2013 Jos de Jong, http://jsoneditoronline.org
*
* @author Jos de Jong, <wjosdejong@gmail.com>
*/
/**
* A context menu
* @param {Object[]} items Array containing the menu structure
* TODO: describe structure
* @param {Object} [options] Object with options. Available options:
* {function} close Callback called when the
* context menu is being closed.
* @constructor
*/
JSONEditor.ContextMenu = function (items, options) {
var me = this;
this.items = items;
this.eventListeners = {};
this.visibleSubmenu = undefined;
this.onClose = options ? options.close : undefined;
// create a container element
var menu = document.createElement('div');
menu.className = 'jsoneditor-contextmenu';
this.menu = menu;
// create a list to hold the menu items
var list = document.createElement('ul');
list.className = 'menu';
menu.appendChild(list);
this.list = list;
function createMenuItems (list, 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 {
// 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;
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');
buttonExpand.className = 'expand';
buttonExpand.innerHTML = '<div class="expand"></div>';
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
var selected = false;
buttonSubmenu.onclick = function () {
me._onShowSubmenu(submenu);
};
// create the submenu
var submenu = document.createElement('ul');
submenu.className = 'menu';
submenu.style.height = '0';
li.appendChild(submenu);
createMenuItems(submenu, item.submenu);
}
else {
// no submenu, just a button with clickhandler
button.innerHTML = '<div class="icon"></div>' + item.text;
}
}
});
}
createMenuItems(list, 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);
});
};
// currently displayed context menu, a singleton. We may only have one visible context menu
JSONEditor.ContextMenu.visibleMenu = undefined;
/**
* Attach the menu to an anchor
* @param {Element} anchor
*/
JSONEditor.ContextMenu.prototype.show = function (anchor) {
this.hide();
// calculate whether the menu fits below the anchor
var windowHeight = JSONEditor.util.getWindowHeight();
var anchorHeight = anchor.offsetHeight;
var menuHeight = this.maxHeight;
// position the menu
var left = JSONEditor.util.getAbsoluteLeft(anchor);
var top = JSONEditor.util.getAbsoluteTop(anchor);
if (top + anchorHeight + menuHeight < windowHeight) {
// display the menu below the anchor
this.menu.style.left = left + 'px';
this.menu.style.top = (top + anchorHeight) + 'px';
this.menu.style.bottom = '';
}
else {
// display the menu above the anchor
this.menu.style.left = left + 'px';
this.menu.style.top = '';
this.menu.style.bottom = (windowHeight - top) + 'px';
}
// attach the menu to the document
document.body.appendChild(this.menu);
// create and attach event listeners
var me = this;
var list = this.list;
this.eventListeners.mousedown = JSONEditor.util.addEventListener(
document, 'mousedown', function (event) {
// hide menu on click outside of the menu
event = event || window.event;
var target = event.target || event.srcElement;
if (!JSONEditor.isChildOf(target, list)) {
me.hide();
}
});
this.eventListeners.mousewheel = JSONEditor.util.addEventListener(
document, 'mousewheel', function () {
// hide the menu on mouse scroll
me.hide();
});
this.eventListeners.keydown = JSONEditor.util.addEventListener(
document, 'keydown', function (event) {
// hide the menu on ESC key
event = event || window.event;
var keynum = event.which || event.keyCode;
if (keynum == 27) { // ESC
me.hide();
JSONEditor.util.stopPropagation(event);
JSONEditor.util.preventDefault(event);
}
});
// TODO: focus to the first button in the context menu
if (JSONEditor.ContextMenu.visibleMenu) {
JSONEditor.ContextMenu.visibleMenu.hide();
}
JSONEditor.ContextMenu.visibleMenu = this;
};
/**
* Hide the context menu if visible
*/
JSONEditor.ContextMenu.prototype.hide = function () {
// remove the menu from the DOM
if (this.menu.parentNode) {
this.menu.parentNode.removeChild(this.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) {
JSONEditor.util.removeEventListener(document, name, fn);
}
delete this.eventListeners[name];
}
}
};
/**
* Show or hide a submenu.
* Any currently visible submenu will be hided.
* @param {Element} submenu
* @private
*/
JSONEditor.ContextMenu.prototype._onShowSubmenu = function (submenu) {
var me = this;
var alreadyVisible = (submenu == this.visibleSubmenu);
// hide the currently visible submenu
var visibleSubmenu = this.visibleSubmenu;
if (visibleSubmenu) {
visibleSubmenu.style.height = '0';
visibleSubmenu.style.padding = '';
setTimeout(function () {
if (me.visibleSubmenu != visibleSubmenu) {
visibleSubmenu.style.display = '';
JSONEditor.util.removeClassName(visibleSubmenu.parentNode, 'selected');
}
}, 300); // timeout duration must match the css transition duration
this.visibleSubmenu = undefined;
}
if (!alreadyVisible) {
submenu.style.display = 'block';
var height = submenu.clientHeight; // force a reflow in Firefox
setTimeout(function () {
if (me.visibleSubmenu == submenu) {
submenu.style.height = (submenu.childNodes.length * 24) + 'px';
submenu.style.padding = '5px 10px';
}
}, 0);
JSONEditor.util.addClassName(submenu.parentNode, 'selected');
this.visibleSubmenu = submenu;
}
};

View File

@ -0,0 +1,102 @@
/**
* @license
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* Copyright (c) 2011-2013 Jos de Jong, http://jsoneditoronline.org
*
* @author Jos de Jong, <wjosdejong@gmail.com>
*/
/**
* The highlighter can highlight/unhighlight a node, and
* animate the visibility of a context menu.
* @constructor JSONEditor.Highlighter
*/
JSONEditor.Highlighter = function () {
this.locked = false;
};
/**
* Hightlight given node and its childs
* @param {JSONEditor.Node} node
*/
JSONEditor.Highlighter.prototype.highlight = function (node) {
if (this.locked) {
return;
}
if (this.node != node) {
// unhighlight current node
if (this.node) {
this.node.setHighlight(false);
}
// highlight new node
this.node = node;
this.node.setHighlight(true);
}
// cancel any current timeout
this._cancelUnhighlight();
};
/**
* Unhighlight currently highlighted node.
* Will be done after a delay
*/
JSONEditor.Highlighter.prototype.unhighlight = function () {
if (this.locked) {
return;
}
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);
}
};
/**
* Cancel an unhighlight action (if before the timeout of the unhighlight action)
* @private
*/
JSONEditor.Highlighter.prototype._cancelUnhighlight = function () {
if (this.unhighlightTimer) {
clearTimeout(this.unhighlightTimer);
this.unhighlightTimer = undefined;
}
};
/**
* Lock highlighting or unhighlighting nodes.
* methods highlight and unhighlight do not work while locked.
*/
JSONEditor.Highlighter.prototype.lock = function () {
this.locked = true;
};
/**
* Unlock highlighting or unhighlighting nodes
*/
JSONEditor.Highlighter.prototype.unlock = function () {
this.locked = false;
};

233
jsoneditor/js/history.js Normal file
View File

@ -0,0 +1,233 @@
/**
* @license
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* Copyright (c) 2011-2013 Jos de Jong, http://jsoneditoronline.org
*
* @author Jos de Jong, <wjosdejong@gmail.com>
*/
/**
* @constructor JSONEditor.History
* Store action history, enables undo and redo
* @param {JSONEditor} editor
*/
JSONEditor.History = function (editor) {
this.editor = editor;
this.clear();
// map with all supported actions
this.actions = {
'editField': {
'undo': function (obj) {
obj.params.node.updateField(obj.params.oldValue);
},
'redo': function (obj) {
obj.params.node.updateField(obj.params.newValue);
}
},
'editValue': {
'undo': function (obj) {
obj.params.node.updateValue(obj.params.oldValue);
},
'redo': function (obj) {
obj.params.node.updateValue(obj.params.newValue);
}
},
'appendNode': {
'undo': function (obj) {
obj.params.parent.removeChild(obj.params.node);
},
'redo': function (obj) {
obj.params.parent.appendChild(obj.params.node);
}
},
'insertBeforeNode': {
'undo': function (obj) {
obj.params.parent.removeChild(obj.params.node);
},
'redo': function (obj) {
obj.params.parent.insertBefore(obj.params.node, obj.params.beforeNode);
}
},
'insertAfterNode': {
'undo': function (obj) {
obj.params.parent.removeChild(obj.params.node);
},
'redo': function (obj) {
obj.params.parent.insertAfter(obj.params.node, obj.params.afterNode);
}
},
'removeNode': {
'undo': function (obj) {
var parent = obj.params.parent;
var beforeNode = parent.childs[obj.params.index] || parent.append;
parent.insertBefore(obj.params.node, beforeNode);
},
'redo': function (obj) {
obj.params.parent.removeChild(obj.params.node);
}
},
'duplicateNode': {
'undo': function (obj) {
obj.params.parent.removeChild(obj.params.clone);
},
'redo': function (obj) {
obj.params.parent.insertAfter(obj.params.clone, obj.params.node);
}
},
'changeType': {
'undo': function (obj) {
obj.params.node.changeType(obj.params.oldType);
},
'redo': function (obj) {
obj.params.node.changeType(obj.params.newType);
}
},
'moveNode': {
'undo': function (obj) {
obj.params.startParent.moveTo(obj.params.node, obj.params.startIndex);
},
'redo': function (obj) {
obj.params.endParent.moveTo(obj.params.node, obj.params.endIndex);
}
},
'sort': {
'undo': function (obj) {
var node = obj.params.node;
node.hideChilds();
node.sort = obj.params.oldSort;
node.childs = obj.params.oldChilds;
node.showChilds();
},
'redo': function (obj) {
var node = obj.params.node;
node.hideChilds();
node.sort = obj.params.newSort;
node.childs = obj.params.newChilds;
node.showChilds();
}
}
// TODO: restore the original caret position and selection with each undo
// TODO: implement history for actions "expand", "collapse", "scroll", "setDocument"
};
};
/**
* The method onChange is executed when the History is changed, and can
* be overloaded.
*/
JSONEditor.History.prototype.onChange = function () {};
/**
* Add a new action to the history
* @param {String} action The executed action. Available actions: "editField",
* "editValue", "changeType", "appendNode",
* "removeNode", "duplicateNode", "moveNode"
* @param {Object} params Object containing parameters describing the change.
* The parameters in params depend on the action (for
* example for "editValue" the Node, old value, and new
* value are provided). params contains all information
* needed to undo or redo the action.
*/
JSONEditor.History.prototype.add = function (action, params) {
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);
}
// fire onchange event
this.onChange();
};
/**
* Clear history
*/
JSONEditor.History.prototype.clear = function () {
this.history = [];
this.index = -1;
// fire onchange event
this.onChange();
};
/**
* Check if there is an action available for undo
* @return {Boolean} canUndo
*/
JSONEditor.History.prototype.canUndo = function () {
return (this.index >= 0);
};
/**
* Check if there is an action available for redo
* @return {Boolean} canRedo
*/
JSONEditor.History.prototype.canRedo = function () {
return (this.index < this.history.length - 1);
};
/**
* Undo the last action
*/
JSONEditor.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);
}
else {
console.log('Error: unknown action "' + obj.action + '"');
}
}
this.index--;
// fire onchange event
this.onChange();
}
};
/**
* Redo the last action
*/
JSONEditor.History.prototype.redo = function () {
if (this.canRedo()) {
this.index++;
var obj = this.history[this.index];
if (obj) {
if (obj) {
var action = this.actions[obj.action];
if (action && action.redo) {
action.redo(obj);
}
else {
console.log('Error: unknown action "' + obj.action + '"');
}
}
}
// fire onchange event
this.onChange();
}
};

786
jsoneditor/js/jsoneditor.js Normal file
View File

@ -0,0 +1,786 @@
/*!
* @file jsoneditor.js
*
* @brief
* JSONEditor is a web-based tool to view, edit, and format JSON.
* It shows data a clear, editable treeview.
*
* Supported browsers: Chrome, Firefox, Safari, Opera, Internet Explorer 8+
*
* @license
* This json editor is open sourced with the intention to use the editor as
* a component in your own application. Not to just copy and monetize the editor
* as it is.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* Copyright (c) 2011-2013 Jos de Jong, http://jsoneditoronline.org
*
* @author Jos de Jong, <wjosdejong@gmail.com>
* @date 2013-01-01
*/
// Internet Explorer 8 and older does not support Array.indexOf,
// so we define it here in that case
// http://soledadpenades.com/2007/05/17/arrayindexof-in-internet-explorer/
if(!Array.prototype.indexOf) {
Array.prototype.indexOf = function(obj){
for(var i = 0; i < this.length; i++){
if(this[i] == obj){
return i;
}
}
return -1;
}
}
// Internet Explorer 8 and older does not support Array.forEach,
// so we define it here in that case
// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach
if (!Array.prototype.forEach) {
Array.prototype.forEach = function(fn, scope) {
for(var i = 0, len = this.length; i < len; ++i) {
fn.call(scope || this, this[i], i, this);
}
}
}
// define variable JSON, needed for correct error handling on IE7 and older
var JSON;
/**
* JSONEditor
* @param {Element} container Container element
* @param {Object} [options] Object with options. available options:
* {String} mode Editor mode. Available values:
* 'editor' (default), 'viewer'.
* {Boolean} search Enable search box.
* True by default
* {Boolean} history Enable history (undo/redo).
* True by default
* {function} change Callback method, triggered
* on change of contents
* {String} name Field name for the root node.
* @param {Object | undefined} json JSON object
*/
var JSONEditor = function (container, options, json) {
// check availability of JSON parser (not available in IE7 and older)
if (!JSON) {
throw new Error ('Your browser does not support JSON. \n\n' +
'Please install the newest version of your browser.\n' +
'(all modern browsers support JSON).');
}
if (!container) {
throw new Error('No container element provided.');
}
this.container = container;
this.dom = {};
this.highlighter = new JSONEditor.Highlighter();
this._setOptions(options);
if (this.options.history && this.editable) {
this.history = new JSONEditor.History(this);
}
this._createFrame();
this._createTable();
this.set(json || {});
};
/**
* Initialize and set default options
* @param {Object} [options] Object with options. available options:
* {String} mode Editor mode. Available values:
* 'editor' (default), 'viewer'.
* {Boolean} search Enable search box.
* True by default.
* {Boolean} history Enable history (undo/redo).
* True by default.
* {function} change Callback method, triggered
* on change of contents.
* {String} name Field name for the root node.
* @private
*/
JSONEditor.prototype._setOptions = function (options) {
this.options = {
search: true,
history: true,
mode: 'editor',
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'];
console.log('WARNING: Option "enableSearch" is deprecated. Use "search" instead.');
}
if (options['enableSearch']) {
// deprecated since version 1.6.0, 2012-11-03
this.options.search = options['enableSearch'];
console.log('WARNING: Option "enableHistory" is deprecated. Use "history" instead.');
}
}
// interpret the options
this.editable = (this.options.mode != 'viewer');
};
// node currently being edited
JSONEditor.focusNode = undefined;
/**
* Set JSON object in editor
* @param {Object | undefined} json JSON data
* @param {String} [name] Optional field name for the root node.
* Can also be set using setName(name).
*/
JSONEditor.prototype.set = function (json, name) {
// adjust field name for root node
if (name) {
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
// replace the root node
var params = {
'field': this.options.name,
'value': json
};
var node = new JSONEditor.Node(this, params);
this._setRoot(node);
// expand
var recurse = false;
this.node.expand(recurse);
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();
}
};
/**
* Get JSON object from editor
* @return {Object | undefined} json
*/
JSONEditor.prototype.get = function () {
// remove focus from currently edited node
if (JSONEditor.focusNode) {
JSONEditor.focusNode.blur();
}
if (this.node) {
return this.node.getValue();
}
else {
return undefined;
}
};
/**
* Set a field name for the root node.
* @param {String | undefined} name
*/
JSONEditor.prototype.setName = function (name) {
this.options.name = name;
if (this.node) {
this.node.updateField(this.options.name);
}
};
/**
* Get the field name for the root node.
* @return {String | undefined} name
*/
JSONEditor.prototype.getName = function () {
return this.options.name;
};
/**
* Remove the root node from the editor
*/
JSONEditor.prototype.clear = function () {
if (this.node) {
this.node.collapse();
this.tbody.removeChild(this.node.getDom());
delete this.node;
}
};
/**
* Set the root node for the json editor
* @param {JSONEditor.Node} node
* @private
*/
JSONEditor.prototype._setRoot = function (node) {
this.clear();
this.node = node;
// append to the dom
this.tbody.appendChild(node.getDom());
};
/**
* Search text in all nodes
* The nodes will be expanded when the text is found one of its childs,
* else it will be collapsed. Searches are case insensitive.
* @param {String} text
* @return {Object[]} results Array with nodes containing the search results
* The result objects contains fields:
* - {JSONEditor.Node} node,
* - {String} elem the dom element name where
* the result is found ('field' or
* 'value')
*/
JSONEditor.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 = [];
}
return results;
};
/**
* Expand all nodes
*/
JSONEditor.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
}
};
/**
* Collapse all nodes
*/
JSONEditor.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
}
};
/**
* The method onChange is called whenever a field or value is changed, created,
* deleted, duplicated, etc.
* @param {String} action Change action. Available values: "editField",
* "editValue", "changeType", "appendNode",
* "removeNode", "duplicateNode", "moveNode", "expand",
* "collapse".
* @param {Object} params Object containing parameters describing the change.
* The parameters in params depend on the action (for
* example for "editValue" the Node, old value, and new
* value are provided). params contains all information
* needed to undo or redo the action.
*/
JSONEditor.prototype.onAction = function (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) {
console.log('Error in change callback: ', err);
}
}
};
/**
* Start autoscrolling when given mouse position is above the top of the
* editor contents, or below the bottom.
* @param {Number} mouseY Absolute mouse position in pixels
*/
JSONEditor.prototype.startAutoScroll = function (mouseY) {
var me = this;
var content = this.content;
var top = JSONEditor.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 (this.autoScrollStep) {
if (!this.autoScrollTimer) {
this.autoScrollTimer = setInterval(function () {
if (me.autoScrollStep) {
content.scrollTop -= me.autoScrollStep;
}
else {
me.stopAutoScroll();
}
}, interval);
}
}
else {
this.stopAutoScroll();
}
};
/**
* Stop auto scrolling. Only applicable when scrolling
*/
JSONEditor.prototype.stopAutoScroll = function () {
if (this.autoScrollTimer) {
clearTimeout(this.autoScrollTimer);
delete this.autoScrollTimer;
}
if (this.autoScrollStep) {
delete this.autoScrollStep;
}
};
/**
* Set the focus to the JSONEditor. A hidden input field will be created
* which captures key events
*/
// TODO: use the focus method?
JSONEditor.prototype.focus = function () {
/*
if (!this.dom.focus) {
this.dom.focus = document.createElement('input');
this.dom.focus.className = 'jsoneditor-hidden-focus';
var editor = this;
this.dom.focus.onblur = function () {
// remove itself
if (editor.dom.focus) {
var focus = editor.dom.focus;
delete editor.dom.focus;
editor.frame.removeChild(focus);
}
};
// attach the hidden input box to the DOM
if (this.frame.firstChild) {
this.frame.insertBefore(this.dom.focus, this.frame.firstChild);
}
else {
this.frame.appendChild(this.dom.focus);
}
}
this.dom.focus.focus();
*/
};
/**
* Adjust the scroll position such that given top position is shown at 1/4
* of the window height.
* @param {Number} top
*/
JSONEditor.prototype.scrollTo = function (top) {
var content = this.content;
if (content) {
// cancel any running animation
var editor = this;
if (editor.animateTimeout) {
clearTimeout(editor.animateTimeout);
delete editor.animateTimeout;
}
// 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.animateTimeout = setTimeout(animate, 50);
}
};
animate();
}
};
/**
* Test if an element is a child of a parent element.
* @param {Element} child
* @param {Element} parent
* @param {boolean} [includeParent] if true (default), the method will return
* true too when the child is the parent.
* @return {boolean} isChild
*/
JSONEditor.isChildOf = function (child, parent, includeParent) {
var e = child;
if (includeParent != false && e == parent) {
return true;
}
e = e.parentNode;
while (e) {
if (e == parent) {
return true;
}
e = e.parentNode;
}
return false;
};
/**
* Create main frame
* @private
*/
JSONEditor.prototype._createFrame = function () {
// create the frame
this.container.innerHTML = '';
this.frame = document.createElement('div');
this.frame.className = 'jsoneditor-frame';
this.container.appendChild(this.frame);
// create one global event listener to handle all events from all nodes
var editor = this;
// TODO: move this onEvent to JSONEditor.prototype.onEvent
var onEvent = function (event) {
event = event || window.event;
var target = event.target || event.srcElement;
if (event.type == 'keydown') {
editor.onKeyDown(event);
}
var node = JSONEditor.getNodeFromTarget(target);
if (node) {
node.onEvent(event);
}
};
this.frame.onclick = function (event) {
onEvent(event);
// prevent default submit action when JSONEditor is located inside a form
JSONEditor.util.preventDefault(event);
};
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
JSONEditor.util.addEventListener(this.frame, 'focus', onEvent, true);
JSONEditor.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 = 'jsoneditor-menu';
this.frame.appendChild(this.menu);
// create expand all button
var expandAll = document.createElement('button');
expandAll.className = 'jsoneditor-menu jsoneditor-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 = 'jsoneditor-menu jsoneditor-collapse-all';
collapseAll.onclick = function () {
editor.collapseAll();
};
this.menu.appendChild(collapseAll);
// create undo/redo buttons
if (this.history) {
// create separator
var separator = document.createElement('span');
separator.innerHTML = '&nbsp;';
this.menu.appendChild(separator);
// create undo button
var undo = document.createElement('button');
undo.className = 'jsoneditor-menu jsoneditor-undo';
undo.title = 'Undo last action';
undo.onclick = function () {
editor._onUndo();
};
this.menu.appendChild(undo);
this.dom.undo = undo;
// create redo button
var redo = document.createElement('button');
redo.className = 'jsoneditor-menu jsoneditor-redo';
redo.title = 'Redo';
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 search box
if (this.options.search) {
this.searchBox = new JSONEditor.SearchBox(this, this.menu);
}
};
/**
* Perform an undo action
* @private
*/
JSONEditor.prototype._onUndo = function () {
if (this.history) {
// undo last action
this.history.undo();
// trigger change callback
if (this.options.change) {
this.options.change();
}
}
};
/**
* Perform a redo action
* @private
*/
JSONEditor.prototype._onRedo = function () {
if (this.history) {
// redo last action
editor.history.redo();
// trigger change callback
if (editor.options.change) {
editor.options.change();
}
}
};
/**
* Event handler for keydown. Handles shortcut keys
* @param {Event} event
*/
JSONEditor.prototype.onKeyDown = function (event) {
var keynum = event.which || event.keyCode;
var ctrlKey = event.ctrlKey;
var shiftKey = event.shiftKey;
var handled = false;
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
if (!shiftKey) {
// select next search result (F3 or Ctrl+G)
this.searchBox.next();
}
else {
// select previous search result (Shift+F3 or Ctrl+Shift+G)
this.searchBox.previous();
}
// set selection to the current
this.searchBox.focusActiveResult();
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) {
JSONEditor.util.preventDefault(event);
JSONEditor.util.stopPropagation(event);
}
};
/**
* Create main table
* @private
*/
JSONEditor.prototype._createTable = function () {
var contentOuter = document.createElement('div');
contentOuter.className = 'jsoneditor-content-outer';
this.contentOuter = contentOuter;
this.content = document.createElement('div');
this.content.className = 'jsoneditor-content';
contentOuter.appendChild(this.content);
this.table = document.createElement('table');
this.table.className = 'jsoneditor-table';
this.content.appendChild(this.table);
// IE8 does not handle overflow='auto' correctly.
// Therefore, set overflow to 'scroll'
var ieVersion = JSONEditor.util.getInternetExplorerVersion();
if (ieVersion == 8) {
this.content.style.overflow = 'scroll';
}
// 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');
col = document.createElement('col');
col.width = "24px";
this.colgroupContent.appendChild(col);
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.frame.appendChild(contentOuter);
};
/**
* Find the node from an event target
* @param {Node} target
* @return {JSONEditor.Node | undefined} node or undefined when not found
*/
JSONEditor.getNodeFromTarget = function (target) {
while (target) {
if (target.node) {
return target.node;
}
target = target.parentNode;
}
return undefined;
};
/**
* Parse JSON using the parser built-in in the browser.
* On exception, the jsonString is validated and a detailed error is thrown.
* @param {String} jsonString
*/
JSONEditor.parse = function (jsonString) {
try {
return JSON.parse(jsonString);
}
catch (err) {
// get a detailed error message using validate
var message = JSONEditor.validate(jsonString) || err;
throw new Error(message);
}
};
/**
* Validate a string containing a JSON object
* This method uses JSONLint to validate the String. If JSONLint is not
* available, the built-in JSON parser of the browser is used.
* @param {String} jsonString String with an (invalid) JSON object
* @return {String | undefined} Returns undefined when the string is valid JSON,
* returns a string with an error message when
* the data is invalid
*/
JSONEditor.validate = function (jsonString) {
var message = undefined;
try {
if (window.jsonlint) {
window.jsonlint.parse(jsonString);
}
else {
JSON.parse(jsonString);
}
}
catch (err) {
message = '<pre class="error">' + err.toString() + '</pre>';
if (window.jsonlint) {
message +=
'<a class="error" href="http://zaach.github.com/jsonlint/" target="_blank">' +
'validated by jsonlint' +
'</a>';
}
}
return message;
};

View File

@ -0,0 +1,175 @@
/**
* @license
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* Copyright (c) 2011-2013 Jos de Jong, http://jsoneditoronline.org
*
* @author Jos de Jong, <wjosdejong@gmail.com>
*/
/**
* Create a JSONFormatter and attach it to given container
* @constructor JSONFormatter
* @param {Element} container
* @param {Object} [options] Object with options. available options:
* {Number} indentation Number of indentation
* spaces. 4 by default.
* {function} change Callback method
* triggered on change
* @param {JSON | String} [json] initial contents of the formatter
*/
JSONFormatter = function (container, options, json) {
// check availability of JSON parser (not available in IE7 and older)
if (!JSON) {
throw new Error('Your browser does not support JSON. \n\n' +
'Please install the newest version of your browser.\n' +
'(all modern browsers support JSON).');
}
this.container = container;
this.indentation = 4; // number of spaces
this.width = container.clientWidth;
this.height = container.clientHeight;
this.frame = document.createElement('div');
this.frame.className = "jsoneditor-frame";
this.frame.onclick = function (event) {
// prevent default submit action when JSONFormatter is located inside a form
JSONEditor.util.preventDefault(event);
};
// create menu
this.menu = document.createElement('div');
this.menu.className = 'jsoneditor-menu';
this.frame.appendChild(this.menu);
// create format button
var buttonFormat = document.createElement('button');
//buttonFormat.innerHTML = 'Format';
buttonFormat.className = 'jsoneditor-menu jsoneditor-format';
buttonFormat.title = 'Format JSON data, with proper indentation and line feeds';
//buttonFormat.className = 'jsoneditor-button';
this.menu.appendChild(buttonFormat);
// create compact button
var buttonCompact = document.createElement('button');
//buttonCompact.innerHTML = 'Compact';
buttonCompact.className = 'jsoneditor-menu jsoneditor-compact';
buttonCompact.title = 'Compact JSON data, remove all whitespaces';
//buttonCompact.className = 'jsoneditor-button';
this.menu.appendChild(buttonCompact);
this.content = document.createElement('div');
this.content.className = 'jsonformatter-content';
this.frame.appendChild(this.content);
this.textarea = document.createElement('textarea');
this.textarea.className = "jsonformatter-textarea";
this.textarea.spellcheck = false;
this.content.appendChild(this.textarea);
var textarea = this.textarea;
// read the options
if (options) {
if (options.change) {
// register on change event
if (this.textarea.oninput === null) {
this.textarea.oninput = function () {
options.change();
}
}
else {
// oninput is undefined. For IE8-
this.textarea.onchange = function () {
options.change();
}
}
}
if (options.indentation) {
this.indentation = Number(options.indentation);
}
}
var me = this;
buttonFormat.onclick = function () {
try {
var json = JSONEditor.parse(textarea.value);
textarea.value = JSON.stringify(json, null, me.indentation);
}
catch (err) {
me.onError(err);
}
};
buttonCompact.onclick = function () {
try {
var json = JSONEditor.parse(textarea.value);
textarea.value = JSON.stringify(json);
}
catch (err) {
me.onError(err);
}
};
this.container.appendChild(this.frame);
// load initial json object or string
if (typeof(json) == 'string') {
this.setText(json);
}
else {
this.set(json);
}
};
/**
* This method is executed on error.
* It can be overwritten for each instance of the JSONFormatter
* @param {String} err
*/
JSONFormatter.prototype.onError = function(err) {
// action should be implemented for the instance
};
/**
* Set json data in the formatter
* @param {Object} json
*/
JSONFormatter.prototype.set = function(json) {
this.textarea.value = JSON.stringify(json, null, this.indentation);
};
/**
* Get json data from the formatter
* @return {Object} json
*/
JSONFormatter.prototype.get = function() {
return JSONEditor.parse(this.textarea.value);
};
/**
* Get the text contents of the JSONFormatter
* @return {String} text
*/
JSONFormatter.prototype.getText = function() {
return this.textarea.value;
};
/**
* Set the text contents of the JSONFormatter
* @param {String} text
*/
JSONFormatter.prototype.setText = function(text) {
this.textarea.value = text;
};

2400
jsoneditor/js/node.js Normal file

File diff suppressed because it is too large Load Diff

309
jsoneditor/js/searchbox.js Normal file
View File

@ -0,0 +1,309 @@
/**
* @license
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* Copyright (c) 2011-2013 Jos de Jong, http://jsoneditoronline.org
*
* @author Jos de Jong, <wjosdejong@gmail.com>
*/
/**
* @constructor JSONEditor.SearchBox
* Create a search box in given HTML container
* @param {JSONEditor} editor The JSON Editor to attach to
* @param {Element} container HTML container element of where to create the
* search box
*/
JSONEditor.SearchBox = function(editor, container) {
var searchBox = this;
this.editor = editor;
this.timeout = undefined;
this.delay = 200; // ms
this.lastText = undefined;
this.dom = {};
this.dom.container = container;
var table = document.createElement('table');
this.dom.table = table;
table.className = 'jsoneditor-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');
td.className = 'jsoneditor-search';
tr.appendChild(td);
var results = document.createElement('div');
this.dom.results = results;
results.className = 'jsoneditor-search-results';
td.appendChild(results);
td = document.createElement('td');
td.className = 'jsoneditor-search';
tr.appendChild(td);
var divInput = document.createElement('div');
this.dom.input = divInput;
divInput.className = 'jsoneditor-search';
divInput.title = 'Search fields and values';
td.appendChild(divInput);
// table to contain the text input and search button
var tableInput = document.createElement('table');
tableInput.className = 'jsoneditor-search-input';
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 = 'jsoneditor-search-refresh';
td = document.createElement('td');
td.appendChild(refreshSearch);
tr.appendChild(td);
var search = document.createElement('input');
this.dom.search = search;
search.className = 'jsoneditor-search';
search.oninput = function (event) {
searchBox.onDelayedSearch(event);
};
search.onchange = function (event) { // For IE 8
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);
var searchNext = document.createElement('button');
searchNext.title = 'Next result (Enter)';
searchNext.className = 'jsoneditor-search-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 = 'jsoneditor-search-previous';
searchPrevious.onclick = function () {
searchBox.previous();
};
td = document.createElement('td');
td.appendChild(searchPrevious);
tr.appendChild(td);
};
/**
* Go to the next search result
*/
JSONEditor.SearchBox.prototype.next = function() {
if (this.results != undefined) {
var index = (this.resultIndex != undefined) ? this.resultIndex + 1 : 0;
if (index > this.results.length - 1) {
index = 0;
}
this.setActiveResult(index);
}
};
/**
* Go to the prevous search result
*/
JSONEditor.SearchBox.prototype.previous = function() {
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);
}
};
/**
* Set new value for the current active result
* @param {Number} index
*/
JSONEditor.SearchBox.prototype.setActiveResult = function(index) {
// 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;
}
else {
node.searchValueActive = true;
}
this.activeResult = this.results[this.resultIndex];
node.updateDom();
node.scrollTo();
};
/**
* Set the focus to the currently active result. If there is no currently
* active result, the next search result will get focus
*/
JSONEditor.SearchBox.prototype.focusActiveResult = function() {
if (!this.activeResult) {
this.next();
}
if (this.activeResult) {
this.activeResult.node.focus(this.activeResult.elem);
}
};
/**
* Cancel any running onDelayedSearch.
*/
JSONEditor.SearchBox.prototype.clearDelay = function() {
if (this.timeout != undefined) {
clearTimeout(this.timeout);
delete this.timeout;
}
};
/**
* Start a timer to execute a search after a short delay.
* Used for reducing the number of searches while typing.
* @param {Event} event
*/
JSONEditor.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);
};
/**
* Handle onSearch event
* @param {Event} event
* @param {boolean} [forceSearch] If true, search will be executed again even
* when the search text is not changed.
* Default is false.
*/
JSONEditor.SearchBox.prototype.onSearch = function (event, forceSearch) {
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);
// display search results
if (text != undefined) {
var resultCount = this.results.length;
switch (resultCount) {
case 0: this.dom.results.innerHTML = 'no&nbsp;results'; break;
case 1: this.dom.results.innerHTML = '1&nbsp;result'; break;
default: this.dom.results.innerHTML = resultCount + '&nbsp;results'; break;
}
}
else {
this.dom.results.innerHTML = '';
}
}
};
/**
* Handle onKeyDown event in the input box
* @param {Event} event
*/
JSONEditor.SearchBox.prototype.onKeyDown = function (event) {
event = event || window.event;
var keynum = event.which || event.keyCode;
if (keynum == 27) { // ESC
this.dom.search.value = ''; // clear search
this.onSearch(event);
JSONEditor.util.preventDefault(event);
JSONEditor.util.stopPropagation(event);
}
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();
}
JSONEditor.util.preventDefault(event);
JSONEditor.util.stopPropagation(event);
}
};
/**
* Handle onKeyUp event in the input box
* @param {Event} event
*/
JSONEditor.SearchBox.prototype.onKeyUp = function (event) {
event = event || window.event;
var keynum = event.which || event.keyCode;
if (keynum != 27 && keynum != 13) { // !show and !Enter
this.onDelayedSearch(event); // For IE 8
}
};

380
jsoneditor/js/util.js Normal file
View File

@ -0,0 +1,380 @@
/**
* @license
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* Copyright (c) 2011-2013 Jos de Jong, http://jsoneditoronline.org
*
* @author Jos de Jong, <wjosdejong@gmail.com>
*/
// create namespace for util methods
JSONEditor.util = {};
/**
* Retrieve the absolute left value of a DOM element
* @param {Element} elem A dom element, for example a div
* @return {Number} left The absolute left position of this element
* in the browser page.
*/
JSONEditor.util.getAbsoluteLeft = function (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;
};
/**
* Retrieve the absolute top value of a DOM element
* @param {Element} elem A dom element, for example a div
* @return {Number} top The absolute top position of this element
* in the browser page.
*/
JSONEditor.util.getAbsoluteTop = function (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;
};
/**
* Get the absolute, vertical mouse position from an event.
* @param {Event} event
* @return {Number} mouseY
*/
JSONEditor.util.getMouseY = function (event) {
var mouseY;
if ('pageY' in event) {
mouseY = event.pageY;
}
else {
// for IE8 and older
mouseY = (event.clientY + document.documentElement.scrollTop);
}
return mouseY;
};
/**
* Get the absolute, horizontal mouse position from an event.
* @param {Event} event
* @return {Number} mouseX
*/
JSONEditor.util.getMouseX = function (event) {
var mouseX;
if ('pageX' in event) {
mouseX = event.pageX;
}
else {
// for IE8 and older
mouseX = (event.clientX + document.documentElement.scrollLeft);
}
return mouseX;
};
/**
* Get the window height
* @return {Number} windowHeight
*/
JSONEditor.util.getWindowHeight = function () {
if ('innerHeight' in window) {
return window.innerHeight;
}
else {
// for IE8 and older
return Math.max(document.body.clientHeight,
document.documentElement.clientHeight);
}
};
/**
* add a className to the given elements style
* @param {Element} elem
* @param {String} className
*/
JSONEditor.util.addClassName = function(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(' ');
}
};
/**
* add a className to the given elements style
* @param {Element} elem
* @param {String} className
*/
JSONEditor.util.removeClassName = function(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(' ');
}
};
/**
* Strip the formatting from the contents of a div
* the formatting from the div itself is not stripped, only from its childs.
* @param {Element} divElement
*/
JSONEditor.util.stripFormatting = function (divElement) {
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
JSONEditor.util.stripFormatting(child);
}
};
/**
* Set focus to the end of an editable div
* code from Nico Burns
* http://stackoverflow.com/users/140293/nico-burns
* http://stackoverflow.com/questions/1125292/how-to-move-cursor-to-end-of-contenteditable-entity
* @param {Element} contentEditableElement
*/
JSONEditor.util.setEndOfContentEditable = function (contentEditableElement) {
var range, selection;
if(document.createRange) {//Firefox, Chrome, Opera, Safari, IE 9+
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
}
else if(document.selection) {//IE 8 and lower
range = document.body.createTextRange();//Create a range (a range is a like the selection but invisible)
range.moveToElementText(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
range.select();//Select the range (make it the visible selection
}
};
/**
* Get the inner text of an HTML element (for example a div element)
* @param {Element} element
* @param {Object} [buffer]
* @return {String} innerText
*/
JSONEditor.util.getInnerText = function (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;
}
};
}
// text node
if (element.nodeValue) {
return buffer.flush() + element.nodeValue;
}
// 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];
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 += JSONEditor.util.getInnerText(child, buffer);
buffer.set('\n');
}
else if (child.nodeName == 'BR') {
innerText += buffer.flush();
buffer.set('\n');
}
else {
innerText += JSONEditor.util.getInnerText(child, buffer);
}
}
return innerText;
}
else {
if (element.nodeName == 'P' && JSONEditor.util.getInternetExplorerVersion() != -1) {
// On Internet Explorer, a <p> with hasChildNodes()==false is
// rendered with a new line. Note that a <p> with
// hasChildNodes()==true is rendered without a new line
// Other browsers always ensure there is a <br> inside the <p>,
// and if not, the <p> does not render a new line
return buffer.flush();
}
}
// br or unknown
return '';
};
/**
* Returns the version of Internet Explorer or a -1
* (indicating the use of another browser).
* Source: http://msdn.microsoft.com/en-us/library/ms537509(v=vs.85).aspx
* @return {Number} Internet Explorer version, or -1 in case of an other browser
*/
JSONEditor.util._ieVersion = undefined;
JSONEditor.util.getInternetExplorerVersion = function() {
if (JSONEditor.util._ieVersion == undefined) {
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 );
}
}
JSONEditor.util._ieVersion = rv;
}
return JSONEditor.util._ieVersion;
};
/**
* Add and event listener. Works for all browsers
* @param {Element} element An html element
* @param {string} action The action, for example "click",
* without the prefix "on"
* @param {function} listener The callback function to be executed
* @param {boolean} [useCapture] false by default
* @return {function} the created event listener
*/
JSONEditor.util.addEventListener = function (element, action, listener, useCapture) {
if (element.addEventListener) {
if (useCapture === undefined)
useCapture = false;
if (action === "mousewheel" && navigator.userAgent.indexOf("Firefox") >= 0) {
action = "DOMMouseScroll"; // For Firefox
}
element.addEventListener(action, listener, useCapture);
return listener;
} else {
// IE browsers
var f = function () {
return listener.call(element, window.event);
};
element.attachEvent("on" + action, f);
return f;
}
};
/**
* Remove an event listener from an element
* @param {Element} element An html dom element
* @param {string} action The name of the event, for example "mousedown"
* @param {function} listener The listener function
* @param {boolean} [useCapture] false by default
*/
JSONEditor.util.removeEventListener = function(element, action, listener, useCapture) {
if (element.removeEventListener) {
// non-IE browsers
if (useCapture === undefined)
useCapture = false;
if (action === "mousewheel" && navigator.userAgent.indexOf("Firefox") >= 0) {
action = "DOMMouseScroll"; // For Firefox
}
element.removeEventListener(action, listener, useCapture);
} else {
// IE browsers
element.detachEvent("on" + action, listener);
}
};
/**
* Stop event propagation
* @param {Event} event
*/
JSONEditor.util.stopPropagation = function (event) {
if (!event) {
event = window.event;
}
if (event.stopPropagation) {
event.stopPropagation(); // non-IE browsers
}
else {
event.cancelBubble = true; // IE browsers
}
};
/**
* Cancels the event if it is cancelable, without stopping further propagation of the event.
* @param {Event} event
*/
JSONEditor.util.preventDefault = function (event) {
if (!event) {
event = window.event;
}
if (event.preventDefault) {
event.preventDefault(); // non-IE browsers
}
else {
event.returnValue = false; // IE browsers
}
};

View File

@ -1,585 +0,0 @@
.jsoneditor-field, .jsoneditor-value, .jsoneditor-field-readonly, .jsoneditor-readonly {
border: 1px solid transparent;
min-height: 16px;
min-width: 24px;
padding: 2px;
margin: 1px;
outline: none;
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;
}
.jsoneditor-value {
word-break: break-word;
}
.jsoneditor-empty {
background-color: #E5E5E5;
border-radius: 2px;
}
.jsoneditor-separator {
padding: 3px 0;
vertical-align: top;
}
.jsoneditor-value:focus, .jsoneditor-field:focus,
.jsoneditor-value:hover, .jsoneditor-field:hover,
.jsoneditor-search-highlight {
background-color: #FFFFAB;
border: 1px solid yellow;
border-radius: 2px;
}
.jsoneditor-search-highlight-active,
.jsoneditor-search-highlight-active:focus,
.jsoneditor-search-highlight-active:hover {
background-color: #ffee00;
border: 1px solid #ffc700;
border-radius: 2px;
}
.jsoneditor-field-readonly:hover {
border: 1px solid white;
}
.jsoneditor-readonly {
color: gray;
}
button.jsoneditor-collapsed, button.jsoneditor-expanded,
button.jsoneditor-invisible, button.jsoneditor-dragarea,
button.jsoneditor-contextmenu, button.jsoneditor-append {
width: 24px;
height: 24px;
padding: 0;
margin: 0;
border: none;
cursor: pointer;
background-color: transparent;
background-image: url('img/jsoneditor-icons.png');
}
/* TODO: no global settings
button:disabled {
color: #808080;
}
*/
td.jsoneditor-nochilds {
color: gray;
}
button.jsoneditor-collapsed {
background-position: 0 -48px;
}
button.jsoneditor-expanded {
background-position: 0 -72px;
}
.jsoneditor-contextmenu {
position: relative;
background-position: -48px -72px;
}
.jsoneditor-contextmenu:hover, .jsoneditor-contextmenu:focus {
background-position: -48px -48px;
}
button.jsoneditor-invisible {
visibility: hidden;
background: none;
}
button.jsoneditor-collapsed, button.jsoneditor-expanded,
button.jsoneditor-invisible {
float: left;
}
div.jsoneditor-frame {
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;
}
table.jsoneditor-table {
border-collapse: collapse;
border-spacing: 0;
width: 100%;
margin: 0;
}
div.jsoneditor-content-outer, div.jsonformatter-content {
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;
overflow: hidden;
}
div.jsoneditor-content {
width: 100%;
height: 100%;
position: relative;
overflow: auto;
}
textarea.jsonformatter-textarea {
width: 100%;
height: 100%;
margin: 0;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
border: none;
background-color: white;
resize: none;
}
tr.jsoneditor-tr-highlight {
background-color: #FFFFAB;
}
button.jsoneditor-dragarea {
width: 24px;
height: 24px;
/*
margin: 3px 0;
background: url('img/dots_gray.gif') top center;
background-repeat: repeat-y;
*/
background: url('img/jsoneditor-icons.png') -72px -72px;
display: block;
cursor: move;
}
button.jsoneditor-dragarea:hover, .jsoneditor-dragarea:focus {
background-position: -72px -48px;
}
/* ___________________________ COMPONENT TOP MENU ___________________________ */
div.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;
color: #1A1A1A;
background-color: #D5DDF6;
border-bottom: 1px solid #97B0F8;
}
button.jsoneditor-menu {
width: 26px;
height: 26px;
margin: 2px;
padding: 2px;
border-radius: 2px;
border: 1px solid #aec0f8;
background: #e3eaf6 url('img/jsoneditor-icons.png');
}
button.jsoneditor-menu:hover {
background-color: #f0f2f5;
}
button.jsoneditor-menu:active {
background-color: #ffffff;
}
button.jsoneditor-menu:disabled {
background-color: #e3eaf6;
}
button.jsoneditor-collapse-all {
background-position: 0 -96px;
}
button.jsoneditor-expand-all {
background-position: 0 -120px;
}
button.jsoneditor-undo {
background-position: -24px -96px;
}
button.jsoneditor-undo:disabled {
background-position: -24px -120px;
}
button.jsoneditor-redo {
background-position: -48px -96px;
}
button.jsoneditor-redo:disabled {
background-position: -48px -120px;
}
/* TODO: css for button:disabled is not supported by IE8 */
button.jsoneditor-compact {
background-position: -72px -96px;
}
button.jsoneditor-format {
background-position: -72px -120px;
}
/* TODO: do not change global tr, th, td */
tr, th, td {
padding: 0;
margin: 0;
}
td.jsoneditor-td {
vertical-align: top;
}
td.jsoneditor-td {
padding: 0;
}
td.jsoneditor-td-edit {
background-color: #F5F5F5;
padding: 0;
}
td.jsoneditor-td-tree {
vertical-align: top;
}
td.jsoneditor-droparea {
height: 24px;
border-top: 1px dashed gray;
border-bottom: 1px dashed gray;
background-color: #FFFF80;
}
.jsoneditor-field, .jsoneditor-value, .jsoneditor-td, .jsoneditor-th,
.jsoneditor-type, .jsonformatter-textarea {
font-family: droid sans mono, monospace, courier new, courier, sans-serif;
font-size: 10pt;
color: #1A1A1A;
}
div.jsoneditor-contextmenu button,
input.jsoneditor-search, div.jsoneditor-search-results {
font-family: arial, sans-serif;
font-size: 10pt;
color: #1A1A1A;
}
.jsoneditor-hidden-focus {
position: absolute;
left: -1000px;
top: -1000px;
border: none;
outline: none;
}
/* _______________________________ SEARCH BAR _______________________________ */
table.jsoneditor-search {
position: absolute;
right: 2px;
top: 2px;
}
table.jsoneditor-search-input {
border-collapse: collapse;
}
div.jsoneditor-search {
border: 1px solid #97B0F8;
background-color: white;
padding: 0 2px;
margin: 0;
}
input.jsoneditor-search {
width: 120px;
border: none;
outline: none;
margin: 1px;
}
div.jsoneditor-search-results {
color: #4d4d4d;
padding-right: 5px;
}
button.jsoneditor-search-refresh, button.jsoneditor-search-next,
button.jsoneditor-search-previous {
width: 16px;
height: 24px;
padding: 0;
margin: 0;
border: none;
background: url('img/jsoneditor-icons.png');
vertical-align: top;
}
button.jsoneditor-search-refresh {
width: 18px;
background-position: -99px -73px;
}
button.jsoneditor-search-next {
cursor: pointer;
background-position: -124px -73px;
}
button.jsoneditor-search-next:hover {
background-position: -124px -49px;
}
button.jsoneditor-search-previous {
cursor: pointer;
background-position: -148px -73px;
margin-right: 2px;
}
button.jsoneditor-search-previous:hover {
background-position: -148px -49px;
}
/* ______________________________ CONTEXT MENU ______________________________ */
div.jsoneditor-contextmenu {
position: absolute;
}
div.jsoneditor-contextmenu ul {
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);
z-index: 1;
list-style: none;
margin: 0;
padding: 0;
}
div.jsoneditor-contextmenu ul li button {
padding: 0;
margin: 0;
width: 124px;
height: 24px;
border: none;
cursor: pointer;
color: #4d4d4d;
background: transparent;
line-height: 24px;
text-align: left;
}
/* Fix button padding in firefox */
div.jsoneditor-contextmenu ul li button::-moz-focus-inner {
padding: 0;
border: 0;
}
div.jsoneditor-contextmenu ul li button:hover {
color: #1a1a1a;
background-color: #f5f5f5;
}
div.jsoneditor-contextmenu ul li button.default {
width: 92px;
}
div.jsoneditor-contextmenu ul li button.expand {
float: right;
width: 32px;
height: 24px;
border-left: 1px solid #e5e5e5;
}
div.jsoneditor-contextmenu div.icon {
float: left;
width: 24px;
height: 24px;
border: none;
padding: 0;
margin: 0;
background-image: url('img/jsoneditor-icons.png');
}
div.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;
}
div.jsoneditor-contextmenu ul li button:hover div.expand,
div.jsoneditor-contextmenu ul li.selected div.expand,
div.jsoneditor-contextmenu ul li button.expand:hover div.expand {
opacity: 1;
}
div.jsoneditor-contextmenu .separator {
height: 0;
border-top: 1px solid #e5e5e5;
padding-top: 5px;
margin-top: 5px;
}
button.jsoneditor-remove > .icon {
background-position: -24px -24px;
}
button.jsoneditor-remove:hover > .icon {
background-position: -24px 0;
}
button.jsoneditor-append > .icon {
background-position: 0 -24px;
}
button.jsoneditor-append:hover > .icon {
background-position: 0 0;
}
button.jsoneditor-insert > .icon {
background-position: 0 -24px;
}
button.jsoneditor-insert:hover > .icon {
background-position: 0 0;
}
button.jsoneditor-insert-above > .icon {
background-position: -24px -24px;
}
button.jsoneditor-insert-above:hover > .icon {
background-position: -24px 0;
}
button.jsoneditor-insert-below > .icon {
background-position: -48px -24px;
}
button.jsoneditor-insert-below:hover > .icon {
background-position: -48px 0;
}
button.jsoneditor-duplicate > .icon {
background-position: -48px -24px;
}
button.jsoneditor-duplicate:hover > .icon {
background-position: -48px 0;
}
button.jsoneditor-sort-asc > .icon {
background-position: -168px -24px;
}
button.jsoneditor-sort-asc:hover > .icon {
background-position: -168px 0;
}
button.jsoneditor-sort-desc > .icon {
background-position: -192px -24px;
}
button.jsoneditor-sort-desc:hover > .icon {
background-position: -192px 0;
}
/* ____________________________ CONTEXT SUB MENU ____________________________ */
div.jsoneditor-contextmenu ul li ul li .selected {
background-color: #D5DDF6;
}
div.jsoneditor-contextmenu ul li {
overflow: hidden;
}
div.jsoneditor-contextmenu ul li ul {
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;
/* 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;
}
div.jsoneditor-contextmenu ul li.selected ul {
}
div.jsoneditor-contextmenu ul li ul li button {
padding-left: 24px;
}
div.jsoneditor-contextmenu ul li ul li button:hover {
background-color: #f5f5f5;
}
button.jsoneditor-type-string > .icon {
background-position: -144px -24px;
}
button.jsoneditor-type-string:hover > .icon,
button.jsoneditor-type-string.selected > .icon{
background-position: -144px 0;
}
button.jsoneditor-type-auto > .icon {
background-position: -120px -24px;
}
button.jsoneditor-type-auto:hover > .icon,
button.jsoneditor-type-auto.selected > .icon {
background-position: -120px 0;
}
button.jsoneditor-type-object > .icon {
background-position: -72px -24px;
}
button.jsoneditor-type-object:hover > .icon,
button.jsoneditor-type-object.selected > .icon{
background-position: -72px 0;
}
button.jsoneditor-type-array > .icon {
background-position: -96px -24px;
}
button.jsoneditor-type-array:hover > .icon,
button.jsoneditor-type-array.selected > .icon{
background-position: -96px 0;
}
/* TODO: drastically cleanup the css, improve/simplify naming and cascading */

File diff suppressed because it is too large Load Diff

View File

@ -10,8 +10,8 @@
<link rel="shortcut icon" href="../app/web/favicon.ico">
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js"></script>
<script type="text/javascript" src="../jsoneditor/jsoneditor.js"></script>
<link rel="stylesheet" type="text/css" href="../jsoneditor/jsoneditor.css">
<script type="text/javascript" src="../jsoneditor/js/jsoneditor.js"></script>
<link rel="stylesheet" type="text/css" href="../jsoneditor/css/jsoneditor.css">
<style type="text/css">
body, html {