Slider, a Mootools (1.2.x) class.


/ Published in: JavaScript
Save to your folder(s)



Copy this code and paste it in your HTML
  1. /*
  2.  
  3. Copyright (c) 2009 Robert Jan Bast
  4.  
  5. Permission is hereby granted, free of charge, to any person
  6. obtaining a copy of this software and associated documentation
  7. files (the "Software"), to deal in the Software without
  8. restriction, including without limitation the rights to use,
  9. copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. copies of the Software, and to permit persons to whom the
  11. Software is furnished to do so, subject to the following
  12. conditions:
  13.  
  14. The above copyright notice and this permission notice shall be
  15. included in all copies or substantial portions of the Software.
  16.  
  17.  
  18. Slider.js
  19.  
  20. Simple class for sliding elements within a container.
  21.  
  22.  
  23. Sample HTML, CSS and JS
  24.  
  25. HTML
  26.  
  27. <div id="parent">
  28. <div class="a"></div>
  29. <div class="b"></div>
  30. <div class="c"></div>
  31. <div class="d"></div>
  32. </div>
  33.  
  34. CSS
  35.  
  36. div{width:100px;height:100px}
  37. #parent{overflow:hidden;}
  38. .a{background-color:blue}
  39. .b{background-color:red}
  40. .c{background-color:green}
  41. .d{background-color:yellow}
  42.  
  43. JS
  44.  
  45. var slider = new Slider('parent'); // default behavior
  46. or var slider = new Slider('parent', {mode:'vertical', endless:true}); // up & down, endlessly
  47. or var slider = new Slider('parent', {endless:true, onStart:function(){this.previous()}}); // reversed, endlessly
  48.  
  49. */
  50. var Slider = new Class({
  51.  
  52. Implements: [Options, Events],
  53.  
  54. options: {
  55. childrenSelector: 'div',
  56. endless: false,
  57. mode: 'horizontal', // horizontal | vertical
  58. autoSlide: true,
  59. autoDelay: 2000,
  60. fxOptions: {
  61. duration: 2000
  62. },
  63. onStart: function(){
  64. this.next();
  65. },
  66. onFirst: function(){
  67. this.next();
  68. },
  69. onLast: function(){
  70. this.previous();
  71. },
  72. onNext: function(){},
  73. onPrevious: function(){},
  74. onStop: function(){},
  75. onPause: function(){},
  76. onResume: function(){}
  77. },
  78.  
  79. container: null,
  80. children: [],
  81. stack: {
  82. next: [],
  83. previous: []
  84. },
  85. fx: null,
  86. timeoutId: null,
  87.  
  88. initialize: function(container, options){
  89. // Grab & extend our container element
  90. this.container = $(container);
  91. // Wtfux?
  92. if (!this.container){
  93. alert('You failed the internet, do not pass start and do not collect awesome fx effects');
  94. }
  95. // Apply options passed
  96. this.setOptions(options);
  97. // Grab all (current) children of our container, based on selector given
  98. this.children = this.container.getElements(this.options.childrenSelector).setStyle('float', 'left');
  99. // Stoopid, durrr
  100. if (this.children.length < 2){
  101. alert('Failure is imminent, it takes two to tango');
  102. }
  103. // Grab all children other than the currently visible one and loop through them
  104. this.children.slice(1,this.children.length).each(
  105. function(el){
  106. // Remove each element from the DOM and push them onto the 'next' stack
  107. this.stack.next.push(el.dispose());
  108. // I bind 'this', because otherwise this.stack is not accessible
  109. }.bind(this)
  110. );
  111. // If autoslide option is true
  112. if (this.options.autoSlide){
  113. // Start! durrr
  114. this.start();
  115. }
  116. },
  117.  
  118. start: function(){
  119. this.fireEvent('start');
  120. },
  121.  
  122. stop: function(){
  123. if (this.timeoutId){
  124. $clear(this.timeoutId);
  125. }
  126. this.fireEvent('stop');
  127. },
  128.  
  129. next: function(){
  130. // Check if we still have elements in the next stack OR if endless mode is set
  131. if (this.stack.next.length || this.options.endless){
  132. // If we have no more elements on the 'next' stack, we assume endless mode is true
  133. if (!this.stack.next.length){
  134. // Grab the last item from the 'previous' stack and push it onto the 'next' stack
  135. this.stack.next.push(this.stack.previous.pop());
  136. }
  137. // Get the current child, use selector given just to be sure we get the right one
  138. var currChild = this.container.getFirst(this.options.childrenSelector);
  139. // Get the next child we want
  140. var nextChild = this.stack.next.shift();
  141. // Generate the options object
  142. var opts = {'0': {}, '1': {}};
  143. // Figure out which mode we are running in
  144. switch (this.options.mode){
  145. // Vertical is ^ v
  146. case 'vertical' :
  147. // So we mess with top margin of current child
  148. opts['0']['margin-top'] = [0, -currChild.getStyle('height').toInt()],
  149. // And with bottom margin of the next child
  150. opts['1']['margin-bottom'] = [-currChild.getStyle('height').toInt(), 0];
  151. // Apply the bottom margin to the to be inserted child and inject it into the dom
  152. nextChild.setStyle('margin-bottom', -currChild.getStyle('height').toInt()).inject(currChild, 'after');
  153. break;
  154. // Horizontal is < >
  155. case 'horizontal' :
  156. default :
  157. // So we mess with left margin of current child
  158. opts['0']['margin-left'] = [0, -currChild.getStyle('width').toInt()],
  159. // And with right margin of the next child
  160. opts['1']['margin-right'] = [-currChild.getStyle('width').toInt(), 0];
  161. // Apply the right margin to the to be inserted child and inject it into the dom
  162. nextChild.setStyle('margin-right', -currChild.getStyle('width').toInt()).inject(currChild, 'after');
  163. break;
  164. }
  165. // Are we in autoslide mode?
  166. if (this.options.autoSlide){
  167. // Is there a timer active?
  168. if (this.timeoutId){
  169. // Clear it
  170. $clear(this.timeoutId);
  171. }
  172. // Generate the fxOptions object by merging default with some extra options
  173. var fxOptions = $merge(this.options.fxOptions, {
  174. // Add a onComplete event
  175. onComplete: function(e){
  176. // When we're done, set a timer again, cause this is like, autoslide mode, mkay
  177. this.timeoutId = this.next.delay(this.options.autoDelay, this);
  178. // Binding 'this' cause otherwise this.next and such are not accessible
  179. }.bind(this)
  180. });
  181. // No autoslide mode
  182. } else {
  183. // Default options are sufficient
  184. var fxOptions = this.options.fxOptions;
  185. }
  186. // Create the fx instance with the custom options, and add a chained function
  187. this.fx = new Fx.Elements($$(currChild, nextChild), fxOptions).start(opts).chain(
  188. function(){
  189. // When we are done, dispose of the current child and put it on the 'previous' stack
  190. this.stack.previous.unshift(currChild.dispose().setStyles({'margin-top':0,'margin-bottom':0,'margin-left':0,'margin-right':0}));
  191. // Again, binding 'this' for accessibility
  192. }.bind(this)
  193. );
  194. // We've moved to the next element, fire event!
  195. this.fireEvent('next', nextChild);
  196. // Ohnoez, no more elements and no endless mode :(
  197. } else {
  198. // Since there are no more elements, fire the last event
  199. this.fireEvent('last');
  200. }
  201. },
  202.  
  203. previous: function(){
  204. // Check if we still have elements in the previous stack OR if endless mode is set
  205. if (this.stack.previous.length || this.options.endless){
  206. // If we have no more elements on the 'previous' stack, we assume endless mode is true
  207. if (!this.stack.previous.length){
  208. // Grab the last item from the 'next' stack and push it onto the 'previous' stack
  209. this.stack.previous.push(this.stack.next.pop());
  210. }
  211. // Get the current child, use selector given just to be sure we get the right one
  212. var currChild = this.container.getFirst(this.options.childrenSelector);
  213. // Get the previous child we want
  214. var prevChild = this.stack.previous.shift();
  215. // Generate the options object
  216. var opts = {'0': {}, '1': {}};
  217. // Figure out which mode we are running in
  218. switch (this.options.mode){
  219. // Vertical is ^ v
  220. case 'vertical' :
  221. // So we mess with bottom margin of current child
  222. opts['0']['margin-bottom'] = [0, -currChild.getStyle('height').toInt()],
  223. // And with top margin of the previous child
  224. opts['1']['margin-top'] = [-currChild.getStyle('height').toInt(), 0];
  225. // Apply the top margin to the to be inserted child and inject it into the dom
  226. prevChild.setStyle('margin-top', -currChild.getStyle('height').toInt()).inject(currChild, 'before');
  227. break;
  228. // Horizontal is < >
  229. case 'horizontal' :
  230. default :
  231. // So we mess with right margin of current child
  232. opts['0']['margin-right'] = [0, -currChild.getStyle('width').toInt()],
  233. // And with left margin of the next child
  234. opts['1']['margin-left'] = [-currChild.getStyle('width').toInt(), 0];
  235. // Apply the left margin to the to be inserted child and inject it into the dom
  236. prevChild.setStyle('margin-left', -currChild.getStyle('width').toInt()).inject(currChild, 'before');
  237. break;
  238. }
  239. // Are we in autoslide mode?
  240. if (this.options.autoSlide){
  241. // Is there a timer active?
  242. if (this.timeoutId){
  243. // Clear it
  244. $clear(this.timeoutId);
  245. }
  246. // Generate the fxOptions object by merging default with some extra options
  247. var fxOptions = $merge(this.options.fxOptions, {
  248. // Add a onComplete event
  249. onComplete: function(e){
  250. // When we're done, set a timer again, cause this is like, autoslide mode, mkay
  251. this.timeoutId = this.previous.delay(this.options.autoDelay, this);
  252. // Binding 'this' cause otherwise this.previous and such are not accessible
  253. }.bind(this)
  254. });
  255. // No autoslide mode
  256. } else {
  257. // Default options are sufficient
  258. var fxOptions = this.options.fxOptions;
  259. }
  260. // Create the fx instance with the custom options, and add a chained function
  261. this.fx = new Fx.Elements($$(currChild, prevChild), fxOptions).start(opts).chain(
  262. function(){
  263. // When we are done, dispose of the current child and put it on the 'next' stack
  264. this.stack.next.unshift(currChild.dispose().setStyles({'margin-top':0,'margin-bottom':0,'margin-left':0,'margin-right':0}));
  265. // Again, binding 'this' for accessibility
  266. }.bind(this)
  267. );
  268. // We've moved to the previous element, fire event!
  269. this.fireEvent('previous', prevChild);
  270. // Ohnoez, no more elements and no endless mode :(
  271. } else {
  272. // Since there are no more elements, fire the first event
  273. this.fireEvent('first');
  274. }
  275. },
  276.  
  277. pause: function(){
  278. this.fx.pause();
  279. this.fireEvent('pause');
  280. },
  281.  
  282. resume: function(){
  283. this.fx.resume();
  284. this.fireEvent('resume');
  285. }
  286.  
  287. });

Report this snippet


Comments

RSS Icon Subscribe to comments

You need to login to post a comment.