diff --git a/modules/monitoring/application/controllers/TimelineController.php b/modules/monitoring/application/controllers/TimelineController.php
index e419b1c3d..df6aa811d 100644
--- a/modules/monitoring/application/controllers/TimelineController.php
+++ b/modules/monitoring/application/controllers/TimelineController.php
@@ -66,9 +66,12 @@ class Monitoring_TimelineController extends ActionController
$timeline->setMinimumCircleWidth('0.3em');
$timeline->setDisplayRange($displayRange);
$timeline->setForecastRange($forecastRange);
- $timeline->setSession($this->getWindowSession('timeline', $this->getRequest()->getParam('extend') != 1));
+ $beingExtended = $this->getRequest()->getParam('extend') == 1;
+ $timeline->setSession($this->getWindowSession('timeline', !$beingExtended));
$this->view->timeline = $timeline;
+ $this->view->nextRange = $forecastRange;
+ $this->view->beingExtended = $beingExtended;
$this->view->intervalFormat = $this->getIntervalFormat();
$oldBase = $timeline->getCalculationBase(false);
$this->view->switchedContext = $oldBase !== null && $oldBase !== $timeline->getCalculationBase(true);
diff --git a/modules/monitoring/application/views/scripts/timeline/index.phtml b/modules/monitoring/application/views/scripts/timeline/index.phtml
index c5e93a590..d7fd85fd4 100644
--- a/modules/monitoring/application/views/scripts/timeline/index.phtml
+++ b/modules/monitoring/application/views/scripts/timeline/index.phtml
@@ -1,10 +1,12 @@
getGroupInfo();
-$firstRow = true;
+$firstRow = !$beingExtended;
?>
+
= $intervalBox; ?>
@@ -20,6 +22,7 @@ $firstRow = true;
+
@@ -76,5 +79,19 @@ $extrapolatedCircleWidth = $timeline->getExtrapolatedCircleWidth($timeInfo[1][$g
+
+
+
diff --git a/modules/monitoring/public/js/module.js b/modules/monitoring/public/js/module.js
new file mode 100644
index 000000000..2d04785b5
--- /dev/null
+++ b/modules/monitoring/public/js/module.js
@@ -0,0 +1,83 @@
+
+(function(Icinga) {
+
+ var Monitoring = function(module) {
+ /**
+ * The Icinga.Module instance
+ */
+ this.module = module;
+
+ /**
+ * The observer used to handle the timeline's infinite loading
+ */
+ this.scrollCheckTimer = null;
+
+ /**
+ * Whether to skip the timeline's scroll-check
+ */
+ this.skipScrollCheck = false;
+
+ this.initialize();
+ };
+
+ Monitoring.prototype = {
+
+ initialize: function()
+ {
+ this.module.on('rendered', this.enableScrollCheck);
+ this.module.icinga.logger.debug('Monitoring module loaded');
+ },
+
+ /**
+ * Enable the timeline's scroll-check
+ */
+ enableScrollCheck: function()
+ {
+ /**
+ * Re-enable the scroll-check in case the timeline has just been extended
+ */
+ if (this.skipScrollCheck) {
+ this.skipScrollCheck = false;
+ }
+
+ /**
+ * Prepare the timer to handle the timeline's infinite loading
+ */
+ if ($('div.timeline').length) {
+ if (this.scrollCheckTimer === null) {
+ this.scrollCheckTimer = this.module.icinga.timer.register(
+ this.checkTimelinePosition,
+ this,
+ 800
+ );
+ this.module.icinga.logger.debug('Enabled timeline scroll-check');
+ }
+ }
+ },
+
+ /**
+ * Check whether the user scrolled to the end of the timeline
+ */
+ checkTimelinePosition: function()
+ {
+ if (!$('div.timeline').length) {
+ this.module.icinga.timer.unregister(this.scrollCheckTimer);
+ this.scrollCheckTimer = null;
+ this.module.icinga.logger.debug('Disabled timeline scroll-check');
+ } else if (!this.skipScrollCheck && this.module.icinga.utils.isVisible('#end')) {
+ this.skipScrollCheck = true;
+ this.module.icinga.loader.loadUrl(
+ $('#end').remove().attr('href'),
+ $('div.timeline'),
+ undefined,
+ undefined,
+ 'append'
+ );
+ }
+ }
+
+ },
+
+ Icinga.availableModules.monitoring = Monitoring;
+
+}(Icinga));
diff --git a/modules/monitoring/public/js/timelineComponent.js b/modules/monitoring/public/js/timelineComponent.js
deleted file mode 100644
index 368d8f861..000000000
--- a/modules/monitoring/public/js/timelineComponent.js
+++ /dev/null
@@ -1,123 +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
- * @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
- * @author Icinga Development Team
- *
- */
-// {{{ICINGA_LICENSE_HEADER}}}
-
-/**
- * Provides infinite scrolling functionality for the monitoring timeline
- */
-define(['jquery', 'logging'], function($, log) {
- 'use strict';
-
- return function() {
- this.scrolled = false;
- this.ignoreScroll = false;
-
- /**
- * Scroll-event to register that the user has scrolled
- */
- this.registerScroll = function() {
- if (!this.ignoreScroll) {
- this.scrolled = true;
- }
- };
-
- /**
- * Check whether the user has scrolled to the timeline's end
- * and initiate the infinite scrolling if this is the case
- */
- this.checkScroll = function() {
- if (this.scrolled) {
- if (this.isScrolledIntoView('#TimelineEnd')) {
- this.ignoreScroll = true;
- this.loadTimeline.bind(this)();
- }
- this.scrolled = false;
- }
-
- if ($('[name="Timeline"]').length > 0) {
- setTimeout(this.checkScroll.bind(this), 1000);
- }
- };
-
- /**
- * Return whether the given element is visible in the users view
- *
- * Borrowed from: http://stackoverflow.com/q/487073
- *
- * @param {selector} element The element to check
- * @returns {Boolean}
- */
- this.isScrolledIntoView = function(element) {
- var docViewTop = $(window).scrollTop();
- var docViewBottom = docViewTop + $(window).height();
-
- var elemTop = $(element).offset().top;
- var elemBottom = elemTop + $(element).height();
-
- return ((elemBottom >= docViewTop) && (elemTop <= docViewBottom)
- && (elemBottom <= docViewBottom) && (elemTop >= docViewTop));
- };
-
- /**
- * Return the current base url
- *
- * @returns {String}
- */
- this.getBaseUrl = function() {
- var protocol = window.location.protocol;
- var host = window.location.host;
- var base = window.base_url;
-
- return protocol + "//" + host + base;
- }
-
- /**
- * Initiate the AJAX timeline request
- */
- this.loadTimeline = function() {
- var query = {};
- var base_url = this.getBaseUrl();
- $.get(base_url + '/monitoring/timeline/extend', query, this.extendTimeline.bind(this));
- };
-
- /**
- * Process the AJAX timeline response
- *
- * @param {string} html
- */
- this.extendTimeline = function(html) {
- this.ignoreScroll = false;
- // TODO: Implement the processing logic
- }
-
- // The scroll-logic is split into two functions to avoid wasting too much
- // performance by checking whether the user reached the end of the timeline
- $(window).scroll(this.registerScroll.bind(this));
- setTimeout(this.checkScroll.bind(this), 1000);
- };
-});
diff --git a/public/js/icinga/utils.js b/public/js/icinga/utils.js
index 5f7cf452c..7a756092e 100644
--- a/public/js/icinga/utils.js
+++ b/public/js/icinga/utils.js
@@ -53,6 +53,30 @@
return hours + ':' + minutes + ':' + seconds;
},
+ /**
+ * Return whether the given element is visible in the users view
+ *
+ * Borrowed from: http://stackoverflow.com/q/487073
+ *
+ * @param {selector} element The element to check
+ * @returns {Boolean}
+ */
+ isVisible: function(element)
+ {
+ var $element = $(element);
+ if (!$element.length) {
+ return false;
+ }
+
+ var docViewTop = $(window).scrollTop();
+ var docViewBottom = docViewTop + $(window).height();
+ var elemTop = $element.offset().top;
+ var elemBottom = elemTop + $element.height();
+
+ return ((elemBottom >= docViewTop) && (elemTop <= docViewBottom)
+ && (elemBottom <= docViewBottom) && (elemTop >= docViewTop));
+ },
+
getUrlHelper: function () {
if (this.urlHelper === null) {
this.urlHelper = document.createElement('a');