Created
May 11, 2013 10:35
-
-
Save m-misseri/5559580 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*jslint unparam: true, browser: true, indent: 2 */ | |
;(function ($, window, document, undefined) { | |
'use strict'; | |
Foundation.libs.clearing = { | |
name : 'clearing', | |
version : '4.1.3', | |
settings : { | |
templates : { | |
viewing : '<a href="#" class="clearing-close">×</a>' + | |
'<div class="visible-img" style="display: none"><img src="//:0">' + | |
'<p class="clearing-caption"></p><a href="#" class="clearing-main-prev"><span></span></a>' + | |
'<a href="#" class="clearing-main-next"><span></span></a></div>' | |
}, | |
// comma delimited list of selectors that, on click, will close clearing, | |
// add 'div.clearing-blackout, div.visible-img' to close on background click | |
close_selectors : '.clearing-close', | |
// event initializers and locks | |
init : false, | |
locked : false | |
}, | |
init : function (scope, method, options) { | |
var self = this; | |
Foundation.inherit(this, 'set_data get_data remove_data throttle data_options'); | |
if (typeof method === 'object') { | |
options = $.extend(true, this.settings, method); | |
} | |
if (typeof method != 'string') { | |
$(this.scope).find('ul[data-clearing]').each(function () { | |
var $el = $(this), | |
options = options || {}, | |
lis = $el.find('li'), | |
settings = self.get_data($el); | |
if (!settings && lis.length > 0) { | |
options.$parent = $el.parent(); | |
self.set_data($el, $.extend({}, self.settings, options, self.data_options($el))); | |
self.assemble($el.find('li')); | |
if (!self.settings.init) { | |
self.events().swipe_events(); | |
} | |
} | |
}); | |
return this.settings.init; | |
} else { | |
// fire method | |
return this[method].call(this, options); | |
} | |
}, | |
// event binding and initial setup | |
events : function () { | |
var self = this; | |
$(this.scope) | |
.on('click.fndtn.clearing', 'ul[data-clearing] li', | |
function (e, current, target) { | |
var current = current || $(this), | |
target = target || current, | |
next = current.next('li'), | |
settings = self.get_data(current.parent()), | |
image = $(e.target); | |
if(image[0].nodeName == 'LI'){ | |
image = image.find('img'); | |
} | |
e.preventDefault(); | |
if (!settings) self.init(); | |
// if clearing is open and the current image is | |
// clicked, go to the next image in sequence | |
if (target.hasClass('visible') | |
&& current[0] === target[0] | |
&& next.length > 0 && self.is_open(current)) { | |
target = next; | |
image = target.find('img'); | |
} | |
// set current and target to the clicked li if not otherwise defined. | |
self.open(image, current, target); | |
self.update_paddles(target); | |
}) | |
.on('click.fndtn.clearing', '.clearing-main-next', | |
function (e) { this.nav(e, 'next') }.bind(this)) | |
.on('click.fndtn.clearing', '.clearing-main-prev', | |
function (e) { this.nav(e, 'prev') }.bind(this)) | |
.on('click.fndtn.clearing', this.settings.close_selectors, | |
function (e) { Foundation.libs.clearing.close(e, this) }) | |
.on('keydown.fndtn.clearing', | |
function (e) { this.keydown(e) }.bind(this)); | |
$(window).on('resize.fndtn.clearing', | |
function () { this.resize() }.bind(this)); | |
this.settings.init = true; | |
return this; | |
}, | |
swipe_events : function () { | |
var self = this; | |
$(this.scope) | |
.on('touchstart.fndtn.clearing', '.visible-img', function(e) { | |
if (!e.touches) { e = e.originalEvent; } | |
var data = { | |
start_page_x: e.touches[0].pageX, | |
start_page_y: e.touches[0].pageY, | |
start_time: (new Date()).getTime(), | |
delta_x: 0, | |
is_scrolling: undefined | |
}; | |
$(this).data('swipe-transition', data); | |
e.stopPropagation(); | |
}) | |
.on('touchmove.fndtn.clearing', '.visible-img', function(e) { | |
if (!e.touches) { e = e.originalEvent; } | |
// Ignore pinch/zoom events | |
if(e.touches.length > 1 || e.scale && e.scale !== 1) return; | |
var data = $(this).data('swipe-transition'); | |
if (typeof data === 'undefined') { | |
data = {}; | |
} | |
data.delta_x = e.touches[0].pageX - data.start_page_x; | |
if ( typeof data.is_scrolling === 'undefined') { | |
data.is_scrolling = !!( data.is_scrolling || Math.abs(data.delta_x) < Math.abs(e.touches[0].pageY - data.start_page_y) ); | |
} | |
if (!data.is_scrolling && !data.active) { | |
e.preventDefault(); | |
var direction = (data.delta_x < 0) ? 'next' : 'prev'; | |
data.active = true; | |
self.nav(e, direction); | |
} | |
}) | |
.on('touchend.fndtn.clearing', '.visible-img', function(e) { | |
$(this).data('swipe-transition', {}); | |
e.stopPropagation(); | |
}); | |
}, | |
assemble : function ($li) { | |
var $el = $li.parent(); | |
$el.after('<div id="foundationClearingHolder"></div>'); | |
var holder = $('#foundationClearingHolder'), | |
settings = this.get_data($el), | |
grid = $el.detach(), | |
data = { | |
grid: '<div class="carousel">' + this.outerHTML(grid[0]) + '</div>', | |
viewing: settings.templates.viewing | |
}, | |
wrapper = '<div class="clearing-assembled"><div>' + data.viewing + | |
data.grid + '</div></div>'; | |
return holder.after(wrapper).remove(); | |
}, | |
// event callbacks | |
open : function ($image, current, target) { | |
var root = target.closest('.clearing-assembled'), | |
container = root.find('div').first(), | |
visible_image = container.find('.visible-img'), | |
image = visible_image.find('img').not($image); | |
if (!this.locked()) { | |
// set the image to the selected thumbnail | |
image | |
.attr('src', this.load($image)) | |
.css('visibility', 'hidden'); | |
this.loaded(image, function () { | |
image.css('visibility', 'visible'); | |
// toggle the gallery | |
root.addClass('clearing-blackout'); | |
container.addClass('clearing-container'); | |
visible_image.show(); | |
this.fix_height(target) | |
.caption(visible_image.find('.clearing-caption'), $image) | |
.center(image) | |
.shift(current, target, function () { | |
target.siblings().removeClass('visible'); | |
target.addClass('visible'); | |
}); | |
}.bind(this)); | |
} | |
}, | |
close : function (e, el) { | |
e.preventDefault(); | |
var root = (function (target) { | |
if (/blackout/.test(target.selector)) { | |
return target; | |
} else { | |
return target.closest('.clearing-blackout'); | |
} | |
}($(el))), container, visible_image; | |
if (el === e.target && root) { | |
container = root.find('div').first(); | |
visible_image = container.find('.visible-img'); | |
this.settings.prev_index = 0; | |
root.find('ul[data-clearing]') | |
.attr('style', '').closest('.clearing-blackout') | |
.removeClass('clearing-blackout'); | |
container.removeClass('clearing-container'); | |
visible_image.hide(); | |
} | |
return false; | |
}, | |
is_open : function (current) { | |
return current.parent().attr('style').length > 0; | |
}, | |
keydown : function (e) { | |
var clearing = $('.clearing-blackout').find('ul[data-clearing]'); | |
if (e.which === 39) this.go(clearing, 'next'); | |
if (e.which === 37) this.go(clearing, 'prev'); | |
if (e.which === 27) $('a.clearing-close').trigger('click'); | |
}, | |
nav : function (e, direction) { | |
var clearing = $('.clearing-blackout').find('ul[data-clearing]'); | |
e.preventDefault(); | |
this.go(clearing, direction); | |
}, | |
resize : function () { | |
var image = $('.clearing-blackout .visible-img').find('img'); | |
if (image.length) { | |
this.center(image); | |
} | |
}, | |
// visual adjustments | |
fix_height : function (target) { | |
var lis = target.parent().children(), | |
self = this; | |
lis.each(function () { | |
var li = $(this), | |
image = li.find('img'); | |
if (li.height() > self.outerHeight(image)) { | |
li.addClass('fix-height'); | |
} | |
}) | |
.closest('ul') | |
.width(lis.length * 100 + '%'); | |
return this; | |
}, | |
update_paddles : function (target) { | |
var visible_image = target | |
.closest('.carousel') | |
.siblings('.visible-img'); | |
if (target.next().length > 0) { | |
visible_image | |
.find('.clearing-main-next') | |
.removeClass('disabled'); | |
} else { | |
visible_image | |
.find('.clearing-main-next') | |
.addClass('disabled'); | |
} | |
if (target.prev().length > 0) { | |
visible_image | |
.find('.clearing-main-prev') | |
.removeClass('disabled'); | |
} else { | |
visible_image | |
.find('.clearing-main-prev') | |
.addClass('disabled'); | |
} | |
}, | |
center : function (target) { | |
if (!this.rtl) { | |
target.css({ | |
marginLeft : -(this.outerWidth(target) / 2), | |
marginTop : -(this.outerHeight(target) / 2) | |
}); | |
} else { | |
target.css({ | |
marginRight : -(this.outerWidth(target) / 2), | |
marginTop : -(this.outerHeight(target) / 2) | |
}); | |
} | |
return this; | |
}, | |
// image loading and preloading | |
load : function ($image) { | |
if ($image[0].nodeName === "A") { | |
var href = $image.attr('href'); | |
} else { | |
var href = $image.parent().attr('href'); | |
} | |
this.preload($image); | |
if (href) return href; | |
return $image.attr('src'); | |
}, | |
preload : function ($image) { | |
this | |
.img($image.closest('li').next()) | |
.img($image.closest('li').prev()); | |
}, | |
loaded : function (image, callback) { | |
// based on jquery.imageready.js | |
// @weblinc, @jsantell, (c) 2012 | |
function loaded () { | |
callback(); | |
} | |
function bindLoad () { | |
this.one('load', loaded); | |
if (/MSIE (\d+\.\d+);/.test(navigator.userAgent)) { | |
var src = this.attr( 'src' ), | |
param = src.match( /\?/ ) ? '&' : '?'; | |
param += 'random=' + (new Date()).getTime(); | |
this.attr('src', src + param); | |
} | |
} | |
if (!image.attr('src')) { | |
loaded(); | |
return; | |
} | |
if (image[0].complete || image[0].readyState === 4) { | |
loaded(); | |
} else { | |
bindLoad.call(image); | |
} | |
}, | |
img : function (img) { | |
if (img.length) { | |
var new_img = new Image(), | |
new_a = img.find('a'); | |
if (new_a.length) { | |
new_img.src = new_a.attr('href'); | |
} else { | |
new_img.src = img.find('img').attr('src'); | |
} | |
} | |
return this; | |
}, | |
// image caption | |
caption : function (container, $image) { | |
var caption = $image.data('caption'); | |
if (caption) { | |
container | |
.text(caption) | |
.show(); | |
} else { | |
container | |
.text('') | |
.hide(); | |
} | |
return this; | |
}, | |
// directional methods | |
go : function ($ul, direction) { | |
var current = $ul.find('.visible'), | |
target = current[direction](); | |
if (target.length) { | |
target | |
.find('img') | |
.trigger('click', [current, target]); | |
} | |
}, | |
shift : function (current, target, callback) { | |
var clearing = target.parent(), | |
old_index = this.settings.prev_index || target.index(), | |
direction = this.direction(clearing, current, target), | |
left = parseInt(clearing.css('left'), 10), | |
width = this.outerWidth(target), | |
skip_shift; | |
// we use jQuery animate instead of CSS transitions because we | |
// need a callback to unlock the next animation | |
if (target.index() !== old_index && !/skip/.test(direction)){ | |
if (/left/.test(direction)) { | |
this.lock(); | |
clearing.animate({left : left + width}, 300, this.unlock()); | |
} else if (/right/.test(direction)) { | |
this.lock(); | |
clearing.animate({left : left - width}, 300, this.unlock()); | |
} | |
} else if (/skip/.test(direction)) { | |
// the target image is not adjacent to the current image, so | |
// do we scroll right or not | |
skip_shift = target.index() - this.settings.up_count; | |
this.lock(); | |
if (skip_shift > 0) { | |
clearing.animate({left : -(skip_shift * width)}, 300, this.unlock()); | |
} else { | |
clearing.animate({left : 0}, 300, this.unlock()); | |
} | |
} | |
callback(); | |
}, | |
direction : function ($el, current, target) { | |
var lis = $el.find('li'), | |
li_width = this.outerWidth(lis) + (this.outerWidth(lis) / 4), | |
up_count = Math.floor(this.outerWidth($('.clearing-container')) / li_width) - 1, | |
target_index = lis.index(target), | |
response; | |
this.settings.up_count = up_count; | |
if (this.adjacent(this.settings.prev_index, target_index)) { | |
if ((target_index > up_count) | |
&& target_index > this.settings.prev_index) { | |
response = 'right'; | |
} else if ((target_index > up_count - 1) | |
&& target_index <= this.settings.prev_index) { | |
response = 'left'; | |
} else { | |
response = false; | |
} | |
} else { | |
response = 'skip'; | |
} | |
this.settings.prev_index = target_index; | |
return response; | |
}, | |
adjacent : function (current_index, target_index) { | |
for (var i = target_index + 1; i >= target_index - 1; i--) { | |
if (i === current_index) return true; | |
} | |
return false; | |
}, | |
// lock management | |
lock : function () { | |
this.settings.locked = true; | |
}, | |
unlock : function () { | |
this.settings.locked = false; | |
}, | |
locked : function () { | |
return this.settings.locked; | |
}, | |
// plugin management/browser quirks | |
outerHTML : function (el) { | |
// support FireFox < 11 | |
return el.outerHTML || new XMLSerializer().serializeToString(el); | |
}, | |
off : function () { | |
$(this.scope).off('.fndtn.clearing'); | |
$(window).off('.fndtn.clearing'); | |
this.remove_data(); // empty settings cache | |
this.settings.init = false; | |
}, | |
reflow : function () { | |
this.init(); | |
} | |
}; | |
}(Foundation.zj, this, this.document)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment