|
|
(20 intermediate revisions by one other user not shown) |
Line 1: |
Line 1: |
| <div class="title">Wizard/Tour framework</div>
| | The content on this page has moved to https://documentation.open-xchange.com/latest/ui/components/guided-tours.html |
|
| |
|
| App Suite UI provides a simple but flexible framework to implement wizards and guided tours. The essence of both a wizard and a tour is a set of steps the end-user walks through. Usually a step is a smaller modal popup.
| | Note: Open-Xchange is in the process of migrating all its technical documentation to a new and improved documentation system (documentation.open-xchange.com). Please note as the migration takes place more information will be available on the new system and less on this system. Thank you for your understanding during this period of transition. |
| | |
| === Simple example ===
| |
| The starting point is the "Wizard" (or "Tour") class defined in io.ox/core/tk/wizard.js. A simple example:
| |
| <pre class="language-javascript">
| |
| require(['io.ox/core/tk/wizard'], function (Tour) {
| |
| new Tour()
| |
| .step()
| |
| .title('Welcome')
| |
| .content('Lorem ipsum dolor sit amet, consetetur sadipscing elitr')
| |
| .end()
| |
| .start();
| |
| });
| |
| </pre>
| |
| The function '''step()''' adds a new step. Each step is separate '''Backbone view''' instance (DisposableView to be more precise). The following function calls '''title()''' and '''content()''' both work on that view; '''end()''' just returns to the tour (same idea as in jQuery's end()). This allows long definition chains. A more complex example that puts a spotlight on an element:
| |
| <pre class="language-javascript">
| |
| require(['io.ox/core/tk/wizard'], function (Tour) {
| |
| new Tour()
| |
| .step()
| |
| .title('Welcome')
| |
| .content('Lorem ipsum dolor sit amet, consetetur sadipscing elitr')
| |
| .mandatory()
| |
| .end()
| |
| .step()
| |
| .title('Step 2')
| |
| .content('Lorem ipsum dolor sit amet, consetetur sadipscing elitr')
| |
| .spotlight('#io-ox-topbar')
| |
| .pointAt('.launchers-secondary')
| |
| .mandatory()
| |
| .beforeShow(function () {
| |
| // do anything you want to customize the step
| |
| console.log('before show', this);
| |
| })
| |
| .end()
| |
| .start();
| |
| });
| |
| </pre>
| |
| | |
| === API ===
| |
| | |
| {|
| |
| |-
| |
| ! Function !! Description
| |
| |-
| |
| !colspan="2"|Wizard/Tour
| |
| |-
| |
| | step()
| |
| | Add a new wizard/tour step.
| |
| |-
| |
| | end()
| |
| | Go back to parent element, i.e. the Wizard or the Tour.
| |
| |-
| |
| | start()
| |
| | Start the wizard/tour.
| |
| |-
| |
| !colspan="2"|Step
| |
| |-
| |
| | title()
| |
| | Append content to the popup title. Handed over to jQuery's append; can be String, DOM element, jQuery set, a function.
| |
| |-
| |
| | content()
| |
| | Append content the popup body. Handed over to jQuery's append; can be String, DOM element, jQuery set, a function.
| |
| |-
| |
| | footer()
| |
| | Append content to the popup footer. Handed over to jQuery's append; can be String, DOM element, jQuery set, a function.
| |
| |-
| |
| | mandatory()
| |
| | Makes a step mandatory. The "close" icon gets removed; escape key no longer works.
| |
| |-
| |
| | toggleNext(state)
| |
| | Enables (true) or disables (false) the "Next" button. All buttons are enabled by default. The first step doesn't have a back button, of course. And the last step offers a "Done" button instead of the "Next" button.
| |
| |-
| |
| | toggleBack(state)
| |
| | Enables (true) or disables (false) the "Back" button.
| |
| |-
| |
| | isFirst()
| |
| | Returns true if the current step is the first one.
| |
| |-
| |
| | isLast()
| |
| | Returns true if the current step is the last one.
| |
| |-
| |
| | pointAt(selector)
| |
| | Affects the dialog location (alignment happens automatically).
| |
| |-
| |
| | spotlight(selector)
| |
| | Sets a spotlight on a given element.
| |
| |-
| |
| | modal([state])
| |
| | Shows a darker backdrop. Default is true.
| |
| |-
| |
| | waitFor(selector)
| |
| | The step waits for a certain element to exist before showing the popup.
| |
| |-
| |
| | navigateTo(id, [options])
| |
| | The step launches given app (id) before showing the popup. "options" are optional; handed over to ox.launch().
| |
| |-
| |
| | scrollIntoView(selector)
| |
| | This element will be scrolled into view before the popup is shown.
| |
| |-
| |
| | beforeShow(callback)
| |
| | Registers for the "before:show" event using once(). The callback's context is the step, i.e. "this" is a backbone view.
| |
| |}
| |
| | |
| === Events ===
| |
| | |
| {|
| |
| |-
| |
| ! Event name !! Description
| |
| |-
| |
| !colspan="2"|Wizard/Tour
| |
| |-
| |
| | step:next
| |
| | Triggered when moving ahead.
| |
| |-
| |
| | step:back
| |
| | Triggered when moving back.
| |
| |-
| |
| | step:close
| |
| | Triggered when closing the wizard/tour.
| |
| |-
| |
| | step:done
| |
| | Triggered when finishing the wizard/tour.
| |
| |-
| |
| | before:start
| |
| | Triggered before starting the wizard or the tour.
| |
| |-
| |
| | start
| |
| | Triggered when the wizard or the tour has been started
| |
| |-
| |
| | before:stop
| |
| | Triggered before closing the wizard or the tour.
| |
| |-
| |
| | stop
| |
| | Triggered when the wizard or the tour has been closed
| |
| |-
| |
| !colspan="2"|Step
| |
| |-
| |
| | next / back
| |
| | Same as step:next or step:back (see above)
| |
| |-
| |
| | close / done
| |
| | Same as step:close or step:done (see above)
| |
| |-
| |
| | before:show
| |
| | Triggered before showing the step
| |
| |-
| |
| | show
| |
| | Triggered when the step is visible
| |
| |-
| |
| | before:hide
| |
| | Triggered before hiding the step
| |
| |-
| |
| | hide
| |
| | Triggered when the step is hidden
| |
| |}
| |
| | |
| === Using the registry ===
| |
| A tour only works once, i.e. its steps get disposed once the tour stops. This is intended behavior in order to avoid side-effects and memory leaks. If you want to run a tour twice you have to redefine it. The registry simplifies that:
| |
| <pre class="language-javascript">
| |
| require(['io.ox/core/tk/wizard'], function (Tour) {
| |
| | |
| // you can store any data you want; only 'id' is mandatory
| |
| Tour.registry.add({ id: 'test', title: 'Test', type: 'tour' }, function () {
| |
| | |
| new Tour()
| |
| .step()
| |
| .title('Welcome')
| |
| .content('Lorem ipsum dolor sit amet, consetetur sadipscing elitr.')
| |
| .spotlight('.classic-toolbar')
| |
| .end()
| |
| .start();
| |
| });
| |
| | |
| // run a tour
| |
| Tour.registry.run('test');
| |
| });
| |
| </pre>
| |
| | |
| The registry also helps at listing existing tours:
| |
| <pre class="language-javascript">
| |
| require(['io.ox/core/tk/wizard'], function (Tour) {
| |
| // get all items
| |
| console.log(Tour.registry.list());
| |
| // just get type=tour
| |
| console.log(Tour.registry.list('tour'));
| |
| // which is a shortcut for
| |
| console.log(Tour.registry.collection.where({ type: 'tour' }));
| |
| });
| |
| </pre>
| |
| | |
| === Complex example ===
| |
| <pre class="language-javascript">
| |
| void require(['io.ox/core/tk/wizard'], function (Tour) {
| |
| | |
| Tour.registry.add({ id: 'test', title: 'Test', type: 'tour' }, function () {
| |
| | |
| new Tour()
| |
| .step()
| |
| .title('Welcome')
| |
| .content('Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.')
| |
| .spotlight('.classic-toolbar')
| |
| .end()
| |
| .step()
| |
| .title('Top-bar')
| |
| .content('Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.')
| |
| .spotlight('#io-ox-topbar')
| |
| .pointAt('.launchers-secondary')
| |
| .end()
| |
| .step()
| |
| .title('Search')
| |
| .content('Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.')
| |
| .spotlight('.io-ox-find')
| |
| .end()
| |
| .step()
| |
| .title('Something at the bottom')
| |
| .content('Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.')
| |
| .spotlight('.generic-toolbar.bottom')
| |
| .end()
| |
| .step()
| |
| .title('Top toolbar')
| |
| .content('Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.')
| |
| .spotlight('.toolbar.generic-toolbar.top')
| |
| .end()
| |
| .step()
| |
| .title('Step 2')
| |
| .navigateTo('io.ox/mail/main')
| |
| .waitFor('.thread-view-list')
| |
| .mandatory()
| |
| .content('Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.')
| |
| .spotlight('.thread-view-list')
| |
| .end()
| |
| .step()
| |
| .title('Step 3')
| |
| .content('Lorem ipsum dolor sit amet.')
| |
| .navigateTo('io.ox/contacts/main')
| |
| .waitFor('.folder[data-id="6"]')
| |
| .spotlight('.folder-tree')
| |
| .scrollIntoView('.folder[data-id="6"]')
| |
| .beforeShow(function () {
| |
| | |
| this.$('.content').append(
| |
| $('<p><a href="#" class="enable-next">Enable</a></p>')
| |
| );
| |
| | |
| this.toggleNext(false);
| |
| | |
| this.$el.on('click', '.enable-next', function (e) {
| |
| e.preventDefault();
| |
| this.toggleNext(true);
| |
| }.bind(this));
| |
| })
| |
| .end()
| |
| .step()
| |
| .title('Last step')
| |
| .content('Lorem ipsum dolor sit amet.')
| |
| .modal(false)
| |
| .end()
| |
| .start();
| |
| });
| |
| | |
| Tour.registry.run('test');
| |
| });
| |
| </pre>
| |