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