Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

jquery.elastislide.js 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. (function( window, $, undefined ) {
  2. // http://www.netcu.de/jquery-touchwipe-iphone-ipad-library
  3. $.fn.touchwipe = function(settings) {
  4. var config = {
  5. min_move_x: 20,
  6. min_move_y: 20,
  7. wipeLeft: function() { },
  8. wipeRight: function() { },
  9. wipeUp: function() { },
  10. wipeDown: function() { },
  11. preventDefaultEvents: true
  12. };
  13. if (settings) $.extend(config, settings);
  14. this.each(function() {
  15. var startX;
  16. var startY;
  17. var isMoving = false;
  18. function cancelTouch() {
  19. this.removeEventListener('touchmove', onTouchMove);
  20. startX = null;
  21. isMoving = false;
  22. }
  23. function onTouchMove(e) {
  24. if(config.preventDefaultEvents) {
  25. e.preventDefault();
  26. }
  27. if(isMoving) {
  28. var x = e.touches[0].pageX;
  29. var y = e.touches[0].pageY;
  30. var dx = startX - x;
  31. var dy = startY - y;
  32. if(Math.abs(dx) >= config.min_move_x) {
  33. cancelTouch();
  34. if(dx > 0) {
  35. config.wipeLeft();
  36. }
  37. else {
  38. config.wipeRight();
  39. }
  40. }
  41. else if(Math.abs(dy) >= config.min_move_y) {
  42. cancelTouch();
  43. if(dy > 0) {
  44. config.wipeDown();
  45. }
  46. else {
  47. config.wipeUp();
  48. }
  49. }
  50. }
  51. }
  52. function onTouchStart(e)
  53. {
  54. if (e.touches.length == 1) {
  55. startX = e.touches[0].pageX;
  56. startY = e.touches[0].pageY;
  57. isMoving = true;
  58. this.addEventListener('touchmove', onTouchMove, false);
  59. }
  60. }
  61. if ('ontouchstart' in document.documentElement) {
  62. this.addEventListener('touchstart', onTouchStart, false);
  63. }
  64. });
  65. return this;
  66. };
  67. $.elastislide = function( options, element ) {
  68. this.$el = $( element );
  69. this._init( options );
  70. };
  71. $.elastislide.defaults = {
  72. speed : 450, // animation speed
  73. easing : '', // animation easing effect
  74. imageW : 190, // the images width
  75. margin : 3, // image margin right
  76. border : 2, // image border
  77. minItems : 1, // the minimum number of items to show.
  78. // when we resize the window, this will make sure minItems are always shown
  79. // (unless of course minItems is higher than the total number of elements)
  80. current : 0, // index of the current item
  81. // when we resize the window, the carousel will make sure this item is visible
  82. onClick : function() { return false; } // click item callback
  83. };
  84. $.elastislide.prototype = {
  85. _init : function( options ) {
  86. this.options = $.extend( true, {}, $.elastislide.defaults, options );
  87. // <ul>
  88. this.$slider = this.$el.find('ul');
  89. // <li>
  90. this.$items = this.$slider.children('li');
  91. // total number of elements / images
  92. this.itemsCount = this.$items.length;
  93. // cache the <ul>'s parent, since we will eventually need to recalculate its width on window resize
  94. this.$esCarousel = this.$slider.parent();
  95. // validate options
  96. this._validateOptions();
  97. // set sizes and initialize some vars...
  98. this._configure();
  99. // add navigation buttons
  100. this._addControls();
  101. // initialize the events
  102. this._initEvents();
  103. // show the <ul>
  104. this.$slider.show();
  105. // slide to current's position
  106. this._slideToCurrent( false );
  107. },
  108. _validateOptions : function() {
  109. if( this.options.speed < 0 )
  110. this.options.speed = 450;
  111. if( this.options.margin < 0 )
  112. this.options.margin = 4;
  113. if( this.options.border < 0 )
  114. this.options.border = 1;
  115. if( this.options.minItems < 1 || this.options.minItems > this.itemsCount )
  116. this.options.minItems = 1;
  117. if( this.options.current > this.itemsCount - 1 )
  118. this.options.current = 0;
  119. },
  120. _configure : function() {
  121. // current item's index
  122. this.current = this.options.current;
  123. // the ul's parent's (div.es-carousel) width is the "visible" width
  124. this.visibleWidth = this.$esCarousel.width();
  125. // test to see if we need to initially resize the items
  126. if( this.visibleWidth < this.options.minItems * ( this.options.imageW + 2 * this.options.border ) + ( this.options.minItems - 1 ) * this.options.margin ) {
  127. this._setDim( ( this.visibleWidth - ( this.options.minItems - 1 ) * this.options.margin ) / this.options.minItems );
  128. this._setCurrentValues();
  129. // how many items fit with the current width
  130. this.fitCount = this.options.minItems;
  131. }
  132. else {
  133. this._setDim();
  134. this._setCurrentValues();
  135. }
  136. // set the <ul> width
  137. this.$slider.css({
  138. width : this.sliderW
  139. });
  140. },
  141. _setDim : function( elW ) {
  142. // <li> style
  143. this.$items.css({
  144. marginRight : this.options.margin,
  145. width : ( elW ) ? elW : this.options.imageW + 2 * this.options.border
  146. }).children('a').css({ // <a> style
  147. borderWidth : this.options.border
  148. });
  149. },
  150. _setCurrentValues : function() {
  151. // the total space occupied by one item
  152. this.itemW = this.$items.outerWidth(true);
  153. // total width of the slider / <ul>
  154. // this will eventually change on window resize
  155. this.sliderW = this.itemW * this.itemsCount;
  156. // the ul parent's (div.es-carousel) width is the "visible" width
  157. this.visibleWidth = this.$esCarousel.width();
  158. // how many items fit with the current width
  159. this.fitCount = Math.floor( this.visibleWidth / this.itemW );
  160. },
  161. _addControls : function() {
  162. this.$navNext = $('<span class="es-nav-next">Next</span>');
  163. this.$navPrev = $('<span class="es-nav-prev">Previous</span>');
  164. $('<div class="es-nav"/>')
  165. .append( this.$navPrev )
  166. .append( this.$navNext )
  167. .appendTo( this.$el );
  168. //this._toggleControls();
  169. },
  170. _toggleControls : function( dir, status ) {
  171. // show / hide navigation buttons
  172. if( dir && status ) {
  173. if( status === 1 )
  174. ( dir === 'right' ) ? this.$navNext.show() : this.$navPrev.show();
  175. else
  176. ( dir === 'right' ) ? this.$navNext.hide() : this.$navPrev.hide();
  177. }
  178. else if( this.current === this.itemsCount - 1 || this.fitCount >= this.itemsCount )
  179. this.$navNext.hide();
  180. },
  181. _initEvents : function() {
  182. var instance = this;
  183. // window resize
  184. $(window).bind('resize.elastislide', function( event ) {
  185. instance._reload();
  186. // slide to the current element
  187. clearTimeout( instance.resetTimeout );
  188. instance.resetTimeout = setTimeout(function() {
  189. instance._slideToCurrent();
  190. }, 200);
  191. });
  192. // navigation buttons events
  193. this.$navNext.bind('click.elastislide', function( event ) {
  194. instance._slide('right');
  195. });
  196. this.$navPrev.bind('click.elastislide', function( event ) {
  197. instance._slide('left');
  198. });
  199. // item click event
  200. this.$items.bind('click.elastislide', function( event ) {
  201. instance.options.onClick( $(this) );
  202. return false;
  203. });
  204. // touch events
  205. instance.$slider.touchwipe({
  206. wipeLeft : function() {
  207. instance._slide('right');
  208. },
  209. wipeRight : function() {
  210. instance._slide('left');
  211. }
  212. });
  213. },
  214. reload : function( callback ) {
  215. this._reload();
  216. if ( callback ) callback.call();
  217. },
  218. _reload : function() {
  219. var instance = this;
  220. // set values again
  221. instance._setCurrentValues();
  222. // need to resize items
  223. if( instance.visibleWidth < instance.options.minItems * ( instance.options.imageW + 2 * instance.options.border ) + ( instance.options.minItems - 1 ) * instance.options.margin ) {
  224. instance._setDim( ( instance.visibleWidth - ( instance.options.minItems - 1 ) * instance.options.margin ) / instance.options.minItems );
  225. instance._setCurrentValues();
  226. instance.fitCount = instance.options.minItems;
  227. }
  228. else{
  229. instance._setDim();
  230. instance._setCurrentValues();
  231. }
  232. instance.$slider.css({
  233. width : instance.sliderW + 10 // TODO: +10px seems to solve a firefox "bug" :S
  234. });
  235. },
  236. _slide : function( dir, val, anim, callback ) {
  237. // if animating return
  238. //if( this.$slider.is(':animated') )
  239. //return false;
  240. // current margin left
  241. var ml = parseFloat( this.$slider.css('margin-left') );
  242. // val is just passed when we want an exact value for the margin left (used in the _slideToCurrent function)
  243. if( val === undefined ) {
  244. // how much to slide?
  245. var amount = this.fitCount * this.itemW, val;
  246. if( amount < 0 ) return false;
  247. // make sure not to leave a space between the last item / first item and the end / beggining of the slider available width
  248. if( dir === 'right' && this.sliderW - ( Math.abs( ml ) + amount ) < this.visibleWidth ) {
  249. amount = this.sliderW - ( Math.abs( ml ) + this.visibleWidth ) - this.options.margin; // decrease the margin left
  250. // show / hide navigation buttons
  251. this._toggleControls( 'right', -1 );
  252. this._toggleControls( 'left', 1 );
  253. }
  254. else if( dir === 'left' && Math.abs( ml ) - amount < 0 ) {
  255. amount = Math.abs( ml );
  256. // show / hide navigation buttons
  257. this._toggleControls( 'left', -1 );
  258. this._toggleControls( 'right', 1 );
  259. }
  260. else {
  261. var fml; // future margin left
  262. ( dir === 'right' )
  263. ? fml = Math.abs( ml ) + this.options.margin + Math.abs( amount )
  264. : fml = Math.abs( ml ) - this.options.margin - Math.abs( amount );
  265. // show / hide navigation buttons
  266. if( fml > 0 )
  267. this._toggleControls( 'left', 1 );
  268. else
  269. this._toggleControls( 'left', -1 );
  270. if( fml < this.sliderW - this.visibleWidth )
  271. this._toggleControls( 'right', 1 );
  272. else
  273. this._toggleControls( 'right', -1 );
  274. }
  275. ( dir === 'right' ) ? val = '-=' + amount : val = '+=' + amount
  276. }
  277. else {
  278. var fml = Math.abs( val ); // future margin left
  279. if( Math.max( this.sliderW, this.visibleWidth ) - fml < this.visibleWidth ) {
  280. val = - ( Math.max( this.sliderW, this.visibleWidth ) - this.visibleWidth );
  281. if( val !== 0 )
  282. val += this.options.margin; // decrease the margin left if not on the first position
  283. // show / hide navigation buttons
  284. this._toggleControls( 'right', -1 );
  285. fml = Math.abs( val );
  286. }
  287. // show / hide navigation buttons
  288. if( fml > 0 )
  289. this._toggleControls( 'left', 1 );
  290. else
  291. this._toggleControls( 'left', -1 );
  292. if( Math.max( this.sliderW, this.visibleWidth ) - this.visibleWidth > fml + this.options.margin )
  293. this._toggleControls( 'right', 1 );
  294. else
  295. this._toggleControls( 'right', -1 );
  296. }
  297. $.fn.applyStyle = ( anim === undefined ) ? $.fn.animate : $.fn.css;
  298. var sliderCSS = { marginLeft : val };
  299. var instance = this;
  300. this.$slider.stop().applyStyle( sliderCSS, $.extend( true, [], { duration : this.options.speed, easing : this.options.easing, complete : function() {
  301. if( callback ) callback.call();
  302. } } ) );
  303. },
  304. _slideToCurrent : function( anim ) {
  305. // how much to slide?
  306. var amount = this.current * this.itemW;
  307. this._slide('', -amount, anim );
  308. },
  309. add : function( $newelems, callback ) {
  310. // adds new items to the carousel
  311. this.$items = this.$items.add( $newelems );
  312. this.itemsCount = this.$items.length;
  313. this._setDim();
  314. this._setCurrentValues();
  315. this.$slider.css({
  316. width : this.sliderW
  317. });
  318. this._slideToCurrent();
  319. if ( callback ) callback.call( $newelems );
  320. },
  321. setCurrent : function( idx, callback ) {
  322. this.current = idx;
  323. var ml = Math.abs( parseFloat( this.$slider.css('margin-left') ) ),
  324. posR = ml + this.visibleWidth,
  325. fml = Math.abs( this.current * this.itemW );
  326. if( fml + this.itemW > posR || fml < ml ) {
  327. this._slideToCurrent();
  328. }
  329. if ( callback ) callback.call();
  330. },
  331. destroy : function( callback ) {
  332. this._destroy( callback );
  333. },
  334. _destroy : function( callback ) {
  335. this.$el.unbind('.elastislide').removeData('elastislide');
  336. $(window).unbind('.elastislide');
  337. if ( callback ) callback.call();
  338. }
  339. };
  340. var logError = function( message ) {
  341. if ( this.console ) {
  342. console.error( message );
  343. }
  344. };
  345. $.fn.elastislide = function( options ) {
  346. if ( typeof options === 'string' ) {
  347. var args = Array.prototype.slice.call( arguments, 1 );
  348. this.each(function() {
  349. var instance = $.data( this, 'elastislide' );
  350. if ( !instance ) {
  351. logError( "cannot call methods on elastislide prior to initialization; " +
  352. "attempted to call method '" + options + "'" );
  353. return;
  354. }
  355. if ( !$.isFunction( instance[options] ) || options.charAt(0) === "_" ) {
  356. logError( "no such method '" + options + "' for elastislide instance" );
  357. return;
  358. }
  359. instance[ options ].apply( instance, args );
  360. });
  361. }
  362. else {
  363. this.each(function() {
  364. var instance = $.data( this, 'elastislide' );
  365. if ( !instance ) {
  366. $.data( this, 'elastislide', new $.elastislide( options, this ) );
  367. }
  368. });
  369. }
  370. return this;
  371. };
  372. })( window, jQuery );