Dialogs and Containers

Mojo containers can be used to encapsulate certain displays or actions to simplify the remaining scene. Drawers and Dialogs are used to keep features hidden except when they are needed, while Scrollers can be used to create windows within the scene, preserving the position of the rest of the view.

Dialogs

The framework will automatically focus the first focusable item in a Dialog, like it does in scenes. Please note that if you launch a Dialog by tapping on an element in the main scene, you need to stop the Mojo.Event.tap event before launching the Dialog. Since your scene has handled the event by opening a new container, you don't want the event that created the container to still be active on the main scene.

this.controller.listen('launchDialogButton',
  Mojo.Event.tap,
  this.handleTap.bind(this));

handleTap: function(tapEvent) {
  //received a tap on the launch dialog button, so stop the event
  tapEvent.stop();
  this.controller.showDialog({
      template: 'myscene/my-dialog',
      assistant: new SampleDialogAssistant(this)
  });
}    

showDialog()

Dialogs can be used to display custom content to the user in the form of a modal dialog box. You can render anything in a Dialog that you can render in a scene. To create a dialog, you'll call this.controller.showDialog with a JSON object containing at least properties for a scene template, an HTML file describing the dialog content which will look like any other scene view file, and a JavaScript function which will be called when the dialog is invoked. The dialog assistant is like a scene assistant, and has setup, activate, deactivate, and cleanup methods. For example:

var dialog = this.controller.showDialog({
  template: 'myscene/my-dialog',
  assistant: new SampleDialogAssistant(this)
});

//put in a full example of a dialog assistant
var SampleDialogAssistant = Class.create({

  initialize: function(sceneAssistant) {
      this.sceneAssistant = sceneAssistant;
      this.controller = sceneAssistant.controller;
  },

  setup : function(widget) {
      this.widget = widget;
      this.controller.get('thanksButton').addEventListener(Mojo.Event.tap,
          this.handleThanks.bindAsEventListener(this));
      },

  handleThanks: function() {
      this.sceneAssistant.outputDisplay.innerHTML = $L("Dialog result = ") +
          this.sceneAssistant.loremRating.rating;
      this.widget.mojo.close();
  }
});    

To programatically close the dialog:

dialog.mojo.close(); 

showAlertDialog()

To display a short message to the user, use an Alert Dialog with a message and one or more selection options presented as buttons. When an option is selected, your specified callback function is called with the value assigned to the selection. If there is no selection (e.g., the user gestures back to exit the dialog) then the onChoose function is called with an undefined value.

You would call this as this.controller.showAlertDialog(model) where model includes properties for the onChoose function, a message and the choices array. The choices array can offer any number of choices with each choice being a button in the dialog, usually stacked vertically. Each choice entry has a label, a value and a type where type corresponds to one of the CSS button classes (primary, secondary, dismissal, affirmative or negative) or your own classname. The classnames are optional.

errorDialog()

The simplest dialog is a modal error dialog with a short message and confirmation button used for dismissing the dialog. These should be used to just display error messages to the user as they do not allow the user to make choices, but only to dismiss the dialog after receiving the information presented.

var error = "An error has occurred.";
Mojo.Controller.errorDialog(error);    

Drawer

Drawers are container widgets that can be "open", allowing child content to be displayed normally, or "closed", keeping it out of view. The open state of the drawer depends on a single model property, but can also be updated by calling widget methods, described in the API documentation. Unlike other widgets, where the inner content of the DIV on which the widget is defined is replaced, the contents of a Drawer widget div are preserved by the framework. The framework will wrap whatever content is contained within the div and make it possible to show and hide it in an animated fashion.

This shows a Drawer widget with an embedded List widget and content. The Drawer widget will automatically resize to enclose all content added from the dynamic list and the other static div contained within it.

<div id='listDrawer' x-mojo-element="Drawer">
  <div class="palm-row">This is just some content</div>
  <div id="list" x-mojo-element="List"></div>
<div>    

Scroller

The scroller widget is used to provide all scrolling behavior. By default, each scene contains a Scroller widget. You can disable this default behavior by having a truthy value in the disableSceneScroller property in the scene arguments to pushScene). The Scroller widget can also be instantiated anywhere else in the scene. The framework will automatically update the position of itself with respect to the screen.

Creating a Scroller

You do not need to call setupWidget on a scroller; simply add the Scroller element to a DIV that has bounded width and height, and it will use the default scroll mode of "vertical." If you are experiencing issues with Scroller functionality, make sure that your DIV has bounded width and height. This is a common mistake when using the widget.

<div id="scroller" style="width:100px; height:500px" x-mojo-element="Scroller"></div>

Scrollers and Widgets

Sometimes, it is useful to get the scroller for a particular widget. To do that, call:

var scroller = Mojo.View.getScrollerForElement(myDiv);    

Scroll Listeners

To listen for changes to scroll position, first add your scene assistant as a listener for the Scroller:

var scroller = this.controller.sceneScroller;scroller.addListener(this);    

Then, implement the "moved" function in your assistant.

moved: function(scrollEnding, position) {
  Mojo.Log.info("The scroller is at position: y coordinate: " +
      position.y + " , x coordinate: " + position.x);
};

The first argument, scrollEnding, is true if this call to moved from the scroller is the last before it stops. Position represents the X and Y coordinates of the Scroller when the function is called. Note: if you make a change in response to every listener callback, it will make scrolling slower.

Scrolling Modes

You can select one of six scrolling modes, specified in the mode property of the widget's attributes:

  1. free: allow scrolling along the x and y axis.
  2. horizontal: allow scrolling only along the horizontal axis.
  3. vertical: allow scrolling only along the vertical axis; default.
  4. dominant: allow scrolling along the horizontal or vertical axis, but not both at once. The direction of the intial drag will determine the axis of scrolling.
  5. horizontal-snap: In this mode, scrolling is locked to the horizontal axis, but snaps to points determined by the position of the block elements found in the model's snapElements property. As the scroller scrolls from snap point to snap point it will send a Mojo.Event.propertyChange event.
  6. vertical-snap: similarly, this mode locks scrolling to the vertical axis, but snaps to points determined by the elements in the snapElements property array.

Programatically Updating the Scroller

The Scroller widget provides a number of ways to programatically update its position. This can be useful if you want to expose a specific element on the scene, return the user to the top (or bottom) of a scene, or just adjust to a new location.

To reveal a specific element on a page:

//first, get the scroller associated with this element,
//so that you are updating the correct Scroller Widget
var myDiv = this.controller.get('myDiv');
var scroller = Mojo.View.getScrollerForElement(myDiv);

//next, update the scroller
scroller.mojo.revealElement(myDiv);