1 // ==========================================================================
  2 // Project:   The M-Project - Mobile HTML5 Application Framework
  3 // Copyright: (c) 2010 M-Way Solutions GmbH. All rights reserved.
  4 //            (c) 2011 panacoda GmbH. All rights reserved.
  5 // Creator:   Dominik
  6 // Date:      09.11.2010
  7 // License:   Dual licensed under the MIT or GPL Version 2 licenses.
  8 //            http://github.com/mwaylabs/The-M-Project/blob/master/MIT-LICENSE
  9 //            http://github.com/mwaylabs/The-M-Project/blob/master/GPL-LICENSE
 10 // ==========================================================================
 11 
 12 /**
 13  * @class
 14  *
 15  * M.ToggleView defines the prototype of any toggle view. A toggle view accepts exactly
 16  * two child views and provides an easy mechanism to toggle between these two views. An
 17  * easy example would be to define two different button views that can be toggled, a more
 18  * complex scenario would be to define two content views (M.ScrollView) with own child views
 19  * and toggle between them.
 20  *
 21  * @extends M.View
 22  */
 23 M.ToggleView = M.View.extend(
 24 /** @scope M.ToggleView.prototype */ {
 25 
 26     /**
 27      * The type of this object.
 28      *
 29      * @type String
 30      */
 31     type: 'M.ToggleView',
 32 
 33     /**
 34      * States whether the toggle view currently displays its first child view or its second
 35      * child view.
 36      *
 37      * @type Boolean
 38      */
 39     isInFirstState: YES,
 40 
 41     /**
 42      * Determines whether to toggle the view on click. This might be useful if the child views
 43      * are e.g. buttons.
 44      *
 45      * @type Boolean
 46      */
 47     toggleOnClick: NO,
 48 
 49     /**
 50      * Contains a reference to the currently displayed view.
 51      *
 52      * @type M.View
 53      */
 54     currentView: null,
 55 
 56     /**
 57      * Renders a ToggleView and its child views.
 58      *
 59      * @private
 60      * @returns {String} The toggle view's html representation.
 61      */
 62     render: function() {
 63         this.html += '<div id="' + this.id + '">';
 64 
 65         this.renderChildViews();
 66 
 67         this.html += '</div>';
 68         
 69         return this.html;
 70     },
 71 
 72     /**
 73      * This method renders one child view of the toggle view, based on the isInFirstState
 74      * property: YES = first child view, NO = second child view.
 75      */
 76     renderChildViews: function() {
 77         if(this.childViews) {
 78             var childViews = this.getChildViewsAsArray();
 79 
 80             if(childViews.length !== 2) {
 81                 M.Logger.log('M.ToggleView requires exactly 2 child views, but ' + childViews.length + ' are given (' + (this.name ? this.name + ', ' : '') + this.id + ')!', M.WARN);
 82             } else {
 83                 for(var i in childViews) {
 84                     if(this[childViews[i]]) {
 85                         if(this.toggleOnClick) {
 86                             this[childViews[i]].internalEvents = {
 87                                 tap: {
 88                                     target: this,
 89                                     action: 'toggleView'
 90                                 }
 91                             }
 92                         }
 93                         this[childViews[i]]._name = childViews[i];
 94                         this[childViews[i]].parentView = this;
 95                         
 96                         this.html += '<div id="' + this.id + '_' + i + '">';
 97                         this.html += this[childViews[i]].render();
 98                         this.html += '</div>';
 99                     }
100                 }
101                 this.currentView = this[childViews[0]];
102             }
103         }
104     },
105 
106     /**
107      * This method toggles the child views by first emptying the toggle view's content
108      * and then rendering the next child view by calling renderUpdateChildViews().
109      */
110     toggleView: function(id, event, nextEvent) {
111         this.isInFirstState = !this.isInFirstState;
112         var currentViewIndex = this.isInFirstState ? 0 : 1;
113         $('#' + this.id + '_' + currentViewIndex).show();
114         $('#' + this.id + '_' + (currentViewIndex > 0 ? 0 : 1)).hide();
115 
116         /* set current view */
117         var childViews = this.getChildViewsAsArray();
118         if(this[childViews[currentViewIndex]]) {
119             this.currentView = this[childViews[currentViewIndex]];
120         }
121 
122         /* call jqm to fix header/footer */
123         $.mobile.fixedToolbars.show();
124 
125         if(nextEvent) {
126             M.EventDispatcher.callHandler(nextEvent, event, YES);
127         }
128     },
129 
130     /**
131      * This method can be used to set on of the toggle view's child views as the active one. Simply pass
132      * the view, its id or its name.
133      *
134      * If a view or id is passed, that does not match on of the toggle view's child views, nothing will be
135      * done.
136      *
137      * @param {Object|String} view The corresponding view.
138      */
139     setView: function(view) {
140         if(typeof(view) === 'string') {
141             /* assume a name was given */
142             var childViews = this.getChildViewsAsArray();
143             if(_.indexOf(childViews, view) >= 0) {
144                 view = this[view];
145             /* assume an id was given */
146             } else {
147                 view = M.ViewManager.getViewById(view) ? M.ViewManager.getViewById(view) : view;
148             }
149         }
150 
151         if(view && typeof(view) === 'object' && view.parentView === this) {
152             if(this.currentView !== view) {
153                 this.toggleView();
154             }
155         } else {
156             M.Logger.log('No valid view passed for toggle view \'' + this._name + '\'.', M.WARN);
157         }
158     },
159 
160     /**
161      * Triggers the rendering engine, jQuery mobile, to style the toggle view respectively
162      * its child views.
163      *
164      * @private
165      */
166     theme: function() {
167         if(this.currentView) {
168             this.themeChildViews();
169             var currentViewIndex = this.isInFirstState ? 0 : 1;
170 
171             $('#' + this.id + '_' + (currentViewIndex > 0 ? 0 : 1)).hide();
172         }
173     }
174 
175 });