PageSourceSearch

https://www.letrasgalegas.org/includes/js_responsive/timeline.js

js letrasgalegas.org collected 2026-10-02 12:06:31 UTC 13,469 bytes, 310 lines download raw bytes

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.