bee_api 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. data/bin/bee_api +84 -0
  2. data/lib/mdpreview.rb +80 -0
  3. data/lib/mdpreview/translator.rb +60 -0
  4. data/lib/mdpreview/version.rb +3 -0
  5. data/test/mdptest.rb +100 -0
  6. data/vendor/HISTORY.md +237 -0
  7. data/vendor/Jakefile.js +316 -0
  8. data/vendor/LICENSE +176 -0
  9. data/vendor/NOTICE +17 -0
  10. data/vendor/README.md +102 -0
  11. data/vendor/app/chrome/documentation.txt +12 -0
  12. data/vendor/app/chrome/manifest.json +24 -0
  13. data/vendor/app/web/ajax.js +43 -0
  14. data/vendor/app/web/app.css +292 -0
  15. data/vendor/app/web/app.js +377 -0
  16. data/vendor/app/web/beta/index.html +17 -0
  17. data/vendor/app/web/datapolicy.txt +48 -0
  18. data/vendor/app/web/doc/doc.css +60 -0
  19. data/vendor/app/web/doc/img/actions_menu.png +0 -0
  20. data/vendor/app/web/doc/img/button_actions_menu.png +0 -0
  21. data/vendor/app/web/doc/img/button_dragarea.png +0 -0
  22. data/vendor/app/web/doc/img/jsoneditor.png +0 -0
  23. data/vendor/app/web/doc/img/jsonformatter.png +0 -0
  24. data/vendor/app/web/doc/img/main_menu.png +0 -0
  25. data/vendor/app/web/doc/img/splitter.png +0 -0
  26. data/vendor/app/web/doc/index.html +201 -0
  27. data/vendor/app/web/favicon.ico +0 -0
  28. data/vendor/app/web/fileretriever.css +54 -0
  29. data/vendor/app/web/fileretriever.js +567 -0
  30. data/vendor/app/web/fileretriever.php +120 -0
  31. data/vendor/app/web/googlea47c4a0b36d11021.html +1 -0
  32. data/vendor/app/web/hash.js +133 -0
  33. data/vendor/app/web/img/description.txt +20 -0
  34. data/vendor/app/web/img/header_background.png +0 -0
  35. data/vendor/app/web/img/icon_128.png +0 -0
  36. data/vendor/app/web/img/icon_16.png +0 -0
  37. data/vendor/app/web/img/icon_gray.svg +151 -0
  38. data/vendor/app/web/img/icon_gray_16.svg +150 -0
  39. data/vendor/app/web/img/icon_orange.svg +151 -0
  40. data/vendor/app/web/img/logo.png +0 -0
  41. data/vendor/app/web/img/logo.xcf +0 -0
  42. data/vendor/app/web/img/logo_app.png +0 -0
  43. data/vendor/app/web/img/logo_app.xcf +0 -0
  44. data/vendor/app/web/index.html +191 -0
  45. data/vendor/app/web/notify.js +150 -0
  46. data/vendor/app/web/queryparams.js +71 -0
  47. data/vendor/app/web/robots.txt +0 -0
  48. data/vendor/app/web/splitter.js +179 -0
  49. data/vendor/app/web/test.html +224 -0
  50. data/vendor/component.json +33 -0
  51. data/vendor/docs/api.md +188 -0
  52. data/vendor/docs/usage.md +137 -0
  53. data/vendor/examples/01_basic_usage.html +45 -0
  54. data/vendor/examples/02_viewer.html +38 -0
  55. data/vendor/examples/03_switch_mode.html +98 -0
  56. data/vendor/examples/cur.file +1 -0
  57. data/vendor/examples/jquery.js +2 -0
  58. data/vendor/examples/meta.js +1 -0
  59. data/vendor/examples/requirejs_demo/requirejs_demo.html +19 -0
  60. data/vendor/examples/requirejs_demo/scripts/main.js +25 -0
  61. data/vendor/examples/requirejs_demo/scripts/require.js +35 -0
  62. data/vendor/img/jsoneditor-icons.png +0 -0
  63. data/vendor/jsoneditor-min.css +1 -0
  64. data/vendor/jsoneditor-min.js +34 -0
  65. data/vendor/jsoneditor.css +597 -0
  66. data/vendor/jsoneditor.js +6069 -0
  67. data/vendor/jsoneditor/css/contextmenu.css +219 -0
  68. data/vendor/jsoneditor/css/img/description.txt +13 -0
  69. data/vendor/jsoneditor/css/img/export.sh +16 -0
  70. data/vendor/jsoneditor/css/img/jsoneditor-icons.png +0 -0
  71. data/vendor/jsoneditor/css/img/jsoneditor-icons.svg +861 -0
  72. data/vendor/jsoneditor/css/jsoneditor.css +220 -0
  73. data/vendor/jsoneditor/css/menu.css +81 -0
  74. data/vendor/jsoneditor/css/searchbox.css +73 -0
  75. data/vendor/jsoneditor/js/appendnode.js +211 -0
  76. data/vendor/jsoneditor/js/contextmenu.js +440 -0
  77. data/vendor/jsoneditor/js/header.js +32 -0
  78. data/vendor/jsoneditor/js/highlighter.js +82 -0
  79. data/vendor/jsoneditor/js/history.js +218 -0
  80. data/vendor/jsoneditor/js/jsoneditor.js +206 -0
  81. data/vendor/jsoneditor/js/module.js +50 -0
  82. data/vendor/jsoneditor/js/node.js +2864 -0
  83. data/vendor/jsoneditor/js/searchbox.js +288 -0
  84. data/vendor/jsoneditor/js/texteditor.js +311 -0
  85. data/vendor/jsoneditor/js/treeeditor.js +770 -0
  86. data/vendor/jsoneditor/js/util.js +582 -0
  87. data/vendor/lib/ace/ace.js +11 -0
  88. data/vendor/lib/ace/mode-json.js +1 -0
  89. data/vendor/lib/ace/theme-jsoneditor.js +144 -0
  90. data/vendor/lib/ace/theme-textmate.js +163 -0
  91. data/vendor/lib/ace/worker-json.js +1 -0
  92. data/vendor/lib/jsonlint/README.md +62 -0
  93. data/vendor/lib/jsonlint/jsonlint.js +432 -0
  94. data/vendor/misc/screenshots/actionsmenu_640x400.png +0 -0
  95. data/vendor/misc/screenshots/codeeditor_640x400.png +0 -0
  96. data/vendor/misc/screenshots/description.json +17 -0
  97. data/vendor/misc/screenshots/jsoneditoronline.png +0 -0
  98. data/vendor/misc/screenshots/jsoneditoronline_640x400.png +0 -0
  99. data/vendor/misc/screenshots/search_640x400.png +0 -0
  100. data/vendor/misc/screenshots/small_tile.xcf +0 -0
  101. data/vendor/misc/screenshots/small_tile_440x280.png +0 -0
  102. data/vendor/misc/todo.txt +101 -0
  103. data/vendor/package.json +28 -0
  104. data/vendor/test/couchdbeditor.html +100 -0
  105. data/vendor/test/largefile.json +12605 -0
  106. data/vendor/test/test_ace.html +60 -0
  107. data/vendor/test/test_editable_div.html +449 -0
  108. metadata +154 -0
@@ -0,0 +1,770 @@
1
+ /**
2
+ * @constructor TreeEditor
3
+ * @param {Element} container Container element
4
+ * @param {Object} [options] Object with options. available options:
5
+ * {String} mode Editor mode. Available values:
6
+ * 'tree' (default), 'view',
7
+ * and 'form'.
8
+ * {Boolean} search Enable search box.
9
+ * True by default
10
+ * {Boolean} history Enable history (undo/redo).
11
+ * True by default
12
+ * {function} change Callback method, triggered
13
+ * on change of contents
14
+ * {String} name Field name for the root node.
15
+ * @param {Object | undefined} json JSON object
16
+ */
17
+ function TreeEditor(container, options, json) {
18
+ if (!(this instanceof TreeEditor)) {
19
+ throw new Error('TreeEditor constructor called without "new".');
20
+ }
21
+
22
+ this._create(container, options, json);
23
+ }
24
+
25
+ /**
26
+ * Create the TreeEditor
27
+ * @param {Element} container Container element
28
+ * @param {Object} [options] See description in constructor
29
+ * @param {Object | undefined} json JSON object
30
+ * @private
31
+ */
32
+ TreeEditor.prototype._create = function (container, options, json) {
33
+ // check availability of JSON parser (not available in IE7 and older)
34
+ if (typeof(JSON) == 'undefined') {
35
+ throw new Error ('Your browser does not support JSON. \n\n' +
36
+ 'Please install the newest version of your browser.\n' +
37
+ '(all modern browsers support JSON).');
38
+ }
39
+
40
+ if (!container) {
41
+ throw new Error('No container element provided.');
42
+ }
43
+ this.container = container;
44
+ this.dom = {};
45
+ this.highlighter = new Highlighter();
46
+ this.selection = undefined; // will hold the last input selection
47
+
48
+ this._setOptions(options);
49
+
50
+ if (this.options.history && !this.mode.view) {
51
+ this.history = new History(this);
52
+ }
53
+
54
+ this._createFrame();
55
+ this._createTable();
56
+
57
+ this.set(json || {});
58
+ };
59
+
60
+ /**
61
+ * Detach the editor from the DOM
62
+ * @private
63
+ */
64
+ TreeEditor.prototype._delete = function () {
65
+ if (this.frame && this.container && this.frame.parentNode == this.container) {
66
+ this.container.removeChild(this.frame);
67
+ }
68
+ };
69
+
70
+ /**
71
+ * Initialize and set default options
72
+ * @param {Object} [options] See description in constructor
73
+ * @private
74
+ */
75
+ TreeEditor.prototype._setOptions = function (options) {
76
+ this.options = {
77
+ search: true,
78
+ history: true,
79
+ mode: 'tree',
80
+ name: undefined // field name of root node
81
+ };
82
+
83
+ // copy all options
84
+ if (options) {
85
+ for (var prop in options) {
86
+ if (options.hasOwnProperty(prop)) {
87
+ this.options[prop] = options[prop];
88
+ }
89
+ }
90
+
91
+ // check for deprecated options
92
+ if (options['enableSearch']) {
93
+ // deprecated since version 1.6.0, 2012-11-03
94
+ this.options.search = options['enableSearch'];
95
+ util.log('WARNING: Option "enableSearch" is deprecated. Use "search" instead.');
96
+ }
97
+ if (options['enableHistory']) {
98
+ // deprecated since version 1.6.0, 2012-11-03
99
+ this.options.history = options['enableHistory'];
100
+ util.log('WARNING: Option "enableHistory" is deprecated. Use "history" instead.');
101
+ }
102
+ if (options['mode'] == 'editor') {
103
+ // deprecated since version 2.2.0, 2013-04-30
104
+ this.options.mode = 'tree';
105
+ util.log('WARNING: Mode "editor" is deprecated. Use "tree" instead.');
106
+ }
107
+ if (options['mode'] == 'viewer') {
108
+ // deprecated since version 2.2.0, 2013-04-30
109
+ this.options.mode = 'view';
110
+ util.log('WARNING: Mode "viewer" is deprecated. Use "view" instead.');
111
+ }
112
+ }
113
+
114
+ // interpret the mode options
115
+ this.mode = {
116
+ edit: (this.options.mode != 'view' && this.options.mode != 'form'),
117
+ view: (this.options.mode == 'view'),
118
+ form: (this.options.mode == 'form')
119
+ };
120
+ };
121
+
122
+ // node currently being edited
123
+ TreeEditor.focusNode = undefined;
124
+
125
+ /**
126
+ * Set JSON object in editor
127
+ * @param {Object | undefined} json JSON data
128
+ * @param {String} [name] Optional field name for the root node.
129
+ * Can also be set using setName(name).
130
+ */
131
+ TreeEditor.prototype.set = function (json, name) {
132
+ // adjust field name for root node
133
+ if (name) {
134
+ // TODO: deprecated since version 2.2.0. Cleanup some day.
135
+ util.log('Warning: second parameter "name" is deprecated. ' +
136
+ 'Use setName(name) instead.');
137
+ this.options.name = name;
138
+ }
139
+
140
+ // verify if json is valid JSON, ignore when a function
141
+ if (json instanceof Function || (json === undefined)) {
142
+ this.clear();
143
+ }
144
+ else {
145
+ this.content.removeChild(this.table); // Take the table offline
146
+
147
+ // replace the root node
148
+ var params = {
149
+ 'field': this.options.name,
150
+ 'value': json
151
+ };
152
+ var node = new Node(this, params);
153
+ this._setRoot(node);
154
+
155
+ // expand
156
+ var recurse = false;
157
+ this.node.expand(recurse);
158
+
159
+ this.content.appendChild(this.table); // Put the table online again
160
+ }
161
+
162
+ // TODO: maintain history, store last state and previous document
163
+ if (this.history) {
164
+ this.history.clear();
165
+ }
166
+ };
167
+
168
+ /**
169
+ * Get JSON object from editor
170
+ * @return {Object | undefined} json
171
+ */
172
+ TreeEditor.prototype.get = function () {
173
+ // remove focus from currently edited node
174
+ if (TreeEditor.focusNode) {
175
+ TreeEditor.focusNode.blur();
176
+ }
177
+
178
+ if (this.node) {
179
+ return this.node.getValue();
180
+ }
181
+ else {
182
+ return undefined;
183
+ }
184
+ };
185
+
186
+ /**
187
+ * Get the text contents of the TreeEditor
188
+ * @return {String} jsonText
189
+ */
190
+ TreeEditor.prototype.getText = function() {
191
+ return JSON.stringify(this.get());
192
+ };
193
+
194
+ /**
195
+ * Set the text contents of the TreeEditor
196
+ * @param {String} jsonText
197
+ */
198
+ TreeEditor.prototype.setText = function(jsonText) {
199
+ this.set(util.parse(jsonText));
200
+ };
201
+
202
+ /**
203
+ * Set a field name for the root node.
204
+ * @param {String | undefined} name
205
+ */
206
+ TreeEditor.prototype.setName = function (name) {
207
+ this.options.name = name;
208
+ if (this.node) {
209
+ this.node.updateField(this.options.name);
210
+ }
211
+ };
212
+
213
+ /**
214
+ * Get the field name for the root node.
215
+ * @return {String | undefined} name
216
+ */
217
+ TreeEditor.prototype.getName = function () {
218
+ return this.options.name;
219
+ };
220
+
221
+ /**
222
+ * Remove the root node from the editor
223
+ */
224
+ TreeEditor.prototype.clear = function () {
225
+ if (this.node) {
226
+ this.node.collapse();
227
+ this.tbody.removeChild(this.node.getDom());
228
+ delete this.node;
229
+ }
230
+ };
231
+
232
+ /**
233
+ * Set the root node for the json editor
234
+ * @param {Node} node
235
+ * @private
236
+ */
237
+ TreeEditor.prototype._setRoot = function (node) {
238
+ this.clear();
239
+
240
+ this.node = node;
241
+
242
+ // append to the dom
243
+ this.tbody.appendChild(node.getDom());
244
+ };
245
+
246
+ /**
247
+ * Search text in all nodes
248
+ * The nodes will be expanded when the text is found one of its childs,
249
+ * else it will be collapsed. Searches are case insensitive.
250
+ * @param {String} text
251
+ * @return {Object[]} results Array with nodes containing the search results
252
+ * The result objects contains fields:
253
+ * - {Node} node,
254
+ * - {String} elem the dom element name where
255
+ * the result is found ('field' or
256
+ * 'value')
257
+ */
258
+ TreeEditor.prototype.search = function (text) {
259
+ var results;
260
+ if (this.node) {
261
+ this.content.removeChild(this.table); // Take the table offline
262
+ results = this.node.search(text);
263
+ this.content.appendChild(this.table); // Put the table online again
264
+ }
265
+ else {
266
+ results = [];
267
+ }
268
+
269
+ return results;
270
+ };
271
+
272
+ /**
273
+ * Expand all nodes
274
+ */
275
+ TreeEditor.prototype.expandAll = function () {
276
+ if (this.node) {
277
+ this.content.removeChild(this.table); // Take the table offline
278
+ this.node.expand();
279
+ this.content.appendChild(this.table); // Put the table online again
280
+ }
281
+ };
282
+
283
+ /**
284
+ * Collapse all nodes
285
+ */
286
+ TreeEditor.prototype.collapseAll = function () {
287
+ if (this.node) {
288
+ this.content.removeChild(this.table); // Take the table offline
289
+ this.node.collapse();
290
+ this.content.appendChild(this.table); // Put the table online again
291
+ }
292
+ };
293
+
294
+ /**
295
+ * The method onChange is called whenever a field or value is changed, created,
296
+ * deleted, duplicated, etc.
297
+ * @param {String} action Change action. Available values: "editField",
298
+ * "editValue", "changeType", "appendNode",
299
+ * "removeNode", "duplicateNode", "moveNode", "expand",
300
+ * "collapse".
301
+ * @param {Object} params Object containing parameters describing the change.
302
+ * The parameters in params depend on the action (for
303
+ * example for "editValue" the Node, old value, and new
304
+ * value are provided). params contains all information
305
+ * needed to undo or redo the action.
306
+ * @private
307
+ */
308
+ TreeEditor.prototype._onAction = function (action, params) {
309
+ // add an action to the history
310
+ if (this.history) {
311
+ this.history.add(action, params);
312
+ }
313
+
314
+ // trigger the onChange callback
315
+ if (this.options.change) {
316
+ try {
317
+ this.options.change();
318
+ }
319
+ catch (err) {
320
+ util.log('Error in change callback: ', err);
321
+ }
322
+ }
323
+ };
324
+
325
+ /**
326
+ * Start autoscrolling when given mouse position is above the top of the
327
+ * editor contents, or below the bottom.
328
+ * @param {Number} mouseY Absolute mouse position in pixels
329
+ */
330
+ TreeEditor.prototype.startAutoScroll = function (mouseY) {
331
+ var me = this;
332
+ var content = this.content;
333
+ var top = util.getAbsoluteTop(content);
334
+ var height = content.clientHeight;
335
+ var bottom = top + height;
336
+ var margin = 24;
337
+ var interval = 50; // ms
338
+
339
+ if ((mouseY < top + margin) && content.scrollTop > 0) {
340
+ this.autoScrollStep = ((top + margin) - mouseY) / 3;
341
+ }
342
+ else if (mouseY > bottom - margin &&
343
+ height + content.scrollTop < content.scrollHeight) {
344
+ this.autoScrollStep = ((bottom - margin) - mouseY) / 3;
345
+ }
346
+ else {
347
+ this.autoScrollStep = undefined;
348
+ }
349
+
350
+ if (this.autoScrollStep) {
351
+ if (!this.autoScrollTimer) {
352
+ this.autoScrollTimer = setInterval(function () {
353
+ if (me.autoScrollStep) {
354
+ content.scrollTop -= me.autoScrollStep;
355
+ }
356
+ else {
357
+ me.stopAutoScroll();
358
+ }
359
+ }, interval);
360
+ }
361
+ }
362
+ else {
363
+ this.stopAutoScroll();
364
+ }
365
+ };
366
+
367
+ /**
368
+ * Stop auto scrolling. Only applicable when scrolling
369
+ */
370
+ TreeEditor.prototype.stopAutoScroll = function () {
371
+ if (this.autoScrollTimer) {
372
+ clearTimeout(this.autoScrollTimer);
373
+ delete this.autoScrollTimer;
374
+ }
375
+ if (this.autoScrollStep) {
376
+ delete this.autoScrollStep;
377
+ }
378
+ };
379
+
380
+
381
+ /**
382
+ * Set the focus to an element in the TreeEditor, set text selection, and
383
+ * set scroll position.
384
+ * @param {Object} selection An object containing fields:
385
+ * {Element | undefined} dom The dom element
386
+ * which has focus
387
+ * {Range | TextRange} range A text selection
388
+ * {Number} scrollTop Scroll position
389
+ */
390
+ TreeEditor.prototype.setSelection = function (selection) {
391
+ if (!selection) {
392
+ return;
393
+ }
394
+
395
+ if ('scrollTop' in selection && this.content) {
396
+ // TODO: animated scroll
397
+ this.content.scrollTop = selection.scrollTop;
398
+ }
399
+ if (selection.range) {
400
+ util.setSelectionOffset(selection.range);
401
+ }
402
+ if (selection.dom) {
403
+ selection.dom.focus();
404
+ }
405
+ };
406
+
407
+ /**
408
+ * Get the current focus
409
+ * @return {Object} selection An object containing fields:
410
+ * {Element | undefined} dom The dom element
411
+ * which has focus
412
+ * {Range | TextRange} range A text selection
413
+ * {Number} scrollTop Scroll position
414
+ */
415
+ TreeEditor.prototype.getSelection = function () {
416
+ return {
417
+ dom: TreeEditor.domFocus,
418
+ scrollTop: this.content ? this.content.scrollTop : 0,
419
+ range: util.getSelectionOffset()
420
+ };
421
+ };
422
+
423
+ /**
424
+ * Adjust the scroll position such that given top position is shown at 1/4
425
+ * of the window height.
426
+ * @param {Number} top
427
+ * @param {function(boolean)} [callback] Callback, executed when animation is
428
+ * finished. The callback returns true
429
+ * when animation is finished, or false
430
+ * when not.
431
+ */
432
+ TreeEditor.prototype.scrollTo = function (top, callback) {
433
+ var content = this.content;
434
+ if (content) {
435
+ var editor = this;
436
+ // cancel any running animation
437
+ if (editor.animateTimeout) {
438
+ clearTimeout(editor.animateTimeout);
439
+ delete editor.animateTimeout;
440
+ }
441
+ if (editor.animateCallback) {
442
+ editor.animateCallback(false);
443
+ delete editor.animateCallback;
444
+ }
445
+
446
+ // calculate final scroll position
447
+ var height = content.clientHeight;
448
+ var bottom = content.scrollHeight - height;
449
+ var finalScrollTop = Math.min(Math.max(top - height / 4, 0), bottom);
450
+
451
+ // animate towards the new scroll position
452
+ var animate = function () {
453
+ var scrollTop = content.scrollTop;
454
+ var diff = (finalScrollTop - scrollTop);
455
+ if (Math.abs(diff) > 3) {
456
+ content.scrollTop += diff / 3;
457
+ editor.animateCallback = callback;
458
+ editor.animateTimeout = setTimeout(animate, 50);
459
+ }
460
+ else {
461
+ // finished
462
+ if (callback) {
463
+ callback(true);
464
+ }
465
+ content.scrollTop = finalScrollTop;
466
+ delete editor.animateTimeout;
467
+ delete editor.animateCallback;
468
+ }
469
+ };
470
+ animate();
471
+ }
472
+ else {
473
+ if (callback) {
474
+ callback(false);
475
+ }
476
+ }
477
+ };
478
+
479
+ /**
480
+ * Create main frame
481
+ * @private
482
+ */
483
+ TreeEditor.prototype._createFrame = function () {
484
+ // create the frame
485
+ this.frame = document.createElement('div');
486
+ this.frame.className = 'jsoneditor';
487
+ this.container.appendChild(this.frame);
488
+
489
+ // create one global event listener to handle all events from all nodes
490
+ var editor = this;
491
+ var onEvent = function (event) {
492
+ editor._onEvent(event);
493
+ };
494
+ this.frame.onclick = function (event) {
495
+ event = event || window.event;
496
+ var target = event.target || event.srcElement;
497
+
498
+ onEvent(event);
499
+
500
+ // prevent default submit action of buttons when TreeEditor is located
501
+ // inside a form
502
+ if (target.nodeName == 'BUTTON') {
503
+ util.preventDefault(event);
504
+ }
505
+ };
506
+ this.frame.oninput = onEvent;
507
+ this.frame.onchange = onEvent;
508
+ this.frame.onkeydown = onEvent;
509
+ this.frame.onkeyup = onEvent;
510
+ this.frame.oncut = onEvent;
511
+ this.frame.onpaste = onEvent;
512
+ this.frame.onmousedown = onEvent;
513
+ this.frame.onmouseup = onEvent;
514
+ this.frame.onmouseover = onEvent;
515
+ this.frame.onmouseout = onEvent;
516
+ // Note: focus and blur events do not propagate, therefore they defined
517
+ // using an eventListener with useCapture=true
518
+ // see http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html
519
+ util.addEventListener(this.frame, 'focus', onEvent, true);
520
+ util.addEventListener(this.frame, 'blur', onEvent, true);
521
+ this.frame.onfocusin = onEvent; // for IE
522
+ this.frame.onfocusout = onEvent; // for IE
523
+
524
+ // create menu
525
+ this.menu = document.createElement('div');
526
+ this.menu.className = 'menu';
527
+ this.frame.appendChild(this.menu);
528
+
529
+ // create expand all button
530
+ var expandAll = document.createElement('button');
531
+ expandAll.className = 'expand-all';
532
+ expandAll.title = 'Expand all fields';
533
+ expandAll.onclick = function () {
534
+ editor.expandAll();
535
+ };
536
+ this.menu.appendChild(expandAll);
537
+
538
+ // create expand all button
539
+ var collapseAll = document.createElement('button');
540
+ collapseAll.title = 'Collapse all fields';
541
+ collapseAll.className = 'collapse-all';
542
+ collapseAll.onclick = function () {
543
+ editor.collapseAll();
544
+ };
545
+ this.menu.appendChild(collapseAll);
546
+
547
+ // create undo/redo buttons
548
+ if (this.history) {
549
+ // create separator
550
+ var separator = document.createElement('span');
551
+ separator.innerHTML = '&nbsp;';
552
+ this.menu.appendChild(separator);
553
+
554
+ // create undo button
555
+ var undo = document.createElement('button');
556
+ undo.className = 'undo';
557
+ undo.title = 'Undo last action (Ctrl+Z)';
558
+ undo.onclick = function () {
559
+ editor._onUndo();
560
+ };
561
+ this.menu.appendChild(undo);
562
+ this.dom.undo = undo;
563
+
564
+ // create redo button
565
+ var redo = document.createElement('button');
566
+ redo.className = 'redo';
567
+ redo.title = 'Redo (Ctrl+Shift+Z)';
568
+ redo.onclick = function () {
569
+ editor._onRedo();
570
+ };
571
+ this.menu.appendChild(redo);
572
+ this.dom.redo = redo;
573
+
574
+ // register handler for onchange of history
575
+ this.history.onChange = function () {
576
+ undo.disabled = !editor.history.canUndo();
577
+ redo.disabled = !editor.history.canRedo();
578
+ };
579
+ this.history.onChange();
580
+ }
581
+
582
+ // create search box
583
+ if (this.options.search) {
584
+ this.searchBox = new SearchBox(this, this.menu);
585
+ }
586
+ };
587
+
588
+ /**
589
+ * Perform an undo action
590
+ * @private
591
+ */
592
+ TreeEditor.prototype._onUndo = function () {
593
+ if (this.history) {
594
+ // undo last action
595
+ this.history.undo();
596
+
597
+ // trigger change callback
598
+ if (this.options.change) {
599
+ this.options.change();
600
+ }
601
+ }
602
+ };
603
+
604
+ /**
605
+ * Perform a redo action
606
+ * @private
607
+ */
608
+ TreeEditor.prototype._onRedo = function () {
609
+ if (this.history) {
610
+ // redo last action
611
+ this.history.redo();
612
+
613
+ // trigger change callback
614
+ if (this.options.change) {
615
+ this.options.change();
616
+ }
617
+ }
618
+ };
619
+
620
+ /**
621
+ * Event handler
622
+ * @param event
623
+ * @private
624
+ */
625
+ TreeEditor.prototype._onEvent = function (event) {
626
+ event = event || window.event;
627
+ var target = event.target || event.srcElement;
628
+
629
+ if (event.type == 'keydown') {
630
+ this._onKeyDown(event);
631
+ }
632
+
633
+ if (event.type == 'focus') {
634
+ TreeEditor.domFocus = target;
635
+ }
636
+
637
+ var node = Node.getNodeFromTarget(target);
638
+ if (node) {
639
+ node.onEvent(event);
640
+ }
641
+ };
642
+
643
+ /**
644
+ * Event handler for keydown. Handles shortcut keys
645
+ * @param {Event} event
646
+ * @private
647
+ */
648
+ TreeEditor.prototype._onKeyDown = function (event) {
649
+ var keynum = event.which || event.keyCode;
650
+ var ctrlKey = event.ctrlKey;
651
+ var shiftKey = event.shiftKey;
652
+ var handled = false;
653
+
654
+ if (keynum == 9) { // Tab or Shift+Tab
655
+ // FIXME: selecting all text on tab key does not work on IE8 (-> put selectContentEditable() in keyup too?)
656
+ //Node.select(TreeEditor.domFocus);
657
+ setTimeout(function () {
658
+ // select all text when moving focus to an editable div
659
+ util.selectContentEditable(TreeEditor.domFocus);
660
+ }, 0);
661
+ }
662
+
663
+ if (this.searchBox) {
664
+ if (ctrlKey && keynum == 70) { // Ctrl+F
665
+ this.searchBox.dom.search.focus();
666
+ this.searchBox.dom.search.select();
667
+ handled = true;
668
+ }
669
+ else if (keynum == 114 || (ctrlKey && keynum == 71)) { // F3 or Ctrl+G
670
+ var focus = true;
671
+ if (!shiftKey) {
672
+ // select next search result (F3 or Ctrl+G)
673
+ this.searchBox.next(focus);
674
+ }
675
+ else {
676
+ // select previous search result (Shift+F3 or Ctrl+Shift+G)
677
+ this.searchBox.previous(focus);
678
+ }
679
+
680
+ handled = true;
681
+ }
682
+ }
683
+
684
+ if (this.history) {
685
+ if (ctrlKey && !shiftKey && keynum == 90) { // Ctrl+Z
686
+ // undo
687
+ this._onUndo();
688
+ handled = true;
689
+ }
690
+ else if (ctrlKey && shiftKey && keynum == 90) { // Ctrl+Shift+Z
691
+ // redo
692
+ this._onRedo();
693
+ handled = true;
694
+ }
695
+ }
696
+
697
+ if (handled) {
698
+ util.preventDefault(event);
699
+ util.stopPropagation(event);
700
+ }
701
+ };
702
+
703
+ /**
704
+ * Create main table
705
+ * @private
706
+ */
707
+ TreeEditor.prototype._createTable = function () {
708
+ var contentOuter = document.createElement('div');
709
+ contentOuter.className = 'outer';
710
+ this.contentOuter = contentOuter;
711
+
712
+ this.content = document.createElement('div');
713
+ this.content.className = 'content';
714
+ contentOuter.appendChild(this.content);
715
+
716
+ this.table = document.createElement('table');
717
+ this.table.className = 'content';
718
+ this.content.appendChild(this.table);
719
+
720
+ // IE8 does not handle overflow='auto' correctly.
721
+ // Therefore, set overflow to 'scroll'
722
+ var ieVersion = util.getInternetExplorerVersion();
723
+ if (ieVersion == 8) {
724
+ this.content.style.overflow = 'scroll';
725
+ }
726
+
727
+ // create colgroup where the first two columns don't have a fixed
728
+ // width, and the edit columns do have a fixed width
729
+ var col;
730
+ this.colgroupContent = document.createElement('colgroup');
731
+ if (this.mode.edit) {
732
+ col = document.createElement('col');
733
+ col.width = "24px";
734
+ this.colgroupContent.appendChild(col);
735
+ }
736
+ col = document.createElement('col');
737
+ col.width = "24px";
738
+ this.colgroupContent.appendChild(col);
739
+ col = document.createElement('col');
740
+ this.colgroupContent.appendChild(col);
741
+ this.table.appendChild(this.colgroupContent);
742
+
743
+ this.tbody = document.createElement('tbody');
744
+ this.table.appendChild(this.tbody);
745
+
746
+ this.frame.appendChild(contentOuter);
747
+ };
748
+
749
+ // register modes at the JSONEditor
750
+ JSONEditor.modes.tree = {
751
+ editor: TreeEditor,
752
+ data: 'json'
753
+ };
754
+ JSONEditor.modes.view = {
755
+ editor: TreeEditor,
756
+ data: 'json'
757
+ };
758
+ JSONEditor.modes.form = {
759
+ editor: TreeEditor,
760
+ data: 'json'
761
+ };
762
+ // Deprecated modes (deprecated since version 2.2.0)
763
+ JSONEditor.modes.editor = {
764
+ editor: TreeEditor,
765
+ data: 'json'
766
+ };
767
+ JSONEditor.modes.viewer = {
768
+ editor: TreeEditor,
769
+ data: 'json'
770
+ };