jquery.smartWizard.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632
  1. /*!
  2. * SmartWizard v4.2.2
  3. * The awesome jQuery step wizard plugin with Bootstrap support
  4. * http://www.techlaboratory.net/smartwizard
  5. *
  6. * Created by Dipu Raj
  7. * http://dipuraj.me
  8. *
  9. * Licensed under the terms of the MIT License
  10. * https://github.com/techlab/SmartWizard/blob/master/LICENSE
  11. */
  12. ;(function ($, window, document, undefined) {
  13. "use strict";
  14. // Default options
  15. var defaults = {
  16. selected: 0, // Initial selected step, 0 = first step
  17. keyNavigation: true, // Enable/Disable keyboard navigation(left and right keys are used if enabled)
  18. autoAdjustHeight: true, // Automatically adjust content height
  19. cycleSteps: false, // Allows to cycle the navigation of steps
  20. backButtonSupport: true, // Enable the back button support
  21. useURLhash: true, // Enable selection of the step based on url hash
  22. showStepURLhash: true, // Show url hash based on step
  23. lang: { // Language variables for button
  24. next: 'Next',
  25. previous: 'Previous'
  26. },
  27. toolbarSettings: {
  28. toolbarPosition: 'bottom', // none, top, bottom, both
  29. toolbarButtonPosition: 'end', // start, end
  30. showNextButton: true, // show/hide a Next button
  31. showPreviousButton: true, // show/hide a Previous button
  32. toolbarExtraButtons: [] // Extra buttons to show on toolbar, array of jQuery input/buttons elements
  33. },
  34. anchorSettings: {
  35. anchorClickable: true, // Enable/Disable anchor navigation
  36. enableAllAnchors: false, // Activates all anchors clickable all times
  37. markDoneStep: true, // Add done css
  38. markAllPreviousStepsAsDone: true, // When a step selected by url hash, all previous steps are marked done
  39. removeDoneStepOnNavigateBack: false, // While navigate back done step after active step will be cleared
  40. enableAnchorOnDoneStep: true // Enable/Disable the done steps navigation
  41. },
  42. contentURL: null, // content url, Enables Ajax content loading. Can also set as data data-content-url on anchor
  43. contentCache: true, // cache step contents, if false content is fetched always from ajax url
  44. ajaxSettings: {}, // Ajax extra settings
  45. disabledSteps: [], // Array Steps disabled
  46. errorSteps: [], // Highlight step with errors
  47. hiddenSteps: [], // Hidden steps
  48. theme: 'default', // theme for the wizard, related css need to include for other than default theme
  49. transitionEffect: 'none', // Effect on navigation, none/slide/fade
  50. transitionSpeed: '400'
  51. };
  52. // The plugin constructor
  53. function SmartWizard(element, options) {
  54. // Merge user settings with default, recursively
  55. this.options = $.extend(true, {}, defaults, options);
  56. // Main container element
  57. this.main = $(element);
  58. // Navigation bar element
  59. this.nav = this.main.children('ul');
  60. // Step anchor elements
  61. this.steps = $("li > a", this.nav);
  62. // Content container
  63. this.container = this.main.children('div');
  64. // Content pages
  65. this.pages = this.container.children('div');
  66. // Active step index
  67. this.current_index = null;
  68. // Call initial method
  69. this.init();
  70. }
  71. $.extend(SmartWizard.prototype, {
  72. init: function () {
  73. // Set the elements
  74. this._setElements();
  75. // Add toolbar
  76. this._setToolbar();
  77. // Assign plugin events
  78. this._setEvents();
  79. var idx = this.options.selected;
  80. // Get selected step from the url
  81. if (this.options.useURLhash) {
  82. // Get step number from url hash if available
  83. var hash = window.location.hash;
  84. if (hash && hash.length > 0) {
  85. var elm = $("a[href*='" + hash + "']", this.nav);
  86. if (elm.length > 0) {
  87. var id = this.steps.index(elm);
  88. idx = id >= 0 ? id : idx;
  89. }
  90. }
  91. }
  92. if (idx > 0 && this.options.anchorSettings.markDoneStep && this.options.anchorSettings.markAllPreviousStepsAsDone) {
  93. // Mark previous steps of the active step as done
  94. this.steps.eq(idx).parent('li').prevAll().addClass("done");
  95. }
  96. // Show the initial step
  97. this._showStep(idx);
  98. },
  99. // PRIVATE FUNCTIONS
  100. _setElements: function () {
  101. // Set the main element
  102. this.main.addClass('sw-main sw-theme-' + this.options.theme);
  103. // Set anchor elements
  104. this.nav.addClass('step-anchor'); // nav-justified nav-pills
  105. // Make the anchor clickable
  106. if (this.options.anchorSettings.enableAllAnchors !== false && this.options.anchorSettings.anchorClickable !== false) {
  107. this.steps.parent('li').addClass('clickable');
  108. }
  109. // Set content container
  110. this.container.addClass('sw-container tab-content');
  111. // Set content pages
  112. this.pages.addClass('tab-pane step-content');
  113. // Disabled steps
  114. var mi = this;
  115. if (this.options.disabledSteps && this.options.disabledSteps.length > 0) {
  116. $.each(this.options.disabledSteps, function (i, n) {
  117. mi.steps.eq(n).parent('li').addClass('disabled');
  118. });
  119. }
  120. // Error steps
  121. if (this.options.errorSteps && this.options.errorSteps.length > 0) {
  122. $.each(this.options.errorSteps, function (i, n) {
  123. mi.steps.eq(n).parent('li').addClass('danger');
  124. });
  125. }
  126. // Hidden steps
  127. if (this.options.hiddenSteps && this.options.hiddenSteps.length > 0) {
  128. $.each(this.options.hiddenSteps, function (i, n) {
  129. mi.steps.eq(n).parent('li').addClass('hidden');
  130. });
  131. }
  132. return true;
  133. },
  134. _setToolbar: function () {
  135. // Skip right away if the toolbar is not enabled
  136. if (this.options.toolbarSettings.toolbarPosition === 'none') {
  137. return true;
  138. }
  139. console.log(this.options.toolbarSettings.toolbarPosition);
  140. // Create the toolbar buttons
  141. var btnNext = this.options.toolbarSettings.showNextButton !== false ? $('<button></button>').text(this.options.lang.next).addClass('btn btn-default sw-btn-next').attr('type', 'button') : null;
  142. var btnPrevious = this.options.toolbarSettings.showPreviousButton !== false ? $('<button></button>').text(this.options.lang.previous).addClass('btn btn-default sw-btn-prev').attr('type', 'button') : null;
  143. var btnGroup = $('<div></div>').addClass('btn-group mr-2 sw-btn-group').attr('role', 'group').append(btnPrevious, btnNext);
  144. var box1 = $('<div></div>').addClass('col-sm-2');
  145. var box2 = $('<div></div>').addClass('col-sm-10').append(btnGroup);
  146. // Add extra toolbar buttons
  147. var btnGroupExtra = null;
  148. if (this.options.toolbarSettings.toolbarExtraButtons && this.options.toolbarSettings.toolbarExtraButtons.length > 0) {
  149. btnGroupExtra = $('<span></span>').addClass('mr-2 sw-btn-group-extra').attr('role', 'group');
  150. $.each(this.options.toolbarSettings.toolbarExtraButtons, function (i, n) {
  151. btnGroupExtra.append(n.clone(true));
  152. });
  153. }
  154. var toolbarTop, toolbarBottom;
  155. // Append toolbar based on the position
  156. switch (this.options.toolbarSettings.toolbarPosition) {
  157. case 'top':
  158. toolbarTop = $('<div></div>').addClass('btn-toolbar sw-toolbar sw-toolbar-top justify-content-' + this.options.toolbarSettings.toolbarButtonPosition);
  159. toolbarTop.append(box1, box2);
  160. if (this.options.toolbarSettings.toolbarButtonPosition === 'left') {
  161. box2.append(btnGroupExtra);
  162. } else {
  163. box2.prepend(btnGroupExtra);
  164. }
  165. this.container.before(toolbarTop);
  166. break;
  167. case 'bottom':
  168. toolbarBottom = $('<div></div>').addClass('btn-toolbar sw-toolbar sw-toolbar-bottom justify-content-' + this.options.toolbarSettings.toolbarButtonPosition);
  169. toolbarBottom.append(box1, box2);
  170. if (this.options.toolbarSettings.toolbarButtonPosition === 'left') {
  171. box2.append(btnGroupExtra);
  172. } else {
  173. box2.prepend(btnGroupExtra);
  174. }
  175. this.container.after(toolbarBottom);
  176. break;
  177. case 'both':
  178. toolbarTop = $('<div></div>').addClass('btn-toolbar sw-toolbar sw-toolbar-top justify-content-' + this.options.toolbarSettings.toolbarButtonPosition);
  179. toolbarTop.append(box1, box2);
  180. if (this.options.toolbarSettings.toolbarButtonPosition === 'left') {
  181. box2.append(btnGroupExtra);
  182. } else {
  183. box2.prepend(btnGroupExtra);
  184. }
  185. this.container.before(toolbarTop);
  186. toolbarBottom = $('<div></div>').addClass('btn-toolbar sw-toolbar sw-toolbar-bottom justify-content-' + this.options.toolbarSettings.toolbarButtonPosition);
  187. toolbarBottom.append(box1, box2);
  188. if (this.options.toolbarSettings.toolbarButtonPosition === 'left') {
  189. box2.append(btnGroupExtra.clone(true));
  190. } else {
  191. box2.prepend(btnGroupExtra.clone(true));
  192. }
  193. this.container.after(toolbarBottom);
  194. break;
  195. default:
  196. toolbarBottom = $('<div></div>').addClass('btn-toolbar sw-toolbar sw-toolbar-bottom justify-content-' + this.options.toolbarSettings.toolbarButtonPosition);
  197. toolbarBottom.append(box1, box2);
  198. if (this.options.toolbarSettings.toolbarButtonPosition === 'left') {
  199. box2.append(btnGroupExtra);
  200. } else {
  201. box2.prepend(btnGroupExtra);
  202. }
  203. this.container.after(toolbarBottom);
  204. break;
  205. }
  206. return true;
  207. },
  208. _setEvents: function () {
  209. // Anchor click event
  210. var mi = this;
  211. $(this.steps).on("click", function (e) {
  212. e.preventDefault();
  213. if (mi.options.anchorSettings.anchorClickable === false) {
  214. return true;
  215. }
  216. var idx = mi.steps.index(this);
  217. if (mi.options.anchorSettings.enableAnchorOnDoneStep === false && mi.steps.eq(idx).parent('li').hasClass('done')) {
  218. return true;
  219. }
  220. if (idx !== mi.current_index) {
  221. if (mi.options.anchorSettings.enableAllAnchors !== false && mi.options.anchorSettings.anchorClickable !== false) {
  222. mi._showStep(idx);
  223. } else {
  224. if (mi.steps.eq(idx).parent('li').hasClass('done')) {
  225. mi._showStep(idx);
  226. }
  227. }
  228. }
  229. });
  230. // Keyboard navigation event
  231. if (this.options.keyNavigation) {
  232. $(document).keyup(function (e) {
  233. mi._keyNav(e);
  234. });
  235. }
  236. // Back/forward browser button event
  237. if (this.options.backButtonSupport) {
  238. $(window).on('hashchange', function (e) {
  239. if (!mi.options.useURLhash) {
  240. return true;
  241. }
  242. if (window.location.hash) {
  243. var elm = $("a[href*='" + window.location.hash + "']", mi.nav);
  244. if (elm && elm.length > 0) {
  245. e.preventDefault();
  246. mi._showStep(mi.steps.index(elm));
  247. }
  248. }
  249. });
  250. }
  251. return true;
  252. },
  253. _showNext: function () {
  254. var si = this.current_index + 1;
  255. // Find the next not disabled step
  256. for (var i = si; i < this.steps.length; i++) {
  257. if (!this.steps.eq(i).parent('li').hasClass('disabled') && !this.steps.eq(i).parent('li').hasClass('hidden')) {
  258. si = i;
  259. break;
  260. }
  261. }
  262. if (this.steps.length <= si) {
  263. if (!this.options.cycleSteps) {
  264. return false;
  265. }
  266. si = 0;
  267. }
  268. this._showStep(si);
  269. return true;
  270. },
  271. _showPrevious: function () {
  272. var si = this.current_index - 1;
  273. // Find the previous not disabled step
  274. for (var i = si; i >= 0; i--) {
  275. if (!this.steps.eq(i).parent('li').hasClass('disabled') && !this.steps.eq(i).parent('li').hasClass('hidden')) {
  276. si = i;
  277. break;
  278. }
  279. }
  280. if (0 > si) {
  281. if (!this.options.cycleSteps) {
  282. return false;
  283. }
  284. si = this.steps.length - 1;
  285. }
  286. this._showStep(si);
  287. return true;
  288. },
  289. _showStep: function (idx) {
  290. // If step not found, skip
  291. if (!this.steps.eq(idx)) {
  292. return false;
  293. }
  294. // If current step is requested again, skip
  295. if (idx == this.current_index) {
  296. return false;
  297. }
  298. // If it is a disabled step, skip
  299. if (this.steps.eq(idx).parent('li').hasClass('disabled') || this.steps.eq(idx).parent('li').hasClass('hidden')) {
  300. return false;
  301. }
  302. // Load step content
  303. this._loadStepContent(idx);
  304. return true;
  305. },
  306. _loadStepContent: function (idx) {
  307. var mi = this;
  308. // Get current step elements
  309. var curTab = this.steps.eq(this.current_index);
  310. // Get the direction of step navigation
  311. var stepDirection = '';
  312. var elm = this.steps.eq(idx);
  313. var contentURL = elm.data('content-url') && elm.data('content-url').length > 0 ? elm.data('content-url') : this.options.contentURL;
  314. if (this.current_index !== null && this.current_index !== idx) {
  315. stepDirection = this.current_index < idx ? "forward" : "backward";
  316. }
  317. // Trigger "leaveStep" event
  318. if (this.current_index !== null && this._triggerEvent("leaveStep", [curTab, this.current_index, stepDirection]) === false) {
  319. return false;
  320. }
  321. if (contentURL && contentURL.length > 0 && (!elm.data('has-content') || !this.options.contentCache)) {
  322. // Get ajax content and then show step
  323. var selPage = elm.length > 0 ? $(elm.attr("href"), this.main) : null;
  324. var ajaxSettings = $.extend(true, {}, {
  325. url: contentURL,
  326. type: "POST",
  327. data: { step_number: idx },
  328. dataType: "text",
  329. beforeSend: function () {
  330. elm.parent('li').addClass('loading');
  331. },
  332. error: function (jqXHR, status, message) {
  333. elm.parent('li').removeClass('loading');
  334. $.error(message);
  335. },
  336. success: function (res) {
  337. if (res && res.length > 0) {
  338. elm.data('has-content', true);
  339. selPage.html(res);
  340. }
  341. elm.parent('li').removeClass('loading');
  342. mi._transitPage(idx);
  343. }
  344. }, this.options.ajaxSettings);
  345. $.ajax(ajaxSettings);
  346. } else {
  347. // Show step
  348. this._transitPage(idx);
  349. }
  350. return true;
  351. },
  352. _transitPage: function (idx) {
  353. var mi = this;
  354. // Get current step elements
  355. var curTab = this.steps.eq(this.current_index);
  356. var curPage = curTab.length > 0 ? $(curTab.attr("href"), this.main) : null;
  357. // Get step to show elements
  358. var selTab = this.steps.eq(idx);
  359. var selPage = selTab.length > 0 ? $(selTab.attr("href"), this.main) : null;
  360. // Get the direction of step navigation
  361. var stepDirection = '';
  362. if (this.current_index !== null && this.current_index !== idx) {
  363. stepDirection = this.current_index < idx ? "forward" : "backward";
  364. }
  365. var stepPosition = 'middle';
  366. if (idx === 0) {
  367. stepPosition = 'first';
  368. } else if (idx === this.steps.length - 1) {
  369. stepPosition = 'final';
  370. }
  371. this.options.transitionEffect = this.options.transitionEffect.toLowerCase();
  372. this.pages.finish();
  373. if (this.options.transitionEffect === 'slide') {
  374. // normal slide
  375. if (curPage && curPage.length > 0) {
  376. curPage.slideUp('fast', this.options.transitionEasing, function () {
  377. selPage.slideDown(mi.options.transitionSpeed, mi.options.transitionEasing);
  378. });
  379. } else {
  380. selPage.slideDown(this.options.transitionSpeed, this.options.transitionEasing);
  381. }
  382. } else if (this.options.transitionEffect === 'fade') {
  383. // normal fade
  384. if (curPage && curPage.length > 0) {
  385. curPage.fadeOut('fast', this.options.transitionEasing, function () {
  386. selPage.fadeIn('fast', mi.options.transitionEasing, function () {
  387. $(this).show();
  388. });
  389. });
  390. } else {
  391. selPage.fadeIn(this.options.transitionSpeed, this.options.transitionEasing, function () {
  392. $(this).show();
  393. });
  394. }
  395. } else {
  396. if (curPage && curPage.length > 0) {
  397. curPage.hide();
  398. }
  399. selPage.show();
  400. }
  401. // Change the url hash to new step
  402. this._setURLHash(selTab.attr("href"));
  403. // Update controls
  404. this._setAnchor(idx);
  405. // Set the buttons based on the step
  406. this._setButtons(idx);
  407. // Fix height with content
  408. this._fixHeight(idx);
  409. // Update the current index
  410. this.current_index = idx;
  411. // Trigger "showStep" event
  412. this._triggerEvent("showStep", [selTab, this.current_index, stepDirection, stepPosition]);
  413. return true;
  414. },
  415. _setAnchor: function (idx) {
  416. // Current step anchor > Remove other classes and add done class
  417. this.steps.eq(this.current_index).parent('li').removeClass("active danger loading");
  418. if (this.options.anchorSettings.markDoneStep !== false && this.current_index !== null) {
  419. this._setDone(this.steps.eq(this.current_index).parent('li'));
  420. if (this.options.anchorSettings.removeDoneStepOnNavigateBack !== false) {
  421. this._removeDone(this.steps.eq(idx).parent('li').nextAll());
  422. }
  423. }
  424. // Next step anchor > Remove other classes and add active class
  425. this.steps.eq(idx).parent('li').removeClass("danger loading").addClass("active");
  426. this._removeDone(this.steps.eq(idx).parent('li'));
  427. return true;
  428. },
  429. _setDone: function ($li) {
  430. $li.addClass("done");
  431. $li.find('.la-step-icon').html('<i style="vertical-align:middle"><svg viewBox="64 64 896 896" focusable="false" class="" data-icon="check" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 0 0-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"></path></svg></i>');
  432. },
  433. //
  434. _removeDone: function ($lis) {
  435. $lis.removeClass("done");
  436. $lis.each(function (k, li) {
  437. var $icon = $(li).find('.la-step-icon');
  438. $icon.text($icon.data('index') + 1);
  439. });
  440. },
  441. _setButtons: function (idx) {
  442. // Previous/Next Button enable/disable based on step
  443. if (!this.options.cycleSteps) {
  444. if (0 >= idx) {
  445. $('.sw-btn-prev', this.main).addClass("disabled");
  446. } else {
  447. $('.sw-btn-prev', this.main).removeClass("disabled");
  448. }
  449. if (this.steps.length - 1 <= idx) {
  450. $('.sw-btn-next', this.main).addClass("disabled");
  451. } else {
  452. $('.sw-btn-next', this.main).removeClass("disabled");
  453. }
  454. }
  455. return true;
  456. },
  457. // HELPER FUNCTIONS
  458. _keyNav: function (e) {
  459. var mi = this;
  460. // Keyboard navigation
  461. switch (e.which) {
  462. case 37:
  463. // left
  464. mi._showPrevious();
  465. e.preventDefault();
  466. break;
  467. case 39:
  468. // right
  469. mi._showNext();
  470. e.preventDefault();
  471. break;
  472. default:
  473. return; // exit this handler for other keys
  474. }
  475. },
  476. _fixHeight: function (idx) {
  477. // Auto adjust height of the container
  478. if (this.options.autoAdjustHeight) {
  479. var selPage = this.steps.eq(idx).length > 0 ? $(this.steps.eq(idx).attr("href"), this.main) : null;
  480. this.container.finish().animate({ minHeight: selPage.outerHeight() }, this.options.transitionSpeed, function () {});
  481. }
  482. return true;
  483. },
  484. _triggerEvent: function (name, params) {
  485. // Trigger an event
  486. var e = $.Event(name);
  487. this.main.trigger(e, params);
  488. if (e.isDefaultPrevented()) {
  489. return false;
  490. }
  491. return e.result;
  492. },
  493. _setURLHash: function (hash) {
  494. if (this.options.showStepURLhash && window.location.hash !== hash) {
  495. window.location.hash = hash;
  496. }
  497. },
  498. // PUBLIC FUNCTIONS
  499. theme: function (v) {
  500. if (this.options.theme === v) {
  501. return false;
  502. }
  503. this.main.removeClass('sw-theme-' + this.options.theme);
  504. this.options.theme = v;
  505. this.main.addClass('sw-theme-' + this.options.theme);
  506. // Trigger "themeChanged" event
  507. this._triggerEvent("themeChanged", [this.options.theme]);
  508. },
  509. next: function () {
  510. this._showNext();
  511. },
  512. prev: function () {
  513. this._showPrevious();
  514. },
  515. reset: function () {
  516. // Trigger "beginReset" event
  517. if (this._triggerEvent("beginReset") === false) {
  518. return false;
  519. }
  520. // Reset all elements and classes
  521. this.container.stop(true);
  522. this.pages.stop(true);
  523. this.pages.hide();
  524. this.current_index = null;
  525. this._setURLHash(this.steps.eq(this.options.selected).attr("href"));
  526. $(".sw-toolbar", this.main).remove();
  527. this.steps.removeClass();
  528. this.steps.parents('li').removeClass();
  529. this.steps.data('has-content', false);
  530. this.init();
  531. // Trigger "endReset" event
  532. this._triggerEvent("endReset");
  533. },
  534. stepState: function (stepArray, state) {
  535. var mi = this;
  536. stepArray = $.isArray(stepArray) ? stepArray : [stepArray];
  537. var selSteps = $.grep(this.steps, function (n, i) {
  538. return $.inArray(i, stepArray) !== -1 && i !== mi.current_index;
  539. });
  540. if (selSteps && selSteps.length > 0) {
  541. switch (state) {
  542. case 'disable':
  543. $(selSteps).parents('li').addClass('disabled');
  544. break;
  545. case 'enable':
  546. $(selSteps).parents('li').removeClass('disabled');
  547. break;
  548. case 'hide':
  549. $(selSteps).parents('li').addClass('hidden');
  550. break;
  551. case 'show':
  552. $(selSteps).parents('li').removeClass('hidden');
  553. break;
  554. }
  555. }
  556. }
  557. });
  558. // Wrapper for the plugin
  559. $.fn.smartWizard = function (options) {
  560. var args = arguments;
  561. var instance;
  562. if (options === undefined || typeof options === 'object') {
  563. return this.each(function () {
  564. if (!$.data(this, "smartWizard")) {
  565. $.data(this, "smartWizard", new SmartWizard(this, options));
  566. }
  567. });
  568. } else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') {
  569. instance = $.data(this[0], 'smartWizard');
  570. if (options === 'destroy') {
  571. $.data(this, 'smartWizard', null);
  572. }
  573. if (instance instanceof SmartWizard && typeof instance[options] === 'function') {
  574. return instance[options].apply(instance, Array.prototype.slice.call(args, 1));
  575. } else {
  576. return this;
  577. }
  578. }
  579. };
  580. })(jQuery, window, document);