text: /*jslint unparam: true, browser: true, indent: 2 */
  
  ;
  (function ($, window, document, undefined) {
      'use strict';
  
      Foundation.libs.clearing = {
          name: 'clearing',
  
          version: '4.3.1',
  
          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
                      .html(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));
  