bee_api 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ };