luci2: fix package install / removal on button click in system/software view
[project/luci2/ui.git] / luci2 / htdocs / luci2 / view / system.software.js
1 L.ui.view.extend({
2         updateDiskSpace: function()
3         {
4                 return L.system.getDiskInfo().then(function(info) {
5                         $('#package_space').empty().append(
6                                 new L.ui.progress({
7                                         value:  info.root.used / 1024,
8                                         max:    info.root.total / 1024,
9                                         format: '%d ' + L.tr('kB') + ' / %d ' + L.tr('kB') + ' ' + L.trc('Used disk space', 'used') + ' (%d%%)'
10                                 }).render());
11                 });
12         },
13
14         installRemovePackage: function(pkgname, installed)
15         {
16                 var dspname   = pkgname.replace(/^.+\//, '');
17                 var action    = installed ? L.opkg.removePackage : L.opkg.installPackage;
18                 var title     = (installed ? L.tr('Removing package "%s" …') : L.tr('Installing package "%s" …')).format(dspname);
19                 var confirm   = (installed ? L.tr('Really remove package "%h" ?') : L.tr('Really install package "%h" ?')).format(dspname);
20
21                 var self = this;
22
23                 L.ui.dialog(title, confirm, {
24                         style:   'confirm',
25                         confirm: function() {
26                                 L.ui.dialog(title, L.tr('Waiting for package manager …'), { style: 'wait' });
27
28                                 action(pkgname).then(function(res) {
29                                         self.fetchInstalledList().then(function() { return self.fetchPackageList(); }).then(function() {
30                                                 var output = [ ];
31
32                                                 if (res.stdout)
33                                                         output.push($('<pre />').text(res.stdout));
34
35                                                 if (res.stderr)
36                                                         output.push($('<pre />').addClass('alert-message').text(res.stderr));
37
38                                                 output.push(res.code ? L.tr('Package manager failed with status %d.').format(res.code) : L.tr('Package manager finished successfully.'));
39
40                                                 L.ui.dialog(title, output, { style: 'close' });
41
42                                                 if (name)
43                                                         $('#package_url').val('');
44                                         });
45                                 });
46                         }
47                 });
48         },
49
50         fetchInstalledList: function()
51         {
52                 var self = this;
53                 return L.opkg.installedPackages(0, 0, '*').then(function(list) {
54                         self.installedList = { };
55                         for (var i = 0; i < list.length; i++)
56                                 self.installedList[list[i][0]] = true;
57                 });
58         },
59
60         fetchPackageList: function(offset, interactive)
61         {
62                 if (interactive)
63                         L.ui.loading(true);
64
65                 if (typeof(offset) == 'undefined')
66                         offset = parseInt($('#package_filter').attr('offset')) || 0;
67
68                 var pattern = $('#package_filter').val() || '';
69                 var action;
70
71                 if (pattern.length)
72                 {
73                         action = $('#package_which').prop('checked') ? L.opkg.installedPackages : L.opkg.findPackages;
74                         pattern = '*' + pattern + '*';
75
76                         $('#package_filter').next().attr('src', L.globals.resource + '/icons/cbi/remove.gif');
77                 }
78                 else
79                 {
80                         action = $('#package_which').prop('checked') ? L.opkg.installedPackages : L.opkg.listPackages;
81                         pattern = '*';
82
83                         $('#package_filter').next().attr('src', L.globals.resource + '/icons/cbi/find.gif');
84                 }
85
86                 $('#package_filter').attr('offset', offset);
87
88                 var install_disabled = $('#package_install').attr('disabled');
89                 var self = this;
90
91                 return action(offset, 100, pattern).then(function(list) {
92                         var packageTable = new L.ui.table({
93                                 placeholder: L.tr('No matching packages found.'),
94                                 columns: [ {
95                                         caption: L.trc('Package table header', 'Package'),
96                                         key:     0
97                                 }, {
98                                         caption: L.trc('Package table header', 'Version'),
99                                         key:     1,
100                                         format:  function(v) {
101                                                 return (v.length > 15 ? v.substring(0, 14) + '…' : v);
102                                         }
103                                 }, {
104                                         caption: L.trc('Package table header', 'Description'),
105                                         key:     2
106                                 }, {
107                                         caption: L.trc('Package table header', 'Installation Status'),
108                                         key:     0,
109                                         width:   '120px',
110                                         format: function(v, n) {
111                                                 var inst = self.installedList[list[n][0]];
112                                                 return $('<button />')
113                                                         .css('width', '100%')
114                                                         .attr('disabled', install_disabled)
115                                                         .attr('pkgname', list[n][0])
116                                                         .attr('installed', inst)
117                                                         .addClass('cbi-button')
118                                                         .addClass(inst ? 'cbi-button-apply' : 'cbi-button-reset')
119                                                         .text(inst ? L.trc('Package state', 'Installed') : L.trc('Package state', 'Not installed'))
120                                                         .click(function() {
121                                                                 self.installRemovePackage(this.getAttribute('pkgname'), this.getAttribute('installed') == 'true');
122                                                         });
123                                         }
124                                 } ]
125                         });
126
127                         packageTable.rows(list);
128                         packageTable.insertInto('#package_table');
129
130                         if (offset > 0)
131                                 $('#package_prev')
132                                         .attr('offset', offset - 100)
133                                         .attr('disabled', false)
134                                         .val('« %d - %d'.format(offset - 100 + 1, offset));
135                         else
136                                 $('#package_prev')
137                                         .attr('disabled', true)
138                                         .val('« %d - %d'.format(1, Math.min(100, list.total)));
139
140                         if ((offset + 100) < list.total)
141                                 $('#package_next')
142                                         .attr('offset', offset + 100)
143                                         .attr('disabled', false)
144                                         .val('%d - %d »'.format(offset + 100 + 1, Math.min(offset + 200, list.total)));
145                         else
146                                 $('#package_next')
147                                         .attr('disabled', true)
148                                         .val('%d - %d »'.format(list.total - (list.total % 100) + 1, list.total));
149
150                         if (interactive)
151                                 L.ui.loading(false);
152                 }).then(self.updateDiskSpace);
153         },
154
155         execute: function()
156         {
157                 var self = this;
158
159                 $('textarea, input.cbi-button-save').attr('disabled', !this.options.acls.software);
160                 $('#package_update, #package_url, #package_install').attr('disabled', !this.options.acls.software);
161
162                 return $.when(
163                         L.opkg.getConfig().then(function(config) {
164                                 $('textarea')
165                                         .attr('rows', (config.match(/\n/g) || [ ]).length + 1)
166                                         .val(config);
167
168                                 $('input.cbi-button-save')
169                                         .click(function() {
170                                                 var data = ($('textarea').val() || '').replace(/\r/g, '').replace(/\n?$/, '\n');
171                                                 L.ui.loading(true);
172                                                 L.opkg.setConfig(data).then(function() {
173                                                         $('textarea')
174                                                                 .attr('rows', (data.match(/\n/g) || [ ]).length + 1)
175                                                                 .val(data);
176
177                                                         L.ui.loading(false);
178                                                 });
179                                         });
180                         }),
181                         self.fetchInstalledList(),
182                         self.updateDiskSpace()
183                 ).then(function() {
184                         $('#tabs').show().tabs();
185
186                         $('#package_prev, #package_next').click(function(ev) {
187                                 if (!this.getAttribute('disabled'))
188                                 {
189                                         self.fetchPackageList(parseInt(this.getAttribute('offset')), true);
190                                         this.blur();
191                                 }
192                         });
193
194                         $('#package_filter').next().click(function(ev) {
195                                 if (this.getAttribute('src').indexOf('remove.gif') > -1)
196                                         $('#package_filter').val('');
197
198                                 self.fetchPackageList(0, true);
199                         });
200
201                         $('#package_filter').keyup(function(ev) {
202                                 if (ev.which != 13)
203                                         return true;
204
205                                 ev.preventDefault();
206                                 self.fetchPackageList(0, true);
207                                 return false;
208                         });
209
210                         $('#package_which').click(function(ev) {
211                                 this.blur();
212                                 self.fetchPackageList(0, true);
213                         });
214
215                         $('#package_url').keyup(function(ev) {
216                                 if (ev.which != 13)
217                                         return true;
218
219                                 ev.preventDefault();
220
221                                 if (this.value)
222                                         self.installRemovePackage(this.value, false);
223                         });
224
225                         $('#package_install').click(function(ev) {
226                                 var name = $('#package_url').val();
227                                 if (name)
228                                         self.installRemovePackage(name, false);
229                         });
230
231                         $('#package_update').click(function(ev) {
232                                 L.ui.dialog(L.tr('Updating package lists'), L.tr('Waiting for package manager …'), { style: 'wait' });
233                                 L.opkg.updateLists().then(function(res) {
234                                         var output = [ ];
235
236                                         if (res.stdout)
237                                                 output.push($('<pre />').text(res.stdout));
238
239                                         if (res.stderr)
240                                                 output.push($('<pre />').addClass('alert-message').text(res.stderr));
241
242                                         output.push(res.code ? L.tr('Package manager failed with status %d.').format(res.code) : L.tr('Package manager finished successfully.'));
243
244                                         L.ui.dialog(L.tr('Updating package lists'), output, { style: 'close' });
245                                 });
246                         });
247
248                         return self.fetchPackageList(0);
249                 });
250         }
251 });