PageSourceSearch

https://cinefil.tokyo/static/lib/jquery-carousel/jquery-carousel.js?260826032636

js cinefil.tokyo collected 2026-09-24 21:06:38 UTC 16,695 bytes, 548 lines download raw bytes

1/**
2 * html:
3 * <div class="carousel">
4 *   <div class="carousel-contents">
5 *     
6 *     <div class="carousel-content">
7 *       <div class="carousel-container">
8 *         content1
9 *             :
10 *       </div>
11 *     </div>
12 *     
13 *     <div class="carousel-content">...</div>
14 *       <div class="carousel-container">
15 *             :
16 *       </div>
17 *     </div>
18 *             :
19 *     <div class="carousel-content">
20 *       <div class="carousel-container"></div>
21 *       <!-- optional more link after the last content -->
22 *       <label class="carousel-next carousel-more"><a href="link_url"></a></label>
23 *     </div>
24 *     
25 *   </div>
26 *   <div class="carousel-nav"></div>
27 * </div>
28 * 
29 * トップ要素には以下の付加クラスを追加可能
30 * carousel-arrownav-none:左右矢印のナビゲーションを消す
31 * carousel-pointnav-none: 下のポイントナビを消す
32 * carousel-pointnav-over: 下のポイントナビをコンテンツにかぶせる
33 * carousel-autoanim: 自動的にアニメーション
34 * 
35 * js:
36 *  - .carousel は自動的に追加
37 *  - $(elm).carousel()で明示追加
38 */
39
40// console.error('jquery-carousel');
41
42(function($) {
43	
44	// need jquery-util.js for toBase, generateUUID4, assureUniqId
45	
46	if ($('#carousel-loaded')[0]){
47		console.error('jquery-carousel/jquery-carousel.js is already loaded.');
48		return;
49	}
50	var css_loaded = false;
51	$('<div id="carousel-loaded"></div>')
52		.appendTo('body')
53		.each(function(){ css_loaded = window.getComputedStyle(this,':before').content });
54	
55	if (!css_loaded) {
56		console.log('jquery-carousel:load css');
57		$('<link></link>').attr({
58				rel:'stylesheet',
59				href:'/static/lib/jquery-carousel/jquery-carousel.css'
60			})
61			.appendTo('head');
62		/*
63		var css_href = $('script[src*="jquery-carousel.js"]').attr('src').replace('jqueyr-carousel.js', 'jquery-carousel.css');
64		if (!css_href) {
65			console.error('jquery-carousel.css is not found');
66		} else {
67			$('<link></link>').attr({
68					rel:'stylesheet',
69					href:css_href
70				})
71				.appendTo('head');
72		}
73		*/
74	}
75	
76	var $test = $('<div></div>').css({
77		'-webkit-transform':'scale(0)',
78		'transform':'scale(0)'
79	});
80	var prefix = ($test.css('transform') && '')
81	|| ($test.css('-webkit-transform') && '-webkit-')
82	|| ($test.css('-moz-transform') && '-moz-')
83	|| ($test.css('-ms-transform') && '-ms-') || '';
84	var TRANSFORM = prefix + 'transform';
85	var TRANSITION = prefix + 'transition';
86	var TRANSITIONEND = 'transitionend webkittransitonend moztransitionend';
87	
88	function Carousel($elm, opts){
89		this.$top = $elm;
90		
91		this._opts = $.extend({
92			'autoanim':$elm.hasClass('carousel-autoanim')
93		}, opts);
94		
95		this.$contents = $elm.children('.carousel-contents');
96		this.$nav = $elm.children('.carousel-nav').empty();
97		this.$radios = $();
98		this.$styles = $();
99		
100		if (!this.initStructure()) {
101			this.$top.attr('data-carousel-stat', 'invalidstructure');
102			this.is_invalid_structure = true;
103			return;
104		}
105		
106		this.$top.attr('data-carousel-stat', 'validstructure');
107		delete this.is_invalid_structure;
108		
109		var _this = this;
110		setTimeout(function(){
111			_this.$contents.removeClass('prevent-animation');
112		});
113		
114		// this.stopanim();
115		if (this._opts.autoanim) {
116			this.autoanim();
117		}
118		
119		this.$top.attr('data-carousel-stat', 'processed');
120		
121		this._animate_queue = []; // [delay, func], ...
122		
123	}
124	Carousel.prototype = {
125		autoanim:function(interval_ms, initial_delay_ms){
126			if (this.is_destroyed) { return; }
127			if (this._prevent_autoanim_restart) { return; }
128			// console.log('Carousel.autoanim()');
129			if (!this._opts.autoanim) { return; }
130			this._anim_interval_ms = (interval_ms === undefined ? 6000 : interval_ms);
131			initial_delay_ms = initial_delay_ms === undefined ? 8000 : initial_delay_ms;
132			
133			var _this = this;
134			function doNext(){
135				// console.log('Carousel.autoanim():doNext()');
136				
137				/*
138				var showing_radio_id = _this.$radios.filter(':checked').attr(id);
139				var $label = _this.$nav.children('label[for="'+showing_radio_id+'"]');
140				*/
141				 
142				_this.next().then(function(){
143					clearTimeout(_this._anim_t);
144					if (_this.is_destoryed) {
145						return;
146					}
147					_this._anim_t = setTimeout(doNext, _this._anim_interval_ms);
148				});
149			}
150			
151			clearTimeout(_this._anim_t); // 多重保険
152			_this._anim_t = setTimeout(doNext, initial_delay_ms);
153			
154			// console.error('autoanim', this);
155		},
156		stopanim:function(prevent_autoanim_restart){
157			var _this = this;
158			// console.log('Carousel.stopanim()');
159			if (_this.is_destroyed) { return; }
160			// console.error('stopanim', this);
161			clearTimeout(_this._anim_t);
162			_this._anim_t = null;
163			_this._prevent_autoanim_restart = prevent_autoanim_restart;
164		},
165		restartanim:function(restart_delay_ms){
166			var _this = this;
167			if (_this.is_destroyed) { return; }
168			if (_this._prevent_autoanim_restart) { return; }
169			_this.stopanim();
170			restart_delay_ms = (restart_delay_ms === undefined) ? 0 : restart_delay_ms;
171			_this.autoanim(_this._anim_inteval_ms, restart_delay_ms);
172		},
173		initStructure:function(){
174			// return false cannot make structure
175			
176			var _this = this;
177			
178			if (!_this.$contents[0]){
179				return false;
180			}
181			
182			_this.$top.children('input[name^=carousel-]').remove();
183			
184			/* make input,label,nav */
185			var contents_cnt = _this.$contents.children('.carousel-content').length;
186			_this._contents_cnt = contents_cnt;
187			
188			if (contents_cnt < 2) {
189				return false;
190			}
191			
192			// remove gap space between contents
193			_this.$contents.contents().filter(function(){
194				if (this.nodeType == 3) {
195					return /^\s*$/.test(this.textContent);
196				}
197				return false;
198			});
199			
200			var top_id = _this.$top.assureUniqId('carousel-').attr('id');
201			
202			var content_percent = 100/contents_cnt;
203			var styles = [
204				'#'+top_id+'.carousel .carousel-contents {',
205					'width:'+(100*contents_cnt)+'%;',
206				'}',
207				'#'+top_id+'.carousel .carousel-content {',
208					'width:'+content_percent+'%;',
209					'width:-webkit-calc(100%/'+contents_cnt+');',
210					'width:calc(100%/'+contents_cnt+');',
211				'}'
212			];
213			
214			
215			var syncSelectors = [];
216			_this.$contents.children('.carousel-content').each(function(i, elm){
217				var id = top_id + '-' + (i+1);
218				var id_prev = top_id + '-' + i;
219				var id_next = top_id + '-' + (i+2);
220				
221				var $content = $(this);
222				$content.attr({
223					'id':id,
224					'data-dx':i==0 ? '0' : '-' + (100/contents_cnt*i) + '%'
225				}).children('label:not(.carousel-more)').remove();
226				if (i > 0) {
227					$('<label class="carousel-prev"></label>').attr({
228						'for':id_prev
229					}).appendTo($content);
230				}
231				if (i < contents_cnt - 1) {
232					$('<label class="carousel-next"></label>').attr({
233						'for':id_next
234					}).appendTo($content);
235				}
236				$('<input type="radio">').attr({
237						id:id,
238						name:top_id + '-g',
239						'checked':i==0
240					})
241					.css({ opacity:0, position:'absolute', width:'1px', height:'1px', top:'-1px', left:'-1px', overflow:'hidden' })
242					.insertBefore(_this.$contents);
243				$('<label></label>').attr({
244					'for':id
245				}).appendTo(_this.$nav);
246				
247				// pointnav
248				syncSelectors.push('#'+top_id+'.carousel > input[name^=carousel-]:nth-of-type('+(i+1)+'):checked ~ .carousel-nav > label:nth-of-type('+(i+1)+')');
249				
250				// scroll-x
251				styles.push([
252					'#'+top_id+'.carousel > input[name^=carousel-]:nth-of-type('+(i+1)+'):checked ~ .carousel-contents {',
253						'-webkit-transform:translate3d('+(-1)*(i*content_percent)+'%,0,0);',
254						'transform:translateX('+(-1)*(i*content_percent)+'%);',
255					'}'
256				].join('\n'));
257				
258			});
259			
260			// pointnav
261			styles.push(syncSelectors.join(',\n') + ' { -moz-opacity:1; opacity:1 }');
262			
263			// scroll-x : loop
264			styles.push([
265				'#'+top_id+'.carousel > input[name^='+top_id+'-]:first-of-type:checked',
266					' ~ .carousel-contents.loop-forward > .carousel-content:first-child {',
267						'-webkit-transform:translate3d('+(contents_cnt*100)+'%,0,0);',
268						'transform:translateX('+(contents_cnt*100)+'%);',
269				'}',
270				'#'+top_id+'.carousel > input[name^='+top_id+'-]:first-of-type:checked',
271					' ~ .carousel-contents.loop-forward {',
272					'-webkit-transform:translate3d(-100%,0,0);',
273					'transform:translateX(-100%);',
274				'}',
275				'#'+top_id+'.carousel > input[name^='+top_id+'-]:last-of-type:checked',
276				' ~ .carousel-contents.loop-backward > .carousel-content:last-child {',
277					'-webkit-transform:translate3d('+(-1)*(contents_cnt*100)+'%,0,0);',
278					'transform:translateX('+(-1)*(contents_cnt*100)+'%);',
279				'}',
280				'#'+top_id+'.carousel > input[name^='+top_id+'-]:last-of-type:checked',
281					' ~ .carousel-contents.loop-backward {',
282					'-webkit-transform:translate3d('+content_percent+'%,0,0);',
283					'transform:translateX('+content_percent+'%);',
284				'}',
285			].join(''));
286			
287			$('#style-' + top_id).remove();
288			_this.$styles = $('<style>'+styles.join('\n')+'</style>')
289				.attr('id', 'style-' + top_id)
290				.appendTo(_this.$top);
291				// .appendTo($('head'));
292			
293			this.initEvents();
294			
295			return true;
296		},
297		
298		initEvents: function(){
299			var _this = this, top_id = _this.$top.attr('id');
300			
301			// events
302			var is_tap = false;
303			_this.$top.find('label[for^='+top_id+'-]')
304				.on('touchstart.carousel', function(ev){
305					is_tap = true;
306				})
307				.on('touchmove.carousel', function(ev){
308					is_tap = false;
309				})
310				.on('touchend.carousel', function(ev){
311					if (is_tap) {
312						ev.preventDefault();
313						var $input = $('#'+$(this).attr('for'));
314						$input.trigger('click', ['from_touchend']);
315						$input.one('click', function(ev, from){
316							if (from == 'from_touchend') {
317								$(this).one('click', function(ev){
318									// ev.immediateStopPropagation();
319									ev.preventDefault();
320									ev.stopPropagation();
321								});
322							} else {
323								// ev.immediateStopPropagation();
324								ev.preventDefault();
325								ev.stopPropagation();
326							}
327						});
328					} else {}
329				});
330			
331			var _t_restart = null;
332			_this.$top.find('label[for^='+top_id+'-]')
333				.on('touchstart.carousel_h click.carousel_h', function(ev){
334					_this.restartanim(10000);
335				});
336			
337			_this.$top
338				.on('mouseenter', function(ev){
339					_this.stopanim();
340				})
341				.on('mouseleave', function(ev){
342					_this.restartanim(1000);
343				});
344			
345			var s = null, sdx = 0;
346			var dx = 0, odx = 0, dt, odt;
347			
348			_this.$contents.find('*').on('dragstart.carousel', function(ev){
349				ev.preventDefault();
350			});
351			_this.$contents
352				.on('touchstart.carousel mousedown.carousel', function(ev){
353					// console.log(ev.type);
354					var t = ev.originalEvent.touches ? ev.originalEvent.touches[0] : ev;
355					s = {
356						sx : t.pageX,
357						sy : t.pageY
358					};
359					// matrix(a,b,c,d,dx,dy);
360					sdx = parseInt(_this.$contents.css(TRANSFORM).split(',')[4], 10);
361					_this.$contents.addClass('touching');
362					// console.log('start', s, sdx);
363				})
364				.on('touchmove.carousel mousemove.carousel', function(ev){
365					if (s) {
366						// console.log(ev.type);
367						var t = ev.originalEvent.touches ? ev.originalEvent.touches[0] : ev;
368						s.dx = t.pageX - s.sx;
369						s.dy = t.pageY - s.sy;
370						odx = dx;
371						odt = dt;
372						dx = sdx + s.dx;
373						// dt = new Date();
374						
375						_this.$contents.css('margin-left', s.dx + 'px');
376						
377						if (Math.abs(s.dx) > 100) {
378							_this.$contents.removeClass('touching');
379							_this.stopanim();
380							if (s.dx < 0) {
381								_this.next();
382							} else {
383								_this.prev();
384							}
385							$(this).css('margin-left', '');
386							s = null;
387						} 
388					}
389				})
390				.on('touchcancel.carousel mousecancel.carousel mouseleave.carousel', function(ev){
391					// console.log(ev.type);
392					s = null;
393					_this.$contents.removeClass('touching touchend').css(TRANSFORM, '');
394				})
395				.on('touchend.carousel mouseup.carousel', function(ev){
396					// console.log(ev.type);
397					if (!s) { return; }
398					_this.$contents.css('margin-left', '');
399					_this.$contents.removeClass('touching');
400					s = null;
401				});
402			
403			// ループ処理
404			this.$radios = this.$top.children('input[type=radio][name^='+top_id+'-]')
405				.on('change.carousel', function(ev){
406					var $this = $(this);
407					if (!($this.is(':checked'))) { return; }
408					
409					var last_is_first = !(_this._last_$radio.prev().is('input[name^='+top_id+'-]'));
410					var last_is_last  = !(_this._last_$radio.next().is('input[name^='+top_id+'-]'));
411					var this_is_first = !($this.prev().is('input[name^='+top_id+'-]'));
412					var this_is_last  = !($this.next().is('input[name^='+top_id+'-]'));
413					var loop_forward  = last_is_last && this_is_first;
414					var loop_backward = last_is_first && this_is_last;
415					
416					if (_this._contents_cnt == 2) {
417						loop_backward = false;
418						loop_forward = true;
419					}
420					
421					if (loop_forward || loop_backward) {
422						// console.log(loop_forward ? 'loop:forward' : 'loop:backward');
423						_this._loop(loop_backward);
424					}
425					_this._last_$radio = $this;
426				});
427			this._last_$radio = this.$radios.first().trigger('click');
428		},
429		
430		removeEvents: function(){
431			
432		},
433		
434		_loop:function(loop_backward) {
435			var _this = this;
436			clearTimeout(_this._loop_t);
437			if (this.is_destroyed) { return; }
438			// console.log('Carousel._loop:' + (loop_backward ? 'backward' : 'forward'));
439			var loop_forward = !loop_backward;
440			_this.$contents
441				.toggleClass('loop-forward',  loop_forward)
442				.toggleClass('loop-backward', loop_backward)
443				.one(TRANSITIONEND, function(ev){
444					// console.log('looped:end');
445					_this.$contents
446						.addClass('prevent-animation')
447						.removeClass('loop-forward loop-backward');
448					_this._loop_t = setTimeout(function(){
449						if (_this.is_destroyed) {
450							clearTimeout(_this._loop_t);
451							return;
452						}
453						_this.$contents.removeClass('prevent-animation');
454					}, 1);
455				});
456		},
457		next:function(){
458			// console.error('carousel:next');
459			var _d = $.Deferred();
460			if (this.is_destroyed) { return _d.reject(); }
461			var _this = this,
462				top_id = this.$top.attr('id');
463				$target = _this.$top
464					.children('input[name^='+top_id+'-]:checked')
465					.next('input[name^='+top_id+'-]');
466			if (!$target[0]) {
467				$target = _this.$top.children('input[name^='+top_id+'-]').first();
468			}
469			_this.$contents.one(TRANSITIONEND, function(){
470				_d.resolve();
471			});
472			$target.trigger('click.carousel');
473			return _d;
474		},
475		prev:function(){
476			var _d = $.Deferred();
477			if (this.is_destroyed) { return _d.reject(); }
478			var _this = this,
479				top_id = this.$top.attr('id'),
480				$target = _this.$top
481					.children('input[name^='+top_id+'-]:checked')
482					.prev('input[name^='+top_id+'-]');
483			if (!$target[0]){
484				$target = _this.$top.children('input[name^='+top_id+'-]').last();
485			}
486			_this.$contents.one(TRANSITIONEND, function(){
487				_d.resolve();
488			});
489			$target.trigger('click.carousel');
490			return _d;
491		},
492		destroy:function(){
493			this.is_destroyed = true;
494			this.stopanim();
495			this.$styles.remove();
496			this.$radios.remove();
497			this.$nav.empty();
498			this.$top
499				.find('> .carousel-content > label.carousel-next, > .carousel-content > label.carousel-prev').remove().end()
500				.find('*')
501					.off('dragstart touchstart touchmove touchend touchcancel mousedown mousemove mouseup mousecancel mouseleave change'.split(' ').join('.carousel ') + '.carousel').end()
502				.data('carousel', null)
503				.attr('data-carousel-stat', 'destroyed');
504			this.$top = null;
505		},
506		tostatic:function(){
507			this.stopanim();
508			this.$top
509				.find('*')
510					.off('dragstart touchstart touchmove touchend touchcancel mousedown mousemove mouseup mousecancel mouseleave change'.split(' ').join('.carousel ') + '.carousel').end()
511		}
512	};
513	
514	$.fn.extend({
515		carousel:function(opts){
516			var command, command_args;
517			if (typeof opts == 'string') {
518				command = opts;
519				command_args = Array.prototype.slice.apply(arguments).splice(1, arguments.length);
520			}
521			return $(this).each(function(){
522				var $target = $(this), carousel = $target.data('carousel');
523				if (command) {
524					if (carousel) {
525						var args = Array.prototype.slice(arguments);
526						if (carousel[command]) {
527							carousel[command].apply(carousel, command_args);
528						}
529					}
530				} else if (!carousel){
531					if ($target.children('.carousel-contents')[0]){
532						carousel = new Carousel($target, opts);
533						$target.data('carousel', carousel);
534					} else {
535						$target.attr('data-carousel-stat','invalid');
536						console.error('carousel:target does not have carousel structure (.carousel > .carousel-contents > .carousel-content', $target)
537					}
538				}
539			})
540		}
541	});
542	
543	$('.carousel:not([data-carousel-stat])').carousel();
544	setInterval(function(){
545		$('.carousel:not([data-carousel-stat])').carousel();
546	}, 250);
547	
548})(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.