Browse Source

分步表单

jqh 6 years ago
parent
commit
84e9142131

+ 458 - 0
resources/assets/SmartWizard/dist/css/step.css

@@ -0,0 +1,458 @@
+.sw-toolbar-bottom {
+    margin-top: 20px;
+    margin-left: 5px;
+}
+
+/* ---------------------------------------------------------------------------------------------------------------- */
+
+.la-step-box {
+    margin: 0 auto;
+}
+.la-step {
+    box-sizing: border-box;
+    padding: 0;
+    color: rgba(0, 0, 0, .65);
+    /*font-variant: tabular-nums;*/
+    line-height: 1.5;
+    list-style: none;
+    /*font-feature-settings: "tnum";*/
+    display: flex;
+    width: 100%;
+    font-size: 0;
+    margin: 0 auto 30px;
+}
+
+.la-step-item {
+    position: relative;
+    display: inline-block;
+    flex: 1 1;
+    overflow: hidden;
+    vertical-align: top
+}
+
+.la-step-item-container {
+    outline: 0;
+    border: 0!important;
+}
+
+.la-step-item:last-child {
+    flex: none
+}
+
+.la-step-item:last-child > .la-step-item-container > .la-step-content > .la-step-title:after, .la-step-item:last-child > .la-step-item-container > .la-step-line {
+    display: none
+}
+
+.la-step-content, .la-step-icons {
+    display: inline-block;
+    vertical-align: top
+}
+
+.la-step-icons {
+    width: 32px;
+    height: 32px;
+    margin-right: 8px;
+    font-size: 16px;
+    line-height: 32px;
+    text-align: center;
+    border: 1px solid rgba(0, 0, 0, .25);
+    border-radius: 32px;
+    transition: background-color .3s, border-color .3s
+}
+
+.la-step-icons > .la-step-icon {
+    position: relative;
+    top: -1px;
+    color: rgba(0,0,0,.25);
+    line-height: 1
+}
+
+.la-step-line {
+    position: absolute;
+    top: 12px;
+    left: 0;
+    width: 100%;
+    padding: 0 10px
+}
+
+.la-step-line:after {
+    display: inline-block;
+    width: 100%;
+    height: 1px;
+    background: #e8e8e8;
+    border-radius: 1px;
+    transition: background .3s;
+    content: ""
+}
+
+.la-step-title {
+    position: relative;
+    display: inline-block;
+    padding-right: 16px;
+    color: rgba(0, 0, 0, .65);
+    font-size: 16px;
+    line-height: 32px
+}
+
+.la-step-title:after {
+    position: absolute;
+    top: 16px;
+    left: 100%;
+    display: block;
+    width: 9999px;
+    height: 1px;
+    background: #e8e8e8;
+    content: ""
+}
+
+.la-step-desc {
+    color: rgba(0, 0, 0, .45);
+    font-size: 14px
+}
+
+.active .la-step-icons {
+    background-color: #fff;
+    border-color: var(--primary)
+}
+
+.active .la-step-icons > .la-step-icon {
+    color: var(--primary)
+}
+
+.active .la-step-icons > .la-step-icon .la-step-icon-dot {
+    background: var(--primary)
+}
+
+.active > .la-step-item-container > .la-step-content > .la-step-title {
+    color: rgba(0, 0, 0, .85)
+}
+
+.active > .la-step-item-container > .la-step-content > .la-step-title:after {
+    background-color: #e8e8e8
+}
+
+.active > .la-step-item-container > .la-step-content > .la-step-desc {
+    color: rgba(0, 0, 0, .65)
+}
+
+.active > .la-step-item-container > .la-step-line:after {
+    background-color: #e8e8e8
+}
+
+.active .la-step-icons {
+    background: var(--primary)
+}
+
+.active .la-step-icons > .la-step-icon {
+    color: #fff
+}
+
+.active .la-step-title {
+    font-weight: 500
+}
+
+.done .la-step-icons {
+    background-color: #fff;
+    border-color: var(--primary)
+}
+
+.done .la-step-icons > .la-step-icon {
+    color: var(--primary)
+}
+
+.done .la-step-icons > .la-step-icon .la-step-icon-dot {
+    background: var(--primary)
+}
+
+.done > .la-step-item-container > .la-step-content > .la-step-title {
+    color: rgba(0, 0, 0, .65)
+}
+
+.done > .la-step-item-container > .la-step-content > .la-step-title:after {
+    background-color: var(--primary)
+}
+
+.done > .la-step-item-container > .la-step-content > .la-step-desc {
+    color: rgba(0, 0, 0, .45)
+}
+
+.done > .la-step-item-container > .la-step-line:after {
+    background-color: var(--primary)
+}
+
+.danger .la-step-icons {
+    background-color: #fff;
+    border-color: var(--danger-dark)
+}
+
+.danger .la-step-icons > .la-step-icon {
+    color: var(--danger-dark)
+}
+
+.danger .la-step-icons > .la-step-icon .la-step-icon-dot {
+    background: var(--danger-dark)
+}
+
+.danger > .la-step-item-container > .la-step-content > .la-step-title {
+    color: var(--danger-dark)
+}
+
+.danger > .la-step-item-container > .la-step-content > .la-step-title:after {
+    background-color: #e8e8e8
+}
+
+.danger > .la-step-item-container > .la-step-content > .la-step-desc {
+    color: var(--danger-dark)
+}
+
+.danger > .la-step-item-container > .la-step-line:after {
+    background-color: #e8e8e8
+}
+
+.la-step-item.la-step-next-error .la-step-title:after {
+    background: var(--danger-dark)
+}
+
+.la-step .la-step-item:not(.active) > .la-step-item-container[role=button] {
+    cursor: pointer
+}
+
+.la-step .la-step-item:not(.active) > .la-step-item-container[role=button] .la-step-desc, .la-step .la-step-item:not(.active) > .la-step-item-container[role=button] .la-step-icons .la-step-icon, .la-step .la-step-item:not(.active) > .la-step-item-container[role=button] .la-step-title {
+    transition: color .3s
+}
+
+.la-step .la-step-item:not(.active) > .la-step-item-container[role=button]:hover .la-step-desc .la-step .la-step-item:not(.active) > .la-step-item-container[role=button]:hover .la-step-title {
+    color: var(--primary)
+}
+
+.la-step .la-step-item:not(.active) > .la-step-item-container[role=button]:hover .la-step-icons {
+    border-color: var(--primary)
+}
+
+.la-step .la-step-item:not(.active) > .la-step-item-container[role=button]:hover .la-step-icons .la-step-icon {
+    color: var(--primary)
+}
+
+.la-step-horizontal:not(.la-step-label-vertical) .la-step-item {
+    margin-right: 16px;
+    white-space: nowrap
+}
+
+.la-step-horizontal:not(.la-step-label-vertical) .la-step-item:last-child {
+    margin-right: 0
+}
+
+.la-step-horizontal:not(.la-step-label-vertical) .la-step-item:last-child .la-step-title {
+    padding-right: 0
+}
+
+.la-step-horizontal:not(.la-step-label-vertical) .la-step-line {
+    display: none
+}
+
+.la-step-horizontal:not(.la-step-label-vertical) .la-step-desc {
+    max-width: 140px;
+    white-space: normal
+}
+
+.la-step-sm.la-step-horizontal:not(.la-step-label-vertical) .la-step-item {
+    margin-right: 12px
+}
+
+.la-step-sm.la-step-horizontal:not(.la-step-label-vertical) .la-step-item:last-child {
+    margin-right: 0
+}
+
+.la-step-sm .la-step-icons {
+    width: 24px;
+    height: 24px;
+    font-size: 12px;
+    line-height: 24px;
+    text-align: center;
+    border-radius: 24px
+}
+
+.la-step-sm .la-step-title {
+    padding-right: 12px;
+    font-size: 14px;
+    line-height: 24px
+}
+
+.la-step-sm .la-step-title:after {
+    top: 12px
+}
+
+.la-step-sm .la-step-desc {
+    color: rgba(0, 0, 0, .45);
+    font-size: 14px
+}
+
+.la-step-sm .la-step-line {
+    top: 8px
+}
+
+@media (max-width: 540px) {
+    .la-step-horizontal.la-step-label-horizontal {
+        display: block
+    }
+
+    .la-step-box .nav-tabs > li {
+        float: none;
+    }
+
+    .la-step-box .nav-tabs>li>a {
+        padding: 0;
+    }
+
+    .la-step-horizontal.la-step-label-horizontal .la-step-item {
+        display: block;
+        overflow: visible
+    }
+
+    .la-step-horizontal.la-step-label-horizontal .la-step-icons {
+        float: left;
+        margin-right: 16px
+    }
+
+    .la-step-horizontal.la-step-label-horizontal .la-step-content {
+        display: block;
+        overflow: hidden
+    }
+
+    .la-step-horizontal.la-step-label-horizontal .la-step-title {
+        line-height: 32px
+    }
+
+    .la-step-horizontal.la-step-label-horizontal .la-step-desc {
+        padding-bottom: 12px
+    }
+
+    .la-step-horizontal.la-step-label-horizontal > .la-step-item > .la-step-item-container > .la-step-line {
+        position: absolute;
+        top: 0;
+        left: 16px;
+        width: 1px;
+        height: 100%;
+        padding: 38px 0 6px
+    }
+
+    .la-step-horizontal.la-step-label-horizontal > .la-step-item > .la-step-item-container > .la-step-line:after {
+        width: 1px;
+        height: 100%
+    }
+
+    .la-step-horizontal.la-step-label-horizontal > .la-step-item:not(:last-child) > .la-step-item-container > .la-step-line {
+        display: none;
+    }
+
+    .la-step-horizontal.la-step-label-horizontal > .la-step-item > .la-step-item-container > .la-step-content > .la-step-title:after {
+        display: none;
+    }
+
+    .la-step-horizontal.la-step-label-horizontal.la-step-sm .la-step-item-container .la-step-title {
+        line-height: 24px
+    }
+}
+
+.la-step-label-vertical .la-step-item {
+    overflow: visible
+}
+
+.la-step-label-vertical .la-step-line {
+    margin-left: 51px;
+    padding: 3.5px 24px;
+    left: 18px;
+    top: 23px;
+}
+
+.la-step-label-vertical .la-step-content {
+    display: block;
+    width: 104px;
+    margin-top: 8px;
+    text-align: center
+}
+
+.la-step-label-vertical .la-step-icons {
+    display: inline-block;
+    margin-left: 36px
+}
+
+.la-step-label-vertical .la-step-title {
+    padding-right: 0
+}
+
+.la-step-label-vertical .la-step-title:after {
+    display: none
+}
+
+.la-step-label-vertical.la-step-sm:not(.la-step-dot) .la-step-icons {
+    margin-left: 40px
+}
+
+.la-step-dot .la-step-title, .la-step-dot.la-step-sm .la-step-title {
+    line-height: 1.5
+}
+
+.la-step-dot .la-step-line, .la-step-dot.la-step-sm .la-step-line {
+    top: 2px;
+    width: 100%;
+    margin: 0 0 0 70px;
+    padding: 0
+}
+
+.la-step-dot .la-step-line:after, .la-step-dot.la-step-sm .la-step-line:after {
+    width: calc(100% - 20px);
+    height: 3px;
+    margin-left: 12px
+}
+
+.la-step-dot .la-step-item:first-child .la-step-icon-dot, .la-step-dot.la-step-sm .la-step-item:first-child .la-step-icon-dot {
+    left: 2px
+}
+
+.la-step-dot .la-step-icons, .la-step-dot.la-step-sm .la-step-icons {
+    width: 8px;
+    height: 8px;
+    margin-left: 67px;
+    padding-right: 0;
+    line-height: 8px;
+    background: 0 0;
+    border: 0
+}
+
+.la-step-dot .la-step-icons .la-step-icon-dot, .la-step-dot.la-step-sm .la-step-icons .la-step-icon-dot {
+    position: relative;
+    float: left;
+    width: 100%;
+    height: 100%;
+    border-radius: 100px;
+    transition: all .3s
+}
+
+.la-step-dot .la-step-icons .la-step-icon-dot:after, .la-step-dot.la-step-sm .la-step-icons .la-step-icon-dot:after {
+    position: absolute;
+    top: -12px;
+    left: -26px;
+    width: 60px;
+    height: 32px;
+    background: rgba(0, 0, 0, .001);
+    content: ""
+}
+
+.la-step-dot .la-step-content, .la-step-dot.la-step-sm .la-step-content {
+    width: 140px
+}
+
+.la-step-dot .active .la-step-icons, .la-step-dot.la-step-sm .active .la-step-icons {
+    width: 10px;
+    height: 10px;
+    line-height: 10px
+}
+
+.la-step-dot .active .la-step-icons .la-step-icon-dot, .la-step-dot.la-step-sm .active .la-step-icons .la-step-icon-dot {
+    top: -1px
+}
+
+.la-step-item a {
+    font-weight: normal!important;
+}

File diff suppressed because it is too large
+ 0 - 0
resources/assets/SmartWizard/dist/css/step.min.css


+ 632 - 0
resources/assets/SmartWizard/dist/js/jquery.smartWizard.js

@@ -0,0 +1,632 @@
+/*!
+ * SmartWizard v4.2.2
+ * The awesome jQuery step wizard plugin with Bootstrap support
+ * http://www.techlaboratory.net/smartwizard
+ *
+ * Created by Dipu Raj
+ * http://dipuraj.me
+ *
+ * Licensed under the terms of the MIT License
+ * https://github.com/techlab/SmartWizard/blob/master/LICENSE
+ */
+
+;(function ($, window, document, undefined) {
+    "use strict";
+    // Default options
+
+    var defaults = {
+        selected: 0, // Initial selected step, 0 = first step
+        keyNavigation: true, // Enable/Disable keyboard navigation(left and right keys are used if enabled)
+        autoAdjustHeight: true, // Automatically adjust content height
+        cycleSteps: false, // Allows to cycle the navigation of steps
+        backButtonSupport: true, // Enable the back button support
+        useURLhash: true, // Enable selection of the step based on url hash
+        showStepURLhash: true, // Show url hash based on step
+        lang: { // Language variables for button
+            next: 'Next',
+            previous: 'Previous'
+        },
+        toolbarSettings: {
+            toolbarPosition: 'bottom', // none, top, bottom, both
+            toolbarButtonPosition: 'end', // start, end
+            showNextButton: true, // show/hide a Next button
+            showPreviousButton: true, // show/hide a Previous button
+            toolbarExtraButtons: [] // Extra buttons to show on toolbar, array of jQuery input/buttons elements
+        },
+        anchorSettings: {
+            anchorClickable: true, // Enable/Disable anchor navigation
+            enableAllAnchors: false, // Activates all anchors clickable all times
+            markDoneStep: true, // Add done css
+            markAllPreviousStepsAsDone: true, // When a step selected by url hash, all previous steps are marked done
+            removeDoneStepOnNavigateBack: false, // While navigate back done step after active step will be cleared
+            enableAnchorOnDoneStep: true // Enable/Disable the done steps navigation
+        },
+        contentURL: null, // content url, Enables Ajax content loading. Can also set as data data-content-url on anchor
+        contentCache: true, // cache step contents, if false content is fetched always from ajax url
+        ajaxSettings: {}, // Ajax extra settings
+        disabledSteps: [], // Array Steps disabled
+        errorSteps: [], // Highlight step with errors
+        hiddenSteps: [], // Hidden steps
+        theme: 'default', // theme for the wizard, related css need to include for other than default theme
+        transitionEffect: 'none', // Effect on navigation, none/slide/fade
+        transitionSpeed: '400'
+    };
+
+    // The plugin constructor
+    function SmartWizard(element, options) {
+        // Merge user settings with default, recursively
+        this.options = $.extend(true, {}, defaults, options);
+        // Main container element
+        this.main = $(element);
+        // Navigation bar element
+        this.nav = this.main.children('ul');
+        // Step anchor elements
+        this.steps = $("li > a", this.nav);
+        // Content container
+        this.container = this.main.children('div');
+        // Content pages
+        this.pages = this.container.children('div');
+        // Active step index
+        this.current_index = null;
+        // Call initial method
+        this.init();
+    }
+
+    $.extend(SmartWizard.prototype, {
+
+        init: function () {
+            // Set the elements
+            this._setElements();
+            // Add toolbar
+            this._setToolbar();
+            // Assign plugin events
+            this._setEvents();
+
+            var idx = this.options.selected;
+            // Get selected step from the url
+            if (this.options.useURLhash) {
+                // Get step number from url hash if available
+                var hash = window.location.hash;
+                if (hash && hash.length > 0) {
+                    var elm = $("a[href*='" + hash + "']", this.nav);
+                    if (elm.length > 0) {
+                        var id = this.steps.index(elm);
+                        idx = id >= 0 ? id : idx;
+                    }
+                }
+            }
+
+            if (idx > 0 && this.options.anchorSettings.markDoneStep && this.options.anchorSettings.markAllPreviousStepsAsDone) {
+                // Mark previous steps of the active step as done
+                this.steps.eq(idx).parent('li').prevAll().addClass("done");
+            }
+
+            // Show the initial step
+            this._showStep(idx);
+        },
+
+        // PRIVATE FUNCTIONS
+
+        _setElements: function () {
+            // Set the main element
+            this.main.addClass('sw-main sw-theme-' + this.options.theme);
+            // Set anchor elements
+            this.nav.addClass('step-anchor'); // nav-justified  nav-pills
+
+            // Make the anchor clickable
+            if (this.options.anchorSettings.enableAllAnchors !== false && this.options.anchorSettings.anchorClickable !== false) {
+                this.steps.parent('li').addClass('clickable');
+            }
+            // Set content container
+            this.container.addClass('sw-container tab-content');
+            // Set content pages
+            this.pages.addClass('tab-pane step-content');
+
+            // Disabled steps
+            var mi = this;
+            if (this.options.disabledSteps && this.options.disabledSteps.length > 0) {
+                $.each(this.options.disabledSteps, function (i, n) {
+                    mi.steps.eq(n).parent('li').addClass('disabled');
+                });
+            }
+            // Error steps
+            if (this.options.errorSteps && this.options.errorSteps.length > 0) {
+                $.each(this.options.errorSteps, function (i, n) {
+                    mi.steps.eq(n).parent('li').addClass('danger');
+                });
+            }
+            // Hidden steps
+            if (this.options.hiddenSteps && this.options.hiddenSteps.length > 0) {
+                $.each(this.options.hiddenSteps, function (i, n) {
+                    mi.steps.eq(n).parent('li').addClass('hidden');
+                });
+            }
+
+            return true;
+        },
+        _setToolbar: function () {
+            // Skip right away if the toolbar is not enabled
+            if (this.options.toolbarSettings.toolbarPosition === 'none') {
+                return true;
+            }
+            console.log(this.options.toolbarSettings.toolbarPosition);
+
+            // Create the toolbar buttons
+            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;
+            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;
+            var btnGroup = $('<div></div>').addClass('btn-group mr-2 sw-btn-group').attr('role', 'group').append(btnPrevious, btnNext);
+
+
+            var box1 = $('<div></div>').addClass('col-sm-2');
+            var box2 = $('<div></div>').addClass('col-sm-10').append(btnGroup);
+
+            // Add extra toolbar buttons
+            var btnGroupExtra = null;
+
+            if (this.options.toolbarSettings.toolbarExtraButtons && this.options.toolbarSettings.toolbarExtraButtons.length > 0) {
+                btnGroupExtra = $('<span></span>').addClass('mr-2 sw-btn-group-extra').attr('role', 'group');
+                $.each(this.options.toolbarSettings.toolbarExtraButtons, function (i, n) {
+                    btnGroupExtra.append(n.clone(true));
+                });
+            }
+
+            var toolbarTop, toolbarBottom;
+            // Append toolbar based on the position
+            switch (this.options.toolbarSettings.toolbarPosition) {
+                case 'top':
+                    toolbarTop = $('<div></div>').addClass('btn-toolbar sw-toolbar sw-toolbar-top justify-content-' + this.options.toolbarSettings.toolbarButtonPosition);
+                    toolbarTop.append(box1, box2);
+                    if (this.options.toolbarSettings.toolbarButtonPosition === 'left') {
+                        box2.append(btnGroupExtra);
+                    } else {
+                        box2.prepend(btnGroupExtra);
+                    }
+                    this.container.before(toolbarTop);
+                    break;
+                case 'bottom':
+                    toolbarBottom = $('<div></div>').addClass('btn-toolbar sw-toolbar sw-toolbar-bottom justify-content-' + this.options.toolbarSettings.toolbarButtonPosition);
+                    toolbarBottom.append(box1, box2);
+                    if (this.options.toolbarSettings.toolbarButtonPosition === 'left') {
+                        box2.append(btnGroupExtra);
+                    } else {
+                        box2.prepend(btnGroupExtra);
+                    }
+                    this.container.after(toolbarBottom);
+                    break;
+                case 'both':
+                    toolbarTop = $('<div></div>').addClass('btn-toolbar sw-toolbar sw-toolbar-top justify-content-' + this.options.toolbarSettings.toolbarButtonPosition);
+                    toolbarTop.append(box1, box2);
+                    if (this.options.toolbarSettings.toolbarButtonPosition === 'left') {
+                        box2.append(btnGroupExtra);
+                    } else {
+                        box2.prepend(btnGroupExtra);
+                    }
+                    this.container.before(toolbarTop);
+
+                    toolbarBottom = $('<div></div>').addClass('btn-toolbar sw-toolbar sw-toolbar-bottom justify-content-' + this.options.toolbarSettings.toolbarButtonPosition);
+                    toolbarBottom.append(box1, box2);
+                    if (this.options.toolbarSettings.toolbarButtonPosition === 'left') {
+                        box2.append(btnGroupExtra.clone(true));
+                    } else {
+                        box2.prepend(btnGroupExtra.clone(true));
+                    }
+                    this.container.after(toolbarBottom);
+                    break;
+                default:
+                    toolbarBottom = $('<div></div>').addClass('btn-toolbar sw-toolbar sw-toolbar-bottom justify-content-' + this.options.toolbarSettings.toolbarButtonPosition);
+                    toolbarBottom.append(box1, box2);
+                    if (this.options.toolbarSettings.toolbarButtonPosition === 'left') {
+                        box2.append(btnGroupExtra);
+                    } else {
+                        box2.prepend(btnGroupExtra);
+                    }
+                    this.container.after(toolbarBottom);
+                    break;
+            }
+            return true;
+        },
+        _setEvents: function () {
+            // Anchor click event
+            var mi = this;
+            $(this.steps).on("click", function (e) {
+                e.preventDefault();
+                if (mi.options.anchorSettings.anchorClickable === false) {
+                    return true;
+                }
+                var idx = mi.steps.index(this);
+                if (mi.options.anchorSettings.enableAnchorOnDoneStep === false && mi.steps.eq(idx).parent('li').hasClass('done')) {
+                    return true;
+                }
+
+                if (idx !== mi.current_index) {
+                    if (mi.options.anchorSettings.enableAllAnchors !== false && mi.options.anchorSettings.anchorClickable !== false) {
+                        mi._showStep(idx);
+                    } else {
+                        if (mi.steps.eq(idx).parent('li').hasClass('done')) {
+                            mi._showStep(idx);
+                        }
+                    }
+                }
+            });
+
+            // Keyboard navigation event
+            if (this.options.keyNavigation) {
+                $(document).keyup(function (e) {
+                    mi._keyNav(e);
+                });
+            }
+
+            // Back/forward browser button event
+            if (this.options.backButtonSupport) {
+                $(window).on('hashchange', function (e) {
+                    if (!mi.options.useURLhash) {
+                        return true;
+                    }
+                    if (window.location.hash) {
+                        var elm = $("a[href*='" + window.location.hash + "']", mi.nav);
+                        if (elm && elm.length > 0) {
+                            e.preventDefault();
+                            mi._showStep(mi.steps.index(elm));
+                        }
+                    }
+                });
+            }
+
+            return true;
+        },
+        _showNext: function () {
+            var si = this.current_index + 1;
+            // Find the next not disabled step
+            for (var i = si; i < this.steps.length; i++) {
+                if (!this.steps.eq(i).parent('li').hasClass('disabled') && !this.steps.eq(i).parent('li').hasClass('hidden')) {
+                    si = i;
+                    break;
+                }
+            }
+
+            if (this.steps.length <= si) {
+                if (!this.options.cycleSteps) {
+                    return false;
+                }
+                si = 0;
+            }
+            this._showStep(si);
+            return true;
+        },
+        _showPrevious: function () {
+            var si = this.current_index - 1;
+            // Find the previous not disabled step
+            for (var i = si; i >= 0; i--) {
+                if (!this.steps.eq(i).parent('li').hasClass('disabled') && !this.steps.eq(i).parent('li').hasClass('hidden')) {
+                    si = i;
+                    break;
+                }
+            }
+            if (0 > si) {
+                if (!this.options.cycleSteps) {
+                    return false;
+                }
+                si = this.steps.length - 1;
+            }
+            this._showStep(si);
+            return true;
+        },
+        _showStep: function (idx) {
+            // If step not found, skip
+            if (!this.steps.eq(idx)) {
+                return false;
+            }
+            // If current step is requested again, skip
+            if (idx == this.current_index) {
+                return false;
+            }
+            // If it is a disabled step, skip
+            if (this.steps.eq(idx).parent('li').hasClass('disabled') || this.steps.eq(idx).parent('li').hasClass('hidden')) {
+                return false;
+            }
+            // Load step content
+            this._loadStepContent(idx);
+            return true;
+        },
+        _loadStepContent: function (idx) {
+            var mi = this;
+            // Get current step elements
+            var curTab = this.steps.eq(this.current_index);
+            // Get the direction of step navigation
+            var stepDirection = '';
+            var elm = this.steps.eq(idx);
+            var contentURL = elm.data('content-url') && elm.data('content-url').length > 0 ? elm.data('content-url') : this.options.contentURL;
+
+            if (this.current_index !== null && this.current_index !== idx) {
+                stepDirection = this.current_index < idx ? "forward" : "backward";
+            }
+
+            // Trigger "leaveStep" event
+            if (this.current_index !== null && this._triggerEvent("leaveStep", [curTab, this.current_index, stepDirection]) === false) {
+                return false;
+            }
+
+            if (contentURL && contentURL.length > 0 && (!elm.data('has-content') || !this.options.contentCache)) {
+                // Get ajax content and then show step
+                var selPage = elm.length > 0 ? $(elm.attr("href"), this.main) : null;
+
+                var ajaxSettings = $.extend(true, {}, {
+                    url: contentURL,
+                    type: "POST",
+                    data: { step_number: idx },
+                    dataType: "text",
+                    beforeSend: function () {
+                        elm.parent('li').addClass('loading');
+                    },
+                    error: function (jqXHR, status, message) {
+                        elm.parent('li').removeClass('loading');
+                        $.error(message);
+                    },
+                    success: function (res) {
+                        if (res && res.length > 0) {
+                            elm.data('has-content', true);
+                            selPage.html(res);
+                        }
+                        elm.parent('li').removeClass('loading');
+                        mi._transitPage(idx);
+                    }
+                }, this.options.ajaxSettings);
+
+                $.ajax(ajaxSettings);
+            } else {
+                // Show step
+                this._transitPage(idx);
+            }
+            return true;
+        },
+        _transitPage: function (idx) {
+            var mi = this;
+            // Get current step elements
+            var curTab = this.steps.eq(this.current_index);
+            var curPage = curTab.length > 0 ? $(curTab.attr("href"), this.main) : null;
+            // Get step to show elements
+            var selTab = this.steps.eq(idx);
+            var selPage = selTab.length > 0 ? $(selTab.attr("href"), this.main) : null;
+            // Get the direction of step navigation
+            var stepDirection = '';
+            if (this.current_index !== null && this.current_index !== idx) {
+                stepDirection = this.current_index < idx ? "forward" : "backward";
+            }
+
+            var stepPosition = 'middle';
+            if (idx === 0) {
+                stepPosition = 'first';
+            } else if (idx === this.steps.length - 1) {
+                stepPosition = 'final';
+            }
+
+            this.options.transitionEffect = this.options.transitionEffect.toLowerCase();
+            this.pages.finish();
+            if (this.options.transitionEffect === 'slide') {
+                // normal slide
+                if (curPage && curPage.length > 0) {
+                    curPage.slideUp('fast', this.options.transitionEasing, function () {
+                        selPage.slideDown(mi.options.transitionSpeed, mi.options.transitionEasing);
+                    });
+                } else {
+                    selPage.slideDown(this.options.transitionSpeed, this.options.transitionEasing);
+                }
+            } else if (this.options.transitionEffect === 'fade') {
+                // normal fade
+                if (curPage && curPage.length > 0) {
+                    curPage.fadeOut('fast', this.options.transitionEasing, function () {
+                        selPage.fadeIn('fast', mi.options.transitionEasing, function () {
+                            $(this).show();
+                        });
+                    });
+                } else {
+                    selPage.fadeIn(this.options.transitionSpeed, this.options.transitionEasing, function () {
+                        $(this).show();
+                    });
+                }
+            } else {
+                if (curPage && curPage.length > 0) {
+                    curPage.hide();
+                }
+                selPage.show();
+            }
+            // Change the url hash to new step
+            this._setURLHash(selTab.attr("href"));
+            // Update controls
+            this._setAnchor(idx);
+            // Set the buttons based on the step
+            this._setButtons(idx);
+            // Fix height with content
+            this._fixHeight(idx);
+            // Update the current index
+            this.current_index = idx;
+
+            // Trigger "showStep" event
+            this._triggerEvent("showStep", [selTab, this.current_index, stepDirection, stepPosition]);
+            return true;
+        },
+        _setAnchor: function (idx) {
+            // Current step anchor > Remove other classes and add done class
+            this.steps.eq(this.current_index).parent('li').removeClass("active danger loading");
+            if (this.options.anchorSettings.markDoneStep !== false && this.current_index !== null) {
+                this._setDone(this.steps.eq(this.current_index).parent('li'));
+                if (this.options.anchorSettings.removeDoneStepOnNavigateBack !== false) {
+                    this._removeDone(this.steps.eq(idx).parent('li').nextAll());
+                }
+            }
+
+            // Next step anchor > Remove other classes and add active class
+            this.steps.eq(idx).parent('li').removeClass("danger loading").addClass("active");
+            this._removeDone(this.steps.eq(idx).parent('li'));
+            return true;
+        },
+
+        _setDone: function ($li) {
+            $li.addClass("done");
+
+            $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>');
+        },
+
+        //
+        _removeDone: function ($lis) {
+            $lis.removeClass("done");
+
+            $lis.each(function (k, li) {
+                var $icon = $(li).find('.la-step-icon');
+
+                $icon.text($icon.data('index') + 1);
+            });
+
+
+        },
+
+        _setButtons: function (idx) {
+            // Previous/Next Button enable/disable based on step
+            if (!this.options.cycleSteps) {
+                if (0 >= idx) {
+                    $('.sw-btn-prev', this.main).addClass("disabled");
+                } else {
+                    $('.sw-btn-prev', this.main).removeClass("disabled");
+                }
+                if (this.steps.length - 1 <= idx) {
+                    $('.sw-btn-next', this.main).addClass("disabled");
+                } else {
+                    $('.sw-btn-next', this.main).removeClass("disabled");
+                }
+            }
+            return true;
+        },
+
+        // HELPER FUNCTIONS
+
+        _keyNav: function (e) {
+            var mi = this;
+            // Keyboard navigation
+            switch (e.which) {
+                case 37:
+                    // left
+                    mi._showPrevious();
+                    e.preventDefault();
+                    break;
+                case 39:
+                    // right
+                    mi._showNext();
+                    e.preventDefault();
+                    break;
+                default:
+                    return; // exit this handler for other keys
+            }
+        },
+        _fixHeight: function (idx) {
+            // Auto adjust height of the container
+            if (this.options.autoAdjustHeight) {
+                var selPage = this.steps.eq(idx).length > 0 ? $(this.steps.eq(idx).attr("href"), this.main) : null;
+                this.container.finish().animate({ minHeight: selPage.outerHeight() }, this.options.transitionSpeed, function () {});
+            }
+            return true;
+        },
+        _triggerEvent: function (name, params) {
+            // Trigger an event
+            var e = $.Event(name);
+            this.main.trigger(e, params);
+            if (e.isDefaultPrevented()) {
+                return false;
+            }
+            return e.result;
+        },
+        _setURLHash: function (hash) {
+            if (this.options.showStepURLhash && window.location.hash !== hash) {
+                window.location.hash = hash;
+            }
+        },
+
+        // PUBLIC FUNCTIONS
+
+        theme: function (v) {
+            if (this.options.theme === v) {
+                return false;
+            }
+            this.main.removeClass('sw-theme-' + this.options.theme);
+            this.options.theme = v;
+            this.main.addClass('sw-theme-' + this.options.theme);
+            // Trigger "themeChanged" event
+            this._triggerEvent("themeChanged", [this.options.theme]);
+        },
+        next: function () {
+            this._showNext();
+        },
+        prev: function () {
+            this._showPrevious();
+        },
+        reset: function () {
+            // Trigger "beginReset" event
+            if (this._triggerEvent("beginReset") === false) {
+                return false;
+            }
+
+            // Reset all elements and classes
+            this.container.stop(true);
+            this.pages.stop(true);
+            this.pages.hide();
+            this.current_index = null;
+            this._setURLHash(this.steps.eq(this.options.selected).attr("href"));
+            $(".sw-toolbar", this.main).remove();
+            this.steps.removeClass();
+            this.steps.parents('li').removeClass();
+            this.steps.data('has-content', false);
+            this.init();
+
+            // Trigger "endReset" event
+            this._triggerEvent("endReset");
+        },
+        stepState: function (stepArray, state) {
+            var mi = this;
+            stepArray = $.isArray(stepArray) ? stepArray : [stepArray];
+            var selSteps = $.grep(this.steps, function (n, i) {
+                return $.inArray(i, stepArray) !== -1 && i !== mi.current_index;
+            });
+            if (selSteps && selSteps.length > 0) {
+                switch (state) {
+                    case 'disable':
+                        $(selSteps).parents('li').addClass('disabled');
+                        break;
+                    case 'enable':
+                        $(selSteps).parents('li').removeClass('disabled');
+                        break;
+                    case 'hide':
+                        $(selSteps).parents('li').addClass('hidden');
+                        break;
+                    case 'show':
+                        $(selSteps).parents('li').removeClass('hidden');
+                        break;
+                }
+            }
+        }
+    });
+
+    // Wrapper for the plugin
+    $.fn.smartWizard = function (options) {
+        var args = arguments;
+        var instance;
+
+        if (options === undefined || typeof options === 'object') {
+            return this.each(function () {
+                if (!$.data(this, "smartWizard")) {
+                    $.data(this, "smartWizard", new SmartWizard(this, options));
+                }
+            });
+        } else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') {
+            instance = $.data(this[0], 'smartWizard');
+
+            if (options === 'destroy') {
+                $.data(this, 'smartWizard', null);
+            }
+
+            if (instance instanceof SmartWizard && typeof instance[options] === 'function') {
+                return instance[options].apply(instance, Array.prototype.slice.call(args, 1));
+            } else {
+                return this;
+            }
+        }
+    };
+})(jQuery, window, document);

File diff suppressed because it is too large
+ 0 - 0
resources/assets/SmartWizard/dist/js/jquery.smartWizard.min.js


+ 11 - 0
resources/assets/SmartWizard/examples/ajaxtest.php

@@ -0,0 +1,11 @@
+<?php
+sleep(2);
+$step_number = $_REQUEST["step_number"];
+echo '<h2 class="StepTitle">Hello from Server! Step '.($step_number + 1).',</h2>
+            <p>We have added a 2 sec sleep to feel the ajax loading, It would be faster otherwise</p>
+            <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, 
+            sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, 
+            quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. 
+            Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. 
+            Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+            </p>';

+ 162 - 0
resources/assets/SmartWizard/examples/index.html

@@ -0,0 +1,162 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Smart Wizard - a JavaScript jQuery Step Wizard plugin</title>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+    <!-- Include Bootstrap CSS -->
+    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
+    <!-- Optional Bootstrap Theme -->
+    <link rel="stylesheet" href="../dist/css/bootstrap.min.css">
+
+    <!-- Include SmartWizard CSS -->
+    <link href="../dist/css/smart_wizard.css" rel="stylesheet" type="text/css" />
+
+    <!-- Optional SmartWizard theme -->
+    <link href="../dist/css/smart_wizard_theme_circles.css" rel="stylesheet" type="text/css" />
+    <link href="../dist/css/smart_wizard_theme_arrows.css" rel="stylesheet" type="text/css" />
+    <link href="../dist/css/smart_wizard_theme_dots.css" rel="stylesheet" type="text/css" />
+</head>
+<body>
+    <div class="container">
+
+        <form class="form-inline">
+            <label class="mr-sm-2">Choose Theme:</label>
+            <select id="theme_selector" class="custom-select mb-2 mr-sm-2 mb-sm-0">
+                  <option value="default">default</option>
+                  <option value="arrows">arrows</option>
+                  <option value="circles">circles</option>
+                  <option value="dots">dots</option>
+            </select>
+
+            <label class="mr-sm-2">External Buttons:</label>
+            <div class="btn-group" role="group">
+                <button class="btn btn-secondary" id="prev-btn" type="button">Go Previous</button>
+                <button class="btn btn-secondary" id="next-btn" type="button">Go Next</button>
+                <button class="btn btn-danger" id="reset-btn" type="button">Reset Wizard</button>
+            </div>
+        </form>
+
+        <br />
+
+        <!-- SmartWizard html -->
+        <div id="smartwizard">
+            <ul>
+                <li><a href="#step-1">Step 1<br /><small>This is step description</small></a></li>
+                <li><a href="#step-2">Step 2<br /><small>This is step description</small></a></li>
+                <li><a href="#step-3">Step 3<br /><small>This is step description</small></a></li>
+                <li><a href="#step-4">Step 4<br /><small>This is step description</small></a></li>
+            </ul>
+
+            <div>
+                <div id="step-1" class="">
+                    <h2>Step 1 Content</h2>
+                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+                </div>
+                <div id="step-2" class="">
+                    <h2>Step 2 Content</h2>
+                    <div>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum. </div>
+                </div>
+                <div id="step-3" class="">
+                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+                </div>
+                <div id="step-4" class="">
+                    <h2>Step 4 Content</h2>
+                    <div class="card">
+                        <div class="card-header">My Details</div>
+                        <div class="card-block p-0">
+                          <table class="table">
+                              <tbody>
+                                  <tr> <th>Name:</th> <td>Tim Smith</td> </tr>
+                                  <tr> <th>Email:</th> <td>example@example.com</td> </tr>
+                              </tbody>
+                          </table>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+
+
+    </div>
+
+    <!-- Include jQuery -->
+    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
+
+    <!-- Include SmartWizard JavaScript source -->
+    <script type="text/javascript" src="../dist/js/jquery.smartWizard.min.js"></script>
+
+    <script type="text/javascript">
+        $(document).ready(function(){
+
+            // Step show event
+            $("#smartwizard").on("showStep", function(e, anchorObject, stepNumber, stepDirection, stepPosition) {
+               //alert("You are on step "+stepNumber+" now");
+               if(stepPosition === 'first'){
+                   $("#prev-btn").addClass('disabled');
+               }else if(stepPosition === 'final'){
+                   $("#next-btn").addClass('disabled');
+               }else{
+                   $("#prev-btn").removeClass('disabled');
+                   $("#next-btn").removeClass('disabled');
+               }
+            });
+
+            // Toolbar extra buttons
+            var btnFinish = $('<button></button>').text('Finish')
+                                             .addClass('btn btn-info')
+                                             .on('click', function(){ alert('Finish Clicked'); });
+            var btnCancel = $('<button></button>').text('Cancel')
+                                             .addClass('btn btn-danger')
+                                             .on('click', function(){ $('#smartwizard').smartWizard("reset"); });
+
+
+            // Smart Wizard
+            $('#smartwizard').smartWizard({
+                    selected: 0,
+                    theme: 'default',
+                    transitionEffect:'fade',
+                    showStepURLhash: true,
+                    toolbarSettings: {toolbarPosition: 'both',
+                                      toolbarExtraButtons: [btnFinish, btnCancel]
+                                    }
+            });
+
+
+            // External Button Events
+            $("#reset-btn").on("click", function() {
+                // Reset wizard
+                $('#smartwizard').smartWizard("reset");
+                return true;
+            });
+
+            $("#prev-btn").on("click", function() {
+                // Navigate previous
+                $('#smartwizard').smartWizard("prev");
+                return true;
+            });
+
+            $("#next-btn").on("click", function() {
+                // Navigate next
+                $('#smartwizard').smartWizard("next");
+                return true;
+            });
+
+            $("#theme_selector").on("change", function() {
+                // Change theme
+                $('#smartwizard').smartWizard("theme", $(this).val());
+                return true;
+            });
+
+            // Set selected theme on page refresh
+            $("#theme_selector").change();
+        });
+    </script>
+</body>
+</html>

+ 98 - 0
resources/assets/SmartWizard/examples/smartwizard-ajax.html

@@ -0,0 +1,98 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Smart Wizard - a JavaScript jQuery Step Wizard plugin</title>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+    <!-- Include Bootstrap CSS -->
+    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
+    <!-- Optional Bootstrap Theme -->
+    <link rel="stylesheet" href="../dist/css/bootstrap.min.css">
+
+    <!-- Include SmartWizard CSS -->
+    <link href="../dist/css/smart_wizard.css" rel="stylesheet" type="text/css" />
+
+    <!-- Optional SmartWizard theme -->
+    <link href="../dist/css/smart_wizard_theme_arrows.css" rel="stylesheet" type="text/css" />
+</head>
+<body>
+    <div class="container">
+
+        <!-- SmartWizard html -->
+        <div id="smartwizard">
+            <ul>
+                <li><a href="#step-1">Step 1<br /><small>This is tab's description</small></a></li>
+                <li><a href="#step-2" data-content-url="./ajaxtest.php">Step 2<br /><small>This is tab's description</small></a></li>
+                <li><a href="#step-3">Step 3<br /><small>This is tab's description</small></a></li>
+                <li><a href="#step-4" data-content-url="./ajaxtest.php">Step 4<br /><small>This is tab's description</small></a></li>
+            </ul>
+
+            <div>
+                <div id="step-1" class="">
+                    <h2>Step 1 Content, Non ajax content</h2>
+                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+                </div>
+                <div id="step-2" class="">
+                    <h2>Step 2 Content, Non ajax content</h2>
+                    <div>Hello This is a div</div>
+                </div>
+                <div id="step-3" class="">
+                    <h2>Step 3 Content, Non ajax content</h2>
+                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+                </div>
+                <div id="step-4" class="">
+                    <h2>Step 4 Content, Non ajax content</h2>
+                    <div class="card">
+                        <div class="card-header">My Details</div>
+                        <div class="card-block p-0">
+                          <table class="table">
+                              <tbody>
+                                  <tr> <th>Name:</th> <td>Tim Smith</td> </tr>
+                                  <tr> <th>Email:</th> <td>example@example.com</td> </tr>
+                              </tbody>
+                          </table>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+
+
+    </div>
+
+    <!-- Include jQuery -->
+    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
+
+    <!-- Include SmartWizard JavaScript source -->
+    <script type="text/javascript" src="../dist/js/jquery.smartWizard.min.js"></script>
+
+    <script type="text/javascript">
+        $(document).ready(function(){
+
+            // Toolbar extra buttons
+            var btnFinish = $('<button></button>').text('Finish')
+                                             .addClass('btn btn-info')
+                                             .on('click', function(){ alert('Finish Clicked'); });
+            var btnCancel = $('<button></button>').text('Cancel')
+                                             .addClass('btn btn-danger')
+                                             .on('click', function(){ $('#smartwizard').smartWizard("reset"); });
+
+            // Smart Wizard
+            $('#smartwizard').smartWizard({
+                    selected: 0,
+                    theme: 'arrows',
+                    transitionEffect:'fade',
+                    toolbarSettings: {toolbarPosition: 'bottom',
+                                      toolbarExtraButtons: [btnFinish, btnCancel]
+                                    }
+                 });
+        });
+    </script>
+</body>
+</html>

+ 173 - 0
resources/assets/SmartWizard/examples/smartwizard-events.html

@@ -0,0 +1,173 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Smart Wizard - a JavaScript jQuery Step Wizard plugin</title>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+    <!-- Include Bootstrap CSS -->
+    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
+    <!-- Optional Bootstrap Theme -->
+    <link rel="stylesheet" href="../dist/css/bootstrap.min.css">
+
+    <!-- Include SmartWizard CSS -->
+    <link href="../dist/css/smart_wizard.css" rel="stylesheet" type="text/css" />
+
+    <!-- Optional SmartWizard theme -->
+    <link href="../dist/css/smart_wizard_theme_circles.css" rel="stylesheet" type="text/css" />
+    <link href="../dist/css/smart_wizard_theme_arrows.css" rel="stylesheet" type="text/css" />
+    <link href="../dist/css/smart_wizard_theme_dots.css" rel="stylesheet" type="text/css" />
+</head>
+<body>
+    <div class="container">
+
+      <form class="form-inline">
+          <label class="mr-sm-2">Choose Theme:</label>
+          <select id="theme_selector" class="custom-select mb-2 mr-sm-2 mb-sm-0">
+                <option value="default">default</option>
+                <option value="arrows">arrows</option>
+                <option value="circles">circles</option>
+                <option value="dots">dots</option>
+          </select>
+
+          <label class="mr-sm-2">External Buttons:</label>
+          <div class="btn-group" role="group">
+              <button class="btn btn-secondary" id="prev-btn" type="button">Go Previous</button>
+              <button class="btn btn-secondary" id="next-btn" type="button">Go Next</button>
+              <button class="btn btn-danger" id="reset-btn" type="button">Reset Wizard</button>
+          </div>
+      </form>
+        <div class="alert alert-info" role="alert" id="message-box"><strong>Event Log:</strong></div>
+
+        <!-- SmartWizard html -->
+        <div id="smartwizard">
+            <ul>
+                <li><a href="#step-1">Step 1<br /><small>This is tab's description</small></a></li>
+                <li><a href="#step-2">Step 2<br /><small>This is tab's description</small></a></li>
+                <li><a href="#step-3">Step 3<br /><small>This is tab's description</small></a></li>
+                <li><a href="#step-4">Step 4<br /><small>This is tab's description</small></a></li>
+            </ul>
+
+            <div>
+                <div id="step-1" class="">
+                    <h2>Step 1 Content</h2>
+                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+                </div>
+                <div id="step-2" class="">
+                    <h2>Step 2 Content</h2>
+                    <div>Hello This is a div</div>
+                </div>
+                <div id="step-3" class="">
+                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+                </div>
+                <div id="step-4" class="">
+                    <h2>Step 4 Content</h2>
+                    <div class="card">
+                        <div class="card-header">My Details</div>
+                        <div class="card-block p-0">
+                          <table class="table">
+                              <tbody>
+                                  <tr> <th>Name:</th> <td>Tim Smith</td> </tr>
+                                  <tr> <th>Email:</th> <td>example@example.com</td> </tr>
+                              </tbody>
+                          </table>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+
+
+    </div>
+
+    <!-- Include jQuery -->
+    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
+
+    <!-- Include SmartWizard JavaScript source -->
+    <script type="text/javascript" src="../dist/js/jquery.smartWizard.min.js"></script>
+
+    <script type="text/javascript">
+        $(document).ready(function(){
+
+            // Smart Wizard events
+            $("#smartwizard").on("leaveStep", function(e, anchorObject, stepNumber, stepDirection) {
+                $("#message-box").append("<br /> > <strong>leaveStep</strong> called on " + stepNumber + ". Direction: " + stepDirection);
+                var res = confirm("Do you want to leave the step "+stepNumber+"?");
+                if(!res){
+                    $("#message-box").append(" <strong>leaveStep</strong> Cancelled");
+                }else{
+                    $("#message-box").append(" <strong>leaveStep</strong> Allowed");
+                }
+                return res;
+            });
+
+            // This event should initialize before initializing smartWizard
+            // Otherwise this event wont load on first page load
+            $("#smartwizard").on("showStep", function(e, anchorObject, stepNumber, stepDirection, stepPosition) {
+                $("#message-box").append(" > <strong>showStep</strong> called on " + stepNumber + ". Direction: " + stepDirection+ ". Position: " + stepPosition);
+            });
+
+            $("#smartwizard").on("beginReset", function(e) {
+                $("#message-box").append("<br /> > <strong>beginReset</strong> called");
+            });
+
+            $("#smartwizard").on("endReset", function(e) {
+                $("#message-box").append(" > <strong>endReset</strong> called");
+            });
+
+            $("#smartwizard").on("themeChanged", function(e, theme) {
+                $("#message-box").append("<br /> > <strong>themeChanged</strong> called. New theme: " + theme);
+            });
+
+            // Toolbar extra buttons
+            var btnFinish = $('<button></button>').text('Finish')
+                                             .addClass('btn btn-info')
+                                             .on('click', function(){ alert('Finish Clicked'); });
+            var btnCancel = $('<button></button>').text('Cancel')
+                                             .addClass('btn btn-danger')
+                                             .on('click', function(){ $('#smartwizard').smartWizard("reset"); });
+
+            // Smart Wizard initialize
+            $('#smartwizard').smartWizard({
+                    selected: 0,
+                    theme: 'dots',
+                    transitionEffect:'fade',
+                    toolbarSettings: {toolbarPosition: 'bottom',
+                                      toolbarExtraButtons: [btnFinish, btnCancel]
+                                    }
+                 });
+
+            // External Button Events
+            $("#reset-btn").on("click", function() {
+                // Reset wizard
+                $('#smartwizard').smartWizard("reset");
+                return true;
+            });
+
+            $("#prev-btn").on("click", function() {
+                // Navigate previous
+                $('#smartwizard').smartWizard("prev");
+                return true;
+            });
+
+            $("#next-btn").on("click", function() {
+                // Navigate next
+                $('#smartwizard').smartWizard("next");
+                return true;
+            });
+
+            $("#theme_selector").on("change", function() {
+                // Change theme
+                $('#smartwizard').smartWizard("theme", $(this).val());
+                return true;
+            });
+
+        });
+    </script>
+</body>
+</html>

+ 190 - 0
resources/assets/SmartWizard/examples/smartwizard-input.html

@@ -0,0 +1,190 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Smart Wizard - a JavaScript jQuery Step Wizard plugin</title>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+    <!-- Include Bootstrap CSS -->
+    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
+    <!-- Optional Bootstrap Theme -->
+    <link rel="stylesheet" href="../dist/css/bootstrap.min.css">
+
+    <!-- Include SmartWizard CSS -->
+    <link href="../dist/css/smart_wizard.css" rel="stylesheet" type="text/css" />
+
+    <!-- Optional SmartWizard theme -->
+    <link href="../dist/css/smart_wizard_theme_dots.css" rel="stylesheet" type="text/css" />
+</head>
+<body>
+    <div class="container">
+        <br />
+        <form action="#" id="myForm" role="form" data-toggle="validator" method="post" accept-charset="utf-8">
+
+        <!-- SmartWizard html -->
+        <div id="smartwizard">
+            <ul>
+                <li><a href="#step-1">Step 1<br /><small>Email Address</small></a></li>
+                <li><a href="#step-2">Step 2<br /><small>Name</small></a></li>
+                <li><a href="#step-3">Step 3<br /><small>Address</small></a></li>
+                <li><a href="#step-4">Step 4<br /><small>Terms and Conditions</small></a></li>
+            </ul>
+
+            <div>
+                <div id="step-1">
+                    <h2>Your Email Address</h2>
+                    <div id="form-step-0" role="form" data-toggle="validator">
+                        <div class="form-group">
+                            <label for="email">Email address:</label>
+                            <input pattern="^[0-9]{1,}$" class="form-control" name="email" id="email" placeholder="Write your email address" required>
+                            <div class="help-block with-errors"></div>
+                        </div>
+                    </div>
+
+                </div>
+                <div id="step-2">
+                    <h2>Your Name</h2>
+                    <div id="form-step-1" role="form" data-toggle="validator">
+                        <div class="form-group">
+                            <label for="name">Name:</label>
+                            <input type="text" class="form-control" name="name" id="email" placeholder="Write your name" required>
+                            <div class="help-block with-errors"></div>
+                        </div>
+                    </div>
+                </div>
+                <div id="step-3">
+                    <h2>Your Address</h2>
+                    <div id="form-step-2" role="form" data-toggle="validator">
+                        <div class="form-group">
+                            <label for="address">Address</label>
+                            <textarea class="form-control" name="address" id="address" rows="3" placeholder="Write your address..." required></textarea>
+                            <div class="help-block with-errors"></div>
+                        </div>
+                    </div>
+                </div>
+                <div id="step-4" class="">
+                    <h2>Terms and Conditions</h2>
+                    <p>
+                        Terms and conditions: Keep your smile :)
+                    </p>
+                    <div id="form-step-3" role="form" data-toggle="validator">
+                        <div class="form-group">
+                            <label for="terms">I agree with the T&C</label>
+                            <input type="checkbox" id="terms" data-error="Please accept the Terms and Conditions" required>
+                            <div class="help-block with-errors"></div>
+                        </div>
+                    </div>
+
+
+                </div>
+            </div>
+        </div>
+
+            <div class=""><button id="next-step">下一步</button></div>
+        </form>
+
+    </div>
+
+    <!-- Include jQuery -->
+    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
+    <!-- Include jQuery Validator plugin -->
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/1000hz-bootstrap-validator/0.11.5/validator.min.js"></script>
+
+
+    <!-- Include SmartWizard JavaScript source -->
+    <script type="text/javascript" src="../dist/js/jquery.smartWizard.min.js"></script>
+
+    <script type="text/javascript">
+        $(document).ready(function(){
+
+            // Toolbar extra buttons
+            var btnFinish = $('<button></button>').text('Finish')
+                                             .addClass('btn btn-info')
+                                             .on('click', function(){
+                                                    if( !$(this).hasClass('disabled')){
+                                                        var elmForm = $("#myForm");
+                                                        if(elmForm){
+                                                            elmForm.validator('validate');
+                                                            var elmErr = elmForm.find('.has-error');
+                                                            if(elmErr && elmErr.length > 0){
+                                                                alert('Oops we still have error in the form');
+                                                                return false;
+                                                            }else{
+                                                                alert('Great! we are ready to submit form');
+                                                                elmForm.submit();
+                                                                return false;
+                                                            }
+                                                        }
+                                                    }
+                                                });
+            var btnCancel = $('<button></button>').text('Cancel')
+                                             .addClass('btn btn-danger')
+                                             .on('click', function(){
+                                                    $('#smartwizard').smartWizard("reset");
+                                                    $('#myForm').find("input, textarea").val("");
+                                                });
+
+
+
+            // Smart Wizard
+            var smartWizard = $('#smartwizard').smartWizard({
+                    selected: 0,
+                    theme: 'dots',
+                    transitionEffect:'fade',
+                    useURLhash: false,
+                    toolbarSettings: {toolbarPosition: 'bottom',
+                                      // toolbarExtraButtons: [btnFinish, btnCancel]
+                        showNextButton: false, // show/hide a Next button
+                        showPreviousButton: false, // show/hide a Previous button
+                                    },
+                    anchorSettings: {
+                                markDoneStep: true, // add done css
+                                markAllPreviousStepsAsDone: true, // When a step selected by url hash, all previous steps are marked done
+                                removeDoneStepOnNavigateBack: true, // While navigate back done step after active step will be cleared
+                                enableAnchorOnDoneStep: true // Enable/Disable the done steps navigation
+                            }
+                 });
+            smartWizard = smartWizard.data('smartWizard');
+
+            $("#smartwizard").on("leaveStep", function(e, anchorObject, stepNumber, stepDirection) {
+                var elmForm = $("#form-step-" + stepNumber);
+                // stepDirection === 'forward' :- this condition allows to do the form validation
+                // only on forward navigation, that makes easy navigation on backwards still do the validation when going next
+
+                console.log('leaveStep', anchorObject, stepNumber, stepDirection, elmForm);
+                if(stepDirection === 'forward' && elmForm){
+                    elmForm.validator('validate');
+                    var elmErr = elmForm.children('.has-error');
+                    if(elmErr && elmErr.length > 0){
+                        // Form validation failed
+                        return false;
+                    }
+                }
+                return true;
+            });
+
+            $("#smartwizard").on("showStep", function(e, anchorObject, stepNumber, stepDirection) {
+                // Enable finish button only on last step
+                if(stepNumber == 3){
+                    $('.btn-finish').removeClass('disabled');
+                }else{
+                    $('.btn-finish').addClass('disabled');
+                }
+            });
+
+            var $sw = $("#smartwizard");
+            $('#next-step').click(function (e) {
+                console.log(smartWizard.current_index, '点击下一步按钮');
+
+                e.preventDefault();
+                if (smartWizard.steps.index(this) !== smartWizard.current_index) {
+                    smartWizard.next();
+                }
+            });
+
+
+
+        });
+    </script>
+</body>
+</html>

+ 217 - 0
resources/assets/SmartWizard/examples/smartwizard-multiple.html

@@ -0,0 +1,217 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Smart Wizard - a JavaScript jQuery Step Wizard plugin</title>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+    <!-- Include Bootstrap CSS -->
+    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
+    <!-- Optional Bootstrap Theme -->
+    <link rel="stylesheet" href="../dist/css/bootstrap.min.css">
+
+    <!-- Include SmartWizard CSS -->
+    <link href="../dist/css/smart_wizard.css" rel="stylesheet" type="text/css" />
+
+    <!-- Optional SmartWizard theme -->
+    <link href="../dist/css/smart_wizard_theme_circles.css" rel="stylesheet" type="text/css" />
+    <link href="../dist/css/smart_wizard_theme_arrows.css" rel="stylesheet" type="text/css" />
+    <link href="../dist/css/smart_wizard_theme_dots.css" rel="stylesheet" type="text/css" />
+</head>
+<body>
+    <div class="container">
+
+        <form class="form-inline">
+            <label class="mr-sm-2">Choose Theme:</label>
+            <select id="theme_selector" class="custom-select mb-2 mr-sm-2 mb-sm-0">
+                  <option value="default">default</option>
+                  <option value="arrows">arrows</option>
+                  <option value="circles">circles</option>
+                  <option value="dots">dots</option>
+            </select>
+
+            <label class="mr-sm-2">External Buttons:</label>
+            <div class="btn-group" role="group">
+                <button class="btn btn-secondary" id="prev-btn" type="button">Go Previous</button>
+                <button class="btn btn-secondary" id="next-btn" type="button">Go Next</button>
+                <button class="btn btn-danger" id="reset-btn" type="button">Reset Wizard</button>
+            </div>
+        </form>
+
+        <br />
+
+        <!-- SmartWizard 1 html -->
+        <div id="smartwizard">
+            <ul>
+                <li><a href="#step-1">Step 1<br /><small>This is step description</small></a></li>
+                <li><a href="#step-2">Step 2<br /><small>This is step description</small></a></li>
+                <li><a href="#step-3">Step 3<br /><small>This is step description</small></a></li>
+                <li><a href="#step-4">Step 4<br /><small>This is step description</small></a></li>
+            </ul>
+
+            <div>
+                <div id="step-1" class="">
+                    <h2>Step 1 Content</h2>
+                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+                </div>
+                <div id="step-2" class="">
+                    <h2>Step 2 Content</h2>
+                    <div>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum. </div>
+                </div>
+                <div id="step-3" class="">
+                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+                </div>
+                <div id="step-4" class="">
+                  <h2>Step 4 Content</h2>
+                  <div class="card">
+                      <div class="card-header">My Details</div>
+                      <div class="card-block p-0">
+                        <table class="table">
+                            <tbody>
+                                <tr> <th>Name:</th> <td>Tim Smith</td> </tr>
+                                <tr> <th>Email:</th> <td>example@example.com</td> </tr>
+                            </tbody>
+                        </table>
+                      </div>
+                  </div>
+                </div>
+            </div>
+        </div>
+
+        <br />
+
+        <!-- SmartWizard 2 html -->
+        <div id="smartwizard2">
+            <ul>
+                <li><a href="#step-1">Step 1<br /><small>This is step description</small></a></li>
+                <li><a href="#step-2">Step 2<br /><small>This is step description</small></a></li>
+                <li><a href="#step-3">Step 3<br /><small>This is step description</small></a></li>
+                <li><a href="#step-4">Step 4<br /><small>This is step description</small></a></li>
+            </ul>
+
+            <div>
+                <div id="step-1" class="">
+                    <h2>Step 1 Content</h2>
+                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+                </div>
+                <div id="step-2" class="">
+                    <h2>Step 2 Content</h2>
+                    <div>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum. </div>
+                </div>
+                <div id="step-3" class="">
+                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+                </div>
+                <div id="step-4" class="">
+                  <h2>Step 4 Content</h2>
+                  <div class="card">
+                      <div class="card-header">My Details</div>
+                      <div class="card-block p-0">
+                        <table class="table">
+                            <tbody>
+                                <tr> <th>Name:</th> <td>Tim Smith</td> </tr>
+                                <tr> <th>Email:</th> <td>example@example.com</td> </tr>
+                            </tbody>
+                        </table>
+                      </div>
+                  </div>
+                </div>
+            </div>
+        </div>
+
+
+    </div>
+
+    <!-- Include jQuery -->
+    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
+
+    <!-- Include SmartWizard JavaScript source -->
+    <script type="text/javascript" src="../dist/js/jquery.smartWizard.min.js"></script>
+
+    <script type="text/javascript">
+        $(document).ready(function(){
+
+            // Step show event
+            $("#smartwizard").on("showStep", function(e, anchorObject, stepNumber, stepDirection, stepPosition) {
+               //alert("You are on step "+stepNumber+" now");
+               if(stepPosition === 'first'){
+                   $("#prev-btn").addClass('disabled');
+               }else if(stepPosition === 'final'){
+                   $("#next-btn").addClass('disabled');
+               }else{
+                   $("#prev-btn").removeClass('disabled');
+                   $("#next-btn").removeClass('disabled');
+               }
+            });
+
+            // Toolbar extra buttons
+            var btnFinish = $('<button></button>').text('Finish')
+                                             .addClass('btn btn-info')
+                                             .on('click', function(){ alert('Finish Clicked'); });
+            var btnCancel = $('<button></button>').text('Cancel')
+                                             .addClass('btn btn-danger')
+                                             .on('click', function(){ $('#smartwizard').smartWizard("reset"); });
+
+            // Please note enabling option "showStepURLhash" will make navigation conflict for multiple wizard in a page.
+            // so that option is disabling => showStepURLhash: false
+
+            // Smart Wizard 1
+            $('#smartwizard').smartWizard({
+                    selected: 0,
+                    theme: 'default',
+                    transitionEffect:'fade',
+                    showStepURLhash: false,
+                    toolbarSettings: {toolbarPosition: 'both',
+                                      toolbarExtraButtons: [btnFinish, btnCancel]
+                                    }
+            });
+
+            // Smart Wizard 2
+            $('#smartwizard2').smartWizard({
+                    selected: 0,
+                    theme: 'default',
+                    transitionEffect:'fade',
+                    showStepURLhash: false
+            });
+
+
+            // External Button Events
+            $("#reset-btn").on("click", function() {
+                // Reset wizard
+                $('#smartwizard').smartWizard("reset");
+                return true;
+            });
+
+            $("#prev-btn").on("click", function() {
+                // Navigate previous
+                $('#smartwizard').smartWizard("prev");
+                return true;
+            });
+
+            $("#next-btn").on("click", function() {
+                // Navigate next
+                $('#smartwizard').smartWizard("next");
+                return true;
+            });
+
+            $("#theme_selector").on("change", function() {
+                // Change theme
+                $('#smartwizard').smartWizard("theme", $(this).val());
+                return true;
+            });
+
+            // Set selected theme on page refresh
+            $("#theme_selector").change();
+        });
+    </script>
+</body>
+</html>

+ 3 - 0
resources/lang/en/admin.php

@@ -147,6 +147,9 @@ return [
     'size'                  => 'Size',
     'between_start'         => 'Start',
     'between_end'           => 'End',
+    'next_step'             => 'Next',
+    'prev_step'             => 'Previous',
+    'done'                  => 'Done',
     'listbox'               => [
         'text_total'         => 'Showing all {0}',
         'text_empty'         => 'Empty list',

+ 3 - 0
resources/lang/zh-CN/admin.php

@@ -147,6 +147,9 @@ return [
     'size'                  => '大小',
     'between_start'         => '起始',
     'between_end'           => '结束',
+    'next_step'             => '下一步',
+    'prev_step'             => '上一步',
+    'done'                  => '完成',
     'create_extension'      => '创建扩展',
     'listbox'               => [
         'text_total'         => '总共 {0} 项',

+ 30 - 0
resources/views/form/step-form.blade.php

@@ -0,0 +1,30 @@
+{!! $start !!}
+<div class="box-body fields-group">
+
+    @foreach($fields as $field)
+        {!! $field->render() !!}
+    @endforeach
+
+</div>
+
+<!-- /.box-body -->
+@if(count($buttons) > 0)
+    <div class="box-footer">
+        <div class="col-md-2"></div>
+
+        <div class="col-md-8">
+            @if(in_array('previous', $buttons))
+                <div class="btn-group pull-left">
+                    <span class="btn btn-warning pull-right previous-step">{!! trans('admin.') !!}</span>
+                </div>
+            @endif
+
+            @if(in_array('next', $buttons))
+                <div class="btn-group pull-right">
+                    <span class="btn btn-primary pull-right next-step">{!! trans('admin.next') !!}</span>
+                </div>
+            @endif
+        </div>
+    </div>
+@endif
+{!! $end !!}

+ 216 - 0
resources/views/form/steps.blade.php

@@ -0,0 +1,216 @@
+@if($showHeader)
+    <div class="box-header with-border">
+        <h3 class="box-title" style="line-height:30px">{!! $form->title() !!}</h3>
+        <div class="pull-right">{!! $form->renderTools() !!}</div>
+    </div>
+@endif
+
+<div class="box-body" style="padding:18px 18px 30px">
+    @if($steps)
+        <div class="fields-group la-step-box" style="padding:18px;max-width: 1000px">
+
+            <ul class="la-step-horizontal la-step-label-horizontal la-step ">
+                @foreach($steps as $step)
+                <li class="la-step-item">
+                    <a href="#{{ $step->getFormId() }}" class="la-step-item-container">
+                        <div class="la-step-line"></div>
+                        <div class="la-step-icons">
+                            <span class="la-step-icon" data-index="{{ $step->getIndex() }}">{{ $step->getIndex() + 1 }}</span>
+                        </div>
+                        <div class="la-step-content">
+                            <div class="la-step-title">{!! $step->getTitle() !!}</div>
+                            <div class="la-step-desc"> {{ $step->getDescription() }} </div>
+                        </div>
+                    </a>
+                </li>
+                @endforeach
+
+                <li class="la-step-item">
+                    <a href="#{{ $doneStep->getElementId() }}" class="la-step-item-container">
+                        <div class="la-step-line"></div>
+                        <div class="la-step-icons">
+                            <span class="la-step-icon" data-index="{{ count($steps) }}"> {{ count($steps) + 1 }} </span>
+                        </div>
+                        <div class="la-step-content">
+                            <div class="la-step-title">{{ $doneStep->title() }}</div>
+                            <div class="la-step-desc"></div>
+                        </div>
+                    </a>
+                </li>
+            </ul>
+            <div>
+                @foreach($steps as $step)
+                    {!! $step->render() !!}
+                @endforeach
+            </div>
+        </div>
+    @endif
+</div>
+
+@foreach($form->getHiddenFields() as $field)
+    {!! $field->render() !!}
+@endforeach
+
+<input type="hidden" class="current-step-input" name="{{ Dcat\Admin\Form\StepForm::CURRENT_VALIDATION_STEP }}" />
+<input type="hidden" class="all-steps-input" name="{{ Dcat\Admin\Form\StepForm::ALL_STEPS }}" />
+<input type="hidden" name="_token" value="{{ csrf_token() }}">
+
+@php
+$lastStep = $step;
+@endphp
+
+<script>
+LA.ready(function () {
+    var form = $('#{{ $form->getFormId() }}'),
+        box = form.find('.la-step-box'),
+        stepInput = form.find('.current-step-input'),
+        allStepInput = form.find('.all-steps-input'),
+        smartWizard,
+        isSubmitting;
+
+    var submitBtn = $('<button style="margin-left: 10px"></button>')
+        .text('{{ trans('admin.submit') }}')
+        .addClass('btn btn-primary step-submit-btn disabled hide')
+        .on('click', function(){
+            var $t = $(this);
+
+            if ($t.hasClass('disabled') || isSubmitting) {
+               return false;
+            }
+
+            form.validator('validate');
+            if (form.find('.has-error').length > 0) {
+                return false;
+            }
+
+            allStepInput.val("1");
+            stepInput.val("");
+            $t.button('loading').removeClass('waves-effect');
+            isSubmitting = 1;
+
+            // 提交完整表单
+            submit(function (result) {
+                $t.button('reset');
+                isSubmitting = 0;
+
+                if (result) {
+                    smartWizard.next();
+
+                    toggle_btn();
+                }
+            });
+
+            return false;
+
+        });
+
+    smartWizard = box.smartWizard({
+        transitionEffect: 'fade',
+        useURLhash: false,
+        lang: {
+            next: '{{ trans('admin.next_step') }}',
+            previous: '{{ trans('admin.prev_step') }}'
+        },
+        toolbarSettings: {
+            toolbarPosition: 'bottom',
+            toolbarExtraButtons: [submitBtn,],
+            toolbarButtonPosition: 'left'
+        },
+        anchorSettings: {
+            enableAnchorOnDoneStep: false,
+        },
+    });
+
+    smartWizard = smartWizard.data('smartWizard');
+
+    var prev = box.find('.sw-btn-prev').click(function (e) {
+        e.preventDefault();
+        if (smartWizard.steps.index(this) !== smartWizard.current_index) {
+            smartWizard.prev();
+        }
+
+        toggle_btn();
+    });
+
+    var next = box.find('.sw-btn-next');
+    next.click(function (e) {
+        e.preventDefault();
+
+        if ($(this).hasClass('disabled') || isSubmitting) {
+            return false;
+        }
+
+        var stepForm = form.find('.sw-container [data-toggle="validator"]').eq(smartWizard.current_index);
+
+        stepForm.validator('validate');
+        if (stepForm.find('.has-error').length > 0) {
+            return false;
+        }
+
+        var self = this;
+        $(self).button('loading').removeClass('waves-effect');
+        isSubmitting = 1;
+
+        // 发送表单到服务器进行验证
+        stepInput.val(smartWizard.current_index);
+        submit(function (result) {
+            $(self).button('reset');
+            isSubmitting = 0;
+
+            if (result) {
+                // 表单验证成功
+                if (smartWizard.steps.index(self) !== smartWizard.current_index) {
+                    smartWizard.next();
+                }
+
+                toggle_btn();
+            }
+
+        });
+    });
+
+    function submit(after) {
+        LA.Form({
+            $form: form,
+            after: function (success, b, c, d) {
+                after(success, b, c, d);
+
+                if (success) {
+                    return false;
+                }
+
+            }
+        });
+    }
+
+    function toggle_btn() {
+        var last = {{ $lastStep->getIndex() }},
+            sbm = box.find('.step-submit-btn');
+
+        if (smartWizard.current_index == last) {
+            sbm.removeClass('disabled hide');
+            next.hide();
+            prev.show();
+        } else {
+            sbm.addClass('disabled hide');
+            if (smartWizard.current_index !== 0) {
+                prev.show();
+            } else {
+                prev.hide();
+            }
+
+            if (smartWizard.current_index != (last + 1)) {
+                next.show()
+            }
+        }
+
+        if (smartWizard.current_index == (last + 1)) {
+            box.find('.sw-btn-group').remove()
+        }
+
+    }
+
+    toggle_btn();
+});
+</script>
+

+ 99 - 3
src/Form.php

@@ -7,6 +7,7 @@ use Dcat\Admin\Form\Builder;
 use Dcat\Admin\Form\Condition;
 use Dcat\Admin\Form\Field;
 use Dcat\Admin\Form\Row;
+use Dcat\Admin\Form\StepForm;
 use Dcat\Admin\Form\Tab;
 use Dcat\Admin\Contracts\Repository;
 use Dcat\Admin\Traits\HasBuilderEvents;
@@ -15,6 +16,7 @@ use Illuminate\Contracts\Support\MessageProvider;
 use Illuminate\Contracts\Support\Renderable;
 use Illuminate\Http\Request;
 use Illuminate\Support\Arr;
+use Illuminate\Support\Collection;
 use Illuminate\Support\Fluent;
 use Illuminate\Support\MessageBag;
 use Illuminate\Support\Str;
@@ -321,10 +323,10 @@ class Form implements Renderable
     /**
      * Get specify field.
      *
-     * @param string $name
-     * @return Field
+     * @param string|null $name
+     * @return Field|Collection|Field[]|null
      */
-    public function field($name)
+    public function field($name = null)
     {
         return $this->builder->field($name);
     }
@@ -572,6 +574,13 @@ class Form implements Renderable
 
         $this->build();
 
+        $this->prepareStepFormFields($data);
+
+        // Validate step form.
+        if ($this->isStepFormValidationRequest()) {
+            return $this->validateStepForm($data);
+        }
+
         if (($response = $this->callSubmitted())) {
             return $response;
         }
@@ -614,6 +623,69 @@ class Form implements Renderable
         );
     }
 
+    /**
+     * @param array $data
+     * @return void
+     */
+    protected function prepareStepFormFields(array $data)
+    {
+        $steps = $this->builder->getSteps();
+
+        if (
+            empty($steps)
+            || (! isset($data[StepForm::ALL_STEPS]) && ! $this->isStepFormValidationRequest())
+        ) {
+            return;
+        }
+
+        if ($this->isStepFormValidationRequest()) {
+            $currentIndex = $data[StepForm::CURRENT_VALIDATION_STEP];
+
+            if (empty($steps[$currentIndex])) {
+                return;
+            }
+
+            foreach ($steps[$currentIndex]->field() as $field) {
+                $this->pushField($field);
+            }
+            return;
+        }
+
+        if (! empty($data[StepForm::ALL_STEPS])) {
+            foreach ($steps as $stepForm) {
+                foreach ($stepForm->field() as $field) {
+                    $this->pushField($field);
+                }
+            }
+        }
+    }
+
+    /**
+     * @return bool
+     */
+    protected function isStepFormValidationRequest()
+    {
+        $index = $this->request->get(StepForm::CURRENT_VALIDATION_STEP);
+
+        return $index !== '' && $index !== null;
+    }
+
+    /**
+     * Validate step form.
+     *
+     * @param array $data
+     * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
+     */
+    protected function  validateStepForm(array $data)
+    {
+        // Handle validation errors.
+        if ($validationMessages = $this->validationMessages($data)) {
+            return $this->makeValidationErrorsResponse($validationMessages);
+        }
+
+        return $this->ajaxResponse('Success');
+    }
+
     /**
      * Get ajax response.
      *
@@ -1371,6 +1443,30 @@ class Form implements Renderable
         return $this->rows;
     }
 
+    /**
+     * @param string $title
+     * @param Closure $callback
+     * @return $this
+     */
+    public function step(string $title, \Closure $callback)
+    {
+        $this->builder->step($title, $callback);
+
+        return $this;
+    }
+
+    /**
+     * @param $title
+     * @param Closure|null $callback
+     * @return $this
+     */
+    public function done($title, \Closure $callback = null)
+    {
+        $this->builder->done($title, $callback);
+
+        return $this;
+    }
+
     /**
      * Tools setting for form.
      *

+ 96 - 30
src/Form/Builder.php

@@ -2,6 +2,7 @@
 
 namespace Dcat\Admin\Form;
 
+use Closure;
 use Dcat\Admin\Admin;
 use Dcat\Admin\Form;
 use Dcat\Admin\Form\Field\Hidden;
@@ -21,6 +22,13 @@ class Builder
      */
     const PREVIOUS_URL_KEY = '_previous_';
 
+    /**
+     * Modes constants.
+     */
+    const MODE_EDIT = 'edit';
+    const MODE_CREATE = 'create';
+    const MODE_DELETE = 'delete';
+
     /**
      * @var mixed
      */
@@ -46,13 +54,6 @@ class Builder
      */
     protected $options = [];
 
-    /**
-     * Modes constants.
-     */
-    const MODE_EDIT = 'edit';
-    const MODE_CREATE = 'create';
-    const MODE_DELETE = 'delete';
-
     /**
      * Form action mode, could be create|view|edit.
      *
@@ -134,6 +135,16 @@ class Builder
      */
     protected $showFooter = true;
 
+    /**
+     * @var StepForm[]
+     */
+    protected $stepForms = [];
+
+    /**
+     * @var DoneStep
+     */
+    protected $doneStep;
+
     /**
      * Builder constructor.
      *
@@ -227,6 +238,49 @@ class Builder
         return $this->footer;
     }
 
+    /**
+     * @param string $title
+     * @param \Closure $callback
+     * @return void
+     */
+    public function step(string $title, \Closure $callback)
+    {
+        $this->view = 'admin::form.steps';
+
+        $form = new StepForm($this->form, count($this->stepForms), $title);
+
+        $this->stepForms[] = $form;
+
+        $callback($form);
+    }
+
+
+    /**
+     * @param string $title
+     * @param Closure|null $callback
+     * @return $this
+     */
+    public function done($title, \Closure $callback = null)
+    {
+        if ($title instanceof \Closure) {
+            $callback = $title;
+            $title    = trans('admin.done');
+        }
+
+        $this->doneStep = new DoneStep($this->form, $title, $callback);
+
+        return $this;
+    }
+
+
+    /**
+     * @return StepForm[]
+     */
+    public function getSteps()
+    {
+        return $this->stepForms;
+    }
+
     /**
      * Set the builder mode.
      *
@@ -425,12 +479,16 @@ class Builder
     /**
      * Get specify field.
      *
-     * @param string $name
+     * @param string|null $name
      *
-     * @return mixed
+     * @return Field|Collection|Field[]|null
      */
-    public function field($name)
+    public function field($name = null)
     {
+        if ($name === null) {
+            return $this->fields;
+        }
+
         return $this->fields->first(function (Field $field) use ($name) {
             return $field->column() == $name;
         });
@@ -722,10 +780,15 @@ class Builder
             $this->setupTabScript();
         }
 
-        if ($this->form->allowAjaxSubmit()) {
+        if ($this->form->allowAjaxSubmit() && empty($this->stepForms)) {
             $this->setupSubmitScript();
         }
 
+        if ($this->stepForms && !$this->doneStep) {
+            $this->done(function () {
+            });
+        }
+
         $open = $this->open(['class' => 'form-horizontal']);
 
         $data = [
@@ -734,6 +797,8 @@ class Builder
             'width'      => $this->width,
             'formId'     => $this->getFormId(),
             'showHeader' => $this->showHeader,
+            'steps'      => $this->stepForms,
+            'doneStep'   => $this->doneStep,
         ];
 
         $this->layout->prepend(
@@ -767,29 +832,30 @@ EOF;
     {
         Admin::script(
             <<<JS
-var f = $('#{$this->getFormId()}');
+(function () {
+    var f = $('#{$this->getFormId()}');
 
-f.find('[type="submit"]').click(function () {
-    var t = $(this);
+    f.find('[type="submit"]').click(function () {
+        var t = $(this);
     
-    LA.Form({
-        \$form: f,
-        before: function () {
-            f.validator('validate');
-    
-            if (f.find('.has-error').length > 0) {
-                return false;
+        LA.Form({
+            \$form: f,
+            before: function () {
+                f.validator('validate');
+        
+                if (f.find('.has-error').length > 0) {
+                    return false;
+                }
+                t.button('loading').removeClass('waves-effect');
+            },
+            after: function () {
+                t.button('reset');
             }
-            
-            t.button('loading');
-        },
-        after: function () {
-            t.button('reset');
-        }
+        });
+    
+        return false;
     });
-
-    return false;
-});
+})()
 JS
 
         );

+ 92 - 0
src/Form/DoneStep.php

@@ -0,0 +1,92 @@
+<?php
+
+namespace Dcat\Admin\Form;
+
+use Dcat\Admin\Form;
+use Dcat\Admin\Support\Helper;
+use Illuminate\Contracts\Support\Renderable;
+use Illuminate\Support\Str;
+
+class DoneStep
+{
+    /**
+     * @var Form
+     */
+    protected $form;
+
+    /**
+     * @var string
+     */
+    protected $title;
+
+    /**
+     * @var string
+     */
+    protected $contents;
+
+    /**
+     * @var \Closure
+     */
+    protected $builder;
+
+    /**
+     * @var string
+     */
+    protected $elementId;
+
+    public function __construct(Form $form, $title, \Closure $callback)
+    {
+        $this->form      = $form;
+        $this->builder   = $callback;
+        $this->elementId = 'done-step-'.Str::random();
+
+        $this->title($title);
+    }
+
+    /**
+     * @return Form
+     */
+    public function form()
+    {
+        return $this->form;
+    }
+
+    /**
+     * @param string $title
+     * @return void|string
+     */
+    public function title($title = null)
+    {
+        if ($title === null) {
+            return $this->title;
+        }
+
+        $this->title = value($title);
+    }
+
+    /**
+     * @param string|\Closure|Renderable $contents
+     * @return void
+     */
+    public function contents($contents)
+    {
+        $this->contents = $contents;
+    }
+
+    /**
+     * @return string
+     */
+    public function getElementId(): string
+    {
+        return $this->elementId;
+    }
+
+    /**
+     * @return string
+     */
+    public function build()
+    {
+        call_user_func($this->builder, $this);
+    }
+
+}

+ 129 - 0
src/Form/StepForm.php

@@ -0,0 +1,129 @@
+<?php
+
+namespace Dcat\Admin\Form;
+
+use Dcat\Admin\Admin;
+use Dcat\Admin\Form;
+use Dcat\Admin\Widgets\Form as WidgetForm;
+
+class StepForm extends WidgetForm
+{
+    const CURRENT_VALIDATION_STEP = 'CURRENT_VALIDATION_STEP';
+    const ALL_STEPS = 'ALL_STEPS';
+
+    /**
+     * @var string
+     */
+    protected $view = 'admin::form.step-form';
+
+    /**
+     * @var array
+     */
+    protected $buttons = [];
+
+    /**
+     * @var Form
+     */
+    protected $form;
+
+    /**
+     * @var int
+     */
+    protected $index;
+
+    /**
+     * @var string
+     */
+    protected $title;
+
+    /**
+     * @var string
+     */
+    protected $description;
+
+    /**
+     * StepForm constructor.
+     *
+     * @param Form $form
+     * @param int $index
+     * @param string $title
+     */
+    public function __construct(Form $form, int $index = 0, string $title = null)
+    {
+        $this->form  = $form;
+        $this->index = $index;
+
+        $this->title($title);
+    }
+
+    /**
+     * @param string|\Closure $title
+     * @return $this
+     */
+    public function title($title)
+    {
+        $this->title = value($title);
+
+        return $this;
+    }
+
+    /**
+     * @param string|\Closure $content
+     * @return $this
+     */
+    public function description($content)
+    {
+        $this->description = value($content);
+
+        return $this;
+    }
+
+    /**
+     * @return int
+     */
+    public function getIndex()
+    {
+        return $this->index;
+    }
+
+    /**
+     * @return string
+     */
+    public function getTitle()
+    {
+        return $this->title;
+    }
+
+    /**
+     * @return string
+     */
+    public function getDescription()
+    {
+        return $this->description;
+    }
+
+    /**
+     * @return string
+     */
+    protected function open()
+    {
+        Admin::js('vendor/dcat-admin/SmartWizard/dist/js/jquery.smartWizard.min.js');
+        Admin::css('vendor/dcat-admin/SmartWizard/dist/css/step.min.css');
+
+        $this->setHtmlAttribute('data-toggle', 'validator');
+        $this->setHtmlAttribute('role', 'form');
+
+        return <<<HTML
+<div {$this->formatHtmlAttributes()}>
+HTML;
+    }
+
+    /**
+     * @return string
+     */
+    protected function close()
+    {
+        return '</div>';
+    }
+
+}

+ 38 - 25
src/Widgets/Form.php

@@ -79,6 +79,11 @@ class Form implements Renderable
         __call as macroCall;
     }
 
+    /**
+     * @var string
+     */
+    protected $view = 'admin::widgets.form';
+
     /**
      * @var Field[]
      */
@@ -253,10 +258,14 @@ class Form implements Renderable
      * Get specify field.
      *
      * @param string $name
-     * @return Field|null
+     * @return Field|null|Field[]
      */
-    public function field($name)
+    public function field($name = null)
     {
+        if ($name === null) {
+            return $this->fields;
+        }
+
         foreach ($this->fields as $field) {
             if ($field->column() === $name) {
                 return $field;
@@ -498,29 +507,31 @@ HTML;
     {
         Admin::script(
             <<<JS
-var f = $('#{$this->getFormId()}');
-
-f.find('[type="submit"]').click(function () {
-    var t = $(this);
-    
-    LA.Form({
-        \$form: f,
-         before: function () {
-            f.validator('validate');
-    
-            if (f.find('.has-error').length > 0) {
-                return false;
+(function () {
+    var f = $('#{$this->getFormId()}');
+
+    f.find('[type="submit"]').click(function () {
+        var t = $(this);
+        
+        LA.Form({
+            \$form: f,
+             before: function () {
+                f.validator('validate');
+        
+                if (f.find('.has-error').length > 0) {
+                    return false;
+                }
+                
+                t.button('loading');
+            },
+            after: function () {
+                t.button('reset');
             }
-            
-            t.button('loading');
-        },
-        after: function () {
-            t.button('reset');
-        }
+        });
+    
+        return false;
     });
-
-    return false;
-});
+})()
 JS
 
         );
@@ -533,9 +544,11 @@ JS
      */
     public function render()
     {
-        $this->useAjaxSubmit && $this->setupSubmitScript();
+        if ($this->allowAjaxSubmit()) {
+            $this->setupSubmitScript();
+        }
 
-        return view('admin::widgets.form', $this->getVariables())->render();
+        return view($this->view, $this->getVariables())->render();
     }
 
     /**

Some files were not shown because too many files changed in this diff