mirror of
https://github.com/Cacti/cacti.git
synced 2026-10-23 03:27:02 +09:00
Add a jQuery rebind() helper and roll it out across the core UI (#8279)
* Add a jQuery rebind() helper and roll it out across the core UI Add $.fn.rebind(events[, selector], handler...) to include/layout.js as a shorthand for the common off(events).on(events, ...) re-attach idiom, then convert the matching chained calls across the core JavaScript and inline PHP handlers to use it. Only pairs whose off() and on() events (and delegated selector) match are converted; off() with no arguments is left as-is since it intentionally clears every handler. * changelog: add 8279.feature fragment * tests: update layout.js JS tests for the rebind() helper * tests: assert the cactiPostAction handler via rebind() * rebind: preserve the delegated selector for the two-argument event-map overload; add helper tests
This commit is contained in:
1 parent
d49126df58
commit
bfa3efb7a9
27 files changed
+214
-98
No files matched your search
@@ -682,7 +682,7 @@ function cdef_edit() : void {
|
||||
|
||||
applySkin();
|
||||
|
||||
$('#continue').off('click').on('click', function(data) {
|
||||
$('#continue').rebind('click', function(data) {
|
||||
$.post('cdef.php?action=item_remove', {
|
||||
__csrf_magic: csrfMagicToken,
|
||||
cdef_id: $('#my_cdef_id').val(),
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Add a jQuery rebind() helper for the common off(events).on(events, ...) idiom and roll it out across the core JavaScript and inline PHP event handlers
|
||||
@@ -1201,7 +1201,7 @@ function profile_edit() : void {
|
||||
|
||||
applySkin();
|
||||
|
||||
$('#continue').off('click').on('click', function(data) {
|
||||
$('#continue').rebind('click', function(data) {
|
||||
$.post('data_source_profiles.php?action=item_remove', {
|
||||
__csrf_magic: csrfMagicToken,
|
||||
id: $('#rra_id').val()
|
||||
|
||||
@@ -265,13 +265,13 @@ midwinter.navigationBox.table = {
|
||||
const ns = midwinter.navigationBox.table;
|
||||
|
||||
// bind toggle checkboxes
|
||||
$box.off('change', '.plugin-table-toggle').on('change', '.plugin-table-toggle', (e) => {
|
||||
$box.rebind('change', '.plugin-table-toggle', (e) => {
|
||||
const $el = $(e.currentTarget);
|
||||
ns._executeToggle($el.data('table'), $el.data('column'), e.target.checked);
|
||||
});
|
||||
|
||||
// bind reset control button
|
||||
$box.off('click', '[data-action="reset_table"]').on('click', '[data-action="reset_table"]', (e) => {
|
||||
$box.rebind('click', '[data-action="reset_table"]', (e) => {
|
||||
const tableHash = $box.find('input[data-table]').first().data('table');
|
||||
ns._executeReset(tableHash);
|
||||
});
|
||||
|
||||
+45
-30
@@ -278,6 +278,22 @@ $.fn.delayKeyup = function (callback, ms) {
|
||||
return $(this);
|
||||
};
|
||||
|
||||
/**
|
||||
* rebind - Shorthand for off(events).on(events, ...) to cleanly re-attach an
|
||||
* event handler, optionally for a delegated selector.
|
||||
*/
|
||||
$.fn.rebind = function (events) {
|
||||
// A string second argument is always a delegated selector (jQuery never
|
||||
// treats a string as handler data), including the .on(map, selector) overload.
|
||||
if (typeof arguments[1] === 'string') {
|
||||
this.off(events, arguments[1]);
|
||||
} else {
|
||||
this.off(events);
|
||||
}
|
||||
|
||||
return this.on.apply(this, arguments);
|
||||
};
|
||||
|
||||
/**
|
||||
* bindFirst - Function ensures that the event is found at the top
|
||||
* of the event stack.
|
||||
@@ -735,7 +751,7 @@ function updateCheckboxes(checkboxes, clicked_element) {
|
||||
* taking action as required to enable or disable rows. */
|
||||
function applySelectorVisibilityAndActions() {
|
||||
// Change for accessibility
|
||||
$('input[type="radio"]').off('click').on('click', function () {
|
||||
$('input[type="radio"]').rebind('click', function () {
|
||||
if ($(this).is(':checked')) {
|
||||
$(this).attr('aria-checked', 'true');
|
||||
} else {
|
||||
@@ -754,12 +770,12 @@ function applySelectorVisibilityAndActions() {
|
||||
});
|
||||
|
||||
// Create Actions for Rows
|
||||
$('tr[id^="gt_line"].selectable:not(.disabled_row)').off('click').on('click', function (event) {
|
||||
$('tr[id^="gt_line"].selectable:not(.disabled_row)').rebind('click', function (event) {
|
||||
selectUpdateRow(event, $(this));
|
||||
});
|
||||
|
||||
// Create Actions for Rows
|
||||
$('tr[id^="line"].selectable').filter(':not(.disabled_row)').off('click').on('click', function (event) {
|
||||
$('tr[id^="line"].selectable').filter(':not(.disabled_row)').rebind('click', function (event) {
|
||||
selectUpdateRow(event, $(this));
|
||||
});
|
||||
}
|
||||
@@ -845,7 +861,7 @@ function dqUpdateDeps(snmp_query_id) {
|
||||
$('#all_' + snmp_query_id).prop('checked', false);
|
||||
}
|
||||
|
||||
$('tr[id^="dqline' + snmp_query_id + '_"]').not('.disabled_row').off('click').on('click', function (event) {
|
||||
$('tr[id^="dqline' + snmp_query_id + '_"]').not('.disabled_row').rebind('click', function (event) {
|
||||
selectUpdateRow(event, $(this));
|
||||
});
|
||||
}
|
||||
@@ -943,8 +959,7 @@ function cactiReturnTo(href) {
|
||||
function setupSelectmenuScrollClose() {
|
||||
$('.cactiConsoleContentArea, .cactiGraphContentArea, .cactiGraphContentAreaPreview, .cactiTreeNavigationArea')
|
||||
.add(window)
|
||||
.off('scroll.cactiSelectmenu')
|
||||
.on('scroll.cactiSelectmenu', function () {
|
||||
.rebind('scroll.cactiSelectmenu', function () {
|
||||
if (!$('.ui-selectmenu-open').length) {
|
||||
return;
|
||||
}
|
||||
@@ -1039,7 +1054,7 @@ function applySkin() {
|
||||
|
||||
setupObjectChange();
|
||||
|
||||
$('.helpPage').off('click').on('click', function (event) {
|
||||
$('.helpPage').rebind('click', function (event) {
|
||||
event.stopPropagation();
|
||||
|
||||
getCactiHelp($(this).attr('data-page'));
|
||||
@@ -1058,7 +1073,7 @@ function applySkin() {
|
||||
setupButtonStyle();
|
||||
|
||||
// Debug message actions
|
||||
$('table.debug tr:nth-child(1)').off('click').on('click', function () {
|
||||
$('table.debug tr:nth-child(1)').rebind('click', function () {
|
||||
if ($(this).parent().find('table').is(':visible')) {
|
||||
$(this).parent().find('table').slideUp('fast');
|
||||
} else {
|
||||
@@ -1066,7 +1081,7 @@ function applySkin() {
|
||||
}
|
||||
});
|
||||
|
||||
$('.cactiTableCopy').off('click').on('click', function (event) {
|
||||
$('.cactiTableCopy').rebind('click', function (event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
var containerId = $(this).attr('id');
|
||||
@@ -1399,7 +1414,7 @@ function applySkin() {
|
||||
* select2 widget on every AJAX filter reload, but that destroy doesn't remove
|
||||
* a plain jQuery listener bound to the underlying <select> itself, so without
|
||||
* this the handler would accumulate and fire the callback multiple times */
|
||||
$select.off('select2:select.select2Callback').on('select2:select.select2Callback', function() {
|
||||
$select.rebind('select2:select.select2Callback', function() {
|
||||
executeFunctionByName(changeFunc.replace('(', '').replace(')', ''), window);
|
||||
});
|
||||
}
|
||||
@@ -1776,7 +1791,7 @@ function makeFiltersResponsive() {
|
||||
filterHeader.find('div.cactiTableButton').append('<span class="cactiSwitchConstraintWrapper"><a title="' + tableConstraints + '" class="linkOverDark cactiSwitchConstraints" href="#"><i id="overflow" class="ti ti-arrows-diagonal"></i></a></span>');
|
||||
}
|
||||
|
||||
$('.cactiSwitchConstraints').off('click').on('click', function (event) {
|
||||
$('.cactiSwitchConstraints').rebind('click', function (event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
@@ -1800,7 +1815,7 @@ function makeFiltersResponsive() {
|
||||
title = $('#export').attr('title');
|
||||
filterHeader.find('div.cactiTableButton').append($('<span style="display:none;" class="cactiFilterExport"><i class="ti ti-table-export"></i></span>').attr('title', title));
|
||||
|
||||
$('.cactiFilterExport').off('click').on('click', function (event) {
|
||||
$('.cactiFilterExport').rebind('click', function (event) {
|
||||
event.stopPropagation();
|
||||
$('#export').trigger('click');
|
||||
}).tooltip();
|
||||
@@ -1810,7 +1825,7 @@ function makeFiltersResponsive() {
|
||||
title = $('#import').attr('title');
|
||||
filterHeader.find('div.cactiTableButton').append($('<span style="display:none;" class="cactiFilterImport"><i class="ti ti-table-import"></i></span>').attr('title', title));
|
||||
|
||||
$('.cactiFilterImport').off('click').on('click', function (event) {
|
||||
$('.cactiFilterImport').rebind('click', function (event) {
|
||||
event.stopPropagation();
|
||||
$('#import').trigger('click');
|
||||
}).tooltip();
|
||||
@@ -1821,7 +1836,7 @@ function makeFiltersResponsive() {
|
||||
filterHeader.find('div.cactiTableButton').append('<span title="' + clearFilterTitle + '" style="display:none;" class="cactiFilterClear"><i class="ti ti-trash"></i></span>');
|
||||
}
|
||||
|
||||
$('.cactiFilterClear').off('click').on('click', function(event) {
|
||||
$('.cactiFilterClear').rebind('click', function(event) {
|
||||
event.stopPropagation();
|
||||
$('#clear').trigger('click');
|
||||
}).tooltip();
|
||||
@@ -1849,7 +1864,7 @@ function makeFiltersResponsive() {
|
||||
}
|
||||
}
|
||||
|
||||
filterHeader.find('.cactiFilterState').off('click').on('click', function() {
|
||||
filterHeader.find('.cactiFilterState').rebind('click', function() {
|
||||
id = $(this).closest('.cactiTable').attr('id');
|
||||
child = id + '_child';
|
||||
toggleFilterAndIcon(id, child, false);
|
||||
@@ -1933,7 +1948,7 @@ function setGraphTabs() {
|
||||
}
|
||||
|
||||
function setupResponsiveMenuAndTabs() {
|
||||
$('.maintabs a.lefttab, .dropdownMenu a, .menuoptions a, #gtabs a.righttab').not('[href^="http"], [href^="https"], [href^="#"], [target="_blank"]').off('click').on('click', function (event) {
|
||||
$('.maintabs a.lefttab, .dropdownMenu a, .menuoptions a, #gtabs a.righttab').not('[href^="http"], [href^="https"], [href^="#"], [target="_blank"]').rebind('click', function (event) {
|
||||
if (!shouldCaptureClick(event)) {
|
||||
return;
|
||||
}
|
||||
@@ -2790,7 +2805,7 @@ function loadPageUsingPost(href, postData, returnLocation) {
|
||||
function setNavigationScroll() {
|
||||
var object = '';
|
||||
|
||||
$('.cactiConsoleNavigationArea, .cactiTreeNavigationArea').off('mousemove').on('mousemove', function (pos) {
|
||||
$('.cactiConsoleNavigationArea, .cactiTreeNavigationArea').rebind('mousemove', function (pos) {
|
||||
object = '';
|
||||
|
||||
if ($('.cactiConsoleNavigationArea').length) {
|
||||
@@ -2829,7 +2844,7 @@ function setNavigationScroll() {
|
||||
}
|
||||
});
|
||||
|
||||
$('.cactiConsoleNavigationArea, .cactiTreeNavigationArea').off('mouseleave').on('mouseleave', function (pos) {
|
||||
$('.cactiConsoleNavigationArea, .cactiTreeNavigationArea').rebind('mouseleave', function (pos) {
|
||||
if ($('.cactiConsoleNavigationArea').length) {
|
||||
object = '.cactiConsoleNavigationArea';
|
||||
} else if ($('.cactiTreeNavigationArea').length) {
|
||||
@@ -3300,7 +3315,7 @@ function getPresentHTTPErrorOrRedirect(data, url) {
|
||||
function ajaxAnchors() {
|
||||
var page = basename(location.pathname);
|
||||
|
||||
$(document).off('click.cactiPostAction', 'a.cactiPostAction').on('click.cactiPostAction', 'a.cactiPostAction', function (event) {
|
||||
$(document).rebind('click.cactiPostAction', 'a.cactiPostAction', function (event) {
|
||||
if (!shouldCaptureClick(event)) {
|
||||
return;
|
||||
}
|
||||
@@ -3317,7 +3332,7 @@ function ajaxAnchors() {
|
||||
return false;
|
||||
});
|
||||
|
||||
$('a.pic, a.linkOverDark, a.linkEditMain, a.console, a.hyperLink, a.tab').not('[href^="http"], [href^="https"], [href^="#"], [href^="mailto"], [target="_blank"]').not('.cactiPostAction').off('click').on('click', function (event) {
|
||||
$('a.pic, a.linkOverDark, a.linkEditMain, a.console, a.hyperLink, a.tab').not('[href^="http"], [href^="https"], [href^="#"], [href^="mailto"], [target="_blank"]').not('.cactiPostAction').rebind('click', function (event) {
|
||||
if (!shouldCaptureClick(event)) {
|
||||
return;
|
||||
}
|
||||
@@ -3424,7 +3439,7 @@ function setupCollapsible() {
|
||||
}
|
||||
});
|
||||
|
||||
$('.collapsible').off('click').on('click', function (data) {
|
||||
$('.collapsible').rebind('click', function (data) {
|
||||
var id = $(this).attr('id') + '_cs';
|
||||
|
||||
if ($(this).find('i').hasClass('ti-chevrons-up')) {
|
||||
@@ -3499,7 +3514,7 @@ function setupSpecialKeys() {
|
||||
}
|
||||
|
||||
// Clicking the search glyph applies the filter: submit its form, or on the modern bar (no form) trigger Enter.
|
||||
$(document).off('click.cactiSearchIcon').on('click.cactiSearchIcon', 'i.ti.ti-search.filter', function () {
|
||||
$(document).rebind('click.cactiSearchIcon', 'i.ti.ti-search.filter', function () {
|
||||
var input = $(this).prev('input').get(0);
|
||||
if (!input) {
|
||||
return;
|
||||
@@ -4232,7 +4247,7 @@ function setupEllipsis() {
|
||||
'</ul>' +
|
||||
'</div>').appendTo('body');
|
||||
|
||||
$('.maintabs-submenu, .usertabs-submenu, .submenu-ellipsis').off('click').on('click', function (event) {
|
||||
$('.maintabs-submenu, .usertabs-submenu, .submenu-ellipsis').rebind('click', function (event) {
|
||||
event.preventDefault();
|
||||
|
||||
var submenu_index = $(this).attr('id').replace('menu-', 'submenu-');
|
||||
@@ -4844,7 +4859,7 @@ function initializeGraphs(disable_cache) {
|
||||
|
||||
$(this).attr('href', urlPath + pageName + 'action=view' + (tree ? '-tree':'-preview') + '&local_graph_id=' + graph_id);
|
||||
|
||||
$(this).off('click').on('click', function (event) {
|
||||
$(this).rebind('click', function (event) {
|
||||
if (!shouldCaptureClick(event))
|
||||
return;
|
||||
|
||||
@@ -4887,7 +4902,7 @@ function initializeGraphs(disable_cache) {
|
||||
|
||||
$(this).attr('href', url);
|
||||
|
||||
$(this).off('click').on('click', function (event) {
|
||||
$(this).rebind('click', function (event) {
|
||||
if (!shouldCaptureClick(event))
|
||||
return;
|
||||
|
||||
@@ -4907,7 +4922,7 @@ function initializeGraphs(disable_cache) {
|
||||
});
|
||||
});
|
||||
|
||||
$('#form_graph_view').off('submit').on('submit', function (event) {
|
||||
$('#form_graph_view').rebind('submit', function (event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
applyFilter();
|
||||
@@ -5031,11 +5046,11 @@ function initializeGraphs(disable_cache) {
|
||||
});
|
||||
});
|
||||
|
||||
$('#realtimeoff').off('click').on('click', function () {
|
||||
$('#realtimeoff').rebind('click', function () {
|
||||
stopRealtime();
|
||||
});
|
||||
|
||||
$('#ds_step').off('change').on('change', function () {
|
||||
$('#ds_step').rebind('change', function () {
|
||||
realtimeGrapher();
|
||||
});
|
||||
|
||||
@@ -5051,7 +5066,7 @@ function initializeGraphs(disable_cache) {
|
||||
'&graph_start=' + timestampDate1 +
|
||||
'&graph_end=' + timestampDate2);
|
||||
|
||||
$(this).off('click').on('click', function (event) {
|
||||
$(this).rebind('click', function (event) {
|
||||
if (!shouldCaptureClick(event))
|
||||
return;
|
||||
|
||||
@@ -5078,7 +5093,7 @@ function initializeGraphs(disable_cache) {
|
||||
return false;
|
||||
});
|
||||
|
||||
$(this).off('click').on('click', function (event) {
|
||||
$(this).rebind('click', function (event) {
|
||||
if (!shouldCaptureClick(event))
|
||||
return;
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ function themeReady() {
|
||||
|
||||
$(window).trigger('resize');
|
||||
|
||||
$('.action-icon-user').off('click').on('click', function(event) {
|
||||
$('.action-icon-user').rebind('click', function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
if ($('.menuoptions').is(':visible') === false) {
|
||||
@@ -152,7 +152,7 @@ function setMenuVisibility() {
|
||||
$('#navigation').show();
|
||||
|
||||
// Functon to give life to the Navigation pane
|
||||
$('#nav li:has(ul) a.active').off('click').on('click', function(event) {
|
||||
$('#nav li:has(ul) a.active').rebind('click', function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
id = $(this).closest('.menuitem').attr('id');
|
||||
|
||||
@@ -103,7 +103,7 @@ function themeReady() {
|
||||
|
||||
$(window).trigger('resize');
|
||||
|
||||
$('.action-icon-user').off('click').on('click', function(event) {
|
||||
$('.action-icon-user').rebind('click', function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
if ($('.menuoptions').is(':visible') === false) {
|
||||
@@ -152,7 +152,7 @@ function setMenuVisibility() {
|
||||
$('#navigation').show();
|
||||
|
||||
// Functon to give life to the Navigation pane
|
||||
$('#nav li:has(ul) a.active').off('click').on('click', function(event) {
|
||||
$('#nav li:has(ul) a.active').rebind('click', function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
id = $(this).closest('.menuitem').attr('id');
|
||||
|
||||
@@ -166,7 +166,7 @@ function setMenuVisibility() {
|
||||
});
|
||||
|
||||
// Function to give life to the Navigation pane
|
||||
$('#nav li:has(ul) a.active').off('click').on('click', function(event) {
|
||||
$('#nav li:has(ul) a.active').rebind('click', function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
id = $(this).closest('.menuitem').attr('id');
|
||||
|
||||
@@ -104,7 +104,7 @@ function themeReady() {
|
||||
|
||||
$(window).trigger('resize');
|
||||
|
||||
$('.action-icon-user').off('click').on('click', function(event) {
|
||||
$('.action-icon-user').rebind('click', function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
if ($('.menuoptions').is(':visible') === false) {
|
||||
@@ -169,7 +169,7 @@ function setMenuVisibility() {
|
||||
});
|
||||
|
||||
// Function to give life to the Navigation pane
|
||||
$('#nav li:has(ul) a.active').off('click').on('click', function(event) {
|
||||
$('#nav li:has(ul) a.active').rebind('click', function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
id = $(this).closest('.menuitem').attr('id');
|
||||
|
||||
@@ -103,7 +103,7 @@ function themeReady() {
|
||||
|
||||
$(window).trigger('resize');
|
||||
|
||||
$('.action-icon-user').off('click').on('click', function(event) {
|
||||
$('.action-icon-user').rebind('click', function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
if ($('.menuoptions').is(':visible') === false) {
|
||||
@@ -152,7 +152,7 @@ function setMenuVisibility() {
|
||||
$('#navigation').show();
|
||||
|
||||
// Functon to give life to the Navigation pane
|
||||
$('#nav li:has(ul) a.active').off('click').on('click', function(event) {
|
||||
$('#nav li:has(ul) a.active').rebind('click', function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
id = $(this).closest('.menuitem').attr('id');
|
||||
|
||||
@@ -275,7 +275,7 @@ function hideConsoleNavigation() {
|
||||
}
|
||||
|
||||
function updateAjaxAnchors() {
|
||||
$('a.pic, a.linkOverDark, a.linkEditMain, a.console, a.hyperLink, a.tab').not('[href^="http"], [href^="https"], [href^="#"], [href^="mailto"], [target="_blank"]').off('click').on('click', function(event) {
|
||||
$('a.pic, a.linkOverDark, a.linkEditMain, a.console, a.hyperLink, a.tab').not('[href^="http"], [href^="https"], [href^="#"], [href^="mailto"], [target="_blank"]').rebind('click', function(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
@@ -508,7 +508,7 @@ function setupTheme() {
|
||||
const $settingsBox = $('[class^="mdw-ConsoleNavigationBox"][data-helper="settings"]');
|
||||
$('[class^="compact_nav_icon"][data-helper="settings"]').toggleClass('hide', $settingsBox.has('li').length === 0);
|
||||
|
||||
$('#main').off('resize').on('resize', function() {
|
||||
$('#main').rebind('resize', function() {
|
||||
$('#main .saveRowParent').width($(this).width());
|
||||
});
|
||||
}
|
||||
@@ -1088,7 +1088,7 @@ function kioskMode(event = false) {
|
||||
toggleConsoleNavigationBox(event);
|
||||
setDocumentAttribute('kiosk-mode', 'on');
|
||||
if(isMobile.any() != null) {
|
||||
$('#mdw-Main').off('click').on('click', function(e) {
|
||||
$('#mdw-Main').rebind('click', function(e) {
|
||||
let tap;
|
||||
mdw.cache.tab.count++;
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ function setMenuVisibility() {
|
||||
});
|
||||
|
||||
// Function to give life to the Navigation pane
|
||||
$('#nav li:has(ul) a.active').off('click').on('click', function(event) {
|
||||
$('#nav li:has(ul) a.active').rebind('click', function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
id = $(this).closest('.menuitem').attr('id');
|
||||
|
||||
@@ -105,7 +105,7 @@ function themeReady() {
|
||||
/* User Menu */
|
||||
$('.menuoptions').parent().appendTo('body');
|
||||
|
||||
$('.action-icon-user').off('click').on('click', function(event) {
|
||||
$('.action-icon-user').rebind('click', function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
if ($('.menuoptions').is(':visible') === false) {
|
||||
@@ -118,7 +118,7 @@ function themeReady() {
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.bottom_scroll_up').off('click').on('click', function(event) {
|
||||
$('.bottom_scroll_up').rebind('click', function(event) {
|
||||
event.preventDefault();
|
||||
$('#navigation_right').animate({ scrollLeft:0, scrollTop: 0 }, 1000, 'easeInOutQuart');
|
||||
});
|
||||
@@ -187,7 +187,7 @@ function setMenuVisibility() {
|
||||
});
|
||||
|
||||
// Function to give life to the Navigation pane
|
||||
$('#nav li:has(ul) a.active').off('click').on('click', function(event) {
|
||||
$('#nav li:has(ul) a.active').rebind('click', function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
id = $(this).closest('.menuitem').attr('id');
|
||||
|
||||
@@ -104,7 +104,7 @@ function themeReady() {
|
||||
|
||||
$(window).trigger('resize');
|
||||
|
||||
$('.action-icon-user').off('click').on('click', function(event) {
|
||||
$('.action-icon-user').rebind('click', function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
if ($('.menuoptions').is(':visible') === false) {
|
||||
@@ -169,7 +169,7 @@ function setMenuVisibility() {
|
||||
});
|
||||
|
||||
// Function to give life to the Navigation pane
|
||||
$('#nav li:has(ul) a.active').off('click').on('click', function(event) {
|
||||
$('#nav li:has(ul) a.active').rebind('click', function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
id = $(this).closest('.menuitem').attr('id');
|
||||
|
||||
@@ -103,7 +103,7 @@ function themeReady() {
|
||||
|
||||
$(window).trigger('resize');
|
||||
|
||||
$('.action-icon-user').off('click').on('click', function(event) {
|
||||
$('.action-icon-user').rebind('click', function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
if ($('.menuoptions').is(':visible') === false) {
|
||||
@@ -152,7 +152,7 @@ function setMenuVisibility() {
|
||||
$('#navigation').show();
|
||||
|
||||
// Functon to give life to the Navigation pane
|
||||
$('#nav li:has(ul) a.active').off('click').on('click', function(event) {
|
||||
$('#nav li:has(ul) a.active').rebind('click', function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
id = $(this).closest('.menuitem').attr('id');
|
||||
|
||||
@@ -25,7 +25,7 @@ function themeReady() {
|
||||
// Setup the navigation menu
|
||||
setMenuVisibility();
|
||||
|
||||
$('#navigation_right').off('scroll').on('scroll', function (event) {
|
||||
$('#navigation_right').rebind('scroll', function (event) {
|
||||
var scroll_position_x = $('#navigation_right').scrollLeft();
|
||||
var scroll_position_y = $('#navigation_right').scrollTop();
|
||||
$('.bottom_scroll_up').css({'color': ((scroll_position_x == 0 & scroll_position_y == 0) ? '' : '#93CEFF') });
|
||||
@@ -109,7 +109,7 @@ function themeReady() {
|
||||
/* User Menu */
|
||||
$('.menuoptions').parent().appendTo('body');
|
||||
|
||||
$('.action-icon-user').off('click').on('click', function(event) {
|
||||
$('.action-icon-user').rebind('click', function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
if ($('.menuoptions').is(':visible') === false) {
|
||||
@@ -122,7 +122,7 @@ function themeReady() {
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.bottom_scroll_up').off('click').on('click', function(event) {
|
||||
$('.bottom_scroll_up').rebind('click', function(event) {
|
||||
event.preventDefault();
|
||||
$('#navigation_right').animate({ scrollLeft:0, scrollTop: 0 }, 1000, 'easeInOutQuart');
|
||||
});
|
||||
@@ -229,7 +229,7 @@ function setMenuVisibility() {
|
||||
});
|
||||
|
||||
// Function to give life to the Navigation pane
|
||||
$('#nav li:has(ul) a.active').off('click').on('click', function(event) {
|
||||
$('#nav li:has(ul) a.active').rebind('click', function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
id = $(this).closest('.menuitem').attr('id');
|
||||
|
||||
+1
-1
@@ -2158,7 +2158,7 @@ function draw_actions_dropdown(array $actions_array, int $delete_action = 1) : v
|
||||
});
|
||||
}
|
||||
|
||||
$('tr[id^="line"]').filter(':not(.disabled_row)').off('click').on('click', function(event) {
|
||||
$('tr[id^="line"]').filter(':not(.disabled_row)').rebind('click', function(event) {
|
||||
selectUpdateRow(event, $(this));
|
||||
});
|
||||
}
|
||||
|
||||
+11
-11
@@ -1133,35 +1133,35 @@ class CactiTableFilter {
|
||||
case 'timespan':
|
||||
// Delegated bindings survive ajax content reloads that replace the timespan controls; direct .change()/.click() handlers would be lost after the first filter apply.
|
||||
if (!isset($field_array['span_function'])) {
|
||||
$readyAdd .= "$(document).off('change.cactiTimespan', '#predefined_timespan').on('change.cactiTimespan', '#predefined_timespan', function() { applyGraphTimespan(); });" . PHP_EOL;
|
||||
$readyAdd .= "$(document).rebind('change.cactiTimespan', '#predefined_timespan', function() { applyGraphTimespan(); });" . PHP_EOL;
|
||||
} else {
|
||||
$readyAdd .= "$(document).off('change.cactiTimespan', '#predefined_timespan').on('change.cactiTimespan', '#predefined_timespan', function() { " . $field_array['span_function'] . '; });' . PHP_EOL;
|
||||
$readyAdd .= "$(document).rebind('change.cactiTimespan', '#predefined_timespan', function() { " . $field_array['span_function'] . '; });' . PHP_EOL;
|
||||
}
|
||||
|
||||
if (isset($field_array['shifter']) && $field_array['shifter'] === true) {
|
||||
if (!isset($field_array['lshift_function'])) {
|
||||
$readyAdd .= "$(document).off('click.cactiTimespan', '#shift_left').on('click.cactiTimespan', '#shift_left', function() { timeshiftGraphFilterLeft(); });" . PHP_EOL;
|
||||
$readyAdd .= "$(document).rebind('click.cactiTimespan', '#shift_left', function() { timeshiftGraphFilterLeft(); });" . PHP_EOL;
|
||||
} else {
|
||||
$readyAdd .= "$(document).off('click.cactiTimespan', '#shift_left').on('click.cactiTimespan', '#shift_left', function() { " . $field_array['lshift_function'] . '; });' . PHP_EOL;
|
||||
$readyAdd .= "$(document).rebind('click.cactiTimespan', '#shift_left', function() { " . $field_array['lshift_function'] . '; });' . PHP_EOL;
|
||||
}
|
||||
|
||||
if (!isset($field_array['rshift_function'])) {
|
||||
$readyAdd .= "$(document).off('click.cactiTimespan', '#shift_right').on('click.cactiTimespan', '#shift_right', function() { timeshiftGraphFilterRight(); });" . PHP_EOL;
|
||||
$readyAdd .= "$(document).rebind('click.cactiTimespan', '#shift_right', function() { timeshiftGraphFilterRight(); });" . PHP_EOL;
|
||||
} else {
|
||||
$readyAdd .= "$(document).off('click.cactiTimespan', '#shift_right').on('click.cactiTimespan', '#shift_right', function() { " . $field_array['rshift_function'] . '; });' . PHP_EOL;
|
||||
$readyAdd .= "$(document).rebind('click.cactiTimespan', '#shift_right', function() { " . $field_array['rshift_function'] . '; });' . PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($field_array['refresh_function'])) {
|
||||
$readyAdd .= "$(document).off('click.cactiTimespan', '#tsrefresh').on('click.cactiTimespan', '#tsrefresh', function() { $(this).find('i').addClass('icon-rotate'); refreshGraphTimespanFilter(); });" . PHP_EOL;
|
||||
$readyAdd .= "$(document).rebind('click.cactiTimespan', '#tsrefresh', function() { $(this).find('i').addClass('icon-rotate'); refreshGraphTimespanFilter(); });" . PHP_EOL;
|
||||
} else {
|
||||
$readyAdd .= "$(document).off('click.cactiTimespan', '#tsrefresh').on('click.cactiTimespan', '#tsrefresh', function() { $(this).find('i').addClass('icon-rotate'); " . $field_array['refresh_function'] . '; });' . PHP_EOL;
|
||||
$readyAdd .= "$(document).rebind('click.cactiTimespan', '#tsrefresh', function() { $(this).find('i').addClass('icon-rotate'); " . $field_array['refresh_function'] . '; });' . PHP_EOL;
|
||||
}
|
||||
|
||||
if (!isset($field_array['clear_function'])) {
|
||||
$readyAdd .= "$(document).off('click.cactiTimespan', '#tsclear').on('click.cactiTimespan', '#tsclear', function() { clearGraphTimespanFilter(); });" . PHP_EOL;
|
||||
$readyAdd .= "$(document).rebind('click.cactiTimespan', '#tsclear', function() { clearGraphTimespanFilter(); });" . PHP_EOL;
|
||||
} else {
|
||||
$readyAdd .= "$(document).off('click.cactiTimespan', '#tsclear').on('click.cactiTimespan', '#tsclear', function() { " . $field_array['clear_function'] . '; });' . PHP_EOL;
|
||||
$readyAdd .= "$(document).rebind('click.cactiTimespan', '#tsclear', function() { " . $field_array['clear_function'] . '; });' . PHP_EOL;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1591,7 +1591,7 @@ class CactiTableFilter {
|
||||
$js .= "\t$('#layout_delete').click(function() { var id = layoutSelectedId(); if (id == 0 || !layoutEditable()) { return; } layoutDeleteDialog(id); });" . PHP_EOL;
|
||||
$js .= "\t$('#layout_name').keydown(function(e) { if (e.keyCode == 13) { e.preventDefault(); layoutDialogSave(layoutDialogForceNew); } });" . PHP_EOL;
|
||||
// Enter in the bar Search box applies the filter; delegated so it survives ajax content reloads.
|
||||
$js .= "\t$(document).off('keydown.cactiSearch', '#filter, #rfilter').on('keydown.cactiSearch', '#filter, #rfilter', function(e) { if (e.keyCode == 13) { e.preventDefault(); " . $changeFunction . '; } });' . PHP_EOL;
|
||||
$js .= "\t$(document).rebind('keydown.cactiSearch', '#filter, #rfilter', function(e) { if (e.keyCode == 13) { e.preventDefault(); " . $changeFunction . '; } });' . PHP_EOL;
|
||||
$js .= '});' . PHP_EOL;
|
||||
|
||||
$js .= '</script>' . PHP_EOL;
|
||||
|
||||
+2
-2
@@ -2026,7 +2026,7 @@ function html_graph_single_view() : void {
|
||||
});
|
||||
});
|
||||
|
||||
$('a[id$="_util"]').off('click').on('click', function() {
|
||||
$('a[id$="_util"]').rebind('click', function() {
|
||||
graph_id = $(this).attr('id').replace('graph_', '').replace('_util', '');
|
||||
rra_id = $(this).attr('rra_id');
|
||||
graph_start = $(this).attr('graph_start');
|
||||
@@ -2044,7 +2044,7 @@ function html_graph_single_view() : void {
|
||||
});
|
||||
|
||||
$('a[id$="_csv"]').each(function() {
|
||||
$(this).off('click').on('click', function(event) {
|
||||
$(this).rebind('click', function(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
document.location = $(this).attr('href');
|
||||
|
||||
+3
-3
@@ -1397,16 +1397,16 @@ function grow_right_pane_tree(int $tree_id, int $leaf_id, string $host_group_dat
|
||||
}
|
||||
|
||||
$(function() {
|
||||
$('#go').off('click').on('click', function(event) {
|
||||
$('#go').rebind('click', function(event) {
|
||||
event.preventDefault();
|
||||
applyGraphFilter();
|
||||
});
|
||||
|
||||
$('#clear').off('click').on('click', function() {
|
||||
$('#clear').rebind('click', function() {
|
||||
clearGraphFilter();
|
||||
});
|
||||
|
||||
$('#save').off('click').on('click', function() {
|
||||
$('#save').rebind('click', function() {
|
||||
saveGraphFilter('tree');
|
||||
});
|
||||
|
||||
|
||||
+3
-3
@@ -1335,7 +1335,7 @@ function import_display_package_data(array $templates, array $files, string $pac
|
||||
makePackagesClickable();
|
||||
}
|
||||
|
||||
$('.diffme').off('click').on('click', function(event) {
|
||||
$('.diffme').rebind('click', function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
var url = $(this).attr('href');
|
||||
@@ -1868,11 +1868,11 @@ function package_import() : void {
|
||||
$(function() {
|
||||
refreshMSeconds = 9999999;
|
||||
|
||||
$('#package_location').off('change').on('change', function() {
|
||||
$('#package_location').rebind('change', function() {
|
||||
switchRepo();
|
||||
});
|
||||
|
||||
$('#import_file').off('change').on('change', function() {
|
||||
$('#import_file').rebind('change', function() {
|
||||
var form = $('#import')[0];
|
||||
var data = new FormData(form);
|
||||
var formExtra = '?action=upload&package_location=0&preview_only=on';
|
||||
|
||||
+9
-9
@@ -882,7 +882,7 @@ function update_show_current() : void {
|
||||
});
|
||||
}
|
||||
|
||||
$('.pirestore').off('click').on('click', function(event) {
|
||||
$('.pirestore').rebind('click', function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
var dialogTitle = '<?php print $resarchive_title; ?>';
|
||||
@@ -895,7 +895,7 @@ function update_show_current() : void {
|
||||
displayDialog(url, dialogTitle, dialogMessage, dialogForm, buttonContinue, buttonCancel, 80, 400);
|
||||
});
|
||||
|
||||
$('.pirmarchive').off('click').on('click', function(event) {
|
||||
$('.pirmarchive').rebind('click', function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
var dialogTitle = '<?php print $rmarchive_title; ?>';
|
||||
@@ -908,7 +908,7 @@ function update_show_current() : void {
|
||||
displayDialog(url, dialogTitle, dialogMessage, dialogForm, buttonContinue, buttonCancel, 80, 400);
|
||||
});
|
||||
|
||||
$('.piarchive').off('click').on('click', function(event) {
|
||||
$('.piarchive').rebind('click', function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
var dialogTitle = '<?php print $archive_title; ?>';
|
||||
@@ -921,7 +921,7 @@ function update_show_current() : void {
|
||||
displayDialog(url, dialogTitle, dialogMessage, dialogForm, buttonContinue, buttonCancel, 120, 600);
|
||||
});
|
||||
|
||||
$('.pirmdata').off('click').on('click', function(event) {
|
||||
$('.pirmdata').rebind('click', function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
var dialogTitle = '<?php print $rmdata_title; ?>';
|
||||
@@ -934,7 +934,7 @@ function update_show_current() : void {
|
||||
displayDialog(url, dialogTitle, dialogMessage, dialogForm, buttonContinue, buttonCancel, 80, 400);
|
||||
});
|
||||
|
||||
$('.piuninstall').off('click').on('click', function(event) {
|
||||
$('.piuninstall').rebind('click', function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
var dialogTitle = '<?php print $uninstall_title; ?>';
|
||||
@@ -947,7 +947,7 @@ function update_show_current() : void {
|
||||
displayDialog(url, dialogTitle, dialogMessage, dialogForm, buttonContinue, buttonCancel, 80, 400);
|
||||
});
|
||||
|
||||
$('.pidisable').off('click').on('click', function(event) {
|
||||
$('.pidisable').rebind('click', function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
var url = $(this).attr('href');
|
||||
@@ -959,7 +959,7 @@ function update_show_current() : void {
|
||||
postUrl({ url: url }, { __csrf_magic: csrfMagicToken });
|
||||
});
|
||||
|
||||
$('.piforceremove').off('click').on('click', function(event) {
|
||||
$('.piforceremove').rebind('click', function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
var cfg = <?php print $forceremove_cfg; ?>;
|
||||
@@ -974,7 +974,7 @@ function update_show_current() : void {
|
||||
$('#dialogForm input[name=plugin]').val(plugin);
|
||||
});
|
||||
|
||||
$('.pireadme').off('click').on('click', function(event) {
|
||||
$('.pireadme').rebind('click', function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
var dialogTitle = '<?php print __esc('Plugin Reame File'); ?>';
|
||||
@@ -983,7 +983,7 @@ function update_show_current() : void {
|
||||
displayFileDialog(url, dialogTitle, 400, 700);
|
||||
});
|
||||
|
||||
$('.pichangelog').off('click').on('click', function(event) {
|
||||
$('.pichangelog').rebind('click', function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
var dialogTitle = '<?php print __esc('Plugin ChangeLog File'); ?>';
|
||||
|
||||
@@ -157,9 +157,8 @@ test('the cactiPostAction handler posts the token and refuses another origin', f
|
||||
/* The class has to be bound on its own, not only through the ajaxAnchors
|
||||
selector, because several tagged anchors carry none of the classes that
|
||||
selector names. */
|
||||
expect($js)->toContain("$(document).off('click.cactiPostAction', 'a.cactiPostAction')")
|
||||
->and($js)->toContain(".on('click.cactiPostAction', 'a.cactiPostAction'")
|
||||
->and($js)->toContain(".not('.cactiPostAction').off('click')")
|
||||
expect($js)->toContain("$(document).rebind('click.cactiPostAction', 'a.cactiPostAction'")
|
||||
->and($js)->toContain(".not('.cactiPostAction').rebind('click'")
|
||||
->and($js)->toContain('submitPageUsingPost')
|
||||
->and($js)->toContain('cactiPreparePostRequestFromUrl');
|
||||
|
||||
|
||||
@@ -75,6 +75,6 @@ test('cross-origin targets are rejected before a token is exposed', () => {
|
||||
});
|
||||
|
||||
test('the state-action handler survives element-level unbind calls', () => {
|
||||
assert.match(source, /\$\(document\)\.off\('click\.cactiPostAction', 'a\.cactiPostAction'\)\.on\('click\.cactiPostAction', 'a\.cactiPostAction'/);
|
||||
assert.match(source, /\$\(document\)\.rebind\('click\.cactiPostAction', 'a\.cactiPostAction'/);
|
||||
assert.doesNotMatch(source, /\$\('a\.cactiPostAction'\)\.off\('click\.cactiPostAction'/);
|
||||
});
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
+-------------------------------------------------------------------------+
|
||||
| Cacti: The Complete RRDtool-based Graphing Solution |
|
||||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const test = require('node:test');
|
||||
const vm = require('node:vm');
|
||||
|
||||
const layoutSource = fs.readFileSync(
|
||||
path.join(__dirname, '..', '..', 'include', 'layout.js'),
|
||||
'utf8'
|
||||
);
|
||||
|
||||
// Pull the `$.fn.rebind = function ... };` assignment out of layout.js by
|
||||
// brace-matching so the helper can be exercised without a browser or jQuery.
|
||||
function rebindSource() {
|
||||
const start = layoutSource.indexOf('$.fn.rebind = function');
|
||||
assert.notEqual(start, -1, '$.fn.rebind must exist in layout.js');
|
||||
|
||||
const bodyStart = layoutSource.indexOf('{', start);
|
||||
let depth = 0;
|
||||
|
||||
for (let offset = bodyStart; offset < layoutSource.length; offset++) {
|
||||
if (layoutSource[offset] === '{') {
|
||||
depth++;
|
||||
} else if (layoutSource[offset] === '}') {
|
||||
depth--;
|
||||
|
||||
if (depth === 0) {
|
||||
return layoutSource.slice(start, offset + 1) + ';';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error('Unable to extract $.fn.rebind');
|
||||
}
|
||||
|
||||
function loadRebind() {
|
||||
const $ = { fn: {} };
|
||||
vm.runInNewContext(rebindSource(), { $ });
|
||||
|
||||
return $.fn.rebind;
|
||||
}
|
||||
|
||||
// A minimal jQuery-set stand-in that records off()/on() calls and chains.
|
||||
function makeSet(calls) {
|
||||
const set = {
|
||||
off(...args) { calls.push(['off', args]); return set; },
|
||||
on(...args) { calls.push(['on', args]); return set; },
|
||||
};
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
const rebind = loadRebind();
|
||||
|
||||
test('rebind unbinds then binds a direct handler and returns the set', () => {
|
||||
const calls = [];
|
||||
const set = makeSet(calls);
|
||||
const handler = () => {};
|
||||
|
||||
const result = rebind.apply(set, ['click', handler]);
|
||||
|
||||
assert.deepEqual(calls, [['off', ['click']], ['on', ['click', handler]]]);
|
||||
assert.equal(result, set);
|
||||
});
|
||||
|
||||
test('rebind preserves the selector for delegated handlers', () => {
|
||||
const calls = [];
|
||||
const set = makeSet(calls);
|
||||
const handler = () => {};
|
||||
|
||||
rebind.apply(set, ['click', '.item', handler]);
|
||||
|
||||
assert.deepEqual(calls, [['off', ['click', '.item']], ['on', ['click', '.item', handler]]]);
|
||||
});
|
||||
|
||||
test('rebind preserves the selector for the two-argument event-map overload', () => {
|
||||
const calls = [];
|
||||
const set = makeSet(calls);
|
||||
const map = { click: () => {} };
|
||||
|
||||
rebind.apply(set, [map, '.item']);
|
||||
|
||||
assert.deepEqual(calls, [['off', [map, '.item']], ['on', [map, '.item']]]);
|
||||
});
|
||||
|
||||
test('rebind treats a non-string second argument as handler data, not a selector', () => {
|
||||
const calls = [];
|
||||
const set = makeSet(calls);
|
||||
const data = { count: 1 };
|
||||
const handler = () => {};
|
||||
|
||||
rebind.apply(set, ['click', data, handler]);
|
||||
|
||||
assert.deepEqual(calls, [['off', ['click']], ['on', ['click', data, handler]]]);
|
||||
});
|
||||
@@ -65,11 +65,9 @@ test('scroll handlers close initialized select menus without duplicate bindings'
|
||||
assert.equal(target, windowObject);
|
||||
|
||||
return {
|
||||
off: (event) => {
|
||||
assert.equal(event, 'scroll.cactiSelectmenu');
|
||||
rebind: (bound, handler) => {
|
||||
assert.equal(bound, 'scroll.cactiSelectmenu');
|
||||
|
||||
return {
|
||||
on: (bound, handler) => {
|
||||
boundEvent = bound;
|
||||
scrollHandler = handler;
|
||||
}
|
||||
@@ -77,8 +75,6 @@ test('scroll handlers close initialized select menus without duplicate bindings'
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (selector === 'select') {
|
||||
selectScans++;
|
||||
|
||||
Reference in new issue
Block a user