]> git.proxmox.com Git - proxmox-widget-toolkit.git/blob - window/Edit.js
e258e49271bf1c1d5a171bb620adc56abdb5ea6b
[proxmox-widget-toolkit.git] / window / Edit.js
1 // fixme: how can we avoid those lint errors?
2 /*jslint confusion: true */
3 Ext.define('Proxmox.window.Edit', {
4 extend: 'Ext.window.Window',
5 alias: 'widget.proxmoxWindowEdit',
6
7 // autoLoad trigger a load() after component creation
8 autoLoad: false,
9
10 resizable: false,
11
12 // use this tio atimatically generate a title like
13 // Create: <subject>
14 subject: undefined,
15
16 // set isCreate to true if you want a Create button (instead
17 // OK and RESET)
18 isCreate: false,
19
20 // set to true if you want an Add button (instead of Create)
21 isAdd: false,
22
23 // set to true if you want an Remove button (instead of Create)
24 isRemove: false,
25
26 // custom submitText
27 submitText: undefined,
28
29 backgroundDelay: 0,
30
31 // needed for finding the reference to submitbutton
32 // because we do not have a controller
33 referenceHolder: true,
34 defaultButton: 'submitbutton',
35
36 // finds the first form field
37 defaultFocus: 'field[disabled=false][hidden=false]',
38
39 showProgress: false,
40
41 showTaskViewer: false,
42
43 // gets called if we have a progress bar or taskview and it detected that
44 // the task finished. function(success)
45 taskDone: Ext.emptyFn,
46
47 // gets called when the api call is finished, right at the beginning
48 // function(success, response, options)
49 apiCallDone: Ext.emptyFn,
50
51 // assign a reference from docs, to add a help button docked to the
52 // bottom of the window. If undefined we magically fall back to the
53 // onlineHelp of our first item, if set.
54 onlineHelp: undefined,
55
56 isValid: function() {
57 let me = this;
58
59 let form = me.formPanel.getForm();
60 return form.isValid();
61 },
62
63 getValues: function(dirtyOnly) {
64 let me = this;
65
66 let values = {};
67
68 let form = me.formPanel.getForm();
69
70 form.getFields().each(function(field) {
71 if (!field.up('inputpanel') && (!dirtyOnly || field.isDirty())) {
72 Proxmox.Utils.assemble_field_data(values, field.getSubmitData());
73 }
74 });
75
76 Ext.Array.each(me.query('inputpanel'), function(panel) {
77 Proxmox.Utils.assemble_field_data(values, panel.getValues(dirtyOnly));
78 });
79
80 return values;
81 },
82
83 setValues: function(values) {
84 let me = this;
85
86 let form = me.formPanel.getForm();
87 let formfields = form.getFields();
88
89 Ext.iterate(values, function(id, val) {
90 let fields = formfields.filterBy((f) =>
91 (f.id === id || f.name === id || f.dataIndex === id) && !f.up('inputpanel'),
92 );
93 fields.each((field) => {
94 field.setValue(val);
95 if (form.trackResetOnLoad) {
96 field.resetOriginalValue();
97 }
98 });
99 });
100
101 Ext.Array.each(me.query('inputpanel'), function(panel) {
102 panel.setValues(values);
103 });
104 },
105
106 setSubmitText: function(text) {
107 this.lookup('submitbutton').setText(text);
108 },
109
110 submit: function() {
111 let me = this;
112
113 let form = me.formPanel.getForm();
114
115 let values = me.getValues();
116 Ext.Object.each(values, function(name, val) {
117 if (Object.prototype.hasOwnProperty.call(values, name)) {
118 if (Ext.isArray(val) && !val.length) {
119 values[name] = '';
120 }
121 }
122 });
123
124 if (me.digest) {
125 values.digest = me.digest;
126 }
127
128 if (me.backgroundDelay) {
129 values.background_delay = me.backgroundDelay;
130 }
131
132 let url = me.url;
133 if (me.method === 'DELETE') {
134 url = url + "?" + Ext.Object.toQueryString(values);
135 values = undefined;
136 }
137
138 Proxmox.Utils.API2Request({
139 url: url,
140 waitMsgTarget: me,
141 method: me.method || (me.backgroundDelay ? 'POST' : 'PUT'),
142 params: values,
143 failure: function(response, options) {
144 me.apiCallDone(false, response, options);
145
146 if (response.result && response.result.errors) {
147 form.markInvalid(response.result.errors);
148 }
149 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
150 },
151 success: function(response, options) {
152 let hasProgressBar =
153 (me.backgroundDelay || me.showProgress || me.showTaskViewer) &&
154 response.result.data;
155
156 me.apiCallDone(true, response, options);
157
158 if (hasProgressBar) {
159 // stay around so we can trigger our close events
160 // when background action is completed
161 me.hide();
162
163 let upid = response.result.data;
164 let viewerClass = me.showTaskViewer ? 'Viewer' : 'Progress';
165 Ext.create('Proxmox.window.Task' + viewerClass, {
166 autoShow: true,
167 upid: upid,
168 taskDone: me.taskDone,
169 listeners: {
170 destroy: function() {
171 me.close();
172 },
173 },
174 });
175 } else {
176 me.close();
177 }
178 },
179 });
180 },
181
182 load: function(options) {
183 let me = this;
184
185 let form = me.formPanel.getForm();
186
187 options = options || {};
188
189 let newopts = Ext.apply({
190 waitMsgTarget: me,
191 }, options);
192
193 let createWrapper = function(successFn) {
194 Ext.apply(newopts, {
195 url: me.url,
196 method: 'GET',
197 success: function(response, opts) {
198 form.clearInvalid();
199 me.digest = response.result.digest || response.result.data.digest;
200 if (successFn) {
201 successFn(response, opts);
202 } else {
203 me.setValues(response.result.data);
204 }
205 // hack: fix ExtJS bug
206 Ext.Array.each(me.query('radiofield'), function(f) {
207 f.resetOriginalValue();
208 });
209 },
210 failure: function(response, opts) {
211 Ext.Msg.alert(gettext('Error'), response.htmlStatus, function() {
212 me.close();
213 });
214 },
215 });
216 };
217
218 createWrapper(options.success);
219
220 Proxmox.Utils.API2Request(newopts);
221 },
222
223 initComponent: function() {
224 let me = this;
225
226 if (!me.url) {
227 throw "no url specified";
228 }
229
230 if (me.create) {throw "deprecated parameter, use isCreate";}
231
232 let items = Ext.isArray(me.items) ? me.items : [me.items];
233
234 me.items = undefined;
235
236 me.formPanel = Ext.create('Ext.form.Panel', {
237 url: me.url,
238 method: me.method || 'PUT',
239 trackResetOnLoad: true,
240 bodyPadding: me.bodyPadding !== undefined ? me.bodyPadding : 10,
241 border: false,
242 defaults: Ext.apply({}, me.defaults, {
243 border: false,
244 }),
245 fieldDefaults: Ext.apply({}, me.fieldDefaults, {
246 labelWidth: 100,
247 anchor: '100%',
248 }),
249 items: items,
250 });
251
252 let inputPanel = me.formPanel.down('inputpanel');
253
254 let form = me.formPanel.getForm();
255
256 let submitText;
257 if (me.isCreate) {
258 if (me.submitText) {
259 submitText = me.submitText;
260 } else if (me.isAdd) {
261 submitText = gettext('Add');
262 } else if (me.isRemove) {
263 submitText = gettext('Remove');
264 } else {
265 submitText = gettext('Create');
266 }
267 } else {
268 submitText = me.submitText || gettext('OK');
269 }
270
271 let submitBtn = Ext.create('Ext.Button', {
272 reference: 'submitbutton',
273 text: submitText,
274 disabled: !me.isCreate,
275 handler: function() {
276 me.submit();
277 },
278 });
279
280 let resetBtn = Ext.create('Ext.Button', {
281 text: 'Reset',
282 disabled: true,
283 handler: function() {
284 form.reset();
285 },
286 });
287
288 let set_button_status = function() {
289 let valid = form.isValid();
290 let dirty = form.isDirty();
291 submitBtn.setDisabled(!valid || !(dirty || me.isCreate));
292 resetBtn.setDisabled(!dirty);
293
294 if (inputPanel && inputPanel.hasAdvanced) {
295 // we want to show the advanced options
296 // as soon as some of it is not valid
297 let advancedItems = me.down('#advancedContainer').query('field');
298 let allAdvancedValid = true;
299 advancedItems.forEach(function(field) {
300 if (!field.isValid()) {
301 allAdvancedValid = false;
302 }
303 });
304
305 if (!allAdvancedValid) {
306 inputPanel.setAdvancedVisible(true);
307 me.down('#advancedcb').setValue(true);
308 }
309 }
310 };
311
312 form.on('dirtychange', set_button_status);
313 form.on('validitychange', set_button_status);
314
315 let colwidth = 300;
316 if (me.fieldDefaults && me.fieldDefaults.labelWidth) {
317 colwidth += me.fieldDefaults.labelWidth - 100;
318 }
319
320 let twoColumn = inputPanel && (inputPanel.column1 || inputPanel.column2);
321
322 if (me.subject && !me.title) {
323 me.title = Proxmox.Utils.dialog_title(me.subject, me.isCreate, me.isAdd);
324 }
325
326 if (me.isCreate) {
327 me.buttons = [submitBtn];
328 } else {
329 me.buttons = [submitBtn, resetBtn];
330 }
331
332 if (inputPanel && inputPanel.hasAdvanced) {
333 let sp = Ext.state.Manager.getProvider();
334 let advchecked = sp.get('proxmox-advanced-cb');
335 inputPanel.setAdvancedVisible(advchecked);
336 me.buttons.unshift(
337 {
338 xtype: 'proxmoxcheckbox',
339 itemId: 'advancedcb',
340 boxLabelAlign: 'before',
341 boxLabel: gettext('Advanced'),
342 stateId: 'proxmox-advanced-cb',
343 value: advchecked,
344 listeners: {
345 change: function(cb, val) {
346 inputPanel.setAdvancedVisible(val);
347 sp.set('proxmox-advanced-cb', val);
348 },
349 },
350 },
351 );
352 }
353
354 let onlineHelp = me.onlineHelp;
355 if (!onlineHelp && inputPanel && inputPanel.onlineHelp) {
356 onlineHelp = inputPanel.onlineHelp;
357 }
358
359 if (onlineHelp) {
360 let helpButton = Ext.create('Proxmox.button.Help');
361 me.buttons.unshift(helpButton, '->');
362 Ext.GlobalEvents.fireEvent('proxmoxShowHelp', onlineHelp);
363 }
364
365 Ext.applyIf(me, {
366 modal: true,
367 width: twoColumn ? colwidth*2 : colwidth,
368 border: false,
369 items: [me.formPanel],
370 });
371
372 me.callParent();
373
374 // always mark invalid fields
375 me.on('afterlayout', function() {
376 // on touch devices, the isValid function
377 // triggers a layout, which triggers an isValid
378 // and so on
379 // to prevent this we disable the layouting here
380 // and enable it afterwards
381 me.suspendLayout = true;
382 me.isValid();
383 me.suspendLayout = false;
384 });
385
386 if (me.autoLoad) {
387 me.load();
388 }
389 },
390 });