]> git.proxmox.com Git - pve-manager.git/blob - www/manager6/form/TagEdit.js
ui: eslint auto-fixes
[pve-manager.git] / www / manager6 / form / TagEdit.js
1 Ext.define('PVE.panel.TagEditContainer', {
2 extend: 'Ext.container.Container',
3 alias: 'widget.pveTagEditContainer',
4
5 layout: {
6 type: 'hbox',
7 align: 'middle',
8 },
9
10 controller: {
11 xclass: 'Ext.app.ViewController',
12
13 loadTags: function(tagstring = '', force = false) {
14 let me = this;
15 let view = me.getView();
16
17 if (me.oldTags === tagstring && !force) {
18 return;
19 }
20
21 view.suspendLayout = true;
22 me.forEachTag((tag) => {
23 view.remove(tag);
24 });
25 me.getViewModel().set('tagCount', 0);
26 let newtags = tagstring.split(/[;, ]/).filter((t) => !!t) || [];
27 newtags.forEach((tag) => {
28 me.addTag(tag);
29 });
30 me.updateFilter();
31 view.suspendLayout = false;
32 view.updateLayout();
33 if (!force) {
34 me.oldTags = tagstring;
35 }
36 },
37
38 onRender: function(v) {
39 let me = this;
40 let view = me.getView();
41 view.toggleCls('hide-handles', PVE.Utils.shouldSortTags());
42
43 view.dragzone = Ext.create('Ext.dd.DragZone', v.getEl(), {
44 getDragData: function(e) {
45 let source = e.getTarget('.handle');
46 if (!source) {
47 return undefined;
48 }
49 let sourceId = source.parentNode.id;
50 let cmp = Ext.getCmp(sourceId);
51 let ddel = document.createElement('div');
52 ddel.classList.add('proxmox-tags-full');
53 ddel.innerHTML = Proxmox.Utils.getTagElement(cmp.tag, PVE.Utils.tagOverrides);
54 let repairXY = Ext.fly(source).getXY();
55 cmp.setDisabled(true);
56 ddel.id = Ext.id();
57 return {
58 ddel,
59 repairXY,
60 sourceId,
61 };
62 },
63 onMouseUp: function(target, e, id) {
64 let cmp = Ext.getCmp(this.dragData.sourceId);
65 if (cmp && !cmp.isDestroyed) {
66 cmp.setDisabled(false);
67 }
68 },
69 getRepairXY: function() {
70 return this.dragData.repairXY;
71 },
72 beforeInvalidDrop: function(target, e, id) {
73 let cmp = Ext.getCmp(this.dragData.sourceId);
74 if (cmp && !cmp.isDestroyed) {
75 cmp.setDisabled(false);
76 }
77 },
78 });
79 view.dropzone = Ext.create('Ext.dd.DropZone', v.getEl(), {
80 getTargetFromEvent: function(e) {
81 return e.getTarget('.proxmox-tag-dark,.proxmox-tag-light');
82 },
83 getIndicator: function() {
84 if (!view.indicator) {
85 view.indicator = Ext.create('Ext.Component', {
86 floating: true,
87 html: '<i class="fa fa-long-arrow-up"></i>',
88 hidden: true,
89 shadow: false,
90 });
91 }
92 return view.indicator;
93 },
94 onContainerOver: function() {
95 this.getIndicator().setVisible(false);
96 },
97 notifyOut: function() {
98 this.getIndicator().setVisible(false);
99 },
100 onNodeOver: function(target, dd, e, data) {
101 let indicator = this.getIndicator();
102 indicator.setVisible(true);
103 indicator.alignTo(Ext.getCmp(target.id), 't50-bl', [-1, -2]);
104 return this.dropAllowed;
105 },
106 onNodeDrop: function(target, dd, e, data) {
107 this.getIndicator().setVisible(false);
108 let sourceCmp = Ext.getCmp(data.sourceId);
109 if (!sourceCmp) {
110 return;
111 }
112 sourceCmp.setDisabled(false);
113 let targetCmp = Ext.getCmp(target.id);
114 view.remove(sourceCmp, { destroy: false });
115 view.insert(view.items.indexOf(targetCmp), sourceCmp);
116 },
117 });
118 },
119
120 forEachTag: function(func) {
121 let me = this;
122 let view = me.getView();
123 view.items.each((field) => {
124 if (field.getXType() === 'pveTag') {
125 func(field);
126 }
127 return true;
128 });
129 },
130
131 toggleEdit: function(cancel) {
132 let me = this;
133 let vm = me.getViewModel();
134 let view = me.getView();
135 let editMode = !vm.get('editMode');
136 vm.set('editMode', editMode);
137
138 // get a current tag list for editing
139 if (editMode) {
140 PVE.Utils.updateUIOptions();
141 }
142
143 me.forEachTag((tag) => {
144 tag.setMode(editMode ? 'editable' : 'normal');
145 });
146
147 if (!vm.get('editMode')) {
148 let tags = [];
149 if (cancel) {
150 me.loadTags(me.oldTags, true);
151 } else {
152 let toRemove = [];
153 me.forEachTag((cmp) => {
154 if (cmp.isVisible() && cmp.tag) {
155 tags.push(cmp.tag);
156 } else {
157 toRemove.push(cmp);
158 }
159 });
160 toRemove.forEach(cmp => view.remove(cmp));
161 tags = tags.join(',');
162 if (me.oldTags !== tags) {
163 me.oldTags = tags;
164 me.loadTags(tags, true);
165 me.getView().fireEvent('change', tags);
166 }
167 }
168 }
169 me.getView().updateLayout();
170 },
171
172 updateFilter: function() {
173 let me = this;
174 let tags = [];
175 me.forEachTag(cmp => {
176 if (cmp.tag) {
177 tags.push(cmp.tag);
178 }
179 });
180 me.forEachTag(cmp => {
181 cmp.updateFilter(tags);
182 });
183 },
184
185 addTag: function(tag, isNew) {
186 let me = this;
187 let view = me.getView();
188 let vm = me.getViewModel();
189 let index = view.items.length - 5;
190 if (PVE.Utils.shouldSortTags() && !isNew) {
191 index = view.items.findIndexBy(tagField => {
192 if (tagField.reference === 'noTagsField') {
193 return false;
194 }
195 if (tagField.xtype !== 'pveTag') {
196 return true;
197 }
198 let a = tagField.tag.toLowerCase();
199 let b = tag.toLowerCase();
200 return a > b ? true : a < b ? false : tagField.tag.localeCompare(tag) > 0;
201 }, 1);
202 }
203 let tagField = view.insert(index, {
204 xtype: 'pveTag',
205 tag,
206 mode: vm.get('editMode') ? 'editable' : 'normal',
207 listeners: {
208 change: (field, newTag) => {
209 me.updateFilter();
210 },
211 destroy: function() {
212 vm.set('tagCount', vm.get('tagCount') - 1);
213 },
214 },
215 });
216
217 if (isNew) {
218 me.updateFilter();
219 tagField.selectText();
220 }
221
222 vm.set('tagCount', vm.get('tagCount') + 1);
223 },
224
225 addTagClick: function(event) {
226 let me = this;
227 me.lookup('noTagsField').setVisible(false);
228 me.addTag('', true);
229 },
230
231 cancelClick: function() {
232 this.toggleEdit(true);
233 },
234
235 editClick: function() {
236 this.toggleEdit(false);
237 },
238
239 init: function(view) {
240 let me = this;
241 if (view.tags) {
242 me.loadTags(view.tags);
243 }
244
245 me.mon(Ext.GlobalEvents, 'loadedUiOptions', () => {
246 view.toggleCls('hide-handles', PVE.Utils.shouldSortTags());
247 me.loadTags(me.oldTags, true); // refresh tag colors and order
248 });
249 },
250 },
251
252 viewModel: {
253 data: {
254 tagCount: 0,
255 editMode: false,
256 },
257
258 formulas: {
259 hideNoTags: function(get) {
260 return get('tagCount') !== 0;
261 },
262 },
263 },
264
265 loadTags: function() {
266 return this.getController().loadTags(...arguments);
267 },
268
269 items: [
270 {
271 xtype: 'box',
272 reference: 'noTagsField',
273 bind: {
274 hidden: '{hideNoTags}',
275 },
276 html: gettext('No Tags'),
277 },
278 {
279 xtype: 'button',
280 iconCls: 'fa fa-plus',
281 tooltip: gettext('Add Tag'),
282 bind: {
283 hidden: '{!editMode}',
284 },
285 hidden: true,
286 margin: '0 8 0 5',
287 ui: 'default-toolbar',
288 handler: 'addTagClick',
289 },
290 {
291 xtype: 'tbseparator',
292 ui: 'horizontal',
293 bind: {
294 hidden: '{!editMode}',
295 },
296 hidden: true,
297 },
298 {
299 xtype: 'button',
300 iconCls: 'fa fa-times',
301 tooltip: gettext('Cancel Edit'),
302 bind: {
303 hidden: '{!editMode}',
304 },
305 hidden: true,
306 margin: '0 5 0 0',
307 ui: 'default-toolbar',
308 handler: 'cancelClick',
309 },
310 {
311 xtype: 'button',
312 iconCls: 'fa fa-check',
313 tooltip: gettext('Finish Edit'),
314 bind: {
315 hidden: '{!editMode}',
316 },
317 hidden: true,
318 ui: 'default-toolbar',
319 handler: 'editClick',
320 },
321 {
322 xtype: 'box',
323 cls: 'pve-tag-inline-button',
324 html: `<i data-qtip="${gettext('Edit Tags')}" class="fa fa-pencil"></i>`,
325 bind: {
326 hidden: '{editMode}',
327 },
328 listeners: {
329 click: 'editClick',
330 element: 'el',
331 },
332 },
333 ],
334
335 listeners: {
336 render: 'onRender',
337 },
338
339 destroy: function() {
340 let me = this;
341 Ext.destroy(me.dragzone);
342 Ext.destroy(me.dropzone);
343 Ext.destroy(me.indicator);
344 me.callParent();
345 },
346 });