1jQuery(document).ready(function($){ 2 var timelineBlocks = $('.cd-timeline-block'), 3 offset = 0.8; 4 5 //hide timeline blocks which are outside the viewport 6 hideBlocks(timelineBlocks, offset); 7 8 //on scolling, show/animate timeline blocks when enter the viewport 9 $(window).on('scroll', function(){ 10 (!window.requestAnimationFrame) 11 ? setTimeout(function(){ showBlocks(timelineBlocks, offset); }, 100) 12 : window.requestAnimationFrame(function(){ showBlocks(timelineBlocks, offset); }); 13 }); 14 15 function hideBlocks(blocks, offset) { 16 blocks.each(function(){ 17 ( $(this).offset().top > $(window).scrollTop()+$(window).height()*offset ) && $(this).find('.cd-timeline-img, .cd-timeline-content').addClass('is-hidden'); 18 }); 19 } 20 21 function showBlocks(blocks, offset) { 22 blocks.each(function(){ 23 ( $(this).offset().top <= $(window).scrollTop()+$(window).height()*offset && $(this).find('.cd-timeline-img').hasClass('is-hidden') ) && $(this).find('.cd-timeline-img, .cd-timeline-content').removeClass('is-hidden').addClass('bounce-in'); 24 }); 25 } 26}); 27 28jQuery(document).ready(function($){ 29 var timelines = $('.cd-horizontal-timeline'), 30 eventsMinDistance = 60; 31 32 (timelines.length > 0) && initTimeline(timelines); 33 34 function initTimeline(timelines) { 35 timelines.each(function(){ 36 var timeline = $(this), 37 timelineComponents = {}; 38 //cache timeline components 39 timelineComponents['timelineWrapper'] = timeline.find('.events-wrapper'); 40 timelineComponents['eventsWrapper'] = timelineComponents['timelineWrapper'].children('.events'); 41 timelineComponents['fillingLine'] = timelineComponents['eventsWrapper'].children('.filling-line'); 42 timelineComponents['timelineEvents'] = timelineComponents['eventsWrapper'].find('a'); 43 timelineComponents['timelineDates'] = parseDate(timelineComponents['timelineEvents']); 44 timelineComponents['eventsMinLapse'] = minLapse(timelineComponents['timelineDates']); 45 timelineComponents['timelineNavigation'] = timeline.find('.cd-timeline-navigation'); 46 timelineComponents['eventsContent'] = timeline.children('.events-content'); 47 48 //assign a left postion to the single events along the timeline 49 setDatePosition(timelineComponents, eventsMinDistance); 50 //assign a width to the timeline 51 var timelineTotWidth = setTimelineWidth(timelineComponents, eventsMinDistance); 52 //the timeline has been initialize - show it 53 timeline.addClass('loaded'); 54 55 //detect click on the next arrow 56 timelineComponents['timelineNavigation'].on('click', '.next', function(event){ 57 event.preventDefault(); 58 updateSlide(timelineComponents, timelineTotWidth, 'next'); 59 }); 60 //detect click on the prev arrow 61 timelineComponents['timelineNavigation'].on('click', '.prev', function(event){ 62 event.preventDefault(); 63 updateSlide(timelineComponents, timelineTotWidth, 'prev'); 64 }); 65 //detect click on the a single event - show new event content 66 timelineComponents['eventsWrapper'].on('click', 'a', function(event){ 67 //event.preventDefault(); 68 timelineComponents['timelineEvents'].removeClass('selected'); 69 $(this).addClass('selected'); 70 updateOlderEvents($(this)); 71 updateFilling($(this), timelineComponents['fillingLine'], timelineTotWidth); 72 //updateVisibleContent($(this), timelineComponents['eventsContent']); 73 }); 74 75 //on swipe, show next/prev event content 76 timelineComponents['eventsContent'].on('swipeleft', function(){ 77 var mq = checkMQ(); 78 ( mq == 'mobile' ) && showNewContent(timelineComponents, timelineTotWidth, 'next'); 79 }); 80 timelineComponents['eventsContent'].on('swiperight', function(){ 81 var mq = checkMQ(); 82 ( mq == 'mobile' ) && showNewContent(timelineComponents, timelineTotWidth, 'prev'); 83 }); 84 85 //keyboard navigation 86 $(document).keyup(function(event){ 87 if(event.which=='37' && elementInViewport(timeline.get(0)) ) { 88 showNewContent(timelineComponents, timelineTotWidth, 'prev'); 89 } else if( event.which=='39' && elementInViewport(timeline.get(0))) { 90 showNewContent(timelineComponents, timelineTotWidth, 'next'); 91 } 92 }); 93 }); 94 } 95 96 function updateSlide(timelineComponents, timelineTotWidth, string) { 97 //retrieve translateX value of timelineComponents['eventsWrapper'] 98 var translateValue = getTranslateValue(timelineComponents['eventsWrapper']),
99 wrapperWidth = Number(timelineComponents['timelineWrapper'].css('width').replace('px', '')); 100 //translate the timeline to the left('next')/right('prev') 101 (string == 'next') 102 ? translateTimeline(timelineComponents, translateValue - wrapperWidth + eventsMinDistance, wrapperWidth - timelineTotWidth) 103 : translateTimeline(timelineComponents, translateValue + wrapperWidth - eventsMinDistance); 104 } 105 106 function showNewContent(timelineComponents, timelineTotWidth, string) { 107 //go from one event to the next/previous one 108 var visibleContent = timelineComponents['eventsContent'].find('.selected'), 109 newContent = ( string == 'next' ) ? visibleContent.next() : visibleContent.prev(); 110 111 if ( newContent.length > 0 ) { //if there's a next/prev event - show it 112 var selectedDate = timelineComponents['eventsWrapper'].find('.selected'), 113 newEvent = ( string == 'next' ) ? selectedDate.parent('li').next('li').children('a') : selectedDate.parent('li').prev('li').children('a'); 114 115 updateFilling(newEvent, timelineComponents['fillingLine'], timelineTotWidth); 116 updateVisibleContent(newEvent, timelineComponents['eventsContent']); 117 newEvent.addClass('selected'); 118 selectedDate.removeClass('selected'); 119 updateOlderEvents(newEvent); 120 updateTimelinePosition(string, newEvent, timelineComponents, timelineTotWidth); 121 } 122 } 123 124 function updateTimelinePosition(string, event, timelineComponents, timelineTotWidth) { 125 //translate timeline to the left/right according to the position of the selected event 126 var eventStyle = window.getComputedStyle(event.get(0), null), 127 eventLeft = Number(eventStyle.getPropertyValue("left").replace('px', '')), 128 timelineWidth = Number(timelineComponents['timelineWrapper'].css('width').replace('px', '')), 129 timelineTotWidth = Number(timelineComponents['eventsWrapper'].css('width').replace('px', '')); 130 var timelineTranslate = getTranslateValue(timelineComponents['eventsWrapper']); 131 132 if( (string == 'next' && eventLeft > timelineWidth - timelineTranslate) || (string == 'prev' && eventLeft < - timelineTranslate) ) { 133 translateTimeline(timelineComponents, - eventLeft + timelineWidth/2, timelineWidth - timelineTotWidth); 134 } 135 } 136 137 function translateTimeline(timelineComponents, value, totWidth) { 138 var eventsWrapper = timelineComponents['eventsWrapper'].get(0); 139 value = (value > 0) ? 0 : value; //only negative translate value 140 value = ( !(typeof totWidth === 'undefined') && value < totWidth ) ? totWidth : value; //do not translate more than timeline width 141 setTransformValue(eventsWrapper, 'translateX', value+'px'); 142 //update navigation arrows visibility 143 (value == 0 ) ? timelineComponents['timelineNavigation'].find('.prev').addClass('inactive') : timelineComponents['timelineNavigation'].find('.prev').removeClass('inactive'); 144 (value == totWidth ) ? timelineComponents['timelineNavigation'].find('.next').addClass('inactive') : timelineComponents['timelineNavigation'].find('.next').removeClass('inactive'); 145 } 146 147 function updateFilling(selectedEvent, filling, totWidth) { 148 //change .filling-line length according to the selected event 149 var eventStyle = window.getComputedStyle(selectedEvent.get(0), null), 150 eventLeft = eventStyle.getPropertyValue("left"), 151 eventWidth = eventStyle.getPropertyValue("width"); 152 eventLeft = Number(eventLeft.replace('px', '')) + Number(eventWidth.replace('px', ''))/2; 153 var scaleValue = eventLeft/totWidth; 154 setTransformValue(filling.get(0), 'scaleX', scaleValue); 155 } 156 157 function setDatePosition(timelineComponents, min) { 158 for (i = 0; i < timelineComponents['timelineDates'].length; i++) { 159 var distance = daydiff(timelineComponents['timelineDates'][0], timelineComponents['timelineDates'][i]), 160 distanceNorm = Math.round(distance/timelineComponents['eventsMinLapse']) + 2; 161 timelineComponents['timelineEvents'].eq(i).css('left', distanceNorm*min+'px'); 162 } 163 } 164 165 function setTimelineWidth(timelineComponents, width) { 166 var timeSpan = daydiff(timelineComponents['timelineDates'][0], timelineComponents['timelineDates'][timelineComponents['timelineDates'].length-1]), 167 timeSpanNorm = timeSpan/timelineComponents['eventsMinLapse'], 168 timeSpanNorm = Math.round(timeSpanNorm) + 4, 169 totalWidth = timeSpanNorm*width; 170 timelineComponents['eventsWrapper'].css('width', totalWidth+'px'); 171 updateFilling(timelineComponents['timelineEvents'].eq(0), timelineComponents['fillingLine'], totalWidth);
172 173 return totalWidth; 174 } 175 176 function updateVisibleContent(event, eventsContent) { 177 var eventDate = event.data('date'), 178 visibleContent = eventsContent.find('.selected'), 179 selectedContent = eventsContent.find('[data-date="'+ eventDate +'"]'), 180 selectedContentHeight = selectedContent.height(); 181 182 if (selectedContent.index() > visibleContent.index()) { 183 var classEnetering = 'selected enter-right', 184 classLeaving = 'leave-left'; 185 } else { 186 var classEnetering = 'selected enter-left', 187 classLeaving = 'leave-right'; 188 } 189 190 selectedContent.attr('class', classEnetering); 191 visibleContent.attr('class', classLeaving).one('webkitAnimationEnd oanimationend msAnimationEnd animationend', function(){ 192 visibleContent.removeClass('leave-right leave-left'); 193 selectedContent.removeClass('enter-left enter-right'); 194 }); 195 eventsContent.css('height', selectedContentHeight+'px'); 196 } 197 198 function updateOlderEvents(event) { 199 event.parent('li').prevAll('li').children('a').addClass('older-event').end().end().nextAll('li').children('a').removeClass('older-event'); 200 } 201 202 function getTranslateValue(timeline) { 203 var timelineStyle = window.getComputedStyle(timeline.get(0), null), 204 timelineTranslate = timelineStyle.getPropertyValue("transform"); 205 206 if (timelineTranslate === 'none') { 207 return 0; 208 } 209 210 var values = timelineTranslate.match(/matrix.*\((.+)\)/)[1].split(','); 211 212 // matrix(a, b, c, d, tx, ty) 213 if (values.length === 6) { 214 return Number(values[4]); 215 } 216 217 // matrix3d(..., tx, ty, tz) 218 if (values.length === 16) { 219 return Number(values[12]); 220 } 221 222 return 0; 223 } 224 225 function setTransformValue(element, property, value) { 226 element.style["-webkit-transform"] = property+"("+value+")"; 227 element.style["-moz-transform"] = property+"("+value+")"; 228 element.style["-ms-transform"] = property+"("+value+")"; 229 element.style["-o-transform"] = property+"("+value+")"; 230 element.style["transform"] = property+"("+value+")"; 231 } 232 233 //based on http://stackoverflow.com/questions/542938/how-do-i-get-the-number-of-days-between-two-dates-in-javascript 234 function parseDate(events) { 235 var dateArrays = []; 236 events.each(function(){ 237 //var dateComp = $(this).data('date').split('/'), 238 //newDate = new Date(dateComp[2], dateComp[1]-1, dateComp[0]); 239 //dateArrays.push(newDate); 240 var dateComp = $(this).data('date'), 241 newDate = new Date(dateComp); 242 dateArrays.push(newDate); 243 }); 244 return dateArrays; 245 } 246 247 function parseDate2(events) { 248 var dateArrays = []; 249 events.each(function(){ 250 var singleDate = $(this), 251 dateComp = singleDate.data('date').split('T'); 252 if( dateComp.length > 1 ) { //both DD/MM/YEAR and time are provided 253 var dayComp = dateComp[0].split('/'), 254 timeComp = dateComp[1].split(':'); 255 } else if( dateComp[0].indexOf(':') >=0 ) { //only time is provide 256 var dayComp = ["2000", "0", "0"], 257 timeComp = dateComp[0].split(':'); 258 } else { //only DD/MM/YEAR 259 var dayComp = dateComp[0].split('/'), 260 timeComp = ["0", "0"]; 261 } 262 var newDate = new Date(dayComp[2], dayComp[1]-1, dayComp[0], timeComp[0], timeComp[1]); 263 dateArrays.push(newDate); 264 }); 265 return dateArrays; 266 } 267 268 function daydiff(first, second) { 269 return Math.round((second-first)); 270 } 271 272 function minLapse(dates) { 273 //determine the minimum distance among events 274 var dateDistances = []; 275 for (i = 1; i < dates.length; i++) { 276 var distance = daydiff(dates[i-1], dates[i]); 277 dateDistances.push(distance); 278 } 279 return Math.min.apply(null, dateDistances); 280 } 281 282 /* 283 How to tell if a DOM element is visible in the current viewport? 284 http://stackoverflow.com/questions/123999/how-to-tell-if-a-dom-element-is-visible-in-the-current-viewport 285 */ 286 function elementInViewport(el) { 287 var top = el.offsetTop; 288 var left = el.offsetLeft; 289 var width = el.offsetWidth; 290 var height = el.offsetHeight; 291 292 while(el.offsetParent) { 293 el = el.offsetParent; 294 top += el.offsetTop; 295 left += el.offsetLeft; 296 } 297 298 return ( 299 top < (window.pageYOffset + window.innerHeight) && 300 left < (window.pageXOffset + window.innerWidth) && 301 (top + height) > window.pageYOffset && 302 (left + width) > window.pageXOffset 303 ); 304 } 305 306 function checkMQ() { 307 //check if mobile or desktop device 308 return window.getComputedStyle(document.querySelector('.cd-horizontal-timeline'), '::before').getPropertyValue('content').replace(/'/g, "").replace(/"/g, ""); 309 } 310});
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.