7 var CBIZoneSelect = form.ListValue.extend({
8 __name__: 'CBI.ZoneSelect',
10 load: function(section_id) {
11 return Promise.all([ firewall.getZones(), network.getNetworks() ]).then(L.bind(function(zn) {
13 this.networks = zn[1];
15 return this.super('load', section_id);
19 filter: function(section_id, value) {
23 lookupZone: function(name) {
24 return this.zones.filter(function(zone) { return zone.getName() == name })[0];
27 lookupNetwork: function(name) {
28 return this.networks.filter(function(network) { return network.getName() == name })[0];
31 renderWidget: function(section_id, option_index, cfgvalue) {
32 var values = L.toArray((cfgvalue != null) ? cfgvalue : this.default),
36 if (this.option == 'dest') {
37 for (var i = 0; i < this.section.children.length; i++) {
38 var opt = this.section.children[i];
39 if (opt.option == 'src') {
40 var val = opt.cfgvalue(section_id) || opt.default;
41 isOutputOnly = (val == null || val == '');
46 this.title = isOutputOnly ? _('Output zone') : _('Destination zone');
49 if (this.allowlocal) {
50 choices[''] = E('span', {
52 'style': 'background-color:' + firewall.getColorForName(null)
54 E('strong', _('Device')),
55 (this.allowany || this.allowlocal)
56 ? ' (%s)'.format(this.option != 'dest' ? _('output') : _('input')) : ''
59 else if (!this.multiple && (this.rmempty || this.optional)) {
60 choices[''] = E('span', {
62 'style': 'background-color:' + firewall.getColorForName(null)
63 }, E('em', _('unspecified')));
67 choices['*'] = E('span', {
69 'style': 'background-color:' + firewall.getColorForName(null)
71 E('strong', _('Any zone')),
72 (this.allowany && this.allowlocal && !isOutputOnly) ? ' (%s)'.format(_('forward')) : ''
76 for (var i = 0; i < this.zones.length; i++) {
77 var zone = this.zones[i],
78 name = zone.getName(),
79 networks = zone.getNetworks(),
82 if (!this.filter(section_id, name))
85 for (var j = 0; j < networks.length; j++) {
86 var network = this.lookupNetwork(networks[j]);
91 var span = E('span', {
92 'class': 'ifacebadge' + (network.getName() == this.network ? ' ifacebadge-active' : '')
93 }, network.getName() + ': ');
95 var devices = network.isBridge() ? network.getDevices() : L.toArray(network.getDevice());
97 for (var k = 0; k < devices.length; k++) {
98 span.appendChild(E('img', {
99 'title': devices[k].getI18n(),
100 'src': L.resource('icons/%s%s.png'.format(devices[k].getType(), devices[k].isUp() ? '' : '_disabled'))
105 span.appendChild(E('em', _('(empty)')));
111 ifaces.push(E('em', _('(empty)')));
113 choices[name] = E('span', {
114 'class': 'zonebadge',
115 'style': 'background-color:' + zone.getColor()
116 }, [ E('strong', name) ].concat(ifaces));
119 var widget = new ui.Dropdown(values, choices, {
120 id: this.cbid(section_id),
122 multiple: this.multiple,
123 optional: this.optional || this.rmempty,
124 select_placeholder: E('em', _('unspecified')),
125 display_items: this.display_size || this.size || 3,
126 dropdown_items: this.dropdown_size || this.size || 5,
127 validate: L.bind(this.validate, this, section_id),
128 create: !this.nocreate,
130 '<li data-value="{{value}}">' +
131 '<span class="zonebadge" style="background:repeating-linear-gradient(45deg,rgba(204,204,204,0.5),rgba(204,204,204,0.5) 5px,rgba(255,255,255,0.5) 5px,rgba(255,255,255,0.5) 10px)">' +
132 '<strong>{{value}}:</strong> <em>('+_('create')+')</em>' +
137 var elem = widget.render();
139 if (this.option == 'src') {
140 elem.addEventListener('cbi-dropdown-change', L.bind(function(ev) {
141 var opt = this.map.lookupOption('dest', section_id),
142 val = ev.detail.instance.getValue();
147 var cbid = opt[0].cbid(section_id),
148 label = document.querySelector('label[for="widget.%s"]'.format(cbid)),
149 node = document.getElementById(cbid);
151 L.dom.content(label, val == '' ? _('Output zone') : _('Destination zone'));
154 if (L.dom.callClassMethod(node, 'getValue') == '')
155 L.dom.callClassMethod(node, 'setValue', '*');
157 var emptyval = node.querySelector('[data-value=""]'),
158 anyval = node.querySelector('[data-value="*"]');
160 L.dom.content(anyval.querySelector('span'), E('strong', _('Any zone')));
162 if (emptyval != null)
163 emptyval.parentNode.removeChild(emptyval);
166 var anyval = node.querySelector('[data-value="*"]'),
167 emptyval = node.querySelector('[data-value=""]');
169 if (emptyval == null) {
170 emptyval = anyval.cloneNode(true);
171 emptyval.removeAttribute('display');
172 emptyval.removeAttribute('selected');
173 emptyval.setAttribute('data-value', '');
176 L.dom.content(emptyval.querySelector('span'), [
177 E('strong', _('Device')), ' (%s)'.format(_('input'))
180 L.dom.content(anyval.querySelector('span'), [
181 E('strong', _('Any zone')), ' (%s)'.format(_('forward'))
184 anyval.parentNode.insertBefore(emptyval, anyval);
189 else if (isOutputOnly) {
190 var emptyval = elem.querySelector('[data-value=""]');
191 emptyval.parentNode.removeChild(emptyval);
198 var CBIZoneForwards = form.DummyValue.extend({
199 __name__: 'CBI.ZoneForwards',
201 load: function(section_id) {
203 firewall.getDefaults(),
205 network.getNetworks(),
207 ]).then(L.bind(function(dznd) {
208 this.defaults = dznd[0];
209 this.zones = dznd[1];
210 this.networks = dznd[2];
211 this.devices = dznd[3];
213 return this.super('load', section_id);
217 renderZone: function(zone) {
218 var name = zone.getName(),
219 networks = zone.getNetworks(),
220 devices = zone.getDevices(),
221 subnets = zone.getSubnets(),
224 for (var j = 0; j < networks.length; j++) {
225 var network = this.networks.filter(function(net) { return net.getName() == networks[j] })[0];
230 var span = E('span', {
231 'class': 'ifacebadge' + (network.getName() == this.network ? ' ifacebadge-active' : '')
232 }, network.getName() + ': ');
234 var subdevs = network.isBridge() ? network.getDevices() : L.toArray(network.getDevice());
236 for (var k = 0; k < subdevs.length && subdevs[k]; k++) {
237 span.appendChild(E('img', {
238 'title': subdevs[k].getI18n(),
239 'src': L.resource('icons/%s%s.png'.format(subdevs[k].getType(), subdevs[k].isUp() ? '' : '_disabled'))
244 span.appendChild(E('em', _('(empty)')));
249 for (var i = 0; i < devices.length; i++) {
250 var device = this.devices.filter(function(dev) { return dev.getName() == devices[i] })[0],
251 title = device ? device.getI18n() : _('Absent Interface'),
252 type = device ? device.getType() : 'ethernet',
253 up = device ? device.isUp() : false;
255 ifaces.push(E('span', { 'class': 'ifacebadge' }, [
258 'src': L.resource('icons/%s%s.png'.format(type, up ? '' : '_disabled'))
260 device ? device.getName() : devices[i]
264 if (subnets.length > 0)
265 ifaces.push(E('span', { 'class': 'ifacebadge' }, [ '{ %s }'.format(subnets.join('; ')) ]));
268 ifaces.push(E('span', { 'class': 'ifacebadge' }, E('em', _('(empty)'))));
271 'class': 'zonebadge cbi-tooltip-container',
272 'style': 'background-color:' + zone.getColor()
275 E('div', { 'class': 'cbi-tooltip' }, ifaces)
279 renderWidget: function(section_id, option_index, cfgvalue) {
280 var value = (cfgvalue != null) ? cfgvalue : this.default,
281 zone = this.zones.filter(function(z) { return z.getName() == value })[0];
286 var forwards = zone.getForwardingsBy('src'),
289 for (var i = 0; i < forwards.length; i++) {
290 var dzone = forwards[i].getDestinationZone();
295 dzones.push(this.renderZone(dzone));
299 dzones.push(E('label', { 'class': 'zonebadge zonebadge-empty' },
300 E('strong', this.defaults.getForward())));
302 return E('div', { 'class': 'zone-forwards' }, [
303 E('div', { 'class': 'zone-src' }, this.renderZone(zone)),
305 E('div', { 'class': 'zone-dest' }, dzones)
310 var CBINetworkSelect = form.ListValue.extend({
311 __name__: 'CBI.NetworkSelect',
313 load: function(section_id) {
314 return network.getNetworks().then(L.bind(function(networks) {
315 this.networks = networks;
317 return this.super('load', section_id);
321 filter: function(section_id, value) {
325 renderIfaceBadge: function(network) {
326 var span = E('span', { 'class': 'ifacebadge' }, network.getName() + ': '),
327 devices = network.isBridge() ? network.getDevices() : L.toArray(network.getDevice());
329 for (var j = 0; j < devices.length && devices[j]; j++) {
330 span.appendChild(E('img', {
331 'title': devices[j].getI18n(),
332 'src': L.resource('icons/%s%s.png'.format(devices[j].getType(), devices[j].isUp() ? '' : '_disabled'))
336 if (!devices.length) {
337 span.appendChild(E('em', { 'class': 'hide-close' }, _('(no interfaces attached)')));
338 span.appendChild(E('em', { 'class': 'hide-open' }, '-'));
344 renderWidget: function(section_id, option_index, cfgvalue) {
345 var values = L.toArray((cfgvalue != null) ? cfgvalue : this.default),
349 for (var i = 0; i < values.length; i++)
350 checked[values[i]] = true;
354 if (!this.multiple && (this.rmempty || this.optional))
355 choices[''] = E('em', _('unspecified'));
357 for (var i = 0; i < this.networks.length; i++) {
358 var network = this.networks[i],
359 name = network.getName();
361 if (name == 'loopback' || name == this.exclude || !this.filter(section_id, name))
364 if (this.novirtual && network.isVirtual())
370 choices[name] = this.renderIfaceBadge(network);
373 var widget = new ui.Dropdown(this.multiple ? values : values[0], choices, {
374 id: this.cbid(section_id),
376 multiple: this.multiple,
377 optional: this.optional || this.rmempty,
378 select_placeholder: E('em', _('unspecified')),
379 display_items: this.display_size || this.size || 3,
380 dropdown_items: this.dropdown_size || this.size || 5,
381 validate: L.bind(this.validate, this, section_id),
382 create: !this.nocreate,
384 '<li data-value="{{value}}">' +
385 '<span class="ifacebadge" style="background:repeating-linear-gradient(45deg,rgba(204,204,204,0.5),rgba(204,204,204,0.5) 5px,rgba(255,255,255,0.5) 5px,rgba(255,255,255,0.5) 10px)">' +
386 '{{value}}: <em>('+_('create')+')</em>' +
391 return widget.render();
394 textvalue: function(section_id) {
395 var cfgvalue = this.cfgvalue(section_id),
396 values = L.toArray((cfgvalue != null) ? cfgvalue : this.default),
399 for (var i = 0; i < (this.networks || []).length; i++) {
400 var network = this.networks[i],
401 name = network.getName();
403 if (values.indexOf(name) == -1)
407 L.dom.append(rv, ' ');
409 L.dom.append(rv, this.renderIfaceBadge(network));
413 rv.appendChild(E('em', _('unspecified')));
419 var CBIDeviceSelect = form.ListValue.extend({
420 __name__: 'CBI.DeviceSelect',
422 load: function(section_id) {
424 network.getDevices(),
425 this.noaliases ? null : network.getNetworks()
426 ]).then(L.bind(function(data) {
427 this.devices = data[0];
428 this.networks = data[1];
430 return this.super('load', section_id);
434 filter: function(section_id, value) {
438 renderWidget: function(section_id, option_index, cfgvalue) {
439 var values = L.toArray((cfgvalue != null) ? cfgvalue : this.default),
444 for (var i = 0; i < values.length; i++)
445 checked[values[i]] = true;
449 if (!this.multiple && (this.rmempty || this.optional))
450 choices[''] = E('em', _('unspecified'));
452 for (var i = 0; i < this.devices.length; i++) {
453 var device = this.devices[i],
454 name = device.getName(),
455 type = device.getType();
457 if (name == 'lo' || name == this.exclude || !this.filter(section_id, name))
460 if (this.noaliases && type == 'alias')
463 if (this.nobridges && type == 'bridge')
466 if (this.noinactive && device.isUp() == false)
471 'title': device.getI18n(),
472 'src': L.resource('icons/%s%s.png'.format(type, device.isUp() ? '' : '_disabled'))
474 E('span', { 'class': 'hide-open' }, [ name ]),
475 E('span', { 'class': 'hide-close'}, [ device.getI18n() ])
478 var networks = device.getNetworks();
480 if (networks.length > 0)
481 L.dom.append(item.lastChild, [ ' (', networks.map(function(n) { return n.getName() }).join(', '), ')' ]);
486 choices[name] = item;
490 if (this.networks != null) {
491 for (var i = 0; i < this.networks.length; i++) {
492 var net = this.networks[i],
493 device = network.instantiateDevice('@%s'.format(net.getName()), net),
494 name = device.getName();
496 if (name == '@loopback' || name == this.exclude || !this.filter(section_id, name))
499 if (this.noinactive && net.isUp() == false)
504 'title': device.getI18n(),
505 'src': L.resource('icons/alias%s.png'.format(net.isUp() ? '' : '_disabled'))
507 E('span', { 'class': 'hide-open' }, [ name ]),
508 E('span', { 'class': 'hide-close'}, [ device.getI18n() ])
514 choices[name] = item;
519 if (!this.nocreate) {
520 var keys = Object.keys(checked).sort();
522 for (var i = 0; i < keys.length; i++) {
523 if (choices.hasOwnProperty(keys[i]))
526 choices[keys[i]] = E([
528 'title': _('Absent Interface'),
529 'src': L.resource('icons/ethernet_disabled.png')
531 E('span', { 'class': 'hide-open' }, [ keys[i] ]),
532 E('span', { 'class': 'hide-close'}, [ '%s: "%h"'.format(_('Absent Interface'), keys[i]) ])
535 values.push(keys[i]);
540 var widget = new ui.Dropdown(this.multiple ? values : values[0], choices, {
541 id: this.cbid(section_id),
543 multiple: this.multiple,
544 optional: this.optional || this.rmempty,
545 select_placeholder: E('em', _('unspecified')),
546 display_items: this.display_size || this.size || 3,
547 dropdown_items: this.dropdown_size || this.size || 5,
548 validate: L.bind(this.validate, this, section_id),
549 create: !this.nocreate,
551 '<li data-value="{{value}}">' +
552 '<img title="'+_('Custom Interface')+': "{{value}}"" src="'+L.resource('icons/ethernet_disabled.png')+'" />' +
553 '<span class="hide-open">{{value}}</span>' +
554 '<span class="hide-close">'+_('Custom Interface')+': "{{value}}"</span>' +
558 return widget.render();
563 return L.Class.extend({
564 ZoneSelect: CBIZoneSelect,
565 ZoneForwards: CBIZoneForwards,
566 NetworkSelect: CBINetworkSelect,
567 DeviceSelect: CBIDeviceSelect,