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: Sebastian 6 // Date: 02.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.PageView is the prototype of any page. It is the seconds 'highest' view, right after 16 * M.Application. A page is the container view for all other views. 17 * 18 * @extends M.View 19 */ 20 M.PageView = M.View.extend( 21 /** @scope M.PageView.prototype */ { 22 23 /** 24 * The type of this object. 25 * 26 * @type String 27 */ 28 type: 'M.PageView', 29 30 /** 31 * States whether a page is loaded the first time or not. It is automatically set to NO 32 * once the page was first loaded. 33 * 34 * @type Boolean 35 */ 36 isFirstLoad: YES, 37 38 /** 39 * Indicates whether the page has a tab bar or not. 40 * 41 * @type Boolean 42 */ 43 hasTabBarView: NO, 44 45 /** 46 * The page's tab bar. 47 * 48 * @type M.TabBarView 49 */ 50 tabBarView: null, 51 52 /** 53 * This property specifies the recommended events for this type of view. 54 * 55 * @type Array 56 */ 57 recommendedEvents: ['pagebeforeshow', 'pageshow', 'pagebeforehide', 'pagehide', 'orientationchange'], 58 59 /** 60 * This property is used to specify a view's internal events and their corresponding actions. If 61 * there are external handlers specified for the same event, the internal handler is called first. 62 * 63 * @type Object 64 */ 65 internalEvents: null, 66 67 /** 68 * An associative array containing all list views used in this page. The key for a list view is 69 * its id. We do this to have direct access to a list view, so we can reset its selected item 70 * once the page was hidden. 71 * 72 * @type Object 73 */ 74 listList: null, 75 76 /** 77 * This property contains the page's current orientation. This property is only used internally! 78 * 79 * @private 80 * @type Number 81 */ 82 orientation: null, 83 84 /** 85 * Renders in three steps: 86 * 1. Rendering Opening div tag with corresponding data-role 87 * 2. Triggering render process of child views 88 * 3. Rendering closing tag 89 * 90 * @private 91 * @returns {String} The page view's html representation. 92 */ 93 render: function() { 94 /* store the currently rendered page as a reference for use in child views */ 95 M.ViewManager.currentlyRenderedPage = this; 96 97 this.html += '<div id="' + this.id + '" data-role="page"' + this.style() + '>'; 98 99 this.renderChildViews(); 100 101 this.html += '</div>'; 102 103 this.writeToDOM(); 104 this.theme(); 105 this.registerEvents(); 106 }, 107 108 /** 109 * This method is responsible for registering events for view elements and its child views. It 110 * basically passes the view's event-property to M.EventDispatcher to bind the appropriate 111 * events. 112 * 113 * It extend M.View's registerEvents method with some special stuff for page views and its 114 * internal events. 115 */ 116 registerEvents: function() { 117 this.internalEvents = { 118 pagebeforeshow: { 119 target: this, 120 action: 'pageWillLoad' 121 }, 122 pageshow: { 123 target: this, 124 action: 'pageDidLoad' 125 }, 126 pagebeforehide: { 127 target: this, 128 action: 'pageWillHide' 129 }, 130 pagehide: { 131 target: this, 132 action: 'pageDidHide' 133 }, 134 orientationchange: { 135 target: this, 136 action: 'orientationDidChange' 137 } 138 } 139 this.bindToCaller(this, M.View.registerEvents)(); 140 }, 141 142 /** 143 * This method writes the view's html string into the DOM. M.Page is the only view that does 144 * that. All other views just deliver their html representation to a page view. 145 */ 146 writeToDOM: function() { 147 document.write(this.html); 148 }, 149 150 /** 151 * This method is called right before the page is loaded. If a beforeLoad-action is defined 152 * for the page, it is now called. 153 * 154 * @param {String} id The DOM id of the event target. 155 * @param {Object} event The DOM event. 156 * @param {Object} nextEvent The next event (external event), if specified. 157 */ 158 pageWillLoad: function(id, event, nextEvent) { 159 /* initialize the tabbar */ 160 if(M.Application.isFirstLoad) { 161 M.Application.isFirstLoad = NO; 162 var currentPage = M.ViewManager.getCurrentPage(); 163 if(currentPage && currentPage.hasTabBarView) { 164 var tabBarView = currentPage.tabBarView; 165 166 if(tabBarView.childViews) { 167 var childViews = tabBarView.getChildViewsAsArray(); 168 for(var i in childViews) { 169 if(M.ViewManager.getPage(tabBarView[childViews[i]].page).id === currentPage.id) { 170 tabBarView.setActiveTab(tabBarView[childViews[i]]); 171 } 172 } 173 } 174 } 175 } 176 177 /* initialize the loader for later use (if not already done) */ 178 if(M.LoaderView) { 179 M.LoaderView.initialize(); 180 } 181 182 /* reset the page's title */ 183 document.title = M.Application.name; 184 185 /* delegate event to external handler, if specified */ 186 if(nextEvent) { 187 M.EventDispatcher.callHandler(nextEvent, event, NO, [this.isFirstLoad]); 188 } 189 }, 190 191 /** 192 * This method is called right after the page was loaded. If a onLoad-action is defined 193 * for the page, it is now called. 194 * 195 * @param {String} id The DOM id of the event target. 196 * @param {Object} event The DOM event. 197 * @param {Object} nextEvent The next event (external event), if specified. 198 */ 199 pageDidLoad: function(id, event, nextEvent) { 200 /* delegate event to external handler, if specified */ 201 if(nextEvent) { 202 M.EventDispatcher.callHandler(nextEvent, event, NO, [this.isFirstLoad]); 203 } 204 205 /* call jqm to fix header/footer */ 206 $.mobile.fixedToolbars.show(); 207 208 this.isFirstLoad = NO; 209 }, 210 211 /** 212 * This method is called right before the page is hidden. If a beforeHide-action is defined 213 * for the page, it is now called. 214 * 215 * @param {String} id The DOM id of the event target. 216 * @param {Object} event The DOM event. 217 * @param {Object} nextEvent The next event (external event), if specified. 218 */ 219 pageWillHide: function(id, event, nextEvent) { 220 /* delegate event to external handler, if specified */ 221 if(nextEvent) { 222 M.EventDispatcher.callHandler(nextEvent, event, NO, [this.isFirstLoad]); 223 } 224 }, 225 226 /** 227 * This method is called right after the page was hidden. If a onHide-action is defined 228 * for the page, it is now called. 229 * 230 * @param {String} id The DOM id of the event target. 231 * @param {Object} event The DOM event. 232 * @param {Object} nextEvent The next event (external event), if specified. 233 */ 234 pageDidHide: function(id, event, nextEvent) { 235 /* if there is a list on the page, reset it: deactivate possible active list items */ 236 if(this.listList) { 237 _.each(this.listList, function(list) { 238 list.resetActiveListItem(); 239 }); 240 } 241 242 /* delegate event to external handler, if specified */ 243 if(nextEvent) { 244 M.EventDispatcher.callHandler(nextEvent, event, NO, [this.isFirstLoad]); 245 } 246 }, 247 248 /** 249 * This method is called right after the device's orientation did change. If a action for 250 * orientationchange is defined for the page, it is now called. 251 * 252 * @param {String} id The DOM id of the event target. 253 * @param {Object} event The DOM event. 254 * @param {Object} nextEvent The next event (external event), if specified. 255 */ 256 orientationDidChange: function(id, event, nextEvent) { 257 /* get the orientation */ 258 var orientation = M.Environment.getOrientation(); 259 260 /* filter event duplicates (can happen due to event delegation in bootstraping.js) */ 261 if(orientation === this.orientation) { 262 return; 263 } 264 265 /* auto-reposition opened dialogs */ 266 $('.tmp-dialog').each(function() { 267 var id = $(this).attr('id'); 268 var dialog = M.ViewManager.getViewById(id); 269 var dialogDOM = $(this); 270 window.setTimeout(function() { 271 dialog.positionDialog(dialogDOM); 272 dialog.positionBackground($('.tmp-dialog-background')); 273 }, 500); 274 }); 275 276 /* set the current orientation */ 277 this.orientation = orientation; 278 279 /* delegate event to external handler, if specified */ 280 if(nextEvent) { 281 M.EventDispatcher.callHandler(nextEvent, event, NO, [M.Environment.getOrientation()]); 282 } 283 }, 284 285 /** 286 * Triggers the rendering engine, jQuery mobile, to style the page and call the theme() of 287 * its child views. 288 * 289 * @private 290 */ 291 theme: function() { 292 $('#' + this.id).page(); 293 this.themeChildViews(); 294 }, 295 296 /** 297 * Applies some style-attributes to the page. 298 * 299 * @private 300 * @returns {String} The page's styling as html representation. 301 */ 302 style: function() { 303 var html = ''; 304 if(this.cssClass) { 305 if(!html) { 306 html += ' class="'; 307 } 308 html += this.cssClass; 309 } 310 if(html) { 311 html += '"'; 312 } 313 return html; 314 } 315 316 });