1	<script type="text/x-jquery-tmpl" id="hostInterfaceRow">
2<tr class="interfaceRow" id="hostInterfaceRow_#{iface.interfaceid}" data-interfaceid="#{iface.interfaceid}">
3	<td class="interface-drag-control <?= ZBX_STYLE_TD_DRAG_ICON ?>">
4		<div class="<?= ZBX_STYLE_DRAG_ICON ?>"></div>
5		<input type="hidden" name="interfaces[#{iface.interfaceid}][items]" value="#{iface.items}" />
6		<input type="hidden" name="interfaces[#{iface.interfaceid}][locked]" value="#{iface.locked}" />
7	</td>
8	<td class="interface-ip">
9		<input type="hidden" name="interfaces[#{iface.interfaceid}][isNew]" value="#{iface.isNew}">
10		<input type="hidden" name="interfaces[#{iface.interfaceid}][interfaceid]" value="#{iface.interfaceid}">
11		<input type="hidden" id="interface_type_#{iface.interfaceid}" name="interfaces[#{iface.interfaceid}][type]" value="#{iface.type}">
12		<input name="interfaces[#{iface.interfaceid}][ip]" type="text" style="width: <?= ZBX_TEXTAREA_INTERFACE_IP_WIDTH ?>px" maxlength="64" value="#{iface.ip}">
13		<ul class="interface-bulk <?= ZBX_STYLE_LIST_CHECK_RADIO ?> <?= ZBX_STYLE_HOR_LIST ?>">
14			<li>
15				<input class="<?= ZBX_STYLE_CHECKBOX_RADIO ?>" type="checkbox" id="interfaces_#{iface.interfaceid}_bulk" name="interfaces[#{iface.interfaceid}][bulk]" value="1" #{attrs.checked_bulk}>
16				<label for="interfaces_#{iface.interfaceid}_bulk"><span></span><?= _('Use bulk requests') ?></label>
17			</li>
18		</ul>
19	</td>
20	<td class="interface-dns">
21		<?= (new CTextBox('interfaces[#{iface.interfaceid}][dns]', '#{iface.dns}', false,
22				DB::getFieldLength('interface', 'dns'))
23			)
24				->setWidth(ZBX_TEXTAREA_INTERFACE_DNS_WIDTH)
25		?>
26	</td>
27	<?= (new CCol(
28			(new CRadioButtonList('interfaces[#{iface.interfaceid}][useip]', null))
29				->addValue(_('IP'), INTERFACE_USE_IP, 'interfaces[#{iface.interfaceid}][useip]['.INTERFACE_USE_IP.']')
30				->addValue(_('DNS'), INTERFACE_USE_DNS,
31					'interfaces[#{iface.interfaceid}][useip]['.INTERFACE_USE_DNS.']'
32				)
33				->setModern(true)
34		))->toString()
35	?>
36	<td class="interface-port">
37		<?= (new CTextBox('interfaces[#{iface.interfaceid}][port]', '#{iface.port}', false, 64))
38				->setWidth(ZBX_TEXTAREA_INTERFACE_PORT_WIDTH)
39				->setAriaRequired()
40		?>
41	</td>
42	<td class="interface-default">
43		<input class="mainInterface <?= ZBX_STYLE_CHECKBOX_RADIO ?>" type="radio" id="interface_main_#{iface.interfaceid}" name="mainInterfaces[#{iface.type}]" value="#{iface.interfaceid}">
44		<label class="checkboxLikeLabel" for="interface_main_#{iface.interfaceid}" style="height: 16px; width: 16px;"><span></span></label>
45	</td>
46	<td class="<?= ZBX_STYLE_NOWRAP ?> interface-control">
47		<button class="<?= ZBX_STYLE_BTN_LINK ?> remove" type="button" id="removeInterface_#{iface.interfaceid}" data-interfaceid="#{iface.interfaceid}" #{attrs.disabled}><?= _('Remove') ?></button>
48	</td>
49</tr>
50</script>
51
52<script type="text/javascript">
53	var hostInterfacesManager = (function() {
54		'use strict';
55
56		var rowTemplate = new Template(jQuery('#hostInterfaceRow').html()),
57			ports = {
58				agent: 10050,
59				snmp: 161,
60				jmx: 12345,
61				ipmi: 623
62			},
63			allHostInterfaces = {};
64
65		function renderHostInterfaceRow(hostInterface) {
66			var domAttrs = getDomElementsAttrsForInterface(hostInterface),
67				domId = getDomIdForRowInsert(hostInterface.type),
68				domRow;
69
70			jQuery(domId).before(rowTemplate.evaluate({iface: hostInterface, attrs: domAttrs}));
71
72			domRow = jQuery('#hostInterfaceRow_' + hostInterface.interfaceid);
73
74			if (hostInterface.type != <?= INTERFACE_TYPE_SNMP ?>) {
75				jQuery('.interface-bulk', domRow).remove();
76			}
77
78			jQuery('#interfaces_' + hostInterface.interfaceid + '_useip_' + hostInterface.useip).prop('checked', true)
79				.trigger('click');
80
81			if (hostInterface.locked > 0) {
82				addNotDraggableIcon(domRow);
83			}
84			else {
85				addDraggableIcon(domRow);
86			}
87		}
88
89		function resetMainInterfaces() {
90			var typeInterfaces,
91				hostInterfaces = getMainInterfacesByType();
92
93			for (var hostInterfaceType in hostInterfaces) {
94				typeInterfaces = hostInterfaces[hostInterfaceType];
95
96				if (!typeInterfaces.main && typeInterfaces.all.length) {
97					for (var i = 0; i < typeInterfaces.all.length; i++) {
98						if (allHostInterfaces[typeInterfaces.all[i]].main === '1') {
99							typeInterfaces.main = allHostInterfaces[typeInterfaces.all[i]].interfaceid;
100						}
101					}
102					if (!typeInterfaces.main) {
103						typeInterfaces.main = typeInterfaces.all[0];
104						allHostInterfaces[typeInterfaces.main].main = '1';
105					}
106				}
107			}
108
109			for (var hostInterfaceType in hostInterfaces){
110				typeInterfaces = hostInterfaces[hostInterfaceType];
111
112				if (typeInterfaces.main) {
113					jQuery('#interface_main_' + typeInterfaces.main).prop('checked', true);
114				}
115			}
116		}
117
118		function getMainInterfacesByType() {
119			var hostInterface,
120				types = {};
121			types[getHostInterfaceNumericType('agent')] = {main: null, all: []};
122			types[getHostInterfaceNumericType('snmp')] = {main: null, all: []};
123			types[getHostInterfaceNumericType('jmx')] = {main: null, all: []};
124			types[getHostInterfaceNumericType('ipmi')] = {main: null, all: []};
125
126			for (var hostInterfaceId in allHostInterfaces) {
127				hostInterface = allHostInterfaces[hostInterfaceId];
128
129				types[hostInterface.type].all.push(hostInterfaceId);
130				if (hostInterface.main === '1') {
131					if (types[hostInterface.type].main !== null) {
132						throw new Error('Multiple default interfaces for same type.');
133					}
134					types[hostInterface.type].main = hostInterfaceId;
135				}
136			}
137			return types;
138		}
139
140		function addDraggableIcon(domElement) {
141			domElement.draggable({
142				handle: 'div.<?= ZBX_STYLE_DRAG_ICON ?>',
143				opacity: 0.6,
144				revert: 'invalid',
145				helper: function(event) {
146					var hostInterfaceId = jQuery(this).data('interfaceid');
147					var clone = jQuery(this).clone();
148					// Make sure to update names for all radio and checkboxes for them not to affect selection of
149					// originals.
150					// If original is addressed by any means (ex. by ID), make sure, to update these means in clone,
151					// for clone not to be addressed in place of original.
152					clone.find("[name$='[useip]']").each(function(){
153						jQuery(this).attr('name','interfaces[' + hostInterfaceId + '][useip_handle]');
154					});
155					clone.find("#interface_main_" + hostInterfaceId)
156						.attr('name','mainInterfaces[handle]')
157						.attr('id','interface_main_' + hostInterfaceId + '_handle');
158					return clone;
159				},
160				start: function(event, ui) {
161					jQuery(ui.helper).css({'z-index': '1000'});
162					// Visibility is added to original element to hide it, while helper is being moved, but to keep
163					// it's place visually.
164					jQuery(this).css({'visibility': 'hidden'});
165				},
166				stop: function(event, ui) {
167					resetMainInterfaces();
168					jQuery(this).css({'visibility': ''});
169				}
170			});
171		}
172
173		function addNotDraggableIcon(domElement) {
174			jQuery('td.<?= ZBX_STYLE_TD_DRAG_ICON ?> div.<?= ZBX_STYLE_DRAG_ICON ?>', domElement)
175				.addClass('<?= ZBX_STYLE_DISABLED ?>')
176				.hover(
177					function (event) {
178						hintBox.showHint(event, this,
179							<?= CJs::encodeJson(_('Interface is used by items that require this type of the interface.')) ?>
180						);
181					},
182					function () {
183						hintBox.hideHint(this);
184					}
185				);
186		}
187
188		function getDomElementsAttrsForInterface(hostInterface) {
189			var attrs = {
190				disabled: ''
191			};
192
193			if (hostInterface.items > 0) {
194				attrs.disabled = 'disabled="disabled"';
195			}
196
197			if (hostInterface.type == <?= INTERFACE_TYPE_SNMP ?>) {
198				if (hostInterface.bulk == 1) {
199					attrs.checked_bulk = 'checked=checked';
200				}
201				else {
202					attrs.checked_bulk = '';
203				}
204			}
205
206			return attrs;
207		}
208
209		function getDomIdForRowInsert(hostInterfaceType) {
210			var footerRowId;
211
212			switch (hostInterfaceType) {
213				case getHostInterfaceNumericType('agent'):
214					footerRowId = '#agentInterfacesFooter';
215					break;
216				case getHostInterfaceNumericType('snmp'):
217					footerRowId = '#SNMPInterfacesFooter';
218					break;
219				case getHostInterfaceNumericType('jmx'):
220					footerRowId = '#JMXInterfacesFooter';
221					break;
222				case getHostInterfaceNumericType('ipmi'):
223					footerRowId = '#IPMIInterfacesFooter';
224					break;
225				default:
226					throw new Error('Unknown host interface type.');
227			}
228			return footerRowId;
229		}
230
231		function createNewHostInterface(hostInterfaceType) {
232			var newInterface = {
233				isNew: true,
234				useip: 1,
235				type: getHostInterfaceNumericType(hostInterfaceType),
236				port: ports[hostInterfaceType],
237				ip: '127.0.0.1'
238			};
239
240			if (newInterface.type == <?= INTERFACE_TYPE_SNMP ?>) {
241				newInterface.bulk = 1;
242			}
243
244			newInterface.interfaceid = 1;
245			while (allHostInterfaces[newInterface.interfaceid] !== void(0)) {
246				newInterface.interfaceid++;
247			}
248
249			addHostInterface(newInterface);
250
251			return newInterface;
252		}
253
254		function addHostInterface(hostInterface) {
255			allHostInterfaces[hostInterface.interfaceid] = hostInterface;
256		}
257
258		function moveRowToAnotherTypeTable(hostInterfaceId, newHostInterfaceType) {
259			var newDomId = getDomIdForRowInsert(newHostInterfaceType);
260
261			jQuery('#interface_main_' + hostInterfaceId).attr('name', 'mainInterfaces[' + newHostInterfaceType + ']');
262			jQuery('#interface_main_' + hostInterfaceId).prop('checked', false);
263			jQuery('#interface_type_' + hostInterfaceId).val(newHostInterfaceType);
264			jQuery('#hostInterfaceRow_' + hostInterfaceId).insertBefore(newDomId);
265		}
266
267		return {
268			add: function(hostInterfaces) {
269				for (var i = 0; i < hostInterfaces.length; i++) {
270					addHostInterface(hostInterfaces[i]);
271					renderHostInterfaceRow(hostInterfaces[i]);
272				}
273				resetMainInterfaces();
274			},
275
276			addNew: function(type) {
277				var hostInterface = createNewHostInterface(type);
278
279				allHostInterfaces[hostInterface.interfaceid] = hostInterface;
280				renderHostInterfaceRow(hostInterface);
281				resetMainInterfaces();
282			},
283
284			remove: function(hostInterfaceId) {
285				delete allHostInterfaces[hostInterfaceId];
286			},
287
288			setType: function(hostInterfaceId, typeName) {
289				var newTypeNum = getHostInterfaceNumericType(typeName);
290
291				if (allHostInterfaces[hostInterfaceId].type !== newTypeNum) {
292					moveRowToAnotherTypeTable(hostInterfaceId, newTypeNum);
293					allHostInterfaces[hostInterfaceId].type = newTypeNum;
294					allHostInterfaces[hostInterfaceId].main = '0';
295				}
296			},
297
298			resetMainInterfaces: function() {
299				resetMainInterfaces();
300			},
301
302			setMainInterface: function(hostInterfaceId) {
303				var interfacesByType = getMainInterfacesByType(),
304					newMainInterfaceType = allHostInterfaces[hostInterfaceId].type,
305					oldMainInterfaceId = interfacesByType[newMainInterfaceType].main;
306
307				if (hostInterfaceId !== oldMainInterfaceId) {
308					allHostInterfaces[hostInterfaceId].main = '1';
309					allHostInterfaces[oldMainInterfaceId].main = '0';
310				}
311			},
312
313			setUseipForInterface: function(hostInterfaceId, useip) {
314				allHostInterfaces[hostInterfaceId].useip = useip;
315			},
316
317			disable: function() {
318				jQuery('.interface-drag-control, .interface-control').html('');
319				jQuery('.interfaceRow').find('input')
320					.removeAttr('id')
321					.removeAttr('name');
322				jQuery('.interfaceRow').find('input[type="text"]').prop('readonly', true);
323				jQuery('.interfaceRow').find('input[type="radio"], input[type="checkbox"]').prop('disabled', true);
324			}
325		}
326	}());
327
328	jQuery(document).ready(function() {
329		'use strict';
330
331		jQuery('#hostlist').on('click', 'button.remove', function() {
332			var interfaceId = jQuery(this).data('interfaceid');
333			jQuery('#hostInterfaceRow_' + interfaceId).remove();
334			hostInterfacesManager.remove(interfaceId);
335			hostInterfacesManager.resetMainInterfaces();
336		});
337
338		jQuery('#hostlist').on('click', 'input[type=radio].mainInterface', function() {
339			var interfaceId = jQuery(this).val();
340			hostInterfacesManager.setMainInterface(interfaceId);
341		});
342
343		jQuery('#hostlist').on('click', 'input[type=radio][id*="_useip_"]', function() {
344			var interfaceId = jQuery(this).attr('id').match(/\d+/);
345			hostInterfacesManager.setUseipForInterface(interfaceId[0], jQuery(this).val());
346
347			jQuery('[name^="interfaces['+interfaceId[0]+']["]')
348				.filter('[name$="[ip]"],[name$="[dns]"]')
349				.removeAttr('aria-required')
350				.filter((jQuery(this).val() == <?= INTERFACE_USE_IP ?>) ? '[name$="[ip]"]' : '[name$="[dns]"]')
351				.attr('aria-required', true);
352		});
353
354		jQuery('#tls_connect, #tls_in_psk, #tls_in_cert').change(function() {
355			// If certificate is selected or checked.
356			if (jQuery('input[name=tls_connect]:checked').val() == <?= HOST_ENCRYPTION_CERTIFICATE ?>
357					|| jQuery('#tls_in_cert').is(':checked')) {
358				jQuery('#tls_issuer, #tls_subject').closest('li').show();
359			}
360			else {
361				jQuery('#tls_issuer, #tls_subject').closest('li').hide();
362			}
363
364			// If PSK is selected or checked.
365			if (jQuery('input[name=tls_connect]:checked').val() == <?= HOST_ENCRYPTION_PSK ?>
366					|| jQuery('#tls_in_psk').is(':checked')) {
367				jQuery('#tls_psk, #tls_psk_identity').closest('li').show();
368			}
369			else {
370				jQuery('#tls_psk, #tls_psk_identity').closest('li').hide();
371			}
372		});
373
374		jQuery('#agentInterfaces, #SNMPInterfaces, #JMXInterfaces, #IPMIInterfaces').parent().droppable({
375			tolerance: 'pointer',
376			drop: function(event, ui) {
377				var hostInterfaceTypeName = jQuery(this).data('type'),
378					hostInterfaceId = ui.draggable.data('interfaceid');
379
380				if (getHostInterfaceNumericType(hostInterfaceTypeName) == <?= INTERFACE_TYPE_SNMP ?>) {
381					if (jQuery('.interface-bulk', jQuery('#hostInterfaceRow_' + hostInterfaceId)).length == 0) {
382						var bulkList = jQuery('<ul>', {
383							'class': 'interface-bulk <?= ZBX_STYLE_LIST_CHECK_RADIO ?> <?= ZBX_STYLE_HOR_LIST ?>'
384						});
385
386						var bulkItem = jQuery('<li>');
387
388						// append checkbox
389						bulkItem.append(jQuery('<input>', {
390							id: 'interfaces_' + hostInterfaceId + '_bulk',
391							type: 'checkbox',
392							class: '<?= ZBX_STYLE_CHECKBOX_RADIO ?>',
393							name: 'interfaces[' + hostInterfaceId + '][bulk]',
394							value: 1,
395							checked: true
396						}));
397
398						// append label
399						var bulkLabel = jQuery('<label>', {
400							'for': 'interfaces_' + hostInterfaceId + '_bulk',
401						});
402
403						bulkLabel.append(jQuery('<span>'));
404						bulkLabel.append(<?= CJs::encodeJson(_('Use bulk requests')) ?>);
405
406						bulkItem.append(bulkLabel);
407						bulkList.append(bulkItem);
408
409						jQuery('.interface-ip', jQuery('#hostInterfaceRow_' + hostInterfaceId)).append(bulkList);
410					}
411				}
412				else {
413					jQuery('.interface-bulk', jQuery('#hostInterfaceRow_' + hostInterfaceId)).remove();
414				}
415
416				hostInterfacesManager.setType(hostInterfaceId, hostInterfaceTypeName);
417			},
418			activate: function(event, ui) {
419				if (!jQuery(this).find(ui.draggable).length) {
420					jQuery(this).addClass('<?= ZBX_STYLE_DRAG_DROP_AREA ?>');
421				}
422			},
423			deactivate: function(event, ui) {
424				jQuery(this).removeClass('<?= ZBX_STYLE_DRAG_DROP_AREA ?>');
425			}
426		});
427
428		jQuery('#addAgentInterface').on('click', function() {
429			hostInterfacesManager.addNew('agent');
430		});
431		jQuery('#addSNMPInterface').on('click', function() {
432			hostInterfacesManager.addNew('snmp');
433		});
434		jQuery('#addJMXInterface').on('click', function() {
435			hostInterfacesManager.addNew('jmx');
436		});
437		jQuery('#addIPMIInterface').on('click', function() {
438			hostInterfacesManager.addNew('ipmi');
439		});
440
441		// radio button of inventory modes was clicked
442		jQuery('input[name=inventory_mode]').click(function() {
443			// action depending on which button was clicked
444			var inventoryFields = jQuery('#inventorylist :input:gt(2)');
445
446			switch (jQuery(this).val()) {
447				case '<?= HOST_INVENTORY_DISABLED ?>':
448					inventoryFields.prop('disabled', true);
449					jQuery('.populating_item').hide();
450					break;
451				case '<?= HOST_INVENTORY_MANUAL ?>':
452					inventoryFields.prop('disabled', false);
453					jQuery('.populating_item').hide();
454					break;
455				case '<?= HOST_INVENTORY_AUTOMATIC ?>':
456					inventoryFields.prop('disabled', false);
457					inventoryFields.filter('.linked_to_item').prop('disabled', true);
458					jQuery('.populating_item').show();
459					break;
460			}
461		});
462
463		/**
464		 * Mass update
465		 */
466		jQuery('#mass_replace_tpls').on('change', function() {
467			jQuery('#mass_clear_tpls').prop('disabled', !this.checked);
468		}).change();
469
470		// Refresh field visibility on document load.
471		if ((jQuery('#tls_accept').val() & <?= HOST_ENCRYPTION_NONE ?>) == <?= HOST_ENCRYPTION_NONE ?>) {
472			jQuery('#tls_in_none').prop('checked', true);
473		}
474		if ((jQuery('#tls_accept').val() & <?= HOST_ENCRYPTION_PSK ?>) == <?= HOST_ENCRYPTION_PSK ?>) {
475			jQuery('#tls_in_psk').prop('checked', true);
476		}
477		if ((jQuery('#tls_accept').val() & <?= HOST_ENCRYPTION_CERTIFICATE ?>) == <?= HOST_ENCRYPTION_CERTIFICATE ?>) {
478			jQuery('#tls_in_cert').prop('checked', true);
479		}
480
481		jQuery('input[name=tls_connect]').trigger('change');
482
483		// Depending on checkboxes, create a value for hidden field 'tls_accept'.
484		jQuery('#hostForm').submit(function() {
485			var tls_accept = 0x00;
486
487			if (jQuery('#tls_in_none').is(':checked')) {
488				tls_accept |= <?= HOST_ENCRYPTION_NONE ?>;
489			}
490			if (jQuery('#tls_in_psk').is(':checked')) {
491				tls_accept |= <?= HOST_ENCRYPTION_PSK ?>;
492			}
493			if (jQuery('#tls_in_cert').is(':checked')) {
494				tls_accept |= <?= HOST_ENCRYPTION_CERTIFICATE ?>;
495			}
496
497			jQuery('#tls_accept').val(tls_accept);
498		});
499	});
500
501	function getHostInterfaceNumericType(typeName) {
502		var typeNum;
503
504		switch (typeName) {
505			case 'agent':
506				typeNum = '<?= INTERFACE_TYPE_AGENT ?>';
507				break;
508			case 'snmp':
509				typeNum = '<?= INTERFACE_TYPE_SNMP ?>';
510				break;
511			case 'jmx':
512				typeNum = '<?= INTERFACE_TYPE_JMX ?>';
513				break;
514			case 'ipmi':
515				typeNum = '<?= INTERFACE_TYPE_IPMI ?>';
516				break;
517			default:
518				throw new Error('Unknown host interface type name.');
519		}
520		return typeNum;
521	}
522</script>
523