1/* 2 3Content Timeline 3.1 4 5Date organised content slider. 6 7Copyright (c) 2012 Br0 (shindiristudio.com) 8 9Project site: http://codecanyon.net/ 10Project demo: http://shindiristudio.com/timeline 11 12*/ 13 14(function($){ 15 16 // EVENTS.timeline 17 18 // init.timeline : triggered when timeline is initialised 19 // scrollStart.timeline : triggered when item move animation starts 20 // scrollEnd.timeline : triggered when item move animation ends 21 // itemOpen.timeline : triggered on click to open item 22 // itemOpened.timeline : triggered on click to open item 23 // itemClose.timeline : triggered on click to close item 24 25 // --------------------------------------------------------- 26 27 // On KeyPress (left) : trigger $.timeline('left') 28 // On KeyPress (right) : trigger $.timeline('right') 29 30 // --------------------------------------------------------- 31 32 // $.timeline(METHODS) 33 34 // $.timeline('init') : initialises timeline 35 // $.timeline('destroy') : clears timeline data 36 // $.timeline('left') : moves one left by one element 37 // $.timeline('right') : moves right by one element 38 // $.timeline('open', id) : opens element with 'data-id' = id 39 // $.timeline('close', id): closes element with 'data-id' = id 40 // $.timeline('goTo', id) : goes to element width 'data-id' = id 41 42 43 var t_methods = { 44 init : function( options ) { 45 46 // Default settings 47 var settings = $.extend( { 48 'itemClass' : '.item', // class used for timeline items 49 'itemOpenClass' : '.item_open', // class used for item details 50 'openTriggerClass' : '.item', // class of read more element (default uses whole item to trigger open event) 51 'closeText' : 'Close', // text of close button in open item 52 'itemMargin' : 10, // spacing between items 53 'scrollSpeed' : 500, // animation speed 54 'startItem' : 'last', // timeline start item id, 'last' or 'first' can be used insted 55 'easing' : 'easeOutSine', // jquery.easing function for animations, 56 'categories' : ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], // categories shown above timeline (months are default) 57 'nuberOfSegments' : [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], // number of elements per category (number of days) 58 'yearsOn' : true, // show years (can be any number you use in data-id (elementNumber/category/yearOrSomeOtherNumber)) 59 'swipeOn' : true, // turn on swipe moving function 60 'hideTimeline' : false, //hides the timeline line 61 'hideControles' : false, //hides the prev/next controles 62 'closeItemOnTransition' : false, //if ture, closes the item after transition 63 'ajaxFailMessage' : 'Ajax request has failed.' 64 }, options); // Setings 65 66 67 // main queries 68 var $this = this, 69 $body = $('body'), 70 $items = $this.find(settings.itemClass), 71 $itemsOpen = $this.find(settings.itemOpenClass), 72 itemWidth = $items.first().width(), 73 itemOpenWidth = $itemsOpen.first().width(), 74 closeItemOnTransition=settings.closeItemOnTransition; 75 76 // Trigger init event 77 $this.trigger('init.Timeline'); 78 79 80 // If no index found 81 var startIndex = $items.length-1; 82 83 // Find index of start element 84 if(settings.startItem == 'first') 85 { 86 startIndex = 0; 87 } 88 else if (settings.startItem == 'last') 89 { 90 startIndex = $items.length-1; 91 } 92 else { 93 $items.each(function(index){ 94 if(settings.startItem == $(this).attr('data-id')) 95 { 96 startIndex = index; 97 return true; 98 } 99 }); 100 } 101 $items.each(function(index){ 102 $(this).attr('data-count', index); 103 $(this).next(settings.itemOpenClass).attr('data-count', index); 104 if(!$(this).hasClass(settings.openTriggerClass)) { 105 $(this).find(settings.openTriggerClass).attr('data-count', index); 106 } 107 }); 108 109 // Create wrapper elements, and needed properties 110 $this.append('<div style="clear:both"></div>'); 111 $this.css({width: '100%', 'overflow' : 'hidden', marginLeft : 'auto', marginRight : 'auto','text-align': 'center', height:0}); 112 $this.wrapInner('<div class="timeline_items" />'); 113 $this.find('.timeline_items').css('text-align','left'); 114 115 if('ontouchstart' in window) { 116 $this.addClass('timelineTouch'); 117 } 118 119 // ZoomOut placement fix 120 $this.wrapInner('<div class="timeline_items_holder" />'); 121 if(!settings.hideControles) { 122 $this.append('<div class="t_controles"><div class="t_left"></div><div class="t_right"></div></div>'); 123 } 124 $this.wrapInner('<div class="timeline_items_wrapper" />'); 125 $this.find('.timeline_items_holder').css({width: '300px', marginLeft : 'auto', marginRight : 'auto'}); 126 127 128 $items.css({paddingLeft:0 , paddingRight:0, marginLeft: settings.itemMargin/2, marginRight: settings.itemMargin/2, float: 'left', position:'relative'}); 129 130 $itemsOpen.each(function(){ 131 $(this).prepend('<div class="t_close" data-count="'+$(this).attr('data-count')+'" data-id="'+$(this).attr('data-id')+'">'+settings.closeText+'</div>'); 132 $(this).wrapInner('<div class="'+settings.itemOpenClass.substr(1)+'_cwrapper" />').find('div:first').css({position: 'relative'}); 133 $(this).css({width: 0, padding:0 , margin: 0, float: 'left', display : 'none', position : 'relative', overflow : 'hidden'}); 134 }); 135 136 137 // Get new queries 138 var $iholder = $this.find('.timeline_items:first'), 139 $line = $this.find('.t_line_wrapper:first'), 140 margin = 300/2 - (itemWidth + settings.itemMargin)*(1/2 + startIndex) , 141 width = (itemWidth + settings.itemMargin)*$items.length + (itemOpenWidth + settings.itemMargin) + 660 , 142 data = $this.data('timeline'); 143 144 // Set margin so start element would place in midle of the screen 145 $iholder.css({width: width, marginLeft: margin}); 146 147 148 149 150 // If the plugin hasn't been initialized yet 151 if (!data){ 152 $this.data('timeline', { 153 currentIndex : startIndex, 154 itemCount : $items.length, 155 margin : margin, 156 itemWidth : itemWidth, 157 itemOpenWidth : itemOpenWidth, 158 lineMargin : 0, 159 lineViewCount : 0, 160 options : settings, 161 items : $items, 162 iholder : $iholder, 163 open : false, 164 noAnimation : false, 165 marginResponse: false, 166 mousedown : false, 167 mousestartpos : 0 168 }); 169 } 170 if(!settings.hideTimeline) { 171 $this.timeline('createElements'); 172 if($this.hasClass('timelineClean')) { 173 } 174 } 175 176 177 178 // Bind keyLeft and KeyRight functions 179 $(document).keydown(function(e){
180 if (e.keyCode == 37) { 181 $this.timeline('left'); 182 return false; 183 } 184 if (e.keyCode == 39) { 185 $this.timeline('right'); 186 return false; 187 } 188 }); 189 190 $(document).ready(function(){ 191 192 $this.find(settings.itemClass).css({ '-webkit-touch-callout': 'none', '-webkit-user-select': 'none', '-khtml-user-select': 'none', '-moz-user-select': 'none', '-ms-user-select': 'none', 'user-select': 'none'}).find('img').on('dragstart', function(event) { 193 if (!($(this).hasClass('timeline_rollover_bottom'))) 194 event.preventDefault(); 195 }); 196 197 198 199 $('.image_rollover_bottom').on('dragstart', function(event) { 200 $(this).addClass("disableClick"); 201 event.preventDefault(); 202 }); 203 204 $('.image_rollover_bottom').on('mousedown', function(event) { 205 if (!$(this).is("hover")) { 206 $(this).removeClass("disableClick"); 207 } 208 209 }); 210 211 $('.image_rollover_bottom').on('click', function(event) { 212 if ($(this).hasClass('disableClick')) { 213 event.preventDefault(); 214 event.stopPropagation(); 215 } 216 $(this).removeClass('disableClick') 217 }); 218 219 220 221 222 }); 223 224 // Respond to window resizing 225 $(window).resize(function() { 226 //var id = $this.find('.active:first').attr('href').substr(1); 227 var data = $this.data('timeline'), 228 id = $items.eq(data.currentIndex).attr('data-id'); 229 230 itemWidth = $items.first().width(), 231 itemOpenWidth = $itemsOpen.first().find('div:first').width(); 232 233 data.margin += data.itemCount*(data.itemWidth-itemWidth);
234 data.itemWidth = itemWidth; 235 236 if(data.open) data.margin += (data.itemOpenWidth-itemOpenWidth)/2; 237 data.itemOpenWidth = itemOpenWidth; 238 239 240 if($('body').width() < 767 && data.open && !data.marginResponse) { 241 data.margin -= (itemWidth+settings.itemMargin)/2; 242 data.marginResponse = true; 243 } 244 else if($('body').width() >= 767 && data.marginResponse && data.open) { 245 data.margin += (itemWidth+settings.itemMargin)/2; 246 data.marginResponse = false; 247 } 248 249 data.noAnimation = true; 250 $this.timeline('goTo', id); 251 }); 252 253 // Bind left on click 254 $this.find('.t_left').click(function(){ 255 $this.timeline('left'); 256 }); 257 258 // Bind right on click 259 $this.find('.t_right').click(function(){ 260 $this.timeline('right'); 261 }); 262 263 // SWIPE bind 264 265 if(settings.swipeOn) { 266 $items.find('*').each(function(){ 267 $(this).css({'-webkit-touch-callout': 'none', 268 '-webkit-user-select': 'none', 269 '-khtml-user-select': 'none', 270 '-moz-user-select': 'none', 271 '-ms-user-select': 'none', 272 'user-select': 'none'}); 273 }); 274 $this.bind('touchstart',function(e){ 275 $this.timeline('touchStart', e); 276 }); 277 278 279 $this.find(settings.itemClass).mousedown(function(e){ 280 $this.timeline('mouseDown', e.pageX); 281 }); 282 283 284 $(document).bind('touchend',function(e){ 285 data = $this.data('timeline'); 286 $this.timeline('touchEnd', data.touchpos); 287 }); 288 289 $(document).mouseup(function(e){ 290 var data = $this.data('timeline'); 291 if(data.mousedown) { 292 $this.timeline('mouseUp', e.pageX); 293 } 294 }); 295 } 296 297 298 299 // Bind open on click 300 $this.find(settings.openTriggerClass).click(function(){ 301 $this.timeline('goTo',$(this).attr('data-id'), $(this).attr('data-count'), true); 302 }); 303 304 // Bind close on click 305 $this.find('.t_close').click(function(){ 306 $this.timeline('close',$(this).attr('data-id'),$(this).attr('data-count')); 307 }); 308 309 // Show when loaded 310 $this.css({height: 'auto'}).show(); 311 $this.prev('.timelineLoader').hide(); 312 313 // Reposition nodes due to their width 314 $this.find('.t_line_node').each(function(){ 315 if($(this).width() < 10) $(this).width(12); 316 $(this).css({marginLeft: -$(this).width()/2}); 317 }); 318 return $this; 319 }, 320 321 // Clear data 322 destroy : function( ) { 323 $(document).unbind('mouseup'); 324 $(window).unbind('resize'); 325 var $this = this, 326 data = $this.data('timeline'); 327 $this.removeData('timeline'); 328 329 }, 330 331 touchStart : function(evt) { 332 var $this = this, 333 data = $this.data('timeline'), 334 xmargin = 0; 335 data.xpos = evt.originalEvent.touches[0].pageX, 336 data.ypos = evt.originalEvent.touches[0].pageY; 337 data.mousedown = true; 338 data.touchHorizontal = false; 339 data.mousestartpos = data.xpos; 340 $this.unbind('touchmove'); 341 $this.bind('touchmove', function(e){ 342 var newx = e.originalEvent.touches[0].pageX, 343 newy = e.originalEvent.touches[0].pageY; 344 if(data.mousedown && !data.touchHorizontal) { 345 if(Math.abs(newx-data.xpos) > Math.abs(newy-data.ypos)) { 346 data.touchHorizontal = true; 347 } 348 } 349 else if(data.touchHorizontal) { 350 e.preventDefault(); 351 data.touchpos = e.originalEvent.touches[0].pageX; 352 xmargin = data.margin - data.xpos + e.originalEvent.touches[0].pageX; 353 data.iholder.css('marginLeft', xmargin + 'px'); 354 } 355 data.mousedown = false 356 }); 357 }, 358 359 mouseDown : function(xpos) { 360 var $this = this, 361 data = $this.data('timeline'), 362 xmargin = 0; 363 data.mousedown = true; 364 data.mousestartpos = xpos; 365 366 $('body').css('cursor','move'); 367 $(document).mousemove(function(e){ 368 xmargin = data.margin - xpos + e.pageX; 369 data.iholder.css('marginLeft', xmargin + 'px'); 370 }); 371 }, 372 373 touchEnd : function(xpos) { 374 var $this = this, 375 data = $this.data('timeline'), 376 itemWidth = data.itemWidth + data.options.itemMargin, 377 itemC = data.currentIndex, 378 mod = 0, 379 xmargin = xpos - data.mousestartpos; 380
381 if(typeof data.touchHorizontal != 'undefined' && data.touchHorizontal) { 382 data.touchHorizontal = false; 383 384 itemC -= parseInt(xmargin/itemWidth); 385 mod = xmargin%itemWidth; 386 if (xmargin < 0 && mod < -itemWidth/2) { 387 itemC++; 388 } 389 if (xmargin > 0 && mod > itemWidth/2) { 390 itemC--; 391 } 392 393 if(itemC < 0) { 394 itemC = 0; 395 } 396 if(itemC >= data.itemCount) { 397 itemC = data.itemCount-1; 398 } 399 400 $this.timeline('goTo', data.items.eq(itemC).attr('data-id'), data.items.eq(itemC).attr('data-count')); 401 402 if (data.options.closeItemOnTransition) 403 $this.timeline('close', data.items.eq(itemC).attr('data-id')); 404 } 405 }, 406 407 mouseUp : function(xpos) { 408 409 var $this = this, 410 data = $this.data('timeline'), 411 itemWidth = data.itemWidth + data.options.itemMargin, 412 itemC = data.currentIndex, 413 mod = 0, 414 xmargin = xpos - data.mousestartpos; 415 data.mousedown = false; 416 417 $(document).unbind('mousemove'); 418 $('body').css('cursor','auto'); 419 420 itemC -= parseInt(xmargin/itemWidth);
421 mod = xmargin%itemWidth; 422 if (xmargin < 0 && mod < -itemWidth/2) { 423 itemC++; 424 } 425 if (xmargin > 0 && mod > itemWidth/2) { 426 itemC--; 427 } 428 429 if(itemC < 0) { 430 itemC = 0; 431 } 432 if(itemC >= data.itemCount) { 433 itemC = data.itemCount-1; 434 } 435 436 $this.timeline('goTo', data.items.eq(itemC).attr('data-id'), data.items.eq(itemC).attr('data-count')); 437 if (data.options.closeItemOnTransition) 438 $this.timeline('close', data.items.eq(itemC).attr('data-id')); 439 440 }, 441 442 open : function (id, data_count) { 443 var $this = this, 444 data = $this.data('timeline'), 445 $items = $this.find(data.options.itemOpenClass), 446 speed = data.options.scrollSpeed, 447 width = data.itemOpenWidth, 448 easing = data.options.easin, 449 itemMargin = data.options.itemMargin; 450 451 452 $items.each(function(){ 453 if ($(this).attr('data-id') == id) { 454 if (!data_count || data_count == $(this).attr('data-count')) { 455 var $newThis = $(this); 456 // Trigger itemOpen event 457 $this.trigger('itemOpen.Timeline'); 458 459 // Open content and move margin 460 $(this).stop(true).show().animate({width: width, marginLeft: itemMargin/2, marginRight: itemMargin/2}, speed, easing); 461 462 if (typeof $(this).attr('data-access') != 'undefined' && $(this).attr('data-access') != '') { 463 var action = $(this).attr('data-access'); 464 465 $.get(action, function(data){ 466 467 $('body').append('<div class="ajax_preloading_holder" style="display:none"></div>'); 468 $('.ajax_preloading_holder').html(data); 469 if ($('.ajax_preloading_holder img').length > 0 ) { 470 $('.ajax_preloading_holder img').load(function() { 471 $newThis.find('.item_open_content').html(data); 472 $('.ajax_preloading_holder').remove(); 473 $(this).attr('data-access', ''); 474 475 /* trigger */ 476 var event = jQuery.Event( 'ajaxLoaded.timeline' ); 477 event.element = $newThis.find('.item_open_content'); 478 $( "body" ).trigger( event ); 479 $this.trigger(event); 480 }); 481 } 482 else { 483 $newThis.find('.item_open_content').html(data); 484 $('.ajax_preloading_holder').remove(); 485 $(this).attr('data-access', ''); 486 487 /* trigger */ 488 var event = jQuery.Event( 'ajaxLoaded.timeline' ); 489 event.element = $newThis.find('.item_open_content'); 490 $( "body" ).trigger( event ); 491 $this.trigger(event); 492 } 493 },'text').fail(function() { 494 data = '<div class="timeline_open_content"><h2 class="no-marg-top">'+data.options.ajaxFailMessage+'</h2></div>'; 495 $newThis.find('.item_open_content').html(data); 496 $('.ajax_preloading_holder').remove(); 497 498 499 /* trigger */ 500 var event = jQuery.Event( 'ajaxLoaded.timeline' ); 501 event.element = $newThis.find('.item_open_content'); 502 $( "body" ).trigger( event ); 503 $this.trigger(event); 504 }); 505 } 506 507 if($('body').width() < 767) { 508 data.margin -= (data.itemWidth+data.options.itemMargin)/2; 509 data.marginResponse = true; 510 } 511 else { 512 data.marginResponse = false; 513 } 514 data.margin -= (width + data.options.itemMargin + data.itemWidth)/2 - data.itemWidth/2; 515 data.iholder.stop(true).animate({marginLeft : data.margin}, speed, easing); 516 data.open = id; 517 } 518 519 $this.trigger('itemOpened.Timeline'); 520 } 521 522 }); 523 return $this; 524 }, 525 526 close : function (id, idOpen, dataCountOpen) { 527 var $this = this, 528 data = $this.data('timeline'), 529 $items = $this.find(data.options.itemOpenClass), 530 speed = data.options.scrollSpeed, 531 width = data.itemOpenWidth, 532 easing = data.options.easing; 533 534 535 $items.each(function(){ 536 if ($(this).attr('data-id') == id && $(this).is(":visible")) { 537 // Trigger itemOpen event 538 $this.trigger('itemClose.Timeline'); 539 540 // Close content and move margin 541 $(this).stop(true).animate({width: 0, margin:0}, speed, easing, function(){$(this).hide()}); 542 if (data.marginResponse) { 543 data.margin += (data.itemWidth+data.options.itemMargin)/2; 544 } 545 data.margin += (width + data.options.itemMargin)/2; 546 data.iholder.stop(true).animate({marginLeft : data.margin}, speed, easing); 547 data.open = false; 548 } 549 }); 550 if(idOpen) { 551 $this.timeline('open', idOpen, dataCountOpen); 552 } 553 return $this; 554 }, 555 556 557 // Move one step left 558 right : function() { 559 var $this = this, 560 data = $this.data('timeline'), 561 speed = data.options.scrollSpeed, 562 easing = data.options.easing; 563 if (data.currentIndex < data.itemCount-1) 564 { 565 var dataId = data.items.eq(data.currentIndex+1).attr('data-id'); 566 var dataCount = data.items.eq(data.currentIndex+1).attr('data-count'); 567 // console.log(dataId, dataCount); 568 $this.timeline('goTo', dataId, dataCount); 569 570 if (data.options.closeItemOnTransition) 571 $this.timeline('close', dataId); 572 } 573 else 574 { 575 data.iholder.stop(true).animate({marginLeft : data.margin-50}, speed/2, easing).animate({marginLeft : data.margin}, speed/2, easing); 576 } 577 return $this 578 }, 579 580 // Move one step right 581 left : function() { 582 var $this = this, 583 data = $this.data('timeline'), 584 speed = data.options.scrollSpeed, 585 easing = data.options.easing; 586 if (data.currentIndex > 0) 587 { 588 var dataId = data.items.eq(data.currentIndex-1).attr('data-id'); 589 var dataCount = data.items.eq(data.currentIndex-1).attr('data-count'); 590 $this.timeline('goTo', dataId, dataCount); 591 592 if (data.options.closeItemOnTransition) 593 $this.timeline('close', dataId); 594 } 595 else 596 { 597 data.iholder.stop(true).animate({marginLeft : data.margin+50}, speed/2, easing).animate({marginLeft : data.margin}, speed/2, easing); 598 } 599 return $this; 600 }, 601 602 // Go to item 603 goTo : function (id, data_count, openElement) { 604 var $this = this, 605 data = $this.data('timeline'), 606 speed = data.options.scrollSpeed, 607 easing = data.options.easing, 608 $items = data.items, 609 timelineWidth = $this.find('.timeline_line').width(), 610 count = -1, 611 found = false; 612 613 // Find item index 614 $items.each(function(index){ 615 if(id == $(this).attr('data-id')) 616 { 617 if (!data_count || data_count == $(this).attr('data-count')) 618 { 619 found = true; 620 count = index; 621 return false; 622 } 623 } 624 }); 625 626 // Move if fount 627 if(found) 628 { 629 // Move lineView to current element 630 var $nodes = $this.find('.t_line_node'); 631 $nodes.removeClass('active'); 632 var $goToNode = $nodes.parent().parent().find('[href="#'+id+'"]').addClass('active'); 633 data.lineMargin = -parseInt($goToNode.parent().parent().attr('data-id'),10)*100; 634 635 // check if responsive width 636 if($this.find('.t_line_view:first').width() > $this.find('.timeline_line').width()) { 637 data.lineMargin *=2; 638 if ($goToNode.parent().hasClass('right')) data.lineMargin -= 100; 639 } 640 641 if(data.noAnimation){ 642 data.noAnimation = false; 643 $this.find('.t_line_wrapper').stop(true).css({marginLeft : data.lineMargin+'%'}); 644 } 645 else { 646 $this.find('.t_line_wrapper').stop(true).animate({marginLeft : data.lineMargin+'%'}, speed, easing ); 647 } 648 649 650 if(data.open) { 651 $this.timeline('close', data.open, id, data_count); 652 } 653 else if (openElement) { 654 $this.timeline('open', id, data_count); 655 } 656 657 // Trigger ScrollStart event 658 $this.trigger('scrollStart.Timeline'); 659 660 // Scroll 661 662 data.margin += (data.itemWidth + data.options.itemMargin)*(data.currentIndex - count); 663 data.currentIndex = count; 664 665 var multiply = (parseInt(data.iholder.css('margin-left')) - data.margin)/data.itemWidth; 666 667 668 // data.iholder.animate({marginLeft : data.margin}); 669 670 data.iholder.stop(true).animate({marginLeft : data.margin}, speed+(speed/5)*(Math.abs(multiply)-1), easing, function(){ 671 $this.trigger('scrollStop.Timeline'); 672 }); 673 } 674 return $this; 675 }, 676 677 // move line to the left 678 lineLeft : function() { 679 var $this = this, 680 data = $this.data('timeline'), 681 speed = data.options.scrollSpeed, 682 easing = data.options.easing; 683 if (data.lineMargin != 0 && data.options.categories) { 684 data.lineMargin += 100; 685 $this.find('.t_line_wrapper').stop(true).animate({marginLeft : data.lineMargin+'%'}, speed, easing); 686 } 687 688 }, 689 690 // move line to the right 691 lineRight : function() { 692 var $this = this, 693 data = $this.data('timeline'), 694 speed = data.options.scrollSpeed, 695 easing = data.options.easing; 696 if ($this.find('.t_line_view:first').width() > $this.find('.timeline_line').width()) 697 var viewCount = data.lineViewCount*2; 698 else 699 var viewCount = data.lineViewCount; 700 701 if (data.lineMargin != -(viewCount-1)*100 && data.options.categories) { 702 data.lineMargin -= 100; 703 $this.find('.t_line_wrapper').stop(true).animate({marginLeft : data.lineMargin+'%'}, speed, easing); 704 } 705 706 }, 707 708 // Create timeline elements and css dependent properties 709 createElements : function() { 710 var $this = this, 711 data = $this.data('timeline'), 712 $items = data.items; 713 714 var html = '\n' + 715' <div class="timeline_line" style="text-align: left; position:relative; margin-left:auto; margin-right:auto;">\n' + 716' </div>\n'; 717 $this.prepend(html); 718 var timelineWidth = $this.find('.timeline_line').width(), 719 nodes = new Array(), 720 months = [''].concat(data.options.categories); 721 monthsDays = [0].concat(data.options.nuberOfSegments), 722 minM = months.length, 723 minY = 99999, 724 maxM = 0, 725 maxY = 0; 726 if(!data.options.yearsOn) maxY = 99999; 727 728 var yearsArr = {}; 729 if(!data.options.categories) { 730 $items.each(function(){ 731 var dataId = $(this).attr('data-id'), 732 dataArray = dataId.split('/'), 733 d = parseInt(dataArray[0],10), 734 m = ($.inArray(dataArray[1],months) != -1) ? $.inArray(dataArray[1],months) : parseInt(dataArray[1],10), 735 y = parseInt(dataArray[2],10); 736 if(d < minY) minY = d; 737 if(d > maxY) maxY = d; 738 }); 739 minY -= 10; 740 maxY += 10; 741 } 742 // find timeline date range and make node elements 743 $items.each(function(index){ 744 var dataId = $(this).attr('data-id'), 745 nodeName = $(this).attr('data-name'), 746 dataDesc = $(this).attr('data-description'), 747 dataArray = dataId.split('/'), 748 d = parseInt(dataArray[0],10), 749 m = ($.inArray(dataArray[1],months) != -1) ? $.inArray(dataArray[1],months) : parseInt(dataArray[1],10), 750 y = parseInt(dataArray[2],10); 751 752 753 if(typeof yearsArr[y] == 'undefined') yearsArr[y] = {}; 754 if(typeof yearsArr[y][m] == 'undefined') yearsArr[y][m] = {}; 755 yearsArr[y][m][d] = dataId; 756 var isActive = (index == data.currentIndex ? ' active' : ''); 757 if(data.options.categories) { 758 var leftPos = (100/monthsDays[m])*d; 759 } 760 else { 761 var leftPos = (100/(maxY-minY))*(d-minY); 762 } 763 var nName = ((typeof nodeName != 'undefined') ? nodeName : d);
764 // Store node element 765 nodes[dataId] = '<a href="#'+dataId+'" class="t_line_node'+isActive+'" style="left: '+leftPos+'%; position:absolute; text-align:center;">'+nName; 766 767 if(typeof dataDesc != 'undefined') nodes[dataId]+= '<span class="t_node_desc" style="white-space:nowrap; position:absolute; z-index: 1;"><span>'+dataDesc+'</span></span>'; 768 769 nodes[dataId]+='</a>\n'; 770 }); 771 // Make wrapper elements 772 html = '\n' + 773' <div id="t_line_left" style="position: absolute;"></div><div id="t_line_right" style="position: absolute;"></div>\n' + 774' <div class="t_line_holder" style="position:relative; overflow: hidden; width:100%;">\n' + 775' <div class="t_line_wrapper" style="white-space:nowrap;">\n'; 776 777 // Prepare for loop, every view has 2 months, we show both if first has nodes in it 778 779 if (!data.options.categories) { 780 html += 781 '<div class="t_line_view" data-id="'+cnt+'" style="position:relative; display:inline-block; width:100%;">\n'+ 782 ' <div class="t_line_m" style="width:100%; border:0; position:absolute; top:0;">\n'; 783 for (var x in nodes) { 784 html += nodes[x]; 785 } 786 html += '</div>\n'+ 787 '</div>'; 788 } 789 else { 790 var firstMonth = true; 791 var cnt = 0; 792 for(var yr in yearsArr) { 793 for(var mnth in yearsArr[yr]) { 794 if (firstMonth) { 795 firstMonth = !firstMonth; 796 html += 797 '<div class="t_line_view" data-id="'+cnt+'" style="position:relative; display:inline-block;">\n'+ 798 ' <div class="t_line_m" style="position:absolute; top:0;">\n'+ 799 ' <h4 class="t_line_month" style="position:abolute; width:100% top:0; text-align:center;">'+months[mnth]+(data.options.yearsOn ? '<span class="t_line_month_year"> '+(yr < 0 ? (-yr)+' B.C.' : yr)+'</span>' : '' )+'</h4>\n'; 800 801 // Fill with nodes 802 for (dy in yearsArr[yr][mnth]) { 803 html+= nodes[yearsArr[yr][mnth][dy]]; 804 805 } 806 html += 807 ' </div> <!-- KRAJ PRVOG -->\n'; 808 } 809 else { 810 firstMonth = !firstMonth; 811 html += 812 ' <div class="t_line_m right" style="position:absolute; top:0;">\n'+ 813 ' <h4 class="t_line_month" style="position:abolute; width:100% top:0; text-align:center;">'+(typeof months[mnth] !== 'undefined' ? months[mnth] : '')+(data.options.yearsOn ? '<span class="t_line_month_year"> '+yr+'</span>' : '' )+'</h4>\n'; 814 815 // Fill with nodes 816 for (dy in yearsArr[yr][mnth]) { 817 html+= nodes[yearsArr[yr][mnth][dy]]; 818 819 } 820 html += 821 ' </div><!-- KRAJ DRUGOG -->\n'+ 822 ' <div style="clear:both"></div>\n'+ 823 ' </div>'; 824 cnt++; 825 826 } 827 } 828 } 829 if (!firstMonth) { 830 html += 831 ' <div class="t_line_m right" style="position:absolute; top:0;">\n'+ 832 ' <h4 class="t_line_month" style="position:abolute; width:100% top:0; text-align:center;"></h4>\n'+ 833 ' </div>\n'+ 834 ' <div style="clear:both"></div>\n'+ 835 ' </div>'; 836 cnt++; 837 } 838 } 839 840 841 842 html += '\n' + 843' <div style="clear:both"></div>\n'+ 844' </div>\n'+ 845' </div>\n'; 846 847 // Set number of View elements 848 data.lineViewCount = cnt; 849 // Add generated html and set width & margin for dinamic timeline 850 $this.find('.timeline_line:first').html(html); 851 $this.find('.t_line_node').each(function(){ 852 var $thisNode = $(this); 853 $(this).find('span').hide(); 854 $(this).hover(function(){ 855 $items.each(function(){ 856 if($(this).attr('data-id') == $thisNode.attr('href').substr(1)) { 857 $(this).addClass('item_node_hover'); 858 } 859 }); 860 $(this).find('span').css('display','block'); 861 }, function(){ 862 $(this).find('span').css('display','none'); 863 $('.item_node_hover').removeClass('item_node_hover'); 864 }); 865 866 //Position lineView to selected item 867 if($(this).hasClass('active')) { 868 data.lineMargin = -parseInt($(this).parent().parent('.t_line_view').attr('data-id'),10)*100; 869 $this.find('.t_line_wrapper').css('margin-left', data.lineMargin+'%'); 870 } 871 // Bind goTo function to click event 872 873 var clickEventType=((document.ontouchstart!==null)?'click':'touchstart'); 874 875 $(this).bind(clickEventType, function(e){
876 e.preventDefault(); 877 $this.find('.t_line_node').removeClass('active'); 878 $(this).addClass('active'); 879 $this.timeline('goTo', $(this).attr('href').substr(1)); 880 }); 881 882 883 }); 884 885 $this.find('#t_line_left').click(function(){ 886 $this.timeline('lineLeft'); 887 }); 888 889 $this.find('#t_line_right').click(function(){ 890 $this.timeline('lineRight'); 891 }); 892 893 } 894 }; 895 896 // Initiate methods 897 $.fn.timeline = function( method ) { 898 899 if ( t_methods[method] ) { 900 return t_methods[method].apply( this, Array.prototype.slice.call( arguments, 1 )); 901 } else if ( typeof method === 'object' || ! method ) { 902 return t_methods.init.apply( this, arguments ); 903 } else { 904 $.error( 'Method ' + method + ' does not exist on jQuery.timeline' ); 905 } 906 907 }; 908 909 910 911 912 913})(jQuery);
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.