mirror of
https://github.com/YunoHost-Apps/lutim_ynh.git
synced 2024-09-03 19:36:24 +02:00
391 lines
14 KiB
JavaScript
391 lines
14 KiB
JavaScript
|
/* -----------------------------------------------------------------------------
|
||
|
* Freezeframe
|
||
|
* freezeframe.js v2.0.2
|
||
|
* 2014 Chris Antonellis
|
||
|
*
|
||
|
* Freezeframe.js is a script that automatically pauses animated GIFs and
|
||
|
* enables them to start animating on mouse hover.
|
||
|
*
|
||
|
* Website: http://freezeframe.chrisantonellis.com/
|
||
|
* Documentation: http://freezeframe.chrisantonellis.com/documentation/
|
||
|
*
|
||
|
* Licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License
|
||
|
* http://creativecommons.org/licenses/by-sa/3.0/deed.en_US
|
||
|
* -------------------------------------------------------------------------- */
|
||
|
|
||
|
FreezeFrame = (function($) {
|
||
|
|
||
|
var _ff;
|
||
|
var canvas;
|
||
|
var context;
|
||
|
|
||
|
var class_name;
|
||
|
var trigger_event;
|
||
|
var support_touch_devices;
|
||
|
var animation_play_duration;
|
||
|
|
||
|
var loading_background_color;
|
||
|
var loading_background_image;
|
||
|
var loading_background_position;
|
||
|
var loading_fade_in_speed;
|
||
|
|
||
|
var animation_icon_image;
|
||
|
var animation_icon_position;
|
||
|
var animation_fade_out_speed;
|
||
|
|
||
|
var is_touch_device;
|
||
|
var freezeframe_count;
|
||
|
|
||
|
function FreezeFrame( _options ) {
|
||
|
|
||
|
_ff = this;
|
||
|
|
||
|
_options.class_name == null ?
|
||
|
this.class_name = "freezeframe" :
|
||
|
this.class_name = _options.class_name;
|
||
|
|
||
|
_options.trigger_event == null ?
|
||
|
this.trigger_event = "hover" :
|
||
|
this.trigger_event = _options.trigger_event.toLowerCase();
|
||
|
|
||
|
_options.support_touch_devices == null ?
|
||
|
this.support_touch_devices = true :
|
||
|
this.support_touch_devuces = _options.support_touch_devices.toLowerCase();
|
||
|
|
||
|
_options.animation_play_duration == null ?
|
||
|
this.animation_play_duration = 10000 :
|
||
|
this.animation_play_duration = parseInt(_options.animation_play_duration);
|
||
|
|
||
|
_options.loading_background_color == null ?
|
||
|
this.loading_background_color = "#666" :
|
||
|
this.loading_background_color = _options.loading_background_color.toLowerCase();
|
||
|
|
||
|
_options.loading_background_image == null ?
|
||
|
this.loading_background_image = "data:image/gif;base64,R0lGODlhEAAQAPIAAGZmZv///4mJidbW1v///8PDw7CwsKampiH+GkNyZWF0ZWQgd2l0aCBhamF4bG9hZC5pbmZvACH5BAAKAAAAIf8LTkVUU0NBUEUyLjADAQAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQACgABACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkEAAoAAgAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkEAAoAAwAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkEAAoABAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQACgAFACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQACgAGACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAAKAAcALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA==" :
|
||
|
this.loading_background_image = _options.loading_background_image;
|
||
|
|
||
|
_options.loading_background_position == null ?
|
||
|
this.loading_background_position = "center center" :
|
||
|
this.loading_background_position = _options.loading_background_position.toLowerCase();
|
||
|
|
||
|
_options.animation_icon_image == null ?
|
||
|
this.animation_icon_image = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAl9JREFUeNrs2s2K2lAUAGATb3TE2Cr+oaJQNFOh1MVsxK0OuJbSdX2V9gG67GqW3RbaB7B9gy7qgKJF8G/EarHVWGMyJj230EXLLITm6q05F44/IVw5X3JPjiGCZVkuJw/R5fCBAAiAAAiAAAiAAAiAAAiAAAiAAAiAAAiAAAjwjyMej79MpVKP/hcAwe6boul0+p3P5/vmdruv4evbVqvVdRRALpd7HQqFpn6/XxUEwdI07UZV1ffNZvMzjwDE7gk9Hs8mGAwuYCl8hTNB32630nw+f1IqlRY8QtgOQAjRZVleJxKJ77AcVLptOBwup9PpPR4hbAcQRdGUJOk2HA5riqKokUjEgKK4GY/HKo8QhMGcv4oKIJg0+Xw+r8H7bSaT0XiEICwnhyLoCgQCptfrNSgCjxDkED8ChdGiwSMEOaQ2jxDkGOtuH4jJZHJ/Nps9LRaLi+Vy2WDVUB0FYB+IXq+36ff7P0ajURj2eQbF9EO73W6cFMBdENA8mXQbNFDier0mhULhQaVSeZzNZj+d3Bnwe+i6LkDCAqx9QmMwGJwlk8nzarV6Cf3EDHZ5DvHx5ADuSjwWiz0sl8uX8H9izjLxowLskfgL1okfBYCnxA8KwGPiBwGg9xpWq5XIY+IsAQT6stvt6BGX4Nrt4jFxZgCmaYqGYRDo4nzdbncny3KGx8SZAcCRl6CH9yuKcl6r1S6i0egXHhP/Y53aGfV6/U2n02nA5yuIC7vntzsEBo/KXkG84vaI/12w8Flhhw8EQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEcNr4KcAABsB8S2vxAV8AAAAASUVORK5CYII=" :
|
||
|
this.animation_icon_image = _options.animation_icon_image;
|
||
|
|
||
|
_options.animation_icon_position == null ?
|
||
|
this.animation_icon_position = "top left" :
|
||
|
this.animation_icon_position = _options.animation_icon_position.toLowerCase();
|
||
|
|
||
|
_options.loading_fade_in_speed == null ?
|
||
|
this.loading_fade_in_speed = 500 :
|
||
|
this.loading_fade_in_speed = parseInt(_options.loading_fade_in_speed);
|
||
|
|
||
|
_options.animation_fade_out_speed == null ?
|
||
|
this.animation_fade_out_speed = 250 :
|
||
|
this.animation_fade_out_speed = parseInt(_options.animation_fade_out_speed);
|
||
|
|
||
|
this.is_touch_device = isMouseEventSupported("ontouchstart");
|
||
|
this.freezeframe_count = 0;
|
||
|
};
|
||
|
|
||
|
/** --------------------------------------------------------------------------
|
||
|
* @function .setup()
|
||
|
* Sets up the freezeframe instance by adding a canvas element to the
|
||
|
* document and capturing references to the canvas and its 2D context
|
||
|
* ------------------------------------------------------------------------ */
|
||
|
|
||
|
FreezeFrame.prototype.setup = function() {
|
||
|
$("<canvas>",{id:"freezeframe-canvas"})
|
||
|
.css("display", "none")
|
||
|
.prependTo($("body"));
|
||
|
this.canvas = $("canvas#freezeframe-canvas");
|
||
|
this.context = this.canvas[0].getContext('2d');
|
||
|
};
|
||
|
|
||
|
/** --------------------------------------------------------------------------
|
||
|
* .run()
|
||
|
* Starts freezeframe processing for each image. Copies the image to
|
||
|
* the freezeframe canvas and converts it to a data url
|
||
|
* ------------------------------------------------------------------------ */
|
||
|
|
||
|
FreezeFrame.prototype.run = function() {
|
||
|
var images = [];
|
||
|
var ext;
|
||
|
var figure_background = _ff.loading_background_color;
|
||
|
|
||
|
if( _ff.loading_background_image !== false ) {
|
||
|
figure_background += " url('" + _ff.loading_background_image + "') " +
|
||
|
_ff.loading_background_position + " no-repeat";
|
||
|
}
|
||
|
|
||
|
// Select all images with a class matching the option class_name
|
||
|
images = $('img[class*="' + _ff.class_name + '"]')
|
||
|
.not('[class*="' + _ff.class_name + '_done"]');
|
||
|
|
||
|
// Process each image by resetting the animation sequence, copying to the
|
||
|
// canvas, converting to a data url, and attaching that data url to the
|
||
|
// image itself as an attribute
|
||
|
$(images).each(function(index) {
|
||
|
// Change image class so it won't be reprocessed if .run() is run again
|
||
|
$(this).removeClass(_ff.class_name).addClass(_ff.class_name + "_done");
|
||
|
// Set cross-origin to anon to load images from remote services that send
|
||
|
// the correct header. Not working correctly, needs more testing
|
||
|
$(this).crossOrigin = "anonymous";
|
||
|
// Determine file extension
|
||
|
ext = $(this)[0].src.split(".");
|
||
|
ext = ext[ext.length - 1].toLowerCase();
|
||
|
// Remove non GIF files
|
||
|
if(ext !== "gif") {
|
||
|
images.splice(index, 1);
|
||
|
} else {
|
||
|
|
||
|
var freezeframe_figure = $("<figure />")
|
||
|
.attr("class", "freezeframe-container " + _ff.freezeframe_count)
|
||
|
.css({"display": "inline-block",
|
||
|
"overflow": "hidden",
|
||
|
"margin": 0,
|
||
|
"background-size": "100% auto",
|
||
|
"width": "100%",
|
||
|
"max-height": "100%",
|
||
|
"background": figure_background});
|
||
|
|
||
|
$(this).css({"opacity": 0,
|
||
|
"display": "block"})
|
||
|
.wrap(freezeframe_figure);
|
||
|
|
||
|
freezeframe_figure = $(this).parent();
|
||
|
|
||
|
// If an animation icon image is available, attach it
|
||
|
if(_ff.animation_icon_image !== false) {
|
||
|
var animation_icon = $("<div />")
|
||
|
.attr("class", "freezeframe-animation-icon")
|
||
|
.css({"display": "block",
|
||
|
"position": "absolute",
|
||
|
"background": "transparent " + "url('" + _ff.animation_icon_image + "') " +
|
||
|
_ff.animation_icon_position + " no-repeat",
|
||
|
"pointer-events": "none",
|
||
|
"z-index": 100,
|
||
|
"opacity": 0});
|
||
|
|
||
|
$(freezeframe_figure).prepend(animation_icon);
|
||
|
|
||
|
animation_icon = $(this).siblings($(".freezeframe-animation-icon"));
|
||
|
}
|
||
|
|
||
|
// Increment counter so each image gets a unique number
|
||
|
_ff.freezeframe_count++;
|
||
|
|
||
|
// Create a temporary refernce to the image as non-object to pass to .drawImage
|
||
|
var _self = this;
|
||
|
|
||
|
// Using imagesLoaded by Desandro because .load doesn't work on cached images
|
||
|
$(this).imagesLoaded(function() {
|
||
|
|
||
|
$(this).off("imagesLoaded");
|
||
|
|
||
|
_ff.canvas[0].width = $(this)[0].clientWidth;
|
||
|
_ff.canvas[0].height = $(this)[0].clientHeight;
|
||
|
|
||
|
$(this).attr("animated", $(this).attr("src"))
|
||
|
.attr("src", $(this).attr("src"));
|
||
|
|
||
|
_ff.context.drawImage(_self, 0, 0, $(this)[0].clientWidth, $(this)[0].clientHeight);
|
||
|
|
||
|
$(this).attr("src", _ff.canvas[0].toDataURL());
|
||
|
|
||
|
// If an animation icon image is available, show it
|
||
|
if(_ff.animation_icon_image !== false) {
|
||
|
$(animation_icon).css({
|
||
|
"width": parseInt($(this)[0].width),
|
||
|
"height": parseInt($(this)[0].height)})
|
||
|
.animate({"opacity": 1}, _ff.loading_fade_in_speed);
|
||
|
}
|
||
|
|
||
|
// When fade in sequence is complete, enable interaction
|
||
|
$(this).animate({"opacity": 1}, _ff.loading_fade_in_speed, function() {
|
||
|
|
||
|
$(freezeframe_figure).css("background", "url('" + $(this).attr("src") + "')");
|
||
|
|
||
|
$(this).css("opacity", 0)
|
||
|
.attr("src", $(this).attr("animated"));
|
||
|
|
||
|
// Touch Device or Click Event
|
||
|
if((_ff.support_touch_devices && _ff.is_touch_device) || _ff.trigger_event.toLowerCase() == "click") {
|
||
|
|
||
|
var stop_animation;
|
||
|
var animating = false;
|
||
|
|
||
|
$(this).click(function() {
|
||
|
|
||
|
// If not currently animating, start animating
|
||
|
if(!animating) {
|
||
|
$(this).attr("src", $(this).attr("src"))
|
||
|
.css("opacity", 1);
|
||
|
if(_ff.animation_icon_image !== false) {
|
||
|
$(animation_icon).css("opacity", 0);
|
||
|
}
|
||
|
|
||
|
stop_animation = setInterval(function() {
|
||
|
clearInterval(stop_animation);
|
||
|
this.animate({"opacity": 0}, _ff.animation_fade_out_speed);
|
||
|
if(_ff.animation_icon_image !== false) {
|
||
|
$(animation_icon).animate({"opacity": 1}, _ff.animation_fade_out_speed);
|
||
|
}
|
||
|
animating = false;
|
||
|
}, _ff.animation_play_duration);
|
||
|
animating = true;
|
||
|
|
||
|
// If currently animating, stop animating
|
||
|
} else {
|
||
|
clearInterval(stop_animation);
|
||
|
$(this).animate({"opacity": 0}, _ff.animation_fade_out_speed);
|
||
|
if(_ff.animation_icon_image !== false) {
|
||
|
$(animation_icon).animate({"opacity": 1}, _ff.animation_fade_out_speed);
|
||
|
}
|
||
|
animating = false;
|
||
|
}
|
||
|
});
|
||
|
|
||
|
} else {
|
||
|
|
||
|
// Hover Event
|
||
|
$(this).mouseenter(function() {
|
||
|
$(this).attr("src", $(this).attr("src"))
|
||
|
.css("opacity", 1);
|
||
|
if(_ff.animation_icon_image !== false) {
|
||
|
$(animation_icon).css("opacity", 0);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
$(this).mouseleave(function() {
|
||
|
$(this).animate({"opacity": 0}, _ff.animation_fade_out_speed);
|
||
|
if(_ff.animation_icon_image !== false) {
|
||
|
$(animation_icon).animate({"opacity": 1}, _ff.animation_fade_out_speed);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
|
||
|
return FreezeFrame;
|
||
|
})(jQuery);
|
||
|
|
||
|
/** ----------------------------------------------------------------------------
|
||
|
* Setup & Run Freezeframe
|
||
|
* -------------------------------------------------------------------------- */
|
||
|
|
||
|
jQuery(document).ready(function($) {
|
||
|
typeof(freezeframe_options) == 'undefined' ? freezeframe_options = {} : null;
|
||
|
freezeframe = new FreezeFrame(freezeframe_options);
|
||
|
freezeframe.setup();
|
||
|
freezeframe.run();
|
||
|
});
|
||
|
|
||
|
/** ----------------------------------------------------------------------------
|
||
|
* jQuery imagesLoaded plugin v2.1.1
|
||
|
* http://github.com/desandro/imagesloaded
|
||
|
*
|
||
|
* MIT License. by Paul Irish et al.
|
||
|
* -------------------------------------------------------------------------- */
|
||
|
|
||
|
;(function($, undefined) {
|
||
|
'use strict';
|
||
|
var BLANK = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==';
|
||
|
$.fn.imagesLoaded = function( callback ) {
|
||
|
var $this = this,
|
||
|
deferred = $.isFunction($.Deferred) ? $.Deferred() : 0,
|
||
|
hasNotify = $.isFunction(deferred.notify),
|
||
|
$images = $this.find('img').add( $this.filter('img') ),
|
||
|
loaded = [],
|
||
|
proper = [],
|
||
|
broken = [];
|
||
|
if ($.isPlainObject(callback)) {
|
||
|
$.each(callback, function (key, value) {
|
||
|
if (key === 'callback') {
|
||
|
callback = value;
|
||
|
} else if (deferred) {
|
||
|
deferred[key](value);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
function doneLoading() {
|
||
|
var $proper = $(proper),
|
||
|
$broken = $(broken);
|
||
|
if ( deferred ) {
|
||
|
if ( broken.length ) {
|
||
|
deferred.reject( $images, $proper, $broken );
|
||
|
} else {
|
||
|
deferred.resolve( $images );
|
||
|
}
|
||
|
}
|
||
|
if ( $.isFunction( callback ) ) {
|
||
|
callback.call( $this, $images, $proper, $broken );
|
||
|
}
|
||
|
}
|
||
|
function imgLoadedHandler( event ) {
|
||
|
imgLoaded( event.target, event.type === 'error' );
|
||
|
}
|
||
|
function imgLoaded( img, isBroken ) {
|
||
|
if ( img.src === BLANK || $.inArray( img, loaded ) !== -1 ) {
|
||
|
return;
|
||
|
}
|
||
|
loaded.push( img );
|
||
|
if ( isBroken ) {
|
||
|
broken.push( img );
|
||
|
} else {
|
||
|
proper.push( img );
|
||
|
}
|
||
|
$.data( img, 'imagesLoaded', { isBroken: isBroken, src: img.src } );
|
||
|
if ( hasNotify ) {
|
||
|
deferred.notifyWith( $(img), [ isBroken, $images, $(proper), $(broken) ] );
|
||
|
}
|
||
|
if ( $images.length === loaded.length ) {
|
||
|
setTimeout( doneLoading );
|
||
|
$images.unbind( '.imagesLoaded', imgLoadedHandler );
|
||
|
}
|
||
|
}
|
||
|
if ( !$images.length ) {
|
||
|
doneLoading();
|
||
|
} else {
|
||
|
$images.bind( 'load.imagesLoaded error.imagesLoaded', imgLoadedHandler )
|
||
|
.each( function( i, el ) {
|
||
|
var src = el.src;
|
||
|
var cached = $.data( el, 'imagesLoaded' );
|
||
|
if ( cached && cached.src === src ) {
|
||
|
imgLoaded( el, cached.isBroken );
|
||
|
return;
|
||
|
}
|
||
|
if ( el.complete && el.naturalWidth !== undefined ) {
|
||
|
imgLoaded( el, el.naturalWidth === 0 || el.naturalHeight === 0 );
|
||
|
return;
|
||
|
}
|
||
|
if ( el.readyState || el.complete ) {
|
||
|
el.src = BLANK;
|
||
|
el.src = src;
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
return deferred ? deferred.promise( $this ) : $this;
|
||
|
};
|
||
|
})(jQuery);
|
||
|
|
||
|
/** ----------------------------------------------------------------------------
|
||
|
* isMouseEventSupported by kangax
|
||
|
* http://perfectionkills.com/detecting-event-support-without-browser-sniffing/
|
||
|
* -------------------------------------------------------------------------- */
|
||
|
|
||
|
function isMouseEventSupported(eventName) {
|
||
|
var el = document.createElement('div');
|
||
|
eventName = 'on' + eventName;
|
||
|
var isSupported = (eventName in el);
|
||
|
if (!isSupported) {
|
||
|
el.setAttribute(eventName, 'return;');
|
||
|
isSupported = typeof el[eventName] == 'function';
|
||
|
}
|
||
|
el = null;
|
||
|
return isSupported;
|
||
|
}
|