1/*jslint unparam: true, browser: true, indent: 2 */ 2 3;(function ($, window, document, undefined) { 4 'use strict'; 5 6 Foundation.libs.clearing = { 7 name : 'clearing', 8 9 version: '4.3.1', 10 11 settings : { 12 templates : { 13 viewing : '<a href="#" class="clearing-close">×</a>' + 14 '<div class="visible-img" style="display: none"><img src="//:0">' + 15 '<p class="clearing-caption"></p><a href="#" class="clearing-main-prev"><span></span></a>' + 16 '<a href="#" class="clearing-main-next"><span></span></a></div>' 17 }, 18 19 // comma delimited list of selectors that, on click, will close clearing, 20 // add 'div.clearing-blackout, div.visible-img' to close on background click 21 close_selectors : '.clearing-close', 22 23 // event initializers and locks 24 init : false, 25 locked : false 26 }, 27 28 init : function (scope, method, options) { 29 var self = this; 30 Foundation.inherit(this, 'set_data get_data remove_data throttle data_options'); 31 32 if (typeof method === 'object') { 33 options = $.extend(true, this.settings, method); 34 } 35 36 if (typeof method !== 'string') { 37 $(this.scope).find('ul[data-clearing]').each(function () { 38 var $el = $(this), 39 options = options || {}, 40 lis = $el.find('li'), 41 settings = self.get_data($el); 42 43 if (!settings && lis.length > 0) { 44 options.$parent = $el.parent(); 45 46 self.set_data($el, $.extend({}, self.settings, options, self.data_options($el))); 47 48 self.assemble($el.find('li')); 49 50 if (!self.settings.init) { 51 self.events().swipe_events(); 52 } 53 } 54 }); 55 56 return this.settings.init; 57 } else { 58 // fire method 59 return this[method].call(this, options); 60 } 61 }, 62 63 // event binding and initial setup 64 65 events : function () { 66 var self = this; 67 68 $(this.scope) 69 .on('click.fndtn.clearing', 'ul[data-clearing] li', 70 function (e, current, target) { 71 var current = current || $(this), 72 target = target || current, 73 next = current.next('li'), 74 settings = self.get_data(current.parent()), 75 image = $(e.target); 76 77 e.preventDefault(); 78 if (!settings) self.init(); 79 80 // if clearing is open and the current image is 81 // clicked, go to the next image in sequence 82 if (target.hasClass('visible') && 83 current[0] === target[0] && 84 next.length > 0 && self.is_open(current)) { 85 target = next; 86 image = target.find('img'); 87 } 88 89 // set current and target to the clicked li if not otherwise defined. 90 self.open(image, current, target); 91 self.update_paddles(target); 92 }) 93 94 .on('click.fndtn.clearing', '.clearing-main-next', 95 function (e) { this.nav(e, 'next') }.bind(this)) 96 .on('click.fndtn.clearing', '.clearing-main-prev', 97 function (e) { this.nav(e, 'prev') }.bind(this)) 98 .on('click.fndtn.clearing', this.settings.close_selectors, 99 function (e) { Foundation.libs.clearing.close(e, this) }) 100 .on('keydown.fndtn.clearing', 101 function (e) { this.keydown(e) }.bind(this)); 102 103 $(window).on('resize.fndtn.clearing', 104 function () { this.resize() }.bind(this)); 105 106 this.settings.init = true; 107 return this; 108 }, 109 110 swipe_events : function () { 111 var self = this; 112 113 $(this.scope) 114 .on('touchstart.fndtn.clearing', '.visible-img', function(e) { 115 if (!e.touches) { e = e.originalEvent; } 116 var data = { 117 start_page_x: e.touches[0].pageX, 118 start_page_y: e.touches[0].pageY, 119 start_time: (new Date()).getTime(), 120 delta_x: 0, 121 is_scrolling: undefined 122 }; 123 124 $(this).data('swipe-transition', data); 125 e.stopPropagation(); 126 }) 127 .on('touchmove.fndtn.clearing', '.visible-img', function(e) { 128 if (!e.touches) { e = e.originalEvent; } 129 // Ignore pinch/zoom events 130 if(e.touches.length > 1 || e.scale && e.scale !== 1) return; 131 132 var data = $(this).data('swipe-transition'); 133 134 if (typeof data === 'undefined') { 135 data = {}; 136 } 137 138 data.delta_x = e.touches[0].pageX - data.start_page_x; 139 140 if ( typeof data.is_scrolling === 'undefined') { 141 data.is_scrolling = !!( data.is_scrolling || Math.abs(data.delta_x) < Math.abs(e.touches[0].pageY - data.start_page_y) ); 142 } 143 144 if (!data.is_scrolling && !data.active) { 145 e.preventDefault(); 146 var direction = (data.delta_x < 0) ? 'next' : 'prev'; 147 data.active = true; 148 self.nav(e, direction); 149 } 150 }) 151 .on('touchend.fndtn.clearing', '.visible-img', function(e) { 152 $(this).data('swipe-transition', {}); 153 e.stopPropagation(); 154 }); 155 }, 156 157 assemble : function ($li) { 158 var $el = $li.parent(); 159 $el.after('<div id="foundationClearingHolder"></div>'); 160 161 var holder = $('#foundationClearingHolder'), 162 settings = this.get_data($el), 163 grid = $el.detach(), 164 data = { 165 grid: '<div class="carousel">' + this.outerHTML(grid[0]) + '</div>', 166 viewing: settings.templates.viewing 167 }, 168 wrapper = '<div class="clearing-assembled"><div>' + data.viewing + 169 data.grid + '</div></div>'; 170 171 return holder.after(wrapper).remove(); 172 }, 173 174 // event callbacks 175 176 open : function ($image, current, target) { 177 var root = target.closest('.clearing-assembled'), 178 container = root.find('div').first(), 179 visible_image = container.find('.visible-img'), 180 image = visible_image.find('img').not($image); 181 182 if (!this.locked()) { 183 // set the image to the selected thumbnail 184 image 185 .attr('src', this.load($image)) 186 .css('visibility', 'hidden'); 187 188 this.loaded(image, function () { 189 image.css('visibility', 'visible'); 190 // toggle the gallery 191 root.addClass('clearing-blackout'); 192 container.addClass('clearing-container'); 193 visible_image.show(); 194 this.fix_height(target) 195 .caption(visible_image.find('.clearing-caption'), $image) 196 .center(image) 197 .shift(current, target, function () { 198 target.siblings().removeClass('visible'); 199 target.addClass('visible'); 200 }); 201 }.bind(this)); 202 } 203 }, 204 205 close : function (e, el) { 206 e.preventDefault(); 207 208 var root = (function (target) { 209 if (/blackout/.test(target.selector)) { 210 return target; 211 } else { 212 return target.closest('.clearing-blackout'); 213 } 214 }($(el))), container, visible_image; 215 216 if (el === e.target && root) { 217 container = root.find('div').first(); 218 visible_image = container.find('.visible-img'); 219 this.settings.prev_index = 0; 220 root.find('ul[data-clearing]') 221 .attr('style', '').closest('.clearing-blackout') 222 .removeClass('clearing-blackout'); 223 container.removeClass('clearing-container'); 224 visible_image.hide(); 225 } 226 227 return false;
228 }, 229 230 is_open : function (current) { 231 return current.parent().attr('style').length > 0; 232 }, 233 234 keydown : function (e) { 235 var clearing = $('.clearing-blackout').find('ul[data-clearing]'); 236 237 if (e.which === 39) this.go(clearing, 'next'); 238 if (e.which === 37) this.go(clearing, 'prev'); 239 if (e.which === 27) $('a.clearing-close').trigger('click'); 240 }, 241 242 nav : function (e, direction) { 243 var clearing = $('.clearing-blackout').find('ul[data-clearing]'); 244 245 e.preventDefault(); 246 this.go(clearing, direction); 247 }, 248 249 resize : function () { 250 var image = $('.clearing-blackout .visible-img').find('img'); 251 252 if (image.length) { 253 this.center(image); 254 } 255 }, 256 257 // visual adjustments 258 fix_height : function (target) { 259 var lis = target.parent().children(), 260 self = this; 261 262 lis.each(function () { 263 var li = $(this), 264 image = li.find('img'); 265 266 if (li.height() > self.outerHeight(image)) { 267 li.addClass('fix-height'); 268 } 269 }) 270 .closest('ul') 271 .width(lis.length * 100 + '%'); 272 273 return this; 274 }, 275 276 update_paddles : function (target) { 277 var visible_image = target 278 .closest('.carousel') 279 .siblings('.visible-img'); 280 281 if (target.next().length > 0) { 282 visible_image 283 .find('.clearing-main-next') 284 .removeClass('disabled'); 285 } else { 286 visible_image 287 .find('.clearing-main-next') 288 .addClass('disabled'); 289 } 290 291 if (target.prev().length > 0) { 292 visible_image 293 .find('.clearing-main-prev') 294 .removeClass('disabled'); 295 } else { 296 visible_image 297 .find('.clearing-main-prev') 298 .addClass('disabled'); 299 } 300 }, 301 302 center : function (target) { 303 if (!this.rtl) { 304 target.css({ 305 marginLeft : -(this.outerWidth(target) / 2), 306 marginTop : -(this.outerHeight(target) / 2) 307 }); 308 } else { 309 target.css({ 310 marginRight : -(this.outerWidth(target) / 2), 311 marginTop : -(this.outerHeight(target) / 2) 312 }); 313 } 314 return this; 315 }, 316 317 // image loading and preloading 318 319 load : function ($image) { 320 if ($image[0].nodeName === "A") { 321 var href = $image.attr('href'); 322 } else { 323 var href = $image.parent().attr('href'); 324 } 325 326 this.preload($image); 327 328 if (href) return href; 329 return $image.attr('src'); 330 }, 331 332 preload : function ($image) { 333 this 334 .img($image.closest('li').next()) 335 .img($image.closest('li').prev()); 336 }, 337 338 loaded : function (image, callback) { 339 // based on jquery.imageready.js 340 // @weblinc, @jsantell, (c) 2012 341 342 function loaded () { 343 callback(); 344 } 345 346 function bindLoad () { 347 this.one('load', loaded); 348 349 if (/MSIE (\d+\.\d+);/.test(navigator.userAgent)) { 350 var src = this.attr( 'src' ), 351 param = src.match( /\?/ ) ? '&' : '?'; 352 353 param += 'random=' + (new Date()).getTime(); 354 this.attr('src', src + param); 355 } 356 } 357 358 if (!image.attr('src')) { 359 loaded(); 360 return; 361 } 362 363 if (image[0].complete || image[0].readyState === 4) { 364 loaded(); 365 } else { 366 bindLoad.call(image); 367 } 368 }, 369 370 img : function (img) { 371 if (img.length) { 372 var new_img = new Image(), 373 new_a = img.find('a'); 374 375 if (new_a.length) { 376 new_img.src = new_a.attr('href'); 377 } else { 378 new_img.src = img.find('img').attr('src'); 379 } 380 } 381 return this; 382 }, 383 384 // image caption 385 386 caption : function (container, $image) { 387 var caption = $image.data('caption'); 388 389 if (caption) { 390 container 391 .html(caption) 392 .show(); 393 } else { 394 container 395 .text('') 396 .hide(); 397 } 398 return this; 399 }, 400 401 // directional methods 402 403 go : function ($ul, direction) { 404 var current = $ul.find('.visible'), 405 target = current[direction](); 406 407 if (target.length) { 408 target 409 .find('img') 410 .trigger('click', [current, target]); 411 } 412 }, 413 414 shift : function (current, target, callback) { 415 var clearing = target.parent(), 416 old_index = this.settings.prev_index || target.index(), 417 direction = this.direction(clearing, current, target), 418 left = parseInt(clearing.css('left'), 10), 419 width = this.outerWidth(target), 420 skip_shift; 421 422 // we use jQuery animate instead of CSS transitions because we 423 // need a callback to unlock the next animation 424 if (target.index() !== old_index && !/skip/.test(direction)){ 425 if (/left/.test(direction)) { 426 this.lock(); 427 clearing.animate({left : left + width}, 300, this.unlock()); 428 } else if (/right/.test(direction)) { 429 this.lock(); 430 clearing.animate({left : left - width}, 300, this.unlock()); 431 } 432 } else if (/skip/.test(direction)) { 433 // the target image is not adjacent to the current image, so 434 // do we scroll right or not 435 skip_shift = target.index() - this.settings.up_count; 436 this.lock(); 437 438 if (skip_shift > 0) { 439 clearing.animate({left : -(skip_shift * width)}, 300, this.unlock()); 440 } else { 441 clearing.animate({left : 0}, 300, this.unlock()); 442 } 443 } 444 445 callback(); 446 }, 447 448 direction : function ($el, current, target) { 449 var lis = $el.find('li'), 450 li_width = this.outerWidth(lis) + (this.outerWidth(lis) / 4), 451 up_count = Math.floor(this.outerWidth($('.clearing-container')) / li_width) - 1, 452 target_index = lis.index(target), 453 response; 454 455 this.settings.up_count = up_count; 456 457 if (this.adjacent(this.settings.prev_index, target_index)) { 458 if ((target_index > up_count) 459 && target_index > this.settings.prev_index) { 460 response = 'right'; 461 } else if ((target_index > up_count - 1) 462 && target_index <= this.settings.prev_index) { 463 response = 'left'; 464 } else { 465 response = false;
466 } 467 } else { 468 response = 'skip'; 469 } 470 471 this.settings.prev_index = target_index; 472 473 return response; 474 }, 475 476 adjacent : function (current_index, target_index) { 477 for (var i = target_index + 1; i >= target_index - 1; i--) { 478 if (i === current_index) return true; 479 } 480 return false; 481 }, 482 483 // lock management 484 485 lock : function () { 486 this.settings.locked = true; 487 }, 488 489 unlock : function () { 490 this.settings.locked = false; 491 }, 492 493 locked : function () { 494 return this.settings.locked; 495 }, 496 497 // plugin management/browser quirks 498 499 outerHTML : function (el) { 500 // support FireFox < 11 501 return el.outerHTML || new XMLSerializer().serializeToString(el); 502 }, 503 504 off : function () { 505 $(this.scope).off('.fndtn.clearing'); 506 $(window).off('.fndtn.clearing'); 507 this.remove_data(); // empty settings cache 508 this.settings.init = false; 509 }, 510 511 reflow : function () { 512 this.init(); 513 } 514 }; 515 516}(Foundation.zj, this, this.document));
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.