Add support for multi-selection
Add classes to handle multi-row selection using the CTRL-Key and to create the link for the selected query. refs #3788
This commit is contained in:
parent
3166e1a3ff
commit
a96331b4d6
|
@ -27,6 +27,17 @@
|
||||||
// {{{ICINGA_LICENSE_HEADER}}}
|
// {{{ICINGA_LICENSE_HEADER}}}
|
||||||
define(['components/app/container', 'jquery', 'logging', 'URIjs/URI', 'URIjs/URITemplate', 'icinga/util/url'],
|
define(['components/app/container', 'jquery', 'logging', 'URIjs/URI', 'URIjs/URITemplate', 'icinga/util/url'],
|
||||||
function(Container, $, logger, URI, tpl, urlMgr) {
|
function(Container, $, logger, URI, tpl, urlMgr) {
|
||||||
|
define(
|
||||||
|
[
|
||||||
|
'components/app/container',
|
||||||
|
'jquery',
|
||||||
|
'logging',
|
||||||
|
'icinga/selection/selectable',
|
||||||
|
'icinga/selection/multiSelection',
|
||||||
|
'URIjs/URI',
|
||||||
|
'URIjs/URITemplate'
|
||||||
|
],
|
||||||
|
function(Container, $, logger, Selectable, TableMultiSelection, URI) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -65,6 +76,13 @@ function(Container, $, logger, URI, tpl, urlMgr) {
|
||||||
*/
|
*/
|
||||||
var controlForms;
|
var controlForms;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles multi-selection
|
||||||
|
*
|
||||||
|
* @type {TableMultiSelection}
|
||||||
|
*/
|
||||||
|
var selection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detect and select control forms for this table and return them
|
* Detect and select control forms for this table and return them
|
||||||
*
|
*
|
||||||
|
@ -131,7 +149,7 @@ function(Container, $, logger, URI, tpl, urlMgr) {
|
||||||
|
|
||||||
if (a.length) {
|
if (a.length) {
|
||||||
// test if the URL is on the current server, if not open it directly
|
// test if the URL is on the current server, if not open it directly
|
||||||
if (true || Container.isExternalLink(a.attr('href'))) {
|
if (Container.isExternalLink(a.attr('href'))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if ($.inArray('input', nodeNames) > -1 || $.inArray('button', nodeNames) > -1) {
|
} else if ($.inArray('input', nodeNames) > -1 || $.inArray('button', nodeNames) > -1) {
|
||||||
|
@ -141,17 +159,35 @@ function(Container, $, logger, URI, tpl, urlMgr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
urlMgr.setDetailUrl($('a', this).attr('href'));
|
var selectable = new Selectable(this);
|
||||||
if (!ev.ctrlKey && !ev.metaKey) {
|
if (ev.ctrlKey || ev.metaKey) {
|
||||||
$('tr', $(this).parent()).removeClass('active');
|
selection.toggle(selectable);
|
||||||
|
} else if (ev.shiftKey) {
|
||||||
|
// select range ?
|
||||||
|
selection.add(selectable);
|
||||||
|
} else {
|
||||||
|
selection.clear();
|
||||||
|
selection.add(selectable);
|
||||||
}
|
}
|
||||||
|
|
||||||
$(this).addClass('active');
|
// TODO: Detail target
|
||||||
|
var url = URI($('a', this).attr('href'));
|
||||||
|
var segments = url.segment();
|
||||||
|
if (selection.size() === 0) {
|
||||||
|
// don't open anything
|
||||||
|
url.search('?');
|
||||||
|
} else if (selection.size() > 1 && segments.length > 3) {
|
||||||
|
// open detail view for multiple objects
|
||||||
|
segments[2] = 'multi';
|
||||||
|
url.pathname(segments.join('/'));
|
||||||
|
url.search('?');
|
||||||
|
url.setSearch(selection.toQuery());
|
||||||
|
}
|
||||||
|
Container.getDetailContainer().replaceDomFromUrl(url);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register submit handler for the form controls (sorting, filtering, etc). Reloading happens in the
|
* Register submit handler for the form controls (sorting, filtering, etc). Reloading happens in the
|
||||||
* current container
|
* current container
|
||||||
|
@ -192,19 +228,23 @@ function(Container, $, logger, URI, tpl, urlMgr) {
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
var getSelectedRows = function() {
|
var getSelectedRows = function() {
|
||||||
return $('a[href="' + urlMgr.getDetailUrl() + '"]', determineContentTable()).
|
return $('a[href="' + urlMgr.getDetailUrl() + '"]', determineContentTable()).
|
||||||
parentsUntil('table', 'tr');
|
parentsUntil('table', 'tr');
|
||||||
};
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Synchronize the current selection with the url displayed in the detail box
|
* Synchronize the current selection with the url displayed in the detail box
|
||||||
*/
|
*/
|
||||||
|
/*
|
||||||
this.syncSelectionWithDetail = function() {
|
this.syncSelectionWithDetail = function() {
|
||||||
$('tr', contentNode).removeClass('active');
|
$('tr', contentNode).removeClass('active');
|
||||||
getSelectedRows().addClass('active');
|
getSelectedRows().addClass('active');
|
||||||
};
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register listener for history changes in the detail box
|
* Register listener for history changes in the detail box
|
||||||
|
@ -221,7 +261,10 @@ function(Container, $, logger, URI, tpl, urlMgr) {
|
||||||
this.container.removeDefaultLoadIndicator();
|
this.container.removeDefaultLoadIndicator();
|
||||||
controlForms = determineControlForms();
|
controlForms = determineControlForms();
|
||||||
contentNode = determineContentTable();
|
contentNode = determineContentTable();
|
||||||
this.syncSelectionWithDetail();
|
selection = new TableMultiSelection(
|
||||||
|
contentNode,
|
||||||
|
Container.getDetailContainer().getContainerHref()
|
||||||
|
);
|
||||||
this.registerControls();
|
this.registerControls();
|
||||||
this.registerTableLinks();
|
this.registerTableLinks();
|
||||||
this.registerHistoryChanges();
|
this.registerHistoryChanges();
|
||||||
|
|
|
@ -0,0 +1,224 @@
|
||||||
|
// {{{ICINGA_LICENSE_HEADER}}}
|
||||||
|
/**
|
||||||
|
* This file is part of Icinga 2 Web.
|
||||||
|
*
|
||||||
|
* Icinga 2 Web - Head for multiple monitoring backends.
|
||||||
|
* Copyright (C) 2013 Icinga Development Team
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* @copyright 2013 Icinga Development Team <info@icinga.org>
|
||||||
|
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
|
||||||
|
* @author Icinga Development Team <info@icinga.org>
|
||||||
|
*/
|
||||||
|
// {{{ICINGA_LICENSE_HEADER}}}
|
||||||
|
define(
|
||||||
|
['jquery', 'URIjs/URI', 'icinga/selection/selectable'],
|
||||||
|
function($, URI, Selectable) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the multi-selection of table rows and generate the query string
|
||||||
|
* that can be used to open the selected items.
|
||||||
|
*
|
||||||
|
* NOTE: After each site reload, the state (the current selection) of this object will be
|
||||||
|
* restored automatically. The selectable items are determined by finding all TR elements
|
||||||
|
* in the targeted table. The active selection is determined by checking the query elements
|
||||||
|
* of the given url.
|
||||||
|
*
|
||||||
|
* @param {HtmlElement} The table that contains the selectable rows.
|
||||||
|
*
|
||||||
|
* @param {Object} The query that contains the selected rows.
|
||||||
|
*/
|
||||||
|
return function MultiSelection(table, detailUrl) {
|
||||||
|
var self = this;
|
||||||
|
/**
|
||||||
|
* Contains all selected selectables
|
||||||
|
*
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
var selection = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the selectable was already added, remove it, otherwise add it.
|
||||||
|
*
|
||||||
|
* @param {Selectable} The selectable to use.
|
||||||
|
*/
|
||||||
|
this.toggle = function(selectable) {
|
||||||
|
if (selection[selectable.getId()]) {
|
||||||
|
self.remove(selectable);
|
||||||
|
} else {
|
||||||
|
self.add(selectable);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the selectable to the current selection.
|
||||||
|
*
|
||||||
|
* @param {Selectable} The selectable to use.
|
||||||
|
*/
|
||||||
|
this.add = function(selectable) {
|
||||||
|
selectable.setActive(true);
|
||||||
|
selection[selectable.getId()] = selectable;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the selectable from the current selection.
|
||||||
|
*
|
||||||
|
* @param {Selectable} The selectable to use.
|
||||||
|
*/
|
||||||
|
this.remove = function(selectable) {
|
||||||
|
selectable.setActive(false);
|
||||||
|
delete selection[selectable.getId()];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the current selection
|
||||||
|
*/
|
||||||
|
this.clear = function() {
|
||||||
|
$.each(selection, function(index, selectable){
|
||||||
|
selectable.setActive(false);
|
||||||
|
});
|
||||||
|
selection = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert the current selection to its query-representation.
|
||||||
|
*
|
||||||
|
* @returns {String} The query
|
||||||
|
*/
|
||||||
|
this.toQuery = function() {
|
||||||
|
var query = {};
|
||||||
|
var i = 0;
|
||||||
|
$.each(selection, function(id, selectable) {
|
||||||
|
$.each(selectable.getQuery(), function(key, value) {
|
||||||
|
query[key + '[' + i + ']'] = value;
|
||||||
|
});
|
||||||
|
i++;
|
||||||
|
});
|
||||||
|
return query;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.size = function() {
|
||||||
|
var size = 0;
|
||||||
|
$.each(selection, function(){ size++; });
|
||||||
|
return size;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch the selections from a query containing multiple selections
|
||||||
|
*/
|
||||||
|
var selectionFromMultiQuery = function(query) {
|
||||||
|
var i = 0;
|
||||||
|
var selections = [];
|
||||||
|
alert('query ' + JSON.stringify(query));
|
||||||
|
$.each(query, function(key, value) {
|
||||||
|
// Fetch the index from the key
|
||||||
|
var id = key.match(/\[([0-9]+)\]/);
|
||||||
|
alert(id);
|
||||||
|
if (id) {
|
||||||
|
alert('extracted id ' + id[1]);
|
||||||
|
// Remove the index from the key
|
||||||
|
key = key.replace(/\[[0-9]+\]/,'');
|
||||||
|
key = encodeURIComponent(key);
|
||||||
|
value = encodeURIComponent(value);
|
||||||
|
// Add it to the array representing this index
|
||||||
|
if (id[1] !== i) {
|
||||||
|
// begin a new index
|
||||||
|
selections[i] = [ key + '=' + value ];
|
||||||
|
i = id[1];
|
||||||
|
} else {
|
||||||
|
selections[i].push(key + '=' + value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return selections;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch the selections from a default query.
|
||||||
|
*/
|
||||||
|
var selectionFromQuery = function(query) {
|
||||||
|
var selection = [];
|
||||||
|
$.each(query, function(key, value){
|
||||||
|
key = encodeURIComponent(key);
|
||||||
|
value = encodeURIComponent(value);
|
||||||
|
selection.push(key + '=' + value);
|
||||||
|
});
|
||||||
|
return [ selection ];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restore the selected ids from the given URL.
|
||||||
|
*
|
||||||
|
* @param {URI} The used URL
|
||||||
|
*
|
||||||
|
* @returns {Array} The selected ids
|
||||||
|
*/
|
||||||
|
var restoreSelectionStateUrl = function(url) {
|
||||||
|
if (!url) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
if (!url.query) {
|
||||||
|
url = new URI(url);
|
||||||
|
}
|
||||||
|
var segments = url.segment();
|
||||||
|
var parts;
|
||||||
|
if (segments.length > 2 && segments[1] === 'Multi') {
|
||||||
|
alert('from multiselection');
|
||||||
|
parts = selectionFromMultiQuery(url.query(true));
|
||||||
|
} else {
|
||||||
|
parts = selectionFromQuery(url.query(true));
|
||||||
|
}
|
||||||
|
return $.map(parts, function(part) {
|
||||||
|
part.sort(function(a, b){
|
||||||
|
a = a.toUpperCase();
|
||||||
|
b = b.toUpperCase();
|
||||||
|
return (a < b ? -1 : (a > b) ? 1 : 0);
|
||||||
|
});
|
||||||
|
return part.join('&');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the selectables from the given table-Html
|
||||||
|
*/
|
||||||
|
var createSelectables = function(table) {
|
||||||
|
var selectables = {};
|
||||||
|
$(table).find('tr').each(function(i, row) {
|
||||||
|
var selectable = new Selectable(row);
|
||||||
|
selectables[selectable.getId()] = selectable;
|
||||||
|
});
|
||||||
|
return selectables;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restore the selectables from the given table and the given url
|
||||||
|
*/
|
||||||
|
var restoreSelection = function() {
|
||||||
|
var selectables = createSelectables(table);
|
||||||
|
var selected = restoreSelectionStateUrl(detailUrl);
|
||||||
|
var selection = {};
|
||||||
|
$.each(selected, function(i, selectionId) {
|
||||||
|
if (selectables[selectionId]) {
|
||||||
|
selection[selectionId] = selectables[selectionId];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return selection;
|
||||||
|
};
|
||||||
|
|
||||||
|
selection = restoreSelection();
|
||||||
|
};
|
||||||
|
});
|
|
@ -0,0 +1,83 @@
|
||||||
|
// {{{ICINGA_LICENSE_HEADER}}}
|
||||||
|
/**
|
||||||
|
* This file is part of Icinga 2 Web.
|
||||||
|
*
|
||||||
|
* Icinga 2 Web - Head for multiple monitoring backends.
|
||||||
|
* Copyright (C) 2013 Icinga Development Team
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* @copyright 2013 Icinga Development Team <info@icinga.org>
|
||||||
|
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
|
||||||
|
* @author Icinga Development Team <info@icinga.org>
|
||||||
|
*/
|
||||||
|
// {{{ICINGA_LICENSE_HEADER}}}
|
||||||
|
define(['jquery', 'URIjs/URI'], function($, URI) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper around a selectable table row. Searches the first href and to identify the associated
|
||||||
|
* query and use this query as an Identifier.
|
||||||
|
*
|
||||||
|
* @param {HtmlElement} The table row.
|
||||||
|
*/
|
||||||
|
return function Selectable(tableRow) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The href that is called when this row clicked.
|
||||||
|
*
|
||||||
|
* @type {*}
|
||||||
|
*/
|
||||||
|
var href = URI($(tableRow).find('a').first().attr('href'));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sort queries alphabetically to ensure non-ambiguous ids.
|
||||||
|
*/
|
||||||
|
var query = href.query();
|
||||||
|
var parts = query.split('&');
|
||||||
|
parts.sort(function(a, b){
|
||||||
|
a = a.toUpperCase();
|
||||||
|
b = b.toUpperCase();
|
||||||
|
return (a < b ? -1 : (a > b) ? 1 : 0);
|
||||||
|
});
|
||||||
|
href.query(parts.join('&'));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an ID for this selectable.
|
||||||
|
*
|
||||||
|
* @returns {String} The id.
|
||||||
|
*/
|
||||||
|
this.getId = function () {
|
||||||
|
return href.query();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the query object associated with this selectable.
|
||||||
|
*
|
||||||
|
* @returns {String} The id.
|
||||||
|
*/
|
||||||
|
this.getQuery = function() {
|
||||||
|
return href.query(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.setActive = function(value) {
|
||||||
|
if (value) {
|
||||||
|
$(tableRow).addClass('active');
|
||||||
|
} else {
|
||||||
|
$(tableRow).removeClass('active');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
Loading…
Reference in New Issue