jquery.smartWizard.js 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. /*
  2. * SmartWizard 3.3.1 plugin
  3. * jQuery Wizard control Plugin
  4. * by Dipu
  5. *
  6. * Refactored and extended:
  7. * https://github.com/mstratman/jQuery-Smart-Wizard
  8. *
  9. * Original URLs:
  10. * http://www.techlaboratory.net
  11. * http://tech-laboratory.blogspot.com
  12. */
  13. function SmartWizard(target, options) {
  14. this.target = target;
  15. this.options = options;
  16. this.curStepIdx = options.selected;
  17. this.steps = $(target).children("ul").children("li").children("a"); // Get all anchors
  18. this.contentWidth = 0;
  19. this.msgBox = $('<div class="msgBox"><div class="content"></div><a href="#" class="close">X</a></div>');
  20. this.elmStepContainer = $('<div></div>').addClass("stepContainer");
  21. this.loader = $('<div>Loading</div>').addClass("loader");
  22. this.buttons = {
  23. next : $('<a>'+options.labelNext+'</a>').attr("href","#").addClass("btn btn-success"),
  24. previous : $('<a>'+options.labelPrevious+'</a>').attr("href","#").addClass("btn btn-primary"),
  25. finish : $('<a>'+options.labelFinish+'</a>').attr("href","#").addClass("btn btn-default")
  26. };
  27. /*
  28. * Private functions
  29. */
  30. var _init = function($this) {
  31. var elmActionBar = $('<div></div>').addClass("actionBar");
  32. //elmActionBar.append($this.msgBox);
  33. $('.close',$this.msgBox).click(function() {
  34. $this.msgBox.fadeOut("normal");
  35. return false;
  36. });
  37. var allDivs = $this.target.children('div');
  38. // CHeck if ul with steps has been added by user, if not add them
  39. if($this.target.children('ul').length == 0 ){
  40. var ul = $("<ul/>");
  41. target.prepend(ul)
  42. // for each div create a li
  43. allDivs.each(function(i,e){
  44. var title = $(e).first().children(".StepTitle").text();
  45. var s = $(e).attr("id")
  46. // if referenced div has no id, add one.
  47. if (s==undefined){
  48. s = "step-"+(i+1)
  49. $(e).attr("id",s);
  50. }
  51. var span = $("<span/>").addClass("stepDesc").text(title);
  52. var li = $("<li></li>").append($("<a></a>").attr("href", "#" + s).append($("<label></label>").addClass("stepNumber").text(i + 1)).append(span));
  53. ul.append(li);
  54. });
  55. // (re)initialise the steps property
  56. $this.steps = $(target).children("ul").children("li").children("a"); // Get all anchors
  57. }
  58. $this.target.children('ul').addClass("anchor");
  59. allDivs.addClass("wizard_content");
  60. // highlight steps with errors
  61. if($this.options.errorSteps && $this.options.errorSteps.length>0){
  62. $.each($this.options.errorSteps, function(i, n){
  63. $this.setError({ stepnum: n, iserror:true });
  64. });
  65. }
  66. $this.elmStepContainer.append(allDivs);
  67. //elmActionBar.append($this.loader);
  68. $this.target.append($this.elmStepContainer);
  69. if ($this.options.includeFinishButton){
  70. elmActionBar.append($this.buttons.finish)
  71. }
  72. elmActionBar.append($this.buttons.next)
  73. .append($this.buttons.previous);
  74. $this.target.append(elmActionBar);
  75. this.contentWidth = $this.elmStepContainer.width();
  76. $($this.buttons.next).click(function() {
  77. $this.goForward();
  78. return false;
  79. });
  80. $($this.buttons.previous).click(function() {
  81. $this.goBackward();
  82. return false;
  83. });
  84. $($this.buttons.finish).click(function() {
  85. if(!$(this).hasClass('buttonDisabled')){
  86. if($.isFunction($this.options.onFinish)) {
  87. var context = { fromStep: $this.curStepIdx + 1 };
  88. if(!$this.options.onFinish.call(this,$($this.steps), context)){
  89. return false;
  90. }
  91. }else{
  92. var frm = $this.target.parents('form');
  93. if(frm && frm.length){
  94. frm.submit();
  95. }
  96. }
  97. }
  98. return false;
  99. });
  100. $($this.steps).bind("click", function(e){
  101. if($this.steps.index(this) == $this.curStepIdx){
  102. return false;
  103. }
  104. var nextStepIdx = $this.steps.index(this);
  105. var isDone = $this.steps.eq(nextStepIdx).attr("isDone") - 0;
  106. if(isDone == 1){
  107. _loadContent($this, nextStepIdx);
  108. }
  109. return false;
  110. });
  111. // Enable keyboard navigation
  112. if($this.options.keyNavigation){
  113. $(document).keyup(function(e){
  114. if(e.which==39){ // Right Arrow
  115. $this.goForward();
  116. }else if(e.which==37){ // Left Arrow
  117. $this.goBackward();
  118. }
  119. });
  120. }
  121. // Prepare the steps
  122. _prepareSteps($this);
  123. // Show the first slected step
  124. _loadContent($this, $this.curStepIdx);
  125. };
  126. var _prepareSteps = function($this) {
  127. if(! $this.options.enableAllSteps){
  128. $($this.steps, $this.target).removeClass("selected").removeClass("done").addClass("disabled");
  129. $($this.steps, $this.target).attr("isDone",0);
  130. }else{
  131. $($this.steps, $this.target).removeClass("selected").removeClass("disabled").addClass("done");
  132. $($this.steps, $this.target).attr("isDone",1);
  133. }
  134. $($this.steps, $this.target).each(function(i){
  135. $($(this).attr("href").replace(/^.+#/, '#'), $this.target).hide();
  136. $(this).attr("rel",i+1);
  137. });
  138. };
  139. var _step = function ($this, selStep) {
  140. return $(
  141. $(selStep, $this.target).attr("href").replace(/^.+#/, '#'),
  142. $this.target
  143. );
  144. };
  145. var _loadContent = function($this, stepIdx) {
  146. var selStep = $this.steps.eq(stepIdx);
  147. var ajaxurl = $this.options.contentURL;
  148. var ajaxurl_data = $this.options.contentURLData;
  149. var hasContent = selStep.data('hasContent');
  150. var stepNum = stepIdx+1;
  151. if (ajaxurl && ajaxurl.length>0) {
  152. if ($this.options.contentCache && hasContent) {
  153. _showStep($this, stepIdx);
  154. } else {
  155. var ajax_args = {
  156. url: ajaxurl,
  157. type: $this.options.ajaxType,
  158. data: ({step_number : stepNum}),
  159. dataType: "text",
  160. beforeSend: function(){
  161. $this.loader.show();
  162. },
  163. error: function(){
  164. $this.loader.hide();
  165. },
  166. success: function(res){
  167. $this.loader.hide();
  168. if(res && res.length>0){
  169. selStep.data('hasContent',true);
  170. _step($this, selStep).html(res);
  171. _showStep($this, stepIdx);
  172. }
  173. }
  174. };
  175. if (ajaxurl_data) {
  176. ajax_args = $.extend(ajax_args, ajaxurl_data(stepNum));
  177. }
  178. $.ajax(ajax_args);
  179. }
  180. }else{
  181. _showStep($this,stepIdx);
  182. }
  183. };
  184. var _showStep = function($this, stepIdx) {
  185. var selStep = $this.steps.eq(stepIdx);
  186. var curStep = $this.steps.eq($this.curStepIdx);
  187. if(stepIdx != $this.curStepIdx){
  188. if($.isFunction($this.options.onLeaveStep)) {
  189. var context = { fromStep: $this.curStepIdx+1, toStep: stepIdx+1 };
  190. if (! $this.options.onLeaveStep.call($this,$(curStep), context)){
  191. return false;
  192. }
  193. }
  194. }
  195. //$this.elmStepContainer.height(_step($this, selStep).outerHeight());
  196. var prevCurStepIdx = $this.curStepIdx;
  197. $this.curStepIdx = stepIdx;
  198. if ($this.options.transitionEffect == 'slide'){
  199. _step($this, curStep).slideUp("fast",function(e){
  200. _step($this, selStep).slideDown("fast");
  201. _setupStep($this,curStep,selStep);
  202. });
  203. } else if ($this.options.transitionEffect == 'fade'){
  204. _step($this, curStep).fadeOut("fast",function(e){
  205. _step($this, selStep).fadeIn("fast");
  206. _setupStep($this,curStep,selStep);
  207. });
  208. } else if ($this.options.transitionEffect == 'slideleft'){
  209. var nextElmLeft = 0;
  210. var nextElmLeft1 = null;
  211. var nextElmLeft = null;
  212. var curElementLeft = 0;
  213. if(stepIdx > prevCurStepIdx){
  214. nextElmLeft1 = $this.elmStepContainer.width() + 10;
  215. nextElmLeft2 = 0;
  216. curElementLeft = 0 - _step($this, curStep).outerWidth();
  217. } else {
  218. nextElmLeft1 = 0 - _step($this, selStep).outerWidth() + 20;
  219. nextElmLeft2 = 0;
  220. curElementLeft = 10 + _step($this, curStep).outerWidth();
  221. }
  222. if (stepIdx == prevCurStepIdx) {
  223. nextElmLeft1 = $($(selStep, $this.target).attr("href"), $this.target).outerWidth() + 20;
  224. nextElmLeft2 = 0;
  225. curElementLeft = 0 - $($(curStep, $this.target).attr("href"), $this.target).outerWidth();
  226. } else {
  227. $($(curStep, $this.target).attr("href"), $this.target).animate({left:curElementLeft},"fast",function(e){
  228. $($(curStep, $this.target).attr("href"), $this.target).hide();
  229. });
  230. }
  231. _step($this, selStep).css("left",nextElmLeft1).show().animate({left:nextElmLeft2},"fast",function(e){
  232. _setupStep($this,curStep,selStep);
  233. });
  234. } else {
  235. _step($this, curStep).hide();
  236. _step($this, selStep).show();
  237. _setupStep($this,curStep,selStep);
  238. }
  239. return true;
  240. };
  241. var _setupStep = function($this, curStep, selStep) {
  242. $(curStep, $this.target).removeClass("selected");
  243. $(curStep, $this.target).addClass("done");
  244. $(selStep, $this.target).removeClass("disabled");
  245. $(selStep, $this.target).removeClass("done");
  246. $(selStep, $this.target).addClass("selected");
  247. $(selStep, $this.target).attr("isDone",1);
  248. _adjustButton($this);
  249. if($.isFunction($this.options.onShowStep)) {
  250. var context = { fromStep: parseInt($(curStep).attr('rel')), toStep: parseInt($(selStep).attr('rel')) };
  251. if(! $this.options.onShowStep.call(this,$(selStep),context)){
  252. return false;
  253. }
  254. }
  255. if ($this.options.noForwardJumping) {
  256. // +2 == +1 (for index to step num) +1 (for next step)
  257. for (var i = $this.curStepIdx + 2; i <= $this.steps.length; i++) {
  258. $this.disableStep(i);
  259. }
  260. }
  261. };
  262. var _adjustButton = function($this) {
  263. if (! $this.options.cycleSteps){
  264. if (0 >= $this.curStepIdx) {
  265. $($this.buttons.previous).addClass("buttonDisabled");
  266. if ($this.options.hideButtonsOnDisabled) {
  267. $($this.buttons.previous).hide();
  268. }
  269. }else{
  270. $($this.buttons.previous).removeClass("buttonDisabled");
  271. if ($this.options.hideButtonsOnDisabled) {
  272. $($this.buttons.previous).show();
  273. }
  274. }
  275. if (($this.steps.length-1) <= $this.curStepIdx){
  276. $($this.buttons.next).addClass("buttonDisabled");
  277. if ($this.options.hideButtonsOnDisabled) {
  278. $($this.buttons.next).hide();
  279. }
  280. }else{
  281. $($this.buttons.next).removeClass("buttonDisabled");
  282. if ($this.options.hideButtonsOnDisabled) {
  283. $($this.buttons.next).show();
  284. }
  285. }
  286. }
  287. // Finish Button
  288. $this.enableFinish($this.options.enableFinishButton);
  289. };
  290. /*
  291. * Public methods
  292. */
  293. SmartWizard.prototype.goForward = function(){
  294. var nextStepIdx = this.curStepIdx + 1;
  295. if (this.steps.length <= nextStepIdx){
  296. if (! this.options.cycleSteps){
  297. return false;
  298. }
  299. nextStepIdx = 0;
  300. }
  301. _loadContent(this, nextStepIdx);
  302. };
  303. SmartWizard.prototype.goBackward = function(){
  304. var nextStepIdx = this.curStepIdx-1;
  305. if (0 > nextStepIdx){
  306. if (! this.options.cycleSteps){
  307. return false;
  308. }
  309. nextStepIdx = this.steps.length - 1;
  310. }
  311. _loadContent(this, nextStepIdx);
  312. };
  313. SmartWizard.prototype.goToStep = function(stepNum){
  314. var stepIdx = stepNum - 1;
  315. if (stepIdx >= 0 && stepIdx < this.steps.length) {
  316. _loadContent(this, stepIdx);
  317. }
  318. };
  319. SmartWizard.prototype.enableStep = function(stepNum) {
  320. var stepIdx = stepNum - 1;
  321. if (stepIdx == this.curStepIdx || stepIdx < 0 || stepIdx >= this.steps.length) {
  322. return false;
  323. }
  324. var step = this.steps.eq(stepIdx);
  325. $(step, this.target).attr("isDone",1);
  326. $(step, this.target).removeClass("disabled").removeClass("selected").addClass("done");
  327. }
  328. SmartWizard.prototype.disableStep = function(stepNum) {
  329. var stepIdx = stepNum - 1;
  330. if (stepIdx == this.curStepIdx || stepIdx < 0 || stepIdx >= this.steps.length) {
  331. return false;
  332. }
  333. var step = this.steps.eq(stepIdx);
  334. $(step, this.target).attr("isDone",0);
  335. $(step, this.target).removeClass("done").removeClass("selected").addClass("disabled");
  336. }
  337. SmartWizard.prototype.currentStep = function() {
  338. return this.curStepIdx + 1;
  339. }
  340. SmartWizard.prototype.showMessage = function (msg) {
  341. $('.content', this.msgBox).html(msg);
  342. this.msgBox.show();
  343. }
  344. SmartWizard.prototype.enableFinish = function (enable) {
  345. // Controll status of finish button dynamically
  346. // just call this with status you want
  347. this.options.enableFinishButton = enable;
  348. if (this.options.includeFinishButton){
  349. if (!this.steps.hasClass('disabled') || this.options.enableFinishButton){
  350. $(this.buttons.finish).removeClass("buttonDisabled");
  351. if (this.options.hideButtonsOnDisabled) {
  352. $(this.buttons.finish).show();
  353. }
  354. }else{
  355. $(this.buttons.finish).addClass("buttonDisabled");
  356. if (this.options.hideButtonsOnDisabled) {
  357. $(this.buttons.finish).hide();
  358. }
  359. }
  360. }
  361. return this.options.enableFinishButton;
  362. }
  363. SmartWizard.prototype.hideMessage = function () {
  364. this.msgBox.fadeOut("normal");
  365. }
  366. SmartWizard.prototype.showError = function(stepnum) {
  367. this.setError(stepnum, true);
  368. }
  369. SmartWizard.prototype.hideError = function(stepnum) {
  370. this.setError(stepnum, false);
  371. }
  372. SmartWizard.prototype.setError = function(stepnum,iserror) {
  373. if (typeof stepnum == "object") {
  374. iserror = stepnum.iserror;
  375. stepnum = stepnum.stepnum;
  376. }
  377. if (iserror){
  378. $(this.steps.eq(stepnum-1), this.target).addClass('error')
  379. }else{
  380. $(this.steps.eq(stepnum-1), this.target).removeClass("error");
  381. }
  382. }
  383. SmartWizard.prototype.fixHeight = function(){
  384. var height = 0;
  385. var selStep = this.steps.eq(this.curStepIdx);
  386. var stepContainer = _step(this, selStep);
  387. stepContainer.children().each(function() {
  388. if($(this).is(':visible')) {
  389. height += $(this).outerHeight(true);
  390. }
  391. });
  392. // These values (5 and 20) are experimentally chosen.
  393. stepContainer.height(height + 5);
  394. this.elmStepContainer.height(height + 20);
  395. }
  396. _init(this);
  397. };
  398. (function($){
  399. $.fn.smartWizard = function(method) {
  400. var args = arguments;
  401. var rv = undefined;
  402. var allObjs = this.each(function() {
  403. var wiz = $(this).data('smartWizard');
  404. if (typeof method == 'object' || ! method || ! wiz) {
  405. var options = $.extend({}, $.fn.smartWizard.defaults, method || {});
  406. if (! wiz) {
  407. wiz = new SmartWizard($(this), options);
  408. $(this).data('smartWizard', wiz);
  409. }
  410. } else {
  411. if (typeof SmartWizard.prototype[method] == "function") {
  412. rv = SmartWizard.prototype[method].apply(wiz, Array.prototype.slice.call(args, 1));
  413. return rv;
  414. } else {
  415. $.error('Method ' + method + ' does not exist on jQuery.smartWizard');
  416. }
  417. }
  418. });
  419. if (rv === undefined) {
  420. return allObjs;
  421. } else {
  422. return rv;
  423. }
  424. };
  425. // Default Properties and Events
  426. $.fn.smartWizard.defaults = {
  427. selected: 0, // Selected Step, 0 = first step
  428. keyNavigation: true, // Enable/Disable key navigation(left and right keys are used if enabled)
  429. enableAllSteps: false,
  430. transitionEffect: 'fade', // Effect on navigation, none/fade/slide/slideleft
  431. contentURL:null, // content url, Enables Ajax content loading
  432. contentCache:true, // cache step contents, if false content is fetched always from ajax url
  433. cycleSteps: false, // cycle step navigation
  434. enableFinishButton: false, // make finish button enabled always
  435. hideButtonsOnDisabled: false, // when the previous/next/finish buttons are disabled, hide them instead?
  436. errorSteps:[], // Array Steps with errors
  437. labelNext:'Next',
  438. labelPrevious:'Previous',
  439. labelFinish:'Finish',
  440. noForwardJumping: false,
  441. ajaxType: "POST",
  442. onLeaveStep: null, // triggers when leaving a step
  443. onShowStep: null, // triggers when showing a step
  444. onFinish: null, // triggers when Finish button is clicked
  445. includeFinishButton : true // Add the finish button
  446. };
  447. })(jQuery);