PageSourceSearch

https://www.ucc.ie/en/media/2017siteassets/contentfiles/js/jquery.timeline.js

js ucc.ie collected 2026-09-24 07:29:44 UTC 29,842 bytes, 913 lines download raw bytes

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.