14 callLoad: L.rpc.declare({
18 expect: { values: { } }
21 callOrder: L.rpc.declare({
24 params: [ 'config', 'sections' ]
27 callAdd: L.rpc.declare({
30 params: [ 'config', 'type', 'name', 'values' ],
31 expect: { section: '' }
34 callSet: L.rpc.declare({
37 params: [ 'config', 'section', 'values' ]
40 callDelete: L.rpc.declare({
43 params: [ 'config', 'section', 'options' ]
46 callApply: L.rpc.declare({
49 params: [ 'timeout', 'rollback' ]
52 callConfirm: L.rpc.declare({
57 createSID: function(conf)
59 var v = this.state.values;
60 var n = this.state.creates;
64 sid = "new%06x".format(Math.random() * 0xFFFFFF);
65 } while ((n[conf] && n[conf][sid]) || (v[conf] && v[conf][sid]));
70 reorderSections: function()
72 var v = this.state.values;
73 var n = this.state.creates;
74 var r = this.state.reorder;
76 if ($.isEmptyObject(r))
77 return L.deferrable();
82 gather all created and existing sections, sort them according
83 to their index value and issue an uci order call
98 o.sort(function(a, b) {
99 return (a['.index'] - b['.index']);
104 for (var i = 0; i < o.length; i++)
105 sids.push(o[i]['.name']);
107 this.callOrder(c, sids);
111 this.state.reorder = { };
112 return L.rpc.flush();
115 load: function(packages)
121 if (!$.isArray(packages))
122 packages = [ packages ];
126 for (var i = 0; i < packages.length; i++)
127 if (!seen[packages[i]] && !self.state.values[packages[i]])
129 pkgs.push(packages[i]);
130 seen[packages[i]] = true;
131 self.callLoad(packages[i]);
134 return L.rpc.flush().then(function(responses) {
135 for (var i = 0; i < responses.length; i++)
136 self.state.values[pkgs[i]] = responses[i];
142 unload: function(packages)
144 if (!$.isArray(packages))
145 packages = [ packages ];
147 for (var i = 0; i < packages.length; i++)
149 delete this.state.values[packages[i]];
150 delete this.state.creates[packages[i]];
151 delete this.state.changes[packages[i]];
152 delete this.state.deletes[packages[i]];
156 add: function(conf, type, name)
158 var n = this.state.creates;
159 var sid = name || this.createSID(conf);
169 '.index': 1000 + this.state.newidx++
175 remove: function(conf, sid)
177 var n = this.state.creates;
178 var c = this.state.changes;
179 var d = this.state.deletes;
181 /* requested deletion of a just created section */
182 if (n[conf] && n[conf][sid])
198 sections: function(conf, type, cb)
201 var v = this.state.values[conf];
202 var n = this.state.creates[conf];
203 var c = this.state.changes[conf];
204 var d = this.state.deletes[conf];
210 if (!d || d[s] !== true)
211 if (!type || v[s]['.type'] == type)
212 sa.push($.extend({ }, v[s], c ? c[s] : undefined));
216 if (!type || n[s]['.type'] == type)
219 sa.sort(function(a, b) {
220 return a['.index'] - b['.index'];
223 for (var i = 0; i < sa.length; i++)
226 if (typeof(cb) == 'function')
227 for (var i = 0; i < sa.length; i++)
228 cb.call(this, sa[i], sa[i]['.name']);
233 get: function(conf, sid, opt)
235 var v = this.state.values;
236 var n = this.state.creates;
237 var c = this.state.changes;
238 var d = this.state.deletes;
240 if (typeof(sid) == 'undefined')
243 /* requested option in a just created section */
244 if (n[conf] && n[conf][sid])
249 if (typeof(opt) == 'undefined')
252 return n[conf][sid][opt];
255 /* requested an option value */
256 if (typeof(opt) != 'undefined')
258 /* check whether option was deleted */
259 if (d[conf] && d[conf][sid])
261 if (d[conf][sid] === true)
264 for (var i = 0; i < d[conf][sid].length; i++)
265 if (d[conf][sid][i] == opt)
269 /* check whether option was changed */
270 if (c[conf] && c[conf][sid] && typeof(c[conf][sid][opt]) != 'undefined')
271 return c[conf][sid][opt];
273 /* return base value */
274 if (v[conf] && v[conf][sid])
275 return v[conf][sid][opt];
280 /* requested an entire section */
287 set: function(conf, sid, opt, val)
289 var v = this.state.values;
290 var n = this.state.creates;
291 var c = this.state.changes;
292 var d = this.state.deletes;
294 if (typeof(sid) == 'undefined' ||
295 typeof(opt) == 'undefined' ||
296 opt.charAt(0) == '.')
299 if (n[conf] && n[conf][sid])
301 if (typeof(val) != 'undefined')
302 n[conf][sid][opt] = val;
304 delete n[conf][sid][opt];
306 else if (typeof(val) != 'undefined')
308 /* do not set within deleted section */
309 if (d[conf] && d[conf][sid] === true)
312 /* only set in existing sections */
313 if (!v[conf] || !v[conf][sid])
322 /* undelete option */
323 if (d[conf] && d[conf][sid])
324 d[conf][sid] = L.filterArray(d[conf][sid], opt);
326 c[conf][sid][opt] = val;
330 /* only delete in existing sections */
331 if (!v[conf] || !v[conf][sid])
340 if (d[conf][sid] !== true)
341 d[conf][sid].push(opt);
345 unset: function(conf, sid, opt)
347 return this.set(conf, sid, opt, undefined);
350 get_first: function(conf, type, opt)
354 L.uci.sections(conf, type, function(s) {
355 if (typeof(sid) != 'string')
359 return this.get(conf, sid, opt);
362 set_first: function(conf, type, opt, val)
366 L.uci.sections(conf, type, function(s) {
367 if (typeof(sid) != 'string')
371 return this.set(conf, sid, opt, val);
374 unset_first: function(conf, type, opt)
376 return this.set_first(conf, type, opt, undefined);
379 swap: function(conf, sid1, sid2)
381 var s1 = this.get(conf, sid1);
382 var s2 = this.get(conf, sid2);
383 var n1 = s1 ? s1['.index'] : NaN;
384 var n2 = s2 ? s2['.index'] : NaN;
386 if (isNaN(n1) || isNaN(n2))
392 this.state.reorder[conf] = true;
401 var v = this.state.values;
402 var n = this.state.creates;
403 var c = this.state.changes;
404 var d = this.state.deletes;
413 for (var sid in n[conf])
420 for (var k in n[conf][sid])
423 r.type = n[conf][sid][k];
424 else if (k == '.create')
425 r.name = n[conf][sid][k];
426 else if (k.charAt(0) != '.')
427 r.values[k] = n[conf][sid][k];
430 snew.push(n[conf][sid]);
432 self.callAdd(r.config, r.type, r.name, r.values);
441 for (var sid in c[conf])
442 self.callSet(conf, sid, c[conf][sid]);
450 for (var sid in d[conf])
452 var o = d[conf][sid];
453 self.callDelete(conf, sid, (o === true) ? undefined : o);
459 return L.rpc.flush().then(function(responses) {
461 array "snew" holds references to the created uci sections,
462 use it to assign the returned names of the new sections
464 for (var i = 0; i < snew.length; i++)
465 snew[i]['.name'] = responses[i];
467 return self.reorderSections();
469 pkgs = L.toArray(pkgs);
473 return self.load(pkgs);
477 apply: function(timeout)
480 var date = new Date();
481 var deferred = $.Deferred();
483 if (typeof(timeout) != 'number' || timeout < 1)
486 self.callApply(timeout, true).then(function(rv) {
489 deferred.rejectWith(self, [ rv ]);
493 var try_deadline = date.getTime() + 1000 * timeout;
494 var try_confirm = function()
496 return self.callConfirm().then(function(rv) {
499 if (date.getTime() < try_deadline)
500 window.setTimeout(try_confirm, 250);
502 deferred.rejectWith(self, [ rv ]);
507 deferred.resolveWith(self, [ rv ]);
511 window.setTimeout(try_confirm, 1000);
517 changes: L.rpc.declare({
520 expect: { changes: { } }
523 readable: function(conf)
525 return L.session.hasACL('uci', conf, 'read');
528 writable: function(conf)
530 return L.session.hasACL('uci', conf, 'write');