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,201 @@
1
+ <!DOCTYPE HTML>
2
+ <html>
3
+ <head>
4
+ <title>JSON Editor Online - Documentation</title>
5
+ <link href="doc.css" rel="stylesheet" type="text/css">
6
+ </head>
7
+
8
+ <body>
9
+ <div id="container">
10
+ <h1 id="documentation">JSON Editor Online - Documentation</h1>
11
+
12
+ <h2 id="introduction">Introduction</h2>
13
+ <p>
14
+ JSON Editor Online is a web-based tool to view, edit, and format JSON.
15
+ It shows your data side by side in a clear, editable treeview and in
16
+ a code editor.
17
+ </p>
18
+ <p>
19
+ Supported browsers: Chrome, Firefox, Safari, Opera, Internet Explorer 8+.
20
+ </p>
21
+ <p>
22
+ Website: <a href="http://jsoneditoronline.org" target="_blank">
23
+ http://jsoneditoronline.org</a>.
24
+ </p>
25
+ <p>
26
+ Contents:
27
+ </p>
28
+ <ul>
29
+ <li><a href="#main_menu">Main menu</a></li>
30
+ <li><a href="#panels">Panels</a></li>
31
+ <li><a href="#formatter">Formatter</a></li>
32
+ <li><a href="#editor">Editor</a></li>
33
+ <li><a href="#shortcut_keys">Shortcut keys</a></li>
34
+ </ul>
35
+
36
+ <h2 id="main_menu">Main menu</h2>
37
+ <p>
38
+ The applications main menu contains options to clear, load and save the
39
+ JSON contents of the application. Files can be loaded from disk or url,
40
+ and can be saved to disk. Please note that due to security restrictions,
41
+ the application can only open files from public websites, not from an
42
+ intranet. The data policy is described
43
+ <a href="http://jsoneditoronline.org/datapolicy.txt">here</a>.
44
+ </p>
45
+ <img src="img/main_menu.png" alt="Main menu">
46
+
47
+ <h2 id="panels">Panels</h2>
48
+ <p>
49
+ The application contains two panels: a <b>JSON Formatter</b> on the left,
50
+ and a <b>JSON Editor</b> on the right.
51
+ </p>
52
+ <p>
53
+ There is a splitter between the two panels, allowing to change the
54
+ width of both panels according to ones needs.
55
+ To copy the contents from one panel to an other, the two copy buttons
56
+ between the panels can be used.
57
+ </p>
58
+ <img src="img/splitter.png">
59
+
60
+ <h2 id="formatter"> Formatter</h2>
61
+ <p>
62
+ The JSON Formatter displays JSON data in a code editor.
63
+ The Formatter is capable of formatting, compacting, and inspecting JSON.
64
+ </p>
65
+ <img src="img/jsonformatter.png">
66
+ <p>
67
+ The menu of the Formatter contains the following buttons:
68
+ </p>
69
+ <ul>
70
+ <li>
71
+ <b>Format</b>.
72
+ Format the JSON data, make the data readable by applying indentation
73
+ and returns.
74
+ </li>
75
+ <li>
76
+ <b>Compact</b>.
77
+ Compact the JSON data, remove all unnecessary characters like
78
+ whitespaces and returns.
79
+ </li>
80
+ </ul>
81
+
82
+ <h2 id="editor">Editor</h2>
83
+ <p>
84
+ The JSON Editor displays the JSON data in an editable tree.
85
+ The editor makes it easy to create, duplicate, remove fields,
86
+ and to edit the contents of the fields.
87
+ </p>
88
+ <img src="img/jsoneditor.png">
89
+ <p>
90
+ The menu of the editor contains the following functions:
91
+ </p>
92
+ <ul>
93
+ <li>
94
+ <b>Expand all</b>. Expand all fields in the editor.
95
+ </li>
96
+ <li>
97
+ <b>Collapse all</b>. Collapse all fields in the editor.
98
+ </li>
99
+ <li>
100
+ <b>Undo</b>. Undo last action.
101
+ </li>
102
+ <li>
103
+ <b>Redo</b>. Redo last action.
104
+ </li>
105
+ <li>
106
+ <b>Search</b>. Search for text in the JSON editor.
107
+ Search results will be highlighted, and can be iterated by
108
+ repeatedly pressing Enter or Shift+Enter.
109
+ The right side of the search box two buttons to go to the next or
110
+ previous search result.
111
+ </li>
112
+ </ul>
113
+
114
+ <p>
115
+ The field values in the editor are editable input fields.
116
+ The fields can be dragged up and down using the dragarea
117
+ <img src="img/button_dragarea.png" class="icon">
118
+ on the left side of the fields. When a field is the last item of the
119
+ childs of an array or object, the field can also be dragged horizontally
120
+ to move it in or out of the array or object.
121
+ </p>
122
+ <img src="img/actions_menu.png" align="right" style="padding-left: 20px;">
123
+ <p>
124
+ Right from the dragarea is a button
125
+ <img src="img/button_actions_menu.png" class="icon">
126
+ to open the <b>actions menu</b>.
127
+ Depending on the type of field, the following functionality is
128
+ available in the actions menu:
129
+ </p>
130
+ <ul>
131
+ <li>
132
+ <b>Type</b>. Change the type of the field. Choose from:
133
+ <ul>
134
+ <li>
135
+ <b>auto</b> The field type is automatically determined from
136
+ the value and can be a string, number, boolean, or null.
137
+ </li>
138
+ <li>
139
+ <b>object</b> An unordered set of key/value pairs.
140
+ </li>
141
+ <li>
142
+ <b>array</b> An ordered collection of values.
143
+ </li>
144
+ <li>
145
+ <b>string</b> Field type is not determined from the value,
146
+ but always returned as string.
147
+ </li>
148
+ </ul>
149
+ </li>
150
+ <li>
151
+ <b>Sort</b>. Sort the childs of an array or object.
152
+ For an array, the values of the childs will be sorted. In case of
153
+ an object, the childs will be sorted by key.
154
+ Arrays and objects can be sorted ascending or descending.
155
+ </li>
156
+ <li>
157
+ <b>Insert</b>. Insert a new field before current field.
158
+ Available types are auto (default), object, array, and string.
159
+ </li>
160
+ <li>
161
+ <b>Append</b>. Insert a new field after current field.
162
+ Available types are the same as the insert action.
163
+ </li>
164
+ <li>
165
+ <b>Duplicate</b>. Duplicate the field including all childs.
166
+ </li>
167
+ <li>
168
+ <b>Remove</b>. Remove the field including all childs.
169
+ </li>
170
+ </ul>
171
+
172
+ <h2 id="shortcut_keys">Shortcut keys</h2>
173
+ <p>
174
+ The JSON Editor supports shortcut keys for all available actions.
175
+ The editor can be used by just a keyboard.
176
+ The following short cut keys are available:
177
+ </p>
178
+
179
+ <table>
180
+ <tr><th>Key</th><th>Description</th></tr>
181
+ <tr><td>Alt+Arrows</td><td>Move the caret up/down/left/right between fields</td></tr>
182
+ <tr><td>Shift+Alt+Arrows</td><td>Move field up/down/left/right</td></tr>
183
+
184
+ <tr><td>Ctrl+D</td><td>Duplicate field</td></tr>
185
+ <tr><td>Ctrl+Del</td><td>Remove field</td></tr>
186
+ <tr><td>Ctrl+Enter</td><td>Open link when on a field containing an url</td></tr>
187
+ <tr><td>Ctrl+Ins</td><td>Insert a new field with type auto</td></tr>
188
+ <tr><td>Ctrl+Shift+Ins</td><td>Append a new field with type auto</td></tr>
189
+ <tr><td>Ctrl+E</td><td>Expand or collapse field</td></tr>
190
+ <tr><td>Alt+End</td><td>Move the caret to the last field</td></tr>
191
+ <tr><td>Ctrl+F</td><td>Find</td></tr>
192
+ <tr><td>F3, Ctrl+G<br></td><td>Find next</td></tr>
193
+ <tr><td>Shift+F3, Ctrl+Shift+G</td><td>Find previous</td></tr>
194
+ <tr><td>Alt+Home</td><td>Move the caret to the first field</td></tr>
195
+ <tr><td>Ctrl+M</td><td>Show actions menu</td></tr>
196
+ <tr><td>Ctrl+Z</td><td>Undo last action</td></tr>
197
+ <tr><td>Ctrl+Shift+Z</td><td>Redo</td></tr>
198
+ </table>
199
+ </div>
200
+ </body>
201
+ </html>
@@ -0,0 +1,54 @@
1
+
2
+ div.fileretriever-overlay, div.fileretriever-background {
3
+ position: absolute;
4
+ left: 0;
5
+ top: 0;
6
+ width: 100%;
7
+ height: 100%;
8
+ z-index: 999;
9
+ }
10
+
11
+ div.fileretriever-overlay {
12
+ background-color: gray;
13
+ opacity: 0.2;
14
+ filter: alpha(opacity = 20);
15
+ }
16
+
17
+ div.fileretriever-border {
18
+ width: 410px;
19
+ margin: 100px auto;
20
+ padding: 20px;
21
+ background-color: white;
22
+ border: 1px solid gray;
23
+ border-radius: 2px;
24
+ }
25
+
26
+ form.fileretriever-form {
27
+ }
28
+
29
+ div.fileretriever-title {
30
+ font-weight: bold;
31
+ }
32
+
33
+ div.fileretriever-contents {
34
+ margin: 30px 0;
35
+ }
36
+
37
+ div.fileretriever-buttons {
38
+ text-align: right;
39
+ }
40
+
41
+ input.fileretriever-field[type="file"] {
42
+ width: 400px;
43
+ padding: 3px;
44
+ }
45
+ input.fileretriever-field[type="text"] {
46
+ width: 400px;
47
+ border: 1px solid lightgray;
48
+ border-radius: 2px;
49
+ padding: 3px;
50
+ }
51
+
52
+ input.fileretriever-submit, input.fileretriever-cancel {
53
+ margin-left: 10px;
54
+ }
@@ -0,0 +1,567 @@
1
+ /**
2
+ * @file fileretriever.js
3
+ *
4
+ * FileRetriever manages client side loading and saving of files.
5
+ * It requires a server script (fileretriever.php). Loading and saving
6
+ * files is done purely clientside using HTML5 techniques when supported
7
+ * by the browser.
8
+ *
9
+ * Requires ajax.js.
10
+ *
11
+ * Supported browsers: Chrome, Firefox, Opera, Safari,
12
+ * Internet Explorer 8+.
13
+ *
14
+ * Example usage:
15
+ * var retriever = new FileRetriever({
16
+ * 'serverUrl': 'fileretriever.php'
17
+ * });
18
+ * retriever.loadFile(function (err, data) {
19
+ * console.log('file loaded:', data);
20
+ * });
21
+ * retriever.loadUrl(function (err, data) {
22
+ * console.log('url loaded:', data);
23
+ * });
24
+ * retriever.saveFile("some text");
25
+ *
26
+ * @constructor FileRetriever
27
+ * @param {String} options Available options:
28
+ * {string} serverUrl Server side script for
29
+ * handling files, for
30
+ * example "fileretriever.php"
31
+ * {Number} [maxSize] Maximum allowed file size
32
+ * in bytes. (this should
33
+ * be the same as maximum
34
+ * size allowed by the server
35
+ * side script). Default is
36
+ * 1024 * 1024 bytes.
37
+ * {Number} [timeout] Timeout in milliseconds.
38
+ * 30000 ms by default.
39
+ * {Boolean} [html5] Use HTML5 solutions
40
+ * to load/save files when
41
+ * supported by the browser.
42
+ * True by default.
43
+ * {Notify} [notify] A handler for notifications
44
+ * If provided, messages like
45
+ * "loading" and "saving" are created.
46
+ *
47
+ * @license
48
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
49
+ * use this file except in compliance with the License. You may obtain a copy
50
+ * of the License at
51
+ *
52
+ * http://www.apache.org/licenses/LICENSE-2.0
53
+ *
54
+ * Unless required by applicable law or agreed to in writing, software
55
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
56
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
57
+ * License for the specific language governing permissions and limitations under
58
+ * the License.
59
+ *
60
+ * Copyright (c) 2013 Jos de Jong, http://jsoneditoronline.org
61
+ *
62
+ * @author Jos de Jong, <wjosdejong@gmail.com>
63
+ * @date 2013-01-01
64
+ */
65
+ var FileRetriever = function (options) {
66
+ // set options and variables
67
+ options = options || {};
68
+ this.options = {
69
+ maxSize: ((options.maxSize != undefined) ? options.maxSize : 1024 * 1024),
70
+ html5: ((options.html5 != undefined) ? options.html5 : true)
71
+ };
72
+ this.timeout = Number(options.timeout) || 30000;
73
+ this.headers = {'Accept': 'application/json'}; // headers for ajax requests
74
+ this.scriptUrl = options.scriptUrl || 'fileretriever.php';
75
+ this.notify = options.notify || undefined;
76
+ this.defaultFilename = 'document.json';
77
+ this.dom = {};
78
+ };
79
+
80
+ /**
81
+ * make an HTML DOM element invisible
82
+ * @param {Element} elem
83
+ * @private
84
+ */
85
+ FileRetriever.prototype._hide = function (elem) {
86
+ elem.style.visibility = 'hidden';
87
+ elem.style.position = 'absolute';
88
+ elem.style.left = '-1000px';
89
+ elem.style.top = '-1000px';
90
+ elem.style.width = '0';
91
+ elem.style.height = '0';
92
+ };
93
+
94
+ /**
95
+ * Delete all HTML DOM elements created by the FileRetriever.
96
+ * The FileRetriever cannot be used after its DOM elements are deleted.
97
+ */
98
+ FileRetriever.prototype.remove = function () {
99
+ var dom = this.dom;
100
+ for (var prop in dom) {
101
+ if (dom.hasOwnProperty(prop)) {
102
+ var elem = dom[prop];
103
+ if (elem.parentNode) {
104
+ elem.parentNode.removeChild(elem);
105
+ }
106
+ }
107
+ }
108
+ this.dom = {};
109
+ };
110
+
111
+ /**
112
+ * get a filename from a path or url.
113
+ * For example "http://site.com/files/example.json" will return "example.json"
114
+ * @param {String} path A filename, path, or url
115
+ * @return {String} filename
116
+ * @private
117
+ */
118
+ FileRetriever.prototype._getFilename = function (path) {
119
+ // http://stackoverflow.com/a/423385/1262753
120
+ return path ? path.replace(/^.*[\\\/]/, '') : '';
121
+ };
122
+
123
+ /**
124
+ * Set the last url
125
+ * @param {String} url
126
+ */
127
+ FileRetriever.prototype.setUrl = function (url) {
128
+ this.url = url;
129
+ };
130
+
131
+ /**
132
+ * Get last filename
133
+ * @return {String} filename
134
+ */
135
+ FileRetriever.prototype.getFilename = function () {
136
+ return this.defaultFilename;
137
+ };
138
+
139
+ /**
140
+ * Get the last url
141
+ * @return {String | undefined} url
142
+ */
143
+ FileRetriever.prototype.getUrl = function () {
144
+ return this.url;
145
+ };
146
+
147
+ /**
148
+ * Load a url
149
+ * @param {String} url The url to be retrieved
150
+ * @param {function} callback Callback method, called with parameters:
151
+ * {Error} error
152
+ * {string} data
153
+ */
154
+ FileRetriever.prototype.loadUrl = function (url, callback) {
155
+ // set current filename (will be used when saving a file again)
156
+ this.setUrl(url);
157
+
158
+ // loading notification
159
+ var loading = undefined;
160
+ if (this.notify) {
161
+ loading = this.notify.showNotification('loading url...');
162
+ }
163
+
164
+ // method to ensure the callback is only executed once
165
+ var me = this;
166
+ var callbackOnce = function (error, data) {
167
+ if (callback) {
168
+ callback(error, data);
169
+ callback = undefined;
170
+ }
171
+ if (me.notify && loading) {
172
+ me.notify.removeMessage(loading);
173
+ loading = undefined;
174
+ }
175
+ };
176
+
177
+ // try to fetch to the url directly (may result in a cross-domain error)
178
+ var scriptUrl = this.scriptUrl;
179
+ ajax.get(url, me.headers, function(data, status) {
180
+ if (status == 200) {
181
+ // success. great. no cross-domain error
182
+ callbackOnce(null, data);
183
+ }
184
+ else {
185
+ // cross-domain error (or other). retrieve the url via the server
186
+ var indirectUrl = scriptUrl + '?url=' + encodeURIComponent(url);
187
+ var err;
188
+ ajax.get(indirectUrl, me.headers, function(data, status) {
189
+ if (status == 200) {
190
+ callbackOnce(null, data);
191
+ }
192
+ else if (status == 404) {
193
+ console.log('Error: url "' + url + '" not found', status, data);
194
+ err = new Error('Error: url "' + url + '" not found');
195
+ callbackOnce(err, null);
196
+ }
197
+ else {
198
+ console.log('Error: failed to load url "' + url + '"', status, data);
199
+ err = new Error('Error: failed to load url "' + url + '"');
200
+ callbackOnce(err, null);
201
+ }
202
+ });
203
+ }
204
+ });
205
+
206
+ // safety mechanism: callback after a timeout
207
+ setTimeout(function () {
208
+ callbackOnce(new Error('Error loading url (time out)'));
209
+ }, this.timeout);
210
+ };
211
+
212
+ /**
213
+ * Load a file from disk.
214
+ * A file explorer will be opened to select a file and press ok.
215
+ * In case of Internet Explorer, an upload form will be shown where the
216
+ * user has to select a file via a file explorer after that click load.
217
+ * @param {function} callback Callback method, called with parameters:
218
+ * {Error} error
219
+ * {string} data
220
+ */
221
+ FileRetriever.prototype.loadFile = function (callback) {
222
+ // loading notification
223
+ var loading = undefined;
224
+ var me = this;
225
+
226
+ var startLoading = function () {
227
+ if (me.notify && !loading) {
228
+ loading = me.notify.showNotification('loading file...');
229
+ }
230
+
231
+ // safety mechanism: callback after a timeout
232
+ setTimeout(function () {
233
+ callbackOnce(new Error('Error loading url (time out)'));
234
+ }, me.timeout);
235
+ };
236
+
237
+ // method to ensure the callback is only executed once
238
+ var callbackOnce = function (error, data) {
239
+ if (callback) {
240
+ callback(error, data);
241
+ callback = undefined;
242
+ }
243
+ if (me.notify && loading) {
244
+ me.notify.removeMessage(loading);
245
+ loading = undefined;
246
+ }
247
+ };
248
+
249
+ // create an iframe for uploading files
250
+ // the iframe must have an unique name, allowing multiple
251
+ // FileRetrievers. The name is needed as target for the uploadForm
252
+ var iframeName = 'fileretriever-upload-' + Math.round(Math.random() * 1E15);
253
+ var iframe = document.createElement('iframe');
254
+ iframe.name = iframeName;
255
+ me._hide(iframe);
256
+ iframe.onload = function () {
257
+ // when a downloaded file is retrieved, send a callback with
258
+ // the retrieved data
259
+ var id = iframe.contentWindow.document.body.innerHTML;
260
+ if (id) {
261
+ var url = me.scriptUrl + '?id=' + id + '&filename=' + me.getFilename();
262
+ ajax.get(url, me.headers, function (data, status) {
263
+ if (status == 200) {
264
+ callbackOnce(null, data);
265
+ }
266
+ else {
267
+ var err = new Error('Error loading file ' + me.getFilename());
268
+ callbackOnce(err, null);
269
+ }
270
+ });
271
+ }
272
+ };
273
+ document.body.appendChild(iframe);
274
+
275
+ var isIE = (navigator.appName == 'Microsoft Internet Explorer');
276
+ if (!isIE) {
277
+ // create a hidden form to select a file
278
+ var domForm = document.createElement('form');
279
+ domForm.action = this.scriptUrl;
280
+ domForm.method = 'POST';
281
+ domForm.enctype = 'multipart/form-data';
282
+ domForm.target = iframeName;
283
+ this._hide(domForm);
284
+ var domFile = document.createElement('input');
285
+ domFile.type = 'file';
286
+ domFile.name = 'file';
287
+ domFile.onchange = function () {
288
+ startLoading();
289
+
290
+ // there is a file selected
291
+ setTimeout(function () { // Timeout needed for IE
292
+ var filename = domFile.value;
293
+ if (filename.length) {
294
+ if (me.options.html5 && window.File && window.FileReader) {
295
+ // load file via HTML5 FileReader (no size limits)
296
+ var file = domFile.files[0];
297
+ var reader = new FileReader();
298
+ reader.onload = function(event) {
299
+ var data = event.target.result;
300
+ callbackOnce(null, data);
301
+ };
302
+
303
+ // Read in the image file as a data URL.
304
+ reader.readAsText(file);
305
+ }
306
+ else {
307
+ // load by uploading to server
308
+ // TODO: how to check the file size? (on older browsers)
309
+ //console.log('submitting...');
310
+
311
+ domForm.submit();
312
+ }
313
+ }
314
+ else {
315
+ // cancel
316
+ callbackOnce(null, null);
317
+ }
318
+ }, 0);
319
+ };
320
+ domForm.appendChild(domFile);
321
+ document.body.appendChild(domForm);
322
+
323
+ // activate file selection (the click is done after a timeout,
324
+ // as in Opera and Safari, the form is not yet rendered)
325
+ setTimeout(function () {
326
+ domFile.click();
327
+ }, 0);
328
+ }
329
+ else {
330
+ // create a visual form and submit manually (for IE)
331
+ this.prompt({
332
+ title: 'Open file',
333
+ titleSubmit: 'Open',
334
+ inputType: 'file',
335
+ inputName: 'file',
336
+ formAction: this.scriptUrl,
337
+ formMethod: 'POST',
338
+ formTarget: iframeName,
339
+ callback: function (value) {
340
+ if (value) {
341
+ startLoading();
342
+ }
343
+ }
344
+ });
345
+ // TODO: handle a cancel
346
+ }
347
+ };
348
+
349
+ /**
350
+ * Show a dialog to select and load an url.
351
+ * @param {function} callback Callback method, called with parameters:
352
+ * {Error} error
353
+ * {String} data
354
+ */
355
+ FileRetriever.prototype.loadUrlDialog = function (callback) {
356
+ var me = this;
357
+ this.prompt({
358
+ title: 'Open url',
359
+ titleSubmit: 'Open',
360
+ inputType: 'text',
361
+ inputName: 'url',
362
+ inputDefault: this.getUrl(),
363
+ callback: function (url) {
364
+ if (url) {
365
+ me.loadUrl(url, callback);
366
+ }
367
+ else {
368
+ // cancel
369
+ callback();
370
+ }
371
+ }
372
+ });
373
+ };
374
+
375
+ /**
376
+ * Show a prompt.
377
+ * The propmt can either:
378
+ * - Post a form when formAction, and formMethod are provided.
379
+ * Will call callback on submit.
380
+ * - Call the callback method "callback" with the entered value as parameter.
381
+ * This happens when a callback parameter is provided.
382
+ * @param {Object} params Available parameters:
383
+ * {String} title
384
+ * {String} titleSubmit
385
+ * {String} titleCancel
386
+ * {String} inputType
387
+ * {String} inputName
388
+ * {String} inputDefault
389
+ * {String} formTarget
390
+ * {String} formAction
391
+ * {String} formMethod
392
+ * {function} callback
393
+ */
394
+ FileRetriever.prototype.prompt = function (params) {
395
+ var removeDialog = function () {
396
+ // remove the form
397
+ if (background.parentNode) {
398
+ background.parentNode.removeChild(background);
399
+ }
400
+ if (overlay.parentNode) {
401
+ overlay.parentNode.removeChild(overlay);
402
+ }
403
+
404
+ jsoneditor.util.removeEventListener(document, 'keydown', onKeyDown);
405
+ };
406
+
407
+ var onCancel = function () {
408
+ removeDialog();
409
+ if(params.callback) {
410
+ params.callback(null);
411
+ }
412
+ };
413
+
414
+ var onKeyDown = jsoneditor.util.addEventListener(document, 'keydown', function (event) {
415
+ event = event || window.event;
416
+ var keynum = event.which || event.keyCode;
417
+ if (keynum == 27) { // ESC
418
+ onCancel();
419
+ jsoneditor.util.preventDefault(event);
420
+ jsoneditor.util.stopPropagation(event);
421
+ }
422
+ });
423
+
424
+ var overlay = document.createElement('div');
425
+ overlay.className = 'fileretriever-overlay';
426
+ document.body.appendChild(overlay);
427
+
428
+ var form = document.createElement('form');
429
+ form.className = 'fileretriever-form';
430
+ form.target = params.formTarget || '';
431
+ form.action = params.formAction || '';
432
+ form.method = params.formMethod || 'POST';
433
+ form.enctype = 'multipart/form-data';
434
+ form.encoding = 'multipart/form-data'; // needed for IE8 and older
435
+ form.onsubmit = function () {
436
+ if (field.value) {
437
+ setTimeout(function () {
438
+ // remove after the submit has taken place!
439
+ removeDialog();
440
+ }, 0);
441
+ if (params.callback) {
442
+ params.callback(field.value);
443
+ }
444
+ return (params.formAction != undefined && params.formMethod != undefined);
445
+ }
446
+ else {
447
+ alert('Enter a ' + params.inputName + ' first...');
448
+ return false;
449
+ }
450
+ };
451
+
452
+ var title = document.createElement('div');
453
+ title.className = 'fileretriever-title';
454
+ title.appendChild(document.createTextNode(params.title || 'Dialog'));
455
+ form.appendChild(title);
456
+
457
+ var field = document.createElement('input');
458
+ field.className = 'fileretriever-field';
459
+ field.type = params.inputType || 'text';
460
+ field.name = params.inputName || 'text';
461
+ field.value = params.inputDefault || '';
462
+
463
+ var contents = document.createElement('div');
464
+ contents.className = 'fileretriever-contents';
465
+ contents.appendChild(field);
466
+ form.appendChild(contents);
467
+
468
+ var cancel = document.createElement('input');
469
+ cancel.className = 'fileretriever-cancel';
470
+ cancel.type = 'button';
471
+ cancel.value = params.titleCancel || 'Cancel';
472
+ cancel.onclick = onCancel;
473
+
474
+ var submit = document.createElement('input');
475
+ submit.className = 'fileretriever-submit';
476
+ submit.type = 'submit';
477
+ submit.value = params.titleSubmit || 'Ok';
478
+
479
+ var buttons = document.createElement('div');
480
+ buttons.className = 'fileretriever-buttons';
481
+ buttons.appendChild(cancel);
482
+ buttons.appendChild(submit);
483
+ form.appendChild(buttons);
484
+
485
+ var border = document.createElement('div');
486
+ border.className = 'fileretriever-border';
487
+ border.appendChild(form);
488
+
489
+ var background = document.createElement('div');
490
+ background.className = 'fileretriever-background';
491
+ background.appendChild(border);
492
+ document.body.appendChild(background);
493
+
494
+ field.focus();
495
+ field.select();
496
+ };
497
+
498
+ /**
499
+ * Save data to disk
500
+ * @param {String} data
501
+ * @param {function} [callback] Callback when the file is saved, called
502
+ * with parameter:
503
+ * {Error} error
504
+ */
505
+ FileRetriever.prototype.saveFile = function (data, callback) {
506
+ // saving notification
507
+ var saving = undefined;
508
+ if (this.notify) {
509
+ saving = this.notify.showNotification('saving file...');
510
+ }
511
+
512
+ // method to ensure the callback is only executed once
513
+ var me = this;
514
+ var callbackOnce = function (error) {
515
+ if (callback) {
516
+ callback(error);
517
+ callback = undefined;
518
+ }
519
+ if (me.notify && saving) {
520
+ me.notify.removeMessage(saving);
521
+ saving = undefined;
522
+ }
523
+ };
524
+
525
+ // create an anchor to save files to disk (if supported by the browser)
526
+ var a = document.createElement('a');
527
+ if (this.options.html5 && a.download != undefined) {
528
+ // save file directly using a data URL
529
+ a.href = 'data:application/json;charset=utf-8,' + encodeURIComponent(data);
530
+ a.download = this.getFilename();
531
+ a.click();
532
+ callbackOnce();
533
+ }
534
+ else {
535
+ // save file by uploading it to the server and then downloading
536
+ // it via an iframe
537
+ if (data.length < this.options.maxSize) {
538
+ ajax.post(me.scriptUrl, data, me.headers, function(id, status) {
539
+ if (status == 200) {
540
+ var iframe = document.createElement('iframe');
541
+ iframe.src = me.scriptUrl + '?id=' + id + '&filename=' + me.getFilename();
542
+ me._hide(iframe);
543
+ document.body.appendChild(iframe);
544
+ /* TODO: send callback after the iframe is loaded. Problem: iframe.onload does not work on IE
545
+ iframe.onload = function () {
546
+ callbackOnce();
547
+ };
548
+ //*/
549
+ callbackOnce();
550
+ // TODO: cleanup the iframe after the file is saved. Problem: we cannot know when the save dialog is closed.
551
+ }
552
+ else {
553
+ callbackOnce(new Error('Error saving file'));
554
+ }
555
+ });
556
+ }
557
+ else {
558
+ callbackOnce(new Error('Maximum allowed file size exceeded (' +
559
+ this.options.maxSize + ' bytes)'));
560
+ }
561
+ }
562
+
563
+ // safety mechanism: callback after a timeout
564
+ setTimeout(function () {
565
+ callbackOnce(new Error('Error saving file (time out)'));
566
+ }, this.timeout);
567
+ };