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 "
\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