559 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			559 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| ;(function ($, window, document, undefined) {
 | |
|   'use strict';
 | |
| 
 | |
|   Foundation.libs.clearing = {
 | |
|     name : 'clearing',
 | |
| 
 | |
|     version: '5.4.7',
 | |
| 
 | |
|     settings : {
 | |
|       templates : {
 | |
|         viewing : '<a href="#" class="clearing-close">×</a>' +
 | |
|           '<div class="visible-img" style="display: none"><div class="clearing-touch-label"></div><img src="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs%3D" alt="" />' +
 | |
|           '<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, div.clearing-blackout', 
 | |
| 
 | |
|       // Default to the entire li element.
 | |
|       open_selectors : '',
 | |
| 
 | |
|       // Image will be skipped in carousel.
 | |
|       skip_selector : '',
 | |
| 
 | |
|       touch_label : '',
 | |
| 
 | |
|       // event initializers and locks
 | |
|       init : false,
 | |
|       locked : false
 | |
|     },
 | |
| 
 | |
|     init : function (scope, method, options) {
 | |
|       var self = this;
 | |
|       Foundation.inherit(this, 'throttle image_loaded');
 | |
| 
 | |
|       this.bindings(method, options);
 | |
| 
 | |
|       if (self.S(this.scope).is('[' + this.attr_name() + ']')) {
 | |
|         this.assemble(self.S('li', this.scope));
 | |
|       } else {
 | |
|         self.S('[' + this.attr_name() + ']', this.scope).each(function () {
 | |
|           self.assemble(self.S('li', this));
 | |
|         });
 | |
|       }
 | |
|     },
 | |
| 
 | |
|     events : function (scope) {
 | |
|       var self = this,
 | |
|           S = self.S,
 | |
|           $scroll_container = $('.scroll-container');
 | |
| 
 | |
|       if ($scroll_container.length > 0) {
 | |
|         this.scope = $scroll_container;
 | |
|       }
 | |
| 
 | |
|       S(this.scope)
 | |
|         .off('.clearing')
 | |
|         .on('click.fndtn.clearing', 'ul[' + this.attr_name() + '] li ' + this.settings.open_selectors,
 | |
|           function (e, current, target) {
 | |
|             var current = current || S(this),
 | |
|                 target = target || current,
 | |
|                 next = current.next('li'),
 | |
|                 settings = current.closest('[' + self.attr_name() + ']').data(self.attr_name(true) + '-init'),
 | |
|                 image = S(e.target);
 | |
| 
 | |
|             e.preventDefault();
 | |
| 
 | |
|             if (!settings) {
 | |
|               self.init();
 | |
|               settings = current.closest('[' + self.attr_name() + ']').data(self.attr_name(true) + '-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 = S('img', target);
 | |
|             }
 | |
| 
 | |
|             // 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) { self.nav(e, 'next') })
 | |
|         .on('click.fndtn.clearing', '.clearing-main-prev',
 | |
|           function (e) { self.nav(e, 'prev') })
 | |
|         .on('click.fndtn.clearing', this.settings.close_selectors,
 | |
|           function (e) { Foundation.libs.clearing.close(e, this) });
 | |
| 
 | |
|       $(document).on('keydown.fndtn.clearing',
 | |
|           function (e) { self.keydown(e) });
 | |
| 
 | |
|       S(window).off('.clearing').on('resize.fndtn.clearing',
 | |
|         function () { self.resize() });
 | |
| 
 | |
|       this.swipe_events(scope);
 | |
|     },
 | |
| 
 | |
|     swipe_events : function (scope) {
 | |
|       var self = this,
 | |
|       S = self.S;
 | |
| 
 | |
|       S(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
 | |
|               };
 | |
| 
 | |
|           S(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 = S(this).data('swipe-transition');
 | |
| 
 | |
|           if (typeof data === 'undefined') {
 | |
|             data = {};
 | |
|           }
 | |
| 
 | |
|           data.delta_x = e.touches[0].pageX - data.start_page_x;
 | |
| 
 | |
|           if (Foundation.rtl) {
 | |
|             data.delta_x = -data.delta_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) {
 | |
|           S(this).data('swipe-transition', {});
 | |
|           e.stopPropagation();
 | |
|         });
 | |
|     },
 | |
| 
 | |
|     assemble : function ($li) {
 | |
|       var $el = $li.parent();
 | |
| 
 | |
|       if ($el.parent().hasClass('carousel')) {
 | |
|         return;
 | |
|       }
 | |
|       
 | |
|       $el.after('<div id="foundationClearingHolder"></div>');
 | |
| 
 | |
|       var grid = $el.detach(),
 | |
|           grid_outerHTML = '';
 | |
| 
 | |
|       if (grid[0] == null) {
 | |
|         return;
 | |
|       } else {
 | |
|         grid_outerHTML = grid[0].outerHTML;
 | |
|       }
 | |
|       
 | |
|       var holder = this.S('#foundationClearingHolder'),
 | |
|           settings = $el.data(this.attr_name(true) + '-init'),
 | |
|           data = {
 | |
|             grid: '<div class="carousel">' + grid_outerHTML + '</div>',
 | |
|             viewing: settings.templates.viewing
 | |
|           },
 | |
|           wrapper = '<div class="clearing-assembled"><div>' + data.viewing +
 | |
|             data.grid + '</div></div>',
 | |
|           touch_label = this.settings.touch_label;
 | |
| 
 | |
|       if (Modernizr.touch) {
 | |
|         wrapper = $(wrapper).find('.clearing-touch-label').html(touch_label).end();
 | |
|       }
 | |
| 
 | |
|       holder.after(wrapper).remove();
 | |
|     },
 | |
| 
 | |
|     open : function ($image, current, target) {
 | |
|       var self = this,
 | |
|           body = $(document.body),
 | |
|           root = target.closest('.clearing-assembled'),
 | |
|           container = self.S('div', root).first(),
 | |
|           visible_image = self.S('.visible-img', container),
 | |
|           image = self.S('img', visible_image).not($image),
 | |
|           label = self.S('.clearing-touch-label', container),
 | |
|           error = false;
 | |
| 
 | |
|       // Event to disable scrolling on touch devices when Clearing is activated
 | |
|       $('body').on('touchmove',function(e){
 | |
|         e.preventDefault();
 | |
|       });
 | |
| 
 | |
|       image.error(function () {
 | |
|         error = true;
 | |
|       });
 | |
| 
 | |
|       function startLoad() {
 | |
|         setTimeout(function () {
 | |
|           this.image_loaded(image, function () {
 | |
|             if (image.outerWidth() === 1 && !error) {
 | |
|               startLoad.call(this);
 | |
|             } else {
 | |
|               cb.call(this, image);
 | |
|             }
 | |
|           }.bind(this));
 | |
|         }.bind(this), 100);
 | |
|       }
 | |
| 
 | |
|       function cb (image) {
 | |
|         var $image = $(image);
 | |
|         $image.css('visibility', 'visible');
 | |
|         // toggle the gallery
 | |
|         body.css('overflow', 'hidden');
 | |
|         root.addClass('clearing-blackout');
 | |
|         container.addClass('clearing-container');
 | |
|         visible_image.show();
 | |
|         this.fix_height(target)
 | |
|           .caption(self.S('.clearing-caption', visible_image), self.S('img', target))
 | |
|           .center_and_label(image, label)
 | |
|           .shift(current, target, function () {
 | |
|             target.closest('li').siblings().removeClass('visible');
 | |
|             target.closest('li').addClass('visible');
 | |
|           });
 | |
|         visible_image.trigger('opened.fndtn.clearing')
 | |
|       }
 | |
| 
 | |
|       if (!this.locked()) {
 | |
|         visible_image.trigger('open.fndtn.clearing');
 | |
|         // set the image to the selected thumbnail
 | |
|         image
 | |
|           .attr('src', this.load($image))
 | |
|           .css('visibility', 'hidden');
 | |
| 
 | |
|         startLoad.call(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))),
 | |
|           body = $(document.body), container, visible_image;
 | |
| 
 | |
|       if (el === e.target && root) {
 | |
|         body.css('overflow', '');
 | |
|         container = $('div', root).first();
 | |
|         visible_image = $('.visible-img', container);
 | |
|         visible_image.trigger('close.fndtn.clearing');
 | |
|         this.settings.prev_index = 0;
 | |
|         $('ul[' + this.attr_name() + ']', root)
 | |
|           .attr('style', '').closest('.clearing-blackout')
 | |
|           .removeClass('clearing-blackout');
 | |
|         container.removeClass('clearing-container');
 | |
|         visible_image.hide();
 | |
|         visible_image.trigger('closed.fndtn.clearing');        
 | |
|       }
 | |
| 
 | |
|       // Event to re-enable scrolling on touch devices
 | |
|       $('body').off('touchmove');
 | |
| 
 | |
|       return false;
 | |
|     },
 | |
| 
 | |
|     is_open : function (current) {
 | |
|       return current.parent().prop('style').length > 0;
 | |
|     },
 | |
| 
 | |
|     keydown : function (e) {
 | |
|       var clearing = $('.clearing-blackout ul[' + this.attr_name() + ']'),
 | |
|           NEXT_KEY = this.rtl ? 37 : 39,
 | |
|           PREV_KEY = this.rtl ? 39 : 37,
 | |
|           ESC_KEY = 27;
 | |
| 
 | |
|       if (e.which === NEXT_KEY) this.go(clearing, 'next');
 | |
|       if (e.which === PREV_KEY) this.go(clearing, 'prev');
 | |
|       if (e.which === ESC_KEY) this.S('a.clearing-close').trigger('click').trigger('click.fndtn.clearing');
 | |
|     },
 | |
| 
 | |
|     nav : function (e, direction) {
 | |
|       var clearing = $('ul[' + this.attr_name() + ']', '.clearing-blackout');
 | |
| 
 | |
|       e.preventDefault();
 | |
|       this.go(clearing, direction);
 | |
|     },
 | |
| 
 | |
|     resize : function () {
 | |
|       var image = $('img', '.clearing-blackout .visible-img'),
 | |
|           label = $('.clearing-touch-label', '.clearing-blackout');
 | |
| 
 | |
|       if (image.length) {
 | |
|         this.center_and_label(image, label);
 | |
|         image.trigger('resized.fndtn.clearing')
 | |
|       }
 | |
|     },
 | |
| 
 | |
|     // visual adjustments
 | |
|     fix_height : function (target) {
 | |
|       var lis = target.parent().children(),
 | |
|           self = this;
 | |
| 
 | |
|       lis.each(function () {
 | |
|         var li = self.S(this),
 | |
|             image = li.find('img');
 | |
| 
 | |
|         if (li.height() > image.outerHeight()) {
 | |
|           li.addClass('fix-height');
 | |
|         }
 | |
|       })
 | |
|       .closest('ul')
 | |
|       .width(lis.length * 100 + '%');
 | |
| 
 | |
|       return this;
 | |
|     },
 | |
| 
 | |
|     update_paddles : function (target) {
 | |
|       target = target.closest('li');
 | |
|       var visible_image = target
 | |
|         .closest('.carousel')
 | |
|         .siblings('.visible-img');
 | |
| 
 | |
|       if (target.next().length > 0) {
 | |
|         this.S('.clearing-main-next', visible_image).removeClass('disabled');
 | |
|       } else {
 | |
|         this.S('.clearing-main-next', visible_image).addClass('disabled');
 | |
|       }
 | |
| 
 | |
|       if (target.prev().length > 0) {
 | |
|         this.S('.clearing-main-prev', visible_image).removeClass('disabled');
 | |
|       } else {
 | |
|         this.S('.clearing-main-prev', visible_image).addClass('disabled');
 | |
|       }
 | |
|     },
 | |
| 
 | |
|     center_and_label : function (target, label) {
 | |
|       if (!this.rtl) {
 | |
|         target.css({
 | |
|           marginLeft : -(target.outerWidth() / 2),
 | |
|           marginTop : -(target.outerHeight() / 2)
 | |
|         });
 | |
| 
 | |
|         if (label.length > 0) {
 | |
|           label.css({
 | |
|             marginLeft : -(label.outerWidth() / 2),
 | |
|             marginTop : -(target.outerHeight() / 2)-label.outerHeight()-10
 | |
|           });
 | |
|         }
 | |
|       } else {
 | |
|         target.css({
 | |
|           marginRight : -(target.outerWidth() / 2),
 | |
|           marginTop : -(target.outerHeight() / 2),
 | |
|           left: 'auto',
 | |
|           right: '50%'
 | |
|         });
 | |
| 
 | |
|         if (label.length > 0) {
 | |
|           label.css({
 | |
|             marginRight : -(label.outerWidth() / 2),
 | |
|             marginTop : -(target.outerHeight() / 2)-label.outerHeight()-10,
 | |
|             left: 'auto',
 | |
|             right: '50%'
 | |
|           });
 | |
|         }
 | |
|       }
 | |
|       return this;
 | |
|     },
 | |
| 
 | |
|     // image loading and preloading
 | |
| 
 | |
|     load : function ($image) {
 | |
|       var href;
 | |
| 
 | |
|       if ($image[0].nodeName === "A") {
 | |
|         href = $image.attr('href');
 | |
|       } else {
 | |
|         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());
 | |
|     },
 | |
| 
 | |
|     img : function (img) {
 | |
|       if (img.length) {
 | |
|         var new_img = new Image(),
 | |
|             new_a = this.S('a', img);
 | |
| 
 | |
|         if (new_a.length) {
 | |
|           new_img.src = new_a.attr('href');
 | |
|         } else {
 | |
|           new_img.src = this.S('img', img).attr('src');
 | |
|         }
 | |
|       }
 | |
|       return this;
 | |
|     },
 | |
| 
 | |
|     // image caption
 | |
| 
 | |
|     caption : function (container, $image) {
 | |
|       var caption = $image.attr('data-caption');
 | |
| 
 | |
|       if (caption) {
 | |
|         container
 | |
|           .html(caption)
 | |
|           .show();
 | |
|       } else {
 | |
|         container
 | |
|           .text('')
 | |
|           .hide();
 | |
|       }
 | |
|       return this;
 | |
|     }, 
 | |
| 
 | |
|     // directional methods
 | |
| 
 | |
|     go : function ($ul, direction) {
 | |
|       var current = this.S('.visible', $ul),
 | |
|           target = current[direction]();
 | |
| 
 | |
|       // Check for skip selector.
 | |
|       if (this.settings.skip_selector && target.find(this.settings.skip_selector).length != 0) {
 | |
|         target = target[direction]();
 | |
|       }
 | |
| 
 | |
|       if (target.length) {
 | |
|         this.S('img', target)
 | |
|           .trigger('click', [current, target]).trigger('click.fndtn.clearing', [current, target])
 | |
|           .trigger('change.fndtn.clearing');
 | |
|       }
 | |
|     },
 | |
| 
 | |
|     shift : function (current, target, callback) {
 | |
|       var clearing = target.parent(),
 | |
|           old_index = this.settings.prev_index || target.index(),
 | |
|           direction = this.direction(clearing, current, target),
 | |
|           dir = this.rtl ? 'right' : 'left',
 | |
|           left = parseInt(clearing.css('left'), 10),
 | |
|           width = target.outerWidth(),
 | |
|           skip_shift;
 | |
| 
 | |
|       var dir_obj = {};
 | |
| 
 | |
|       // we use jQuery animate instead of CSS transitions because we
 | |
|       // need a callback to unlock the next animation
 | |
|       // needs support for RTL **
 | |
|       if (target.index() !== old_index && !/skip/.test(direction)){
 | |
|         if (/left/.test(direction)) {
 | |
|           this.lock();
 | |
|           dir_obj[dir] = left + width;
 | |
|           clearing.animate(dir_obj, 300, this.unlock());
 | |
|         } else if (/right/.test(direction)) {
 | |
|           this.lock();
 | |
|           dir_obj[dir] = left - width;
 | |
|           clearing.animate(dir_obj, 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) {
 | |
|           dir_obj[dir] = -(skip_shift * width);
 | |
|           clearing.animate(dir_obj, 300, this.unlock());
 | |
|         } else {
 | |
|           dir_obj[dir] = 0;
 | |
|           clearing.animate(dir_obj, 300, this.unlock());
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       callback();
 | |
|     },
 | |
| 
 | |
|     direction : function ($el, current, target) {
 | |
|       var lis = this.S('li', $el),
 | |
|           li_width = lis.outerWidth() + (lis.outerWidth() / 4),
 | |
|           up_count = Math.floor(this.S('.clearing-container').outerWidth() / 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;
 | |
|     },
 | |
| 
 | |
|     off : function () {
 | |
|       this.S(this.scope).off('.fndtn.clearing');
 | |
|       this.S(window).off('.fndtn.clearing');
 | |
|     },
 | |
| 
 | |
|     reflow : function () {
 | |
|       this.init();
 | |
|     }
 | |
|   };
 | |
| 
 | |
| }(jQuery, window, window.document));
 |