PageSourceSearch

https://tactec.co.jp/js/curtain.js

js tactec.co.jp collected 2026-09-28 13:37:58 UTC 19,844 bytes, 534 lines download raw bytes

1/*
2* Curtain.js - Create an unique page transitioning system
3* ---
4* Version: 2
5* Copyright 2011, Victor Coulon (http://victorcoulon.fr)
6* Released under the MIT Licence
7*/
8
9(function ( $, window, document, undefined ) {
10
11    var pluginName = 'curtain',
12        defaults = {
13            scrollSpeed: 400,
14            bodyHeight: 0,
15            linksArray: [],
16            mobile: false,
17            scrollButtons: {},
18            controls: null,
19            curtainLinks: '.curtain-links',
20            enableKeys: true,
21            easing: 'swing',
22            disabled: false,
23            nextSlide: function() {},
24            prevSlide: function() {}
25        };
26
27    // The actual plugin constructor
28    function Plugin( element, options ) {
29        var self = this;
30
31        // Public attributes
32        this.element = element;
33        this.options = $.extend( {}, defaults, options) ;
34
35        this._defaults = defaults;
36        this._name = pluginName;
37        this._ignoreHashChange = false;
38
39        this.init();
40    }
41
42    Plugin.prototype = {
43        init: function () {
44            var self = this;
45
46            // Cache element
47            this.$element = $(this.element);
48            this.$li = $(this.element).find('>li');
49            this.$liLength = this.$li.length;
50            self.$windowHeight = $(window).height();
51            self.$elDatas = {};
52            self.$document = $(document);
53            self.$window = $(window);
54
55
56            self.webkit = (navigator.userAgent.indexOf('Chrome') > -1 || navigator.userAgent.indexOf("Safari") > -1);
57            $.msie = /msie/.test(navigator.userAgent.toLowerCase()); 
58            $.mozilla = /firefox/.test(navigator.userAgent.toLowerCase()); 
59            $.Android = (navigator.userAgent.match(/Android/i));
60            $.iPhone = ((navigator.userAgent.match(/iPhone/i)) || (navigator.userAgent.match(/iPod/i)));
61            $.iPad = ((navigator.userAgent.match(/iPad/i)));
62            $.iOs4 = (/OS [1-4]_[0-9_]+ like Mac OS X/i.test(navigator.userAgent));
63            
64            if($.iPhone || $.iPad || $.Android || self.options.disabled){
65                this.options.mobile = true;
66                this.$li.css({position:'relative'});
67                this.$element.find('.fixed').css({position:'absolute'});
68            }
69
70            if(this.options.mobile){
71               this.scrollEl =  this.$element;
72            } else if($.mozilla || $.msie) {
73                this.scrollEl = $('html');
74            } else {
75                this.scrollEl = $('body');
76            }
77
78            if(self.options.controls){
79                self.options.scrollButtons['up'] =  $(self.options.controls).find('[href="#up"]');
80                self.options.scrollButtons['down'] =  $(self.options.controls).find('[href="#down"]');
81
82                if(!$.iOs4 && ($.iPhone || $.iPad)){
83                    self.$element.css({
84                        position:'fixed',
85                        top:0,
86                        left:0,
87                        right:0,
88                        bottom:0,
89                        '-webkit-overflow-scrolling':'touch',
90                        overflow:'auto'
91                    });
92                    $(self.options.controls).css({position:'absolute'});
93                }
94            }
95
96            // When all image is loaded
97            var callbackImageLoaded = function(){
98                self.setDimensions();
99                self.$li.eq(0).addClass('current');
100
101                self.setCache();
102                
103                if(!self.options.mobile){
104                    if(self.$li.eq(1).length)
105                        self.$li.eq(1).nextAll().addClass('hidden');
106                }
107
108                self.setEvents();
109                self.setLinks();
110                self.isHashIsOnList(location.hash.substring(1));
111            };
112
113            if(self.$element.find('img').length)
114                self.imageLoaded(callbackImageLoaded);
115            else
116                callbackImageLoaded();
117
118        },
119        // Events
120        scrollToPosition: function (direction){
121            var position = null,
122                self = this;
123
124            if(self.scrollEl.is(':animated')){
125                return false;
126            }
127
128            if(direction === 'up' || direction == 'down'){
129                // Keyboard event
130                var $next = (direction === 'up') ? self.$current.prev() : self.$current.next();
131
132                // Step in the current panel ?
133                if(self.$step){
134
135                    if(!self.$current.find('.current-step').length){
136                        self.$step.eq(0).addClass('current-step');
137                    }
138                        
139                    var $nextStep = (direction === 'up') ? self.$current.find('.current-step').prev('.step') : self.$current.find('.current-step').next('.step');
140
141                    if($nextStep.length) {
142                        position = (self.options.mobile) ? $nextStep.position().top + self.$elDatas[self.$current.index()]['data-position'] : $nextStep.position().top + self.$elDatas[self.$current.index()]['data-position'];
143                    }
144                }
145
146                position = position || ((self.$elDatas[$next.index()] === undefined) ? null : self.$elDatas[$next.index()]['data-position']);
147
148                if(position !== null){
149                    self.scrollEl.animate({
150                        scrollTop: position
151                    }, self.options.scrollSpeed, self.options.easing);
152                }
153
154            } else if(direction === 'top'){
155                self.scrollEl.animate({
156                    scrollTop:0
157                }, self.options.scrollSpeed, self.options.easing);
158            } else if(direction === 'bottom'){
159                self.scrollEl.animate({
160                    scrollTop:self.options.bodyHeight
161                }, self.options.scrollSpeed, self.options.easing);
162            } else {
163                var index = $("#"+direction).index(),
164                    speed = Math.abs(self.currentIndex-index) * (this.options.scrollSpeed*4) / self.$liLength;
165
166                self.scrollEl.animate({
167                    scrollTop:self.$elDatas[index]['data-position'] || null
168                }, (speed <= self.options.scrollSpeed) ? self.options.scrollSpeed : speed, this.options.easing);
169            }
170            
171        },
172        scrollEvent: function() {
173            var self = this,
174                docTop = self.$document.scrollTop();
175
176            if(docTop < self.currentP && self.currentIndex > 0){
177                // Scroll to top
178                self._ignoreHashChange = true;
179
180                if(self.$current.prev().attr('id'))
181                    self.setHash(self.$current.prev().attr('id'));
182                
183                self.$current
184                    .removeClass('current')
185                    .css( (self.webkit) ? {'-webkit-transform': 'translateY(0px) translateZ(0)'} : {marginTop: 0} )
186                    .nextAll().addClass('hidden').end()
187                    .prev().addClass('current').removeClass('hidden');
188  
189                self.setCache();
190                self.options.prevSlide();
191
192            } else if(docTop < (self.currentP + self.currentHeight)){
193
194                // Animate the current pannel during the scroll
195                if(self.webkit)
196                    self.$current.css({'-webkit-transform': 'translateY('+(-(docTop-self.currentP))+'px) translateZ(0)' });
197                else
198                    self.$current.css({marginTop: -(docTop-self.currentP) });
199
200                // If there is a fixed element in the current panel
201                if(self.$fixedLength){
202                    var dataTop = parseInt(self.$fixed.attr('data-top'), 10);
203
204                    if(docTop + self.$windowHeight >= self.currentP + self.currentHeight){
205                        self.$fixed.css({
206                            position: 'fixed'
207                        });
208                    } else {
209                        self.$fixed.css({
210                            position: 'absolute',
211                            marginTop: Math.abs(docTop-self.currentP)
212                        });
213                    }
214                }
215                
216                // If there is a step element in the current panel
217                if(self.$stepLength){
218                    $.each(self.$step, function(i,el){
219                        if(($(el).position().top+self.currentP) <= docTop+5 && $(el).position().top + self.currentP + $(el).height() >= docTop+5){
220                            if(!$(el).hasClass('current-step')){
221                                self.$step.removeClass('current-step');
222                                $(el).addClass('current-step');
223                                return false;
224                            }
225                        }
226                    });
227                }
228
229
230                if(self.parallaxBg){
231                    self.$current.css({
232                        'background-position-y': docTop * self.parallaxBg
233                    });
234                }
235
236                if(self.$fade.length){
237                    self.$fade.css({
238                        'opacity': 1-(docTop/ self.$fade.attr('data-fade'))
239                    });
240                }
241
242                if(self.$slowScroll.length){
243                    self.$slowScroll.css({
244                        'margin-top' : (docTop / self.$slowScroll.attr('data-slow-scroll'))
245                    });
246                }
247
248            } else {
249                // Scroll bottom
250                self._ignoreHashChange = true;
251                if(self.$current.next().attr('id'))
252                    self.setHash(self.$current.next().attr('id'));
253
254                self.$current.removeClass('current')
255                    .addClass('hidden')
256                    .next('li').addClass('current').next('li').removeClass('hidden');
257
258                self.setCache();
259                self.options.nextSlide();
260            }
261
262        },
263        scrollMobileEvent: function() {
264            var self = this,
265                docTop = self.$element.scrollTop();
266
267            if(docTop+10 < self.currentP && self.currentIndex > 0){
268
269                // Scroll to top
270                self._ignoreHashChange = true;
271
272                if(self.$current.prev().attr('id'))
273                    self.setHash(self.$current.prev().attr('id'));
274
275                self.$current.removeClass('current').prev().addClass('current');
276                self.setCache();
277                self.options.prevSlide();
278            } else if(docTop+10 < (self.currentP + self.currentHeight)){
279
280                // If there is a step element in the current panel
281                if(self.$stepLength){
282                    $.each(self.$step, function(i,el){
283                        if(($(el).position().top+self.currentP) <= docTop && (($(el).position().top+self.currentP) + $(el).outerHeight()) >= docTop){
284                            if(!$(el).hasClass('current-step')){
285                                self.$step.removeClass('current-step');
286                                $(el).addClass('current-step');
287                            }
288                        }
289                    });
290                }
291
292            } else {
293
294                // Scroll bottom
295                self._ignoreHashChange = true;
296                if(self.$current.next().attr('id'))
297                    self.setHash(self.$current.next().attr('id'));
298
299                self.$current.removeClass('current').next().addClass('current');
300                self.setCache();
301                self.options.nextSlide();
302            }
303
304
305        },
306        // Setters
307        setDimensions: function(){
308            var self = this,
309                levelHeight = 0,
310                cover = false,
311                height = null;
312            
313            self.$windowHeight = self.$window.height();
314
315            this.$li.each(function(index) {
316                var $self = $(this);
317                cover = $self.hasClass('cover');
318
319                if(cover){
320                    $self.css({height: self.$windowHeight, zIndex: 999-index})
321                        .attr('data-height',self.$windowHeight)
322                        .attr('data-position',levelHeight);
323
324                    self.$elDatas[$self.index()] = {
325                        'data-height': parseInt(self.$windowHeight,10),
326                        'data-position': parseInt(levelHeight, 10)
327                    };
328
329                    levelHeight += self.$windowHeight;
330
331                } else{
332                    height = ($self.outerHeight() <= self.$windowHeight) ? self.$windowHeight : $self.outerHeight();
333                    $self.css({minHeight: height, zIndex: 999-index})
334                        .attr('data-height',height)
335                        .attr('data-position',levelHeight);
336                    
337                     self.$elDatas[$self.index()] = {
338                        'data-height': parseInt(height, 10),
339                        'data-position': parseInt(levelHeight, 10)
340                    };
341
342                    levelHeight += height;
343                }
344
345                if($self.find('.fixed').length){
346                    var top = $self.find('.fixed').css('top');
347                    $self.find('.fixed').attr('data-top', top);
348                }
349            });
350            if(!this.options.mobile)
351                this.setBodyHeight();
352        },
353        setEvents: function() {
354            var self = this;
355
356            $(window).on('resize', function(){
357                self.setDimensions();
358            });
359
360            if(self.options.mobile) {
361                self.$element.on('scroll', function(){
362                    self.scrollMobileEvent();
363                });
364            } else {
365                self.$window.on('scroll', function(){
366                    self.scrollEvent();
367                });
368            }
369            
370            if(self.options.enableKeys) {
371                self.$document.on('keydown', function(e){
372                    if(e.keyCode === 38 || e.keyCode === 37) {
373                        self.scrollToPosition('up');
374                        e.preventDefault();
375                        return false;
376                    }
377                    if(e.keyCode === 40 || e.keyCode === 39){
378                        self.scrollToPosition('down');
379                        e.preventDefault();
380                        return false;
381                    }
382                    // Home button
383                    if(e.keyCode === 36){
384                        self.scrollToPosition('top');
385                        e.preventDefault();
386                        return false;
387                    }
388                    // End button
389                    if(e.keyCode === 35){
390                        self.scrollToPosition('bottom');
391                        e.preventDefault();
392                        return false;
393                    }
394                });
395            }
396
397            if(self.options.scrollButtons){
398                if(self.options.scrollButtons.up){
399                    self.options.scrollButtons.up.on('click', function(e){
400                        e.preventDefault();
401                        self.scrollToPosition('up');
402                    });
403                }
404                if(self.options.scrollButtons.down){
405                    self.options.scrollButtons.down.on('click', function(e){
406                        e.preventDefault();
407                        self.scrollToPosition('down');
408                    });
409                }
410            }
411
412            if(self.options.curtainLinks){
413                $(self.options.curtainLinks).on('click', function(e){
414                    e.preventDefault();
415                    var href = $(this).attr('href');
416                    
417                    if(!self.isHashIsOnList(href.substring(1)) && position)
418                        return false;
419                    var position = self.$elDatas[$(href).index()]['data-position'] || null;
420
421                    if(position){
422                        self.scrollEl.animate({
423                            scrollTop:position
424                        }, self.options.scrollSpeed, self.options.easing);
425                    }
426                    return false;
427                });
428            }
429
430            self.$window.on("hashchange", function(event){
431                if(self._ignoreHashChange === false){
432                    self.isHashIsOnList(location.hash.substring(1));
433                }
434                self._ignoreHashChange = false;
435            });
436        },
437        setBodyHeight: function(){
438            var h = 0;
439
440            for (var key in this.$elDatas) {
441               var obj = this.$elDatas[key];
442               h += obj['data-height'];
443            }
444  
445            this.options.bodyHeight = h;
446            $('body').height(h);
447        },
448        setLinks: function(){
449            var self = this;
450            this.$li.each(function() {
451                var id = $(this).attr('id') || 0;
452                self.options.linksArray.push(id);
453            });
454        },
455        setHash: function(hash){
456            // "HARD FIX"
457            el = $('[href=#'+hash+']');
458            el.parent().siblings('li').removeClass('active');
459            el.parent().addClass('active');
460
461            if(history.pushState) {
462                history.pushState(null, null, '#'+hash);
463            }
464            else {
465                location.hash = hash;
466            }
467        },
468        setCache: function(){
469            var self = this;
470            self.$current = self.$element.find('.current');
471            self.$fixed = self.$current.find('.fixed');
472            self.$fixedLength = self.$fixed.length;
473            self.$step = self.$current.find('.step');
474            self.$stepLength = self.$step.length;
475            self.currentIndex = self.$current.index();
476            self.currentP = self.$elDatas[self.currentIndex]['data-position'];
477            self.currentHeight = self.$elDatas[self.currentIndex]['data-height'];
478
479            self.parallaxBg = self.$current.attr('data-parallax-background');
480            self.$fade = self.$current.find('[data-fade]');
481            self.$slowScroll = self.$current.find('[data-slow-scroll]');
482
483        },
484        // Utils
485        isHashIsOnList: function(hash){
486            var self = this;
487            $.each(self.options.linksArray, function(i,val){
488                if(val === hash){
489                    self.scrollToPosition(hash);
490                    return false;
491                }
492            });
493        },
494        readyElement: function(el,callback){
495          var interval = setInterval(function(){
496            if(el.length){
497              callback(el.length);
498              clearInterval(interval);
499            }
500          },60);
501        },
502        imageLoaded: function(callback){
503            var self = this,
504                elems = self.$element.find('img'),
505                len   = elems.length,
506                blank = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
507
508            elems.bind('load.imgloaded',function(){
509                if (--len <= 0 && this.src !== blank || $(this).not(':visible')){
510                    elems.unbind('load.imgloaded');
511                    callback.call(elems,this);
512                }
513            }).each(function(){
514                if (this.complete || this.complete === undefined){
515                    var src = this.src;
516                    this.src = blank;
517                    this.src = src;
518                }
519            });
520        }
521    };
522
523
524
525    $.fn[pluginName] = function ( options ) {
526        return this.each(function () {
527            if (!$.data(this, 'plugin_' + pluginName)) {
528                $.data(this, 'plugin_' + pluginName, new Plugin( this, options ));
529            }
530        });
531    };
532
533
534})( jQuery, window, document );

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.