From: Alexander Ebert Date: Tue, 11 Feb 2014 21:59:10 +0000 (+0100) Subject: Improved image viewer, added WCF.PeriodicalExecuter.resume() X-Git-Tag: 2.0.3~51 X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=ff34ee1ff2a7185767aa5711edfbf552e2d1e8fa;p=GitHub%2FWoltLab%2FWCF.git Improved image viewer, added WCF.PeriodicalExecuter.resume() --- diff --git a/wcfsetup/install/files/js/WCF.ImageViewer.js b/wcfsetup/install/files/js/WCF.ImageViewer.js index 8618aae01e..04921abece 100644 --- a/wcfsetup/install/files/js/WCF.ImageViewer.js +++ b/wcfsetup/install/files/js/WCF.ImageViewer.js @@ -303,6 +303,8 @@ $.widget('ui.wcfImageViewer', { this._isOpen = true; + WCF.System.DisableScrolling.disable(); + return true; }, @@ -323,6 +325,8 @@ $.widget('ui.wcfImageViewer', { this._isOpen = false; + WCF.System.DisableScrolling.enable(); + return true; }, @@ -336,14 +340,19 @@ $.widget('ui.wcfImageViewer', { return false; } - this._timer = new WCF.PeriodicalExecuter($.proxy(function() { - var $index = this._active + 1; - if ($index == this._items) { - $index = 0; - } - - this.showImage($index); - }, this), this.options.speed * 1000); + if (this._timer === null) { + this._timer = new WCF.PeriodicalExecuter($.proxy(function() { + var $index = this._active + 1; + if ($index == this._items) { + $index = 0; + } + + this.showImage($index); + }, this), this.options.speed * 1000); + } + else { + this._timer.resume(); + } this._slideshowEnabled = true; @@ -355,9 +364,10 @@ $.widget('ui.wcfImageViewer', { /** * Disables the slideshow. * + * @param boolean disableSlideshow * @return boolean */ - stopSlideshow: function() { + stopSlideshow: function(disableSlideshow) { if (!this._slideshowEnabled) { return false; } @@ -415,21 +425,23 @@ $.widget('ui.wcfImageViewer', { * @param object event */ _showImage: function(event) { - this.stopSlideshow(); - this.showImage($(event.currentTarget).data('index')); + this.showImage($(event.currentTarget).data('index'), true); }, /** * Displays an image by index. * * @param integer index + * @param boolean disableSlideshow * @return boolean */ - showImage: function(index) { + showImage: function(index, disableSlideshow) { if (this._active == index) { return false; } + this.stopSlideshow(disableSlideshow || false); + // reset active marking if (this._active != -1) { this._images[this._active].listItem.removeClass('active'); @@ -442,19 +454,26 @@ $.widget('ui.wcfImageViewer', { $image.listItem.addClass('active'); var $dimensions = this._ui.imageContainer.getDimensions('inner'); + var $newImageIndex = (this._activeImage ? 0 : 1); + this._renderImage($newImageIndex, $image, $dimensions); - if (this._activeImage === null) { - this._activeImage = 0; - this._renderImage(this._activeImage, $image, $dimensions); + if (this._activeImage !== null) { + this._ui.images[this._activeImage].removeClass('active'); + } + + this._activeImage = $newImageIndex; + + var $currentActiveImage = this._active; + if (this._ui.images[$newImageIndex].get(0).complete) { + // image was fetched from cache + this._imageOnLoad($currentActiveImage, $newImageIndex); } else { - var $newImageIndex = (this._activeImage ? 0 : 1); - this._renderImage($newImageIndex, $image, $dimensions); - - this._ui.images[this._activeImage].removeClass('active'); - this._ui.images[$newImageIndex].addClass('active'); - - this._activeImage = $newImageIndex; + // image is loading, display once loaded + this._ui.imageContainer.addClass('loading'); + this._ui.images[$newImageIndex].off('load').on('load', $.proxy(function() { + this._imageOnLoad($currentActiveImage, $newImageIndex); + }, this)); } // user @@ -481,6 +500,16 @@ $.widget('ui.wcfImageViewer', { return true; }, + _imageOnLoad: function(currentActiveImage, activeImageIndex) { + // image did not load in time, ignore + if (currentActiveImage != this._active) { + return; + } + + this._ui.imageContainer.removeClass('loading'); + this._ui.images[activeImageIndex].addClass('active'); + }, + /** * Renders target image, leaving 'imageData' undefined will invoke the rendering process for the currently active image. * @@ -584,7 +613,7 @@ $.widget('ui.wcfImageViewer', { $slideshowButtonEnlarge.click($.proxy(this._toggleView, this)); $slideshowButtonToggle.click($.proxy(function() { if (this._slideshowEnabled) { - this.stopSlideshow(); + this.stopSlideshow(true); } else { this.startSlideshow(); @@ -618,7 +647,7 @@ $.widget('ui.wcfImageViewer', { _next: function(event, shiftBy) { if (this._ui.buttonNext.hasClass('pointer')) { if (shiftBy == undefined) { - this.stopSlideshow(); + this.stopSlideshow(true); } var $maximumOffset = Math.max((this._items * this._thumbnailWidth) - this._thumbnailContainerWidth - this._thumbnailMarginRight, 0); @@ -640,7 +669,7 @@ $.widget('ui.wcfImageViewer', { _previous: function(event, unshiftBy) { if (this._ui.buttonPrevious.hasClass('pointer')) { if (unshiftBy == undefined) { - this.stopSlideshow(); + this.stopSlideshow(true); } this._thumbnailOffset = Math.max(this._thumbnailOffset - (this._thumbnailWidth * (unshiftBy ? unshiftBy : this.options.shiftBy)), 0); @@ -657,7 +686,7 @@ $.widget('ui.wcfImageViewer', { */ _nextImage: function(event) { if (this._ui.slideshow.next.hasClass('pointer')) { - this.stopSlideshow(); + this.stopSlideshow(true); this.showImage(this._active + 1); } }, @@ -669,7 +698,7 @@ $.widget('ui.wcfImageViewer', { */ _previousImage: function(event) { if (this._ui.slideshow.previous.hasClass('pointer')) { - this.stopSlideshow(); + this.stopSlideshow(true); this.showImage(this._active - 1); } }, @@ -765,8 +794,16 @@ $.widget('ui.wcfImageViewer', { for (var $i = 0, $length = images.length; $i < $length; $i++) { var $image = images[$i]; - var $listItem = $('
  • ').appendTo(this._ui.imageList); + var $listItem = $('
  • ').appendTo(this._ui.imageList); $listItem.data('index', this._images.length).click($.proxy(this._showImage, this)); + var $img = $listItem.children('img'); + if ($img.get(0).complete) { + // thumbnail is read from cache + $listItem.removeClass('loading'); + } + else { + $img.on('load', function() { $(this).parent().removeClass('loading'); }); + } $image.listItem = $listItem; this._images.push($image); @@ -788,6 +825,7 @@ $.widget('ui.wcfImageViewer', { offset: this._images.length } }); + this._proxy.setOption('showLoadingOverlay', false); this._proxy.sendRequest(); }, diff --git a/wcfsetup/install/files/js/WCF.js b/wcfsetup/install/files/js/WCF.js index 0d989cfa8d..7eae22e64a 100755 --- a/wcfsetup/install/files/js/WCF.js +++ b/wcfsetup/install/files/js/WCF.js @@ -1732,6 +1732,12 @@ WCF.PeriodicalExecuter = Class.extend({ */ _callback: null, + /** + * interval + * @var integer + */ + _delay: 0, + /** * interval id * @var integer @@ -1757,7 +1763,8 @@ WCF.PeriodicalExecuter = Class.extend({ } this._callback = callback; - this._intervalID = setInterval($.proxy(this._execute, this), delay); + this._interval = delay; + this.resume(); }, /** @@ -1786,6 +1793,17 @@ WCF.PeriodicalExecuter = Class.extend({ } clearInterval(this._intervalID); + }, + + /** + * Resumes the interval-based callback execution. + */ + resume: function() { + if (this._intervalID) { + this.stop(); + } + + this._intervalID = setInterval($.proxy(this._execute, this), this._interval); } }); diff --git a/wcfsetup/install/files/style/imageViewer.less b/wcfsetup/install/files/style/imageViewer.less index 5f156ed8c4..eb2887c1a7 100644 --- a/wcfsetup/install/files/style/imageViewer.less +++ b/wcfsetup/install/files/style/imageViewer.less @@ -210,6 +210,18 @@ -webkit-transition: top .3s, bottom .3s, border-color .3s; + &.loading:before { + content: @spinner; + margin: -24px 0 0 -24px; + left: 50%; + position: absolute; + top: 50%; + + .icon; + .icon48; + .icon-spinner; + } + > img { opacity: 0; position: absolute; @@ -291,7 +303,7 @@ transition: bottom linear .3s; - &:hover > div > ul > li > a { + &:hover > div > ul > li > img { filter: none; -webkit-filter: none; } @@ -340,12 +352,15 @@ > li { display: inline-block; + height: 80px; opacity: .6; + position: relative; + width: 80px; transition: opacity linear .5s; &.active, - &.hover { + &:hover { opacity: 1; } @@ -353,22 +368,38 @@ margin-right: 10px; } - &.active > a { + &.active > img { filter: none; -webkit-filter: none; } - > a { - background-position: center; - background-repeat: no-repeat; - background-size: contain; - display: block; + &.loading{ + &:before { + content: @spinner; + margin: -16px 0 0 -16px; + left: 50%; + position: absolute; + top: 50%; + z-index: -1; + + .icon; + .icon32; + .icon-spinner; + } + + > img { + opacity: 0; + } + } + + > img { height: 80px; + opacity: 1; width: 80px; .grayscale; -webkit-filter: grayscale(100%); - -webkit-transition: filter,-webkit-filter .5s linear; + -webkit-transition: -webkit-filter .5s, opacity 1s; } } }