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}}}
|
||||
define(['components/app/container', 'jquery', 'logging', 'URIjs/URI', 'URIjs/URITemplate', 'icinga/util/url'],
|
||||
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";
|
||||
|
||||
/**
|
||||
|
@ -65,6 +76,13 @@ function(Container, $, logger, URI, tpl, urlMgr) {
|
|||
*/
|
||||
var controlForms;
|
||||
|
||||
/**
|
||||
* Handles multi-selection
|
||||
*
|
||||
* @type {TableMultiSelection}
|
||||
*/
|
||||
var selection;
|
||||
|
||||
/**
|
||||
* Detect and select control forms for this table and return them
|
||||
*
|
||||
|
@ -131,7 +149,7 @@ function(Container, $, logger, URI, tpl, urlMgr) {
|
|||
|
||||
if (a.length) {
|
||||
// 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;
|
||||
}
|
||||
} 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'));
|
||||
if (!ev.ctrlKey && !ev.metaKey) {
|
||||
$('tr', $(this).parent()).removeClass('active');
|
||||
var selectable = new Selectable(this);
|
||||
if (ev.ctrlKey || ev.metaKey) {
|
||||
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;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Register submit handler for the form controls (sorting, filtering, etc). Reloading happens in the
|
||||
* current container
|
||||
|
@ -192,19 +228,23 @@ function(Container, $, logger, URI, tpl, urlMgr) {
|
|||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
var getSelectedRows = function() {
|
||||
return $('a[href="' + urlMgr.getDetailUrl() + '"]', determineContentTable()).
|
||||
parentsUntil('table', 'tr');
|
||||
};
|
||||
*/
|
||||
|
||||
/**
|
||||
* Synchronize the current selection with the url displayed in the detail box
|
||||
*/
|
||||
/*
|
||||
this.syncSelectionWithDetail = function() {
|
||||
$('tr', contentNode).removeClass('active');
|
||||
getSelectedRows().addClass('active');
|
||||
};
|
||||
*/
|
||||
|
||||
/**
|
||||
* Register listener for history changes in the detail box
|
||||
|
@ -221,7 +261,10 @@ function(Container, $, logger, URI, tpl, urlMgr) {
|
|||
this.container.removeDefaultLoadIndicator();
|
||||
controlForms = determineControlForms();
|
||||
contentNode = determineContentTable();
|
||||
this.syncSelectionWithDetail();
|
||||
selection = new TableMultiSelection(
|
||||
contentNode,
|
||||
Container.getDetailContainer().getContainerHref()
|
||||
);
|
||||
this.registerControls();
|
||||
this.registerTableLinks();
|
||||
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