From fa7549e17a674798a0937a74830861a7d9ccb4a2 Mon Sep 17 00:00:00 2001 From: Alexander Ebert Date: Fri, 18 Jul 2014 12:07:43 +0200 Subject: [PATCH] Improved image viewer, now supports static images + mobile UI --- com.woltlab.wcf/templates/imageViewer.tpl | 11 +- wcfsetup/install/files/js/WCF.ImageViewer.js | 304 ++++++++++++++++-- wcfsetup/install/files/js/WCF.js | 15 + wcfsetup/install/files/style/imageViewer.less | 110 ++++++- 4 files changed, 410 insertions(+), 30 deletions(-) diff --git a/com.woltlab.wcf/templates/imageViewer.tpl b/com.woltlab.wcf/templates/imageViewer.tpl index a1b7c7d889..e1c372395d 100644 --- a/com.woltlab.wcf/templates/imageViewer.tpl +++ b/com.woltlab.wcf/templates/imageViewer.tpl @@ -1,5 +1,4 @@ {if !$__imageViewerLoaded|isset} - diff --git a/wcfsetup/install/files/js/WCF.ImageViewer.js b/wcfsetup/install/files/js/WCF.ImageViewer.js index 76b45f3aaa..06afcd1c31 100644 --- a/wcfsetup/install/files/js/WCF.ImageViewer.js +++ b/wcfsetup/install/files/js/WCF.ImageViewer.js @@ -108,6 +108,57 @@ WCF.ImageViewer = Class.extend({ } }); +/** + * Enhanced image viewer for WCF. + * + * @author Alexander Ebert + * @copyright 2001-2014 WoltLab GmbH + * @license GNU Lesser General Public License + */ +WCF.ImageViewer = Class.extend({ + /** + * trigger element to mimic a slideshow button + * @var jQuery + */ + _triggerElement: null, + + /** + * Initializes the WCF.ImageViewer class. + */ + init: function() { + this._triggerElement = $('').data('disableSlideshow', true).hide().appendTo(document.body); + this._triggerElement.wcfImageViewer({ + enableSlideshow: 0, + imageSelector: '.jsImageViewerEnabled', + staticViewer: true + }); + + this._rebuildImageViewer(); + }, + + /** + * Rebuilds the image viewer. + */ + _rebuildImageViewer: function() { + var $links = $('a.jsImageViewer'); + if ($links.length) { + $links.removeClass('jsImageViewer').addClass('jsImageViewerEnabled').click($.proxy(this._click, this)); + } + }, + + /** + * Handles click on an image with image viewer support. + * + * @param object event + */ + _click: function(event) { + event.preventDefault(); + event.stopPropagation(); + + this._triggerElement.wcfImageViewer('open', null, $(event.currentTarget).wcfIdentify()); + } +}); + /** * Provides a focused image viewer for WCF. * @@ -164,6 +215,12 @@ $.widget('ui.wcfImageViewer', { */ _images: [ ], + /** + * true if image viewer uses the mobile-optimized UI + * @var boolean + */ + _isMobile: false, + /** * true if image viewer is open * @var boolean @@ -260,7 +317,11 @@ $.widget('ui.wcfImageViewer', { speed: 5, // time in seconds // ajax - className: '' // must be an instance of \wcf\data\IImageViewerAction + className: '', // must be an instance of \wcf\data\IImageViewerAction + + // alternative mode - static view + imageSelector: '', + staticViewer: false }, /** @@ -274,6 +335,7 @@ $.widget('ui.wcfImageViewer', { this._disableSlideshow = (this.element.data('disableSlideshow')); this._eventNamespace = this.element.wcfIdentify(); this._images = [ ]; + this._isMobile = false; this._isOpen = false; this._items = -1; this._maxDimensions = { @@ -298,28 +360,50 @@ $.widget('ui.wcfImageViewer', { * Opens the image viewer. * * @param object event + * @param string targetImageElementID * @return boolean */ - open: function(event) { + open: function(event, targetImageElementID) { if (event) event.preventDefault(); if (this._isOpen) { return false; } - if (this._images.length === 0) { - this._loadNextImages(true); + if (this.options.staticViewer) { + var $images = this._getStaticImages(); + this._initUI(); + this._createThumbnails($images, true); + this._render(true, undefined, targetImageElementID); + + this._isOpen = true; + + WCF.System.DisableScrolling.disable(); + + // switch to fullscreen mode on smartphones + if ($.browser.touch) { + setTimeout($.proxy(function() { + if (this._isMobile && !this._container.hasClass('maximized')) { + this._toggleView(); + } + }, this), 500); + } } else { - this._render(false, this.element.data('targetImageID')); - - if (this._items > 1 && this._slideshowEnabled) { - this.startSlideshow(); + if (this._images.length === 0) { + this._loadNextImages(true); } + else { + this._render(false, this.element.data('targetImageID')); + + if (this._items > 1 && this._slideshowEnabled) { + this.startSlideshow(); + } + + this._isOpen = true; - this._isOpen = true; - - WCF.System.DisableScrolling.disable(); + WCF.System.DisableScrolling.disable(); + } } this._bindListener(); @@ -489,8 +573,9 @@ $.widget('ui.wcfImageViewer', { * * @param boolean initialized * @param integer targetImageID + * @param string targetImageElementID */ - _render: function(initialized, targetImageID) { + _render: function(initialized, targetImageID, targetImageElementID) { this._container.addClass('open'); var $thumbnail = null; @@ -500,7 +585,7 @@ $.widget('ui.wcfImageViewer', { this._thumbnailWidth = $thumbnail.outerWidth(true); this._thumbnailContainerWidth = this._ui.imageList.parent().innerWidth(); - if (this._items > 1 && this.options.enableSlideshow && !targetImageID) { + if (this._items > 1 && this.options.enableSlideshow && !targetImageID && !targetImageElementID) { this.startSlideshow(); } } @@ -516,6 +601,20 @@ $.widget('ui.wcfImageViewer', { } }, this)); } + else if (targetImageElementID !== null) { + var $i = 0; + $(this.options.imageSelector).each(function(index, element) { + if ($(element).wcfIdentify() == targetImageElementID) { + $i = index; + + return false; + } + }); + + var $item = this._ui.imageList.children('li:eq(' + $i + ')'); + $item.trigger('click'); + this.moveToImage($item.data('index')); + } else if ($thumbnail !== null) { $thumbnail.trigger('click'); } @@ -590,17 +689,21 @@ $.widget('ui.wcfImageViewer', { this._renderImage($newImageIndex, $image, $dimensions); // user - var $link = this._ui.header.find('> div > a').prop('href', $image.user.link).prop('title', $image.user.username); - $link.children('img').prop('src', $image.user.avatarURL); + if (!this.options.staticViewer) { + var $link = this._ui.header.find('> div > a').prop('href', $image.user.link).prop('title', $image.user.username); + $link.children('img').prop('src', $image.user.avatarURL); + } // meta data var $title = WCF.String.escapeHTML($image.image.title); if ($image.image.link) $title = '' + $image.image.title + ''; this._ui.header.find('> div > h1').html($title); - var $seriesTitle = ($image.series && $image.series.title ? WCF.String.escapeHTML($image.series.title) : ''); - if ($image.series.link) $seriesTitle = '' + $seriesTitle + ''; - this._ui.header.find('> div > h2').html($seriesTitle); + if (!this.options.staticViewer) { + var $seriesTitle = ($image.series && $image.series.title ? WCF.String.escapeHTML($image.series.title) : ''); + if ($image.series.link) $seriesTitle = '' + $seriesTitle + ''; + this._ui.header.find('> div > h2').html($seriesTitle); + } this._ui.header.find('> div > h3').text(WCF.Language.get('wcf.imageViewer.seriesIndex').replace(/{x}/, $image.listItem.data('index') + 1).replace(/{y}/, this._items)); @@ -628,6 +731,10 @@ $.widget('ui.wcfImageViewer', { this._ui.imageContainer.removeClass('loading'); this._ui.images[activeImageIndex].addClass('active'); + if (this.options.staticViewer) { + this._renderImage(activeImageIndex, null); + } + this.startSlideshow(); }, @@ -644,7 +751,7 @@ $.widget('ui.wcfImageViewer', { imageData = this._images[this._active]; containerDimensions = { - height: $(window).height() - (this._container.hasClass('maximized') ? 0 : 200), + height: $(window).height() - (this._container.hasClass('maximized') || this._container.hasClass('wcfImageViewerMobile') ? 0 : 200), width: this._ui.imageContainer.innerWidth() }; } @@ -653,7 +760,15 @@ $.widget('ui.wcfImageViewer', { containerDimensions.height -= 22; containerDimensions.width -= 20; - this._ui.images[targetIndex].prop('src', imageData.image.url); + var $image = this._ui.images[targetIndex].prop('src', imageData.image.url); + + if (this.options.staticViewer && !imageData.height && $image.get(0).complete) { + var $img = new Image(); + $img.src = imageData.image.url; + + imageData.image.height = $img.height; + imageData.image.width = $img.width; + } var $height = imageData.image.height; var $width = imageData.image.width; @@ -695,7 +810,7 @@ $.widget('ui.wcfImageViewer', { this._didInit = true; - this._container = $('
').appendTo(document.body); + this._container = $('
').appendTo(document.body); var $imageContainer = $('
').appendTo(this._container); var $imageList = $('
    ').appendTo(this._container); var $slideshowContainer = $('
      ').appendTo($imageContainer); @@ -708,7 +823,7 @@ $.widget('ui.wcfImageViewer', { this._ui = { buttonNext: $imageList.children('span.wcfImageViewerButtonNext'), buttonPrevious: $imageList.children('span.wcfImageViewerButtonPrevious'), - header: $('

      ').appendTo(this._container), + header: $('
      ' : ' class="box64">' ) + '

    ').appendTo(this._container), imageContainer: $imageContainer, images: [ $imageContainer.children('img:eq(0)').on('webkitTransitionEnd transitionend msTransitionEnd oTransitionEnd', function() { $(this).removeClass('animateTransformation'); }), @@ -745,9 +860,58 @@ $.widget('ui.wcfImageViewer', { // close button $('').appendTo(this._ui.header).click($.proxy(this.close, this)); + WCF.DOMNodeInsertedHandler.execute(); + + enquire.register('screen and (max-width: 800px)', { + match: $.proxy(this._enableMobileView, this), + unmatch: $.proxy(this._disableMobileView, this) + }); + return true; }, + /** + * Enables the mobile-optimized UI. + */ + _enableMobileView: function() { + this._container.addClass('wcfImageViewerMobile'); + + var self = this; + this._ui.imageContainer.swipe({ + swipeLeft: function(event) { + if (self._container.hasClass('maximized')) { + self._nextImage(event); + } + }, + swipeRight: function(event) { + if (self._container.hasClass('maximized')) { + self._previousImage(event); + } + }, + tap: function(event, element) { + // tap fires before click, prevent conflicts + switch (element.tagName) { + case 'DIV': + case 'IMG': + self._toggleView(); + break; + } + } + }); + + this._isMobile = true; + }, + + /** + * Disables the mobile-optimized UI. + */ + _disableMobileView: function() { + this._container.removeClass('wcfImageViewerMobile'); + this._ui.imageContainer.swipe('destroy'); + + this._isMobile = false; + }, + /** * Toggles between normal and fullscreen view. */ @@ -811,6 +975,11 @@ $.widget('ui.wcfImageViewer', { this.stopSlideshow(true); this.showImage(this._active + 1); + + if (event) { + event.preventDefault(); + event.stopPropagation(); + } } }, @@ -825,6 +994,11 @@ $.widget('ui.wcfImageViewer', { this.stopSlideshow(true); this.showImage(this._active - 1); + + if (event) { + event.preventDefault(); + event.stopPropagation(); + } } }, @@ -916,6 +1090,11 @@ $.widget('ui.wcfImageViewer', { * @param array images */ _createThumbnails: function(images) { + if (this.options.staticViewer) { + this._images = [ ]; + this._ui.imageList.empty(); + } + for (var $i = 0, $length = images.length; $i < $length; $i++) { var $image = images[$i]; @@ -925,9 +1104,22 @@ $.widget('ui.wcfImageViewer', { if ($img.get(0).complete) { // thumbnail is read from cache $listItem.removeClass('loading'); + + // fix dimensions + if (this.options.staticViewer) { + this._fixThumbnailDimensions($img); + } } else { - $img.on('load', function() { $(this).parent().removeClass('loading'); }); + var self = this; + $img.on('load', function() { + var $img = $(this); + $img.parent().removeClass('loading'); + + if (self.options.staticViewer) { + self._fixThumbnailDimensions($img); + } + }); } $image.listItem = $listItem; @@ -935,6 +1127,41 @@ $.widget('ui.wcfImageViewer', { } }, + /** + * Fixes thumbnail dimensions within static mode. + * + * @param jQuery image + */ + _fixThumbnailDimensions: function(image) { + var $image = new Image(); + $image.src = image.prop('src'); + + var $height = $image.height; + var $width = $image.width; + + // quadratic, scale to 80x80 + if ($height == $width) { + $height = $width = 80; + } + else if ($height < $width) { + // landscape, use width as reference + var $scale = 80 / $width; + $width = 80; + $height *= $scale; + } + else { + // portrait, use height as reference + var $scale = 80 / $height; + $height = 80; + $width *= $scale; + } + + image.css({ + height: $height + 'px', + width: $width + 'px' + }); + }, + /** * Loads the next images via AJAX. * @@ -957,6 +1184,37 @@ $.widget('ui.wcfImageViewer', { this._proxy.sendRequest(); }, + /** + * Builds the list of static images and returns it. + * + * @return array + */ + _getStaticImages: function() { + var $images = [ ]; + + $(this.options.imageSelector).each(function(index, link) { + var $link = $(link); + + $images.push({ + image: { + fullURL: $link.prop('href'), + link: '', + title: $link.prop('title'), + url: $link.prop('href'), + }, + series: null, + thumbnail: { + url: $link.children('img').prop('src') + }, + user: null + }); + }); + + this._items = $images.length; + + return $images; + }, + /** * Handles successful AJAX requests. * diff --git a/wcfsetup/install/files/js/WCF.js b/wcfsetup/install/files/js/WCF.js index caaa4dfbb5..75c657c083 100755 --- a/wcfsetup/install/files/js/WCF.js +++ b/wcfsetup/install/files/js/WCF.js @@ -106,6 +106,21 @@ window.matchMedia||(window.matchMedia=function(){"use strict";var e=window.style */ !function(){var e=function(e){"use strict";function t(e){if(e.paused||e.ended||w)return!1;try{f.clearRect(0,0,h,s),f.drawImage(e,0,0,h,s)}catch(o){}p=setTimeout(t,k.duration,e),R.setIcon(c)}function o(e){var t=/^#?([a-f\d])([a-f\d])([a-f\d])$/i;e=e.replace(t,function(e,t,o,n){return t+t+o+o+n+n});var o=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);return o?{r:parseInt(o[1],16),g:parseInt(o[2],16),b:parseInt(o[3],16)}:!1}function n(e,t){var o,n={};for(o in e)n[o]=e[o];for(o in t)n[o]=t[o];return n}function i(){return document.hidden||document.msHidden||document.webkitHidden||document.mozHidden}e=e?e:{};var r,a,s,h,c,f,l,d,u,y,g,w,m,x,p,b={bgColor:"#d00",textColor:"#fff",fontFamily:"sans-serif",fontStyle:"bold",type:"circle",position:"down",animation:"slide",elementId:!1};m={},m.ff=/firefox/i.test(navigator.userAgent.toLowerCase()),m.chrome=/chrome/i.test(navigator.userAgent.toLowerCase()),m.opera=/opera/i.test(navigator.userAgent.toLowerCase()),m.ie=/msie/i.test(navigator.userAgent.toLowerCase())||/trident/i.test(navigator.userAgent.toLowerCase()),m.supported=m.chrome||m.ff||m.opera;var v=[];g=function(){},d=w=!1;var C=function(){r=n(b,e),r.bgColor=o(r.bgColor),r.textColor=o(r.textColor),r.position=r.position.toLowerCase(),r.animation=k.types[""+r.animation]?r.animation:b.animation;var t=r.position.indexOf("up")>-1,i=r.position.indexOf("left")>-1;if(t||i)for(var d=0;d0?l.height:32,h=l.width>0?l.width:32,c.height=s,c.width=h,f=c.getContext("2d"),M.ready()}):(l.setAttribute("src",""),s=32,h=32,l.height=s,l.width=h,c.height=s,c.width=h,f=c.getContext("2d"),M.ready())}catch(y){throw"Error initializing favico. Message: "+y.message}},M={};M.ready=function(){d=!0,M.reset(),g()},M.reset=function(){d&&(v=[],u=!1,f.clearRect(0,0,h,s),f.drawImage(l,0,0,h,s),R.setIcon(c),window.clearTimeout(x),window.clearTimeout(p))},M.start=function(){if(d&&!y){var e=function(){u=v[0],y=!1,v.length>0&&(v.shift(),M.start())};if(v.length>0){y=!0;var t=function(){["type","animation","bgColor","textColor","fontFamily","fontStyle"].forEach(function(e){e in v[0].options&&(r[e]=v[0].options[e])}),k.run(v[0].options,function(){e()},!1)};u?k.run(u.options,function(){t()},!0):t()}}};var I={},A=function(e){return e.n="number"==typeof e.n?Math.abs(0|e.n):e.n,e.x=h*e.x,e.y=s*e.y,e.w=h*e.w,e.h=s*e.h,e.len=(""+e.n).length,e};I.circle=function(e){e=A(e);var t=!1;2===e.len?(e.x=e.x-.4*e.w,e.w=1.4*e.w,t=!0):e.len>=3&&(e.x=e.x-.65*e.w,e.w=1.65*e.w,t=!0),f.clearRect(0,0,h,s),f.drawImage(l,0,0,h,s),f.beginPath(),f.font=r.fontStyle+" "+Math.floor(e.h*(e.n>99?.85:1))+"px "+r.fontFamily,f.textAlign="center",t?(f.moveTo(e.x+e.w/2,e.y),f.lineTo(e.x+e.w-e.h/2,e.y),f.quadraticCurveTo(e.x+e.w,e.y,e.x+e.w,e.y+e.h/2),f.lineTo(e.x+e.w,e.y+e.h-e.h/2),f.quadraticCurveTo(e.x+e.w,e.y+e.h,e.x+e.w-e.h/2,e.y+e.h),f.lineTo(e.x+e.h/2,e.y+e.h),f.quadraticCurveTo(e.x,e.y+e.h,e.x,e.y+e.h-e.h/2),f.lineTo(e.x,e.y+e.h/2),f.quadraticCurveTo(e.x,e.y,e.x+e.h/2,e.y)):f.arc(e.x+e.w/2,e.y+e.h/2,e.h/2,0,2*Math.PI),f.fillStyle="rgba("+r.bgColor.r+","+r.bgColor.g+","+r.bgColor.b+","+e.o+")",f.fill(),f.closePath(),f.beginPath(),f.stroke(),f.fillStyle="rgba("+r.textColor.r+","+r.textColor.g+","+r.textColor.b+","+e.o+")","number"==typeof e.n&&e.n>999?f.fillText((e.n>9999?9:Math.floor(e.n/1e3))+"k+",Math.floor(e.x+e.w/2),Math.floor(e.y+e.h-.2*e.h)):f.fillText(e.n,Math.floor(e.x+e.w/2),Math.floor(e.y+e.h-.15*e.h)),f.closePath()},I.rectangle=function(e){e=A(e);var t=!1;2===e.len?(e.x=e.x-.4*e.w,e.w=1.4*e.w,t=!0):e.len>=3&&(e.x=e.x-.65*e.w,e.w=1.65*e.w,t=!0),f.clearRect(0,0,h,s),f.drawImage(l,0,0,h,s),f.beginPath(),f.font="bold "+Math.floor(e.h*(e.n>99?.9:1))+"px sans-serif",f.textAlign="center",f.fillStyle="rgba("+r.bgColor.r+","+r.bgColor.g+","+r.bgColor.b+","+e.o+")",f.fillRect(e.x,e.y,e.w,e.h),f.fillStyle="rgba("+r.textColor.r+","+r.textColor.g+","+r.textColor.b+","+e.o+")","number"==typeof e.n&&e.len>3?f.fillText((e.n>9999?9:Math.floor(e.n/1e3))+"k+",Math.floor(e.x+e.w/2),Math.floor(e.y+e.h-.2*e.h)):f.fillText(e.n,Math.floor(e.x+e.w/2),Math.floor(e.y+e.h-.15*e.h)),f.closePath()};var E=function(e,t){t=("string"==typeof t?{animation:t}:t)||{},g=function(){try{if("number"==typeof e?e>0:""!==e){var n={type:"badge",options:{n:e}};if("animation"in t&&k.types[""+t.animation]&&(n.options.animation=""+t.animation),"type"in t&&I[""+t.type]&&(n.options.type=""+t.type),["bgColor","textColor"].forEach(function(e){e in t&&(n.options[e]=o(t[e]))}),["fontStyle","fontFamily"].forEach(function(e){e in t&&(n.options[e]=t[e])}),v.push(n),v.length>100)throw"Too many badges requests in queue.";M.start()}else M.reset()}catch(i){throw"Error setting badge. Message: "+i.message}},d&&g()},T=function(e){g=function(){try{var t=e.width,o=e.height,n=document.createElement("img"),i=o/s>t/h?t/h:o/s;n.setAttribute("src",e.getAttribute("src")),n.height=o/i,n.width=t/i,f.clearRect(0,0,h,s),f.drawImage(n,0,0,h,s),R.setIcon(c)}catch(r){throw"Error setting image. Message: "+r.message}},d&&g()},L=function(e){g=function(){try{if("stop"===e)return w=!0,M.reset(),void(w=!1);e.addEventListener("play",function(){t(this)},!1)}catch(o){throw"Error setting video. Message: "+o.message}},d&&g()},U=function(e){if(window.URL&&window.URL.createObjectURL||(window.URL=window.URL||{},window.URL.createObjectURL=function(e){return e}),m.supported){var o=!1;navigator.getUserMedia=navigator.getUserMedia||navigator.oGetUserMedia||navigator.msGetUserMedia||navigator.mozGetUserMedia||navigator.webkitGetUserMedia,g=function(){try{if("stop"===e)return w=!0,M.reset(),void(w=!1);o=document.createElement("video"),o.width=h,o.height=s,navigator.getUserMedia({video:!0,audio:!1},function(e){o.src=URL.createObjectURL(e),o.play(),t(o)},function(){})}catch(n){throw"Error setting webcam. Message: "+n.message}},d&&g()}},R={};R.getIcon=function(){var e=!1,t="",o=function(){for(var e=document.getElementsByTagName("head")[0].getElementsByTagName("link"),t=e.length,o=t-1;o>=0;o--)if(/(^|\s)icon(\s|$)/i.test(e[o].getAttribute("rel")))return e[o];return!1};if(r.elementId?(e=document.getElementById(r.elementId),e.setAttribute("href",e.getAttribute("src"))):(e=o(),e===!1&&(e=document.createElement("link"),e.setAttribute("rel","icon"),document.getElementsByTagName("head")[0].appendChild(e))),t=r.elementId?e.src:e.href,-1===t.indexOf(document.location.hostname))throw new Error("Error setting favicon. Favicon image is on different domain (Icon: "+t+", Domain: "+document.location.hostname+")");return e.setAttribute("type","image/png"),e},R.setIcon=function(e){var t=e.toDataURL("image/png");if(r.elementId)document.getElementById(r.elementId).setAttribute("src",t);else if(m.ff||m.opera){var o=a;a=document.createElement("link"),m.opera&&a.setAttribute("rel","icon"),a.setAttribute("rel","icon"),a.setAttribute("type","image/png"),document.getElementsByTagName("head")[0].appendChild(a),a.setAttribute("href",t),o.parentNode&&o.parentNode.removeChild(o)}else a.setAttribute("href",t)};var k={};return k.duration=40,k.types={},k.types.fade=[{x:.4,y:.4,w:.6,h:.6,o:0},{x:.4,y:.4,w:.6,h:.6,o:.1},{x:.4,y:.4,w:.6,h:.6,o:.2},{x:.4,y:.4,w:.6,h:.6,o:.3},{x:.4,y:.4,w:.6,h:.6,o:.4},{x:.4,y:.4,w:.6,h:.6,o:.5},{x:.4,y:.4,w:.6,h:.6,o:.6},{x:.4,y:.4,w:.6,h:.6,o:.7},{x:.4,y:.4,w:.6,h:.6,o:.8},{x:.4,y:.4,w:.6,h:.6,o:.9},{x:.4,y:.4,w:.6,h:.6,o:1}],k.types.none=[{x:.4,y:.4,w:.6,h:.6,o:1}],k.types.pop=[{x:1,y:1,w:0,h:0,o:1},{x:.9,y:.9,w:.1,h:.1,o:1},{x:.8,y:.8,w:.2,h:.2,o:1},{x:.7,y:.7,w:.3,h:.3,o:1},{x:.6,y:.6,w:.4,h:.4,o:1},{x:.5,y:.5,w:.5,h:.5,o:1},{x:.4,y:.4,w:.6,h:.6,o:1}],k.types.popFade=[{x:.75,y:.75,w:0,h:0,o:0},{x:.65,y:.65,w:.1,h:.1,o:.2},{x:.6,y:.6,w:.2,h:.2,o:.4},{x:.55,y:.55,w:.3,h:.3,o:.6},{x:.5,y:.5,w:.4,h:.4,o:.8},{x:.45,y:.45,w:.5,h:.5,o:.9},{x:.4,y:.4,w:.6,h:.6,o:1}],k.types.slide=[{x:.4,y:1,w:.6,h:.6,o:1},{x:.4,y:.9,w:.6,h:.6,o:1},{x:.4,y:.9,w:.6,h:.6,o:1},{x:.4,y:.8,w:.6,h:.6,o:1},{x:.4,y:.7,w:.6,h:.6,o:1},{x:.4,y:.6,w:.6,h:.6,o:1},{x:.4,y:.5,w:.6,h:.6,o:1},{x:.4,y:.4,w:.6,h:.6,o:1}],k.run=function(e,t,o,a){var s=k.types[i()?"none":r.animation];return a=o===!0?"undefined"!=typeof a?a:s.length-1:"undefined"!=typeof a?a:0,t=t?t:function(){},a=0?(I[r.type](n(e,s[a])),x=setTimeout(function(){o?a-=1:a+=1,k.run(e,t,o,a)},k.duration),R.setIcon(c),void 0):void t()},C(),{badge:E,video:L,image:T,webcam:U,reset:M.reset}};"undefined"!=typeof define&&define.amd?define([],function(){return e}):"undefined"!=typeof module&&module.exports?module.exports=e:this.Favico=e}(); +/* +* @fileOverview TouchSwipe - jQuery Plugin +* @version 1.6.6 +* +* @author Matt Bryson http://www.github.com/mattbryson +* @see https://github.com/mattbryson/TouchSwipe-Jquery-Plugin +* @see http://labs.skinkers.com/touchSwipe/ +* @see http://plugins.jquery.com/project/touchSwipe +* +* Copyright (c) 2010 Matt Bryson +* Dual licensed under the MIT or GPL Version 2 licenses. +* +*/ +(function(a){if(typeof define==="function"&&define.amd&&define.amd.jQuery){define(["jquery"],a)}else{a(jQuery)}}(function(f){var p="left",o="right",e="up",x="down",c="in",z="out",m="none",s="auto",l="swipe",t="pinch",A="tap",j="doubletap",b="longtap",y="hold",D="horizontal",u="vertical",i="all",r=10,g="start",k="move",h="end",q="cancel",a="ontouchstart" in window,v=window.navigator.msPointerEnabled&&!window.navigator.pointerEnabled,d=window.navigator.pointerEnabled||window.navigator.msPointerEnabled,B="TouchSwipe";var n={fingers:1,threshold:75,cancelThreshold:null,pinchThreshold:20,maxTimeThreshold:null,fingerReleaseThreshold:250,longTapThreshold:500,doubleTapThreshold:200,swipe:null,swipeLeft:null,swipeRight:null,swipeUp:null,swipeDown:null,swipeStatus:null,pinchIn:null,pinchOut:null,pinchStatus:null,click:null,tap:null,doubleTap:null,longTap:null,hold:null,triggerOnTouchEnd:true,triggerOnTouchLeave:false,allowPageScroll:"auto",fallbackToMouseEvents:true,excludedElements:"label, button, input, select, textarea, a, .noSwipe"};f.fn.swipe=function(G){var F=f(this),E=F.data(B);if(E&&typeof G==="string"){if(E[G]){return E[G].apply(this,Array.prototype.slice.call(arguments,1))}else{f.error("Method "+G+" does not exist on jQuery.swipe")}}else{if(!E&&(typeof G==="object"||!G)){return w.apply(this,arguments)}}return F};f.fn.swipe.defaults=n;f.fn.swipe.phases={PHASE_START:g,PHASE_MOVE:k,PHASE_END:h,PHASE_CANCEL:q};f.fn.swipe.directions={LEFT:p,RIGHT:o,UP:e,DOWN:x,IN:c,OUT:z};f.fn.swipe.pageScroll={NONE:m,HORIZONTAL:D,VERTICAL:u,AUTO:s};f.fn.swipe.fingers={ONE:1,TWO:2,THREE:3,ALL:i};function w(E){if(E&&(E.allowPageScroll===undefined&&(E.swipe!==undefined||E.swipeStatus!==undefined))){E.allowPageScroll=m}if(E.click!==undefined&&E.tap===undefined){E.tap=E.click}if(!E){E={}}E=f.extend({},f.fn.swipe.defaults,E);return this.each(function(){var G=f(this);var F=G.data(B);if(!F){F=new C(this,E);G.data(B,F)}})}function C(a4,av){var az=(a||d||!av.fallbackToMouseEvents),J=az?(d?(v?"MSPointerDown":"pointerdown"):"touchstart"):"mousedown",ay=az?(d?(v?"MSPointerMove":"pointermove"):"touchmove"):"mousemove",U=az?(d?(v?"MSPointerUp":"pointerup"):"touchend"):"mouseup",S=az?null:"mouseleave",aD=(d?(v?"MSPointerCancel":"pointercancel"):"touchcancel");var ag=0,aP=null,ab=0,a1=0,aZ=0,G=1,aq=0,aJ=0,M=null;var aR=f(a4);var Z="start";var W=0;var aQ=null;var T=0,a2=0,a5=0,ad=0,N=0;var aW=null,af=null;try{aR.bind(J,aN);aR.bind(aD,a9)}catch(ak){f.error("events not supported "+J+","+aD+" on jQuery.swipe")}this.enable=function(){aR.bind(J,aN);aR.bind(aD,a9);return aR};this.disable=function(){aK();return aR};this.destroy=function(){aK();aR.data(B,null);return aR};this.option=function(bc,bb){if(av[bc]!==undefined){if(bb===undefined){return av[bc]}else{av[bc]=bb}}else{f.error("Option "+bc+" does not exist on jQuery.swipe.options")}return null};function aN(bd){if(aB()){return}if(f(bd.target).closest(av.excludedElements,aR).length>0){return}var be=bd.originalEvent?bd.originalEvent:bd;var bc,bb=a?be.touches[0]:be;Z=g;if(a){W=be.touches.length}else{bd.preventDefault()}ag=0;aP=null;aJ=null;ab=0;a1=0;aZ=0;G=1;aq=0;aQ=aj();M=aa();R();if(!a||(W===av.fingers||av.fingers===i)||aX()){ai(0,bb);T=at();if(W==2){ai(1,be.touches[1]);a1=aZ=au(aQ[0].start,aQ[1].start)}if(av.swipeStatus||av.pinchStatus){bc=O(be,Z)}}else{bc=false}if(bc===false){Z=q;O(be,Z);return bc}else{if(av.hold){af=setTimeout(f.proxy(function(){aR.trigger("hold",[be.target]);if(av.hold){bc=av.hold.call(aR,be,be.target)}},this),av.longTapThreshold)}ao(true)}return null}function a3(be){var bh=be.originalEvent?be.originalEvent:be;if(Z===h||Z===q||am()){return}var bd,bc=a?bh.touches[0]:bh;var bf=aH(bc);a2=at();if(a){W=bh.touches.length}if(av.hold){clearTimeout(af)}Z=k;if(W==2){if(a1==0){ai(1,bh.touches[1]);a1=aZ=au(aQ[0].start,aQ[1].start)}else{aH(bh.touches[1]);aZ=au(aQ[0].end,aQ[1].end);aJ=ar(aQ[0].end,aQ[1].end)}G=a7(a1,aZ);aq=Math.abs(a1-aZ)}if((W===av.fingers||av.fingers===i)||!a||aX()){aP=aL(bf.start,bf.end);al(be,aP);ag=aS(bf.start,bf.end);ab=aM();aI(aP,ag);if(av.swipeStatus||av.pinchStatus){bd=O(bh,Z)}if(!av.triggerOnTouchEnd||av.triggerOnTouchLeave){var bb=true;if(av.triggerOnTouchLeave){var bg=aY(this);bb=E(bf.end,bg)}if(!av.triggerOnTouchEnd&&bb){Z=aC(k)}else{if(av.triggerOnTouchLeave&&!bb){Z=aC(h)}}if(Z==q||Z==h){O(bh,Z)}}}else{Z=q;O(bh,Z)}if(bd===false){Z=q;O(bh,Z)}}function L(bb){var bc=bb.originalEvent;if(a){if(bc.touches.length>0){F();return true}}if(am()){W=ad}a2=at();ab=aM();if(ba()||!an()){Z=q;O(bc,Z)}else{if(av.triggerOnTouchEnd||(av.triggerOnTouchEnd==false&&Z===k)){bb.preventDefault();Z=h;O(bc,Z)}else{if(!av.triggerOnTouchEnd&&a6()){Z=h;aF(bc,Z,A)}else{if(Z===k){Z=q;O(bc,Z)}}}}ao(false);return null}function a9(){W=0;a2=0;T=0;a1=0;aZ=0;G=1;R();ao(false)}function K(bb){var bc=bb.originalEvent;if(av.triggerOnTouchLeave){Z=aC(h);O(bc,Z)}}function aK(){aR.unbind(J,aN);aR.unbind(aD,a9);aR.unbind(ay,a3);aR.unbind(U,L);if(S){aR.unbind(S,K)}ao(false)}function aC(bf){var be=bf;var bd=aA();var bc=an();var bb=ba();if(!bd||bb){be=q}else{if(bc&&bf==k&&(!av.triggerOnTouchEnd||av.triggerOnTouchLeave)){be=h}else{if(!bc&&bf==h&&av.triggerOnTouchLeave){be=q}}}return be}function O(bd,bb){var bc=undefined;if(I()||V()){bc=aF(bd,bb,l)}else{if((P()||aX())&&bc!==false){bc=aF(bd,bb,t)}}if(aG()&&bc!==false){bc=aF(bd,bb,j)}else{if(ap()&&bc!==false){bc=aF(bd,bb,b)}else{if(ah()&&bc!==false){bc=aF(bd,bb,A)}}}if(bb===q){a9(bd)}if(bb===h){if(a){if(bd.touches.length==0){a9(bd)}}else{a9(bd)}}return bc}function aF(be,bb,bd){var bc=undefined;if(bd==l){aR.trigger("swipeStatus",[bb,aP||null,ag||0,ab||0,W,aQ]);if(av.swipeStatus){bc=av.swipeStatus.call(aR,be,bb,aP||null,ag||0,ab||0,W,aQ);if(bc===false){return false}}if(bb==h&&aV()){aR.trigger("swipe",[aP,ag,ab,W,aQ]);if(av.swipe){bc=av.swipe.call(aR,be,aP,ag,ab,W,aQ);if(bc===false){return false}}switch(aP){case p:aR.trigger("swipeLeft",[aP,ag,ab,W,aQ]);if(av.swipeLeft){bc=av.swipeLeft.call(aR,be,aP,ag,ab,W,aQ)}break;case o:aR.trigger("swipeRight",[aP,ag,ab,W,aQ]);if(av.swipeRight){bc=av.swipeRight.call(aR,be,aP,ag,ab,W,aQ)}break;case e:aR.trigger("swipeUp",[aP,ag,ab,W,aQ]);if(av.swipeUp){bc=av.swipeUp.call(aR,be,aP,ag,ab,W,aQ)}break;case x:aR.trigger("swipeDown",[aP,ag,ab,W,aQ]);if(av.swipeDown){bc=av.swipeDown.call(aR,be,aP,ag,ab,W,aQ)}break}}}if(bd==t){aR.trigger("pinchStatus",[bb,aJ||null,aq||0,ab||0,W,G,aQ]);if(av.pinchStatus){bc=av.pinchStatus.call(aR,be,bb,aJ||null,aq||0,ab||0,W,G,aQ);if(bc===false){return false}}if(bb==h&&a8()){switch(aJ){case c:aR.trigger("pinchIn",[aJ||null,aq||0,ab||0,W,G,aQ]);if(av.pinchIn){bc=av.pinchIn.call(aR,be,aJ||null,aq||0,ab||0,W,G,aQ)}break;case z:aR.trigger("pinchOut",[aJ||null,aq||0,ab||0,W,G,aQ]);if(av.pinchOut){bc=av.pinchOut.call(aR,be,aJ||null,aq||0,ab||0,W,G,aQ)}break}}}if(bd==A){if(bb===q||bb===h){clearTimeout(aW);clearTimeout(af);if(Y()&&!H()){N=at();aW=setTimeout(f.proxy(function(){N=null;aR.trigger("tap",[be.target]);if(av.tap){bc=av.tap.call(aR,be,be.target)}},this),av.doubleTapThreshold)}else{N=null;aR.trigger("tap",[be.target]);if(av.tap){bc=av.tap.call(aR,be,be.target)}}}}else{if(bd==j){if(bb===q||bb===h){clearTimeout(aW);N=null;aR.trigger("doubletap",[be.target]);if(av.doubleTap){bc=av.doubleTap.call(aR,be,be.target)}}}else{if(bd==b){if(bb===q||bb===h){clearTimeout(aW);N=null;aR.trigger("longtap",[be.target]);if(av.longTap){bc=av.longTap.call(aR,be,be.target)}}}}}return bc}function an(){var bb=true;if(av.threshold!==null){bb=ag>=av.threshold}return bb}function ba(){var bb=false;if(av.cancelThreshold!==null&&aP!==null){bb=(aT(aP)-ag)>=av.cancelThreshold}return bb}function ae(){if(av.pinchThreshold!==null){return aq>=av.pinchThreshold}return true}function aA(){var bb;if(av.maxTimeThreshold){if(ab>=av.maxTimeThreshold){bb=false}else{bb=true}}else{bb=true}return bb}function al(bb,bc){if(av.allowPageScroll===m||aX()){bb.preventDefault()}else{var bd=av.allowPageScroll===s;switch(bc){case p:if((av.swipeLeft&&bd)||(!bd&&av.allowPageScroll!=D)){bb.preventDefault()}break;case o:if((av.swipeRight&&bd)||(!bd&&av.allowPageScroll!=D)){bb.preventDefault()}break;case e:if((av.swipeUp&&bd)||(!bd&&av.allowPageScroll!=u)){bb.preventDefault()}break;case x:if((av.swipeDown&&bd)||(!bd&&av.allowPageScroll!=u)){bb.preventDefault()}break}}}function a8(){var bc=aO();var bb=X();var bd=ae();return bc&&bb&&bd}function aX(){return !!(av.pinchStatus||av.pinchIn||av.pinchOut)}function P(){return !!(a8()&&aX())}function aV(){var be=aA();var bg=an();var bd=aO();var bb=X();var bc=ba();var bf=!bc&&bb&&bd&&bg&&be;return bf}function V(){return !!(av.swipe||av.swipeStatus||av.swipeLeft||av.swipeRight||av.swipeUp||av.swipeDown)}function I(){return !!(aV()&&V())}function aO(){return((W===av.fingers||av.fingers===i)||!a)}function X(){return aQ[0].end.x!==0}function a6(){return !!(av.tap)}function Y(){return !!(av.doubleTap)}function aU(){return !!(av.longTap)}function Q(){if(N==null){return false}var bb=at();return(Y()&&((bb-N)<=av.doubleTapThreshold))}function H(){return Q()}function ax(){return((W===1||!a)&&(isNaN(ag)||agav.longTapThreshold)&&(ag=0)){return p}else{if((bd<=360)&&(bd>=315)){return p}else{if((bd>=135)&&(bd<=225)){return o}else{if((bd>45)&&(bd<135)){return x}else{return e}}}}}function at(){var bb=new Date();return bb.getTime()}function aY(bb){bb=f(bb);var bd=bb.offset();var bc={left:bd.left,right:bd.left+bb.outerWidth(),top:bd.top,bottom:bd.top+bb.outerHeight()};return bc}function E(bb,bc){return(bb.x>bc.left&&bb.xbc.top&&bb.y header { top: -100px; } @@ -152,6 +152,98 @@ } } + &.wcfImageViewerStatic > header > div { + > h1, + > h2, + > h3 { + margin-left: 0 !important; + } + } + + &.wcfImageViewerMobile { + > header, + > footer { + background-color: rgba(0, 0, 0, 1); + opacity: 1; + position: absolute; + visibility: visible; + z-index: 402; + } + + &.maximized { + > header, + > footer { + opacity: 0; + visibility: hidden; + + transition: visibility 0s linear .5s, opacity .5s linear; + } + + > div > ul > li.pointer { + opacity: 0; + } + } + + > div { + bottom: 0; + top: 0; + + > ul { + > li { + background-color: rgba(224, 224, 224, 1); + border-radius: 30px; + margin-top: -24px; + opacity: 0; + position: absolute; + top: 50%; + + .transition(opacity, .3s); + + &.pointer { + opacity: 1; + } + + &.wcfImageViewerSlideshowButtonPrevious { + left: 10px; + + > span { + left: -3px; + position: relative; + top: 2px; + } + } + + &.wcfImageViewerSlideshowButtonNext { + right: 10px; + + > span { + position: relative; + right: -1px; + top: 2px; + } + } + + &.wcfImageViewerSlideshowButtonToggle, + &.wcfImageViewerSlideshowButtonEnlarge, + &.wcfImageViewerSlideshowButtonFull { + display: none; + } + } + } + } + + > footer { + > .wcfImageViewerButtonPrevious, + > .wcfImageViewerButtonNext { + display: none; + } + + > div { + margin: 0; + } + } + } + > header, > div, > footer { @@ -168,8 +260,6 @@ padding: 1rem; top: 0; - .transition(top, .3s); - > div { > h1, > h2, @@ -267,8 +357,18 @@ opacity: 1; } } + } + + &:not(.wcfImageViewerMobile) { + > header { + .transition(top, .3s); + } + + > footer { + .transition(bottom, .3s); + } - > ul { + > div > ul { background-color: rgba(0, 0, 0, 1); border: 1px solid @wcfImageViewerBorderColor; border-bottom-width: 0; @@ -331,8 +431,6 @@ height: 100px; padding: 10px; - .transition(bottom, .3s); - &:hover > div > ul > li > img { filter: none; -webkit-filter: none; -- 2.20.1