From 80b4e3bf3321f8fcbdd656e852c5021ede71a370 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Tue, 1 Apr 2014 11:41:05 +0200 Subject: [PATCH] Add infinite scrolling to the timeline refs #4190 --- .../controllers/TimelineController.php | 5 +- .../views/scripts/timeline/index.phtml | 19 ++- modules/monitoring/public/js/module.js | 83 ++++++++++++ .../monitoring/public/js/timelineComponent.js | 123 ------------------ public/js/icinga/utils.js | 24 ++++ 5 files changed, 129 insertions(+), 125 deletions(-) create mode 100644 modules/monitoring/public/js/module.js delete mode 100644 modules/monitoring/public/js/timelineComponent.js 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; ?> +
@@ -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');