PageSourceSearch

https://www.winterthur.org/wp-content/themes/winterthur/assets/js/jquery.youtube-background.js?ver=5.9.13

js winterthur.org collected 2026-10-01 10:31:13 UTC 17,739 bytes, 611 lines download raw bytes

1/* jquery.youtube-background v1.0.7 | Nikola Stamatovic <@stamat> | MIT */
2
3var tag = document.createElement('script');
4tag.src = "https://www.youtube.com/player_api";
5var firstScriptTag = document.getElementsByTagName('script')[0];
6firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
7
8
9//native addClass, removeClass, hasClass and toggleClass
10if (!window.hasOwnProperty('d0')) {
11	window.d0 = {};
12
13	d0.hasClass = function(element, className) {
14		if (element.classList) {
15			return element.classList.contains(className);
16		}
17	    return new RegExp('\\b'+ className+'\\b').test(element.className);
18	};
19
20	d0.addClass = function(element, className) {
21	    if (element.classList) {
22			element.classList.add(className);
23			return;
24		}
25
26		if (!d0.hasClass(element, className)) {
27			element.className += ' ' + className;
28		}
29	};
30
31	d0.removeClass = function(element, className) {
32	    if (element.classList) {
33			element.classList.remove(className);
34			return;
35		}
36
37		element.className = element.className.replace(new RegExp('\\b'+ className+'\\b', 'g'), '');
38	};
39
40	d0.toogleClass = function(element, className) {
41	    if (d0.hasClass(element, className)) {
42			d0.removeClass(element, className);
43		} else {
44			d0.addClass(element, className);
45		}
46	};
47}
48
49function YoutubeBackground(elem, params, id, uid) {
50	this.is_mobile = this.isMobile();
51
52	this.element = elem;
53	this.ytid = id;
54	this.uid = uid;
55	this.player = null;
56	this.buttons = {};
57
58	this.state = {};
59	this.state.play = false;
60	this.state.mute = false;
61
62	this.params = {};
63
64	this.defaults = {
65		'fitToBackground': true,
66		'pause': false, //deprecated
67		'play-button': false,
68		'mute-button': false,
69		'autoplay': true,
70		'muted': true,
71		'loop': true,
72		'mobile': false,
73		'load-background': true,
74		'resolution': '16:9',
75		'offset': 200
76	};
77
78	this.__init__ = function () {
79		if (!this.ytid) {
80			return;
81		}
82
83		this.parseProperties(params);
84		this.params.resolution_mod = this.parseResolutionString(this.params.resolution);
85		this.state.playing = this.params.autoplay;
86		this.state.muted = this.params.muted;
87
88		this.buildHTML();
89		this.injectIFrame();
90
91
92		if (this.params['play-button']) {
93			this.generateActionButton({
94				name: 'play',
95				className: 'play-toggle',
96				innerHtml: '<i class="fa"></i>',
97				initialState: false,
98				stateClassName: 'paused',
99				condition_parameter: 'autoplay',
100				stateChildClassNames: ['fa-pause-circle', 'fa-play-circle'],
101				actions: ['play', 'pause']
102			});
103		}
104
105		if (this.params['mute-button']) {
106			this.generateActionButton({
107				name: 'mute',
108				className: 'mute-toggle',
109				innerHtml: '<i class="fa"></i>',
110				initialState: true,
111				stateClassName: 'muted',
112				condition_parameter: 'muted',
113				stateChildClassNames: ['fa-volume-up', 'fa-volume-mute'],
114				actions: ['unmute', 'mute']
115			});
116		}
117	}
118
119	this.__init__();
120}
121
122YoutubeBackground.prototype.initYTPlayer = function () {
123	var self = this;
124
125	if (window.hasOwnProperty('YT')) {
126		this.player = new YT.Player(this.uid, {
127			events: {
128				'onReady': function(event) {
129					self.onVideoPlayerReady(event);
130				},
131				'onStateChange': function(event) {
132					self.onVideoStateChange(event);
133				},
134				'onError' : function(event) {
135					//console.error('player_api', event);
136				}
137			}
138		});
139	}
140};
141
142YoutubeBackground.prototype.onVideoPlayerReady = function (event) {
143	if (this.params.autoplay) {
144		event.target.playVideo();
145	}
146};
147
148YoutubeBackground.prototype.onVideoStateChange = function (event) {
149	if (event.data === 0 && this.params.loop) {
150		event.target.playVideo();
151	}
152
153	if (event.data === -1 && this.params.autoplay) {
154		event.target.playVideo();
155	}
156
157	if (event.data === 1) {
158		this.iframe.style.opacity = 1;
159	}
160};
161
162YoutubeBackground.prototype.parseProperties = function (params) {
163	if (!params) {
164		this.params = this.defaults;
165	} else {
166		//load in defaults
167		for (var k in this.defaults) {
168			if (!this.params.hasOwnProperty(k)) {
169				this.params[k] = this.defaults[k];
170			}
171		}
172	}
173
174	// load params from data attributes
175	for (var k in this.params) {
176		var data = this.element.getAttribute('data-ytbg-'+k);
177
178		if (data !== undefined && data !== null) {
179			switch (data) {
180				case data === 'false':
181					data = false;
182					break;
183				case data === 'true':
184					data = true;
185					break;
186			}
187
188			this.params[k] = data;
189		}
190	}
191
192	//pause deprecated
193	if (this.params.pause) {
194		this.params['play-button'] = this.params.pause;
195	}
196};
197
198YoutubeBackground.prototype.injectIFrame = function () {
199	this.iframe = document.createElement('iframe');
200	this.iframe.setAttribute('frameborder', 0);
201	this.iframe.setAttribute('title', 'Video Background');
202	this.iframe.setAttribute('allow', ['autoplay; mute']);
203	var src = 'https://www.youtube.com/embed/'+this.ytid+'?enablejsapi=1&disablekb=1&controls=0&rel=0&iv_load_policy=3&cc_load_policy=0&playsinline=1&showinfo=0&modestbranding=1&fs=0&origin='+window.location.origin;
204
205	if (this.params.muted) {
206		src += '&mute=1';
207	}
208
209	if (this.params.autoplay) {
210		src += '&autoplay=1';
211	}
212
213	if (this.params.loop) {
214		src += '&loop=1';
215	}
216
217	this.iframe.src = src;
218
219	if (this.uid) {
220		this.iframe.id = this.uid;
221	}
222
223	this.iframe.style.top = '50%';
224	this.iframe.style.left = '50%';
225	this.iframe.style.transform = 'translateX(-50%) translateY(-50%)';
226	this.iframe.style.position = 'absolute';
227	this.iframe.style.opacity = 0;
228
229	this.element.parentNode.appendChild(this.iframe);
230	this.iframe.parentNode.removeChild(this.element);
231
232	var self = this;
233
234	function onResize() {
235		var h = self.iframe.parentNode.offsetHeight + self.params.offset; // since showinfo is deprecated and ignored after September 25, 2018. we add +200 to hide it in the overflow
236		var w = self.iframe.parentNode.offsetWidth + self.params.offset;
237		var res = self.params.resolution_mod;
238
239		if (res > w/h) {
240			self.iframe.style.width = h*res + 'px';
241			self.iframe.style.height = h + 'px';
242		} else {
243			self.iframe.style.width = w + 'px';
244			self.iframe.style.height = w/res + 'px';
245		}
246	}
247
248	window.addEventListener('resize', onResize);
249	onResize();
250};
251
252YoutubeBackground.prototype.buildHTML = function () {
253	var parent = this.element.parentNode;
254	// wrap
255	var wrapper = document.createElement('div');
256	wrapper.className = 'youtube-background';
257	parent.insertBefore(wrapper, this.element);
258	wrapper.appendChild(this.element);
259	var id = this.element.id;
260	this.element.id = '';
261	wrapper.id = id;
262
263	//set css rules
264	var wrapper_styles = {
265		"height" : "100%",
266		"width" : "100%",
267		"z-index": "0",
268		"position": "absolute",
269		"overflow": "hidden",
270		"top": 0, // added by @insad
271		"left": 0,
272		"bottom": 0,
273		"right": 0
274	};
275
276	if (!this.params['mute-button']) {
277		wrapper_styles["pointer-events"] = "none" // avoid right mouse click popup menu
278	}
279
280	if (this.params['load-background']) {
281		wrapper_styles['background-image'] = 'url(https://img.youtube.com/vi/'+this.ytid+'/maxresdefault.jpg)';
282		wrapper_styles['background-size'] = 'cover';
283		wrapper_styles['background-repeat'] = 'no-repeat';
284		wrapper_styles['background-position'] = 'center';
285	}
286
287	for (var property in wrapper_styles) {
288		wrapper.style[property] = wrapper_styles[property];
289	}
290
291	wrapper.parentNode.style.position = 'relative';
292
293	if (this.is_mobile && !this.params.mobile) {
294		return wrapper;
295	}
296
297	// set play/mute controls wrap
298	if (this.params['play-button'] || this.params['mute-button']) {
299		var controls = document.createElement('div');
300		controls.className = 'video-background-controls';
301
302		controls.style.position = 'absolute';
303		controls.style.top = '10px';
304		controls.style.right = '10px';
305		controls.style['z-index'] = 2;
306
307		this.controls_element = controls;
308		wrapper.parentNode.appendChild(controls);
309	}
310
311	return wrapper;
312};
313
314YoutubeBackground.prototype.play = function () {
315	if (this.buttons.hasOwnProperty('play')) {
316		var btn_obj = this.buttons.play;
317		d0.removeClass(btn_obj.element, btn_obj.button_properties.stateClassName);
318		d0.addClass(btn_obj.element.firstChild, btn_obj.button_properties.stateChildClassNames[0])
319		d0.removeClass(btn_obj.element.firstChild, btn_obj.button_properties.stateChildClassNames[1]);
320	}
321
322	if (this.player) {
323		this.player.playVideo();
324	}
325}
326
327YoutubeBackground.prototype.pause = function () {
328	if (this.buttons.hasOwnProperty('play')) {
329		var btn_obj = this.buttons.play;
330		d0.addClass(btn_obj.element, btn_obj.button_properties.stateClassName);
331		d0.removeClass(btn_obj.element.firstChild, btn_obj.button_properties.stateChildClassNames[0])
332		d0.addClass(btn_obj.element.firstChild, btn_obj.button_properties.stateChildClassNames[1]);
333	}
334
335	if (this.player) {
336		this.player.pauseVideo();
337	}
338}
339
340YoutubeBackground.prototype.unmute = function () {
341	if (this.buttons.hasOwnProperty('mute')) {
342		var btn_obj = this.buttons.mute;
343		d0.removeClass(btn_obj.element, btn_obj.button_properties.stateClassName);
344		d0.addClass(btn_obj.element.firstChild, btn_obj.button_properties.stateChildClassNames[0])
345		d0.removeClass(btn_obj.element.firstChild, btn_obj.button_properties.stateChildClassNames[1]);
346	}
347
348	if (this.player) {
349		this.player.unMute();
350	}
351}
352
353YoutubeBackground.prototype.mute = function () {
354	if (this.buttons.hasOwnProperty('mute')) {
355		var btn_obj = this.buttons.mute;
356		d0.addClass(btn_obj.element, btn_obj.button_properties.stateClassName);
357		d0.removeClass(btn_obj.element.firstChild, btn_obj.button_properties.stateChildClassNames[0])
358		d0.addClass(btn_obj.element.firstChild, btn_obj.button_properties.stateChildClassNames[1]);
359	}
360
361	if (this.player) {
362		this.player.mute();
363	}
364}
365
366//TODO: refactor states to be equal for all buttons
367YoutubeBackground.prototype.generateActionButton = function (obj) {
368	var btn = document.createElement('button');
369	btn.className = obj.className;
370	btn.innerHTML = obj.innerHtml;
371	d0.addClass(btn.firstChild, obj.stateChildClassNames[0]);
372
373	if (this.params[obj.condition_parameter] == obj.initialState) {
374		d0.addClass(btn, obj.stateClassName);
375		d0.removeClass(btn.firstChild, obj.stateChildClassNames[0]);
376		d0.addClass(btn.firstChild, obj.stateChildClassNames[1]);
377	}
378
379	var self = this;
380	btn.addEventListener('click', function(e) {
381		if (d0.hasClass(this, obj.stateClassName)) {
382			self.state[obj.name] = false;
383			self[obj.actions[0]]();
384		} else {
385			self.state[obj.name] = true;
386			self[obj.actions[1]]();
387		}
388	});
389
390	this.buttons[obj.name] = {
391		element: btn,
392		button_properties: obj
393	};
394
395	this.controls_element.appendChild(btn);
396};
397
398
399YoutubeBackground.prototype.parseResolutionString = function (res) {
400	var pts = res.split(/\s?:\s?/i);
401	if (pts.length < 2) {
402		return 16/9;
403	}
404
405	var w = parseInt(pts[0], 10);
406	var h = parseInt(pts[1], 10);
407
408	if (isNaN(w) || isNaN(h)) {
409		return 16/9;
410	}
411
412	return w/h;
413};
414
415YoutubeBackground.prototype.isMobile = function (event) {
416	var is_mobile = false;
417	(function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|
417sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) is_mobile = true;})(navigator.userAgent||navigator.vendor||window.opera);
418
419	return is_mobile;
420};
421
422YoutubeBackground.prototype.error = function (message, value) {
423	if (window.hasOwnProperty('console')
424		&& window.console.hasOwnProperty('error')) {
425		console.error(message, value);
426	}
427};
428
429function ActivityMonitor(on_activity, on_inactivity, activity_timeout, inactivity_timeout, events) {
430	this.timer = null;
431	this.timeout = inactivity_timeout || 10000;
432	this.activity_timer = null; //for event throttling
433	this.activity_timeout = activity_timeout || 1000;
434	this.last_activity = null;
435
436	this.resetTimer = function() {
437		if (this.timer) {
438			clearTimeout(this.timer);
439			this.timer = null;
440		}
441
442		var self = this;
443		this.timer = setTimeout(function() {
444			if (self.last_activity + self.timeout + self.activity_timeout
445				>= new Date().getTime()) {
446					if (on_inactivity) {
447						on_inactivity();
448					}
449			}
450		}, this.timeout);
451	};
452
453	this.logActivity = function() {
454		this.last_activity = new Date().getTime();
455
456		if (on_activity) {
457			on_activity();
458		}
459	};
460
461	this.onActivity = function() {
462		if (!this.activity_timer) {
463			var self = this;
464			this.activity_timer = setTimeout(function(){
465				self.logActivity();
466				self.resetTimer();
467
468				clearTimeout(self.activity_timer);
469				self.activity_timer = null;
470			}, this.activity_timeout);
471		}
472	};
473
474	this.__init__ = function() {
475		var self = this;
476
477		if (!events) {
478			events = ['click', 'mousemove', 'scroll'];
479		} else {
480			if (typeof events === 'string') {
481				events = [events];
482			}
483		}
484
485		for (var i = 0; i < events.length; i++) {
486			document.addEventListener(events[i], function() {
487				self.onActivity();
488			});
489		}
490	};
491
492	this.__init__();
493}
494
495function VideoBackgrounds(selector, params) {
496	this.elements = selector;
497
498	if (typeof selector === 'string') {
499		this.elements = document.querySelectorAll(selector);
500	}
501
502	this.index = {};
503	this.re = {};
504	this.re.YOUTUBE = /(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/ ]{11})/i;
505
506	this.__init__ = function () {
507		for (var i = 0; i < this.elements.length; i++) {
508			var element = this.elements[i];
509
510			var link = element.getAttribute('data-youtube');
511			var ytid = this.getYTID(link);
512			var uid = this.generateUID(ytid);
513
514			var yb = new YoutubeBackground(element, params, ytid, uid);
515
516			if (!uid) {
517				continue;
518			}
519
520			this.index[uid] = yb;
521		}
522
523		var self = this;
524
525		this.initYTPlayers(function() {
526			//TODO: FIX!
527			if (params &&
528				(params.hasOwnProperty('activity_timeout')
529				|| params.hasOwnProperty('inactivity_timeout'))) {
530					this.activity_monitor = new ActivityMonitor(function () {
531						self.playVideos();
532					}, function() {
533						self.pauseVideos();
534					},
535					params ? params.activity_timeout : null,
536					params ? params.inactivity_timeout : null,
537					['mousemove', 'scroll']
538				);
539			}
540		});
541	};
542
543	this.__init__();
544}
545
546VideoBackgrounds.prototype.getYTID = function (link) {
547	if (link !== undefined && link !== null) {
548		var pts = link.match(this.re.YOUTUBE);
549		if (pts && pts.length) {
550			this.re.YOUTUBE.lastIndex = 0; //regex needs a reset in for loops, I always forget this
551			return pts[1];
552		}
553	}
554	return null;
555};
556
557VideoBackgrounds.prototype.generateUID = function (pref) {
558	//index the instance
559	function getRandomIntInclusive(min, max) {
560		min = Math.ceil(min);
561		max = Math.floor(max);
562		return Math.floor(Math.random() * (max - min + 1)) + min; //The maximum is inclusive and the minimum is inclusive
563	}
564
565	var uid = pref +'-'+ getRandomIntInclusive(0, 9999);
566	while (this.index.hasOwnProperty(uid)) {
567		uid = pref +'-'+ getRandomIntInclusive(0, 9999);
568	}
569
570	return uid;
571};
572
573VideoBackgrounds.prototype.pauseVideos = function () {
574	for (var k in this.index) {
575		this.index[k].pause();
576	}
577};
578
579VideoBackgrounds.prototype.playVideos = function () {
580	for (var k in this.index) {
581		this.index[k].play();
582	}
583};
584
585VideoBackgrounds.prototype.initYTPlayers = function (callback) {
586	var self = this;
587
588	window.onYouTubeIframeAPIReady = function () {
589		for (var k in self.index) {
590			self.index[k].initYTPlayer();
591		}
592
593		if (callback) {
594			setTimeout(callback, 100);
595		}
596	};
597
598	if (window.hasOwnProperty('YT') && window.YT.loaded) {
599		window.onYouTubeIframeAPIReady();
600	}
601};
602
603if (window.hasOwnProperty('jQuery')) {
604	(function ($) {
605	    $.fn.youtube_background = function(params) {
606	        var $this = $(this);
607			new VideoBackgrounds(this, params);
608	 		return $this;
609	 	};
610	})(jQuery);
611}

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.