diff --git a/ajax/libs/fluidbox/1.4.1/css/fluidbox.css b/ajax/libs/fluidbox/1.4.1/css/fluidbox.css new file mode 100644 index 000000000..093f69e66 --- /dev/null +++ b/ajax/libs/fluidbox/1.4.1/css/fluidbox.css @@ -0,0 +1,44 @@ +.fluidbox { + outline: none; +} +.hidden { + display: none; +} +.fluidbox-overlay { + background-color: rgba(255,255,255,.85); + cursor: pointer; + cursor: -webkit-zoom-out; + cursor: -moz-zoom-out; + opacity: 0; + position: fixed; + top: 0; + left: 0; + bottom: 0; + right: 0; + transition: all .25s ease-in-out; +} +.fluidbox-wrap { + background-position: center center; + background-size: cover; + margin: 0 auto; + position: relative; + transition: all .25s ease-in-out; +} +.fluidbox-ghost { + background-size: 100% 100%; + background-position: center center; + position: absolute; + transition: all .25s ease-in-out; +} + .fluidbox-closed .fluidbox-ghost { + -webkit-transition-property: top, left, opacity, -webkit-transform; + -moz-transition-property: top, left, opacity, -moz-transform; + -o-transition-property: top, left, opacity, -o-transform; + transition-property: top, left, opacity, transform; + transition-delay: 0, 0, .25s, 0; + } + .fluidbox-closed .fluidbox-wrap img { + transition-property: opacity; + transition-delay: .25s; + transition-duration: 0s; + } \ No newline at end of file diff --git a/ajax/libs/fluidbox/1.4.1/jquery.fluidbox.js b/ajax/libs/fluidbox/1.4.1/jquery.fluidbox.js new file mode 100644 index 000000000..5fd1f8f65 --- /dev/null +++ b/ajax/libs/fluidbox/1.4.1/jquery.fluidbox.js @@ -0,0 +1,424 @@ +// Fluidbox +// Description: Replicating the seamless lightbox transition effect seen on Medium.com, with some improvements +// Version: 1.4.1 +// Author: Terry Mun +// Author URI: http://terrymun.com + +// -------------------------------------------------------- // +// Dependency: Paul Irish's jQuery debounced resize event // +// -------------------------------------------------------- // +(function($,sr){ + + // debouncing function from John Hann + // http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/ + var debounce = function (func, threshold, execAsap) { + var timeout; + + return function debounced () { + var obj = this, args = arguments; + function delayed () { + if (!execAsap) + func.apply(obj, args); + timeout = null; + }; + + if (timeout) + clearTimeout(timeout); + else if (execAsap) + func.apply(obj, args); + + timeout = setTimeout(delayed, threshold || 100); + }; + } + // smartresize + jQuery.fn[sr] = function(fn){ return fn ? this.bind('resize', debounce(fn)) : this.trigger(sr); }; + +})(jQuery,'smartresize'); + + +// ---------------------------------------------------------------------------------------------------------------------- // +// Dependency: David Walsh (http://davidwalsh.name/css-animation-callback) // +// and // +// Jonathan Suh (https://jonsuh.com/blog/detect-the-end-of-css-animations-and-transitions-with-javascript/) // +// ---------------------------------------------------------------------------------------------------------------------- // +function whichTransitionEvent() { + var t, + el = document.createElement("fakeelement"); + + var transitions = { + "transition" : "transitionend", + "OTransition" : "oTransitionEnd", + "MozTransition" : "transitionend", + "WebkitTransition": "webkitTransitionEnd" + } + + for (t in transitions){ + if (el.style[t] !== undefined){ + return transitions[t]; + } + } +} +var customTransitionEnd = whichTransitionEvent(); + +// ----------------------------- +// Fluidbox plugin starts here +// ----------------------------- +(function ($) { + + $.fn.fluidbox = function (opts) { + + // Default settings + var settings = $.extend(true, { + viewportFill: 0.95, + debounceResize: true, + stackIndex: 1000, + stackIndexDelta: 10, + closeTrigger: [ + { + selector: '.fluidbox-overlay', + event: 'click' + }, + { + selector: 'document', + event: 'keyup', + keyCode: 27 + } + ] + }, opts); + + // Ensure that the stackIndex does not become negative + if(settings.stackIndex < settings.stackIndexDelta) settings.stackIndexDelta = settings.stackIndex; + + // Dynamically create overlay + $fbOverlay = $('
', { + 'class': 'fluidbox-overlay', + css: { + 'z-index': settings.stackIndex + } + }); + + // Declare variables + var $fb = this, + $w = $(window), // Shorthand for $(window) + vpRatio, + + // Function: + // 1. funcCloseFb() - used to close any instance of opened Fluidbox + // 2. funcPositionFb() - used for dynamic positioning of any instance of opened Fluidbox + // 3. funcCalcAll() - used to run funcCalc() for every instance of targered Fluidbox thumbnail + // 4. funcCalc() - used to store dimensions of image, ghost element and wrapper element upon initialization or resize + // 5. fbClickhandler() - universal click handler for all Fluidbox items + funcCloseFb = function () { + $('.fluidbox-opened').trigger('click'); + }, + funcPositionFb = function ($activeFb, customEvent) { + // Get shorthand for more objects + var $img = $activeFb.find('img'), + $ghost = $activeFb.find('.fluidbox-ghost'), + $wrap = $activeFb.find('.fluidbox-wrap'), + $data = $activeFb.data(), + fHeight = 0, + fWidth = 0; + $img.data().imgRatio = $data.natWidth/ $data.natHeight; + + var newHeight, missingRatioNormal, missingRatio; + + // Check natural dimensions + if(vpRatio > $img.data().imgRatio) { + if($data.natHeight < $w.height()*settings.viewportFill) { + fHeight = $data.natHeight; + } else { + fHeight = $w.height()*settings.viewportFill; + } + $data.imgScale = fHeight/$img.height(); + $data.imgScaleY = $data.imgScale; + + newHeight = $img.height() * $data.imgScaleY; + missingRatioNormal = newHeight / $data.natHeight; + missingRatio = $data.natWidth * missingRatioNormal / $img.width(); + + $data.imgScaleX = missingRatio; + } else { + if($data.natWidth < $w.width()*settings.viewportFill) { + fWidth = $data.natWidth; + } else { + fWidth = $w.width()*settings.viewportFill; + } + $data.imgScale = fWidth/$img.width(); + $data.imgScaleX = $data.imgScale; + + var newWidth = $img.width() * $data.imgScaleX; + var missingRatioNormal = newWidth / $data.natWidth; + var missingRatio = $data.natHeight * missingRatioNormal / $img.height(); + + $data.imgScaleY = missingRatio; + } + + // Calculation goes here + var offsetY = $w.scrollTop()-$img.offset().top+0.5*($img.data('imgHeight')*($img.data('imgScale')-1))+0.5*($w.height()-$img.data('imgHeight')*$img.data('imgScale')), + offsetX = 0.5*($img.data('imgWidth')*($img.data('imgScale')-1))+0.5*($w.width()-$img.data('imgWidth')*$img.data('imgScale'))-$img.offset().left, + scale = parseInt($data.imgScaleX * 1000) / 1000 + ',' + parseInt($data.imgScaleY * 1000) / 1000; + + // Apply CSS transforms to ghost element + // For offsetX and Y, we round to one decimal place + // For scale, we round to three decimal places + $ghost.css({ + 'transform': 'translate('+parseInt(offsetX*10)/10+'px,'+parseInt(offsetY*10)/10+'px) scale('+ scale +')', + top: $img.offset().top - $wrap.offset().top, + left: $img.offset().left - $wrap.offset().left + }).one(customTransitionEnd, function() { + $activeFb.trigger(customEvent); + }); + }, + funcCalcAll = function() { + $fb.each(function () { + funcCalc($(this)); + }); + }, + funcCalc = function ($fbItem) { + // Get viewport ratio + vpRatio = $w.width() / $w.height(); + + // Get image dimensions and aspect ratio + if($fbItem.hasClass('fluidbox')) { + var $img = $fbItem.find('img'), + $ghost = $fbItem.find('.fluidbox-ghost'), + $wrap = $fbItem.find('.fluidbox-wrap'), + data = $img.data(); + + function imageProp() { + // Store image dimensions in jQuery object + data.imgWidth = $img.width(); + data.imgHeight = $img.height(); + data.imgRatio = $img.width()/$img.height(); + + // Resize and position ghost element + $ghost.css({ + width: $img.width(), + height: $img.height(), + top: $img.offset().top - $wrap.offset().top + parseInt($img.css('borderTopWidth')) + parseInt($img.css('paddingTop')), + left: $img.offset().left - $wrap.offset().left + parseInt($img.css('borderLeftWidth')) + parseInt($img.css('paddingLeft')) + }); + + // Calculate scale based on orientation + if(vpRatio > data.imgRatio) { + data.imgScale = $w.height()*settings.viewportFill/$img.height(); + } else { + data.imgScale = $w.width()*settings.viewportFill/$img.width(); + } + } + + imageProp(); + + // Rerun everything on imageload, to overcome issue in Firefox + $img.load(imageProp); + } + }, + fbClickHandler = function(e) { + + // Check if the fluidbox element does have .fluidbox assigned to it + if($(this).hasClass('fluidbox')) { + + // Variables + var $activeFb = $(this), + $img = $(this).find('img'), + $ghost = $(this).find('.fluidbox-ghost'), + $wrap = $(this).find('.fluidbox-wrap'), + timer = {}; + + if($(this).data('fluidbox-state') === 0 || !$(this).data('fluidbox-state')) { + // State: Closed + // Action: Open fluidbox + + // Fire custom event: openstart + $(this).trigger('openstart'); + + // Wait for ghost image to be loaded successfully first, then do the rest + $('', { + src: $img.attr('src') + }).load(function () { + // Preload ghost image + $('', { + src: $activeFb.attr('href') + }).load(function() { + // Store natural width and heights + $activeFb + .data('natWidth', $(this)[0].naturalWidth) + .data('natHeight', $(this)[0].naturalHeight); + + // What are we doing here: + // 1. Append overlay in fluidbox + // 2. Toggle fluidbox state with data attribute + // 3. Store original z-index with data attribute (so users can change z-index when they see fit in CSS file) + // 4. Class toggle + $activeFb + .append($fbOverlay) + .data('fluidbox-state', 1) + .removeClass('fluidbox-closed') + .addClass('fluidbox-opened'); + + // Force timer to completion + if(timer['close']) window.clearTimeout(timer['close']); + + // Set timer for opening + timer['open'] = window.setTimeout(function() { + // Show overlay + $('.fluidbox-overlay').css({ opacity: 1 }); + }, 10); + + // Change wrapper z-index, so it is above everything else + // Decrease all siblings z-index by 1 just in case + $('.fluidbox-wrap').css({ zIndex: settings.stackIndex - settings.stackIndexDelta - 1 }); + $wrap.css({ 'z-index': settings.stackIndex + settings.stackIndexDelta }); + + // Set thumbnail image source as background image first, preload later + $ghost.css({ + 'background-image': 'url('+$img.attr('src')+')', + opacity: 1 + }); + + // Hide original image + $img.css({ opacity: 0 }); + + $ghost.css({ 'background-image': 'url('+$activeFb.attr('href')+')' }); + + // Position Fluidbox + funcPositionFb($activeFb, 'openend'); + }); + }); + + } else { + // State: Open + // Action: Close fluidbox + + // Fire custom event: closestart + $activeFb.trigger('closestart'); + + // Switch state + $activeFb + .data('fluidbox-state', 0) + .removeClass('fluidbox-opened') + .addClass('fluidbox-closed'); + + // Set timer for closing + if(timer['open']) window.clearTimeout(timer['open']); + timer['close'] = window.setTimeout(function() { + $('.fluidbox-overlay').remove(); + $wrap.css({ 'z-index': settings.stackIndex - settings.stackIndexDelta }); + }, 10); + + // Hide overlay + $('.fluidbox-overlay').css({ opacity: 0 }); + + // Reverse animation on wrapped elements, and restore stacking order + // You might want to change this value if your transition timing is longer + $ghost.css({ + 'transform': 'translate(0,0) scale(1)', + opacity: 0, + top: $img.offset().top - $wrap.offset().top + parseInt($img.css('borderTopWidth')) + parseInt($img.css('paddingTop')), + left: $img.offset().left - $wrap.offset().left + parseInt($img.css('borderLeftWidth')) + parseInt($img.css('paddingLeft')) + }).one(customTransitionEnd, function() { + $activeFb.trigger('closeend'); + }); + $img.css({ opacity: 1 }); + } + + e.preventDefault(); + } + }; + + // When should we close Fluidbox? + if(settings.closeTrigger) { + // Go through array + $.each(settings.closeTrigger, function (i) { + var trigger = settings.closeTrigger[i]; + + // Attach events + if(trigger.selector != 'window') { + // If it is not 'window', we append click handler to $(document) object, allow it to bubble up + // However, if thes selector is 'document', we use a different .on() syntax + if(trigger.selector == 'document') { + if(trigger.keyCode) { + $(document).on(trigger.event, function (e) { + if(e.keyCode == trigger.keyCode) funcCloseFb(); + }); + } else { + $(document).on(trigger.event, funcCloseFb); + } + } else { + $(document).on(trigger.event, settings.closeTrigger[i].selector, funcCloseFb); + } + } else { + // If it is 'window', append click handler to $(window) object + $w.on(trigger.event, funcCloseFb); + } + }); + } + + // Go through each individual object + $fb.each(function (i) { + + // Check if Fluidbox: + // 1. Is an anchor element , + // 2. Contains one and ONLY one child + // 3. The only child is an image element, + // 4. If the element is hidden + if($(this).is('a') && $(this).children().length === 1 && $(this).children().is('img') && $(this).css('display') !== 'none' && $(this).parents().css('display') !=='none') { + + // Define wrap + var $fbInnerWrap = $('
', { + 'class': 'fluidbox-wrap', + css: { + 'z-index': settings.stackIndex - settings.stackIndexDelta + } + }); + + // Add class + var $fbItem = $(this); + $fbItem + .addClass('fluidbox') + .wrapInner($fbInnerWrap) + .find('img') + .css({ opacity: 1 }) + .after('
') + .each(function(){ + var $img = $(this); + + if ($img.width() > 0 && $img.height() > 0) { + // if image is already loaded (from cache) + funcCalc($fbItem); + $fbItem.click(fbClickHandler); + } else { + // wait for image to load + $img.load(function(){ + funcCalc($fbItem); + $fbItem.click(fbClickHandler); + }); + } + }); + + } + }); + + // Listen to window resize event + // Check if user wants to debounce the resize event (it is debounced by default) + var funcResize = function () { + // Recalculate dimensions + funcCalcAll(); + + // Reposition Fluidbox, but only if one is found to be open + var $activeFb = $('a.fluidbox.fluidbox-opened'); + if($activeFb.length > 0) funcPositionFb($activeFb, 'resizeend'); + } + + if(settings.debounceResize) { + $(window).smartresize(funcResize); + } else { + $(window).resize(funcResize); + } + + // Return to allow chaining + return $fb; + }; + +})(jQuery); \ No newline at end of file diff --git a/ajax/libs/fluidbox/1.4.1/jquery.fluidbox.min.js b/ajax/libs/fluidbox/1.4.1/jquery.fluidbox.min.js new file mode 100644 index 000000000..69a955d86 --- /dev/null +++ b/ajax/libs/fluidbox/1.4.1/jquery.fluidbox.min.js @@ -0,0 +1 @@ +function whichTransitionEvent(){var a,b=document.createElement("fakeelement"),c={transition:"transitionend",OTransition:"oTransitionEnd",MozTransition:"transitionend",WebkitTransition:"webkitTransitionEnd"};for(a in c)if(void 0!==b.style[a])return c[a]}!function(a,b){var c=function(a,b,c){var d;return function(){function g(){c||a.apply(e,f),d=null}var e=this,f=arguments;d?clearTimeout(d):c&&a.apply(e,f),d=setTimeout(g,b||100)}};jQuery.fn[b]=function(a){return a?this.bind("resize",c(a)):this.trigger(b)}}(jQuery,"smartresize");var customTransitionEnd=whichTransitionEvent();!function(a){a.fn.fluidbox=function(b){var c=a.extend(!0,{viewportFill:.95,debounceResize:!0,stackIndex:1e3,stackIndexDelta:10,closeTrigger:[{selector:".fluidbox-overlay",event:"click"},{selector:"document",event:"keyup",keyCode:27}]},b);c.stackIndex",{"class":"fluidbox-overlay",css:{"z-index":c.stackIndex}});var f,d=this,e=a(window),g=function(){a(".fluidbox-opened").trigger("click")},h=function(a,b){var d=a.find("img"),g=a.find(".fluidbox-ghost"),h=a.find(".fluidbox-wrap"),i=a.data(),j=0,k=0;d.data().imgRatio=i.natWidth/i.natHeight;var l,m,n;if(f>d.data().imgRatio)j=i.natHeighth.imgRatio?e.height()*c.viewportFill/b.height():e.width()*c.viewportFill/b.width()}if(f=e.width()/e.height(),a.hasClass("fluidbox")){var b=a.find("img"),d=a.find(".fluidbox-ghost"),g=a.find(".fluidbox-wrap"),h=b.data();i(),b.load(i)}},k=function(b){if(a(this).hasClass("fluidbox")){var d=a(this),e=a(this).find("img"),f=a(this).find(".fluidbox-ghost"),g=a(this).find(".fluidbox-wrap"),i={};0!==a(this).data("fluidbox-state")&&a(this).data("fluidbox-state")?(d.trigger("closestart"),d.data("fluidbox-state",0).removeClass("fluidbox-opened").addClass("fluidbox-closed"),i.open&&window.clearTimeout(i.open),i.close=window.setTimeout(function(){a(".fluidbox-overlay").remove(),g.css({"z-index":c.stackIndex-c.stackIndexDelta})},10),a(".fluidbox-overlay").css({opacity:0}),f.css({transform:"translate(0,0) scale(1)",opacity:0,top:e.offset().top-g.offset().top+parseInt(e.css("borderTopWidth"))+parseInt(e.css("paddingTop")),left:e.offset().left-g.offset().left+parseInt(e.css("borderLeftWidth"))+parseInt(e.css("paddingLeft"))}).one(customTransitionEnd,function(){d.trigger("closeend")}),e.css({opacity:1})):(a(this).trigger("openstart"),a("",{src:e.attr("src")}).load(function(){a("",{src:d.attr("href")}).load(function(){d.data("natWidth",a(this)[0].naturalWidth).data("natHeight",a(this)[0].naturalHeight),d.append($fbOverlay).data("fluidbox-state",1).removeClass("fluidbox-closed").addClass("fluidbox-opened"),i.close&&window.clearTimeout(i.close),i.open=window.setTimeout(function(){a(".fluidbox-overlay").css({opacity:1})},10),a(".fluidbox-wrap").css({zIndex:c.stackIndex-c.stackIndexDelta-1}),g.css({"z-index":c.stackIndex+c.stackIndexDelta}),f.css({"background-image":"url("+e.attr("src")+")",opacity:1}),e.css({opacity:0}),f.css({"background-image":"url("+d.attr("href")+")"}),h(d,"openend")})})),b.preventDefault()}};c.closeTrigger&&a.each(c.closeTrigger,function(b){var d=c.closeTrigger[b];"window"!=d.selector?"document"==d.selector?d.keyCode?a(document).on(d.event,function(a){a.keyCode==d.keyCode&&g()}):a(document).on(d.event,g):a(document).on(d.event,c.closeTrigger[b].selector,g):e.on(d.event,g)}),d.each(function(){if(a(this).is("a")&&1===a(this).children().length&&a(this).children().is("img")&&"none"!==a(this).css("display")&&"none"!==a(this).parents().css("display")){var d=a("
",{"class":"fluidbox-wrap",css:{"z-index":c.stackIndex-c.stackIndexDelta}}),e=a(this);e.addClass("fluidbox").wrapInner(d).find("img").css({opacity:1}).after('
').each(function(){var b=a(this);b.width()>0&&b.height()>0?(j(e),e.click(k)):b.load(function(){j(e),e.click(k)})})}});var l=function(){i();var b=a("a.fluidbox.fluidbox-opened");b.length>0&&h(b,"resizeend")};return c.debounceResize?a(window).smartresize(l):a(window).resize(l),d}}(jQuery); \ No newline at end of file diff --git a/ajax/libs/fluidbox/package.json b/ajax/libs/fluidbox/package.json index e08df06ad..082647fb1 100644 --- a/ajax/libs/fluidbox/package.json +++ b/ajax/libs/fluidbox/package.json @@ -1,7 +1,7 @@ { "name": "fluidbox", "filename": "jquery.fluidbox.min.js", - "version": "1.4.0", + "version": "1.4.1", "description": "Replicating Medium's beautiful, minimalist lightbox module", "homepage": "https://github.com/terrymun/Fluidbox", "authors": [