7 var CBINode
= Class
.extend({
8 __init__: function(title
, description
) {
9 this.title
= title
|| '';
10 this.description
= description
|| '';
14 append: function(obj
) {
15 this.children
.push(obj
);
20 this.children
.forEach(function(child
) {
21 child
.parse
.apply(child
, args
);
26 L
.error('InternalError', 'Not implemented');
29 loadChildren: function(/* ... */) {
32 if (Array
.isArray(this.children
))
33 for (var i
= 0; i
< this.children
.length
; i
++)
34 if (!this.children
[i
].disable
)
35 tasks
.push(this.children
[i
].load
.apply(this.children
[i
], arguments
));
37 return Promise
.all(tasks
);
40 renderChildren: function(tab_name
/*, ... */) {
44 if (Array
.isArray(this.children
))
45 for (var i
= 0; i
< this.children
.length
; i
++)
46 if (tab_name
=== null || this.children
[i
].tab
=== tab_name
)
47 if (!this.children
[i
].disable
)
48 tasks
.push(this.children
[i
].render
.apply(
49 this.children
[i
], this.varargs(arguments
, 1, index
++)));
51 return Promise
.all(tasks
);
54 stripTags: function(s
) {
58 var x
= E('div', {}, s
);
59 return x
.textContent
|| x
.innerText
|| '';
62 titleFn: function(attr
/*, ... */) {
65 if (typeof(this[attr
]) == 'function')
66 s
= this[attr
].apply(this, this.varargs(arguments
, 1));
67 else if (typeof(this[attr
]) == 'string')
68 s
= (arguments
.length
> 1) ? ''.format
.apply(this[attr
], this.varargs(arguments
, 1)) : this[attr
];
71 s
= this.stripTags(String(s
)).trim();
73 if (s
== null || s
== '')
80 var CBIMap
= CBINode
.extend({
81 __init__: function(config
/*, ... */) {
82 this.super('__init__', this.varargs(arguments
, 1));
85 this.parsechain
= [ config
];
88 findElements: function(/* ... */) {
91 if (arguments
.length
== 1)
93 else if (arguments
.length
== 2)
94 q
= '[%s="%s"]'.format(arguments
[0], arguments
[1]);
96 L
.error('InternalError', 'Expecting one or two arguments to findElements()');
98 return this.root
.querySelectorAll(q
);
101 findElement: function(/* ... */) {
102 var res
= this.findElements
.apply(this, arguments
);
103 return res
.length
? res
[0] : null;
106 chain: function(config
) {
107 if (this.parsechain
.indexOf(config
) == -1)
108 this.parsechain
.push(config
);
111 section: function(cbiClass
/*, ... */) {
112 if (!CBIAbstractSection
.isSubclass(cbiClass
))
113 L
.error('TypeError', 'Class must be a descendent of CBIAbstractSection');
115 var obj
= cbiClass
.instantiate(this.varargs(arguments
, 1, this));
121 return uci
.load(this.parsechain
|| [ this.config
])
122 .then(this.loadChildren
.bind(this));
128 if (Array
.isArray(this.children
))
129 for (var i
= 0; i
< this.children
.length
; i
++)
130 tasks
.push(this.children
[i
].parse());
132 return Promise
.all(tasks
);
135 save: function(cb
, silent
) {
140 .then(uci
.save
.bind(uci
))
141 .then(this.load
.bind(this))
144 alert('Cannot save due to invalid values');
146 return Promise
.reject();
147 }).finally(this.renderContents
.bind(this));
151 return this.renderContents();
155 return this.load().then(this.renderContents
.bind(this));
158 renderContents: function() {
159 var mapEl
= this.root
|| (this.root
= E('div', {
160 'id': 'cbi-%s'.format(this.config
),
162 'cbi-dependency-check': L
.bind(this.checkDepends
, this)
165 L
.dom
.bindClassInstance(mapEl
, this);
167 return this.renderChildren(null).then(L
.bind(function(nodes
) {
168 var initialRender
= !mapEl
.firstChild
;
170 L
.dom
.content(mapEl
, null);
172 if (this.title
!= null && this.title
!= '')
173 mapEl
.appendChild(E('h2', { 'name': 'content' }, this.title
));
175 if (this.description
!= null && this.description
!= '')
176 mapEl
.appendChild(E('div', { 'class': 'cbi-map-descr' }, this.description
));
179 L
.dom
.append(mapEl
, E('div', { 'class': 'cbi-map-tabbed' }, nodes
));
181 L
.dom
.append(mapEl
, nodes
);
183 if (!initialRender
) {
184 mapEl
.classList
.remove('flash');
186 window
.setTimeout(function() {
187 mapEl
.classList
.add('flash');
193 var tabGroups
= mapEl
.querySelectorAll('.cbi-map-tabbed, .cbi-section-node-tabbed');
195 for (var i
= 0; i
< tabGroups
.length
; i
++)
196 ui
.tabs
.initTabGroup(tabGroups
[i
].childNodes
);
202 lookupOption: function(name
, section_id
, config_name
) {
203 var id
, elem
, sid
, inst
;
205 if (name
.indexOf('.') > -1)
206 id
= 'cbid.%s'.format(name
);
208 id
= 'cbid.%s.%s.%s'.format(config_name
|| this.config
, section_id
, name
);
210 elem
= this.findElement('data-field', id
);
211 sid
= elem
? id
.split(/\./)[2] : null;
212 inst
= elem
? L
.dom
.findClassInstance(elem
) : null;
214 return (inst
instanceof CBIAbstractValue
) ? [ inst
, sid
] : null;
217 checkDepends: function(ev
, n
) {
220 for (var i
= 0, s
= this.children
[0]; (s
= this.children
[i
]) != null; i
++)
221 if (s
.checkDepends(ev
, n
))
224 if (changed
&& (n
|| 0) < 10)
225 this.checkDepends(ev
, (n
|| 10) + 1);
227 ui
.tabs
.updateTabs(ev
, this.root
);
231 var CBIAbstractSection
= CBINode
.extend({
232 __init__: function(map
, sectionType
/*, ... */) {
233 this.super('__init__', this.varargs(arguments
, 2));
235 this.sectiontype
= sectionType
;
237 this.config
= map
.config
;
239 this.optional
= true;
240 this.addremove
= false;
241 this.dynamic
= false;
244 cfgsections: function() {
245 L
.error('InternalError', 'Not implemented');
248 filter: function(section_id
) {
253 var section_ids
= this.cfgsections(),
256 if (Array
.isArray(this.children
))
257 for (var i
= 0; i
< section_ids
.length
; i
++)
258 tasks
.push(this.loadChildren(section_ids
[i
])
259 .then(Function
.prototype.bind
.call(function(section_id
, set_values
) {
260 for (var i
= 0; i
< set_values
.length
; i
++)
261 this.children
[i
].cfgvalue(section_id
, set_values
[i
]);
262 }, this, section_ids
[i
])));
264 return Promise
.all(tasks
);
268 var section_ids
= this.cfgsections(),
271 if (Array
.isArray(this.children
))
272 for (var i
= 0; i
< section_ids
.length
; i
++)
273 for (var j
= 0; j
< this.children
.length
; j
++)
274 tasks
.push(this.children
[j
].parse(section_ids
[i
]));
276 return Promise
.all(tasks
);
279 tab: function(name
, title
, description
) {
280 if (this.tabs
&& this.tabs
[name
])
281 throw 'Tab already declared';
286 description
: description
,
290 this.tabs
= this.tabs
|| [];
291 this.tabs
.push(entry
);
292 this.tabs
[name
] = entry
;
294 this.tab_names
= this.tab_names
|| [];
295 this.tab_names
.push(name
);
298 option: function(cbiClass
/*, ... */) {
299 if (!CBIAbstractValue
.isSubclass(cbiClass
))
300 throw L
.error('TypeError', 'Class must be a descendent of CBIAbstractValue');
302 var obj
= cbiClass
.instantiate(this.varargs(arguments
, 1, this.map
, this));
307 taboption: function(tabName
/*, ... */) {
308 if (!this.tabs
|| !this.tabs
[tabName
])
309 throw L
.error('ReferenceError', 'Associated tab not declared');
311 var obj
= this.option
.apply(this, this.varargs(arguments
, 1));
313 this.tabs
[tabName
].children
.push(obj
);
317 renderUCISection: function(section_id
) {
318 var renderTasks
= [];
321 return this.renderOptions(null, section_id
);
323 for (var i
= 0; i
< this.tab_names
.length
; i
++)
324 renderTasks
.push(this.renderOptions(this.tab_names
[i
], section_id
));
326 return Promise
.all(renderTasks
)
327 .then(this.renderTabContainers
.bind(this, section_id
));
330 renderTabContainers: function(section_id
, nodes
) {
331 var config_name
= this.uciconfig
|| this.map
.config
,
332 containerEls
= E([]);
334 for (var i
= 0; i
< nodes
.length
; i
++) {
335 var tab_name
= this.tab_names
[i
],
336 tab_data
= this.tabs
[tab_name
],
337 containerEl
= E('div', {
338 'id': 'container.%s.%s.%s'.format(config_name
, section_id
, tab_name
),
339 'data-tab': tab_name
,
340 'data-tab-title': tab_data
.title
,
341 'data-tab-active': tab_name
=== this.selected_tab
344 if (tab_data
.description
!= null && tab_data
.description
!= '')
345 containerEl
.appendChild(
346 E('div', { 'class': 'cbi-tab-descr' }, tab_data
.description
));
348 containerEl
.appendChild(nodes
[i
]);
349 containerEls
.appendChild(containerEl
);
355 renderOptions: function(tab_name
, section_id
) {
356 var in_table
= (this instanceof CBITableSection
);
357 return this.renderChildren(tab_name
, section_id
, in_table
).then(function(nodes
) {
358 var optionEls
= E([]);
359 for (var i
= 0; i
< nodes
.length
; i
++)
360 optionEls
.appendChild(nodes
[i
]);
365 checkDepends: function(ev
, n
) {
367 sids
= this.cfgsections();
369 for (var i
= 0, sid
= sids
[0]; (sid
= sids
[i
]) != null; i
++) {
370 for (var j
= 0, o
= this.children
[0]; (o
= this.children
[j
]) != null; j
++) {
371 var isActive
= o
.isActive(sid
),
372 isSatisified
= o
.checkDepends(sid
);
374 if (isActive
!= isSatisified
) {
375 o
.setActive(sid
, !isActive
);
380 o
.triggerValidation(sid
);
389 var isEqual = function(x
, y
) {
390 if (x
!= null && y
!= null && typeof(x
) != typeof(y
))
393 if ((x
== null && y
!= null) || (x
!= null && y
== null))
396 if (Array
.isArray(x
)) {
397 if (x
.length
!= y
.length
)
400 for (var i
= 0; i
< x
.length
; i
++)
401 if (!isEqual(x
[i
], y
[i
]))
404 else if (typeof(x
) == 'object') {
406 if (x
.hasOwnProperty(k
) && !y
.hasOwnProperty(k
))
409 if (!isEqual(x
[k
], y
[k
]))
414 if (y
.hasOwnProperty(k
) && !x
.hasOwnProperty(k
))
424 var CBIAbstractValue
= CBINode
.extend({
425 __init__: function(map
, section
, option
/*, ... */) {
426 this.super('__init__', this.varargs(arguments
, 3));
428 this.section
= section
;
429 this.option
= option
;
431 this.config
= map
.config
;
438 this.optional
= false;
441 depends: function(field
, value
) {
444 if (typeof(field
) === 'string')
445 deps
= {}, deps
[field
] = value
;
449 this.deps
.push(deps
);
452 transformDepList: function(section_id
, deplist
) {
453 var list
= deplist
|| this.deps
,
456 if (Array
.isArray(list
)) {
457 for (var i
= 0; i
< list
.length
; i
++) {
460 for (var k
in list
[i
]) {
461 if (list
[i
].hasOwnProperty(k
)) {
462 if (k
.charAt(0) === '!')
464 else if (k
.indexOf('.') !== -1)
465 dep
['cbid.%s'.format(k
)] = list
[i
][k
];
467 dep
['cbid.%s.%s.%s'.format(
468 this.uciconfig
|| this.section
.uciconfig
|| this.map
.config
,
469 this.ucisection
|| section_id
,
476 if (dep
.hasOwnProperty(k
)) {
487 transformChoices: function() {
488 if (!Array
.isArray(this.keylist
) || this.keylist
.length
== 0)
493 for (var i
= 0; i
< this.keylist
.length
; i
++)
494 choices
[this.keylist
[i
]] = this.vallist
[i
];
499 checkDepends: function(section_id
) {
502 if (!Array
.isArray(this.deps
) || !this.deps
.length
)
505 for (var i
= 0; i
< this.deps
.length
; i
++) {
509 for (var dep
in this.deps
[i
]) {
510 if (dep
== '!reverse') {
513 else if (dep
== '!default') {
518 var conf
= this.uciconfig
|| this.section
.uciconfig
|| this.map
.config
,
519 res
= this.map
.lookupOption(dep
, section_id
, conf
),
520 val
= res
? res
[0].formvalue(res
[1]) : null;
522 istat
= (istat
&& isEqual(val
, this.deps
[i
][dep
]));
533 cbid: function(section_id
) {
534 if (section_id
== null)
535 L
.error('TypeError', 'Section ID required');
537 return 'cbid.%s.%s.%s'.format(
538 this.uciconfig
|| this.section
.uciconfig
|| this.map
.config
,
539 section_id
, this.option
);
542 load: function(section_id
) {
543 if (section_id
== null)
544 L
.error('TypeError', 'Section ID required');
547 this.uciconfig
|| this.section
.uciconfig
|| this.map
.config
,
548 this.ucisection
|| section_id
,
549 this.ucioption
|| this.option
);
552 cfgvalue: function(section_id
, set_value
) {
553 if (section_id
== null)
554 L
.error('TypeError', 'Section ID required');
556 if (arguments
.length
== 2) {
557 this.data
= this.data
|| {};
558 this.data
[section_id
] = set_value
;
561 return this.data
? this.data
[section_id
] : null;
564 formvalue: function(section_id
) {
565 var node
= this.map
.findElement('id', this.cbid(section_id
));
566 return node
? L
.dom
.callClassMethod(node
, 'getValue') : null;
569 textvalue: function(section_id
) {
570 var cval
= this.cfgvalue(section_id
);
575 return (cval
!= null) ? '%h'.format(cval
) : null;
578 validate: function(section_id
, value
) {
582 isValid: function(section_id
) {
583 var node
= this.map
.findElement('id', this.cbid(section_id
));
584 return node
? L
.dom
.callClassMethod(node
, 'isValid') : true;
587 isActive: function(section_id
) {
588 var field
= this.map
.findElement('data-field', this.cbid(section_id
));
589 return (field
!= null && !field
.classList
.contains('hidden'));
592 setActive: function(section_id
, active
) {
593 var field
= this.map
.findElement('data-field', this.cbid(section_id
));
595 if (field
&& field
.classList
.contains('hidden') == active
) {
596 field
.classList
[active
? 'remove' : 'add']('hidden');
603 triggerValidation: function(section_id
) {
604 var node
= this.map
.findElement('id', this.cbid(section_id
));
605 return node
? L
.dom
.callClassMethod(node
, 'triggerValidation') : true;
608 parse: function(section_id
) {
609 var active
= this.isActive(section_id
),
610 cval
= this.cfgvalue(section_id
),
611 fval
= active
? this.formvalue(section_id
) : null;
613 if (active
&& !this.isValid(section_id
))
614 return Promise
.reject();
616 if (fval
!= '' && fval
!= null) {
617 if (this.forcewrite
|| !isEqual(cval
, fval
))
618 return Promise
.resolve(this.write(section_id
, fval
));
621 if (this.rmempty
|| this.optional
) {
622 return Promise
.resolve(this.remove(section_id
));
624 else if (!isEqual(cval
, fval
)) {
625 console
.log('This should have been catched by isValid()');
626 return Promise
.reject();
630 return Promise
.resolve();
633 write: function(section_id
, formvalue
) {
635 this.uciconfig
|| this.section
.uciconfig
|| this.map
.config
,
636 this.ucisection
|| section_id
,
637 this.ucioption
|| this.option
,
641 remove: function(section_id
) {
643 this.uciconfig
|| this.section
.uciconfig
|| this.map
.config
,
644 this.ucisection
|| section_id
,
645 this.ucioption
|| this.option
);
649 var CBITypedSection
= CBIAbstractSection
.extend({
650 __name__
: 'CBI.TypedSection',
652 cfgsections: function() {
653 return uci
.sections(this.uciconfig
|| this.map
.config
, this.sectiontype
)
654 .map(function(s
) { return s
['.name'] })
655 .filter(L
.bind(this.filter
, this));
658 handleAdd: function(ev
, name
) {
659 var config_name
= this.uciconfig
|| this.map
.config
;
661 uci
.add(config_name
, this.sectiontype
, name
);
662 return this.map
.save(null, true);
665 handleRemove: function(section_id
, ev
) {
666 var config_name
= this.uciconfig
|| this.map
.config
;
668 uci
.remove(config_name
, section_id
);
669 return this.map
.save(null, true);
672 renderSectionAdd: function(extra_class
) {
676 var createEl
= E('div', { 'class': 'cbi-section-create' }),
677 config_name
= this.uciconfig
|| this.map
.config
,
678 btn_title
= this.titleFn('addbtntitle');
680 if (extra_class
!= null)
681 createEl
.classList
.add(extra_class
);
683 if (this.anonymous
) {
684 createEl
.appendChild(E('button', {
685 'class': 'cbi-button cbi-button-add',
686 'title': btn_title
|| _('Add'),
687 'click': L
.ui
.createHandlerFn(this, 'handleAdd')
688 }, btn_title
|| _('Add')));
691 var nameEl
= E('input', {
693 'class': 'cbi-section-create-name'
696 L
.dom
.append(createEl
, [
697 E('div', {}, nameEl
),
699 'class': 'cbi-button cbi-button-add',
701 'value': btn_title
|| _('Add'),
702 'title': btn_title
|| _('Add'),
703 'click': L
.ui
.createHandlerFn(this, function(ev
) {
704 if (nameEl
.classList
.contains('cbi-input-invalid'))
707 return this.handleAdd(ev
, nameEl
.value
);
712 ui
.addValidator(nameEl
, 'uciname', true, 'blur', 'keyup');
718 renderSectionPlaceholder: function() {
720 E('em', _('This section contains no values yet')),
725 renderContents: function(cfgsections
, nodes
) {
726 var section_id
= null,
727 config_name
= this.uciconfig
|| this.map
.config
,
728 sectionEl
= E('div', {
729 'id': 'cbi-%s-%s'.format(config_name
, this.sectiontype
),
730 'class': 'cbi-section',
731 'data-tab': this.map
.tabbed
? this.sectiontype
: null,
732 'data-tab-title': this.map
.tabbed
? this.title
|| this.sectiontype
: null
735 if (this.title
!= null && this.title
!= '')
736 sectionEl
.appendChild(E('legend', {}, this.title
));
738 if (this.description
!= null && this.description
!= '')
739 sectionEl
.appendChild(E('div', { 'class': 'cbi-section-descr' }, this.description
));
741 for (var i
= 0; i
< nodes
.length
; i
++) {
742 if (this.addremove
) {
743 sectionEl
.appendChild(
744 E('div', { 'class': 'cbi-section-remove right' },
746 'class': 'cbi-button',
747 'name': 'cbi.rts.%s.%s'.format(config_name
, cfgsections
[i
]),
748 'data-section-id': cfgsections
[i
],
749 'click': L
.ui
.createHandlerFn(this, 'handleRemove', cfgsections
[i
])
754 sectionEl
.appendChild(E('h3', cfgsections
[i
].toUpperCase()));
756 sectionEl
.appendChild(E('div', {
757 'id': 'cbi-%s-%s'.format(config_name
, cfgsections
[i
]),
759 ? 'cbi-section-node cbi-section-node-tabbed' : 'cbi-section-node',
760 'data-section-id': cfgsections
[i
]
764 if (nodes
.length
== 0)
765 sectionEl
.appendChild(this.renderSectionPlaceholder());
767 sectionEl
.appendChild(this.renderSectionAdd());
769 L
.dom
.bindClassInstance(sectionEl
, this);
775 var cfgsections
= this.cfgsections(),
778 for (var i
= 0; i
< cfgsections
.length
; i
++)
779 renderTasks
.push(this.renderUCISection(cfgsections
[i
]));
781 return Promise
.all(renderTasks
).then(this.renderContents
.bind(this, cfgsections
));
785 var CBITableSection
= CBITypedSection
.extend({
786 __name__
: 'CBI.TableSection',
789 throw 'Tabs are not supported by TableSection';
792 renderContents: function(cfgsections
, nodes
) {
793 var section_id
= null,
794 config_name
= this.uciconfig
|| this.map
.config
,
795 max_cols
= isNaN(this.max_cols
) ? this.children
.length
: this.max_cols
,
796 has_more
= max_cols
< this.children
.length
,
797 sectionEl
= E('div', {
798 'id': 'cbi-%s-%s'.format(config_name
, this.sectiontype
),
799 'class': 'cbi-section cbi-tblsection',
800 'data-tab': this.map
.tabbed
? this.sectiontype
: null,
801 'data-tab-title': this.map
.tabbed
? this.title
|| this.sectiontype
: null
804 'class': 'table cbi-section-table'
807 if (this.title
!= null && this.title
!= '')
808 sectionEl
.appendChild(E('h3', {}, this.title
));
810 if (this.description
!= null && this.description
!= '')
811 sectionEl
.appendChild(E('div', { 'class': 'cbi-section-descr' }, this.description
));
813 tableEl
.appendChild(this.renderHeaderRows(max_cols
));
815 for (var i
= 0; i
< nodes
.length
; i
++) {
816 var sectionname
= this.titleFn('sectiontitle', cfgsections
[i
]);
818 var trEl
= E('div', {
819 'id': 'cbi-%s-%s'.format(config_name
, cfgsections
[i
]),
820 'class': 'tr cbi-section-table-row',
821 'data-sid': cfgsections
[i
],
822 'draggable': this.sortable
? true : null,
823 'mousedown': this.sortable
? L
.bind(this.handleDragInit
, this) : null,
824 'dragstart': this.sortable
? L
.bind(this.handleDragStart
, this) : null,
825 'dragover': this.sortable
? L
.bind(this.handleDragOver
, this) : null,
826 'dragenter': this.sortable
? L
.bind(this.handleDragEnter
, this) : null,
827 'dragleave': this.sortable
? L
.bind(this.handleDragLeave
, this) : null,
828 'dragend': this.sortable
? L
.bind(this.handleDragEnd
, this) : null,
829 'drop': this.sortable
? L
.bind(this.handleDrop
, this) : null,
830 'data-title': (sectionname
&& (!this.anonymous
|| this.sectiontitle
)) ? sectionname
: null,
831 'data-section-id': cfgsections
[i
]
834 if (this.extedit
|| this.rowcolors
)
835 trEl
.classList
.add(!(tableEl
.childNodes
.length
% 2)
836 ? 'cbi-rowstyle-1' : 'cbi-rowstyle-2');
838 for (var j
= 0; j
< max_cols
&& nodes
[i
].firstChild
; j
++)
839 trEl
.appendChild(nodes
[i
].firstChild
);
841 trEl
.appendChild(this.renderRowActions(cfgsections
[i
], has_more
? _('More…') : null));
842 tableEl
.appendChild(trEl
);
845 if (nodes
.length
== 0)
846 tableEl
.appendChild(E('div', { 'class': 'tr cbi-section-table-row placeholder' },
847 E('div', { 'class': 'td' },
848 E('em', {}, _('This section contains no values yet')))));
850 sectionEl
.appendChild(tableEl
);
852 sectionEl
.appendChild(this.renderSectionAdd('cbi-tblsection-create'));
854 L
.dom
.bindClassInstance(sectionEl
, this);
859 renderHeaderRows: function(max_cols
) {
860 var has_titles
= false,
861 has_descriptions
= false,
862 anon_class
= (!this.anonymous
|| this.sectiontitle
) ? 'named' : 'anonymous',
865 for (var i
= 0, opt
; i
< max_cols
&& (opt
= this.children
[i
]) != null; i
++) {
866 if (opt
.optional
|| opt
.modalonly
)
869 has_titles
= has_titles
|| !!opt
.title
;
870 has_descriptions
= has_descriptions
|| !!opt
.description
;
874 var trEl
= E('div', {
875 'class': 'tr cbi-section-table-titles ' + anon_class
,
876 'data-title': (!this.anonymous
|| this.sectiontitle
) ? _('Name') : null
879 for (var i
= 0, opt
; i
< max_cols
&& (opt
= this.children
[i
]) != null; i
++) {
880 if (opt
.optional
|| opt
.modalonly
)
883 trEl
.appendChild(E('div', {
884 'class': 'th cbi-section-table-cell',
885 'data-type': opt
.__name__
888 if (opt
.width
!= null)
889 trEl
.lastElementChild
.style
.width
=
890 (typeof(opt
.width
) == 'number') ? opt
.width
+'px' : opt
.width
;
893 trEl
.lastElementChild
.appendChild(E('a', {
894 'href': opt
.titleref
,
895 'class': 'cbi-title-ref',
896 'title': this.titledesc
|| _('Go to relevant configuration page')
899 L
.dom
.content(trEl
.lastElementChild
, opt
.title
);
902 if (this.sortable
|| this.extedit
|| this.addremove
|| has_more
)
903 trEl
.appendChild(E('div', {
904 'class': 'th cbi-section-table-cell cbi-section-actions'
907 trEls
.appendChild(trEl
);
910 if (has_descriptions
) {
911 var trEl
= E('div', {
912 'class': 'tr cbi-section-table-descr ' + anon_class
915 for (var i
= 0, opt
; i
< max_cols
&& (opt
= this.children
[i
]) != null; i
++) {
916 if (opt
.optional
|| opt
.modalonly
)
919 trEl
.appendChild(E('div', {
920 'class': 'th cbi-section-table-cell',
921 'data-type': opt
.__name__
922 }, opt
.description
));
924 if (opt
.width
!= null)
925 trEl
.lastElementChild
.style
.width
=
926 (typeof(opt
.width
) == 'number') ? opt
.width
+'px' : opt
.width
;
929 if (this.sortable
|| this.extedit
|| this.addremove
|| has_more
)
930 trEl
.appendChild(E('div', {
931 'class': 'th cbi-section-table-cell cbi-section-actions'
934 trEls
.appendChild(trEl
);
940 renderRowActions: function(section_id
, more_label
) {
941 var config_name
= this.uciconfig
|| this.map
.config
;
943 if (!this.sortable
&& !this.extedit
&& !this.addremove
&& !more_label
)
946 var tdEl
= E('div', {
947 'class': 'td cbi-section-table-cell nowrap cbi-section-actions'
951 L
.dom
.append(tdEl
.lastElementChild
, [
953 'title': _('Drag to reorder'),
954 'class': 'cbi-button drag-handle center',
955 'style': 'cursor:move'
963 if (typeof(this.extedit
) == 'function')
964 evFn
= L
.bind(this.extedit
, this);
965 else if (typeof(this.extedit
) == 'string')
966 evFn
= L
.bind(function(sid
, ev
) {
967 location
.href
= this.extedit
.format(sid
);
968 }, this, section_id
);
970 L
.dom
.append(tdEl
.lastElementChild
,
975 'class': 'cbi-button cbi-button-edit',
982 L
.dom
.append(tdEl
.lastElementChild
,
987 'class': 'cbi-button cbi-button-edit',
988 'click': L
.bind(this.renderMoreOptionsModal
, this, section_id
)
993 if (this.addremove
) {
994 var btn_title
= this.titleFn('removebtntitle', section_id
);
996 L
.dom
.append(tdEl
.lastElementChild
,
999 'value': btn_title
|| _('Delete'),
1000 'title': btn_title
|| _('Delete'),
1001 'class': 'cbi-button cbi-button-remove',
1002 'click': L
.bind(function(sid
, ev
) {
1003 uci
.remove(config_name
, sid
);
1004 this.map
.save(null, true);
1005 }, this, section_id
)
1013 handleDragInit: function(ev
) {
1014 scope
.dragState
= { node
: ev
.target
};
1017 handleDragStart: function(ev
) {
1018 if (!scope
.dragState
|| !scope
.dragState
.node
.classList
.contains('drag-handle')) {
1019 scope
.dragState
= null;
1020 ev
.preventDefault();
1024 scope
.dragState
.node
= L
.dom
.parent(scope
.dragState
.node
, '.tr');
1025 ev
.dataTransfer
.setData('text', 'drag');
1026 ev
.target
.style
.opacity
= 0.4;
1029 handleDragOver: function(ev
) {
1030 var n
= scope
.dragState
.targetNode
,
1031 r
= scope
.dragState
.rect
,
1032 t
= r
.top
+ r
.height
/ 2;
1034 if (ev
.clientY
<= t
) {
1035 n
.classList
.remove('drag-over-below');
1036 n
.classList
.add('drag-over-above');
1039 n
.classList
.remove('drag-over-above');
1040 n
.classList
.add('drag-over-below');
1043 ev
.dataTransfer
.dropEffect
= 'move';
1044 ev
.preventDefault();
1048 handleDragEnter: function(ev
) {
1049 scope
.dragState
.rect
= ev
.currentTarget
.getBoundingClientRect();
1050 scope
.dragState
.targetNode
= ev
.currentTarget
;
1053 handleDragLeave: function(ev
) {
1054 ev
.currentTarget
.classList
.remove('drag-over-above');
1055 ev
.currentTarget
.classList
.remove('drag-over-below');
1058 handleDragEnd: function(ev
) {
1061 n
.style
.opacity
= '';
1062 n
.classList
.add('flash');
1063 n
.parentNode
.querySelectorAll('.drag-over-above, .drag-over-below')
1064 .forEach(function(tr
) {
1065 tr
.classList
.remove('drag-over-above');
1066 tr
.classList
.remove('drag-over-below');
1070 handleDrop: function(ev
) {
1071 var s
= scope
.dragState
;
1073 if (s
.node
&& s
.targetNode
) {
1074 var config_name
= this.uciconfig
|| this.map
.config
,
1075 ref_node
= s
.targetNode
,
1078 if (ref_node
.classList
.contains('drag-over-below')) {
1079 ref_node
= ref_node
.nextElementSibling
;
1083 var sid1
= s
.node
.getAttribute('data-sid'),
1084 sid2
= s
.targetNode
.getAttribute('data-sid');
1086 s
.node
.parentNode
.insertBefore(s
.node
, ref_node
);
1087 uci
.move(config_name
, sid1
, sid2
, after
);
1090 scope
.dragState
= null;
1091 ev
.target
.style
.opacity
= '';
1092 ev
.stopPropagation();
1093 ev
.preventDefault();
1097 handleModalCancel: function(modalMap
, ev
) {
1098 return Promise
.resolve(L
.ui
.hideModal());
1101 handleModalSave: function(modalMap
, ev
) {
1102 return modalMap
.save()
1103 .then(L
.bind(this.map
.load
, this.map
))
1104 .then(L
.bind(this.map
.reset
, this.map
))
1105 .then(L
.ui
.hideModal
)
1106 .catch(function() {});
1109 addModalOptions: function(modalSection
, section_id
, ev
) {
1113 renderMoreOptionsModal: function(section_id
, ev
) {
1114 var parent
= this.map
,
1115 title
= parent
.title
,
1117 m
= new CBIMap(this.map
.config
, null, null),
1118 s
= m
.section(CBINamedSection
, section_id
, this.sectiontype
);
1121 s
.tab_names
= this.tab_names
;
1123 if ((name
= this.titleFn('modaltitle', section_id
)) != null)
1125 else if ((name
= this.titleFn('sectiontitle', section_id
)) != null)
1126 title
= '%s - %s'.format(parent
.title
, name
);
1127 else if (!this.anonymous
)
1128 title
= '%s - %s'.format(parent
.title
, section_id
);
1130 for (var i
= 0; i
< this.children
.length
; i
++) {
1131 var o1
= this.children
[i
];
1133 if (o1
.modalonly
=== false)
1136 var o2
= s
.option(o1
.constructor, o1
.option
, o1
.title
, o1
.description
);
1139 if (!o1
.hasOwnProperty(k
))
1156 //ev.target.classList.add('spinning');
1157 Promise
.resolve(this.addModalOptions(s
, section_id
, ev
)).then(L
.bind(m
.render
, m
)).then(L
.bind(function(nodes
) {
1158 //ev.target.classList.remove('spinning');
1159 L
.ui
.showModal(title
, [
1161 E('div', { 'class': 'right' }, [
1165 'click': L
.bind(this.handleModalCancel
, this, m
),
1166 'value': _('Dismiss')
1170 'class': 'cbi-button cbi-button-positive important',
1171 'click': L
.bind(this.handleModalSave
, this, m
),
1176 }, this)).catch(L
.error
);
1180 var CBIGridSection
= CBITableSection
.extend({
1181 tab: function(name
, title
, description
) {
1182 CBIAbstractSection
.prototype.tab
.call(this, name
, title
, description
);
1185 handleAdd: function(ev
) {
1186 var config_name
= this.uciconfig
|| this.map
.config
,
1187 section_id
= uci
.add(config_name
, this.sectiontype
);
1189 this.addedSection
= section_id
;
1190 this.renderMoreOptionsModal(section_id
);
1193 handleModalSave: function(/* ... */) {
1194 return this.super('handleModalSave', arguments
)
1195 .then(L
.bind(function() { this.addedSection
= null }, this));
1198 handleModalCancel: function(/* ... */) {
1199 var config_name
= this.uciconfig
|| this.map
.config
;
1201 if (this.addedSection
!= null) {
1202 uci
.remove(config_name
, this.addedSection
);
1203 this.addedSection
= null;
1206 return this.super('handleModalCancel', arguments
);
1209 renderUCISection: function(section_id
) {
1210 return this.renderOptions(null, section_id
);
1213 renderChildren: function(tab_name
, section_id
, in_table
) {
1214 var tasks
= [], index
= 0;
1216 for (var i
= 0, opt
; (opt
= this.children
[i
]) != null; i
++) {
1217 if (opt
.disable
|| opt
.modalonly
)
1221 tasks
.push(opt
.render(index
++, section_id
, in_table
));
1223 tasks
.push(this.renderTextValue(section_id
, opt
));
1226 return Promise
.all(tasks
);
1229 renderTextValue: function(section_id
, opt
) {
1230 var title
= this.stripTags(opt
.title
).trim(),
1231 descr
= this.stripTags(opt
.description
).trim(),
1232 value
= opt
.textvalue(section_id
);
1235 'class': 'td cbi-value-field',
1236 'data-title': (title
!= '') ? title
: opt
.option
,
1237 'data-description': (descr
!= '') ? descr
: null,
1238 'data-name': opt
.option
,
1239 'data-type': opt
.typename
|| opt
.__name__
1240 }, (value
!= null) ? value
: E('em', _('none')));
1243 renderRowActions: function(section_id
) {
1244 return this.super('renderRowActions', [ section_id
, _('Edit') ]);
1248 var section_ids
= this.cfgsections(),
1251 if (Array
.isArray(this.children
)) {
1252 for (var i
= 0; i
< section_ids
.length
; i
++) {
1253 for (var j
= 0; j
< this.children
.length
; j
++) {
1254 if (!this.children
[j
].editable
|| this.children
[j
].modalonly
)
1257 tasks
.push(this.children
[j
].parse(section_ids
[i
]));
1262 return Promise
.all(tasks
);
1266 var CBINamedSection
= CBIAbstractSection
.extend({
1267 __name__
: 'CBI.NamedSection',
1268 __init__: function(map
, section_id
/*, ... */) {
1269 this.super('__init__', this.varargs(arguments
, 2, map
));
1271 this.section
= section_id
;
1274 cfgsections: function() {
1275 return [ this.section
];
1278 handleAdd: function(ev
) {
1279 var section_id
= this.section
,
1280 config_name
= this.uciconfig
|| this.map
.config
;
1282 uci
.add(config_name
, this.sectiontype
, section_id
);
1283 return this.map
.save(null, true);
1286 handleRemove: function(ev
) {
1287 var section_id
= this.section
,
1288 config_name
= this.uciconfig
|| this.map
.config
;
1290 uci
.remove(config_name
, section_id
);
1291 return this.map
.save(null, true);
1294 renderContents: function(data
) {
1295 var ucidata
= data
[0], nodes
= data
[1],
1296 section_id
= this.section
,
1297 config_name
= this.uciconfig
|| this.map
.config
,
1298 sectionEl
= E('div', {
1299 'id': ucidata
? null : 'cbi-%s-%s'.format(config_name
, section_id
),
1300 'class': 'cbi-section',
1301 'data-tab': this.map
.tabbed
? this.sectiontype
: null,
1302 'data-tab-title': this.map
.tabbed
? this.title
|| this.sectiontype
: null
1305 if (typeof(this.title
) === 'string' && this.title
!== '')
1306 sectionEl
.appendChild(E('legend', {}, this.title
));
1308 if (typeof(this.description
) === 'string' && this.description
!== '')
1309 sectionEl
.appendChild(E('div', { 'class': 'cbi-section-descr' }, this.description
));
1312 if (this.addremove
) {
1313 sectionEl
.appendChild(
1314 E('div', { 'class': 'cbi-section-remove right' },
1316 'class': 'cbi-button',
1317 'click': L
.ui
.createHandlerFn(this, 'handleRemove')
1321 sectionEl
.appendChild(E('div', {
1322 'id': 'cbi-%s-%s'.format(config_name
, section_id
),
1324 ? 'cbi-section-node cbi-section-node-tabbed' : 'cbi-section-node',
1325 'data-section-id': section_id
1328 else if (this.addremove
) {
1329 sectionEl
.appendChild(
1331 'class': 'cbi-button cbi-button-add',
1332 'click': L
.ui
.createHandlerFn(this, 'handleAdd')
1336 L
.dom
.bindClassInstance(sectionEl
, this);
1341 render: function() {
1342 var config_name
= this.uciconfig
|| this.map
.config
,
1343 section_id
= this.section
;
1345 return Promise
.all([
1346 uci
.get(config_name
, section_id
),
1347 this.renderUCISection(section_id
)
1348 ]).then(this.renderContents
.bind(this));
1352 var CBIValue
= CBIAbstractValue
.extend({
1353 __name__
: 'CBI.Value',
1355 value: function(key
, val
) {
1356 this.keylist
= this.keylist
|| [];
1357 this.keylist
.push(String(key
));
1359 this.vallist
= this.vallist
|| [];
1360 this.vallist
.push(String(val
!= null ? val
: key
));
1363 render: function(option_index
, section_id
, in_table
) {
1364 return Promise
.resolve(this.cfgvalue(section_id
))
1365 .then(this.renderWidget
.bind(this, section_id
, option_index
))
1366 .then(this.renderFrame
.bind(this, section_id
, in_table
, option_index
));
1369 renderFrame: function(section_id
, in_table
, option_index
, nodes
) {
1370 var config_name
= this.uciconfig
|| this.section
.uciconfig
|| this.map
.config
,
1371 depend_list
= this.transformDepList(section_id
),
1375 optionEl
= E('div', {
1376 'class': 'td cbi-value-field',
1377 'data-title': this.stripTags(this.title
).trim(),
1378 'data-description': this.stripTags(this.description
).trim(),
1379 'data-name': this.option
,
1380 'data-type': this.typename
|| (this.template
? this.template
.replace(/^.+\//, '') : null) || this.__name__
1382 'id': 'cbi-%s-%s-%s'.format(config_name
, section_id
, this.option
),
1383 'data-index': option_index
,
1384 'data-depends': depend_list
,
1385 'data-field': this.cbid(section_id
)
1389 optionEl
= E('div', {
1390 'class': 'cbi-value',
1391 'id': 'cbi-%s-%s-%s'.format(config_name
, section_id
, this.option
),
1392 'data-index': option_index
,
1393 'data-depends': depend_list
,
1394 'data-field': this.cbid(section_id
),
1395 'data-name': this.option
,
1396 'data-type': this.typename
|| (this.template
? this.template
.replace(/^.+\//, '') : null) || this.__name__
1399 if (this.last_child
)
1400 optionEl
.classList
.add('cbi-value-last');
1402 if (typeof(this.title
) === 'string' && this.title
!== '') {
1403 optionEl
.appendChild(E('label', {
1404 'class': 'cbi-value-title',
1405 'for': 'widget.cbid.%s.%s.%s'.format(config_name
, section_id
, this.option
)
1407 this.titleref
? E('a', {
1408 'class': 'cbi-title-ref',
1409 'href': this.titleref
,
1410 'title': this.titledesc
|| _('Go to relevant configuration page')
1411 }, this.title
) : this.title
));
1413 optionEl
.appendChild(E('div', { 'class': 'cbi-value-field' }));
1418 (optionEl
.lastChild
|| optionEl
).appendChild(nodes
);
1420 if (!in_table
&& typeof(this.description
) === 'string' && this.description
!== '')
1421 L
.dom
.append(optionEl
.lastChild
|| optionEl
,
1422 E('div', { 'class': 'cbi-value-description' }, this.description
));
1424 if (depend_list
&& depend_list
.length
)
1425 optionEl
.classList
.add('hidden');
1427 optionEl
.addEventListener('widget-change',
1428 L
.bind(this.map
.checkDepends
, this.map
));
1430 L
.dom
.bindClassInstance(optionEl
, this);
1435 renderWidget: function(section_id
, option_index
, cfgvalue
) {
1436 var value
= (cfgvalue
!= null) ? cfgvalue
: this.default,
1437 choices
= this.transformChoices(),
1441 var placeholder
= (this.optional
|| this.rmempty
)
1442 ? E('em', _('unspecified')) : _('-- Please choose --');
1444 widget
= new ui
.Combobox(Array
.isArray(value
) ? value
.join(' ') : value
, choices
, {
1445 id
: this.cbid(section_id
),
1447 optional
: this.optional
|| this.rmempty
,
1448 datatype
: this.datatype
,
1449 select_placeholder
: this.placeholder
|| placeholder
,
1450 validate
: L
.bind(this.validate
, this, section_id
)
1454 widget
= new ui
.Textfield(Array
.isArray(value
) ? value
.join(' ') : value
, {
1455 id
: this.cbid(section_id
),
1456 password
: this.password
,
1457 optional
: this.optional
|| this.rmempty
,
1458 datatype
: this.datatype
,
1459 placeholder
: this.placeholder
,
1460 validate
: L
.bind(this.validate
, this, section_id
)
1464 return widget
.render();
1468 var CBIDynamicList
= CBIValue
.extend({
1469 __name__
: 'CBI.DynamicList',
1471 renderWidget: function(section_id
, option_index
, cfgvalue
) {
1472 var value
= (cfgvalue
!= null) ? cfgvalue
: this.default,
1473 choices
= this.transformChoices(),
1474 items
= L
.toArray(value
);
1476 var widget
= new ui
.DynamicList(items
, choices
, {
1477 id
: this.cbid(section_id
),
1479 optional
: this.optional
|| this.rmempty
,
1480 datatype
: this.datatype
,
1481 placeholder
: this.placeholder
,
1482 validate
: L
.bind(this.validate
, this, section_id
)
1485 return widget
.render();
1489 var CBIListValue
= CBIValue
.extend({
1490 __name__
: 'CBI.ListValue',
1492 __init__: function() {
1493 this.super('__init__', arguments
);
1494 this.widget
= 'select';
1498 renderWidget: function(section_id
, option_index
, cfgvalue
) {
1499 var choices
= this.transformChoices();
1500 var widget
= new ui
.Select((cfgvalue
!= null) ? cfgvalue
: this.default, choices
, {
1501 id
: this.cbid(section_id
),
1504 optional
: this.optional
,
1505 placeholder
: this.placeholder
,
1506 validate
: L
.bind(this.validate
, this, section_id
)
1509 return widget
.render();
1513 var CBIFlagValue
= CBIValue
.extend({
1514 __name__
: 'CBI.FlagValue',
1516 __init__: function() {
1517 this.super('__init__', arguments
);
1520 this.disabled
= '0';
1521 this.default = this.disabled
;
1524 renderWidget: function(section_id
, option_index
, cfgvalue
) {
1525 var widget
= new ui
.Checkbox((cfgvalue
!= null) ? cfgvalue
: this.default, {
1526 id
: this.cbid(section_id
),
1527 value_enabled
: this.enabled
,
1528 value_disabled
: this.disabled
,
1529 validate
: L
.bind(this.validate
, this, section_id
)
1532 return widget
.render();
1535 formvalue: function(section_id
) {
1536 var node
= this.map
.findElement('id', this.cbid(section_id
)),
1537 checked
= node
? L
.dom
.callClassMethod(node
, 'isChecked') : false;
1539 return checked
? this.enabled
: this.disabled
;
1542 textvalue: function(section_id
) {
1543 var cval
= this.cfgvalue(section_id
);
1546 cval
= this.default;
1548 return (cval
== this.enabled
) ? _('Yes') : _('No');
1551 parse: function(section_id
) {
1552 if (this.isActive(section_id
)) {
1553 var fval
= this.formvalue(section_id
);
1555 if (!this.isValid(section_id
))
1556 return Promise
.reject();
1558 if (fval
== this.default && (this.optional
|| this.rmempty
))
1559 return Promise
.resolve(this.remove(section_id
));
1561 return Promise
.resolve(this.write(section_id
, fval
));
1564 return Promise
.resolve(this.remove(section_id
));
1569 var CBIMultiValue
= CBIDynamicList
.extend({
1570 __name__
: 'CBI.MultiValue',
1572 __init__: function() {
1573 this.super('__init__', arguments
);
1574 this.placeholder
= _('-- Please choose --');
1577 renderWidget: function(section_id
, option_index
, cfgvalue
) {
1578 var value
= (cfgvalue
!= null) ? cfgvalue
: this.default,
1579 choices
= this.transformChoices();
1581 var widget
= new ui
.Dropdown(L
.toArray(value
), choices
, {
1582 id
: this.cbid(section_id
),
1585 optional
: this.optional
|| this.rmempty
,
1586 select_placeholder
: this.placeholder
,
1587 display_items
: this.display_size
|| this.size
|| 3,
1588 dropdown_items
: this.dropdown_size
|| this.size
|| -1,
1589 validate
: L
.bind(this.validate
, this, section_id
)
1592 return widget
.render();
1596 var CBITextValue
= CBIValue
.extend({
1597 __name__
: 'CBI.TextValue',
1601 renderWidget: function(section_id
, option_index
, cfgvalue
) {
1602 var value
= (cfgvalue
!= null) ? cfgvalue
: this.default;
1604 var widget
= new ui
.Textarea(value
, {
1605 id
: this.cbid(section_id
),
1606 optional
: this.optional
|| this.rmempty
,
1607 placeholder
: this.placeholder
,
1608 monospace
: this.monospace
,
1612 validate
: L
.bind(this.validate
, this, section_id
)
1615 return widget
.render();
1619 var CBIDummyValue
= CBIValue
.extend({
1620 __name__
: 'CBI.DummyValue',
1622 renderWidget: function(section_id
, option_index
, cfgvalue
) {
1623 var value
= (cfgvalue
!= null) ? cfgvalue
: this.default,
1624 hiddenEl
= new ui
.Hiddenfield(value
, { id
: this.cbid(section_id
) }),
1625 outputEl
= E('div');
1628 outputEl
.appendChild(E('a', { 'href': this.href
}));
1630 L
.dom
.append(outputEl
.lastChild
|| outputEl
,
1631 this.rawhtml
? value
: [ value
]);
1640 var CBIButtonValue
= CBIValue
.extend({
1641 __name__
: 'CBI.ButtonValue',
1643 renderWidget: function(section_id
, option_index
, cfgvalue
) {
1644 var value
= (cfgvalue
!= null) ? cfgvalue
: this.default,
1645 hiddenEl
= new ui
.Hiddenfield(value
, { id
: this.cbid(section_id
) }),
1646 outputEl
= E('div'),
1647 btn_title
= this.titleFn('inputtitle', section_id
) || this.titleFn('title', section_id
);
1649 if (value
!== false)
1650 L
.dom
.content(outputEl
, [
1652 'class': 'cbi-button cbi-button-%s'.format(this.inputstyle
|| 'button'),
1655 'click': L
.bind(this.onclick
|| function(ev
) {
1656 ev
.target
.previousElementSibling
.value
= ev
.target
.value
;
1662 L
.dom
.content(outputEl
, ' - ');
1671 var CBIHiddenValue
= CBIValue
.extend({
1672 __name__
: 'CBI.HiddenValue',
1674 renderWidget: function(section_id
, option_index
, cfgvalue
) {
1675 var widget
= new ui
.Hiddenfield((cfgvalue
!= null) ? cfgvalue
: this.default, {
1676 id
: this.cbid(section_id
)
1679 return widget
.render();
1683 var CBISectionValue
= CBIValue
.extend({
1684 __name__
: 'CBI.ContainerValue',
1685 __init__: function(map
, section
, option
, cbiClass
/*, ... */) {
1686 this.super('__init__', [map
, section
, option
]);
1688 if (!CBIAbstractSection
.isSubclass(cbiClass
))
1689 throw 'Sub section must be a descendent of CBIAbstractSection';
1691 this.subsection
= cbiClass
.instantiate(this.varargs(arguments
, 4, this.map
));
1694 load: function(section_id
) {
1695 return this.subsection
.load();
1698 parse: function(section_id
) {
1699 return this.subsection
.parse();
1702 renderWidget: function(section_id
, option_index
, cfgvalue
) {
1703 return this.subsection
.render();
1706 checkDepends: function(section_id
) {
1707 this.subsection
.checkDepends();
1708 return CBIValue
.prototype.checkDepends
.apply(this, [ section_id
]);
1711 write: function() {},
1712 remove: function() {},
1713 cfgvalue: function() { return null },
1714 formvalue: function() { return null }
1717 return L
.Class
.extend({
1719 AbstractSection
: CBIAbstractSection
,
1720 AbstractValue
: CBIAbstractValue
,
1722 TypedSection
: CBITypedSection
,
1723 TableSection
: CBITableSection
,
1724 GridSection
: CBIGridSection
,
1725 NamedSection
: CBINamedSection
,
1728 DynamicList
: CBIDynamicList
,
1729 ListValue
: CBIListValue
,
1731 MultiValue
: CBIMultiValue
,
1732 TextValue
: CBITextValue
,
1733 DummyValue
: CBIDummyValue
,
1734 Button
: CBIButtonValue
,
1735 HiddenValue
: CBIHiddenValue
,
1736 SectionValue
: CBISectionValue