Removed legacy icinga JS

This commit is contained in:
Thomas Gelf 2014-02-18 18:28:37 +00:00
parent a38a126d42
commit c0a740ca9e
17 changed files with 0 additions and 2704 deletions

View File

@ -1,172 +0,0 @@
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
*
* Icinga Web 2 - 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}}}
/**
* A module to load and manage frontend components
*
*/
define(['jquery', 'logging', 'icinga/componentRegistry'], function ($, log, registry) {
'use strict';
var ComponentLoader = function() {
/**
* Load the component with the given type and attach it to the target
*
* @param {String} cmpType The component type to load '<module>/<component>'
* @param {HTMLElement} target The targeted dom node
* @param {function} fin The called when the component was successfully loaded
* @param {function} err The error-callback
*/
var loadComponent = function(cmpType, target, fin, err) {
requirejs(
['components/' + cmpType],
function (Cmp) {
var cmp;
try {
cmp = new Cmp(target);
} catch (e) {
log.emergency('Error in component "' + cmpType + '" : "' + e + '"');
err(e);
return;
}
if (fin) {
fin(cmp);
}
},
function (ex) {
if (!ex) {
return;
}
log.emergency('Component "' + cmpType + '" could not be loaded.', ex);
if (err) {
err(ex);
}
}
);
};
/**
* Load all new components and remove components that were removed from
* the DOM from the internal registry
*
* @param {function} fin Called when the loading is completed
*/
this.load = function(fin) {
/*
* Count the amount of pending callbacks to make sure everything is loaded
* when calling the garbage collection.
*/
var pendingFns = 1;
var finalize = function() {
pendingFns--;
/*
* Only return when all components are loaded
*/
if (pendingFns === 0) {
registry.removeInactive();
if (fin) {
fin();
}
}
};
registry.markAllInactive();
$('[data-icinga-component]')
.each(function(index, el) {
var type = $(el).attr('data-icinga-component');
pendingFns++;
if (!el.id || !registry.getById(el.id)) {
loadComponent(
type,
el,
function(cmp) {
var id = registry.add(cmp, type);
registry.markActive(id);
el.id = id;
finalize();
},
finalize
);
} else {
registry.markActive(el.id);
finalize();
}
});
finalize();
};
/**
* Get the id of the given component, if one is assigned
*
* @param {*} component The component of which the id should be retrieved
*
* @returns {String|null} The id of the component, or null
*/
this.getId = function(component) {
return registry.getId(component);
};
/**
* Get the component that is assigned to the given id
*
* @param {String} id The id of the component
*
* @returns {*} The component or null
*/
this.getById = function(id) {
return registry.getById(id);
};
/**
* Get all components that match the given type
*
* @param {String} type The component type in the form '<module>/<component>'
*
* @returns {*|Array} The components or an empty array
*/
this.getByType = function(type) {
return registry.getByType(type);
};
/**
* Get all components
*
* @returns {*|Array} The components or an empty array
*/
this.getComponents = function() {
return registry.getComponents();
};
};
return new ComponentLoader();
});

View File

@ -1,158 +0,0 @@
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
*
* Icinga Web 2 - 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}}}
/**
* A component registry that maps components to unique IDs and keeps track
* of component types to allow easy querying
*
*/
define(['jquery'], function($) {
"use strict";
var ComponentRegistry = function() {
var self = this;
/**
* Map ids to components
*/
var components = {};
/**
* Generate a new component id
*/
var createId = (function() {
var id = 0;
return function() {
return 'icinga-component-' + id++;
};
})();
/**
* Get the id of the given component, if one is assigned
*
* @param {*} component The component of which the id should be retrieved
*
* @returns {String|null} The id of the component, or null
*/
this.getId = function(cmp) {
var id = null;
$.each(components, function(key, value) {
if (value && value.cmp === cmp) {
id = key;
}
});
return id;
};
/**
* Get the component that is assigned to the given id
*
* @param {String} id The id of the component
*
* @returns {*} The component or null
*/
this.getById = function(id) {
return components[id] && components[id].cmp;
};
/**
* Get all components that match the given type
*
* @param {String} type The component type in the form '<module>/<component>'
*
* @returns {*|Array} The components or an empty array
*/
this.getByType = function(type) {
return $.map(components, function(entry) {
return entry.type === type ? entry.cmp : null;
});
};
/**
* Get all components
*
* @returns {*|Array} The components or an empty array
*/
this.getComponents = function() {
return $.map(components, function(entry) {
return entry.cmp;
});
};
/**
* Add the given component to the registry and return the assigned id
*
* @param {*} cmp The component to add
* @param {String} id The optional id that should be assigned to that component
* @param {String} type The component type to load '<module>/<component>'
*
* @returns {*|Array}
*/
this.add = function(cmp, type) {
var id = createId();
components[id] = {
cmp: cmp,
type: type,
active: true
};
return id;
};
/**
* Mark all components inactive
*/
this.markAllInactive = function() {
$.each(components,function(index, el){
if (el && el.active) {
el.active = false;
}
});
};
/**
* Mark the component with the given id as active
*/
this.markActive = function(id) {
if (components[id]) {
components[id].active = true;
}
};
/**
* Let the garbage collection remove all inactive components
*/
this.removeInactive = function() {
$.each(components, function(key,value) {
if (!value || !value.active) {
delete components[key];
}
});
};
};
return new ComponentRegistry();
});

View File

@ -1,84 +0,0 @@
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
*
* Icinga Web 2 - 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}}}
/*global Icinga:false define:false require:false base_url:false console:false */
/**
* Icinga app/ajaxPostSubmitForm component.
*
* This component converts generic post forms into ajax
* submit forms.
*/
define(['components/app/container', 'jquery'], function(Container, $) {
"use strict";
/**;
* Handler for ajax post submit
*
* @param {Event} e
*/
var submitHandler = function(e) {
e.preventDefault();
var form = $(this);
var url = form.attr('action');
var submit = form.find('button[type="submit"]', 'input[type="submit"]');
var data = form.serialize();
// Submit name is missing for valid submission
if (data) {
data += '&';
}
data += submit.attr('name') + '=1';
$.ajax({
url: url,
type: 'POST',
data: data,
beforeSend: function() {
submit.attr('disabled', true);
}
}).done(function() {
var c = new Container(form);
c.refresh();
}).error(function() {
submit.removeAttr('disabled');
});
return false;
};
/**
* The component bootstrap
*
* @param {Element} targetElement
*/
return function(targetForm) {
var form = $(targetForm);
form.submit(submitHandler);
};
});

View File

@ -1,509 +0,0 @@
/*global Icinga:false, Modernizr: false, document: false, History: false, define:false require:false base_url:false console:false */
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
*
* Icinga Web 2 - 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', 'logging', 'icinga/componentLoader', 'URIjs/URI', 'URIjs/URITemplate', 'icinga/util/url'],
function($, logger, componentLoader, URI, Tpl, urlMgr) {
'use strict';
var Icinga;
/**
* Enumeration of possible container types
*
* @type {{GENERIC: string, MAIN: string, DETAIL: string}}
*/
var CONTAINER_TYPES = {
'GENERIC' : 'generic',
'MAIN' : 'icingamain',
'DETAIL': 'icingadetail'
};
/**
* Static reference to the main container, populated on the first 'getMainContainer' call
*
* @type {Container}
*/
var mainContainer = null;
/**
* Static reference to the detail container, populated on the first getDetailContainer call
*
* @type {Container}
*/
var detailContainer = null;
/**
* Contains currently pending requests
*
* @type {jqAJAX}
*/
var pendingDetailRequest = null;
/**
* Cancel the pending request, if one exists
*/
var cancelPendingRequest = function() {
if (pendingDetailRequest) {
pendingDetailRequest.abort();
}
};
/**
* A handler for accessing icinga containers, i.e. the #icingamain, #icingadetail containers and specific 'app/container'
* components.
*
* This component can be constructed with every object as the parameter and will provide access to the nearest
* container (which could be the applied object itself, if it is a container) wrapping this object.
*
* The windows url should always be modified with this implementation, so an objects context should point to a
* new URL, call new Container('#myObject').updateContainerHref('/my/url')
*
* This requirejs module also registers a global handler catching all links of the main container and rendering
* their content to the main container, in case you don't want to extend the container with additional handlers.
*
* @param {HTMLElement, jQuery, String} target A jQuery resultset, dom element or matcher string
*/
var Container = function(target) {
/**
* Return the container that is at the nearest location to this element, or the element itself if it is a container
*
* Containers are either the icingamain and icingadetail ids or components tagged as app/container
*
* @param {String, jQuery, HTMLElement} target The node to use as the starting point
*
* @returns {HTMLElement|null} The nearest container found or null if target is no container
* and no container is above target
*/
this.findNearestContainer = function(target) {
target = $(target);
if (target.attr('data-icinga-component') === 'app/container' ||
target.attr('id') === 'icingamain' || target.attr('id') === 'icingadetail') {
return target;
}
return target.parents('[data-icinga-component="app/container"], #icingamain, #icingadetail')[0];
};
/**
* Find the container responsible for target and determine it's type
*
* @param {HTMLElement, jQuery, String} target A jQuery resultset, dom element or matcher string
*/
this.construct = function(target) {
this.containerDom = $(this.findNearestContainer(target));
this.containerType = CONTAINER_TYPES.GENERIC;
if (this.containerDom.attr('id') === CONTAINER_TYPES.MAIN) {
this.containerType = CONTAINER_TYPES.MAIN;
} else if (this.containerDom.attr('id') === CONTAINER_TYPES.DETAIL) {
this.containerType = CONTAINER_TYPES.DETAIL;
} else {
this.containerType = CONTAINER_TYPES.GENERIC;
}
if (this.containerDom.data('loadIndicator') !== true) {
this.installDefaultLoadIndicator();
this.containerDom.data('loadIndicator', true);
}
};
/**
* Returns the window without the hostname
*
* @returns {string} path with query, search and hash
*/
var getWindowLocationWithoutHost = function() {
return window.location.pathname + window.location.search + window.location.hash;
};
/**
* Create default load mask
*
* @private
*/
var createDefaultLoadIndicator = function() {
if (this.containerDom.find('div.load-indicator').length === 0) {
var content = '<div class="load-indicator">' +
'<div class="mask"></div>' +
'<div class="label">Loading</div>' +
'</div>';
$(this.containerDom).append(content);
}
};
/**
* Remove default load mask
*
* @private
*/
var destroyDefaultLoadIndicator = function() {
this.containerDom.find('div.load-indicator').remove();
};
/**
* Load the provided url, stop all pending requests for this container and call replaceDom for the returned html
*
* This method relaods the page if a 401 (Authorization required) header is encountered
*
* @param {String, URI} url The Url to load or and URI.js object encapsulating it
*/
this.updateFromUrl = function(url) {
if (this.containerType === CONTAINER_TYPES.DETAIL) {
urlMgr.setDetailUrl(url);
} else {
urlMgr.setMainUrl(url);
}
};
this.replaceDomAsync = function(url) {
urlMgr.syncWithUrl();
if (urlMgr.detailUrl === '') {
this.hideDetail();
}
cancelPendingRequest();
var loadingTimeout = window.setTimeout(
(function(containerDom) {
return function() {
containerDom.trigger('showLoadIndicator');
}
})(this.containerDom),
500
);
pendingDetailRequest = $.ajax({
'url': url,
'data': {
'render': 'detail'
},
'context': this
})
.done(function (response) {
pendingDetailRequest = null;
this.replaceDom($(response));
})
.fail(function (response, reason) {
if (reason === 'abort') {
return;
}
if (response.statusCode().status === 401) {
var error = JSON.parse(response.responseText);
window.location.replace(
URI(error.redirectTo).search({
redirect: URI(urlMgr.getUrl()).resource().replace(new RegExp('^' + window.base_url), '')
})
);
return;
}
var errorReason;
if (response.statusCode.toString()[0] === '4') {
errorReason = 'The Requested View Couldn\'t Be Found<br/>';
} else {
errorReason = response.responseText;
}
this.replaceDom(response.responseText);
})
.always(function () {
window.clearTimeout(loadingTimeout);
this.containerDom.trigger('hideLoadIndicator');
});
};
this.getUrl = function() {
if (this.containerType === CONTAINER_TYPES.DETAIL) {
return urlMgr.detailUrl;
} else {
return urlMgr.mainUrl;
}
};
/**
* Remove all dom nodes from this container and replace them with the ones from domNodes
*
* Triggers the custom "updated" event and causes a rescan for components on the DOM nodes
*
* If keepLayout is given, the detail panel won't be expanded if this is an update for the detail panel,
* otherwise it will be automatically shown.
*
* @param {String, jQuery, HTMLElement, Array} domNodes Any valid representation of the Dom nodes to insert
* @param {boolean} keepLayout Whether to keep the layout untouched, even if detail
* is updated end collapsed
*
* @see registerOnUpdate
*/
this.replaceDom = function(domNodes, keepLayout) {
this.containerDom.trigger('showLoadIndicator');
this.containerDom.empty().append(domNodes);
this.containerDom.trigger('updated', [domNodes]);
this.containerDom.trigger('hideLoadIndicator');
componentLoader.load();
if (!keepLayout) {
if (this.containerType === CONTAINER_TYPES.DETAIL) {
this.showDetail();
}
}
};
/**
* Register a method to be called when this container is updated
*
* @param {function} fn The function to call when the container is updated
*/
this.registerOnUpdate = function(fn) {
this.containerDom.on('updated', fn);
};
/**
* Register a method to show a load indicator
*
* @param {function} fn The function to register
*/
this.registerOnShowLoadIndicator = function(fn) {
this.containerDom.on('showLoadIndicator', fn);
};
/**
* Register a method when load indicator should be removed
*
* @param {function} fn The function to register
*/
this.registerOnHideLoadIndicator = function(fn) {
this.containerDom.on('hideLoadIndicator', fn);
};
/**
* Install default load indicator
*/
this.installDefaultLoadIndicator = function() {
this.registerOnShowLoadIndicator($.proxy(createDefaultLoadIndicator, this));
this.registerOnHideLoadIndicator($.proxy(destroyDefaultLoadIndicator, this));
};
/**
* Remove default load indicator
*/
this.removeDefaultLoadIndicator = function() {
this.containerDom.off('showLoadIndicator');
this.containerDom.off('hideLoadIndicator');
};
this.onLinkClick = function(ev, target) {
if ($.trim($(target).attr('href')) === '#') {
return true;
}
var url = URI($(target).attr('href'));
var explicitTarget = $(target).attr('data-icinga-target');
var isHash = ('#' + url.fragment() === url.href());
if (isHash) {
explicitTarget = this.containerType === CONTAINER_TYPES.MAIN ? 'main' : 'detail';
}
if (explicitTarget) {
urlMgr[{
'main' : 'setMainUrl',
'detail' : 'setDetailUrl',
'self' : 'setUrl'
}[explicitTarget]](url.href());
} else if (this.containerType === CONTAINER_TYPES.MAIN) {
urlMgr.setDetailUrl(url.href());
} else {
urlMgr.setMainUrl(url.href());
}
ev.preventDefault();
ev.stopPropagation();
return false;
};
this.setUrl = function(url) {
if (typeof url === 'string') {
url = URI(url);
}
console.log(url);
if (this.containerType === CONTAINER_TYPES.MAIN) {
urlMgr.setMainUrl(url.href());
} else {
urlMgr.setDetailUrl(url.href());
}
};
this.refresh = function() {
if (this.containerType === CONTAINER_TYPES.MAIN) {
Container.getMainContainer().replaceDomAsync(urlMgr.mainUrl);
} else {
Container.getDetailContainer().replaceDomAsync(urlMgr.detailUrl);
}
};
this.construct(target);
};
/**
* Static method for detecting whether the given link is external or only browserside (hash links)
*
* @param {String} link The link to test for being site-related
*
* @returns {boolean} True when the link should be executed with the browsers normal behaviour, false
* when the link should be catched and processed internally
*/
Container.isExternalLink = function(link) {
return (/^\/\//).test(URI(link).relativeTo(window.location.href).href());
};
/**
* Return the page's detail container (which is always there)
*
* @returns {Container} The detail container of the page
*/
Container.getDetailContainer = function() {
detailContainer = detailContainer || new Container('#icingadetail');
if(!jQuery.contains(document.body, mainContainer)) {
detailContainer = new Container('#icingadetail');
}
return detailContainer;
};
/**
* Return the page's main container (which is always there)
*
* @returns {Container} The main container of the page
*/
Container.getMainContainer = function() {
mainContainer = mainContainer || new Container('#icingamain');
if(!jQuery.contains(document.body, mainContainer)) {
mainContainer = new Container('#icingamain');
}
return mainContainer;
};
/**
* Expand the detail container and shrinken the main container
*
* Available as a static method on the Container object or as an instance method
*/
Container.prototype.showDetail = Container.showDetail = function() {
$('#icingadetailClose').removeClass('hidden');
var mainDom = Container.getMainContainer().containerDom,
detailDom = Container.getDetailContainer().containerDom;
if (detailDom.find('*').length === 0) {
var mainHeight = $(window).height();
detailDom.append('<div style="height: ' + mainHeight + 'px;"></div>');
}
mainDom.removeClass();
detailDom.removeClass();
mainDom.addClass('col-xs-pull-12 col-sm-pull-12 col-md-pull-12 col-lg-7');
detailDom.addClass('col-xs-push-12 col-sm-push-12 col-md-push-12 col-lg-5');
$(window).trigger('layoutchange');
};
/**
* Hide the detail container and expand the main container
*
* Also updates the Url by removing the detail part
*
* Available as a static method on the Container object or as an instance method
*/
Container.prototype.hideDetail = Container.hideDetail = function() {
$('#icingadetailClose').addClass('hidden');
cancelPendingRequest();
urlMgr.setDetailUrl('');
var mainDom = Container.getMainContainer().containerDom,
detailDom = Container.getDetailContainer().containerDom;
mainDom.removeClass();
detailDom.removeClass();
mainDom.addClass('col-md-12');
detailDom.addClass('hidden-md');
mainDom.addClass('col-lg-12');
detailDom.addClass('hidden-lg');
mainDom.addClass('col-xs-12');
detailDom.addClass('hidden-xs');
mainDom.addClass('col-sm-12');
detailDom.addClass('hidden-sm');
detailDom.removeAttr('data-icinga-href');
$(window).trigger('layoutchange');
};
/**
* Injects the icinga object into the Container class
*
* This can't be done via requirejs as we would end up in circular references
*
* @param {Icinga} icingaObj The Icinga object to use for reloading
*/
Container.setIcinga = function(icingaObj) {
Icinga = icingaObj;
};
$('body').on('click', '*[data-icinga-component="app/container"], #icingamain, #icingadetail', function(ev) {
var targetEl = ev.target || ev.toElement || ev.relatedTarget;
if (targetEl.tagName.toLowerCase() !== 'a') {
targetEl = $(targetEl).parents('a')[0];
if (!targetEl) {
return true;
}
}
return (new Container(targetEl)).onLinkClick(ev, targetEl);
});
$(window).on('hashchange', (function() {
urlMgr.syncWithUrl();
if (urlMgr.detailUrl) {
Container.getDetailContainer().replaceDomAsync(urlMgr.detailUrl);
} else {
Container.hideDetail();
}
}));
if (urlMgr.detailUrl) {
Container.getDetailContainer().replaceDomAsync(urlMgr.detailUrl);
}
$('#icingadetailClose').click(function(){
detailContainer.hideDetail();
});
return Container;
});

View File

@ -1,87 +0,0 @@
/*global Icinga:false, document: false, define:false require:false base_url:false console:false */
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
*
* Icinga Web 2 - 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}}}
/**
* Dashboard container, uses freetile for layout
*
*/
define(['jquery', 'logging', 'URIjs/URI', 'icinga/componentLoader', 'icinga/util/url'],
function($, log, URI, components, urlMgr) {
'use strict';
return function(parent) {
this.dom = $(parent);
var dashboardContainer = this.dom.parent('div');
dashboardContainer.freetile();
this.container = this.dom.children('.container');
this.dashboardUrl = this.dom.attr('data-icinga-url');
var reloadTimeout = null;
/**
* Refresh the container content and layout
*/
this.refresh = function () {
$.ajax({
url: this.dashboardUrl,
context: this
})
.done(function (response) {
this.container.empty();
this.container.html(response);
components.load();
})
.fail(function (response, reason) {
if (response.statusCode().status === 401) {
var error = JSON.parse(response.responseText);
window.location.replace(
URI(error.redirectTo).search({
redirect: URI(urlMgr.getUrl()).resource().replace(new RegExp('^' + window.base_url), '')
})
);
return;
}
this.container.html(response.responseText);
})
.always(function () {
dashboardContainer.freetile('layout');
$(window).on('layoutchange', function() {
dashboardContainer.freetile('layout');
});
this.triggerRefresh();
})
};
this.triggerRefresh = function() {
if (reloadTimeout) {
clearTimeout(reloadTimeout);
}
setTimeout(this.refresh.bind(this), 10000);
};
this.refresh();
};
});

View File

@ -1,52 +0,0 @@
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
*
* Icinga Web 2 - 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}}}
/*global Icinga:false, document: false, define:false require:false base_url:false console:false */
/**
* Ensures that our date/time controls will work on every browser (natively or javascript based)
*/
define(['jquery', 'datetimepicker'], function($) {
"use strict";
var DateTimePicker = function(target) {
$(target).datetimepicker({
format: 'yyyy-mm-dd hh:ii:ss',
minuteStep: 10,
autoclose: true,
todayBtn: true,
todayHighlight: true
});
$(target).parent().find('a').click(function(e) {
e.preventDefault();
$(target).datetimepicker('show');
});
};
return DateTimePicker;
});

View File

@ -1,100 +0,0 @@
/*global Icinga:false, Modernizr: false, document: false, History: false, define:false require:false base_url:false console:false */
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
*
* Icinga Web 2 - 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}}}
/**
* Icinga app/ellipsisText component
*
* This component adds ellipsis with expand functionality
* to content.
*
* Example:
*
* <pre>
* <code>
* <span data-icinga-component="app/ellipsisText">
* A very long example text
* </span>
* </code>
* </pre>
*/
define(['jquery'],
function($, logger, componentLoader, URI) {
"use strict";
/**
* Test if a css3 ellipsis is avtive
*
* @param {Element} element
* @returns {boolean}
*/
var activeEllipsis = function(element) {
return (element.offsetWidth < element.scrollWidth);
};
/**
* Add classes to element to create a css3 ellipsis
*
* Parent elements width is used to calculate containing width
* and set target element width to a fixed one.
*
* @param {Element} target
* @constructor
*/
var EllipsisText = function(target) {
var parentWidth = $(target).parent().width();
$(target).width(parentWidth)
.css('overflow', 'hidden')
.css('text-overflow', 'ellipsis')
.css('display', 'block')
.css('white-space', 'nowrap');
if (activeEllipsis(target)) {
$(target).wrap('<a></a>')
.css('cursor', 'pointer');
$(target).parent()
.attr('data-icinga-ellipsistext', 'true')
.attr('data-content', $(target).html())
.popover({
trigger : 'manual',
html : true,
placement : 'auto'
})
.click(function(e) {
e.stopImmediatePropagation();
$('a[data-icinga-ellipsistext=\'true\']').popover('hide');
$(e.currentTarget).popover('toggle');
});
}
};
return EllipsisText;
}
);

View File

@ -1,140 +0,0 @@
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
*
* Icinga Web 2 - 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}}}
/*global Icinga:false define:false require:false base_url:false console:false */
/**
* Icinga app/form component.
*
* This component makes sure a user has to confirm when trying to discard unsaved changes
* by leaving the current page. It also implements the code for autosubmitting fields having the
* 'data-icinga-form-autosubmit' component.
*/
define(['jquery'], function($) {
"use strict";
/**
* The attribute name marking forms as being modified
*
* @type {string}
*/
var ATTR_MODIFIED = 'data-icinga-form-modified';
/**
* Takes a form and returns an overloaded jQuery object
*
* The returned object is the jQuery matcher with the following additional methods:
*
* - isModified: Return true when the form is marked as modified
* - setModificationFlag: Mark this form as being modified
* - clearModificationFlag: Clear the modification mark
*
* @param targetForm
* @returns {jQuery}
*/
var getFormObject = function(targetForm) {
var form = $(targetForm);
/**
* Return true when the form is marked as modified
*
* @returns {boolean} True when the form has the @see ATTR_MODIFIED attribute set to 'true', otherwise false
*/
form.isModified = function() {
return form.attr(ATTR_MODIFIED) === 'true' ||
form.attr(ATTR_MODIFIED) === '1';
};
/**
* Mark this form as being modified
*/
form.setModificationFlag = function() {
form.attr(ATTR_MODIFIED, true);
};
/**
* Clear the modification flag on this form
*/
form.clearModificationFlag = function() {
form.attr(ATTR_MODIFIED, false);
};
return form;
};
/**
* Register event handler for detecting form modifications.
*
* This handler takes care of autosubmit form fields causing submissions on change and
* makes sure the modification flag on the form is set when changes occur.
*
* @param {jQuery} form A form object returned from @see getFormObject()
*/
var registerFormEventHandler = function(form) {
form.change(function(changed) {
if ($(changed.target).attr('data-icinga-form-autosubmit')) {
form.clearModificationFlag();
form.submit();
} else {
form.setModificationFlag();
}
});
// submissions should clear the modification flag
form.submit(function() {
form.clearModificationFlag();
});
};
/**
* Register an eventhandler that triggers a confirmation message when the user tries to leave a modified form
*
* @param {jQuery} form A form object returned from @see getFormObject()
*/
var registerLeaveConfirmationHandler = function(form) {
$(window).on('beforeunload', function() {
if (form.isModified()) {
return 'All unsaved changes will be lost when leaving this page';
}
});
};
/**
* The component bootstrap
*/
return function(targetForm) {
var form = getFormObject(targetForm);
registerFormEventHandler(form);
registerLeaveConfirmationHandler(form);
// Remove DOM level onchange, we registered proper jQuery listeners for them
$('[data-icinga-form-autosubmit]').removeAttr('onchange');
};
});

View File

@ -1,337 +0,0 @@
/*global Icinga:false, document: false, define:false require:false base_url:false console:false */
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
*
* Icinga Web 2 - 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(['components/app/container', 'jquery', 'logging', 'URIjs/URI', 'URIjs/URITemplate', 'icinga/util/url', 'icinga/selection/selectable', 'icinga/selection/multiSelection'],
function(Container, $, logger, URI, tpl, urlMgr, Selectable, TableMultiSelection) {
"use strict";
/**
* Master/Detail grid component handling history, link behaviour, selection (@TODO 3788) and updates of
* grids
*
* @param {HTMLElement} The outer element to apply the behaviour on
*/
return function(gridDomNode) {
/**
* Reference to the outer container of this component
*
* @type {*|HTMLElement}
*/
gridDomNode = $(gridDomNode);
/**
* A container component to use for updating URLs and content
*
* @type {Container}
*/
this.container = null;
/**
* The node wrapping the table and pagination
*
* @type {jQuery}
*/
var contentNode;
/**
* jQuery matcher result of the form components wrapping the controls
*
* @type {jQuery}
*/
var controlForms;
/**
* Handles multi-selection
*
* @type {TableMultiSelection}
*/
var selection;
/**
* Defines how row clicks are handled. Can either be 'none', 'single' or 'multi'
*
* @type {string}
*/
var selectionMode;
/**
* Detect and select control forms for this table and return them
*
* Form controls are either all forms underneath the of the component, but not underneath the table
* or in a dom node explicitly tagged with the 'data-icinga-actiongrid-controls' attribute
*
* @param {jQuery|null} domContext The context to use as the root node for matching, if null
* the component node given in the constructor is used
*
* @returns {jQuery} A selector result with all forms modifying this grid
*/
var determineControlForms = function(domContext) {
domContext = domContext || gridDomNode;
var controls = $('[data-icinga-grid-controls]', domContext);
if (controls.length > 0) {
return $('form', controls);
} else {
return $('form', domContext).filter(function () {
return $(this).parentsUntil(domContext, 'table').length === 0;
});
}
};
/**
* Detect and select the dom of all tables displaying content for this mainDetailGrid component
*
* The table can either explicitly tagged with the 'data-icinga-grid-content' attribute, if not every table
* underneath the components root dom will be used
*
* @param {jQuery|null} domContext The context to use as the root node for matching, if null
* the component node given in the constructor is used
*
* @returns {jQuery} A selector result with all tables displaying information in the
* grid
*/
var determineContentTable = function(domContext) {
domContext = domContext || gridDomNode;
var maindetail = $('[data-icinga-grid-content]', domContext);
if (maindetail.length > 0) {
return maindetail;
} else {
return $('table', domContext);
}
};
/**
* Show a 'hand' to indicate that the row is selectable,
* when hovering.
*/
this.showMousePointerOnRow = function(domContext) {
domContext = domContext || contentNode;
$('tbody tr', domContext).css('cursor' ,'pointer');
};
/**
* Activate a hover effect on all table rows, to indicate that
* this table row is clickable.
*
* @param domContext
*/
this.activateRowHovering = function(domContext) {
domContext = domContext || contentNode;
//$(domContext).addClass('table-hover');
$('tbody tr', domContext).hover(
function(e) {
$(this).addClass('hover');
e.preventDefault();
e.stopPropagation();
},
function(e) {
$(this).removeClass('hover');
e.preventDefault();
e.stopPropagation();
}
);
};
/**
* Register the row links of tables using the first link found in the table (no matter if visible or not)
*
* Row level links can only be realized via JavaScript, so every row should provide additional links for
* Users that don't have javascript enabled
*
* @param {jQuery|null} domContext The rootnode to use for selecting rows or null to use contentNode
*/
this.registerTableLinks = function(domContext) {
domContext = domContext || contentNode;
$('tbody tr button[type=submit], tbody tr submit', domContext).click(function(ev) {
ev.stopPropagation();
return true;
});
$('tbody tr', domContext).click(function(ev) {
var targetEl = ev.target || ev.toElement || ev.relatedTarget,
a = $(targetEl).closest('a');
ev.preventDefault();
ev.stopPropagation();
var nodeNames = [];
nodeNames.push($(targetEl).prop('nodeName').toLowerCase());
nodeNames.push($(targetEl).parent().prop('nodeName').toLowerCase());
if (a.length) {
// test if the URL is on the current server, if not open it directly
if (Container.isExternalLink(a.attr('href'))) {
return true;
}
}
var selected = new Selectable(this);
switch (selectionMode) {
case 'multi':
if (ev.ctrlKey || ev.metaKey) {
selection.toggle(selected);
} else if (ev.shiftKey) {
selection.add(selected);
} else {
var oldState = selected.isActive();
if (!oldState) {
selection.clear();
selection.add(selected);
}
}
break;
case 'single':
oldState = selected.isActive();
if (!oldState) {
selection.clear();
selection.add(selected);
}
break;
default:
// don't open the link
return;
}
var url = URI($('a', this).attr('href'));
if (targetEl.tagName.toLowerCase() === 'a') {
url = URI($(targetEl).attr('href'));
}
var segments = url.segment();
if (selection.size() === 0) {
// don't open anything
urlMgr.setDetailUrl('');
return false;
} 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());
}
urlMgr.setDetailUrl(url);
return false;
});
/*
* Clear the URL when deselected or when a wildcard is used
*/
$(window).on('hashchange', function(){
if (
!location.hash ||
location.hash.match(/(host=%2A)|(service=%2A)/)
) {
selection.clear();
}
});
};
/**
* Register submit handler for the form controls (sorting, filtering, etc). Reloading happens in the
* current container
*/
this.registerControls = function() {
controlForms.on('submit', function(evt) {
var container = (new Container(this));
var form = $(this);
var url = container.getUrl();
if (url.indexOf('?') >= 0) {
url += '&';
} else {
url += '?';
}
url += form.serialize();
container.setUrl(url);
evt.preventDefault();
evt.stopPropagation();
return false;
});
$('.pagination li a, a.filter-badge', contentNode.parent()).on('click', function(ev) {
var container = (new Container(this));
// Detail will be removed when main pagination changes
if (container.containerType === 'icingamain') {
urlMgr.setMainUrl(URI($(this).attr('href')));
urlMgr.setDetailUrl('');
} else {
urlMgr.setDetailUrl(URI($(this).attr('href')));
}
ev.preventDefault();
ev.stopPropagation();
return false;
});
};
/**
* Create a new TableMultiSelection, attach it to the content node, and use the
* current detail url to restore the selection state
*/
this.initSelection = function() {
var detail = urlMgr.getDetailUrl();
if (typeof detail !== 'string') {
detail = detail[0] || '';
}
selection = new TableMultiSelection(contentNode,new URI(detail));
};
/**
* Init all objects responsible for selection handling
*
* - Indicate selection by showing active and hovered rows
* - Handle click-events according to the selection mode
* - Create and follow links according to the row content
*/
this.initRowSelection = function() {
selectionMode = gridDomNode.data('icinga-grid-selection-type');
if (selectionMode === 'multi' || selectionMode === 'single') {
// indicate selectable rows
this.showMousePointerOnRow();
this.activateRowHovering();
this.initSelection();
}
this.registerTableLinks();
};
/**
* Create this component, setup listeners and behaviour
*/
this.construct = function(target) {
this.container = new Container(target);
this.container.removeDefaultLoadIndicator();
controlForms = determineControlForms();
contentNode = determineContentTable();
this.initRowSelection();
this.registerControls();
};
if (typeof $(gridDomNode).attr('id') === 'undefined') {
this.construct(gridDomNode);
}
};
});

View File

@ -1,231 +0,0 @@
/*global Icinga:false, document: false, define:false require:false base_url:false console:false */
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
*
* Icinga Web 2 - 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}}}
/**
* Ensures that our date/time controls will work on every browser (natively or javascript based)
*/
define(['jquery', 'logging', 'URIjs/URI', 'components/app/container'], function($, log, URI, Container) {
'use strict';
return function(inputDOM) {
this.inputDom = $(inputDOM);
this.domain = this.inputDom.attr('data-icinga-filter-domain');
this.module = this.inputDom.attr('data-icinga-filter-module');
this.form = $(this.inputDom.parents('form').first());
this.formUrl = URI(this.form.attr('action'));
this.lastQueuedEvent = null;
this.pendingRequest = null;
/**
* Register the input listener
*/
this.construct = function() {
this.registerControlListener();
};
/**
* Request new proposals for the given input box
*/
this.getProposal = function() {
var text = $.trim(this.inputDom.val());
if (this.pendingRequest) {
this.pendingRequest.abort();
}
this.pendingRequest = $.ajax(this.getRequestParams(text))
.done(this.showProposals.bind(this))
.fail(this.showError.bind(this));
};
/**
* Apply a selected proposal to the text box
*
* String parts encapsulated in {} are parts that already exist in the input
*
* @param token The selected token
*/
this.applySelectedProposal = function(token) {
var currentText = $.trim(this.inputDom.val());
var substr = token.match(/^(\{.*\})/);
if (substr !== null) {
token = token.substr(substr[0].length);
} else {
token = ' ' + token;
}
currentText += token;
this.inputDom.val(currentText);
this.inputDom.popover('hide');
this.inputDom.focus();
};
/**
* Display an error in the box if the request failed
*
* @param {Object} error The error response
* @param {String} state The HTTP state as a string
*/
this.showError = function(error, state) {
if (!error.message || state === 'abort') {
return;
}
this.inputDom.popover('destroy').popover({
content: '<div class="alert alert-danger"> ' + error.message + ' </div>',
html: true,
trigger: 'manual'
}).popover('show');
};
/**
* Return an Object containing the request information for the given query
*
* @param query
* @returns {{data: {cache: number, query: *, filter_domain: (*|Function|Function), filter_module: Function}, headers: {Accept: string}, url: *}}
*/
this.getRequestParams = function(query) {
return {
data: {
'cache' : (new Date()).getTime(),
'query' : query,
'filter_domain' : this.domain,
'filter_module' : this.module
},
headers: {
'Accept': 'application/json'
},
url: this.formUrl
};
};
/**
* Callback that renders the proposal list after retrieving it from the server
*
* @param {Object} response The jquery response object inheritn XHttpResponse Attributes
*/
this.showProposals = function(response) {
if (!response || !response.proposals || response.proposals.length === 0) {
this.inputDom.popover('destroy');
return;
}
if (response.valid) {
this.inputDom.parent('div').removeClass('has-error').addClass('has-success');
} else {
this.inputDom.parent('div').removeClass('has-success').addClass('has-error');
}
var list = $('<ul>').addClass('nav nav-stacked');
$.each(response.proposals, (function(idx, token) {
var displayToken = token.replace(/(\{|\})/g, '');
var proposal = $('<li>').
append($('<a href="#">').
text(displayToken)
).appendTo(list);
proposal.on('click', (function(ev) {
ev.preventDefault();
ev.stopPropagation();
this.applySelectedProposal(token);
return false;
}).bind(this));
}).bind(this));
this.inputDom.popover('destroy').popover({
content: list,
placement : 'bottom',
html: true,
trigger: 'manual'
}).popover('show');
};
/**
* Callback to update the current container with the entered url if it's valid
*/
this.updateFilter = function() {
var query = $.trim(this.inputDom.val());
$.ajax(this.getRequestParams(query))
.done((function(response) {
var domContainer = new Container(this.inputDom);
var url = response.urlParam;
if (url) {
domContainer.setUrl(url);
}
}).bind(this));
};
/**
* Register listeners for the searchbox
*
* This means:
* - Activate/Deactivate the popover on focus and blur
* - Add Url tokens and submit on enter
*/
this.registerControlListener = function() {
this.inputDom.on('blur', (function() {
$(this).popover('hide');
}));
this.inputDom.on('focus', updateProposalList.bind(this));
this.inputDom.on('keyup', updateProposalList.bind(this));
this.inputDom.on('keydown', (function(keyEv) {
if ((keyEv.keyCode || keyEv.which) === 13) {
this.updateFilter();
keyEv.stopPropagation();
keyEv.preventDefault();
return false;
}
}).bind(this));
this.form.submit(function(ev) {
ev.stopPropagation();
ev.preventDefault();
return false;
});
};
/**
* Callback to update the proposal list if a slight delay on keyPress
*
* Needs to be bound to the object scope
*
* @param {jQuery.Event} keyEv The key Event to react on
*/
var updateProposalList = function(keyEv) {
if (this.lastQueuedEvent) {
window.clearTimeout(this.lastQueuedEvent);
}
this.lastQueuedEvent = window.setTimeout(this.getProposal.bind(this), 500);
};
this.construct();
};
});

View File

@ -1,40 +0,0 @@
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
*
* Icinga Web 2 - 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}}}
/*global Icinga:false, document: false, define:false require:false base_url:false console:false */
/**
* Ensures that our date/time controls will work on every browser (natively or javascript based)
*/
define(['jquery', 'datetimepicker'], function($) {
"use strict";
var triStateCheckbox = function(target) {
// TODO: remove radio button group from form and add a tri-state checkbox
};
return triStateCheckbox;
});

View File

@ -1,145 +0,0 @@
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
*
* Icinga Web 2 - 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}}}
/*global Icinga:false, document: false, define:false require:false base_url:false console:false */
define([
'jquery',
'logging',
'icinga/componentLoader',
'components/app/container',
'URIjs/URI',
'icinga/util/url'
], function ($, log, components, Container, URI, urlMgr) {
'use strict';
/**
* Icinga prototype
*/
var Icinga = function() {
var pendingRequest = null;
/**
* Initia
*/
var initialize = function () {
components.load();
// qd, wip, wrong, the nastiest piece of JS code you've ever seen..
if (window.name === '') {
window.name = request_id; // The request id should survive page reloads..
}
$(document).on('click', 'a', function() {
// TODO: The intention of these lines is sending the "request_id" every
// time a request is made, though this approach does not work for
// XHR requests and it is also hijacking external links.
// An alternative is required, once someone reworked the Javascript
// implementation so we have some sort of centralized place to handle
// stuff like that properly.
var href = $(this).attr('href');
window.location.href = URI(href).addSearch('request_id', window.name);
return false;
});
// qd, wip, wrong, the nastiest piece of JS code you've ever seen..
log.debug("Initialization finished");
};
/**
* Globally open the given url and reload the main/detail box to represent it
*
* @param url The url to load
*/
this.openUrl = function(url) {
if (pendingRequest) {
pendingRequest.abort();
}
pendingRequest = $.ajax({
"url": url
}).done(function(response) {
var dom = $(response);
var detailDom = null;
if (urlMgr.detailUrl) {
detailDom = $('#icingadetail');
}
$(document.body).empty().append(dom);
if (detailDom && detailDom.length) {
$('#icingadetail').replaceWith(detailDom);
Container.showDetail();
}
components.load();
Container.getMainContainer();
}).fail(function(response, reason) {
if (reason === 'abort') {
return;
}
log.error("Request failed: ", response.message);
});
};
if (Modernizr.history) {
/**
* Event handler that will be called when the url change
*/
urlMgr.syncWithUrl();
var lastMain = urlMgr.mainUrl;
$(window).on('pushstate', (function() {
urlMgr.syncWithUrl();
if (urlMgr.mainUrl !== lastMain) {
this.openUrl(urlMgr.getUrl());
lastMain = urlMgr.mainUrl;
}
// If an anchor is set, scroll to it's position
if ($('#' + urlMgr.anchor).length) {
$(document.body).scrollTo($('#' + urlMgr.anchor));
}
}).bind(this));
/**
* Event handler for browser back/forward events
*/
$(window).on('popstate', (function() {
var lastMain = urlMgr.mainUrl;
urlMgr.syncWithUrl();
if (urlMgr.mainUrl !== lastMain) {
this.openUrl(urlMgr.getUrl());
}
}).bind(this));
}
$(document).ready(initialize.bind(this));
Container.setIcinga(this);
this.components = components;
};
return new Icinga();
});

View File

@ -1,217 +0,0 @@
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
*
* Icinga Web 2 - 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 {URI} 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 selections = [];
$.each(query, function(key, value) {
// Fetch the index from the key
var id = key.match(/\[([0-9]+)\]/);
if (id) {
// Remove the index from the key
key = key.replace(/\[[0-9]+\]/,'');
// Create an object that contains the queries for each index.
var i = id[1];
if (!selections[i]) {
selections[i] = [];
}
selections[i].push(encodeURIComponent(key) + '=' + encodeURIComponent(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 [];
}
var segments = url.segment();
var parts;
// TODO: Handle it for cases when there is no /icinga-web2/ in the path
if (segments.length > 2 && segments[2].toLowerCase() === 'multi') {
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) {
var restored = selectables[selectionId];
if (restored) {
selection[selectionId] = restored;
restored.setActive(true);
}
});
return selection;
};
selection = restoreSelection();
};
});

View File

@ -1,99 +0,0 @@
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
*
* Icinga Web 2 - 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);
};
/**
* Set the current selection state
*
* @param {boolean} The new state
*/
this.setActive = function(value) {
if (value) {
$(tableRow).addClass('active');
} else {
$(tableRow).removeClass('active');
}
};
/**
* Return the current selection state
*
* @returns {boolean} True when the object is selected
*/
this.isActive = function()
{
return $(tableRow).hasClass('active');
};
};
});

View File

@ -1,98 +0,0 @@
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
*
* Icinga Web 2 - 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}}}
/*global Icinga:false, document: false, define:false require:false base_url:false console:false, window:false */
/**
* Icinga Logger
*
* Allows platform independent logging of via logger.info, logger.warn, logger.error and logger.emergency
*
*/
define(function() {
'use strict';
/**
* Log a message to the console (if available), using the provided tag
*
* @param {String} tag The tag to use, error and emergency are logged as console.error
* @param {String} logArgs The arguments to log
*/
function logTagged(tag, logArgs) {
var now = new Date();
var ms = now.getMilliseconds() + '';
while (ms.length < length) {
ms = '0' + ms;
}
logArgs = [].slice.call(logArgs);
logArgs.unshift(now.toLocaleTimeString() + '.' + ms);
var args = [tag.toUpperCase() + ' :'];
for (var el in logArgs) {
args.push(logArgs[el]);
}
try {
if (console[tag]) {
console[tag].apply(console, logArgs);
} else if (tag === 'emergency') {
console.error.apply(console, logArgs);
} else {
console.log.apply(console, args);
}
} catch (e) { // IE fallback
console.log(logArgs);
}
}
if(!window.console) {
window.console = { log: function() {} };
}
/**
* Callinterface for this module
*/
return {
debug: function() {
if (!window.ICINGA_DEBUG) {
return;
}
logTagged('debug', arguments);
},
warn: function() {
logTagged('warn', arguments);
},
error: function() {
logTagged('error', arguments);
},
emergency: function() {
logTagged('emergency', arguments);
// TODO: log *emergency* errors to the backend
}
};
});

View File

@ -1,194 +0,0 @@
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
*
* Icinga Web 2 - 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', 'logging', 'URIjs/URI'], function($, log, URI, Container) {
"use strict";
var currentUrl = URI(window.location.href);
/**
* Utility class for Url handling
*
*/
var URLMgr = function() {
/**
* The current url of the main part
* @type {string}
*/
this.mainUrl = '';
/**
* The current main anchor
* @type {string}
*/
this.anchor = '';
/**
* The current detail url
*
* @type {string}
*/
this.detailUrl = '';
/**
* The current anchor of the detail url
*
* @type {string}
*/
this.detailAnchor = '';
/**
* Extract the anchor of the main url part from the given url
*
* @param {String|URI} url An URL object to extract the information from
* @returns {*}
*/
this.getMainAnchor = function(url) {
url = url || URI(window.location.href);
if (typeof url === 'string') {
url = URI(url);
}
var fragment = url.fragment();
if (fragment.length === 0) {
return '';
}
var parts = fragment.split('!');
if (parts.length > 0) {
return parts[0];
} else {
return '';
}
};
/**
* Extract the detail url a the given url. Returns a [URL, ANCHOR] Tupel
*
* @param String url An optional url to parse (otherwise window.location.href is used)
* @returns {Array} A [{String} Url, {String} anchor] tupel
*/
this.getDetailUrl = function(url) {
url = url || URI(window.location.href);
if (typeof url === 'string') {
url = URI(url);
}
var fragment = url.fragment();
if (fragment.length === 0) {
return '';
}
var parts = fragment.split('!', 2);
if (parts.length === 2) {
var result = /detail=(.*)$/.exec(parts[1]);
if (!result || result.length < 2) {
return '';
}
return result[1].replace('%23', '#').split('#');
} else {
return '';
}
};
/**
* Overwrite the detail Url and update the hash
*
* @param String url The url to use for the detail part
*/
this.setDetailUrl = function(url) {
if (typeof url === 'string') {
url = URI(url);
}
if( !url.fragment() || url.href() !== '#' + url.fragment()) {
this.detailUrl = url.clone().fragment('').href();
}
this.detailAnchor = this.getMainAnchor(url);
window.location.hash = this.getUrlHash();
};
/**
* Get the hash of the current detail url and anchor i
*
* @returns {string}
*/
this.getUrlHash = function() {
var anchor = '#' + this.anchor +
'!' + ($.trim(this.detailUrl) ? 'detail=' : '') + this.detailUrl +
(this.detailAnchor ? '%23' : '') + this.detailAnchor;
anchor = $.trim(anchor);
if (anchor === '#!' || anchor === '#') {
anchor = '';
}
return anchor;
};
/**
* Set the main url to be used
*
* This triggers the pushstate event or causes a page reload if the history api is
* not available
*
* @param url
*/
this.setMainUrl = function(url) {
this.anchor = this.getMainAnchor(url);
this.mainUrl = URI(url).clone().fragment('').href();
if (!Modernizr.history) {
window.location.href = this.mainUrl + this.getUrlHash();
} else {
window.history.pushState({}, document.title, this.mainUrl + this.getUrlHash());
$(window).trigger('pushstate');
}
};
/**
* Return the href (main path + hash)
*
* @returns {string}
*/
this.getUrl = function() {
return this.mainUrl + this.getUrlHash();
};
/**
* Take the current url and sync the internal state of this url manager with it
*/
this.syncWithUrl = function() {
this.mainUrl = URI(window.location.href).clone().fragment('').href();
this.anchor = this.getMainAnchor();
var urlAnchorTupel = this.getDetailUrl();
this.detailUrl = urlAnchorTupel[0] || '';
this.detailAnchor = urlAnchorTupel[1] || '';
};
this.syncWithUrl();
};
var urlMgr = new URLMgr();
return urlMgr;
});

View File

@ -1,41 +0,0 @@
requirejs.config({
'baseUrl': window.base_url + '/js',
'urlArgs': "bust=" + (new Date()).getTime(),
'paths': {
'jquery': 'vendor/jquery-1.8.3',
'jquery_scrollto': 'vendor/jquery.scrollto',
'freetile': 'vendor/freetile',
'bootstrap': 'vendor/bootstrap/bootstrap.min',
'logging': 'icinga/util/logging',
'URIjs': 'vendor/uri',
'datetimepicker': 'vendor/bootstrap/datetimepicker.min'
},
'shim': {
'datetimepicker': {
'exports': 'datetimepicker'
},
'jquery_scrollto': {
exports: 'jquery_scrollto'
},
'freetile': {
exports: 'freetile'
},
'jquery' : {
exports: 'jquery'
}
}
});
define(['jquery'], function ($, history) {
window.$ = $;
window.jQuery = $;
requirejs(['bootstrap','vendor/imagesLoaded','jquery_scrollto', 'freetile'], function() {
requirejs(['datetimepicker']);
});
requirejs(['icinga/icinga'], function (Icinga) {
window.Icinga = Icinga;
});
});