diff --git a/src/classes/BoardItem.php b/src/classes/BoardItem.php index 1366806..52c3392 100644 --- a/src/classes/BoardItem.php +++ b/src/classes/BoardItem.php @@ -81,7 +81,7 @@ public function toHTML(){ echo "
"; echo ""; - echo "\"\""; + echo "\"\""; echo "\n"; echo "
\n"; diff --git a/src/classes/Image.php b/src/classes/Image.php index d656cfa..33ee989 100644 --- a/src/classes/Image.php +++ b/src/classes/Image.php @@ -111,7 +111,7 @@ public function toHTML(){ echo " background: black url(\"?t=".$this->t."&f=$this->fileweb\") no-repeat center center;"; echo " background-size: contain;"; echo " -moz-background-size: contain;"; - echo " height:100%;"; + echo " height:100%; display: none;"; echo "';>"; echo ""; diff --git a/src/classes/ImageBar.php b/src/classes/ImageBar.php index 1da69c2..41028b6 100644 --- a/src/classes/ImageBar.php +++ b/src/classes/ImageBar.php @@ -71,10 +71,10 @@ public function __construct($fs=false){ $this->buttons['back'] = "?f=".urlencode(File::a2r(dirname(CurrentUser::$path))); $this->awesome['back'] = ""; - if(!Settings::$nodownload){ - $this->buttons['img'] = "?t=Big&f=".$file; - $this->awesome['img'] = ""; + $this->buttons['img'] = "?f=".$file; + $this->awesome['img'] = ""; + if(!Settings::$nodownload){ $this->buttons['get'] = "?t=BDl&f=".$file; $this->awesome['get'] = ""; } @@ -87,9 +87,6 @@ public function __construct($fs=false){ $this->awesome['pshere'] = ""; } - $this->buttons['next'] = "?p=n&f=".$file; - $this->awesome['next'] = ""; - $this->buttons['pause'] = "?f=".$file; $this->awesome['pause'] = ""; @@ -99,7 +96,8 @@ public function __construct($fs=false){ $this->buttons['stop'] = "?f=".$file; $this->awesome['stop'] = ""; - + $this->buttons['next'] = "?p=n&f=".$file; + $this->awesome['next'] = ""; } diff --git a/src/classes/Page.php b/src/classes/Page.php index 20d007f..cb21b23 100644 --- a/src/classes/Page.php +++ b/src/classes/Page.php @@ -90,6 +90,8 @@ public function header($head_content=NULL){ echo "\n"; echo "\n"; echo "\n"; + echo "\n"; + echo "\n"; echo "\n"; echo "\n"; echo "\n"; diff --git a/src/js/image_panel.js b/src/js/image_panel.js index 1fc5a37..30542fd 100644 --- a/src/js/image_panel.js +++ b/src/js/image_panel.js @@ -43,6 +43,14 @@ function init_image_panel(){ url = url.slice(url.indexOf('f=')); $('.linear_panel a[href$="' + url + '"]').parent().addClass("selected"); } + + $('#image_big').waitForImages().done(function() { + $("#image_big").fadeIn('slow', function(){ + if(slideshow_status == 1){ + play_slideshow(); + } + }); + }); // On clicking the bigimage $("#bigimage a, #image_bar #back").click(function(){ @@ -68,9 +76,12 @@ function init_image_panel(){ $(".linear_panel .selected").removeClass("selected"); $(this).parent().addClass("selected"); update_url($(this).attr("href"),"Image"); - - $(".image_panel").load($(this).attr("href")+"&j=Pan",function(){ - init_image_panel(); + + var elem = $(this); + $("#image_big").fadeOut('normal', function(){ + $(".image_panel").load(elem.attr("href")+"&j=Pan",function(){ + init_image_panel(); + }); }); // Load infos @@ -89,12 +100,14 @@ function init_image_panel(){ } if(! new_select.length){ - new_select = $(".linear_panel .item").last(); + new_select = $(".linear_panel .item").first(); } new_url = new_select.children("a").attr("href"); - $(".image_panel").load(new_url + "&j=Pan",function(){ + var elem = $(this); + $("#image_big").fadeOut('normal', function(){ + $(".image_panel").load(new_url + "&j=Pan",function(){ update_url(new_url,"Image"); curr_select.removeClass("selected"); @@ -105,6 +118,7 @@ function init_image_panel(){ if(slideshow_status != 0){ hide_links(); } + }); }); // Load infos @@ -134,12 +148,14 @@ function init_image_panel(){ } if(! new_select.length){ - new_select = $(".linear_panel .item").first(); + new_select = $(".linear_panel .item").last(); } new_url = new_select.children("a").attr("href") - $(".image_panel").load(new_url+"&j=Pan",function(){ + var elem = $(this); + $("#image_big").fadeOut('normal', function(){ + $(".image_panel").load(new_url+"&j=Pan",function(){ update_url(new_url,"Image"); @@ -151,6 +167,7 @@ function init_image_panel(){ if(slideshow_status != 0){ hide_links(); } + }); }); // Load infos @@ -167,6 +184,14 @@ function init_image_panel(){ } }); + // On scroll + $("#page").scroll(function(){ + instance.update(); + }); + $(".linear_panel").scroll(function(){ + instance.update(); + }); + $(".linear_panel").scrollTo($(".linear_panel .selected")).scrollTo("-="+$(".linear_panel").width()/2); init_comments(); @@ -193,6 +218,12 @@ function init_description(){ }); } -$("document").ready(function(){ +var instance; + +$("document").ready(function(){ + instance = $('.lazy').lazy({ + chainable: false + }); + init_image_panel(); }); \ No newline at end of file diff --git a/src/js/lazy.js b/src/js/lazy.js new file mode 100644 index 0000000..2d30ff3 --- /dev/null +++ b/src/js/lazy.js @@ -0,0 +1,870 @@ +/*! + * jQuery & Zepto Lazy - v1.7.6 + * http://jquery.eisbehr.de/lazy/ + * + * Copyright 2012 - 2017, Daniel 'Eisbehr' Kern + * + * Dual licensed under the MIT and GPL-2.0 licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl-2.0.html + * + * $("img.lazy").lazy(); + */ + +;(function(window, undefined) { + "use strict"; + + // noinspection JSUnresolvedVariable + /** + * library instance - here and not in construct to be shorter in minimization + * @return void + */ + var $ = window.jQuery || window.Zepto, + + /** + * unique plugin instance id counter + * @type {number} + */ + lazyInstanceId = 0, + + /** + * helper to register window load for jQuery 3 + * @type {boolean} + */ + windowLoaded = false; + + /** + * make lazy available to jquery - and make it a bit more case-insensitive :) + * @access public + * @type {function} + * @param {object} settings + * @return void + */ + $.fn.Lazy = $.fn.lazy = function(settings) { + return new LazyPlugin(this, settings); + }; + + /** + * helper to add plugins to lazy prototype configuration + * @access public + * @type {function} + * @param {string|Array} names + * @param {string|Array} [elements] + * @param {function} loader + * @return void + */ + $.Lazy = $.lazy = function(names, elements, loader) { + // make second parameter optional + if( $.isFunction(elements) ) { + loader = elements; + elements = []; + } + + // exit here if parameter is not a callable function + if( !$.isFunction(loader) ) { + return; + } + + // make parameters an array of names to be sure + names = $.isArray(names) ? names : [names]; + elements = $.isArray(elements) ? elements : [elements]; + + var config = LazyPlugin.prototype.config, + forced = config._f || (config._f = {}); + + // add the loader plugin for every name + for( var i = 0, l = names.length; i < l; i++ ) { + if( config[names[i]] === undefined || $.isFunction(config[names[i]]) ) { + config[names[i]] = loader; + } + } + + // add forced elements loader + for( var c = 0, a = elements.length; c < a; c++ ) { + forced[elements[c]] = names[0]; + } + }; + + /** + * contains all logic and the whole element handling + * is packed in a private function outside class to reduce memory usage, because it will not be created on every plugin instance + * @access private + * @type {function} + * @param {LazyPlugin} instance + * @param {object} config + * @param {object|Array} items + * @param {object} events + * @param {string} namespace + * @return void + */ + function _executeLazy(instance, config, items, events, namespace) { + /** + * a helper to trigger the 'onFinishedAll' callback after all other events + * @access private + * @type {number} + */ + var _awaitingAfterLoad = 0, + + /** + * visible content width + * @access private + * @type {number} + */ + _actualWidth = -1, + + /** + * visible content height + * @access private + * @type {number} + */ + _actualHeight = -1, + + /** + * determine possibly detected high pixel density + * @access private + * @type {boolean} + */ + _isRetinaDisplay = false, + + /** + * dictionary entry for better minimization + * @access private + * @type {string} + */ + _afterLoad = "afterLoad", + + /** + * dictionary entry for better minimization + * @access private + * @type {string} + */ + _load = "load", + + /** + * dictionary entry for better minimization + * @access private + * @type {string} + */ + _error = "error", + + /** + * dictionary entry for better minimization + * @access private + * @type {string} + */ + _img = "img", + + /** + * dictionary entry for better minimization + * @access private + * @type {string} + */ + _src = "src", + + /** + * dictionary entry for better minimization + * @access private + * @type {string} + */ + _srcset = "srcset", + + /** + * dictionary entry for better minimization + * @access private + * @type {string} + */ + _sizes = "sizes", + + /** + * dictionary entry for better minimization + * @access private + * @type {string} + */ + _backgroundImage = "background-image"; + + /** + * initialize plugin + * bind loading to events or set delay time to load all items at once + * @access private + * @return void + */ + function _initialize() { + // detect actual device pixel ratio + // noinspection JSUnresolvedVariable + _isRetinaDisplay = window.devicePixelRatio > 1; + + // prepare all initial items + items = _prepareItems(items); + + // if delay time is set load all items at once after delay time + if( config.delay >= 0 ) { + setTimeout(function() { + _lazyLoadItems(true); + }, config.delay); + } + + // if no delay is set or combine usage is active bind events + if( config.delay < 0 || config.combined ) { + // create unique event function + events.e = _throttle(config.throttle, function(event) { + // reset detected window size on resize event + if( event.type === "resize" ) { + _actualWidth = _actualHeight = -1; + } + + // execute 'lazy magic' + _lazyLoadItems(event.all); + }); + + // create function to add new items to instance + events.a = function(additionalItems) { + additionalItems = _prepareItems(additionalItems); + items.push.apply(items, additionalItems); + }; + + // create function to get all instance items left + events.g = function() { + // filter loaded items before return in case internal filter was not running until now + return (items = $(items).filter(function() { + return !$(this).data(config.loadedName); + })); + }; + + // create function to force loading elements + events.f = function(forcedItems) { + for( var i = 0; i < forcedItems.length; i++ ) { + // only handle item if available in current instance + // use a compare function, because Zepto can't handle object parameter for filter + // var item = items.filter(forcedItems[i]); + /* jshint loopfunc: true */ + var item = items.filter(function() { + return this === forcedItems[i]; + }); + + if( item.length ) { + _lazyLoadItems(false, item); + } + } + }; + + // load initial items + _lazyLoadItems(); + + // bind lazy load functions to scroll and resize event + // noinspection JSUnresolvedVariable + $(config.appendScroll).on("scroll." + namespace + " resize." + namespace, events.e); + } + } + + /** + * prepare items before handle them + * @access private + * @param {Array|object|jQuery} items + * @return {Array|object|jQuery} + */ + function _prepareItems(items) { + // fetch used configurations before loops + var defaultImage = config.defaultImage, + placeholder = config.placeholder, + imageBase = config.imageBase, + srcsetAttribute = config.srcsetAttribute, + loaderAttribute = config.loaderAttribute, + forcedTags = config._f || {}; + + // filter items and only add those who not handled yet and got needed attributes available + items = $(items).filter(function() { + var element = $(this), + tag = _getElementTagName(this); + + return !element.data(config.handledName) && + (element.attr(config.attribute) || element.attr(srcsetAttribute) || element.attr(loaderAttribute) || forcedTags[tag] !== undefined); + }) + + // append plugin instance to all elements + .data("plugin_" + config.name, instance); + + for( var i = 0, l = items.length; i < l; i++ ) { + var element = $(items[i]), + tag = _getElementTagName(items[i]), + elementImageBase = element.attr(config.imageBaseAttribute) || imageBase; + + // generate and update source set if an image base is set + if( tag === _img && elementImageBase && element.attr(srcsetAttribute) ) { + element.attr(srcsetAttribute, _getCorrectedSrcSet(element.attr(srcsetAttribute), elementImageBase)); + } + + // add loader to forced element types + if( forcedTags[tag] !== undefined && !element.attr(loaderAttribute) ) { + element.attr(loaderAttribute, forcedTags[tag]); + } + + // set default image on every element without source + if( tag === _img && defaultImage && !element.attr(_src) ) { + element.attr(_src, defaultImage); + } + + // set placeholder on every element without background image + else if( tag !== _img && placeholder && (!element.css(_backgroundImage) || element.css(_backgroundImage) === "none") ) { + element.css(_backgroundImage, "url('" + placeholder + "')"); + } + } + + return items; + } + + /** + * the 'lazy magic' - check all items + * @access private + * @param {boolean} [allItems] + * @param {object} [forced] + * @return void + */ + function _lazyLoadItems(allItems, forced) { + // skip if no items where left + if( !items.length ) { + // destroy instance if option is enabled + if( config.autoDestroy ) { + // noinspection JSUnresolvedFunction + instance.destroy(); + } + + return; + } + + var elements = forced || items, + loadTriggered = false, + imageBase = config.imageBase || "", + srcsetAttribute = config.srcsetAttribute, + handledName = config.handledName; + + // loop all available items + for( var i = 0; i < elements.length; i++ ) { + // item is at least in loadable area + if( allItems || forced || _isInLoadableArea(elements[i]) ) { + var element = $(elements[i]), + tag = _getElementTagName(elements[i]), + attribute = element.attr(config.attribute), + elementImageBase = element.attr(config.imageBaseAttribute) || imageBase, + customLoader = element.attr(config.loaderAttribute); + + // is not already handled + if( !element.data(handledName) && + // and is visible or visibility doesn't matter + (!config.visibleOnly || element.is(":visible")) && ( + // and image source or source set attribute is available + (attribute || element.attr(srcsetAttribute)) && ( + // and is image tag where attribute is not equal source or source set + (tag === _img && (elementImageBase + attribute !== element.attr(_src) || element.attr(srcsetAttribute) !== element.attr(_srcset))) || + // or is non image tag where attribute is not equal background + (tag !== _img && elementImageBase + attribute !== element.css(_backgroundImage)) + ) || + // or custom loader is available + customLoader )) + { + // mark element always as handled as this point to prevent double handling + loadTriggered = true; + element.data(handledName, true); + + // load item + _handleItem(element, tag, elementImageBase, customLoader); + } + } + } + + // when something was loaded remove them from remaining items + if( loadTriggered ) { + items = $(items).filter(function() { + return !$(this).data(handledName); + }); + } + } + + /** + * load the given element the lazy way + * @access private + * @param {object} element + * @param {string} tag + * @param {string} imageBase + * @param {function} [customLoader] + * @return void + */ + function _handleItem(element, tag, imageBase, customLoader) { + // increment count of items waiting for after load + ++_awaitingAfterLoad; + + // extended error callback for correct 'onFinishedAll' handling + var errorCallback = function() { + _triggerCallback("onError", element); + _reduceAwaiting(); + + // prevent further callback calls + errorCallback = $.noop; + }; + + // trigger function before loading image + _triggerCallback("beforeLoad", element); + + // fetch all double used data here for better code minimization + var srcAttribute = config.attribute, + srcsetAttribute = config.srcsetAttribute, + sizesAttribute = config.sizesAttribute, + retinaAttribute = config.retinaAttribute, + removeAttribute = config.removeAttribute, + loadedName = config.loadedName, + elementRetina = element.attr(retinaAttribute); + + // handle custom loader + if( customLoader ) { + // on load callback + var loadCallback = function() { + // remove attribute from element + if( removeAttribute ) { + element.removeAttr(config.loaderAttribute); + } + + // mark element as loaded + element.data(loadedName, true); + + // call after load event + _triggerCallback(_afterLoad, element); + + // remove item from waiting queue and possibly trigger finished event + // it's needed to be asynchronous to run after filter was in _lazyLoadItems + setTimeout(_reduceAwaiting, 1); + + // prevent further callback calls + loadCallback = $.noop; + }; + + // bind error event to trigger callback and reduce waiting amount + element.off(_error).one(_error, errorCallback) + + // bind after load callback to element + .one(_load, loadCallback); + + // trigger custom loader and handle response + if( !_triggerCallback(customLoader, element, function(response) { + if( response ) { + element.off(_load); + loadCallback(); + } + else { + element.off(_error); + errorCallback(); + } + })) element.trigger(_error); + } + + // handle images + else { + // create image object + var imageObj = $(new Image()); + + // bind error event to trigger callback and reduce waiting amount + imageObj.one(_error, errorCallback) + + // bind after load callback to image + .one(_load, function() { + // remove element from view + element.hide(); + + // set image back to element + // do it as single 'attr' calls, to be sure 'src' is set after 'srcset' + if( tag === _img ) { + element.attr(_sizes, imageObj.attr(_sizes)); + element.attr(_srcset, imageObj.attr(_srcset)); + element.attr(_src, imageObj.attr(_src)); + } + else { + element.css(_backgroundImage, "url('" + imageObj.attr(_src) + "')"); + } + + // bring it back with some effect! + element[config.effect](config.effectTime); + + // remove attribute from element + if( removeAttribute ) { + element.removeAttr(srcAttribute + " " + srcsetAttribute + " " + retinaAttribute + " " + config.imageBaseAttribute); + + // only remove 'sizes' attribute, if it was a custom one + if( sizesAttribute !== _sizes ) { + element.removeAttr(sizesAttribute); + } + } + + // mark element as loaded + element.data(loadedName, true); + + // call after load event + _triggerCallback(_afterLoad, element); + + // cleanup image object + imageObj.remove(); + + // remove item from waiting queue and possibly trigger finished event + _reduceAwaiting(); + }); + + // set sources + // do it as single 'attr' calls, to be sure 'src' is set after 'srcset' + var imageSrc = (_isRetinaDisplay && elementRetina ? elementRetina : element.attr(srcAttribute)) || ""; + imageObj.attr(_sizes, element.attr(sizesAttribute)); + imageObj.attr(_srcset, element.attr(srcsetAttribute)); + imageObj.attr(_src, imageSrc ? imageBase + imageSrc : null); + + // call after load even on cached image + imageObj.complete && imageObj.trigger(_load); // jshint ignore : line + } + } + + /** + * check if the given element is inside the current viewport or threshold + * @access private + * @param {object} element + * @return {boolean} + */ + function _isInLoadableArea(element) { + var elementBound = element.getBoundingClientRect(), + direction = config.scrollDirection, + threshold = config.threshold, + vertical = // check if element is in loadable area from top + ((_getActualHeight() + threshold) > elementBound.top) && + // check if element is even in loadable are from bottom + (-threshold < elementBound.bottom), + horizontal = // check if element is in loadable area from left + ((_getActualWidth() + threshold) > elementBound.left) && + // check if element is even in loadable area from right + (-threshold < elementBound.right); + + if( direction === "vertical" ) { + return vertical; + } + else if( direction === "horizontal" ) { + return horizontal; + } + + return vertical && horizontal; + } + + /** + * receive the current viewed width of the browser + * @access private + * @return {number} + */ + function _getActualWidth() { + return _actualWidth >= 0 ? _actualWidth : (_actualWidth = $(window).width()); + } + + /** + * receive the current viewed height of the browser + * @access private + * @return {number} + */ + function _getActualHeight() { + return _actualHeight >= 0 ? _actualHeight : (_actualHeight = $(window).height()); + } + + /** + * get lowercase tag name of an element + * @access private + * @param {object} element + * @returns {string} + */ + function _getElementTagName(element) { + return element.tagName.toLowerCase(); + } + + /** + * prepend image base to all srcset entries + * @access private + * @param {string} srcset + * @param {string} imageBase + * @returns {string} + */ + function _getCorrectedSrcSet(srcset, imageBase) { + if( imageBase ) { + // trim, remove unnecessary spaces and split entries + var entries = srcset.split(","); + srcset = ""; + + for( var i = 0, l = entries.length; i < l; i++ ) { + srcset += imageBase + entries[i].trim() + (i !== l - 1 ? "," : ""); + } + } + + return srcset; + } + + /** + * helper function to throttle down event triggering + * @access private + * @param {number} delay + * @param {function} callback + * @return {function} + */ + function _throttle(delay, callback) { + var timeout, + lastExecute = 0; + + return function(event, ignoreThrottle) { + var elapsed = +new Date() - lastExecute; + + function run() { + lastExecute = +new Date(); + // noinspection JSUnresolvedFunction + callback.call(instance, event); + } + + timeout && clearTimeout(timeout); // jshint ignore : line + + if( elapsed > delay || !config.enableThrottle || ignoreThrottle ) { + run(); + } + else { + timeout = setTimeout(run, delay - elapsed); + } + }; + } + + /** + * reduce count of awaiting elements to 'afterLoad' event and fire 'onFinishedAll' if reached zero + * @access private + * @return void + */ + function _reduceAwaiting() { + --_awaitingAfterLoad; + + // if no items were left trigger finished event + if( !items.length && !_awaitingAfterLoad ) { + _triggerCallback("onFinishedAll"); + } + } + + /** + * single implementation to handle callbacks, pass element and set 'this' to current instance + * @access private + * @param {string|function} callback + * @param {object} [element] + * @param {*} [args] + * @return {boolean} + */ + function _triggerCallback(callback, element, args) { + if( (callback = config[callback]) ) { + // jQuery's internal '$(arguments).slice(1)' are causing problems at least on old iPads + // below is shorthand of 'Array.prototype.slice.call(arguments, 1)' + callback.apply(instance, [].slice.call(arguments, 1)); + return true; + } + + return false; + } + + // if event driven or window is already loaded don't wait for page loading + if( config.bind === "event" || windowLoaded ) { + _initialize(); + } + + // otherwise load initial items and start lazy after page load + else { + // noinspection JSUnresolvedVariable + $(window).on(_load + "." + namespace, _initialize); + } + } + + /** + * lazy plugin class constructor + * @constructor + * @access private + * @param {object} elements + * @param {object} settings + * @return {object|LazyPlugin} + */ + function LazyPlugin(elements, settings) { + /** + * this lazy plugin instance + * @access private + * @type {object|LazyPlugin|LazyPlugin.prototype} + */ + var _instance = this, + + /** + * this lazy plugin instance configuration + * @access private + * @type {object} + */ + _config = $.extend({}, _instance.config, settings), + + /** + * instance generated event executed on container scroll or resize + * packed in an object to be referenceable and short named because properties will not be minified + * @access private + * @type {object} + */ + _events = {}, + + /** + * unique namespace for instance related events + * @access private + * @type {string} + */ + _namespace = _config.name + "-" + (++lazyInstanceId); + + // noinspection JSUndefinedPropertyAssignment + /** + * wrapper to get or set an entry from plugin instance configuration + * much smaller on minify as direct access + * @access public + * @type {function} + * @param {string} entryName + * @param {*} [value] + * @return {LazyPlugin|*} + */ + _instance.config = function(entryName, value) { + if( value === undefined ) { + return _config[entryName]; + } + + _config[entryName] = value; + return _instance; + }; + + // noinspection JSUndefinedPropertyAssignment + /** + * add additional items to current instance + * @access public + * @param {Array|object|string} items + * @return {LazyPlugin} + */ + _instance.addItems = function(items) { + _events.a && _events.a($.type(items) === "string" ? $(items) : items); // jshint ignore : line + return _instance; + }; + + // noinspection JSUndefinedPropertyAssignment + /** + * get all left items of this instance + * @access public + * @returns {object} + */ + _instance.getItems = function() { + return _events.g ? _events.g() : {}; + }; + + // noinspection JSUndefinedPropertyAssignment + /** + * force lazy to load all items in loadable area right now + * by default without throttle + * @access public + * @type {function} + * @param {boolean} [useThrottle] + * @return {LazyPlugin} + */ + _instance.update = function(useThrottle) { + _events.e && _events.e({}, !useThrottle); // jshint ignore : line + return _instance; + }; + + // noinspection JSUndefinedPropertyAssignment + /** + * force element(s) to load directly, ignoring the viewport + * @access public + * @param {Array|object|string} items + * @return {LazyPlugin} + */ + _instance.force = function(items) { + _events.f && _events.f($.type(items) === "string" ? $(items) : items); // jshint ignore : line + return _instance; + }; + + // noinspection JSUndefinedPropertyAssignment + /** + * force lazy to load all available items right now + * this call ignores throttling + * @access public + * @type {function} + * @return {LazyPlugin} + */ + _instance.loadAll = function() { + _events.e && _events.e({all: true}, true); // jshint ignore : line + return _instance; + }; + + // noinspection JSUndefinedPropertyAssignment + /** + * destroy this plugin instance + * @access public + * @type {function} + * @return undefined + */ + _instance.destroy = function() { + // unbind instance generated events + // noinspection JSUnresolvedFunction, JSUnresolvedVariable + $(_config.appendScroll).off("." + _namespace, _events.e); + // noinspection JSUnresolvedVariable + $(window).off("." + _namespace); + + // clear events + _events = {}; + + return undefined; + }; + + // start using lazy and return all elements to be chainable or instance for further use + // noinspection JSUnresolvedVariable + _executeLazy(_instance, _config, elements, _events, _namespace); + return _config.chainable ? elements : _instance; + } + + /** + * settings and configuration data + * @access public + * @type {object} + */ + LazyPlugin.prototype.config = { + // general + name : "lazy", + chainable : true, + autoDestroy : true, + bind : "load", + threshold : 500, + visibleOnly : false, + appendScroll : window, + scrollDirection : "both", + imageBase : null, + defaultImage : "data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==", + placeholder : null, + delay : -1, + combined : false, + + // attributes + attribute : "data-src", + srcsetAttribute : "data-srcset", + sizesAttribute : "data-sizes", + retinaAttribute : "data-retina", + loaderAttribute : "data-loader", + imageBaseAttribute : "data-imagebase", + removeAttribute : true, + handledName : "handled", + loadedName : "loaded", + + // effect + effect : "show", + effectTime : 0, + + // throttle + enableThrottle : true, + throttle : 250, + + // callbacks + beforeLoad : undefined, + afterLoad : undefined, + onError : undefined, + onFinishedAll : undefined + }; + + // register window load event globally to prevent not loading elements + // since jQuery 3.X ready state is fully async and may be executed after 'load' + $(window).on("load", function() { + windowLoaded = true; + }); +})(window); \ No newline at end of file diff --git a/src/js/slideshow.js b/src/js/slideshow.js index 18bfcdf..f261b70 100644 --- a/src/js/slideshow.js +++ b/src/js/slideshow.js @@ -29,11 +29,30 @@ */ var slideshow_status = 0; -var timer = 0; - -function run_slideshow(){ - $("#next a").click(); -} +var timer = { + id : 0, + + make : function ( fun, delay ) { + if ((typeof id !== 'undefined') && (id > 0)) { + clearInterval(id); + } + + id = setInterval.apply( + window, + [ fun, delay ].concat( [].slice.call(arguments, 2) ) + ); + + return id; + }, + + clear : function () { + if (typeof id !== 'undefined') { + var old = id; + id = 0; + return clearInterval( old ); + } + } +}; function toggleFullScreen() { var doc = window.document; @@ -42,7 +61,7 @@ function toggleFullScreen() { var requestFullScreen = docEl.requestFullscreen || docEl.mozRequestFullScreen || docEl.webkitRequestFullScreen || docEl.msRequestFullscreen; var cancelFullScreen = doc.exitFullscreen || doc.mozCancelFullScreen || doc.webkitExitFullscreen || doc.msExitFullscreen; - if(!doc.fullscreenElement && !doc.mozFullScreenElement && !doc.webkitFullscreenElement && !doc.msFullscreenElement) { + if(!isFullScreen()) { requestFullScreen.call(docEl); } else { @@ -50,16 +69,38 @@ function toggleFullScreen() { } } -function start_slideshow(){ - slideshow_status = 1; - timer = setInterval('run_slideshow()',7000); +function isFullScreen() { + var doc = window.document; + return (doc.fullscreenElement || doc.mozFullScreenElement || doc.webkitFullscreenElement || doc.msFullscreenElement); +} + +function show_image(){ + slideshow_status = -1; $(".image_panel").css("position","fixed"); $(".image_panel").css("z-index",5000); $(".image_panel").animate({bottom:'0'},200); hide_links(); + + if(!isFullScreen()) { + toggleFullScreen(); + } +} - toggleFullScreen(); +function start_slideshow(){ + $(".image_panel").css("position","fixed"); + $(".image_panel").css("z-index",5000); + $(".image_panel").animate({bottom:'0'},200); + + if(!isFullScreen()) { + toggleFullScreen(); + } + + play_slideshow(); +} +function run_slideshow(){ + timer.clear(); + $("#next a").click(); } function play_pause_slideshow(){ @@ -71,26 +112,33 @@ function play_pause_slideshow(){ } function play_slideshow(){ - start_slideshow(); - $("#pause").show(); - $("#play").hide(); + //timer = setInterval('run_slideshow()',3000); + timer.make('run_slideshow()',3000); + slideshow_status = 1; + + hide_links(); } function pause_slideshow(){ + timer.clear(); slideshow_status = 2; - clearInterval(timer); - $("#play").show(); - $("#pause").hide(); + + hide_links(); } function stop_slideshow(){ + timer.clear(); slideshow_status = 0; - clearInterval(timer); + $(".image_panel").animate({bottom:'150'},200); $(".image_panel").css("position","absolute"); $(".image_panel").css("z-index",50); + + if(isFullScreen()) { + toggleFullScreen(); + } + show_links(); - toggleFullScreen(); } function init_slideshow_panel(){ @@ -98,6 +146,12 @@ function init_slideshow_panel(){ $("#image_bar #play").hide(); $("#image_bar #stop").hide(); + $("#img").unbind(); + $("#img").click(function(){ + show_image(); + return false; + }); + $("#slideshow").unbind(); $("#slideshow").click(function(){ start_slideshow(); @@ -131,6 +185,8 @@ function show_links(){ $('#image_bar #pause').hide(); $('#image_bar #play').hide(); $('#image_bar #stop').hide(); + $('#image_bar #prev').show(); + $('#image_bar #next').show(); } function hide_links(){ @@ -139,11 +195,23 @@ function hide_links(){ $('#image_bar #get').hide(); $('#image_bar #slideshow').hide(); $('#image_bar #stop').show(); - if(slideshow_status == 1){ + if(slideshow_status == -1){ + // show image full scren + $('#image_bar #play').hide(); + $('#image_bar #pause').hide(); + $('#image_bar #prev').show(); + $('#image_bar #next').show(); + } else if(slideshow_status == 1){ + // play slideshow $('#image_bar #pause').show(); $('#image_bar #play').hide(); + //$('#image_bar #prev').hide(); + //$('#image_bar #next').hide(); }else{ + //pause slideshow $('#image_bar #play').show(); $('#image_bar #pause').hide(); - } -} + $('#image_bar #prev').show(); + $('#image_bar #next').show(); + } +} \ No newline at end of file diff --git a/src/js/waitforimages.js b/src/js/waitforimages.js new file mode 100644 index 0000000..d61d85a --- /dev/null +++ b/src/js/waitforimages.js @@ -0,0 +1,2 @@ +/*! waitForImages jQuery Plugin 2017-02-20 */ +!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof exports?module.exports=a(require("jquery")):a(jQuery)}(function(a){var b="waitForImages",c=function(a){return a.srcset&&a.sizes}(new Image);a.waitForImages={hasImageProperties:["backgroundImage","listStyleImage","borderImage","borderCornerImage","cursor"],hasImageAttributes:["srcset"]},a.expr[":"]["has-src"]=function(b){return a(b).is('img[src][src!=""]')},a.expr[":"].uncached=function(b){return!!a(b).is(":has-src")&&!b.complete},a.fn.waitForImages=function(){var d,e,f,g=0,h=0,i=a.Deferred(),j=this,k=[],l=a.waitForImages.hasImageProperties||[],m=a.waitForImages.hasImageAttributes||[],n=/url\(\s*(['"]?)(.*?)\1\s*\)/g;if(a.isPlainObject(arguments[0])?(f=arguments[0].waitForAll,e=arguments[0].each,d=arguments[0].finished):1===arguments.length&&"boolean"===a.type(arguments[0])?f=arguments[0]:(d=arguments[0],e=arguments[1],f=arguments[2]),d=d||a.noop,e=e||a.noop,f=!!f,!a.isFunction(d)||!a.isFunction(e))throw new TypeError("An invalid callback was supplied.");return this.each(function(){var b=a(this);f?b.find("*").addBack().each(function(){var b=a(this);b.is("img:has-src")&&!b.is("[srcset]")&&k.push({src:b.attr("src"),element:b[0]}),a.each(l,function(a,c){var d,e=b.css(c);if(!e)return!0;for(;d=n.exec(e);)k.push({src:d[2],element:b[0]})}),a.each(m,function(a,c){var d=b.attr(c);return!d||void k.push({src:b.attr("src"),srcset:b.attr("srcset"),element:b[0]})})}):b.find("img:has-src").each(function(){k.push({src:this.src,element:this})})}),g=k.length,h=0,0===g&&(d.call(j),i.resolveWith(j)),a.each(k,function(f,k){var l=new Image,m="load."+b+" error."+b;a(l).one(m,function b(c){var f=[h,g,"load"==c.type];if(h++,e.apply(k.element,f),i.notifyWith(k.element,f),a(this).off(m,b),h==g)return d.call(j[0]),i.resolveWith(j[0]),!1}),c&&k.srcset&&(l.srcset=k.srcset,l.sizes=k.sizes),l.src=k.src}),i.promise()}}); \ No newline at end of file diff --git a/user/themes/Default/loading.gif b/user/themes/Default/loading.gif new file mode 100644 index 0000000..8b6be2d Binary files /dev/null and b/user/themes/Default/loading.gif differ diff --git a/user/themes/Default/style.css b/user/themes/Default/style.css index e69de29..bb429e2 100644 --- a/user/themes/Default/style.css +++ b/user/themes/Default/style.css @@ -0,0 +1,5 @@ +img.lazy { + background-image: url('loading.gif'); + background-repeat: no-repeat; + background-position: 50% 50%; +} \ No newline at end of file diff --git a/user/themes/Demo/loading.gif b/user/themes/Demo/loading.gif new file mode 100644 index 0000000..8b6be2d Binary files /dev/null and b/user/themes/Demo/loading.gif differ diff --git a/user/themes/Demo/style.css b/user/themes/Demo/style.css index 37b8b92..89f0a0b 100644 --- a/user/themes/Demo/style.css +++ b/user/themes/Demo/style.css @@ -21,4 +21,9 @@ h3{ #menuright-header{ background: black; +} +img.lazy { + background-image: url('loading.gif'); + background-repeat: no-repeat; + background-position: 50% 50%; } \ No newline at end of file diff --git a/user/themes/Vendredi/loading.gif b/user/themes/Vendredi/loading.gif new file mode 100644 index 0000000..8b6be2d Binary files /dev/null and b/user/themes/Vendredi/loading.gif differ diff --git a/user/themes/Vendredi/style.css b/user/themes/Vendredi/style.css index 1b1eab1..130cce3 100644 --- a/user/themes/Vendredi/style.css +++ b/user/themes/Vendredi/style.css @@ -48,6 +48,10 @@ li.currentSelected > a:hover { .pure-g { padding: 2%; } +.pure-g .item { + margin: 3px; +} + .pure-button-primary, .pure-button-selected, a.pure-button-primary, a.pure-button-selected { background-color: #ff0056; } @@ -55,5 +59,8 @@ li.currentSelected > a:hover { color: #333; } - - +img.lazy { + background-image: url('loading.gif'); + background-repeat: no-repeat; + background-position: 50% 50%; +} \ No newline at end of file