1 /** 2 @class 3 @extends rio.Attr 4 5 Page is used to create page classes in a rio application. It handles css dependencies, rendering, templating, 6 layout management, and popup management. 7 8 @author Jason Tillery 9 @copyright 2008-2009 Thinklink LLC 10 */ 11 rio.Page = { 12 create: function() { 13 var args = $A(arguments); 14 if (args.length > 0 && args.last() != undefined && !args.last().ATTR) { 15 args[args.size() - 1] = Object.extend({ noExtend: true }, args.last()); 16 } 17 var page = rio.Attr.create.apply(this, args); 18 19 Object.extend(page, { 20 requireCss: function(name) { 21 rio.Application.includeCss("pages/" + name); 22 }, 23 template: function(name) { 24 rio.boot.loadedTemplates.push(rio.boot.appRoot + "pages/" + name); 25 26 this._templateName = name; 27 }, 28 applyTemplate: function() { 29 if (this._templateName && !this._templateApplied) { 30 var template = rio.JsTemplate.build("pages/" + this._templateName); 31 page.addMethods(template.mixinMethods()); 32 33 this._templateApplied = true; 34 } 35 }, 36 manageLayout: function() { 37 this.__manageLayout = true; 38 }, 39 manageUndo: function() { 40 this.__manageUndo = true; 41 } 42 }); 43 44 page.addMethods({ 45 html: function() { 46 if (!this._html) { this._html = this.buildHtml(); } 47 return this._html; 48 }, 49 50 popup: function() { 51 if (!this.__popup) { 52 this.__popup = new rio.components.Popup({ 53 content: this.html() 54 }); 55 } 56 this.__popup.activate(); 57 this.render(); 58 }, 59 60 resizePopup: function() { 61 this.__popup.resize(); 62 }, 63 64 closePopup: function(skipFade) { 65 this.__popup.deactivate(skipFade); 66 }, 67 68 isManagingLayout: function() { 69 return page.__manageLayout; 70 }, 71 72 _manageLayout: function() { 73 if (page.__manageLayout) { 74 this.__lm = new rio.LayoutManager(this.html()); 75 } 76 }, 77 78 layoutManager: function() { 79 return this.__lm; 80 }, 81 82 _afterRender: function() { 83 if (this.isManagingLayout()) { 84 (function() { this.__lm.resize(); }.bind(this)).defer(); 85 (function() { this.__lm.resize(); }.bind(this)).delay(2); 86 (function() { this.__lm.resize(); }.bind(this)).delay(5); 87 } 88 }, 89 90 render: function() { 91 this._manageLayout(); 92 this._afterRender(); 93 }, 94 95 show: function() { 96 this.html().show(); 97 this.resizePopup(); 98 }, 99 100 hide: function() { 101 this.html().hide(); 102 }, 103 104 addHistoryEntry: function(location, isTransient) { 105 rio.app.addHistoryEntry(location, isTransient); 106 }, 107 108 applyHistoryEntry: function() { 109 // Meant to be overriden 110 }, 111 112 keyPress: function(e) { 113 // Meant to be overriden 114 }, 115 116 keyDown: function(e) { 117 // Meant to be overriden 118 }, 119 120 resize: function() { 121 // Meant to be overriden 122 }, 123 124 getKeyMap: function() { 125 if (!this._keyMap) { 126 var maps = this.keyMap ? this.keyMap() : []; 127 128 if (page.__manageUndo) { 129 maps.push({ 130 mac: { meta: true, shift: false, alt: false, key: "z" }, 131 win: { ctrl: true, alt: false, key: "z" }, 132 handler: function(e) { 133 if (e.target.value == undefined && this.undoShortcutsEnabled()) { 134 rio.Undo.undo(); 135 } 136 }.bind(this) 137 }); 138 maps.push({ 139 mac: { meta: true, shift: true, alt: false, key: "z" }, 140 win: { ctrl: true, alt: false, key: "y" }, 141 handler: function(e) { 142 if (e.target.value == undefined && this.undoShortcutsEnabled()) { 143 rio.Undo.redo(); 144 e.stop(); 145 } 146 }.bind(this) 147 }); 148 } 149 this._keyMap = rio.KeyMap.build(maps); 150 } 151 return this._keyMap; 152 }, 153 154 enableUndoKeyboardShortcuts: function() { 155 this._undoShortuctsEnabled = true; 156 }, 157 158 disableUndoKeyboardShortcuts: function() { 159 this._undoShortuctsEnabled = false; 160 }, 161 162 undoShortcutsEnabled: function() { 163 if (this._undoShortuctsEnabled == undefined) { this._undoShortuctsEnabled = true; } 164 return this._undoShortuctsEnabled; 165 }, 166 167 _keyDown: function(e) { 168 this.getKeyMap().handle(e); 169 this.keyDown(e); 170 }, 171 172 navigateTo: function(path) { 173 rio.app.navigateTo(path); 174 }, 175 176 refresh: function() { 177 rio.app.refresh(); 178 }, 179 180 rootUrl: function() { 181 return rio.app.rootUrl(); 182 }, 183 184 getCurrentLocation: function() { 185 return rio.app.getCurrentLocation(); 186 }, 187 188 toString: function() { 189 return "[rio.pages.*]"; 190 } 191 }); 192 193 // if (last arg is a concise syntax initializer) 194 if (args.length > 0 && args.last() != undefined && !args.last().ATTR) { 195 var initializers = args.last(); 196 if (Object.isString(initializers.requireCss)) { 197 page.requireCss(initializers.requireCss); 198 } 199 200 if (Object.isString(initializers.template)) { 201 page.template(initializers.template); 202 } 203 if (Object.isString(initializers.jstemplate)) { 204 page.template(initializers.jstemplate); 205 } 206 207 if (initializers.manageLayout) { 208 page.manageLayout(); 209 } 210 211 if (initializers.manageUndo) { 212 page.manageUndo(); 213 } 214 215 rio.Page.extend(page, initializers.methods || {}); 216 } 217 218 return page; 219 }, 220 221 extend: function(page, extension) { 222 extension._render = extension.render || Prototype.emptyFunction; 223 extension.render = function() { 224 this._manageLayout(); 225 this._render(); 226 this._afterRender(); 227 }; 228 229 extension.__initialize = extension.initialize || Prototype.emptyFunction; 230 extension.initialize = function(options) { 231 page.applyTemplate(); 232 233 (this.__initialize.bind(this))(options); 234 }; 235 236 rio.Attr.extend(page, extension); 237 } 238 }; 239