PageRenderTime 44ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/Solutions/Wolfpack.Core.WebUI/Scripts/FlexiJsonEditor/jquery.jsoneditor.js

#
JavaScript | 218 lines | 151 code | 46 blank | 21 comment | 46 complexity | 3e6d6a6af14ac395e862b4bf8c4549ed MD5 | raw file
Possible License(s): Apache-2.0, BSD-2-Clause, BSD-3-Clause, GPL-2.0, MIT
  1. // Simple yet flexible JSON editor plugin.
  2. // Turns any element into a stylable interactive JSON editor.
  3. // Copyright (c) 2011 David Durman
  4. // Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php).
  5. // Dependencies:
  6. // * jQuery
  7. // * JSON (use json2 library for browsers that do not support JSON natively)
  8. // Example:
  9. // var myjson = { any: { json: { value: 1 } } };
  10. // var opt = { change: function() { /* called on every change */ } };
  11. // /* opt.propertyElement = '<textarea>'; */ // element of the property field, <input> is default
  12. // /* opt.valueElement = '<textarea>'; */ // element of the value field, <input> is default
  13. // $('#mydiv').jsonEditor(myjson, opt);
  14. (function( $ ) {
  15. $.fn.jsonEditor = function(json, options) {
  16. options = options || {};
  17. var K = function() {},
  18. onchange = options.change || K;
  19. return this.each(function() {
  20. JSONEditor($(this), json, onchange, options.propertyElement, options.valueElement);
  21. });
  22. };
  23. function JSONEditor(target, json, onchange, propertyElement, valueElement) {
  24. var opt = {
  25. target: target,
  26. onchange: onchange,
  27. original: json,
  28. propertyElement: propertyElement,
  29. valueElement: valueElement
  30. };
  31. construct(opt, json, opt.target);
  32. $('.property, .value', opt.target).on('blur focus', function() {
  33. $(this).toggleClass('editing');
  34. });
  35. }
  36. function isObject(o) { return Object.prototype.toString.call(o) == '[object Object]'; }
  37. function isArray(o) { return Object.prototype.toString.call(o) == '[object Array]'; }
  38. function isBoolean(o) { return Object.prototype.toString.call(o) == '[object Boolean]'; }
  39. function isNumber(o) { return Object.prototype.toString.call(o) == '[object Number]'; }
  40. function isString(o) { return Object.prototype.toString.call(o) == '[object String]'; }
  41. var types = 'object array boolean number string null';
  42. // Feeds object `o` with `value` at `path`. If value argument is omitted,
  43. // object at `path` will be deleted from `o`.
  44. // Example:
  45. // feed({}, 'foo.bar.baz', 10); // returns { foo: { bar: { baz: 10 } } }
  46. function feed(o, path, value) {
  47. var del = arguments.length == 2;
  48. if (path.indexOf('.') > -1) {
  49. var diver = o,
  50. i = 0,
  51. parts = path.split('.');
  52. for (var len = parts.length; i < len - 1; i++) {
  53. diver = diver[parts[i]];
  54. }
  55. if (del) delete diver[parts[len - 1]];
  56. else diver[parts[len - 1]] = value;
  57. } else {
  58. if (del) delete o[path];
  59. else o[path] = value;
  60. }
  61. return o;
  62. }
  63. // Get a property by path from object o if it exists. If not, return defaultValue.
  64. // Example:
  65. // def({ foo: { bar: 5 } }, 'foo.bar', 100); // returns 5
  66. // def({ foo: { bar: 5 } }, 'foo.baz', 100); // returns 100
  67. function def(o, path, defaultValue) {
  68. path = path.split('.');
  69. var i = 0;
  70. while (i < path.length) {
  71. if ((o = o[path[i++]]) == undefined) return defaultValue;
  72. }
  73. return o;
  74. }
  75. function error(reason) { if (window.console) { console.error(reason); } }
  76. function parse(str) {
  77. var res;
  78. try { res = JSON.parse(str); }
  79. catch (e) { res = null; error('JSON parse failed.'); }
  80. return res;
  81. }
  82. function stringify(obj) {
  83. var res;
  84. try { res = JSON.stringify(obj); }
  85. catch (e) { res = 'null'; error('JSON stringify failed.'); }
  86. return res;
  87. }
  88. function addExpander(item) {
  89. if (item.children('.expander').length == 0) {
  90. var expander = $('<span>', { 'class': 'expander' });
  91. expander.bind('click', function() {
  92. var item = $(this).parent();
  93. item.toggleClass('expanded');
  94. });
  95. item.prepend(expander);
  96. }
  97. }
  98. function construct(opt, json, root, path) {
  99. path = path || '';
  100. root.children('.item').remove();
  101. for (var key in json) {
  102. if (!json.hasOwnProperty(key)) continue;
  103. var item = $('<div>', { 'class': 'item', 'data-path': path }),
  104. property = $(opt.propertyElement || '<input>', { 'class': 'property' }),
  105. value = $(opt.valueElement || '<input>', { 'class': 'value' });
  106. if (isObject(json[key]) || isArray(json[key])) {
  107. addExpander(item);
  108. }
  109. item.append(property).append(value);
  110. root.append(item);
  111. property.val(key).attr('title', key);
  112. var val = stringify(json[key]);
  113. value.val(val).attr('title', val);
  114. assignType(item, json[key]);
  115. property.change(propertyChanged(opt));
  116. value.change(valueChanged(opt));
  117. if (isObject(json[key]) || isArray(json[key])) {
  118. construct(opt, json[key], item, (path ? path + '.' : '') + key);
  119. }
  120. }
  121. }
  122. function updateParents(el, opt) {
  123. $(el).parentsUntil(opt.target).each(function() {
  124. var path = $(this).data('path');
  125. path = (path ? path + '.' : path) + $(this).children('.property').val();
  126. var val = stringify(def(opt.original, path, null));
  127. $(this).children('.value').val(val).attr('title', val);
  128. });
  129. }
  130. function propertyChanged(opt) {
  131. return function() {
  132. var path = $(this).parent().data('path'),
  133. val = parse($(this).next().val()),
  134. newKey = $(this).val(),
  135. oldKey = $(this).attr('title');
  136. $(this).attr('title', newKey);
  137. feed(opt.original, (path ? path + '.' : '') + oldKey);
  138. if (newKey) feed(opt.original, (path ? path + '.' : '') + newKey, val);
  139. updateParents(this, opt);
  140. if (!newKey) $(this).parent().remove();
  141. opt.onchange();
  142. };
  143. }
  144. function valueChanged(opt) {
  145. return function() {
  146. var key = $(this).prev().val(),
  147. val = parse($(this).val() || 'null'),
  148. item = $(this).parent(),
  149. path = item.data('path');
  150. feed(opt.original, (path ? path + '.' : '') + key, val);
  151. if ((isObject(val) || isArray(val)) && !$.isEmptyObject(val)) {
  152. construct(opt, val, item, (path ? path + '.' : '') + key);
  153. addExpander(item);
  154. } else {
  155. item.find('.expander, .item').remove();
  156. }
  157. assignType(item, val);
  158. updateParents(this, opt);
  159. opt.onchange();
  160. };
  161. }
  162. function assignType(item, val) {
  163. var className = 'null';
  164. if (isObject(val)) className = 'object';
  165. else if (isArray(val)) className = 'array';
  166. else if (isBoolean(val)) className = 'boolean';
  167. else if (isString(val)) className = 'string';
  168. else if (isNumber(val)) className = 'number';
  169. item.removeClass(types);
  170. item.addClass(className);
  171. }
  172. })( jQuery );