libs/cbi: implement tabbing to split large sections and group options in tabs
[project/luci.git] / libs / cbi / htdocs / luci-static / resources / cbi.js
1 /*
2         LuCI - Lua Configuration Interface
3
4         Copyright 2008 Steven Barth <steven@midlink.org>
5         Copyright 2008-2009 Jo-Philipp Wich <xm@subsignal.org>
6
7         Licensed under the Apache License, Version 2.0 (the "License");
8         you may not use this file except in compliance with the License.
9         You may obtain a copy of the License at
10
11         http://www.apache.org/licenses/LICENSE-2.0
12
13         $Id$
14 */
15
16 var cbi_d = [];
17 var cbi_t = [];
18
19 function cbi_d_add(field, dep, next) {
20         var obj = document.getElementById(field);
21         if (obj) {
22                 var entry
23                 for (var i=0; i<cbi_d.length; i++) {
24                         if (cbi_d[i].id == field) {
25                                 entry = cbi_d[i];
26                                 break;
27                         }
28                 }
29                 if (!entry) {
30                         entry = {
31                                 "node": obj,
32                                 "id": field,
33                                 "parent": obj.parentNode.id,
34                                 "next": next,
35                                 "deps": []
36                         };
37                         cbi_d.unshift(entry);
38                 }
39                 entry.deps.push(dep)
40         }
41 }
42
43 function cbi_d_checkvalue(target, ref) {
44         var t = document.getElementById(target);
45         var value;
46
47         if (!t || !t.value) {
48                 value = "";
49         } else {
50                 value = t.value;
51
52                 if (t.type == "checkbox") {
53                         value = t.checked ? value : "";
54                 }
55         }
56
57         return (value == ref)
58 }
59
60 function cbi_d_check(deps) {
61         for (var i=0; i<deps.length; i++) {
62                 var istat = true
63                 for (var j in deps[i]) {
64                         istat = (istat && cbi_d_checkvalue(j, deps[i][j]))
65                 }
66                 if (istat) {
67                         return true
68                 }
69         }
70 }
71
72 function cbi_d_update() {
73         var state = false;
74         for (var i=0; i<cbi_d.length; i++) {
75                 var entry = cbi_d[i];
76                 var next  = document.getElementById(entry.next)
77                 var node  = document.getElementById(entry.id)
78                 var parent = document.getElementById(entry.parent)
79
80                 if (node && node.parentNode && !cbi_d_check(entry.deps)) {
81                         node.parentNode.removeChild(node);
82                         state = (state || !node.parentNode)
83                 } else if ((!node || !node.parentNode) && cbi_d_check(entry.deps)) {
84                         if (!next) {
85                                 parent.appendChild(entry.node);
86                         } else {
87                                 next.parentNode.insertBefore(entry.node, next);
88                         }
89                         state = (state || (node && node.parentNode))
90                 }
91         }
92         if (state) {
93                 cbi_d_update();
94         }
95 }
96
97 function cbi_bind(obj, type, callback, mode) {
98         if (typeof mode == "undefined") {
99                 mode = false;
100         }
101         if (!obj.addEventListener) {
102                 ieCallback = function(){
103                         var e = window.event;
104                         if (!e.target && e.srcElement) {
105                                 e.target = e.srcElement;
106                         };
107                         e.target['_eCB' + type + callback] = callback;
108                         e.target['_eCB' + type + callback](e);
109                         e.target['_eCB' + type + callback] = null;
110                 };
111                 obj.attachEvent('on' + type, ieCallback);
112         } else {
113                 obj.addEventListener(type, callback, mode);
114         }
115         return obj;
116 }
117
118 function cbi_combobox(id, values, def, man) {
119         var selid = "cbi.combobox." + id;
120         if (document.getElementById(selid)) {
121                 return
122         }
123
124         var obj = document.getElementById(id)
125         var sel = document.createElement("select");
126         sel.id = selid;
127         sel.className = 'cbi-input-select';
128         if (obj.nextSibling) {
129                 obj.parentNode.insertBefore(sel, obj.nextSibling);
130         } else {
131                 obj.parentNode.appendChild(sel);
132         }
133
134         if (!values[obj.value]) {
135                 if (obj.value == "") {
136                         var optdef = document.createElement("option");
137                         optdef.value = "";
138                         optdef.appendChild(document.createTextNode(def));
139                         sel.appendChild(optdef);
140                 } else {
141                         var opt = document.createElement("option");
142                         opt.value = obj.value;
143                         opt.selected = "selected";
144                         opt.appendChild(document.createTextNode(obj.value));
145                         sel.appendChild(opt);
146                 }
147         }
148
149         for (var i in values) {
150                 var opt = document.createElement("option");
151                 opt.value = i;
152
153                 if (obj.value == i) {
154                         opt.selected = "selected";
155                 }
156
157                 opt.appendChild(document.createTextNode(values[i]));
158                 sel.appendChild(opt);
159         }
160
161         var optman = document.createElement("option");
162         optman.value = "";
163         optman.appendChild(document.createTextNode(man));
164         sel.appendChild(optman);
165
166         obj.style.display = "none";
167
168         cbi_bind(sel, "change", function() {
169                 if (sel.selectedIndex == sel.options.length - 1) {
170                         obj.style.display = "inline";
171                         sel.parentNode.removeChild(sel);
172                         obj.focus();
173                 } else {
174                         obj.value = sel.options[sel.selectedIndex].value;
175                 }
176
177                 try {
178                         cbi_d_update();
179                 } catch (e) {
180                         //Do nothing
181                 }
182         })
183 }
184
185 function cbi_combobox_init(id, values, def, man) {
186         var obj = document.getElementById(id);
187         cbi_bind(obj, "blur", function() {
188                 cbi_combobox(id, values, def, man)
189         });
190         cbi_combobox(id, values, def, man);
191 }
192
193 function cbi_filebrowser(id, url, defpath) {
194         var field   = document.getElementById(id);
195         var browser = window.open(
196                 url + ( field.value || defpath || '' ) + '?field=' + id,
197                 "luci_filebrowser", "width=300,height=400,left=100,top=200,scrollbars=yes"
198         );
199
200         browser.focus();
201 }
202
203 //Hijacks the CBI form to send via XHR (requires Prototype)
204 function cbi_hijack_forms(layer, win, fail, load) {
205         var forms = layer.getElementsByTagName('form');
206         for (var i=0; i<forms.length; i++) {
207                 $(forms[i]).observe('submit', function(event) {
208                         // Prevent the form from also submitting the regular way
209                         event.stop();
210
211                         // Submit via XHR
212                         event.element().request({
213                                 onSuccess: win,
214                                 onFailure: fail
215                         });
216
217                         if (load) {
218                                 load();
219                         }
220                 });
221         }
222 }
223
224
225 function cbi_t_add(section, tab) {
226         var t = document.getElementById('tab.' + section + '.' + tab);
227         var c = document.getElementById('container.' + section + '.' + tab);
228
229         if( t && c ) {
230                 cbi_t[section] = (cbi_t[section] || [ ]);
231                 cbi_t[section][tab] = { 'tab': t, 'container': c };
232         }
233 }
234
235 function cbi_t_switch(section, tab) {
236         if( cbi_t[section] && cbi_t[section][tab] ) {
237                 var o = cbi_t[section][tab];
238                 for( var tid in cbi_t[section] ) {
239                         var o2 = cbi_t[section][tid];
240                         if( o.tab.id != o2.tab.id ) {
241                                 o2.tab.className = o2.tab.className.replace(/(^| )cbi-tab( |$)/, " cbi-tab-disabled ");
242                                 o2.container.style.display = 'none';
243                         }
244                         else {
245                                 o2.tab.className = o2.tab.className.replace(/(^| )cbi-tab-disabled( |$)/, " cbi-tab ");
246                                 o2.container.style.display = 'block';
247                         }
248                 }
249         }
250         return false
251 }