{"_id":"551c12c781b8563500fd998e","parentDoc":null,"project":"54d53c7b23010a0d001aca0c","user":"54cfa8e1a8a4fd0d00b7fd1d","__v":55,"category":{"_id":"54d5635632d98b0d00384afd","project":"54d53c7b23010a0d001aca0c","version":"54d5635532d98b0d00384afb","__v":7,"pages":["54d5635632d98b0d00384b03","54d5635632d98b0d00384b04","54d5635632d98b0d00384b05","54d5635632d98b0d00384b06","54d5635632d98b0d00384b07","54d5635632d98b0d00384b08","54d5635632d98b0d00384b09","54d5635632d98b0d00384b0a","54d5635632d98b0d00384b0b","54d5635632d98b0d00384b0c","54d5635632d98b0d00384b0d","54d5635632d98b0d00384b0e","54d5635632d98b0d00384b0f","54e2254d22de1c230094b156","54e2255622de1c230094b158","54e23b349d045721004cbc26","54e65455d8873117005c773f","54e6b5c0ba1a980d00e3ecb0","551c12c781b8563500fd998e"],"sync":{"url":"","isSync":false},"reference":false,"createdAt":"2015-02-06T23:43:39.709Z","from_sync":false,"order":7,"slug":"plugin-base-classes","title":"Plugin Base Classes"},"version":{"_id":"54d5635532d98b0d00384afb","project":"54d53c7b23010a0d001aca0c","__v":10,"forked_from":"54d53c7c23010a0d001aca0f","createdAt":"2015-02-07T00:59:01.934Z","releaseDate":"2015-02-07T00:59:01.934Z","categories":["54d5635632d98b0d00384afc","54d5635632d98b0d00384afd","54d5635632d98b0d00384afe","54d5635632d98b0d00384aff","54d5635632d98b0d00384b00","54d5635632d98b0d00384b01","54d5635632d98b0d00384b02","54d652097e05890d006f153e","54dd1315ca1e5219007e9daa","54e21e2b22de1c230094b147","54e68e62a43fe13500db3879","54fa1d3fe7a0ba2f00306309","551c453a23a1ee190034d19a","551df586e52a0b23000c62b6","551f39be6886f8230055f02a","55a6720751457325000e4d97"],"is_deprecated":false,"is_hidden":false,"is_beta":true,"is_stable":true,"codename":"","version_clean":"0.1.0","version":"0.1"},"updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-04-01T15:46:15.149Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"auth":"required","params":[],"url":""},"isReference":false,"order":7,"body":"A Wizard is a dialog that consists of multiple pages and guides a user through a multi-step process. Wizards usually involve getting input from the user and then performing some action based on those inputs. \n[block:callout]\n{\n  \"type\": \"warning\",\n  \"title\": \"Use Wizards Wisely\",\n  \"body\": \"In the past, especially when they became popular, wizards were used for everything - even things that could otherwise be simple dialog or wouldn't need a UI at all. Therefore a word of caution: Use wizards wisely. Make sure you really need to guide a user through a blocking process. If you do, then wizards can be very powerful.\"\n}\n[/block]\n# Creating a Wizard\n\nA basic wizard with a single page and a close button.\n\n```\nvar plugin = new Wizard(\"Your Name\", main.consumes, {\n    title: \"The title of the dialog\",\n    allowClose: true,\n    height: 200\n});\n\nplugin.on(\"draw\", function(){\n    var firstPage = new WizardPage({ name: \"first\" }, plugin);\n    plugin.startPage = firstPage;\n});\n\nplugin.show();\n```\n\nLooks like this.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/qETNvJQQkWVffp5PseF6_2015-04-01_0923.png\",\n        \"2015-04-01_0923.png\",\n        \"1570\",\n        \"448\",\n        \"#7c7c7c\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"title\": \"Wizard inherits from Dialog()\",\n  \"body\": \"The interface from `Dialog()` is available to you as well. That means that you can tweak the button bar of your wizard and use any of the other APIs that `Dialog()` offers.\"\n}\n[/block]\n# Wizard Properties\n\nThe following properties can be passed to the `Wizard()` constructor.\n[block:html]\n{\n  \"html\": \"<table>\\n<tr><th>allowClose</th><td>Boolean specifying whether the close button is shown.</td></tr>\\n<tr><th>class</th><td>The css class for the wizard dialog.</td></tr>\\n<tr><th>height</th><td>The height of the wizard dialog.</td></tr>\\n<tr><th>width</th><td>The width of the wizard dialog.</td></tr>\\n<tr><th>resizable</th><td>Whether the wizard dialog is resizable.</td></tr>\\n<tr><th>title</th><td>The title of the wizard dialog.</td></tr>\\n<tr><th>modal</th><td>Whether the dialog is modal. Defaults to true.</td></tr>\\n</table>\"\n}\n[/block]\n# Adding Wizard Pages\n\nA wizard lets a user walk through different wizard pages via next and previous buttons. Optionally the wizard can show the user finish and cancel buttons when appropriate. The wizard api lets you decide the sequence of the pages shown. It keeps a history of the shown pages in order for the previous button to provide a consistent history. Of course even this can be influence via events.\n\nLets start by creating four pages. It is common practice to create the wizard pages in the `draw` event of the wizard. This way they are created just in time.\n```\nplugin.on(\"draw\", function(){\n    var intro = new WizardPage({ name: \"intro\" }, plugin);\n    var input = new WizardPage({ name: \"input\" }, plugin);\n    var action = new WizardPage({ name: \"action\" }, plugin);\n    var last = new WizardPage({ name: \"last\" }, plugin);\n    \n    plugin.startPage = intro;\n});\n```\n\nSettings the `startPage` property tells the wizard to show that page (in this case `intro`) when the wizard is first shown.\n\n# Adding your own contents\n\nThe easiest way to populate a dialog is by adding custom html and css. The following example loads css from wizard.css and adds a div element to the body of the first page.\n\n```\nplugin.on(\"draw\", function(){\n    // Insert css\n    ui.insertCss(require(\"text!./wizard.css\"), options.staticPrefix, plugin);\n\n    var intro = new WizardPage({ name: \"intro\" }, plugin);\n    intro.on(\"draw\", function(e){\n        // Insert HTML from a file\n        ui.insertHtml(e.html, require(\"text!./intro.html\"), intro);\n    });\n\n    var input = new WizardPage({ name: \"input\" }, plugin);\n    var action = new WizardPage({ name: \"action\" }, plugin);\n    var last = new WizardPage({ name: \"last\" }, plugin);\n    \n    plugin.startPage = intro;\n});\n```\n\nIn the same way you can populate the other pages with contents as well. Make sure to check out the [Ace Widgets](doc:ace-tree) and [Form](doc:form) as they make for a great combination with the wizard pages.\n\n# Managing State during the Page's Life Time.\n\nSimilar to the [Dialog plugin](doc:dialog-plugin) use the `show` event to manage state of the components in the page.\n\nThis example adds a list widget to a wizard page. Each time the page is shown the contents of the list of recalculated.\n```\nvar input = new WizardPage({ name: \"input\" }, plugin);\n\nvar list;\ninput.on(\"draw\", function(e){\n    list = new List({ container: e.html }, plugin);\n});\ninput.on(\"show\", function(){\n    list.setRoot(calculateItems());\n});\n```\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/8DeHVAorT0G6BtBQAzgQ_2015-04-01_1051.png\",\n        \"2015-04-01_1051.png\",\n        \"1570\",\n        \"454\",\n        \"#64acfc\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n# Wizard Buttons\n\nThe next and previous buttons are automatically turned on when a page is activated. You can use the `next` event as described in the next section to alter the visible state of the 4 buttons that the wizard has.\n\nThe code in the example below would show all buttons except next.\n```\nplugin.showNext = false;\nplugin.showPrevious = true;\nplugin.showFinish = true;\nplugin.showCancel = true;\n```\n\nWhich looks like this.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/IHcZ4RAFTtmZZTif6GVc_2015-04-01_1058.png\",\n        \"2015-04-01_1058.png\",\n        \"1570\",\n        \"454\",\n        \"#64acfc\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n# Wizard Interactions\n\nUse the `next`, `previous` and `cancel` events to breathe life into your wizard. You often want to determine the next page based on choices a user has made for instance. The following sections tell you how to do this.\n\n*We'll assume there are four pages; `intro`, `input`, `action` and `last`*\n\n## Next Event\n\nThe `next` event is fired when a user clicks on the next button. You determine which page to present next to the user by returning a reference to that page in the event handler. \n\nThis is what the `next` event handler might look like for our wizard. After the `intro` pag the user goes on to the `input` page. There the user can either click a checkbox or not. If the user checks the checkbox and clicks next they go to the `action` page. Otherwise they are shown the `last` page. After the `action` page, the `last` page is shown as well.\n\n```\nplugin.on(\"next\", function(e){\n    var page = e.activePage;\n    \n    // Intro -> Input\n    if (page.name == \"intro\") {\n        return input;\n    }\n    // Input -> Action (if checked) \n    else if (page.name == \"input\") {\n        if (page.container.querySelector(\".checkbox\").checked) {\n            plugin.showPrevious = false; // We don't allow to go back from here\n            plugin.showCancel = true; // Allow the user to cancel the process\n            return action;\n        }\n    }\n    \n    // In all other cases, show the last page\n    plugin.showFinish = true;\n    plugin.showPrevious = false;\n    plugin.showNext = false;\n    return last;\n});\n```\n\n## Previous Event\n\nThe previous event is called when a user uses the previous button to navigate to a page.\n\n```\nplugin.on(\"previous\", function(e){\n   var page = e.activePage;\n   if (page.name == \"intro\")\n       plugin.showFinish = true;\n});\n```\n\n## Cancel Event\n\nThe cancel event is called when a user clicks the cancel button.\n\n```\nplugin.on(\"cancel\", function(e){\n   abort();\n   plugin.gotoPage(last);\n});\n```\n\n# Navigating\n\nYou can programmatically trigger the actions that correspond to the buttons. \n```\nplugin.next()\nplugin.previous()\nplugin.cancel()\nplugin.finish()\n```\n\nIn addition you can display any page automatically. \n```\nplugin.gotoPage(intro);\n```\nThe page will be added to the history when using `gotoPage()`.\n\nFetch a reference to the active page like this.\n```\nvar page = plugin.activePage;\n```\n\n# Full Example\n\n```\ndefine(function(require, exports, module) {\n    main.consumes = [\"Wizard\", \"WizardPage\", \"ui\"];\n    main.provides = [\"yourplugin\"];\n    return main;\n\n    function main(options, imports, register) {\n        var Wizard = imports.Wizard;\n        var WizardPage = imports.WizardPage;\n        var ui = imports.ui;\n        \n        /***** Initialization *****/\n        \n        var plugin = new Wizard(\"Your Name\", main.consumes, {\n            title: \"The title of the dialog\",\n            allowClose: true,\n            height: 400\n        });\n        \n        plugin.on(\"draw\", function(){\n            // Insert css\n            ui.insertCss(require(\"text!./wizard.css\"), options.staticPrefix, plugin);\n        \n            var intro = new WizardPage({ name: \"intro\" }, plugin);\n            intro.on(\"draw\", function(e){\n                // Insert HTML from a file\n                ui.insertHtml(e.html, require(\"text!./intro.html\"), intro);\n            });\n        \n            var input = new WizardPage({ name: \"input\" }, plugin);\n            input.on(\"draw\", function(e){\n                // Insert HTML from a file\n                ui.insertHtml(e.html, require(\"text!./input.html\"), input);\n            });\n            \n            var action = new WizardPage({ name: \"action\" }, plugin);\n            action.on(\"draw\", function(e){\n                // Insert HTML from a file\n                ui.insertHtml(e.html, require(\"text!./action.html\"), action);\n            });\n            \n            var last = new WizardPage({ name: \"last\" }, plugin);\n            last.on(\"draw\", function(e){\n                // Insert HTML from a file\n                ui.insertHtml(e.html, require(\"text!./last.html\"), last);\n            });\n            \n            plugin.on(\"next\", function(e){\n                var page = e.activePage;\n                \n                // Intro -> Input\n                if (page.name == \"intro\") {\n                    return input;\n                }\n                // Input -> Action (if checked) \n                else if (page.name == \"input\") {\n                    if (page.container.querySelector(\".checkbox\").checked) {\n                        plugin.showPrevious = false; // We don't allow to go back from here\n                        plugin.showCancel = true; // Allow the user to cancel the process\n                        start();\n                        return action;\n                    }\n                }\n                \n                // In all other cases, show the last page\n                plugin.showFinish = true;\n                plugin.showPrevious = false;\n                plugin.showNext = false;\n                return last;\n            }, plugin);\n            \n            plugin.on(\"cancel\", function(e){\n               abort();\n               plugin.gotoPage(last);\n            }, plugin);\n            \n            plugin.startPage = intro;\n        });\n        \n        /***** Functions *****/\n        \n        function start(){\n            \n        }\n        \n        function abort(){\n            \n        }\n        \n        /***** Lifecycle *****/\n        \n        plugin.on(\"load\", function(){\n            \n        });\n        \n        plugin.on(\"unload\", function(){\n            \n        });\n        \n        /***** Register and define API *****/\n        \n        /**\n         * Your wizard description\n         **/\n        plugin.freezePublicAPI({\n            \n        });\n        \n        register(null, {\n            \"yourplugin\": plugin\n        });\n    }\n});\n```","excerpt":"","slug":"wizard-plugin","type":"basic","title":"Wizard Plugin"}
A Wizard is a dialog that consists of multiple pages and guides a user through a multi-step process. Wizards usually involve getting input from the user and then performing some action based on those inputs. [block:callout] { "type": "warning", "title": "Use Wizards Wisely", "body": "In the past, especially when they became popular, wizards were used for everything - even things that could otherwise be simple dialog or wouldn't need a UI at all. Therefore a word of caution: Use wizards wisely. Make sure you really need to guide a user through a blocking process. If you do, then wizards can be very powerful." } [/block] # Creating a Wizard A basic wizard with a single page and a close button. ``` var plugin = new Wizard("Your Name", main.consumes, { title: "The title of the dialog", allowClose: true, height: 200 }); plugin.on("draw", function(){ var firstPage = new WizardPage({ name: "first" }, plugin); plugin.startPage = firstPage; }); plugin.show(); ``` Looks like this. [block:image] { "images": [ { "image": [ "https://files.readme.io/qETNvJQQkWVffp5PseF6_2015-04-01_0923.png", "2015-04-01_0923.png", "1570", "448", "#7c7c7c", "" ] } ] } [/block] [block:callout] { "type": "warning", "title": "Wizard inherits from Dialog()", "body": "The interface from `Dialog()` is available to you as well. That means that you can tweak the button bar of your wizard and use any of the other APIs that `Dialog()` offers." } [/block] # Wizard Properties The following properties can be passed to the `Wizard()` constructor. [block:html] { "html": "<table>\n<tr><th>allowClose</th><td>Boolean specifying whether the close button is shown.</td></tr>\n<tr><th>class</th><td>The css class for the wizard dialog.</td></tr>\n<tr><th>height</th><td>The height of the wizard dialog.</td></tr>\n<tr><th>width</th><td>The width of the wizard dialog.</td></tr>\n<tr><th>resizable</th><td>Whether the wizard dialog is resizable.</td></tr>\n<tr><th>title</th><td>The title of the wizard dialog.</td></tr>\n<tr><th>modal</th><td>Whether the dialog is modal. Defaults to true.</td></tr>\n</table>" } [/block] # Adding Wizard Pages A wizard lets a user walk through different wizard pages via next and previous buttons. Optionally the wizard can show the user finish and cancel buttons when appropriate. The wizard api lets you decide the sequence of the pages shown. It keeps a history of the shown pages in order for the previous button to provide a consistent history. Of course even this can be influence via events. Lets start by creating four pages. It is common practice to create the wizard pages in the `draw` event of the wizard. This way they are created just in time. ``` plugin.on("draw", function(){ var intro = new WizardPage({ name: "intro" }, plugin); var input = new WizardPage({ name: "input" }, plugin); var action = new WizardPage({ name: "action" }, plugin); var last = new WizardPage({ name: "last" }, plugin); plugin.startPage = intro; }); ``` Settings the `startPage` property tells the wizard to show that page (in this case `intro`) when the wizard is first shown. # Adding your own contents The easiest way to populate a dialog is by adding custom html and css. The following example loads css from wizard.css and adds a div element to the body of the first page. ``` plugin.on("draw", function(){ // Insert css ui.insertCss(require("text!./wizard.css"), options.staticPrefix, plugin); var intro = new WizardPage({ name: "intro" }, plugin); intro.on("draw", function(e){ // Insert HTML from a file ui.insertHtml(e.html, require("text!./intro.html"), intro); }); var input = new WizardPage({ name: "input" }, plugin); var action = new WizardPage({ name: "action" }, plugin); var last = new WizardPage({ name: "last" }, plugin); plugin.startPage = intro; }); ``` In the same way you can populate the other pages with contents as well. Make sure to check out the [Ace Widgets](doc:ace-tree) and [Form](doc:form) as they make for a great combination with the wizard pages. # Managing State during the Page's Life Time. Similar to the [Dialog plugin](doc:dialog-plugin) use the `show` event to manage state of the components in the page. This example adds a list widget to a wizard page. Each time the page is shown the contents of the list of recalculated. ``` var input = new WizardPage({ name: "input" }, plugin); var list; input.on("draw", function(e){ list = new List({ container: e.html }, plugin); }); input.on("show", function(){ list.setRoot(calculateItems()); }); ``` [block:image] { "images": [ { "image": [ "https://files.readme.io/8DeHVAorT0G6BtBQAzgQ_2015-04-01_1051.png", "2015-04-01_1051.png", "1570", "454", "#64acfc", "" ] } ] } [/block] # Wizard Buttons The next and previous buttons are automatically turned on when a page is activated. You can use the `next` event as described in the next section to alter the visible state of the 4 buttons that the wizard has. The code in the example below would show all buttons except next. ``` plugin.showNext = false; plugin.showPrevious = true; plugin.showFinish = true; plugin.showCancel = true; ``` Which looks like this. [block:image] { "images": [ { "image": [ "https://files.readme.io/IHcZ4RAFTtmZZTif6GVc_2015-04-01_1058.png", "2015-04-01_1058.png", "1570", "454", "#64acfc", "" ] } ] } [/block] # Wizard Interactions Use the `next`, `previous` and `cancel` events to breathe life into your wizard. You often want to determine the next page based on choices a user has made for instance. The following sections tell you how to do this. *We'll assume there are four pages; `intro`, `input`, `action` and `last`* ## Next Event The `next` event is fired when a user clicks on the next button. You determine which page to present next to the user by returning a reference to that page in the event handler. This is what the `next` event handler might look like for our wizard. After the `intro` pag the user goes on to the `input` page. There the user can either click a checkbox or not. If the user checks the checkbox and clicks next they go to the `action` page. Otherwise they are shown the `last` page. After the `action` page, the `last` page is shown as well. ``` plugin.on("next", function(e){ var page = e.activePage; // Intro -> Input if (page.name == "intro") { return input; } // Input -> Action (if checked) else if (page.name == "input") { if (page.container.querySelector(".checkbox").checked) { plugin.showPrevious = false; // We don't allow to go back from here plugin.showCancel = true; // Allow the user to cancel the process return action; } } // In all other cases, show the last page plugin.showFinish = true; plugin.showPrevious = false; plugin.showNext = false; return last; }); ``` ## Previous Event The previous event is called when a user uses the previous button to navigate to a page. ``` plugin.on("previous", function(e){ var page = e.activePage; if (page.name == "intro") plugin.showFinish = true; }); ``` ## Cancel Event The cancel event is called when a user clicks the cancel button. ``` plugin.on("cancel", function(e){ abort(); plugin.gotoPage(last); }); ``` # Navigating You can programmatically trigger the actions that correspond to the buttons. ``` plugin.next() plugin.previous() plugin.cancel() plugin.finish() ``` In addition you can display any page automatically. ``` plugin.gotoPage(intro); ``` The page will be added to the history when using `gotoPage()`. Fetch a reference to the active page like this. ``` var page = plugin.activePage; ``` # Full Example ``` define(function(require, exports, module) { main.consumes = ["Wizard", "WizardPage", "ui"]; main.provides = ["yourplugin"]; return main; function main(options, imports, register) { var Wizard = imports.Wizard; var WizardPage = imports.WizardPage; var ui = imports.ui; /***** Initialization *****/ var plugin = new Wizard("Your Name", main.consumes, { title: "The title of the dialog", allowClose: true, height: 400 }); plugin.on("draw", function(){ // Insert css ui.insertCss(require("text!./wizard.css"), options.staticPrefix, plugin); var intro = new WizardPage({ name: "intro" }, plugin); intro.on("draw", function(e){ // Insert HTML from a file ui.insertHtml(e.html, require("text!./intro.html"), intro); }); var input = new WizardPage({ name: "input" }, plugin); input.on("draw", function(e){ // Insert HTML from a file ui.insertHtml(e.html, require("text!./input.html"), input); }); var action = new WizardPage({ name: "action" }, plugin); action.on("draw", function(e){ // Insert HTML from a file ui.insertHtml(e.html, require("text!./action.html"), action); }); var last = new WizardPage({ name: "last" }, plugin); last.on("draw", function(e){ // Insert HTML from a file ui.insertHtml(e.html, require("text!./last.html"), last); }); plugin.on("next", function(e){ var page = e.activePage; // Intro -> Input if (page.name == "intro") { return input; } // Input -> Action (if checked) else if (page.name == "input") { if (page.container.querySelector(".checkbox").checked) { plugin.showPrevious = false; // We don't allow to go back from here plugin.showCancel = true; // Allow the user to cancel the process start(); return action; } } // In all other cases, show the last page plugin.showFinish = true; plugin.showPrevious = false; plugin.showNext = false; return last; }, plugin); plugin.on("cancel", function(e){ abort(); plugin.gotoPage(last); }, plugin); plugin.startPage = intro; }); /***** Functions *****/ function start(){ } function abort(){ } /***** Lifecycle *****/ plugin.on("load", function(){ }); plugin.on("unload", function(){ }); /***** Register and define API *****/ /** * Your wizard description **/ plugin.freezePublicAPI({ }); register(null, { "yourplugin": plugin }); } }); ```