silk.slider = xb.core.object.extend( { ctor: function( domNode, config ) { this.domNode = domNode; this.axis = "y"; this.classes = [ "silk-slider" ]; if ( typeof( config ) === "object" ) { this.config = config; if ( typeof( config.axis ) === "string" ) { this.axis = config.axis; } if ( config.classes instanceof Array ) { for ( var i = 0, il = config.classes.length; i < il; i++ ) { if ( this.classes.indexOf( config.classes[ i ] ) < 0 ) { this.classes.push( config.classes[ i ] ); } } } } if ( this.axis === "y" ) { this.classes.push( "vertical" ); } else { this.classes.push( "horizontal" ); } if ( ( this.classes instanceof Array ) && this.classes.length ) { this.domNode.className += " " + this.classes.join( " " ); } silk.slider.manager.add( this ); }, initialize: function() { this.move = this.__proto__.move( this ); this.position = this.__proto__.position( this ); }, each: function( f, state ) { var state = ( typeof( state ) === "object" ) ? state : this.state; var result = []; for ( var i = 0, il = state.nodes.length; i < il; i++ ) { var r = f.call( state.nodes[ i ] ); if ( typeof( r ) !== "undefined" ) { result.push( r ); } } return result; }, move: xb.core.object.extend( { ctor: function( slider ) { this.slider = slider; this.direction = 0; // -1 | 0 | +1 this.handler = null; }, start: function( domNode, delta ) { this.handler = this.__proto__.scroller( this.slider, domNode, delta ); this.handler.start( delta ); }, change: function( delta ) { if ( typeof( this.handler ) === "object" ) { this.handler.change( delta ); } }, end: function( delta ) { if ( typeof( this.handler ) === "object" ) { this.handler.end( delta ); } this.handler = null; }, scroller: xb.core.object.extend( { factory: function( slider, domNode, delta ) { if ( domNode !== null ) { var offset = delta[ slider.axis ]; var direction = ( offset > 0 ) ? -1 : 1; //var data = slider.move.scroller.prototype.getData( slider, domNode ); var scroll = slider.position.scroll(); //getScrollData( domNode ); if ( direction > 0 && scroll.offsetEnd > 0 || direction < 0 && scroll.offset > 0 ) { return new slider.move.__proto__.scroller( slider, domNode, scroll ); } } return new slider.move.__proto__.slider( slider, domNode ); }, ctor: function( slider, domNode, data ) { this.slider = slider; this.domNode = domNode; this.data = data; }, start: function( delta ) { this.change( delta ); }, change: function( delta ) { var offset = -delta[ this.slider.axis ]; this.slider.position.scroll( this.data.offset + offset ); }, end: function( delta ) { this.change( delta ); } } ), slider: xb.core.object.extend( { ctor: function( slider, domNode ) { this.slider = slider; this.domNode = domNode; }, start: function( delta ) { this.change( delta ); }, change: function( delta ) { var offset = delta[ this.slider.axis ]; this.slider.position.offset( offset ); }, end: function( delta ) { this.slider.position.commit(); } } ) } ), position: xb.core.object.extend( { ctor: function( slider ) { var self = this; this.slider = slider; this.nav = null; this.animating = null; this.modules = []; this._page = 0; this._offset = 0; this.init(); if ( this.slider.config.nav instanceof Array ) { for ( var i = 0, il = this.slider.config.nav.length; i < il; i++ ) { var module = this.slider.config.nav[ i ]; if ( typeof( module ) === "function" ) { this.modules.push( module( this ) ); } } } window.addEventListener( "resize", function( evt ) { self.render(); } ); }, init: function() { var axis = this.slider.axis; this.nodes = []; var offset = 0; var nodes = $( this.slider.domNode ).find( " > .silk-listItem" ).toArray(); for ( var i = 0, il = nodes.length; i < il; i++ ) { var rect = nodes[ i ].getBoundingClientRect(); var node = { domNode: nodes[ i ], rect: rect, start: offset, end: ( axis === "x" ) ? offset + rect.width : offset + rect.height, width: ( axis === "x" ) ? rect.width : rect.height, }; this.nodes.push( node ); if ( this.slider.axis === "x" ) { offset += rect.width; } else { offset += rect.height; } } }, getActivePage: function( page, offset ) { var page = page; if ( page < 0 ) page = 0; if ( page >= this.nodes.length ) page = this.nodes.length - 1; var current = this.nodes[ page ]; var o = current.end + offset; if ( offset < 0 ) { o = current.start + offset; } if ( o <= 0 ) { return 0; } var page = ( offset < 0 ) ? page : 0; for ( var i = 0, il = this.nodes.length; i < il; i++ ) { var node = this.nodes[ i ]; if ( o >= node.start && o <= node.end ) { var margin = node.end - o; if ( offset > 0 ) { margin = o - node.start; } var min = node.width * 0.2; if ( margin > min ) { return i; } return page; } page = i; } return page; }, render: function( animate ) { var self = this; if ( this.animating !== null ) { return; } if ( typeof( animate ) === "object" ) { this.animating = animate; } var firstDOMNode = this.slider.domNode.firstElementChild; var propName = "margin-left"; if ( this.slider.axis === "y" ) { propName = "margin-top"; } var node = this.nodes[ this._page ]; var offset = node.start - this._offset; this.tickleModules(); if ( this.animating === null ) { $( firstDOMNode ).css( propName, ( -offset ) + "px" ); } else { var properties = {}; properties[ propName ] = ( -offset ) + "px"; $( firstDOMNode ).animate( properties, { duration: animate.duration, easing: animate.easing, complete: function() { self.animating = null; } } ); } }, tickleModules: function() { for ( var i = 0, il = this.modules.length; i < il; i++ ) { this.modules[ i ].update(); } return this; }, page: function( index ) { if ( typeof( index ) === "number" ) { this._page = page; this.render(); } return this._page; }, offset: function( pixels ) { if ( typeof( pixels ) === "number" ) { this._offset = pixels; this.render(); } return this._offset; }, scroll: function( pixels ) { var domNode = this.nodes[ this._page ].domNode; if ( typeof( pixels ) === "number" ) { if ( this.slider.axis === "x" ) { domNode.scrollLeft = pixels; } else { domNode.scrollTop = pixels; } this.tickleModules(); } return this.getScrollData( domNode ); }, getScrollData: function( domNode ) { var size = 0; var content = $( domNode ).find( "> .rows > .silk-listItem" ); for ( var i = 0, il = content.length; i < il; i++ ) { var cRect = content[ i ].getBoundingClientRect(); if ( this.slider.axis === "x" ) { size += cRect.width; } else { size += cRect.height; } } size = Math.floor( size ); var rect = domNode.getBoundingClientRect(); var offset = domNode.scrollTop; var max_size = Math.floor( rect.height ); if ( this.slider.axis === "x" ) { offset = domNode.scrollLeft; max_size = Math.floor( rect.width ); } var offsetEnd = ( size - offset ) - max_size; if ( offsetEnd < 0 ) { offsetEnd = 0; } return ( { offset: offset, offsetEnd: offsetEnd, size: max_size, content: size } ); }, commit: function() { this.init(); var page = this.getActivePage( this._page, -this._offset ); console.warn( "new page", page ); var duration = 400; if ( this._page === page ) { duration = 400; } this._page = page; this._offset = 0; this.render( { duration: duration, easing: "swing" } ); } } ) } ); silk.slider.arrows = xb.core.object.extend( { ctor: function( sPosition ) { this.sPosition = sPosition; this.slider = sPosition.slider; this.domNode = this.slider.domNode; this.init(); this.update(); }, init: function() { var self = this; this.lastOffset = null; this.domNode.appendChild( this.getHTMLArrow( "prev" ) ); this.domNode.appendChild( this.getHTMLArrow( "next" ) ); this.domNode.addEventListener( "click", function( evt ) { self.onClick( evt ); } ); }, getHTMLArrow: function( className ) { var li = document.createElement( "div" ); li.className = "silk-object slider-arrow " + className; li.appendChild( document.createElement( "span" ) ); return li; }, update: function() { var scroll = this.sPosition.scroll(); for ( var i = 0, il = this.domNode.classList.length; i < il; i++ ) { var c = this.domNode.classList[ i ]; if ( /page-pos-[0-9]+/.test( c ) && c !== "page-pos-" + this.sPosition._page ) { $( this.domNode ).removeClass( c ); break; } } $( this.domNode ).addClass( "page-pos-" + this.sPosition._page ); if ( this.sPosition._page > 0 && scroll.offset <= 0 ) { $( this.domNode ).addClass( "page-prev" ); } else { $( this.domNode ).removeClass( "page-prev" ); } if ( scroll.offsetEnd <= 0 && this.sPosition.nodes.length > this.sPosition._page + 1 ) { $( this.domNode ).addClass( "page-next" ); } else { $( this.domNode ).removeClass( "page-next" ); } // console.error( this.sPosition.scroll() ); }, onClick: function( evt ) { var page = this.sPosition._page; var newPage = null; if ( $( evt.target ).parents( ".slider-arrow.next" ).length ) { if ( page + 1 < this.sPosition.nodes.length ) { newPage = page + 1; } } else if ( $( evt.target ).parents( ".slider-arrow.prev" ).length ) { if ( page > 0 ) { newPage = page - 1; } } if ( newPage !== null ) { this.sPosition.init(); this.sPosition._page = newPage; this.sPosition._offset = 0; this.sPosition.render( { duration: 400, easing: "swing" } ); } } } ); silk.slider.bullets = xb.core.object.extend( { ctor: function( sPosition ) { this.domNode = null; this.sPosition = sPosition; this.slider = sPosition.slider; this.init(); this.update(); }, init: function() { var self = this; this.lastOffset = null; var nodes = this.sPosition.nodes; var ul = document.createElement( "ul" ); for ( var i = 0, il = nodes.length; i < il; i++ ) { ul.appendChild( document.createElement( "li" ) ); } var object = document.createElement( "div" ); object.className = "silk-object slider-bullets"; object.appendChild( ul ); this.domNode = object; this.domNode.addEventListener( "click", function( evt ) { self.onClick( evt ); } ); this.slider.domNode.appendChild( object ); }, onClick: function( evt ) { var tag = ( "" + evt.target.tagName ).toLowerCase(); if ( tag === "li" ) { // evt.preventDefault(); var page = -1; $( this.domNode ) .find( " > ul > li " ) .each( function( i ) { if ( evt.target === this ) { page = i; } } ) ; if ( page > -1 ) { this.sPosition.init(); this.sPosition._page = 0 + page; this.sPosition._offset = 0; this.sPosition.render( { duration: 400, easing: "swing" } ); } } }, update: function() { var offset = this.sPosition._page; if ( offset === this.lastOffset ) { return; } this.lastOffset = offset; var items = $( this.domNode ).find( " > ul > li " ).toArray(); for ( var i = 0, il = items.length; i < il; i++ ) { if ( i === offset ) { $( items[ i ] ).addClass( "current" ); } else { $( items[ i ] ).removeClass( "current" ); } } } } ); silk.slider.manager = {}; silk.slider.manager = ( xb.core.object.extend( { ctor: function() { this.hasInited = false; this.move = this.__proto__.move( this ); this.sliders = []; this.handlers = []; }, add: function( slider ) { if ( document.body.getAttribute( "data-simply-edit" ) !== null ) { return null; } if ( this.sliders.length === 0 ) { this.initialize(); } var s = this.sliders.indexOf( slider ); if ( s < 0 ) { this.sliders.push( slider ); slider.initialize(); } return this; }, initialize: function() { if ( this.hasInited ) { return this; } this.hasInited = true; this.handlers.push( silk.slider.manager.touchHandler( this ) ); this.handlers.push( silk.slider.manager.mouseWheelHandler( this ) ); return this; }, getSliderFromDOM: function( domNode, axis ) { var sliders = []; var pages = []; var current = domNode; do { if ( current.parentElement !== null && current.parentElement.classList.contains( "silk-slider" ) ) { pages.push( current ); } else if ( current.classList.contains( "silk-slider" ) ) { sliders.push( current ); } current = current.parentElement; } while ( current !== null ); if ( !sliders.length ) { console.warn( "getSliderFromDOM(", axis, domNode, ") /No slider found here!" ); return null; } for ( var s = 0, sl = sliders.length; s < sl; s++ ) { var index = -1; for ( var i = 0, il = this.sliders.length; i < il; i++ ) { if ( this.sliders[ i ].domNode === sliders[ s ] ) { if ( this.sliders[ i ].axis === axis ) { return { slider: this.sliders[ i ], domNode: ( typeof( pages[ s ] ) === "object" ) ? pages[ s ] : null } } } } } console.warn( "getSliderFromDOM(", axis, domNode, sliders.length, ") /No suitable axis-aligned slider found!" ); return null; }, move: xb.core.object.extend( { ctor: function( manager ) { this.manager = manager; this.init(); }, init: function() { this.state = { slider: null, delta: { x: 0, y: 0 }, axis: "y" }; }, start: function( domNode, delta ) { if ( this.state.slider !== null ) { console.error( "slider::manager::move.start(", domNode, delta, ") /Already moving another slider!", this.state.slider ); } if ( Math.abs( delta.x ) > Math.abs( delta.y ) ) { this.state.axis = "x"; } var domInfo = this.manager.getSliderFromDOM( domNode, this.state.axis ); if ( domInfo === null ) { return; } this.state.slider = domInfo.slider; this.state.delta = { x: delta.x, y: delta.y }; this.state.slider.move.start( domInfo.domNode, this.state.delta ); }, change: function( delta ) { if ( this.state.slider !== null ) { this.state.delta = delta; this.state.slider.move.change( this.state.delta ); } }, end: function( delta ) { if ( this.state.slider !== null ) { this.state.delta = delta; this.state.slider.move.end( this.state.delta ); } this.init(); } } ), mouseWheelHandler: xb.core.object.extend( { ctor: function( manager ) { var self = this; this.manager = manager; this.timestamp = 0; this.timeout = 150; this.delta = { x: 0, y: 0 }; this.manager = manager; /* $( document.body ).on( "mousewheel", function( evt ) { self.onMouseWheel( evt ); evt.preventDefault(); } ); */ }, onMouseWheel: function( evt ) { if ( this.timestamp === 0 ) { return this.onStart( evt ); } return this.onMove( evt ); }, getDelta: function( evt ) { if ( typeof( evt ) === "undefined" ) { return this.delta; } var step = -80; step = evt.deltaFactor * evt.deltaX; if ( evt.deltaX > 0 ) { this.delta.x += step; return this.delta; }; if ( evt.deltaX < 0 ) { this.delta.x += step; return this.delta; }; step = evt.deltaFactor * evt.deltaY; if ( evt.deltaY > 0 ) { this.delta.y += step; return this.delta; }; if ( evt.deltaY < 0 ) { this.delta.y += step; return this.delta; }; this.delta = { x: this.delta.x + evt.deltaX, y: this.delta.y + evt.deltaY }; return this.delta; }, onMonitor: function() { var self = this; var time = Date.now(); if ( self.timestamp + self.timeout - 10 < time ) { return self.onEnd(); } window.setTimeout( function( evt ) { self.onMonitor( evt ); }, self.timeout ); }, onStart: function( evt ) { var self = this; this.timestamp = Date.now(); this.manager.move.start( evt.target, self.getDelta( evt ) ); window.setTimeout( function( evt ) { self.onMonitor( evt ); }, self.timeout ); }, onMove: function( evt ) { this.timestamp = Date.now(); return this.manager.move.change( this.getDelta( evt ) ); }, onEnd: function() { this.timestamp = 0; this.manager.move.end( this.getDelta() ); this.delta = { x: 0, y: 0 }; } } ), touchHandler: xb.core.object.extend( { ctor: function( manager ) { var self = this; this.node = null; this.manager = manager; this.mc = new Hammer( document.body ); this.mc.on( "panstart", function( evt ) { return self.manager.move.start( evt.target, self.getDelta( evt ) ); } ); this.mc.on( "panup pandown panleft panright", function( evt ) { return self.manager.move.change( self.getDelta( evt ) ); } ); this.mc.on( "pancancel panend", function( evt ) { return self.manager.move.end( self.getDelta( evt ) ); } ); this.mc.get( "pan" ).set( { direction: Hammer.DIRECTION_LEFT | Hammer.DIRECTION_RIGHT } ); }, getDelta: function( evt ) { return ( { x: evt.deltaX, y: evt.deltaY } ); } } ) } ) )();