1/** 2 * <div class="carousel2 prevent-anim"> 3 * <div class="carousel-contents"> 4 * <div class="carousel-content">content1</div> 5 * <div class="carousel-content">content2</div> 6 * <div class="carousel-content">content3</div> 7 * : 8 * </div> 9 * </div> 10 * 11 * initialize: 12 * $('.carousel2').carousel2(); 13 * If carousel is already initialized, do nothing. 14 * 'reset' is re-initialize. 15 * 16 * data-carousel-anim:(|crossfade|roll-horiz|roll-down|roll-up|slidein-left|slidein-right|slidein-down|slidein-up|turn-vert|turn-horiz|flip-up|flip-down|flip-right|flip-left) 17 * default:roll-horiz 18 * data-carousel-duration:{anim duration:number} in ms 19 * default:500 20 * data-carousel-autoanim: (none|{delay:number}ms,{interval:number}ms) 21 * default:7000,3000 22 * data-carousel-nav:(none|below|below-point|below-manip|over|over-point|over-manip) 23 * default:below 24 * data-carousel-navrel:(0|1) 25 * default:1 26 * 27 * $carousel.carouselw() : no effect (.carousel-valid) 28 * $carousel.carousel2(cmd, arg) 29 * play,pause,rewind,stop : manipulate autoanim 30 * reset : re-configure 31 * destroy : stop autoanim and remove temp classes for save html 32 * 33 * connectsettings: connect :inputs for data-carousel-XXXX 34 * argument: 35 * { 36 * anim: $input_for_anim, 37 * duration: $input_for_duration, 38 * autoanim: $input_for_autoanim, 39 * nav: $input_for_nav 40 * navrel: $input_for_navrel 41 * } 42 */ 43 44// console.error('jquery-carousel-2'); 45 46$(function() { 47 48if ($('#carousel2-loaded')[0]){ 49 console.error('juquery-carousel-2/jquery-carousel.js is already loaded.'); 50 return; 51} 52var css_loaded = false; 53$('<div id="carousel2-loaded"></div>') 54 .appendTo('body') 55 .each(function(){ css_loaded = window.getComputedStyle(this,':before').content }); 56 57if (!css_loaded) { 58 console.log('jquery-carousel2:load css'); 59 $('<link></link>').attr({ 60 rel:'stylesheet', 61 href:'/static/lib/jquery-carousel-2/jquery-carousel.css' 62 }) 63 .appendTo('head'); 64 /* 65 var css_href = $('script[src*="jquery-carousel.js"]').attr('src').replace('jqueyr-carousel.js', 'jquery-carousel.css'); 66 if (!css_href) { 67 console.error('jquery-carousel.css is not found'); 68 } else { 69 $('<link></link>').attr({ 70 rel:'stylesheet', 71 href:css_href 72 }) 73 .appendTo('head'); 74 } 75 */ 76} 77 78 79if (!$.assureUniqId) { 80 // unique id 81 $.fn.extend({ 82 83 assureUniqId: function(prefix, context) { 84 /** 85 * assure all elements ids are unique. 86 * if target element has already have unique id in context, no effect. 87 * if it doesn't have id or not unique, new unique (in the world) id is assigned. 88 * 'unique' is based on RFC4122 version4 and base62 encoded. 89 */ 90 // assign prefix + generated uuid(62) as elements id when it is not have id or id is not unique in context. 91 prefix = prefix || 'asuq-'; 92 return $(this).each(function() { 93 var org_id = $(this).attr('id'); 94 if (org_id) { 95 var $ids = $('[id]', context).filter(function() { 96 return this.id == org_id 97 }); 98 if ($ids.length > 1) { 99 // duplicated id 100 console.error('assureUniqId:duplicated id is found:' + org_id, $ids); 101 $(this).attr('data-duplicated-id', org_id); 102 } else { 103 // already have unique id in context 104 return; 105 } 106 } 107 $(this).attr('id', prefix + $.generateUUID4(62)); 108 }); 109 }, 110 }); 111 $.extend({ 112 toBase: function(num, base) { 113 var chars, type = typeof base, 114 use_chars = false; 115 if (type == 'number') { 116 chars = '01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; 117 } else if (type == 'string') { 118 chars = base; 119 base = chars.length; 120 use_chars = true; 121 } else { 122 throw new Error('invalid base (number or string):' + base); 123 } 124 if (base <= 36 && !use_chars) { 125 return Number(num).toString(base); 126 } 127 var is_negative = num < 0; 128 for (var str = '', num = Math.abs(num); num > 0; num = Math.floor(num / base)) { 129 str = chars[num % base] + str; 130 } 131 return (is_negative ? '-' : '') + str; 132 }, 133 134 generateUUID4: function(base) { 135 // based on http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript 136 // version 4 (base = 16) 137 if (base < 2 || base > 62) { 138 throw new Error('invalid base (2 to 62):' + base); 139 } 140 base = base || 16; 141 return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { 142 var r = Math.random() * 16 | 0, 143 v = c == 'x' ? r : (r & 0x3 | 0x8); 144 return v.toString(16) 145 }).split('-').map(function(v) { 146 return $.toBase(parseInt(v, 16), base); 147 }).join('-'); 148 }, 149 }); 150} 151 152// 'uncheck' event for input[type="radio"] 153$(document) 154 .on('click', 'input[type="radio"][name]', function(ev, data){ 155 if (data && data.nofocus){ 156 $(this).one('focus', function(ev){ 157 ev.preventDefault(); 158 }); 159 } 160 }) 161 .on('click change', 'input[type="radio"][name]', function(ev, data) { 162 var $this = $(this), 163 name = $this.attr('name'), 164 is_click = ev.type == 'click', 165 context = $this.closest('form')[0] || document; 166 if (!context._radio_prev || !context._radio_prev[name]) { 167 // initialize 168 if (is_click) { 169 // cancel first check 170 ev.preventDefault(); 171 ev.stopPropagation(); 172 ev.stopImmediatePropagation(); 173 context._radio_prev = context._radio_prev || {}; 174 setTimeout(function() { 175 // save default checked 176 var $group = $('input[type="radio"]', context).filter(function() { 177 return $(this).attr('name') == name; 178 }); 179 context._radio_prev[name] = $group.filter(':checked'); 180 // re-check this 181 $this 182 .one('focus', function(ev){ ev.preventDefault(); }) 183 .trigger('click', data); 184 }); 185 } 186 } else { 187 // change event 188 if (!is_click) { 189 context._radio_prev[name].trigger('uncheck'); 190 context._radio_prev[name] = $this; 191 } 192 } 193 }); 194 195 196// remove space chars between children 197if (!$.fn.spaceless) { 198 $.fn.spaceless = function() { 199 return $(this).contents().each(function() { 200 if (this.nodeType == 3) { 201 this.nodeValue = this.nodeValue.replace(/\s+/g, ''); 202 } 203 }) 204 }; 205} 206 207if (!$.fn.isInVeiw) { 208 (function(){ 209 210 var VH = $(window).height(); 211 $(window).on('resize', function(){ 212 VH = $(window).height(); 213 }); 214 var ST = $(window).scrollTop(), LAST_ST = ST, SCROLLING_DOWN = false, SCROLLING_UP = false;
215 $(window).on('scroll', function(){ 216 ST = $(window).scrollTop(); 217 SCROLLING_DOWN = ST > LAST_ST; 218 SCROLLING_UP = ST < LAST_ST; 219 LAST_ST = ST; 220 }); 221 222 // offset, heightåè¨ç®æå°ééms 223 var METRICS_EXPIRE_MS = 100; 224 225 $.fn.isInView = function(offset){ 226 // offset = window position offset 227 offset = offset === undefined ? 0 : offset; 228 var $elm = $(this), 229 metrics = $(this).data('metrics'), 230 now = new Date().getTime(); 231 if (!metrics || metrics.expire < now ) { 232 metrics = { 233 expire: now + METRICS_EXPIRE_MS, 234 offset:$elm.offset(), 235 height:$elm.outerHeight() 236 }; 237 $elm.data('metrics', metrics); 238 } 239 240 if (!metrics.offset || !metrics.height) { 241 return false; 242 } 243 244 var et = metrics.offset.top, eb = et + metrics.height; 245 var ret = et < ST + VH + offset && eb > ST + offset && $elm.is(':visible'); 246 247 // parents scroll 248 249 // check overflowed in parents 250 if (ret) { 251 var $p = $elm.parentsUntil('body').filter(function(){ 252 return this.clientHeight != this.scrollHeight 253 && $(this).css('overflow') != 'visible'; 254 }) 255 .each(function(){ 256 257 // DEBUG && console.log('isInView:checking hidden parent', this); 258 259 var $c = $(this), 260 metrics = $c.data('metrics'), 261 now = new Date().getTime(); 262 263 if (!metrics || metrics.expire < now ) { 264 metrics = {
265 expire: now + METRICS_EXPIRE_MS, 266 offset:$c.offset(), 267 height:$c.outerHeight() 268 }; 269 $c.data('metrics', metrics); 270 } 271 272 var pt = metrics.offset.top, 273 pb = pt + metrics.height; 274 275 if (et > pb || eb < pt ){ 276 // hidden by parent scroll 277 278 // DEBUG && console.log('isInView:hidden by parent', this); 279 280 ret = false; 281 return false; 282 } 283 }); 284 } 285 286 // DEBUG && console.log('isInView:' + ret, $elm); 287 288 return ret; 289 } 290 291 })(); 292 293} 294 295/******* small support by js ******/ 296$(document) 297 .on('uncheck.carousel2', '.carousel-valid > input[type="radio"]', function() { 298 // for CSS animation: set .prev-checked for last checked radio 299 var name = $(this).attr('name'), 300 $i = $(this), 301 context = $i.closest('form')[0] || document, 302 $is = $('input[type="radio"]', context).filter(function() { 303 return $(this).attr('name') == name; 304 }); 305 $is.removeClass('prev-checked'); 306 $(this).addClass('prev-checked'); 307 308 309 }) 310 .on('uncheck.carousel2', '.carousel-valid > input[type="radio"]', function(ev) { 311 // for reverse select 312 var $c = $(this).closest('.carousel-valid'), 313 anim_rev; 314 if ($c.is('.prevent-anim-rev')) { 315 anim_rev = false; 316 $c.removeClass('prevent-anim-rev') 317 } else if ($c.is('.force-anim-rev')) { 318 anim_rev = true; 319 $c.removeClass('force-anim-rev') 320 } else { 321 anim_rev = !($(this).nextAll(':checked')[0]); 322 } 323 $c.toggleClass('anim-rev', anim_rev); 324 }) 325 326function getNextPrevLoop($carousel) { 327 var anim_type = ($carousel.attr('data-carousel-anim') || '').split('-'), 328 anim_v = !!((anim_type[1] || '').match(/^(down|up)$/)), 329 $inputs = $carousel.children('input[type="radio"]'), 330 $contents = $carousel.find('> .carousel-contents').children('.carousel-content'), 331 l = $inputs.length, 332 cur = $inputs.index($inputs.filter(':checked')), 333 next = (cur + l + 1) % l, 334 prev = (cur + l - 1) % l, 335 next_loop = next < cur, 336 prev_loop = prev > cur; 337 var ret = { 338 $carousel: $carousel, 339 anim: { 340 all: anim_type.join('-'), 341 type: anim_type[0], // crossfade, slidein, roll 342 direction: anim_type[1] || '', // left, right, down, up 343 is_vertical: (anim_type[1] || '').match(/^(down|up)$/), 344 }, 345 prev: { 346 is_loop: prev_loop, 347 $input: $($inputs[prev]), 348 $content: $($contents[prev]), 349 w: $($contents[prev]).width(), 350 h: $($contents[prev]).height(), 351 }, 352 cur: { 353 $input: $($inputs[cur]), 354 $content: $($contents[cur]), 355 w: $($contents[cur]).width(), 356 h: $($contents[cur]).height(), 357 }, 358 next: { 359 is_loop: next_loop, 360 $input: $($inputs[next]), 361 $content: $($contents[next]), 362 w: $($contents[next]).width(), 363 h: $($contents[next]).height(), 364 }, 365 toNext: function(loop) { 366 this.$carousel.toggleClass('prevent-anim-rev', this.next.is_loop); 367 // this.next.$input.trigger('click', { nofocus:true }); 368 var $prev_input = this.$carousel.children('input[type="radio"]').removeClass('prev-checked') 369 .filter(':checked').addClass('prev-checked'); 370 this.next.$input.prop('checked', true).trigger('change'); 371 $prev_input.trigger('uncheck.carousel2'); 372 }, 373 toPrev: function(loop) { 374 this.$carousel.toggleClass('force-anim-rev', this.prev.is_loop); 375 // this.prev.$input.trigger('click', { nofocus:true }); 376 var $prev_input = this.$carousel.children('input[type="radio"]').removeClass('prev-checked') 377 .filter(':checked').addClass('prev-checked'); 378 this.prev.$input.prop('checked', true).trigger('change'); 379 $prev_input.trigger('uncheck.carousel2'); 380 } 381 }; 382 // console.log(ret); 383 return ret; 384} 385 386// prev, next label 387$(document) 388 .on('click.carousel2', '.carousel-valid .carousel-nav-prev, .carousel-valid .carousel-nav-next', function(ev) { 389 // handle click previous / next area 390 var $carousel = $(this).closest('.carousel2'), 391 npl = getNextPrevLoop($carousel), 392 to_next = $(this).is('.carousel-nav-next'), 393 to_prev = !to_next; 394 395 // swap 396 if (($carousel.attr('data-carousel-anim') || '').match(/^roll-down$/)) { 397 to_next = [to_prev, to_prev = to_next][0]; 398 } 399 to_next && npl.toNext(); 400 to_prev && npl.toPrev(); 401 }); 402 403// mouse drag or swipe 404var _t, _o, THRESHOLD = 20; 405$(document) 406 .on('select.carousel2 selectstart.carousel2 dragstart.carousel2', '.carousel-valid > .carousel-contents > .carousel-content', function(ev) { 407 ev.preventDefault(); 408 }) 409 // .on('click', '.carousel > .carousel-contents', function(ev){ _o = null; }) 410 .on('mousedown.carousel2 touchstart.carousel2', '.carousel-valid > .carousel-contents', function(ev) { 411 // console.error('mousedown', ev); 412 if ((ev.type == 'mousedown' && ev.which != 1)||(ev.type == 'touchstart' && ev.originalEvent.touches[1])) { 413 return; 414 } 415 var t = ev.originalEvent.touches ? ev.originalEvent.touches[0] : ev; 416 var point = { 417 ox: t.pageX, 418 oy: t.pageY, 419 $carousel: $(this).parent() 420 }; 421 _o = point; 422 // console.log(_o); 423 var nextprev = getNextPrevLoop(_o.$carousel); 424 $.extend(_o, nextprev); 425 }) 426 .on('mousemove.carousel2 touchmove.carousel2', function(ev) { 427 if (!_o) { 428 return; 429 } 430 if ((ev.type == 'mousemove' && ev.which != 1)||(ev.type == 'touchmove' && ev.originalEvent.touches[1])) { 431 _o = null; 432 return; 433 } 434 // console.error('mousemove', ev); 435 var t = ev.originalEvent.touches ? ev.originalEvent.touches[0] : ev, 436 dx = t.pageX - _o.ox, 437 dy = t.pageY - _o.oy; 438 dx = Math.max(Math.min(dx, _o.cur.w), -_o.cur.w); 439 dy = Math.max(Math.min(dy, _o.cur.h), -_o.cur.h); 440 441 var d = _o.anim.is_vertical ? dy : dx, 442 to_next = d < 0, 443 to_prev = d > 0; 444 445 if (Math.abs(d) > THRESHOLD) { 446 if (_o.anim.direction == 'down' || _o.anim.direction == 'right') {
447 to_next = [to_prev, to_prev = to_next][0]; // swap 448 } 449 to_next && _o.toNext(true); 450 to_prev && _o.toPrev(true); 451 _o = null; 452 } 453 }) 454 .on('mouseup.carousel2 touchend.carousel2', function(ev) { 455 _o = null; 456 }); 457 458/********** control auto animation **********/ 459$(document).on('mouseenter.carousel2 mouseleave.carousel2', '.carousel2.carousel-valid', function(ev){ 460 $(this).toggleClass('hover', ev.type == 'mouseenter'); 461}); 462 463function doPlayCmd($c, cmd){ 464 465 var stat = $c.attr('data-carousel-autoanim-stat') || ''; 466 467 function play(stat){ 468 // console.error('carousel:play:', $c); 469 $c.attr('data-carousel-autoanim-stat', 'playing'); 470 var intervals = ($c.attr('data-carousel-autoanim') || '7000,3000').split(','); 471 var delay = parseInt(intervals[0], 10), 472 interval = parseInt(intervals[1], 10) || delay || 3000, 473 _t = $c.data('carousel-t'); 474 clearTimeout(_t); 475 clearInterval(_t); 476 if (stat != 'pausing') { 477 var _t = setTimeout(function(){ 478 var _t = $c.data('carousel-t'); 479 clearTimeout(_t); 480 clearInterval(_t); 481 if (!$c.is('.hover') && $c.isInView()) { 482 getNextPrevLoop($c).toNext(true); 483 } 484 _t = setInterval(function(){ 485 if (!$c.is('.hover') && $c.isInView()) { 486 getNextPrevLoop($c).toNext(true); 487 } 488 }, interval); 489 $c.data('carousel-t', _t); 490 }, delay); 491 $c.data('carousel-t', _t); 492 } else { 493 _t = setInterval(function(){ 494 if (!$c.is('.hover') && $c.isInView()) { 495 getNextPrevLoop($c).toNext(true); 496 } 497 }, interval); 498 // getNextPrevLoop($c).toNext(true); 499 $c.data('carousel-t', _t); 500 } 501 } 502 function pause(stat){ 503 // console.error('carousel:pause:', $c); 504 $c.attr('data-carousel-autoanim-stat', 'pausing'); 505 var _t = $c.data('carousel-t'); 506 clearTimeout(_t); 507 clearInterval(_t); 508 $c.removeData('carousel-t'); 509 } 510 function stop(stat){ 511 // console.error('carousel:stop:', $c); 512 $c.attr('data-carousel-autoanim-stat', 'stopped'); 513 var _t = $c.data('carousel-t'); 514 clearTimeout(_t); 515 clearInterval(_t); 516 $c.removeData('carousel-t'); 517 } 518 function rewind(stat){ 519 // console.error('carousel:rewind:', $c); 520 $c 521 .children('input[type="radio"]').removeClass('prev-checked') 522 .first().prop('checked', true).trigger('change').end() 523 .end() 524 .carousel2('reset', stat != 'playing'); 525 } 526 function noeffect(stat){} 527 528 var func = { 529 '':{ 530 'play':play, 531 'stop':stop, 532 'pause':pause, 533 'rewind':rewind, 534 }, 535 'playing':{ 536 'play':noeffect, 537 'stop':stop, 538 'pause':pause, 539 'rewind':rewind, 540 }, 541 'pausing':{ 542 'play':play, 543 'stop':stop, 544 'pause':noeffect, 545 'rewind':rewind, 546 }, 547 'stopped':{ 548 'play':play, 549 'stop':noeffect, 550 'pause':noeffect, 551 'rewind':rewind, 552 } 553 }[stat][cmd]; 554 if (func) { 555 func(stat); 556 } else { 557 console.error('carousel2:invalid stat and cmd:stat=' + stat + ':cmd=' + cmd); 558 } 559} 560 561$(document).on('click.carousel2', '.carousel-valid [data-carousel-cmd]', function(ev){ 562 ev.preventDefault(); 563 doPlayCmd($(this).closest('.carousel-valid'), $(this).attr('data-carousel-cmd')); 564}); 565 566/* 567var ST = $(window).scrollTop(), 568 VH = $(window).height(); 569$(window) 570 .on('resize', function() { 571 VH = $(window).height(); 572 }) 573 .on('scroll', function() { 574 ST = $(window).scrollTop(); 575 }); 576setInterval(function() { 577 $('.carousel-valid[data-carousel-autoanim][data-carousel-autoanim-cmd]').each(function() { 578 var $c = $(this), 579 cmd = $c.attr('data-carousel-autoanim-cmd'); 580 doPlayCmd($c, cmd); 581 $c.removeAttr('data-carousel-autoanim-cmd'); 582 }); 583}, 100); 584*/ 585 586var OPT = { 587 anim: 'roll-horiz', // '(|crolssfade|slidein-left|slidein-right|slidein-up|slidein-down|roll-horiz|roll-up|roll-down)' 588 autoanim: '7000,3000', // '<initial delay in ms>, <interval ms> ) 589 duration: '500', // '<duration in ms>' 590 nav: 'under', // (null|false|''|'none'|'under'|'over') : position of point navigation 591 navrel: true, // true|false : use next/prev navigation 592}; 593 594var ATTRS = ['anim', 'duration', 'autoanim' /* = delay,interval */, 'nav', 'navrel']; 595 596$.fn.carousel2 = function(opt, arg, args) { 597 opt = opt || {}; 598 var cmd; 599 if (opt && typeof opt !== 'object') { 600 cmd = opt; 601 opt = null; 602 } 603 604 return $(this).each(function() { 605 var $c = $(this); 606 607 if (cmd) { 608 609 console.log('carousel2():cmd:' + cmd, $c); 610 if (['play', 'stop', 'pause', 'rewind'].indexOf(cmd) >= 0) { 611 doPlayCmd($c, cmd); 612 } else if (cmd == 'destroy' || cmd == 'reset') { 613 $c.carousel2('stop') 614 .removeClass('carousel-valid hover prevent-anim prevent-anim-rev anim-rev') 615 .removeAttr('data-carouse-autoanim-stat') 616 .addClass('prevent-anim') 617 .find('>input[type="radio"]').removeClass('prev-checked') 618 .first().prop('checked', true).trigger('change').end().end(); 619 if (cmd == 'reset') { 620 setTimeout(function(){ 621 $c.carousel2(); 622 if (arg && !$c.is('[data-carousel-autoanim="none"]')) { 623 // 'reset', true : pause at restart 624 setTimeout(function(){ 625 $c.carousel2('pause'); 626 }); 627 } 628 }); 629 } 630 } else if (cmd == 'next') { 631 getNextPrevLoop($c).toNext(); 632 } else if (cmd == 'prev') { 633 getNextPrevLoop($c).toPrev(); 634 } else if (cmd == 'settings') { 635 if (typeof arg === 'string') {
636 arg = { arg:arg2 }; 637 } 638 } else if (cmd == 'connectsettings'){ 639 if (typeof arg === 'string') { 640 arg = { arg:arg2 }; 641 } 642 console.log('carousel2():connectsettings:', $c[0]); 643 $.each(arg, function(attr, $input){ 644 if (!ATTRS.indexOf(attr) < 0) { 645 console.error('carousel2:connectsetting:' + attr + ' is not in ' + ATTRS.join(',')); 646 return; 647 } 648 if (!$input.is(':input')) { 649 console.error('carousel2:connectsetting:$input is not :input'); 650 return; 651 } 652 $input.data('carouselsetting', $input.data('carouselsetting')||[]); 653 var connected = $input.data('carouselsetting'); 654 if (connected.indexOf($c[0]) >= 0){ 655 console.log('carousel2():connectsettings:$input is already connected to .carousel2', $input[0], $c[0]); 656 return; 657 } 658 connected.push($c[0]); 659 $input.data('caroselsetting', connected); 660 661 /* sync $c to $input 662 var setting = $c.attr('data-carousel-' + attr); 663 console.log('carousel2():connectsettings:' + attr + '=' + setting, $input[0]); 664 $input.val(setting); 665 */ 666 667 $input.on('change.carousel2setting', function(ev){ 668 $c.attr('data-carousel-' + attr, $(this).val()) 669 .carousel2('reset'); 670 var attrs = {}; 671 $.each(ATTRS, function(attr, val){ 672 attrs[attr] = val; 673 }); 674 $c.addClass('setting-changed') 675 .trigger('changesetting', [attrs]); 676 setTimeout(function(){ 677 $c.removeClass('setting-changed'); 678 }, 1000); 679 }) 680 .on('focus blur', function(ev){ 681 var is_focus = (ev.type == 'focus'), 682 $this = $(this), 683 target_selector = { 684 anim:'.carousel-contents', 685 duration:'.carousel-contents', 686 autoanim:'.carousel-contents', 687 nav:'.carousel-nav', 688 navrel:'.carousel-nav-rel .carousel-nav-prev, .carousel-nav-rel .carousel-nav-next', 689 }[attr]; 690 $c.toggleClass('setting-focused', is_focus); 691 if (target_selector) { 692 $c.find(target_selector).toggleClass('setting-focused', is_focus); 693 } 694 }); 695 }); 696 } else { 697 console.error('carousel2():invalid cmd:' + cmd); 698 } 699 700 } else { 701 ////// init 702 703 if ($c.is('.carousel-invalid')) { 704 return; 705 } 706 707 var _opt = $.extend({}, OPT, opt); 708 Object.keys(OPT).forEach(function(key) { 709 var opt_attr = $c.attr('data-carousel-' + key); 710 if (opt_attr !== undefined) { 711 _opt[key] = opt_attr; 712 } 713 }); 714 715 var $contents = $c.children('.carousel-contents'), 716 $content = $contents.children('.carousel-content'), 717 $nav = $contents.next('.carousel-nav'), 718 $navrel = $contents.children('.carousel-nav-rel'); 719 720 function hasValidStructure() { 721 return $content.length >= 2; 722 } 723 if (!hasValidStructure()) { 724 console.error('.carousel2 is not valid structure', $c); 725 $c.addClass('carousel-invalid'); 726 return; 727 } 728 729 $c.addClass('carousel-valid') 730 .addClass('prevent-anim') 731 .assureUniqId('carousel-') 732 .children('.carousel-contents').spaceless(); 733 734 var cid = $c.attr('id'); 735 736 console.log('$.carousel2():init:', _opt, $c); 737 738 var _waits_d = $.Deferred(), 739 _waits_l = 0, 740 $waits = $c.find('img[src]:visible').filter(function(){ 741 var has_size = !!($(this).height()); 742 if (!has_size) { 743 _waits_l++; 744 return true; 745 } 746 return false; 747 }) 748 .on('load error', function(ev){ 749 _waits_l--; 750 if (_waits_l==0) { 751 _waits_d.resolve('all images are loaded'); 752 } 753 }); 754 if (!_waits_l) { 755 _waits_d.resolve('all images are already loaded'); 756 } else { 757 $c.addClass('carousel-loading'); 758 _waits_d.then(function(){ 759 $c.removeClass('carousel-loading'); 760 }); 761 setTimeout(function(){ 762 _waits_d.resolve('timeout'); 763 }, 5000); 764 } 765 766 if ($content.length >= min_dynamic_css_contents_num) { 767 max_dynamic_css_contents_num = $content.length; 768 makeDynamicCssForContents(min_dynamic_css_contents_num, max_dynamic_css_contents_num); 769 min_dynamic_css_contents_num = max_dynamic_css_contents_num + 1; 770 } 771 772 $('#style-' + cid + '-duration').remove(); 773 if (parseInt(duration, 10) != 500) { 774 $('<style></style>') 775 .attr('id', 'style-' + cid + '-duration') 776 .html('#' + cid + ' > .carousel-contents > .carousel-content { animation-duration:'+ _opt.duration + 'ms; ') 777 .appendTo('head'); 778 } 779 780 var $i = $c.children('input[type="radio"]'); 781 782 // make navigations 783 if (!_opt.nav) { 784 $nav.remove(); 785 } else { 786 if (!($nav[0])) {
787 $nav = $('<div class="carousel-nav"></div>').insertAfter($contents); 788 } 789 if (!($nav.children('.carousel-nav-manip')[0])) { 790 $('<div class="carousel-nav-manip"><div class="carousel-nav-rewind" data-carousel-cmd="rewind"></div><div class="carousel-nav-stop" data-carousel-cmd="stop"></div><div class="carousel-nav-pause" data-carousel-cmd="pause"></div><div class="carousel-nav-play" data-carousel-cmd="play"></div></div>').appendTo($nav); 791 } 792 } 793 794 if (!_opt.navrel) { 795 $navrel.remove(); 796 } else if (!($navrel[0])) { 797 $navrel = $('<div class="carousel-nav-rel"><div class="carousel-nav-prev"></div><div class="carousel-nav-next"></div></div>').appendTo($contents); 798 } 799 800 // safe checked 801 var checked_idx = Math.max(0, $i.index($i.filter(':checked'))); 802 803 $i.remove(); 804 $i = $(); 805 $nav.children('label').remove(); 806 807 for (var i = $contents.children('.carousel-content').length; i; i--) { 808 var rid = cid + '-radio-' + i; 809 $i = $i.add( 810 $('<input type="radio">') 811 .attr({ 812 id: rid, 813 name: cid + '-radio' 814 }) 815 .css({ 816 position:'absolute', 817 zIndex:-1, 818 width:'1px', 819 height:'1px', 820 overflow:'hidden', 821 opacity:0, 822 }) 823 .prependTo($c) 824 ); 825 $('<label></label>').attr('for', rid) 826 .prependTo($nav); 827 } 828 829 // checked_idx = checked_idx < 0 ? 0 : checked_idx; 830 831 // $($i.get(checked_idx)).prop('checked', true); 832 // has valid structure 833 834 // animation duration 835 var duration = $c.attr('data-carousel-anim-duration'); 836 if (duration) { 837 $('<style></style>').attr('id', 'style-duration-' + cid).html('#' + cid + ' .carousel-content { animation-duration:' + duration + 'ms; }').appendTo('head'); 838 } else { 839 $('#style-duration-' + cid).remove(); 840 } 841 842 $i.one('change', function(){ 843 $c.removeClass('prevent-anim'); 844 }); 845 846 $i[checked_idx].checked = true; 847 848 if (_opt.autoanim != 'none') { 849 _waits_d.then(function(res){ 850 console.log('carousel2:auto animation start:' + res); 851 $c.carousel2('play'); 852 }); 853 } 854 } 855 }); 856}; 857 858// generate styles 859var min_dynamic_css_contents_num = 13, max_dynamic_css_contents_num = 20, tmpls, _template_loading_d; 860 861// load template css 862if (!window._jquery_carousel2_tmpls) { 863 window_jquery_carousel2_tmpls = 'loading'; 864 _template_loading_d = $.Deferred(); 865 $('script[src]').filter(function(){ 866 return $(this).attr('src').indexOf('/jquery-carousel.js') >= 0 867 }).each(function(){ 868 var url = $(this).attr('src').replace('/jquery-carousel.js', '/jquery-carousel.css'); 869 // load as text 870 $.ajax({ 871 type:'get', 872 url:url, 873 dataType:'text' 874 }).then(function(res){ 875 if (res.substring(0, '.this-is-carousel2-stylesheet'.length) != '.this-is-carousel2-stylesheet' ){ 876 return; 877 } 878 window._jquery_carousel2_tmpls = res.match(/\.carousel-template ([\u0000-\uffff]+?){([\u0000-\uffff]+?)}/mg).map(function(tmpl){ 879 tmpl = tmpl.match(/^\.carousel-template ([\u0000-\uffff]+?){([\u0000-\uffff]+?)}$/m); 880 tmpl.shift(); 881 return tmpl; 882 }); 883 _template_loading_d.resolve(); 884 }); 885 }); 886} 887 888function makeDynamicCssForContents(min_contents_num, max_contents_num) { 889 // make dynamic styles for carousel from stylesheet that have '.this-is-carousel-stylesheet' in first style. 890 // jquery-carousel.css located 891 var i,l,s,r,t,c,rules = [], rules_dict = {} 892 var min_contents_num = min_contents_num == undefined ? min_dynamic_css_contents_num : min_contents_num; 893 var max_contents_num = max_contents_num == undefined ? max_dynamic_css_contents_num : max_contents_num; 894 895 if (!window._jquery_carousel2_tmpls || window._jquery_carousel2_tmpls == 'loading') { 896 return _template_loading_d.then(function(){ 897 makeDynamicCssForContents(min_contents_num, max_contents_num); 898 }); 899 } 900 901 var cssText = []; 902 window._jquery_carousel2_tmpls.forEach(function(tmpl) { 903 for (var t=[],i=min_contents_num,l=max_contents_num;i<=l;i++){ 904 cssText.push(tmpl[0].split('(1)').join('(' + i + ')') + '{' + tmpl[1] + '}'); 905 } 906 }); 907 908 909 // console.log(cssText); 910 // $('#style-carousel-dynamic').remove();
911 var sid = 'style-carousel-dynamic-'+ min_contents_num +'-'+ max_contents_num; 912 $('<style></style>').attr('id', sid).html(cssText.join('\n')).appendTo('head'); 913 console.log('$.carousel():extend dynamic css:#' + sid); 914 915 var _d = $.Deferred(); 916 _d.resolve(); 917 return _d; 918} 919 920// makeDynamicCssForContents(min_dynamic_css_contents_num, max_dynamic_css_contents_num); 921 922$('.carousel2') 923 .carousel2(); 924});
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.