1 /** 2 * Copyright (C) 2005-2010 Alfresco Software Limited. 3 * 4 * This file is part of Alfresco 5 * 6 * Alfresco is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU Lesser General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * Alfresco is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public License 17 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 /** 21 * Form UI component. 22 * 23 * @namespace Alfresco 24 * @class Alfresco.FormUI 25 */ 26 (function() 27 { 28 /** 29 * YUI Library aliases 30 */ 31 var Dom = YAHOO.util.Dom, 32 Event = YAHOO.util.Event, 33 Element = YAHOO.util.Element; 34 35 /** 36 * FormUI constructor. 37 * 38 * @param {String} htmlId The HTML id of the parent element 39 * @return {Alfresco.FormUI} The new FormUI instance 40 * @constructor 41 */ 42 Alfresco.FormUI = function FormUI_constructor(htmlId, parentId) 43 { 44 Alfresco.FormUI.superclass.constructor.call(this, "Alfresco.FormUI", htmlId, ["button", "menu", "container"]); 45 46 // Initialise prototype properties 47 this.parentId = parentId; 48 this.buttons = {}; 49 this.formsRuntime = null; 50 this.eventGroup = htmlId; 51 52 /* Decoupled event listeners */ 53 YAHOO.Bubbling.on("metadataRefresh", this.onFormRefresh, this); 54 YAHOO.Bubbling.on("mandatoryControlValueUpdated", this.onMandatoryControlValueUpdated, this); 55 YAHOO.Bubbling.on("registerValidationHandler", this.onRegisterValidationHandler, this); 56 YAHOO.Bubbling.on("addSubmitElement", this.onAddSubmitElement, this); 57 58 return this; 59 }; 60 61 /** 62 * Extend from Base component 63 */ 64 YAHOO.extend(Alfresco.FormUI, Alfresco.component.Base, 65 { 66 /** 67 * Object container for initialization options 68 * 69 * @property options 70 * @type object 71 */ 72 options: 73 { 74 /** 75 * Mode the current form is in, can be "view", "edit" or "create", defaults to "edit". 76 * 77 * @property mode 78 * @type string 79 */ 80 mode: "edit", 81 82 /** 83 * Encoding type to be used when the form is submitted, can be "multipart/form-data", 84 * "application/x-www-form-urlencoded" or "application/json", defaults to "multipart/form-data". 85 * 86 * @property enctype 87 * @type string 88 */ 89 enctype: "multipart/form-data", 90 91 /** 92 * List of objects representing the id of each form field 93 * 94 * @property fields 95 * @type array[object] 96 */ 97 fields: [], 98 99 /** 100 * List of objects representing the constraints to setup on the form fields 101 * 102 * @property fieldConstraints 103 * @type array[object] 104 */ 105 fieldConstraints: [], 106 107 /** 108 * Arguments used to build the form. 109 * Used to Ajax-rebuild the form when in "view" mode 110 * 111 * @property arguments 112 * @type object 113 */ 114 arguments: {} 115 }, 116 117 /** 118 * Object container for storing YUI button instances. 119 * 120 * @property buttons 121 * @type object 122 */ 123 buttons: null, 124 125 /** 126 * The forms runtime instance. 127 * 128 * @property 129 * @type object 130 */ 131 formsRuntime: null, 132 133 /** 134 * Fired by YUI when parent element is available for scripting. 135 * Component initialisation, including instantiation of YUI widgets and event listener binding. 136 * 137 * @method onReady 138 */ 139 onReady: function FormUI_onReady() 140 { 141 if (this.options.mode !== "view") 142 { 143 // make buttons YUI buttons 144 145 if (Dom.get(this.id + "-submit") !== null) 146 { 147 this.buttons.submit = Alfresco.util.createYUIButton(this, "submit", null, 148 { 149 type: "submit" 150 }); 151 152 // force the generated button to have a name of "-" so it gets ignored in 153 // JSON submit. TODO: remove this when JSON submit behaviour is configurable 154 Dom.get(this.id + "-submit-button").name = "-"; 155 } 156 157 if (Dom.get(this.id + "-reset") !== null) 158 { 159 this.buttons.reset = Alfresco.util.createYUIButton(this, "reset", null, 160 { 161 type: "reset" 162 }); 163 164 // force the generated button to have a name of "-" so it gets ignored in 165 // JSON submit. TODO: remove this when JSON submit behaviour is configurable 166 Dom.get(this.id + "-reset-button").name = "-"; 167 } 168 169 if (Dom.get(this.id + "-cancel") !== null) 170 { 171 this.buttons.cancel = Alfresco.util.createYUIButton(this, "cancel", null); 172 173 // force the generated button to have a name of "-" so it gets ignored in 174 // JSON submit. TODO: remove this when JSON submit behaviour is configurable 175 Dom.get(this.id + "-cancel-button").name = "-"; 176 } 177 178 // fire event to inform any listening components that the form HTML is ready 179 YAHOO.Bubbling.fire("formContentReady", this); 180 181 this.formsRuntime = new Alfresco.forms.Form(this.id); 182 this.formsRuntime.setShowSubmitStateDynamically(true, false); 183 this.formsRuntime.setSubmitElements(this.buttons.submit); 184 185 // setup JSON/AJAX mode if appropriate 186 if (this.options.enctype === "application/json") 187 { 188 this.formsRuntime.setAJAXSubmit(true, 189 { 190 successCallback: 191 { 192 fn: this.onJsonPostSuccess, 193 scope: this 194 }, 195 failureCallback: 196 { 197 fn: this.onJsonPostFailure, 198 scope: this 199 } 200 }); 201 this.formsRuntime.setSubmitAsJSON(true); 202 } 203 204 // add field help 205 for (var f = 0; f < this.options.fields.length; f++) 206 { 207 var ff = this.options.fields[f], 208 iconEl = Dom.get(this.parentId + "_" + ff.id + "-help-icon"); 209 if (iconEl) 210 { 211 Alfresco.util.useAsButton(iconEl, this.toggleHelpText, ff.id, this); 212 } 213 } 214 215 // add any field constraints present 216 for (var c = 0; c < this.options.fieldConstraints.length; c++) 217 { 218 var fc = this.options.fieldConstraints[c]; 219 this.formsRuntime.addValidation(fc.fieldId, fc.handler, fc.params, fc.event, fc.message); 220 } 221 222 // fire event to inform any listening components that the form is about to be initialised 223 YAHOO.Bubbling.fire("beforeFormRuntimeInit", 224 { 225 eventGroup: this.eventGroup, 226 component: this, 227 runtime: this.formsRuntime 228 }); 229 230 this.formsRuntime.init(); 231 232 // fire event to inform any listening components that the form has finished initialising 233 YAHOO.Bubbling.fire("afterFormRuntimeInit", 234 { 235 eventGroup: this.eventGroup, 236 component: this, 237 runtime: this.formsRuntime 238 }); 239 } 240 }, 241 242 /** 243 * Toggles help text for a field. 244 * 245 * @method toggleHelpText 246 * @param event The user event 247 * @param fieldId The id of the field to toggle help text for 248 */ 249 toggleHelpText: function FormUI_toggleHelpText(event, fieldId) 250 { 251 Alfresco.util.toggleHelpText(this.parentId + "_" + fieldId + "-help"); 252 }, 253 254 /** 255 * Default handler used when submit mode is JSON and the sumbission was successful 256 * 257 * @method onJsonPostSuccess 258 * @param response The response from the submission 259 */ 260 onJsonPostSuccess: function FormUI_onJsonPostSuccess(response) 261 { 262 // TODO: Display the JSON response here by default, when it's returned! 263 264 Alfresco.util.PopupManager.displayPrompt( 265 { 266 text: response.serverResponse.responseText 267 }); 268 }, 269 270 /** 271 * Default handler used when submit mode is JSON and the sumbission failed 272 * 273 * @method onJsonPostFailure 274 * @param response The response from the submission 275 */ 276 onJsonPostFailure: function FormUI_onJsonPostFailure(response) 277 { 278 var errorMsg = this._msg("form.jsonsubmit.failed"); 279 if (response.json && response.json.message) 280 { 281 errorMsg = errorMsg + ": " + response.json.message; 282 } 283 284 Alfresco.util.PopupManager.displayPrompt( 285 { 286 text: errorMsg 287 }); 288 }, 289 290 /** 291 * Form refresh event handler 292 * 293 * @method onFormRefresh 294 * @param layer {object} Event fired 295 * @param args {array} Event parameters (depends on event type) 296 */ 297 onFormRefresh: function FormUI_onFormRefresh(layer, args) 298 { 299 // Can't do anything if basic arguments weren't set 300 if (this.options.arguments) 301 { 302 var itemKind = this.options.arguments.itemKind, 303 itemId = this.options.arguments.itemId, 304 formId = this.options.arguments.formId; 305 306 if (itemKind && itemId) 307 { 308 var fnFormLoaded = function(response, p_formUI) 309 { 310 Alfresco.util.populateHTML( 311 [ p_formUI.parentId, response.serverResponse.responseText ] 312 ); 313 }; 314 315 var data = 316 { 317 htmlid: this.parentId, 318 formUI: false, 319 mode: this.options.mode, 320 itemKind: itemKind, 321 itemId: itemId, 322 formId: formId 323 }; 324 325 Alfresco.util.Ajax.request( 326 { 327 url: Alfresco.constants.URL_SERVICECONTEXT + "components/form", 328 dataObj: data, 329 successCallback: 330 { 331 fn: fnFormLoaded, 332 obj: this, 333 scope: this 334 }, 335 scope: this, 336 execScripts: true 337 }); 338 } 339 } 340 }, 341 342 /** 343 * Mandatory control value updated event handler 344 * 345 * @method onMandatoryControlValueUpdated 346 * @param layer {object} Event fired 347 * @param args {array} Event parameters (depends on event type) 348 */ 349 onMandatoryControlValueUpdated: function FormUI_onMandatoryControlValueUpdated(layer, args) 350 { 351 // the value of a mandatory control on the page (usually represented by a hidden field) 352 // has been updated, force the forms runtime to check if form state is still valid 353 if (this.formsRuntime) 354 { 355 this.formsRuntime.updateSubmitElements(); 356 } 357 }, 358 359 /** 360 * Register validation handler event handler 361 * 362 * @method onRegisterValidationHandler 363 * @param layer {object} Event fired 364 * @param args {array} Event parameters (depends on event type) 365 */ 366 onRegisterValidationHandler: function FormUI_onRegisterValidationHandler(layer, args) 367 { 368 if (this.formsRuntime) 369 { 370 // extract the validation arguments 371 var validation = args[1]; 372 373 // check the minimim required data is provided 374 if (validation && validation.fieldId && validation.handler) 375 { 376 // register with the forms runtime instance 377 this.formsRuntime.addValidation(validation.fieldId, validation.handler, validation.args, 378 validation.when, validation.message); 379 } 380 } 381 }, 382 383 /** 384 * Adds a submit element to the form runtime instance 385 * 386 * @method onAddSubmitElement 387 * @param layer {object} Event fired 388 * @param args {array} Event parameters (depends on event type) 389 */ 390 onAddSubmitElement: function FormUI_onAddSubmitElement(layer, args) 391 { 392 // extract the submit element to add 393 var submitElement = args[1]; 394 395 // add to the forms runtime instance, if there is one 396 if (this.formsRuntime != null) 397 { 398 this.formsRuntime.addSubmitElement(submitElement); 399 } 400 } 401 }); 402 })(); 403 404 405 /** 406 * Helper function to add the current state of the given multi-select list to 407 * the given hidden field. 408 * 409 * @method updateMultiSelectListValue 410 * @param list {string} The id of the multi-select element 411 * @param hiddenField {string} The id of the hidden field to populate the value with 412 * @param signalChange {boolean} If true a bubbling event is sent to inform any 413 * interested listeners that the hidden field value changed 414 * @static 415 */ 416 Alfresco.util.updateMultiSelectListValue = function(list, hiddenField, signalChange) 417 { 418 var listElement = YUIDom.get(list); 419 420 if (listElement !== null) 421 { 422 var values = new Array(); 423 for (var j = 0, jj = listElement.options.length; j < jj; j++) 424 { 425 if (listElement.options[j].selected) 426 { 427 values.push(listElement.options[j].value); 428 } 429 } 430 431 YUIDom.get(hiddenField).value = values.join(","); 432 433 if (signalChange) 434 { 435 YAHOO.Bubbling.fire("mandatoryControlValueUpdated", this); 436 } 437 } 438 }; 439 440 /** 441 * Helper function to toggle the state of the help text element 442 * represented by the given id. 443 * 444 * @method toggleHelpText 445 * @param helpTextId The id of the help text element to toggle 446 * @static 447 */ 448 Alfresco.util.toggleHelpText = function(helpTextId) 449 { 450 var helpElem = YUIDom.get(helpTextId); 451 452 if (helpElem) 453 { 454 if (helpElem.style.display != "block") 455 { 456 helpElem.style.display = "block"; 457 } 458 else 459 { 460 helpElem.style.display = "none"; 461 } 462 } 463 }; 464 465