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