pelican-red/static/js/vendor/foundation.clearing.js

517 lines
14 KiB
JavaScript

/*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">&times;</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);
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));