From f58da73e2d6165c32568f8235bdce9be99048190 Mon Sep 17 00:00:00 2001 From: Matthias Jentsch Date: Wed, 10 Sep 2014 10:45:34 +0200 Subject: [PATCH] Move javascript behaviors into separate classes --- library/Icinga/Web/JavaScript.php | 5 +- public/js/icinga/behavior/navigation.js | 75 ++++++++++++++++ public/js/icinga/behavior/sparkline.js | 58 +++++++++++++ public/js/icinga/behavior/tooltip.js | 9 +- public/js/icinga/behavior/tristate.js | 62 +++++++++++++ public/js/icinga/events.js | 110 ------------------------ 6 files changed, 204 insertions(+), 115 deletions(-) create mode 100644 public/js/icinga/behavior/navigation.js create mode 100644 public/js/icinga/behavior/sparkline.js create mode 100644 public/js/icinga/behavior/tristate.js diff --git a/library/Icinga/Web/JavaScript.php b/library/Icinga/Web/JavaScript.php index acb9433da..01e6a55eb 100644 --- a/library/Icinga/Web/JavaScript.php +++ b/library/Icinga/Web/JavaScript.php @@ -22,7 +22,10 @@ class JavaScript 'js/icinga/history.js', 'js/icinga/module.js', 'js/icinga/timezone.js', - 'js/icinga/behavior/tooltip.js' + 'js/icinga/behavior/tooltip.js', + 'js/icinga/behavior/sparkline.js', + 'js/icinga/behavior/tristate.js', + 'js/icinga/behavior/navigation.js' ); protected static $vendorFiles = array( diff --git a/public/js/icinga/behavior/navigation.js b/public/js/icinga/behavior/navigation.js new file mode 100644 index 000000000..d3e34733c --- /dev/null +++ b/public/js/icinga/behavior/navigation.js @@ -0,0 +1,75 @@ +// {{{ICINGA_LICENSE_HEADER}}} +// {{{ICINGA_LICENSE_HEADER}}} + +(function(Icinga, $) { + + "use strict"; + + var activeMenuId; + + Icinga.Behaviors = Icinga.Behaviors || {}; + + var Navigation = function (icinga) { + this.icinga = icinga; + + }; + + Navigation.prototype.apply = function(el) { + // restore menu state + if (activeMenuId) { + $('[role="navigation"] li.active', el).removeClass('active'); + + var $selectedMenu = $('#' + activeMenuId, el); + var $outerMenu = $selectedMenu.parent().closest('li'); + if ($outerMenu.size()) { + $selectedMenu = $outerMenu; + } + $selectedMenu.addClass('active'); + } else { + // store menu state + var $menus = $('[role="navigation"] li.active', el); + if ($menus.size()) { + activeMenuId = $menus[0].id; + } + } + }; + + Navigation.prototype.bind = function() { + $(document).on('click', 'a', { self: this }, this.linkClicked); + $(document).on('click', 'tr[href]', { self: this }, this.linkClicked); + }; + + Navigation.prototype.unbind = function() { + $(document).off('click', 'a', this.linkClicked); + $(document).off('click', 'tr[href]', this.linkClicked); + }; + + Navigation.prototype.linkClicked = function(event) { + var $a = $(this); + var href = $a.attr('href'); + var isMenuLink = $a.closest('#menu').length > 0; + var $li; + var icinga = event.data.self.icinga; + + if (href.match(/#/)) { + $li = $a.closest('li'); + if (isMenuLink) { + activeMenuId = $($li).attr('id'); + } + } else { + if (isMenuLink) { + activeMenuId = $(event.target).closest('li').attr('id'); + } + } + if (isMenuLink) { + var $menu = $('#menu'); + // update target url of the menu container to the clicked link + var menuDataUrl = icinga.utils.parseUrl($menu.data('icinga-url')); + menuDataUrl = icinga.utils.addUrlParams(menuDataUrl.path, { url: href }); + $menu.data('icinga-url', menuDataUrl); + } + }; + + Icinga.Behaviors.Navigation = Navigation; + +}) (Icinga, jQuery); diff --git a/public/js/icinga/behavior/sparkline.js b/public/js/icinga/behavior/sparkline.js new file mode 100644 index 000000000..4c29f47cc --- /dev/null +++ b/public/js/icinga/behavior/sparkline.js @@ -0,0 +1,58 @@ +// {{{ICINGA_LICENSE_HEADER}}} +// {{{ICINGA_LICENSE_HEADER}}} + +(function(Icinga, $) { + + "use strict"; + + Icinga.Behaviors = Icinga.Behaviors || {}; + + var Sparkline = function (icinga) { + this.icinga = icinga; + }; + + Sparkline.prototype.apply = function(el) { + var self = this, icinga = this.icinga; + + $('span.sparkline', el).each(function(i, element) { + // read custom options + var $spark = $(element); + var labels = $spark.attr('labels').split('|'); + var formatted = $spark.attr('formatted').split('|'); + var tooltipChartTitle = $spark.attr('sparkSparklineChartTitle') || ''; + var format = $spark.attr('tooltipformat'); + var hideEmpty = $spark.attr('hideEmptyLabel') === 'true'; + $spark.sparkline( + 'html', + { + enableTagOptions: true, + tooltipFormatter: function (sparkline, options, fields) { + var out = format; + if (hideEmpty && fields.offset === 3) { + return ''; + } + var replace = { + title: tooltipChartTitle, + label: labels[fields.offset] ? labels[fields.offset] : fields.offset, + formatted: formatted[fields.offset] ? formatted[fields.offset] : '', + value: fields.value, + percent: Math.round(fields.percent * 100) / 100 + }; + $.each(replace, function(key, value) { + out = out.replace('{{' + key + '}}', value); + }); + return out; + } + }); + }); + }; + + Sparkline.prototype.bind = function() { + }; + + Sparkline.prototype.unbind = function() { + }; + + Icinga.Behaviors.Sparkline = Sparkline; + +}) (Icinga, jQuery); diff --git a/public/js/icinga/behavior/tooltip.js b/public/js/icinga/behavior/tooltip.js index 1feb6f54f..9cf207d7f 100644 --- a/public/js/icinga/behavior/tooltip.js +++ b/public/js/icinga/behavior/tooltip.js @@ -7,13 +7,14 @@ Icinga.Behaviors = Icinga.Behaviors || {}; - var Tooltip = function () { + var Tooltip = function (icinga) { + this.icinga = icinga; this.mouseX = 0; this.mouseY = 0; }; Tooltip.prototype.apply = function(el) { - var self = this; + var self = this, icinga = this.icinga; $('[title]').each(function () { var $el = $(this); @@ -27,11 +28,11 @@ // migrate or remove all orphaned tooltips $('.tipsy').each(function () { var arrow = $('.tipsy-arrow', this)[0]; - if (!Icinga.utils.elementsOverlap(arrow, $('#main')[0])) { + if (!icinga.utils.elementsOverlap(arrow, $('#main')[0])) { $(this).remove(); return; } - if (!Icinga.utils.elementsOverlap(arrow, el)) { + if (!icinga.utils.elementsOverlap(arrow, el)) { return; } var title = $(this).find('.tipsy-inner').html(); diff --git a/public/js/icinga/behavior/tristate.js b/public/js/icinga/behavior/tristate.js new file mode 100644 index 000000000..c828d6cd7 --- /dev/null +++ b/public/js/icinga/behavior/tristate.js @@ -0,0 +1,62 @@ +// {{{ICINGA_LICENSE_HEADER}}} +// {{{ICINGA_LICENSE_HEADER}}} + +(function(Icinga, $) { + + "use strict"; + + Icinga.Behaviors = Icinga.Behaviors || {}; + + var Tristate = function (icinga) { + this.icinga = icinga; + }; + + Tristate.prototype.apply = function(el) { + var self = this, icinga = this.icinga; + }; + + Tristate.prototype.bind = function() { + // Toggle all triStateButtons + $(document).on('click', 'div.tristate .tristate-dummy', { self: this }, this.clickTriState); + }; + + Tristate.prototype.unbind = function() { + $(document).off('click', 'div.tristate .tristate-dummy', this.clickTriState); + }; + + Tristate.prototype.clickTriState = function (event) { + var self = event.data.self; + var $tristate = $(this); + var triState = parseInt($tristate.data('icinga-tristate'), 10); + + // load current values + var old = $tristate.data('icinga-old').toString(); + var value = $tristate.parent().find('input:radio:checked').first().prop('checked', false).val(); + + // calculate the new value + if (triState) { + // 1 => 0 + // 0 => unchanged + // unchanged => 1 + value = value === '1' ? '0' : (value === '0' ? 'unchanged' : '1'); + } else { + // 1 => 0 + // 0 => 1 + value = value === '1' ? '0' : '1'; + } + + // update form value + $tristate.parent().find('input:radio[value="' + value + '"]').prop('checked', true); + // update dummy + + if (value !== old) { + $tristate.parent().find('b.tristate-changed').css('visibility', 'visible'); + } else { + $tristate.parent().find('b.tristate-changed').css('visibility', 'hidden'); + } + self.icinga.ui.setTriState(value.toString(), $tristate); + }; + + Icinga.Behaviors.Tristate = Tristate; + +}) (Icinga, jQuery); diff --git a/public/js/icinga/events.js b/public/js/icinga/events.js index 6ecdd61ba..2b70cfa5b 100644 --- a/public/js/icinga/events.js +++ b/public/js/icinga/events.js @@ -10,8 +10,6 @@ 'use strict'; - var activeMenuId; - Icinga.Events = function (icinga) { this.icinga = icinga; @@ -82,61 +80,11 @@ $('input.autofocus', el).focus(); - // replace all sparklines - $('span.sparkline', el).each(function(i, element) { - // read custom options - var $spark = $(element); - var labels = $spark.attr('labels').split('|'); - var formatted = $spark.attr('formatted').split('|'); - var tooltipChartTitle = $spark.attr('sparkTooltipChartTitle') || ''; - var format = $spark.attr('tooltipformat'); - var hideEmpty = $spark.attr('hideEmptyLabel') === 'true'; - $spark.sparkline( - 'html', - { - enableTagOptions: true, - tooltipFormatter: function (sparkline, options, fields) { - var out = format; - if (hideEmpty && fields.offset === 3) { - return ''; - } - var replace = { - title: tooltipChartTitle, - label: labels[fields.offset] ? labels[fields.offset] : fields.offset, - formatted: formatted[fields.offset] ? formatted[fields.offset] : '', - value: fields.value, - percent: Math.round(fields.percent * 100) / 100 - }; - $.each(replace, function(key, value) { - out = out.replace('{{' + key + '}}', value); - }); - return out; - } - }); - }); var searchField = $('#menu input.search', el); // Remember initial search field value if any if (searchField.length && searchField.val().length) { this.searchValue = searchField.val(); } - - // restore menu state - if (activeMenuId) { - $('[role="navigation"] li.active', el).removeClass('active'); - - var $selectedMenu = $('#' + activeMenuId, el); - var $outerMenu = $selectedMenu.parent().closest('li'); - if ($outerMenu.size()) { - $selectedMenu = $outerMenu; - } - $selectedMenu.addClass('active'); - } else { - // store menu state - var $menus = $('[role="navigation"] li.active', el); - if ($menus.size()) { - activeMenuId = $menus[0].id; - } - } }, /** @@ -178,8 +126,6 @@ $(document).on('keyup', '#menu input.search', {self: this}, this.autoSubmitSearch); - $(document).on('mouseenter', '.historycolorgrid td', this.historycolorgridHover); - $(document).on('mouseleave', '.historycolorgrid td', this.historycolorgidUnhover); $(document).on('mouseenter', 'li.dropdown', this.dropdownHover); $(document).on('mouseleave', 'li.dropdown', {self: this}, this.dropdownLeave); @@ -187,14 +133,11 @@ $(document).on('mouseleave', '#sidebar', { self: this }, this.leaveSidebar); $(document).on('click', '.tree .handle', { self: this }, this.treeNodeToggle); - // Toggle all triStateButtons - $(document).on('click', 'div.tristate .tristate-dummy', { self: this }, this.clickTriState); // TBD: a global autocompletion handler // $(document).on('keyup', 'form.auto input', this.formChangeDelayed); // $(document).on('change', 'form.auto input', this.formChanged); // $(document).on('change', 'form.auto select', this.submitForm); - }, menuTitleHovered: function (event) { @@ -301,14 +244,6 @@ icinga.ui.fixControls(); }, - historycolorgridHover: function () { - $(this).addClass('hover'); - }, - - historycolorgidUnhover: function() { - $(this).removeClass('hover'); - }, - autoSubmitSearch: function(event) { var self = event.data.self; if ($('#menu input.search').val() === self.searchValue) { @@ -322,39 +257,6 @@ return event.data.self.submitForm(event, true); }, - clickTriState: function (event) { - var self = event.data.self; - var $tristate = $(this); - var triState = parseInt($tristate.data('icinga-tristate'), 10); - - // load current values - var old = $tristate.data('icinga-old').toString(); - var value = $tristate.parent().find('input:radio:checked').first().prop('checked', false).val(); - - // calculate the new value - if (triState) { - // 1 => 0 - // 0 => unchanged - // unchanged => 1 - value = value === '1' ? '0' : (value === '0' ? 'unchanged' : '1'); - } else { - // 1 => 0 - // 0 => 1 - value = value === '1' ? '0' : '1'; - } - - // update form value - $tristate.parent().find('input:radio[value="' + value + '"]').prop('checked', true); - // update dummy - - if (value !== old) { - $tristate.parent().find('b.tristate-changed').css('visibility', 'visible'); - } else { - $tristate.parent().find('b.tristate-changed').css('visibility', 'hidden'); - } - self.icinga.ui.setTriState(value.toString(), $tristate); - }, - /** * */ @@ -557,7 +459,6 @@ $li = $a.closest('li'); $('#menu .active').removeClass('active'); $li.addClass('active'); - activeMenuId = $($li).attr('id'); if ($li.hasClass('hover')) { $li.removeClass('hover'); } @@ -583,9 +484,6 @@ return false; } } else { - if (isMenuLink) { - activeMenuId = $(event.target).closest('li').attr('id'); - } $target = self.getLinkTargetFor($a); } @@ -593,11 +491,6 @@ icinga.loader.loadUrl(href, $target); if (isMenuLink) { - // update target url of the menu container to the clicked link - var menuDataUrl = icinga.utils.parseUrl($('#menu').data('icinga-url')); - menuDataUrl = icinga.utils.addUrlParams(menuDataUrl.path, { url: href }); - $('#menu').data('icinga-url', menuDataUrl); - // Menu links should remove all but the first layout column icinga.ui.layout1col(); } @@ -682,11 +575,8 @@ $(document).off('submit', 'form', this.submitForm); $(document).off('click', 'button', this.submitForm); $(document).off('change', 'form select.autosubmit', this.submitForm); - $(document).off('mouseenter', '.historycolorgrid td', this.historycolorgridHover); - $(document).off('mouseleave', '.historycolorgrid td', this.historycolorgidUnhover); $(document).off('mouseenter', 'li.dropdown', this.dropdownHover); $(document).off('mouseleave', 'li.dropdown', this.dropdownLeave); - $(document).off('click', 'div.tristate .tristate-dummy', this.clickTriState); }, destroy: function() {