├── .DS_Store ├── license.txt ├── readme.md ├── uibot.coffee └── uibot.js /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gotdan/UiBot/f4bb87a0c691a466e76c1bb84a25901b54afe54a/.DS_Store -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | Copyright (C) 2012 Dan Gottlieb 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # UiBot for Google Apps Script 2 | 3 | * [Overview](#overview) 4 | * [Comparison with UI Service](#comparison) 5 | * [Using UiBot](#using-uibot) 6 | * [Add UiBot to your project](#add-uibot-to-your-project) 7 | * [Create a blank UiBot app](#create-a-blank-uibot-app) 8 | * [Set basic interface properties](#set-basic-interface-properties) 9 | * [Add a widget to your app](#add-a-widget-to-your-app) 10 | * [Nest widgets inside other widgets](#nest-widgets-inside-other-widgets) 11 | * [Create a form](#create-a-form) 12 | * [Add data to a ListBox widget](#add-data-to-a-listbox-widget) 13 | * [Give a widget some style](#give-a-widget-some-style) 14 | * [Handle clicks on the client](#handle-clicks-on-the-client) 15 | * [Handle clicks on the server](#handle-clicks-on-the-server) 16 | * [Code](#code) 17 | * [Roadmap](#roadmap) 18 | * [Contact](#contact) 19 | 20 | 21 | ## Overview 22 | UiBot is a small helper library to make using the Google Apps Script UI Service faster and more enjoyable. With the UiBot library, you can specify your interface using a simple declarative JSON syntax, rather then lots of chained function calls. UiBot also includes some helpers to reduce the amount of code needed to build forms. 23 | 24 | While you can also create a UI with Google's recently released Html Service, by using the UI Service your dialogs will share a common design with Google Docs and will work smoothly across all of the browsers supported by Google Docs. 25 | 26 | ## Comparison 27 | ###UI Service without UiBot 28 | ```javascript 29 | function doGet() { 30 | var app = UiApp.createApplication() 31 | .setTitle('New app'); 32 | var grid = app.createGrid(4, 2); 33 | 34 | var cityChoices = app.createListBox() 35 | .setName('city').setId('city') 36 | .addItem('New York').addItem('Paris') 37 | .addItem('London').addItem('Tokyo'); 38 | cityChoices.setItemSelected(2, true); 39 | grid.setWidget(0, 0, app.createLabel('Name:')); 40 | grid.setWidget(0, 1, app.createTextBox() 41 | .setName('userName').setId('userName')); 42 | grid.setWidget(1, 0, app.createLabel('Age:')); 43 | grid.setWidget(1, 1, app.createTextBox() 44 | .setName('age').setId('age')); 45 | grid.setWidget(3, 0, app.createLabel('City')); 46 | grid.setWidget(3, 1, cityChoices); 47 | 48 | var panel = app.createVerticalPanel(); 49 | app.add(panel); 50 | panel.add(grid); 51 | 52 | var button = app.createButton('submit'); 53 | var handler = app.createServerHandler('b'); 54 | handler.addCallbackElement(grid); 55 | var handler2 = app.createClientHandler() 56 | .forTargets(grid) 57 | .setVisible(false); 58 | button.addClickHandler(handler); 59 | button.addClickHandler(handler2); 60 | panel.add(button); 61 | 62 | return app; 63 | } 64 | function b() { 65 | Browser.msgBox('callback!'); 66 | } 67 | ``` 68 | 69 | ###UI Service with UiBot 70 | ```javascript 71 | function doGet() { 72 | var panel = { 73 | wType: 'VerticalPanel', 74 | items: [{ 75 | wType: 'HorizontalForm', 76 | id: 'form', 77 | items: [{ 78 | fieldLabel : 'Name:', 79 | wType : 'TextBox', 80 | name : 'userName' 81 | },{ 82 | fieldLabel : 'Age:', 83 | wType : 'TextBox', 84 | name : 'age' 85 | },{ 86 | blank : true 87 | },{ 88 | fieldLabel : 'City:', 89 | wType : 'ListBox', 90 | name : 'city', 91 | data : ['New York', 'Paris', 92 | 'London', 'Tokyo'], 93 | selected : 'London' 94 | }], 95 | },{ 96 | wType : 'Button', 97 | text : 'Submit', 98 | onClick: { 99 | callback : 'b', 100 | cbElementId : 'form', 101 | hide : 'form' 102 | } 103 | }] //panel items 104 | }; //panel 105 | 106 | bot = new UiBot.UiBot({ 107 | title: 'New App', 108 | items: [ panel ] 109 | }); 110 | return bot.getApp(); 111 | } 112 | UiBot.b = function() { 113 | Browser.msgBox('callback!'); 114 | } 115 | ``` 116 | 117 | ## Using UiBot 118 | This tutorial covers the use of UiBot and assumes some familiarity with Google Apps Script and the Google Apps Script UI Service. If you're new to either of these, you may want to take a look at the following tutorials before continuing. 119 | 120 | * [Google Apps Script Tutorial](https://developers.google.com/apps-script/your_first_script) 121 | * [Google UI Service Overview](https://developers.google.com/apps-script/uiapp) 122 | 123 | ### Add UiBot to your project 124 | If you'd like to follow along, be sure to add the UiBot library to your project. The project key is *MdY_z6sqJlAAsbzYJGBr7WppQAdMKFO40* and instructions on adding a library to your development environment are [here](https://developers.google.com/apps-script/guide_libraries#includeLibrary). 125 | 126 | 127 | ### Create a blank UiBot app 128 | ```javascript 129 | function doGet() { 130 | var bot = new UiBot.UiBot(); 131 | return bot.getApp(); 132 | } 133 | ``` 134 | 135 | Google Apps Script requires you to return an _App_ object to render the interface in a web apps. We could also show our interface in a spreadsheet by changing the last line of the code above. 136 | ```javascript 137 | function doGet() { 138 | var bot = new UiBot.UiBot(); 139 | SpreadsheetApp 140 | .getActiveSpreadsheet() 141 | .show( bot.getApp() ); 142 | } 143 | ``` 144 | 145 | 146 | ### Set basic interface properties 147 | We can supply an optional configuration object to UiBot to set the title, width and height of our interface. 148 | ```javascript 149 | function doGet() { 150 | var bot = new UiBot.UiBot({ 151 | title: 'Test App!', 152 | width: 300, 153 | height: 300 154 | }); 155 | return bot.getApp(); 156 | } 157 | ``` 158 | 159 | ### Add a widget to your app 160 | When defining widgets with UiBot, you must specify a widget type using the _wType_ property. Widgets may also have other properties (the part after the 'set' in the UI Service documentation). For example, the api function _setText_ is equivalent to the UiBot property _text_). A full list of the widget types and their properties is [here](https://developers.google.com/apps-script/service_ui). 161 | 162 | Let's create a label on our interface 163 | ```javascript 164 | function doGet() { 165 | var bot = new UiBot.UiBot(); 166 | 167 | bot.addWidget({ 168 | wType : 'Label', 169 | text : 'This is a label!' 170 | }); 171 | 172 | return bot.getApp(); 173 | } 174 | ``` 175 | 176 | ### Nest widgets inside other widgets 177 | Widgets that can contain other widgets (such as panels) have an _items_ property that can be filled with an array of other widgets. Let's create a panel with our label inside. 178 | 179 | ```javascript 180 | function doGet() { 181 | var bot = new UiBot.UiBot(); 182 | 183 | bot.addWidget({ 184 | wType : 'VerticalPanel', 185 | items : [{ 186 | wType : 'Label', 187 | text : 'This is a label!' 188 | }] 189 | }); 190 | 191 | return bot.getApp(); 192 | } 193 | ``` 194 | 195 | Of course, there's no reason to create a panel for a single widget... 196 | 197 | ```javascript 198 | function doGet() { 199 | var bot = new UiBot.UiBot(); 200 | 201 | bot.addWidget({ 202 | wType : 'VerticalPanel', 203 | items : [{ 204 | wType : 'Label', 205 | text : 'This is a label!' 206 | },{ 207 | wType : 'Label', 208 | text : 'This is a second label!' 209 | }] 210 | }); 211 | 212 | return bot.getApp(); 213 | } 214 | ``` 215 | 216 | We can nest widgets inside of the UiBot object too... 217 | ```javascript 218 | function doGet() { 219 | var bot = new UiBot.UiBot({ 220 | 221 | title: 'Test App!', 222 | items: [{ 223 | wType : 'VerticalPanel', 224 | 225 | items : [{ 226 | wType : 'Label', 227 | text : 'This is a label!' 228 | },{ 229 | wType : 'Label', 230 | text : 'This is a second label!' 231 | }] //panel items 232 | 233 | }] //app items 234 | 235 | }); 236 | 237 | return bot.getApp(); 238 | } 239 | ``` 240 | 241 | Nesting is a choice though - we can also break out each widget into separate objects (somewhere between these extremes is usually the best choice to write clear code). 242 | 243 | ```javascript 244 | function doGet() { 245 | 246 | var label1 = { 247 | wType : 'Label', 248 | text : 'This is a label!' 249 | } 250 | 251 | var label2 = { 252 | wType : 'Label', 253 | text : 'This is a second label!' 254 | } 255 | 256 | var panel = { 257 | wType : 'VerticalPanel', 258 | items : [ label1, label2 ] 259 | } 260 | 261 | var bot = new UiBot.UiBot({ 262 | title: 'Test App!', 263 | items: [ panel ] 264 | }); 265 | 266 | return bot.getApp(); 267 | 268 | } 269 | ``` 270 | 271 | ### Create a form 272 | We often need create forms with labels on the left and widgets on the right, so UiBot has a special helper for this. The _HorizontalForm_ widget type automatically creates a grid with two columns and the correct number of rows. A new _fieldLabel_ property in each widget makes it easy to set a label for the widget. You can also add a blank row to separate sections of your form using the _blank_ property. 273 | 274 | ```javascript 275 | function doGet() { 276 | 277 | var form = { 278 | wType: 'HorizontalForm', 279 | items: [{ 280 | fieldLabel : 'Name:', 281 | wType : 'TextBox', 282 | name : 'userName' 283 | },{ 284 | fieldLabel : 'Age:', 285 | wType : 'TextBox', 286 | name : 'age' 287 | },{ 288 | blank : true 289 | },{ 290 | fieldLabel : 'City:', 291 | wType : 'TextBox', 292 | name : 'city' 293 | }] 294 | }; 295 | 296 | var bot = new UiBot.UiBot({ 297 | title: 'Test App!', 298 | items: [ form ] 299 | }); 300 | 301 | return bot.getApp(); 302 | 303 | } 304 | ``` 305 | ### Add data to a ListBox widget 306 | It's also pretty common to create listboxes with data in them, so UiBot adds optional _data_ and _selected_ properties to the _ListBox_ widget. 307 | 308 | ```javascript 309 | function doGet() { 310 | 311 | var form = { 312 | wType : 'HorizontalForm', 313 | items : [{ 314 | fieldLabel : 'Period:', 315 | wType : 'ListBox', 316 | name : 'periodList', 317 | data : ["Day", "Month","Quarter", "Year"], 318 | selected : "Month" 319 | }] 320 | }; 321 | 322 | var bot = new UiBot.UiBot({ 323 | title: 'Test App!', 324 | items: [ form ] 325 | }); 326 | 327 | return bot.getApp(); 328 | } 329 | ``` 330 | 331 | ### Give a widget some style 332 | To change the look of each widget, you can use the optional _styles_ property which accepts a set of css styles. 333 | 334 | ```javascript 335 | function doGet() { 336 | 337 | var bot = new UiBot.UiBot({ 338 | 339 | title: 'Test App!', 340 | items: [{ 341 | wType : 'Label', 342 | text : 'This is a label!', 343 | styles : { 344 | 'font-size' : 20, 345 | 'color' : 'blue' 346 | } 347 | }] 348 | 349 | }); 350 | 351 | return bot.getApp(); 352 | } 353 | ``` 354 | 355 | ### Handle clicks on the client 356 | onClick handlers can also work on the client side to offer a faster response to the user. Let's create handlers that toggle two labels. The _show_ and _hide_ properties accept an array of widget ids. There are also properties to _enable_ and _disable_ widgets, which also take an array of widget ids. 357 | 358 | ```javascript 359 | function doGet() { 360 | 361 | var bot = new UiBot.UiBot({ 362 | 363 | title: 'ui test', 364 | items: [{ 365 | 366 | wType : 'Label', 367 | text : 'This is label 1', 368 | id : 'label1', 369 | styles : { 'font-size' : 30 }, 370 | onClick : { 'show' : 'label2' } 371 | 372 | },{ 373 | 374 | wType : 'Label', 375 | text : 'This is label 2', 376 | id : 'label2', 377 | visible : false, 378 | styles : { 'font-size' : 30 }, 379 | onClick : { 'hide' : ['label1', 'label2'] } 380 | 381 | }] 382 | 383 | }); 384 | 385 | return bot.getApp(); 386 | } 387 | ``` 388 | 389 | ### Handle clicks on the server 390 | UiBot also makes it simple to add server side click handlers to buttons and other widgets. An _onClick_ property can accept an object with the name of a _callback_ function and an optional element id to be passed to this function (the _cbElementId_ property). Note that Google Apps Script scopes the callback to the libary where it was created, so for now your server callback must be placed in the UiBot namespace (see the example below). 391 | 392 | 393 | ```javascript 394 | function doGet() { 395 | 396 | var buttons = { 397 | wType : 'HorizontalPanel', 398 | items : [{ 399 | wType : 'Button', 400 | text : 'Submit', 401 | onClick : { 402 | callback: 'submitHandler', 403 | cbElementId: 'mainForm' 404 | } 405 | }] 406 | }; 407 | 408 | var form = { 409 | wType : 'HorizontalForm', 410 | id : 'mainForm', 411 | items : [{ 412 | fieldLabel : 'Period:', 413 | wType : 'ListBox', 414 | name : 'period', 415 | data : ["Day", "Month","Quarter", "Year"], 416 | selected : "Month" 417 | }] 418 | }; 419 | 420 | var bot = new UiBot.UiBot({ 421 | title: 'Test App!', 422 | items: [ form, buttons ] 423 | }); 424 | 425 | return bot.getApp(); 426 | 427 | } 428 | 429 | UiBot.submitHandler = function(e) { 430 | Browser.msgBox(e.parameter.period); 431 | } 432 | ``` 433 | 434 | ## Code 435 | The code for UiBot is released under the permissive MIT license and was written in [CoffeeScript](http://coffeescript.org) and compiled to Javascript. It is available on Github at https://github.com/gotdan/UiBot. Inspiration for the design came from [ExtJs](http://www.sencha.com/products/extjs/) 436 | 437 | ## Roadmap 438 | Future additions to UiBot may include support for other handlers and for validators. For now, you can build most of your interface in UiBot and then write non-click related handlers and validators using the traditional UI Service api. 439 | 440 | ## Contact 441 | Please feel free contact me with any questions or suggestions - dan at dan-gottlieb dot com. 442 | 443 | -------------------------------------------------------------------------------- /uibot.coffee: -------------------------------------------------------------------------------- 1 | class @UiBot 2 | 3 | ###* 4 | * Constructor 5 | * @param {object} config supports width, height and items properties 6 | * @returns {object} a new UiBot object 7 | ### 8 | constructor: (config) -> 9 | @ui_ = UiApp.createApplication() 10 | @handlers_ = [] 11 | @setProperties_ @ui_, config 12 | 13 | ###* 14 | * Create a widget and add it to the user interface 15 | * @param {object} config the widget's properties 16 | * @returns {object} the newly created widget 17 | ### 18 | addWidget: (config) -> 19 | widget = @createWidget(config) 20 | @ui_.add widget 21 | return widget 22 | 23 | ###* 24 | * Create a widget 25 | * @param {object} config the widget's properties 26 | * @returns {object} the newly created widget 27 | ### 28 | createWidget: (config) -> 29 | if config.wType is "HorizontalForm" 30 | widget = @createHorizontalForm_(config) 31 | else 32 | unless config.wType and @ui_["create#{config.wType}"] 33 | throw new Error("Invalid Widget Type") 34 | widget = @ui_["create#{config.wType}"]() 35 | @setProperties_(widget, config) 36 | return widget 37 | 38 | setProperties_: (widget, properties) -> 39 | for key, value of properties 40 | if key is "data" 41 | @setData_(widget, value, properties.selected) 42 | else if key is "styles" 43 | @setStyles_(widget, value) 44 | else if key is "items" 45 | @createChildren_(widget, value) 46 | else if key is "onClick" 47 | #process after all elements are added 48 | @handlers_.push [widget,'click', value] 49 | else 50 | @setSimpleProperty_(widget, key, value) 51 | 52 | return widget 53 | 54 | createChildren_: (widget, items) -> 55 | for item in items 56 | widget.add @createWidget(item) 57 | 58 | setData_: (widget, data, defaultValue) -> 59 | for item, i in data 60 | if (item instanceof Array) 61 | itemName = item[0] 62 | itemValue = item[1] 63 | else 64 | itemName = itemValue = item 65 | 66 | widget.addItem(itemName, itemValue) 67 | if itemValue is defaultValue 68 | widget.setSelectedIndex(i) 69 | 70 | setStyles_: (widget, styles) -> 71 | unless (styles instanceof Object) 72 | throw new Error("Styles must be an instance of object") 73 | for key, value of styles 74 | widget.setStyleAttribute(key, value) 75 | 76 | setSimpleProperty_: (widget, key, value) -> 77 | if widget["set#{@capitalize_ key}"] 78 | if (value instanceof Array) 79 | widget["set#{@capitalize_ key}"](value...) 80 | else 81 | widget["set#{@capitalize_ key}"](value) 82 | 83 | capitalize_: (word) -> 84 | word[0].toUpperCase() + word[1..-1] 85 | 86 | createHorizontalForm_: (config) -> 87 | return unless config.items 88 | grid = @ui_.createGrid(config.items.length, 2) 89 | grid.setId(config.id) if config.id 90 | 91 | for row, i in config.items 92 | row.name ||= row.id 93 | if row.fieldLabel 94 | grid.setText(i, 0, row.fieldLabel) 95 | if row.wType 96 | if row.name and !row.id 97 | row.id = row.name 98 | grid.setWidget i, 1, @createWidget(row) 99 | 100 | return grid 101 | 102 | applyHandlers_: -> 103 | targetIdsToTargets = (targetIds) => 104 | if typeof(targetIds) is "string" 105 | targetIds = [targetIds] 106 | (@ui_.getElementById(targetId) for targetId in targetIds) 107 | 108 | createClientHandler = (targetIds, handlerType, toggle) => 109 | targets = targetIdsToTargets(targetIds) 110 | handler = @ui_.createClientHandler().forTargets(targets) 111 | handler["set#{@capitalize_(handlerType)}"](toggle) 112 | return handler 113 | 114 | createServerHandler = (callback, cbElementId) => 115 | handler = @ui_.createServerHandler callback 116 | if cbElementId 117 | cbElement = @ui_.getElementById cbElementId 118 | handler.addCallbackElement(cbElement) 119 | return handler 120 | 121 | for handler in @handlers_ 122 | widget = handler[0] 123 | config = handler[2] 124 | 125 | for k, v of config 126 | uiHandler = 127 | if k is "show" 128 | createClientHandler(v,'visible', true) 129 | else if k is "hide" 130 | createClientHandler(v, 'visible', false) 131 | else if k is "enable" 132 | createClientHandler(v, 'enabled', true) 133 | else if k is "disable" 134 | createClientHandler(v, 'enabled', false) 135 | else if k is "callback" 136 | createServerHandler(v, config.cbElementId) 137 | widget.addClickHandler(uiHandler) if uiHandler 138 | 139 | ###* 140 | * Get the Google UiInstance associated with this UiBot instance 141 | * @returns {UiApp} the Google UiApp instance 142 | ### 143 | getApp: -> 144 | @applyHandlers_() 145 | return @ui_ -------------------------------------------------------------------------------- /uibot.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | this.UiBot = (function() { 4 | /** 5 | * Constructor 6 | * @param {object} config supports width, height and items properties 7 | * @returns {object} a new UiBot object 8 | */ 9 | function UiBot(config) { 10 | this.ui_ = UiApp.createApplication(); 11 | this.handlers_ = []; 12 | this.setProperties_(this.ui_, config); 13 | } 14 | 15 | /** 16 | * Create a widget and add it to the user interface 17 | * @param {object} config the widget's properties 18 | * @returns {object} the newly created widget 19 | */ 20 | 21 | UiBot.prototype.addWidget = function(config) { 22 | var widget; 23 | widget = this.createWidget(config); 24 | this.ui_.add(widget); 25 | return widget; 26 | }; 27 | 28 | /** 29 | * Create a widget 30 | * @param {object} config the widget's properties 31 | * @returns {object} the newly created widget 32 | */ 33 | 34 | UiBot.prototype.createWidget = function(config) { 35 | var widget; 36 | if (config.wType === "HorizontalForm") { 37 | widget = this.createHorizontalForm_(config); 38 | } else { 39 | if (!(config.wType && this.ui_["create" + config.wType])) { 40 | throw new Error("Invalid Widget Type"); 41 | } 42 | widget = this.ui_["create" + config.wType](); 43 | this.setProperties_(widget, config); 44 | } 45 | return widget; 46 | }; 47 | 48 | UiBot.prototype.setProperties_ = function(widget, properties) { 49 | var key, value; 50 | for (key in properties) { 51 | value = properties[key]; 52 | if (key === "data") { 53 | this.setData_(widget, value, properties.selected); 54 | } else if (key === "styles") { 55 | this.setStyles_(widget, value); 56 | } else if (key === "items") { 57 | this.createChildren_(widget, value); 58 | } else if (key === "onClick") { 59 | this.handlers_.push([widget, 'click', value]); 60 | } else { 61 | this.setSimpleProperty_(widget, key, value); 62 | } 63 | } 64 | return widget; 65 | }; 66 | 67 | UiBot.prototype.createChildren_ = function(widget, items) { 68 | var item, _i, _len, _results; 69 | _results = []; 70 | for (_i = 0, _len = items.length; _i < _len; _i++) { 71 | item = items[_i]; 72 | _results.push(widget.add(this.createWidget(item))); 73 | } 74 | return _results; 75 | }; 76 | 77 | UiBot.prototype.setData_ = function(widget, data, defaultValue) { 78 | var i, item, itemName, itemValue, _len, _results; 79 | _results = []; 80 | for (i = 0, _len = data.length; i < _len; i++) { 81 | item = data[i]; 82 | if (item instanceof Array) { 83 | itemName = item[0]; 84 | itemValue = item[1]; 85 | } else { 86 | itemName = itemValue = item; 87 | } 88 | widget.addItem(itemName, itemValue); 89 | if (itemValue === defaultValue) { 90 | _results.push(widget.setSelectedIndex(i)); 91 | } else { 92 | _results.push(void 0); 93 | } 94 | } 95 | return _results; 96 | }; 97 | 98 | UiBot.prototype.setStyles_ = function(widget, styles) { 99 | var key, value, _results; 100 | if (!(styles instanceof Object)) { 101 | throw new Error("Styles must be an instance of object"); 102 | } 103 | _results = []; 104 | for (key in styles) { 105 | value = styles[key]; 106 | _results.push(widget.setStyleAttribute(key, value)); 107 | } 108 | return _results; 109 | }; 110 | 111 | UiBot.prototype.setSimpleProperty_ = function(widget, key, value) { 112 | if (widget["set" + (this.capitalize_(key))]) { 113 | if (value instanceof Array) { 114 | return widget["set" + (this.capitalize_(key))].apply(widget, value); 115 | } else { 116 | return widget["set" + (this.capitalize_(key))](value); 117 | } 118 | } 119 | }; 120 | 121 | UiBot.prototype.capitalize_ = function(word) { 122 | return word[0].toUpperCase() + word.slice(1); 123 | }; 124 | 125 | UiBot.prototype.createHorizontalForm_ = function(config) { 126 | var grid, i, row, _len, _ref; 127 | if (!config.items) return; 128 | grid = this.ui_.createGrid(config.items.length, 2); 129 | if (config.id) grid.setId(config.id); 130 | _ref = config.items; 131 | for (i = 0, _len = _ref.length; i < _len; i++) { 132 | row = _ref[i]; 133 | row.name || (row.name = row.id); 134 | if (row.fieldLabel) grid.setText(i, 0, row.fieldLabel); 135 | if (row.wType) { 136 | if (row.name && !row.id) row.id = row.name; 137 | grid.setWidget(i, 1, this.createWidget(row)); 138 | } 139 | } 140 | return grid; 141 | }; 142 | 143 | UiBot.prototype.applyHandlers_ = function() { 144 | var config, createClientHandler, createServerHandler, handler, k, targetIdsToTargets, uiHandler, v, widget, _i, _len, _ref, _results, 145 | _this = this; 146 | targetIdsToTargets = function(targetIds) { 147 | var targetId, _i, _len, _results; 148 | if (typeof targetIds === "string") targetIds = [targetIds]; 149 | _results = []; 150 | for (_i = 0, _len = targetIds.length; _i < _len; _i++) { 151 | targetId = targetIds[_i]; 152 | _results.push(_this.ui_.getElementById(targetId)); 153 | } 154 | return _results; 155 | }; 156 | createClientHandler = function(targetIds, handlerType, toggle) { 157 | var handler, targets; 158 | targets = targetIdsToTargets(targetIds); 159 | handler = _this.ui_.createClientHandler().forTargets(targets); 160 | handler["set" + (_this.capitalize_(handlerType))](toggle); 161 | return handler; 162 | }; 163 | createServerHandler = function(callback, cbElementId) { 164 | var cbElement, handler; 165 | handler = _this.ui_.createServerHandler(callback); 166 | if (cbElementId) { 167 | cbElement = _this.ui_.getElementById(cbElementId); 168 | handler.addCallbackElement(cbElement); 169 | } 170 | return handler; 171 | }; 172 | _ref = this.handlers_; 173 | _results = []; 174 | for (_i = 0, _len = _ref.length; _i < _len; _i++) { 175 | handler = _ref[_i]; 176 | widget = handler[0]; 177 | config = handler[2]; 178 | _results.push((function() { 179 | var _results2; 180 | _results2 = []; 181 | for (k in config) { 182 | v = config[k]; 183 | uiHandler = k === "show" ? createClientHandler(v, 'visible', true) : k === "hide" ? createClientHandler(v, 'visible', false) : k === "enable" ? createClientHandler(v, 'enabled', true) : k === "disable" ? createClientHandler(v, 'enabled', false) : k === "callback" ? createServerHandler(v, config.cbElementId) : void 0; 184 | if (uiHandler) { 185 | _results2.push(widget.addClickHandler(uiHandler)); 186 | } else { 187 | _results2.push(void 0); 188 | } 189 | } 190 | return _results2; 191 | })()); 192 | } 193 | return _results; 194 | }; 195 | 196 | /** 197 | * Get the Google UiInstance associated with this UiBot instance 198 | * @returns {UiApp} the Google UiApp instance 199 | */ 200 | 201 | UiBot.prototype.getApp = function() { 202 | this.applyHandlers_(); 203 | return this.ui_; 204 | }; 205 | 206 | return UiBot; 207 | 208 | })(); 209 | 210 | }).call(this); 211 | --------------------------------------------------------------------------------