diff --git a/library/Icinga/Web/JavaScript.php b/library/Icinga/Web/JavaScript.php
index 6a378559f..ed39c1b39 100644
--- a/library/Icinga/Web/JavaScript.php
+++ b/library/Icinga/Web/JavaScript.php
@@ -26,7 +26,8 @@ class JavaScript
'js/icinga/behavior/sparkline.js',
'js/icinga/behavior/tristate.js',
'js/icinga/behavior/navigation.js',
- 'js/icinga/behavior/form.js'
+ 'js/icinga/behavior/form.js',
+ 'js/icinga/behavior/actiontable.js'
);
protected static $vendorFiles = array(
diff --git a/modules/monitoring/application/views/helpers/Link.php b/modules/monitoring/application/views/helpers/Link.php
index 35c5a4cbc..e37375d14 100644
--- a/modules/monitoring/application/views/helpers/Link.php
+++ b/modules/monitoring/application/views/helpers/Link.php
@@ -45,10 +45,11 @@ class Zend_View_Helper_Link extends Zend_View_Helper_Abstract
* @param string $serviceLinkText Text for the service link, e.g. the service's display name
* @param string $host Hostname
* @param string $hostLinkText Text for the host link, e.g. the host's display name
+ * @param string $class An optional class to use for this link
*
* @return string
*/
- public function service($service, $serviceLinkText, $host, $hostLinkText)
+ public function service($service, $serviceLinkText, $host, $hostLinkText, $class = null)
{
return sprintf(
'%s: %s',
@@ -57,11 +58,14 @@ class Zend_View_Helper_Link extends Zend_View_Helper_Abstract
$serviceLinkText,
'monitoring/service/show',
array('host' => $host, 'service' => $service),
- array('title' => sprintf(
- $this->view->translate('Show detailed information for service %s on host %s'),
- $service,
- $host
- ))
+ array(
+ 'title' => sprintf(
+ $this->view->translate('Show detailed information for service %s on host %s'),
+ $service,
+ $host
+ ),
+ 'class' => $class
+ )
)
);
}
diff --git a/modules/monitoring/application/views/scripts/list/comments.phtml b/modules/monitoring/application/views/scripts/list/comments.phtml
index 43b94be66..7c3863d17 100644
--- a/modules/monitoring/application/views/scripts/list/comments.phtml
+++ b/modules/monitoring/application/views/scripts/list/comments.phtml
@@ -43,11 +43,14 @@ if (count($comments) === 0) {
),
'monitoring/comment/show',
array('comment_id' => $comment->id),
- array('title' => sprintf(
- $this->translate('Show detailed information for comment on %s for %s'),
- $comment->service_display_name,
- $comment->host_display_name
- ))) ?>
+ array(
+ 'title' => sprintf(
+ $this->translate('Show detailed information for comment on %s for %s'),
+ $comment->service_display_name,
+ $comment->host_display_name
+ ),
+ 'class' => 'rowaction'
+ )) ?>
= $this->icon('host', $this->translate('Host')); ?>
diff --git a/modules/monitoring/application/views/scripts/list/downtimes.phtml b/modules/monitoring/application/views/scripts/list/downtimes.phtml
index e0836aa26..0c587a03f 100644
--- a/modules/monitoring/application/views/scripts/list/downtimes.phtml
+++ b/modules/monitoring/application/views/scripts/list/downtimes.phtml
@@ -57,11 +57,14 @@ if (count($downtimes) === 0) {
sprintf('%s: %s', $downtime->host_display_name, $downtime->service_display_name),
'monitoring/downtime/show',
array('downtime_id' => $downtime->id),
- array('title' => sprintf(
- $this->translate('Show detailed information for downtime on %s for %s'),
- $downtime->service_display_name,
- $downtime->host_display_name
- ))) ?>
+ array(
+ 'title' => sprintf(
+ $this->translate('Show detailed information for downtime on %s for %s'),
+ $downtime->service_display_name,
+ $downtime->host_display_name
+ ),
+ 'class' => 'rowaction'
+ )) ?>
= $this->icon('comment', $this->translate('Comment')); ?> [= $this->escape($downtime->author_name) ?>] = $this->escape($downtime->comment) ?>
diff --git a/modules/monitoring/application/views/scripts/list/eventhistory.phtml b/modules/monitoring/application/views/scripts/list/eventhistory.phtml
index 538702a64..ab9cb2331 100644
--- a/modules/monitoring/application/views/scripts/list/eventhistory.phtml
+++ b/modules/monitoring/application/views/scripts/list/eventhistory.phtml
@@ -82,7 +82,7 @@ if (count($history) === 0) {
= $this->link()->service(
- $event->service_description, $event->service_display_name, $event->host_name, $event->host_display_name
+ $event->service_description, $event->service_display_name, $event->host_name, $event->host_display_name, 'rowaction'
) ?>
= $this->link()->host($event->host_name, $event->host_display_name) ?>
diff --git a/modules/monitoring/application/views/scripts/list/hosts.phtml b/modules/monitoring/application/views/scripts/list/hosts.phtml
index 15dbb5a6f..0d033eaad 100644
--- a/modules/monitoring/application/views/scripts/list/hosts.phtml
+++ b/modules/monitoring/application/views/scripts/list/hosts.phtml
@@ -60,7 +60,8 @@ if (count($hosts) === 0) {
$hostLink,
null,
array(
- 'title' => sprintf($this->translate('Show detailed information for host %s'), $host->host_display_name)
+ 'title' => sprintf($this->translate('Show detailed information for host %s'), $host->host_display_name),
+ 'class' => 'rowaction'
)
); ?>
host_unhandled_services) && $host->host_unhandled_services > 0): ?>
diff --git a/public/js/icinga/behavior/actiontable.js b/public/js/icinga/behavior/actiontable.js
new file mode 100644
index 000000000..d3df54614
--- /dev/null
+++ b/public/js/icinga/behavior/actiontable.js
@@ -0,0 +1,396 @@
+/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
+
+/**
+ * Icinga.Behavior.ActionTable
+ *
+ * A multi selection that distincts between the table rows using the row action URL filter
+ */
+(function(Icinga, $) {
+
+ "use strict";
+
+ /**
+ * Remove one leading and trailing bracket and all text outside those brackets
+ *
+ * @param str {String}
+ * @returns {string}
+ */
+ var stripBrackets = function (str) {
+ return str.replace(/^[^\(]*\(/, '').replace(/\)[^\)]*$/, '');
+ };
+
+ /**
+ * Parse the filter query contained in the given url filter string
+ *
+ * @param filterString {String}
+ *
+ * @returns {Array} An object containing each row filter
+ */
+ var parseSelectionQuery = function(filterString) {
+ var selections = [];
+ $.each(stripBrackets(filterString).split('|'), function(i, row) {
+ var tuple = {};
+ $.each(stripBrackets(row).split('&'), function(i, keyValue) {
+ var s = keyValue.split('=');
+ tuple[s[0]] = decodeURIComponent(s[1]);
+ });
+ selections.push(tuple);
+ });
+ return selections;
+ };
+
+ /**
+ * Handle the selection of an action table
+ *
+ * @param table {HTMLElement} The table
+ * @param {Icinga}
+ *
+ * @constructor
+ */
+ var Selection = function(table, icinga) {
+ this.$el = $(table);
+ this.icinga = icinga;
+
+ if (this.hasMultiselection()) {
+ if (! this.getMultiselectionKeys().length) {
+ icinga.logger.error('multiselect table has no data-icinga-multiselect-data');
+ }
+ if (! this.getMultiselectionUrl()) {
+ icinga.logger.error('multiselect table has no data-icinga-multiselect-url');
+ }
+ }
+ };
+
+ Selection.prototype = {
+
+ /**
+ * Return all rows as jQuery selector
+ *
+ * @returns {jQuery}
+ */
+ rows: function() {
+ return this.$el.find('tr');
+ },
+
+ /**
+ * Return all row action links as jQuery selector
+ *
+ * @returns {jQuery}
+ */
+ rowActions: function() {
+ return this.$el.find('tr a.rowaction');
+ },
+
+ /**
+ * Return all selected rows as jQuery selector
+ *
+ * @returns {jQuery}
+ */
+ selections: function() {
+ return this.$el.find('tr.active');
+ },
+
+ /**
+ * If this selection allows selecting multiple rows
+ *
+ * @returns {Boolean}
+ */
+ hasMultiselection: function() {
+ return this.$el.hasClass('multiselect');
+ },
+
+ /**
+ * Return all filter keys that are significant when applying the selection
+ *
+ * @returns {Array}
+ */
+ getMultiselectionKeys: function() {
+ var data = this.$el.data('icinga-multiselect-data');
+ return (data && data.split(',')) || [];
+ },
+
+ /**
+ * Return the target URL that is used when multi selecting rows
+ *
+ * This URL may differ from the url that is used when applying single rows
+ *
+ * @returns {String}
+ */
+ getMultiselectionUrl: function() {
+ return this.$el.data('icinga-multiselect-url');
+ },
+
+ /**
+ * Read all filter data from the given row
+ *
+ * @param row {jQuery} The row element
+ *
+ * @returns {Object} An object containing all filter data in this row as key-value pairs
+ */
+ getRowData: function(row) {
+ var params = this.icinga.utils.parseUrl(row.attr('href')).params;
+ var tuple = {};
+ var keys = this.getMultiselectionKeys();
+ for (var i = 0; i < keys.length; i++) {
+ var key = keys[i];
+ if (params[key]) {
+ tuple[key] = params[key];
+ }
+ }
+ return tuple;
+ },
+
+ /**
+ * Deselect all selected rows
+ */
+ clear: function() {
+ this.selections().removeClass('active');
+ },
+
+ /**
+ * Add all rows that match the given filter to the selection
+ *
+ * @param filter {jQuery|Object} Either an object containing filter variables or the actual row to select
+ */
+ select: function(filter) {
+ if (filter instanceof jQuery) {
+ filter.addClass('active');
+ return;
+ }
+ var self = this;
+ var url = this.getMultiselectionUrl();
+ this.rowActions()
+ .filter(
+ function (i, el) {
+ var params = self.getRowData($(el));
+ if (self.icinga.utils.objectKeys(params).length !== self.icinga.utils.objectKeys(filter).length) {
+ return false;
+ }
+ var equal = true;
+ $.each(params, function(key, value) {
+ if (filter[key] !== value) {
+ equal = false;
+ }
+ });
+ return equal;
+ }
+ )
+ .closest('tr')
+ .addClass('active');
+ },
+
+ /**
+ * Toggle the selection of the row between on and off
+ *
+ * @param row {jQuery} The row to toggle
+ */
+ toggle: function(row) {
+ row.toggleClass('active');
+ },
+
+ /**
+ * Add a new selection range to the closest table, using the selected row as
+ * range target.
+ *
+ * @param row {jQuery} The target of the selected range.
+ *
+ * @returns {boolean} If the selection was changed.
+ */
+ range: function(row) {
+ var from, to;
+ var selected = row.first().get(0);
+ this.rows().each(function(i, el) {
+ if ($(el).hasClass('active') || el === selected) {
+ if (!from) {
+ from = el;
+ }
+ to = el;
+ }
+ });
+ var inRange = false;
+ this.rows().each(function(i, el) {
+ if (el === from) {
+ inRange = true;
+ }
+ if (inRange) {
+ $(el).addClass('active');
+ }
+ if (el === to) {
+ inRange = false;
+ }
+ });
+ return false;
+ },
+
+ /**
+ * Select rows that target the given url
+ *
+ * @param url {String} The target url
+ */
+ selectUrl: function(url) {
+ this.rows().filter('[href="' + url + '"]').addClass('active');
+ },
+
+ /**
+ * Convert all currently selected rows into an url query string
+ *
+ * @returns {String} The filter string
+ */
+ toQuery: function() {
+ var self = this;
+ var selections = this.selections();
+ var queries = [];
+ if (selections.length === 1) {
+ return $(selections[0]).attr('href');
+ } else if (selections.length > 1 && self.hasMultiselection()) {
+ selections.each(function (i, el) {
+ var parts = [];
+ $.each(self.getRowData($(el)), function(key, value) {
+ parts.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
+ });
+ queries.push('(' + parts.join('&') + ')');
+ });
+ return self.getMultiselectionUrl() + '?(' + queries.join('|') + ')';
+ } else {
+ return '';
+ }
+ },
+
+ /**
+ * Refresh the displayed active columns using the current page location
+ */
+ refresh: function() {
+ this.clear();
+ var hash = this.icinga.utils.parseUrl(window.location.href).hash;
+ if (this.hasMultiselection()) {
+ var query = parseSelectionQuery(hash);
+ if (query.length > 1 && this.getMultiselectionUrl() === this.icinga.utils.parseUrl(hash.substr(1)).path) {
+ // select all rows with matching filters
+ var self = this;
+ $.each(query, function(i, selection) {
+ self.select(selection);
+ });
+ }
+ if (query.length > 1) {
+ return;
+ }
+ }
+ this.selectUrl(hash.substr(1));
+ }
+ };
+
+ Icinga.Behaviors = Icinga.Behaviors || {};
+
+ var ActionTable = function (icinga) {
+ Icinga.EventListener.call(this, icinga);
+
+ /**
+ * The hash that is currently being loaded
+ *
+ * @var String
+ */
+ this.loadingHash = null;
+
+ /**
+ * If currently loading
+ *
+ * @var Boolean
+ */
+ this.loading = false;
+
+ this.on('rendered', this.onRendered, this);
+ this.on('click', 'table.action tr[href]', this.onRowClicked, this);
+ };
+ ActionTable.prototype = new Icinga.EventListener();
+
+ /**
+ * Return all active tables in this table, or in the context as jQuery selector
+ *
+ * @param context {HTMLElement}
+ * @returns {jQuery}
+ */
+ ActionTable.prototype.tables = function(context) {
+ if (context) {
+ return $(context).find('table.action');
+ }
+ return $('table.action');
+ };
+
+ /**
+ * Handle clicks on table rows and update selection and history
+ */
+ ActionTable.prototype.onRowClicked = function (event) {
+ var self = event.data.self;
+ var $tr = $(event.target).closest('tr');
+ var table = new Selection($tr.closest('table.action')[0], self.icinga);
+
+ // allow form actions in table rows to pass through
+ if ($(event.target).closest('form').length) {
+ return;
+ }
+ event.stopPropagation();
+ event.preventDefault();
+
+ // update selection
+ if (table.hasMultiselection()) {
+ if (event.ctrlKey || event.metaKey) {
+ // add to selection
+ table.toggle($tr);
+ } else if (event.shiftKey) {
+ // range selection
+ table.range($tr);
+ } else {
+ // single selection
+ table.clear();
+ table.select($tr);
+ }
+ } else {
+ table.clear();
+ table.select($tr);
+ }
+
+ // update history
+ var url = self.icinga.utils.parseUrl(window.location.href.split('#')[0]);
+ var count = table.selections().length;
+ var state = url.path + url.query;
+ if (count > 0) {
+ var query = table.toQuery();
+ self.icinga.loader.loadUrl(query, self.icinga.events.getLinkTargetFor($tr));
+ state += '#!' + query;
+ } else {
+ if (self.icinga.events.getLinkTargetFor($tr).attr('id') === 'col2') {
+ self.icinga.ui.layout1col();
+ }
+ }
+ self.icinga.history.pushUrl(state);
+
+ // re draw all table selections
+ self.tables().each(function () {
+ new Selection(this, self.icinga).refresh();
+ });
+
+ // update selection info
+ $('.selection-info-count').text(table.selections().size());
+ return false;
+ };
+
+ /**
+ * Ensure that
+ */
+ ActionTable.prototype.onRendered = function(evt) {
+ var container = evt.target;
+ var self = evt.data.self;
+
+ // draw all selections
+ self.tables().each(function(i, el) {
+ new Selection(el, self.icinga).refresh();
+ });
+
+ // update displayed selection count
+ var table = new Selection(self.tables(container).first());
+ $(container).find('.selection-info-count').text(table.selections().size());
+ };
+
+ Icinga.Behaviors.ActionTable = ActionTable;
+
+}) (Icinga, jQuery);
diff --git a/public/js/icinga/events.js b/public/js/icinga/events.js
index 4d4ae736c..00a0ff9f4 100644
--- a/public/js/icinga/events.js
+++ b/public/js/icinga/events.js
@@ -117,9 +117,6 @@
$(document).on('click', 'a', { self: this }, this.linkClicked);
$(document).on('click', 'tr[href]', { self: this }, this.linkClicked);
- // Select a table row
- $(document).on('click', 'table.multiselect tr[href]', { self: this }, this.rowSelected);
-
// We catch all form submit events
$(document).on('submit', 'form', { self: this }, this.submitForm);
@@ -303,74 +300,6 @@
return false;
},
- /**
- * Handle table selection.
- */
- rowSelected: function(event) {
- var self = event.data.self;
- var icinga = self.icinga;
- var $tr = $(this);
- var $table = $tr.closest('table.multiselect');
- var data = self.icinga.ui.getSelectionKeys($table);
- var url = $table.data('icinga-multiselect-url');
-
- if ($(event.target).closest('form').length) {
- // allow form actions in table rows to pass through
- return;
- }
- event.stopPropagation();
- event.preventDefault();
-
- if (!data) {
- icinga.logger.error('multiselect table has no data-icinga-multiselect-data');
- return;
- }
- if (!url) {
- icinga.logger.error('multiselect table has no data-icinga-multiselect-url');
- return;
- }
-
- // update selection
- if (event.ctrlKey || event.metaKey) {
- icinga.ui.toogleTableRowSelection($tr);
- // multi selection
- } else if (event.shiftKey) {
- // range selection
- icinga.ui.addTableRowRangeSelection($tr);
- } else {
- // single selection
- icinga.ui.setTableRowSelection($tr);
- }
- // focus only the current table.
- icinga.ui.focusTable($table[0]);
-
- var $target = self.getLinkTargetFor($tr);
-
- var $trs = $table.find('tr[href].active');
- if ($trs.length > 1) {
- var selectionData = icinga.ui.getSelectionSetData($trs, data);
- var query = icinga.ui.selectionDataToQuery(selectionData);
- icinga.loader.loadUrl(url + '?' + query, $target);
- icinga.ui.storeSelectionData(selectionData);
- icinga.ui.provideSelectionCount();
- } else if ($trs.length === 1) {
- // display a single row
- $tr = $trs.first();
- icinga.loader.loadUrl($tr.attr('href'), $target);
- icinga.ui.storeSelectionData($tr.attr('href'));
- icinga.ui.provideSelectionCount();
- } else {
- // display nothing
- if ($target.attr('id') === 'col2') {
- icinga.ui.layout1col();
- }
- icinga.ui.storeSelectionData(null);
- icinga.ui.provideSelectionCount();
- }
-
- return false;
- },
-
/**
* Handle anchor, i.e. focus the element which is referenced by the anchor
*
@@ -406,16 +335,16 @@
// Special checks for link clicks in multiselect rows
if (! $a.is('tr[href]') && $a.closest('tr[href]').length > 0 && $a.closest('table.multiselect').length > 0) {
- // Forward clicks to ANY link with special key pressed to rowSelected
+ // ignoray clicks to ANY link with special key pressed
if (event.ctrlKey || event.metaKey || event.shiftKey)
{
- return self.rowSelected.call($a.closest('tr[href]'), event);
+ return true;
}
- // Forward inner links matching the row URL to rowSelected
+ // ignore inner links matching the row URL
if ($a.attr('href') === $a.closest('tr[href]').attr('href'))
{
- return self.rowSelected.call($a.closest('tr[href]'), event);
+ return true;
}
}
@@ -477,8 +406,6 @@
icinga.ui.layout1col();
}
$('table tr[href].active').removeClass('active');
- icinga.ui.storeSelectionData(null);
- icinga.ui.loadSelectionData();
icinga.history.pushCurrentState();
}
}
@@ -574,8 +501,6 @@
$(window).off('beforeunload', this.onUnload);
$(document).off('scroll', '.container', this.onContainerScroll);
$(document).off('click', 'a', this.linkClicked);
- $(document).off('click', 'table.action tr[href]', this.rowSelected);
- $(document).off('click', 'table.action tr a', this.rowSelected);
$(document).off('submit', 'form', this.submitForm);
$(document).off('change', 'form select.autosubmit', this.submitForm);
$(document).off('change', 'form input.autosubmit', this.submitForm);
diff --git a/public/js/icinga/loader.js b/public/js/icinga/loader.js
index 082b41e87..5b345a308 100644
--- a/public/js/icinga/loader.js
+++ b/public/js/icinga/loader.js
@@ -504,42 +504,6 @@
this.icinga.ui.fixDebugVisibility().triggerWindowResize();
}
self.cacheLoadedIcons(req.$target);
-
- if (active) {
- var focusedUrl = this.icinga.ui.getFocusedContainerDataUrl();
- var oldSelectionData = this.icinga.ui.loadSelectionData();
- if (typeof oldSelectionData === 'string') {
- $('[href="' + oldSelectionData + '"]', req.$target).addClass('active');
-
- } else if (oldSelectionData !== null) {
- var $container;
- if (!focusedUrl) {
- $container = $('document').first();
- } else {
- $container = $('.container[data-icinga-url="' + focusedUrl + '"]');
- }
-
- var $table = $container.find('table.action').first();
- var keys = self.icinga.ui.getSelectionKeys($table);
-
- // build map of selected queries
- var oldSelectionQueries = {};
- $.each(oldSelectionData, function(i, query){
- oldSelectionQueries[self.icinga.ui.selectionDataToQueryComp(query)] = true;
- });
-
- // set all new selections to active
- $table.find('tr[href]').filter(function(){
- var $tr = $(this);
- var rowData = self.icinga.ui.getSelectionData($tr, keys, self.icinga);
- var newSelectionQuery = self.icinga.ui.selectionDataToQueryComp(rowData);
- if (oldSelectionQueries[newSelectionQuery]) {
- return true;
- }
- return false;
- }).addClass('active');
- }
- }
},
/**
diff --git a/public/js/icinga/ui.js b/public/js/icinga/ui.js
index cd5290f32..d2f9ab138 100644
--- a/public/js/icinga/ui.js
+++ b/public/js/icinga/ui.js
@@ -9,13 +9,6 @@
'use strict';
- // Stores the icinga-data-url of the last focused table.
- var focusedTableDataUrl = null;
-
- // The stored selection data, useful for preserving selections over
- // multiple reload-cycles.
- var selectionData = null;
-
Icinga.UI = function (icinga) {
this.icinga = icinga;
@@ -38,8 +31,7 @@
this.fadeNotificationsAway();
},
- fadeNotificationsAway: function()
- {
+ fadeNotificationsAway: function() {
var icinga = this.icinga;
$('#notifications li')
.not('.fading-out')
@@ -298,226 +290,6 @@
return $('#main > .container').length;
},
- /**
- * Add the given table-row to the selection of the closest
- * table and deselect all other rows of the closest table.
- *
- * @param $tr {jQuery} The selected table row.
- * @returns {boolean} If the selection was changed.
- */
- setTableRowSelection: function ($tr) {
- var $table = $tr.closest('table.multiselect');
- $table.find('tr[href].active').removeClass('active');
- $tr.addClass('active');
- return true;
- },
-
- /**
- * Toggle the given table row to "on" when not selected, or to "off" when
- * currently selected.
- *
- * @param $tr {jQuery} The table row.
- * @returns {boolean} If the selection was changed.
- */
- toogleTableRowSelection: function ($tr) {
- // multi selection
- if ($tr.hasClass('active')) {
- $tr.removeClass('active');
- } else {
- $tr.addClass('active');
- }
- return true;
- },
-
- /**
- * Add a new selection range to the closest table, using the selected row as
- * range target.
- *
- * @param $tr {jQuery} The target of the selected range.
- * @returns {boolean} If the selection was changed.
- */
- addTableRowRangeSelection: function ($tr) {
- var $table = $tr.closest('table.multiselect');
- var $rows = $table.find('tr[href]'),
- from, to;
- var selected = $tr.first().get(0);
- $rows.each(function(i, el) {
- if ($(el).hasClass('active') || el === selected) {
- if (!from) {
- from = el;
- }
- to = el;
- }
- });
- var inRange = false;
- $rows.each(function(i, el){
- if (el === from) {
- inRange = true;
- }
- if (inRange) {
- $(el).addClass('active');
- }
- if (el === to) {
- inRange = false;
- }
- });
- return false;
- },
-
-
- /**
- * Read the data from a whole set of selections.
- *
- * @param $selections {jQuery} All selected rows in a jQuery-selector.
- * @param keys {Array} An array containing all valid keys.
- * @returns {Array} An array containing an object with the data for each selection.
- */
- getSelectionSetData: function($selections, keys) {
- var selections = [];
- var icinga = this.icinga;
-
- // read all current selections
- $selections.each(function(ind, selected) {
- selections.push(icinga.ui.getSelectionData($(selected), keys, icinga));
- });
- return selections;
- },
-
- getSelectionKeys: function($selection)
- {
- var d = $selection.data('icinga-multiselect-data') && $selection.data('icinga-multiselect-data').split(',');
- return d || [];
- },
-
- /**
- * Read the data from the given selected object.
- *
- * @param $selection {jQuery} The selected object.
- * @param keys {Array} An array containing all valid keys.
- * @param icinga {Icinga} The main icinga object.
- * @returns {Object} An object containing all key-value pairs associated with this selection.
- */
- getSelectionData: function($selection, keys, icinga)
- {
- var url = $selection.attr('href');
- var params = this.icinga.utils.parseUrl(url).params;
- var tuple = {};
- for (var i = 0; i < keys.length; i++) {
- var key = keys[i];
- if (params[key]) {
- tuple[key] = params[key];
- }
- }
- return tuple;
- },
-
- /**
- * Convert a set of selection data to a single query.
- *
- * @param selectionData {Array} The selection data generated from getSelectionData
- * @returns {String} The formatted and uri-encoded query-string.
- */
- selectionDataToQuery: function (selectionData) {
- var queries = [];
-
- // create new url
- if (selectionData.length < 2) {
- this.icinga.logger.error('Something went wrong, we should never multiselect just one row');
- } else {
- $.each(selectionData, function(i, el){
- var parts = []
- $.each(el, function(key, value) {
- parts.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
- });
- queries.push('(' + parts.join('&') + ')');
- });
- }
- return '(' + queries.join('|') + ')';
- },
-
- /**
- * Create a single query-argument (not compatible to selectionDataToQuery)
- *
- * @param data
- * @returns {string}
- */
- selectionDataToQueryComp: function(data) {
- var queries = [];
- $.each(data, function(key, value){
- queries.push(key + '=' + encodeURIComponent(value));
- });
- return queries.join('&');
- },
-
- /**
- * Store a set of selection-data to preserve it accross page-reloads
- *
- * @param data {Array|String|Null} The selection-data be an Array of Objects,
- * containing the selection data (when multiple rows where selected), a
- * String containing a single url (when only a single row was selected) or
- * Null when nothing was selected.
- */
- storeSelectionData: function(data) {
- selectionData = data;
- },
-
- /**
- * Load the last stored set of selection-data
- *
- * @returns {Array|String|Null} May be an Array of Objects, containing the selection data
- * (when multiple rows where selected), a String containing a single url
- * (when only a single row was selected) or Null when nothing was selected.
- */
- loadSelectionData: function() {
- this.provideSelectionCount();
- return selectionData;
- },
-
- /**
- * Set the selections row count hint info
- */
- provideSelectionCount: function() {
- var $count = $('.selection-info-count');
-
- if (typeof selectionData === 'undefined' || selectionData === null) {
- $count.text(0);
- return;
- }
-
- if (typeof selectionData === 'string') {
- $count.text(1);
- } else if (selectionData.length > 1) {
- $count.text(selectionData.length);
- } else {
- $count.text(0);
- }
- },
-
- /**
- * Focus the given table by deselecting all selections on all other tables.
- *
- * Focusing a table is important for environments with multiple tables like
- * the dashboard. It should only be possible to select rows at one table at a time,
- * when a user selects a row on a table all rows that are not child of the given table
- * will be removed from the selection.
- *
- * @param table {htmlElement} The table to focus.
- */
- focusTable: function (table) {
- $('table').filter(function(){ return this !== table; }).find('tr[href]').removeClass('active');
- var n = $(table).closest('div.container').attr('data-icinga-url');
- focusedTableDataUrl = n;
- },
-
- /**
- * Return the URL of the last focused table container.
- *
- * @returns {String} The data-icinga-url of the last focused table, which should be unique in each site.
- */
- getFocusedContainerDataUrl: function() {
- return focusedTableDataUrl;
- },
-
/**
* Assign a unique ID to each .container without such
*
diff --git a/public/js/icinga/utils.js b/public/js/icinga/utils.js
index 4b04b3d44..b447454e3 100644
--- a/public/js/icinga/utils.js
+++ b/public/js/icinga/utils.js
@@ -293,6 +293,14 @@
return $element[0];
},
+ objectKeys: Object.keys || function (obj) {
+ var keys = [];
+ $.each(obj, function (key) {
+ keys.push(key);
+ });
+ return keys;
+ },
+
/**
* Cleanup
*/
|