|
1 | | -var StringEditor = JSONEditor.defaults.editors.string; |
| 1 | +var StringEditor = JSONEditor.defaults.editors.string |
2 | 2 |
|
3 | 3 | class FlysystemEditor extends StringEditor { |
4 | 4 | setValue(value) { |
5 | | - if (value === null) { |
6 | | - value = ''; |
7 | | - } |
| 5 | + value = value || '' |
| 6 | + if (this.value === value) return |
8 | 7 |
|
9 | | - if (this.value === value) { |
10 | | - return; |
11 | | - } |
12 | | - this.input.value = value; |
13 | | - this.value = value; |
14 | | - this.onChange(); |
15 | | - } |
16 | | - |
17 | | - register() { |
18 | | - super.register(); |
19 | | - if (!this.input) return; |
20 | | - this.input.setAttribute('name', this.formname); |
21 | | - } |
22 | | - |
23 | | - unregister() { |
24 | | - super.unregister(); |
25 | | - if (!this.input) return; |
26 | | - this.input.removeAttribute('name'); |
27 | | - } |
28 | | - |
29 | | - getNumColumns() { |
30 | | - if (!this.enum_options) return 3; |
31 | | - var longest_text = this.getTitle().length; |
32 | | - for (var i = 0; i < this.enum_options.length; i++) { |
33 | | - longest_text = Math.max(longest_text, this.enum_options[i].length + 4); |
34 | | - } |
35 | | - return Math.min(12, Math.max(longest_text / 7, 2)); |
36 | | - } |
37 | | - |
38 | | - getValue() { |
39 | | - if (!this.value) { |
40 | | - this.value = ''; |
41 | | - } |
42 | | - return this.value; |
| 8 | + this.input.value = value |
| 9 | + this.value = value |
| 10 | + this.setOption(value) |
| 11 | + this.onChange() |
43 | 12 | } |
44 | 13 |
|
45 | 14 | build() { |
46 | | - var self = this; |
47 | | - |
48 | | - if (!this.options.compact) { |
49 | | - this.header = this.label = this.theme.getFormInputLabel(this.getTitle()); |
50 | | - } |
51 | | - |
52 | | - if (this.schema.description) { |
53 | | - this.description = this.theme.getFormInputDescription(this.schema.description); |
54 | | - } |
| 15 | + this.selectInput = this.theme.getSelectInput() |
| 16 | + this.input = this.theme.getFormInputField('hidden') |
55 | 17 |
|
56 | | - if (this.options.infoText) { |
57 | | - this.infoButton = this.theme.getInfoButton(this.options.infoText); |
58 | | - } |
59 | | - |
60 | | - if (this.options.compact) { |
61 | | - this.container.classList.add('compact'); |
62 | | - } |
63 | | - |
64 | | - this.input = this.theme.getFormInputField('text'); |
65 | | - |
66 | | - |
67 | | - if (this.schema.readOnly || this.schema.readonly) { |
68 | | - this.always_disabled = true; |
69 | | - this.input.disabled = true; |
70 | | - } |
71 | | - |
72 | | - this.input.addEventListener('change', function (e) { |
73 | | - e.preventDefault(); |
74 | | - e.stopPropagation(); |
75 | | - self.onInputChange(); |
76 | | - }); |
77 | | - |
78 | | - this.control = this.theme.getFormControl(this.label, this.input, this.description, this.infoButton); |
79 | | - this.container.appendChild(this.control); |
80 | | - |
81 | | - self.jsoneditor.on('ready', function () { |
82 | | - self.initSelectize(); |
83 | | - }); |
84 | | - |
85 | | - self.jsoneditor.on('addRow', function () { |
86 | | - self.initSelectize(); |
87 | | - }); |
88 | | - |
89 | | - self.jsoneditor.on('moveRow', function () { |
90 | | - self.initSelectize(); |
91 | | - }); |
92 | | - |
93 | | - self.jsoneditor.on('deleteRow', function () { |
94 | | - self.initSelectize(); |
95 | | - }); |
| 18 | + this.input.addEventListener('change', (e) => { |
| 19 | + e.preventDefault() |
| 20 | + e.stopPropagation() |
| 21 | + this.onInputChange() |
| 22 | + }) |
96 | 23 |
|
| 24 | + this.control = this.theme.getFormControl(this.label, this.input, this.description, this.infoButton) |
| 25 | + this.container.appendChild(this.control) |
| 26 | + this.control.appendChild(this.selectInput) |
97 | 27 | } |
98 | 28 |
|
99 | 29 | postBuild() { |
100 | | - super.postBuild(); |
101 | | - this.initSelectize(); |
102 | | - this.theme.afterInputReady(this.input); |
103 | | - } |
104 | | - |
105 | | - hasThumbnailPreview(item) { |
106 | | - return (item && item.extraMetadata && item.extraMetadata.thumbnail) |
| 30 | + super.postBuild() |
| 31 | + this.initSelect2() |
| 32 | + this.theme.afterInputReady(this.input) |
107 | 33 | } |
108 | 34 |
|
109 | | - hasImageExtension (path) { |
| 35 | + hasImageExtension(path) { |
110 | 36 | if (typeof path !== 'string') { |
111 | 37 | throw 'path is not a string!' |
112 | 38 | } |
113 | 39 |
|
114 | | - var imageExtensions = ['jpg', 'jpeg', 'gif', 'svg', 'png', 'bmp'] |
| 40 | + const imageExtensions = ['jpg', 'jpeg', 'gif', 'svg', 'png', 'bmp'].map(ext => ext.toLowerCase()) |
| 41 | + const extension = path.split('.').pop().toLowerCase() |
| 42 | + |
| 43 | + return imageExtensions.includes(extension) |
| 44 | + } |
| 45 | + |
| 46 | + initSelect2() { |
| 47 | + this.destroySelect2() |
| 48 | + this.searchUrl = this.schema?.searchUrl || '/filemanager/api/search' |
| 49 | + this.streamUrl = this.schema?.streamUrl || '/filemanager/api/stream' |
| 50 | + |
| 51 | + this.select2instance = $(this.selectInput).select2({ |
| 52 | + theme: 'krajee-bs3', |
| 53 | + ajax: { |
| 54 | + cache: true, |
| 55 | + url: this.searchUrl, |
| 56 | + dataType: 'json', |
| 57 | + delay: 250, |
| 58 | + data: (params) => ({ |
| 59 | + q: params.term, |
| 60 | + page: params.page || 0 // Send the page number to the server |
| 61 | + }), |
| 62 | + processResults: (data, params) => { |
| 63 | + params.page = params.page || 0 |
| 64 | + |
| 65 | + return { |
| 66 | + results: data.results.map(item => ({ |
| 67 | + id: item.fullPath |
| 68 | + })), |
| 69 | + pagination: { |
| 70 | + more: data.pagination.more // Indicate if there are more results https://select2.org/data-sources/ajax#pagination |
| 71 | + } |
| 72 | + } |
| 73 | + } |
| 74 | + }, |
| 75 | + error: (jqXHR, textStatus, errorThrown) => { |
| 76 | + console.error('AJAX error:', textStatus, errorThrown) |
| 77 | + }, |
| 78 | + placeholder: 'Search for a file...', |
| 79 | + allowClear: true, |
| 80 | + debug: true, |
| 81 | + minimumInputLength: 0, |
| 82 | + templateResult: (item) => { |
| 83 | + if (item.loading) return item.id |
| 84 | + if (this.hasImageExtension(item.id)) { |
| 85 | + return $(`<span><img src='${this.streamUrl}?path=${item.id}' style='max-width: 70px; max-height: 70px;' /> ${item.id}</span>`) |
| 86 | + } |
| 87 | + return $(`<span><i class='fa fa-file' style='font-size: 50px;'></i> ${item.id}</span>`) |
| 88 | + }, |
| 89 | + templateSelection: (item) => { |
| 90 | + if (!item.id) { |
| 91 | + return item.text; |
| 92 | + } |
115 | 93 |
|
116 | | - imageExtensions = imageExtensions.map(extension => { |
117 | | - return extension.toLowerCase() |
| 94 | + if (item.id && this.hasImageExtension(item.id)) { |
| 95 | + return $(`<span><img src='${this.streamUrl}?path=${item.id}' style='max-width: 20px; max-height: 20px;' /> ${item.id}</span>`) |
| 96 | + } |
| 97 | + return $(`<span><i class='fa fa-file'></i> ${item.id}</span>`) |
| 98 | + }, |
| 99 | + escapeMarkup: (markup) => markup |
118 | 100 | }) |
119 | 101 |
|
120 | | - var extension = path.split('.').pop().toLowerCase() |
121 | | - |
122 | | - return (imageExtensions.indexOf(extension) !== -1) |
123 | | - } |
124 | | - |
125 | | - initSelectize() { |
126 | | - var self = this; |
127 | | - this.destroySelectize(); |
128 | | - this.searchUrl = '/filemanager/api/search'; |
129 | | - this.streamUrl = '/filemanager/api/stream'; |
130 | | - |
131 | | - if (this.schema && this.schema.searchUrl) { |
132 | | - this.searchUrl = this.schema.searchUrl; |
133 | | - } |
134 | | - |
135 | | - if (this.schema && this.schema.streamUrl) { |
136 | | - this.streamUrl = this.schema.streamUrl; |
137 | | - } |
| 102 | + this.select2instance.on('select2:select', (e) => { |
| 103 | + this.input.value = e.params.data.id |
| 104 | + this.onInputChange() |
| 105 | + }) |
138 | 106 |
|
139 | | - var firstLoad = false; |
| 107 | + this.select2instance.on('select2:clear', (e) => { |
| 108 | + this.input.value = '' |
| 109 | + this.onInputChange() |
140 | 110 |
|
141 | | - this.selectize = $(this.input).selectize({ |
142 | | - valueField: 'fullPath', |
143 | | - labelField: 'name', |
144 | | - searchField: 'name', |
145 | | - placeholder: 'Search for a file...', |
146 | | - maxItems: 1, |
147 | | - plugins: ['remove_button'], |
148 | | - preload: false, |
149 | | - options: [], |
150 | | - create: true, |
151 | | - persist: false, |
152 | | - render: { |
153 | | - item: function (item, escape) { |
154 | | - if (self.hasImageExtension(item.fullPath)) { |
155 | | - return '<div class="" style="height: 70px">' + |
156 | | - '<img class="pull-left img-responsive" alt="flysystem image" style="max-width: 100px; max-height: 70px" src="' + escape(self.streamUrl) + '?path=' + escape(item.fullPath) + '" />' + |
157 | | - '<span class="">' + escape(item.name) + '</span><br/>' + |
158 | | - '</div>'; |
159 | | - } |
| 111 | + setTimeout(() => { |
| 112 | + this.select2instance.select2('close'); |
| 113 | + }) |
| 114 | + }) |
160 | 115 |
|
161 | | - return '<span><i class="fa fa-file"></i> ' + escape(item.name) + '</span>'; |
162 | | - }, |
163 | | - option: function (item, escape) { |
164 | | - if (self.hasThumbnailPreview(item)) { |
165 | | - return '<div class="col-xs-6 col-sm-4 col-md-3 col-lg-2" style="height: 150px">' + |
166 | | - '<img class="img-responsive" alt="flysystem image" style="max-height: 100px" src="' + escape(item.extraMetadata.thumbnail) + '" />' + |
167 | | - '<span class="">' + escape(item.name) + '</span>' + |
168 | | - '</div>'; |
169 | | - } |
| 116 | + this.setOption(this.input.value) |
| 117 | + } |
170 | 118 |
|
171 | | - return '<span><i class="fa fa-file"> ' + escape(item.name) + '</span>'; |
172 | | - } |
173 | | - }, |
174 | | - onLoad: function () { |
175 | | - var selectize = this |
176 | | - setTimeout(function () { |
177 | | - selectize.open() |
178 | | - }, 0) |
179 | | - }, |
180 | | - load: function (query, callback) { |
181 | | - var selectize = this; |
182 | | - $.ajax({ |
183 | | - url: self.searchUrl, |
184 | | - type: 'GET', |
185 | | - dataType: 'json', |
186 | | - data: { |
187 | | - q: query |
188 | | - }, |
189 | | - error: function (e) { |
190 | | - console.log('error', e) |
191 | | - }, |
192 | | - success: function (data) { |
193 | | - callback(data); |
194 | | - if (!firstLoad) { |
195 | | - selectize.setValue(self.input.value); |
196 | | - firstLoad = true; |
197 | | - self.onInputChange(); |
198 | | - } |
199 | | - } |
200 | | - }); |
201 | | - }, |
202 | | - onChange: function () { |
203 | | - self.input.value = this.getValue(); |
204 | | - self.onInputChange(); |
205 | | - } |
206 | | - }); |
| 119 | + setOption(value) { |
| 120 | + const option = new Option(value, value, true, true) |
| 121 | + $(this.selectInput).append(option) |
207 | 122 | } |
208 | 123 |
|
209 | 124 | onInputChange() { |
210 | | - this.value = this.input.value; |
211 | | - this.onChange(true); |
212 | | - } |
| 125 | + this.value = this.select2instance.val() |
213 | 126 |
|
214 | | - enable() { |
215 | | - if (!this.always_disabled) { |
216 | | - this.input.disabled = false; |
217 | | - if (this.selectize) { |
218 | | - this.selectize[0].selectize.unlock(); |
219 | | - } |
220 | | - super.enable(); |
| 127 | + if (this.value !== '') { |
| 128 | + this.setOption(this.value) |
221 | 129 | } |
222 | | - } |
223 | 130 |
|
224 | | - disable(always_disabled) { |
225 | | - if (always_disabled) this.always_disabled = true; |
226 | | - this.input.disabled = true; |
227 | | - if (this.selectize) { |
228 | | - this.selectize[0].selectize.lock(); |
229 | | - } |
230 | | - super.disable(); |
| 131 | + this.onChange(true) |
231 | 132 | } |
232 | 133 |
|
233 | 134 | destroy() { |
234 | | - this.destroySelectize(); |
235 | | - if (this.label && this.label.parentNode) this.label.parentNode.removeChild(this.label); |
236 | | - if (this.description && this.description.parentNode) this.description.parentNode.removeChild(this.description); |
237 | | - if (this.input && this.input.parentNode) this.input.parentNode.removeChild(this.input); |
238 | | - super.destroy(); |
| 135 | + this.destroySelect2() |
| 136 | + if (this.label && this.label.parentNode) this.label.parentNode.removeChild(this.label) |
| 137 | + if (this.description && this.description.parentNode) this.description.parentNode.removeChild(this.description) |
| 138 | + if (this.input && this.input.parentNode) this.input.parentNode.removeChild(this.input) |
| 139 | + super.destroy() |
239 | 140 | } |
240 | 141 |
|
241 | | - destroySelectize() { |
242 | | - if (this.selectize) { |
243 | | - this.selectize[0].selectize.destroy(); |
244 | | - this.selectize = null; |
| 142 | + destroySelect2() { |
| 143 | + if ($(this.input).data('select2')) { |
| 144 | + $(this.input).select2('destroy') |
245 | 145 | } |
246 | 146 | } |
247 | 147 | } |
248 | 148 |
|
249 | | -JSONEditor.defaults.editors.flysystem = FlysystemEditor; |
| 149 | +JSONEditor.defaults.editors.flysystem = FlysystemEditor |
250 | 150 |
|
251 | | -// Make it compatible with old widgets |
252 | 151 | JSONEditor.defaults.resolvers.unshift(function (schema) { |
253 | | - if (schema.type === "string" && schema.format === "flysystem") { |
254 | | - return "flysystem"; |
| 152 | + if (schema.type === 'string' && schema.format === 'flysystem') { |
| 153 | + return 'flysystem' |
255 | 154 | } |
256 | | -}); |
| 155 | +}) |
0 commit comments