1 /** 2 * @class Ozone.layout.CreateViewContainer 3 * @extends Ext.form.Panel 4 */ 5 Ext.define('Ozone.layout.CreateViewContainer', { 6 extend: 'Ext.form.Panel', 7 alias: [ 8 'widget.owfCreateDashboardsContainer', 9 'widget.owfCreateViewsContainer', 10 'widget.Ozone.layout.CreateViewContainer' 11 ], 12 requires: [ 13 'Ext.layout.container.Border' 14 ], 15 border: false, 16 config: {}, 17 views: null, 18 dashboardContainer: null, 19 itemId: 'createNewDashboardPanel', 20 cls: 'cvc-createNewDashboardContainer', 21 afterRenderInitComplete: false, 22 createViewContainer_FormValid: true, 23 hideViewSelectRadio: false, 24 25 initComponent: function() { 26 this.config = this.dashboardContainer.activeDashboard.config; 27 this.views = this.dashboardContainer.dashboards; 28 29 this.addEvents('saved', 'failed'); 30 31 this.titleBox = { 32 xtype: 'textfield', 33 name: 'titleBox', 34 cls: 'titleBox', 35 itemId: 'titleBox', //OWF-2558 36 fieldLabel: Ozone.util.createRequiredLabel(Ozone.ux.DashboardMgmtString.title), 37 labelSeparator: '', 38 labelWidth: undefined, 39 allowBlank: false, 40 maxLength: 200, 41 value: '', 42 enforceMaxLength: true, 43 listeners: { 44 blur: function(field){ 45 // Remove leading and tailing spaces 46 var val = field.getValue().replace(new RegExp(Ozone.lang.regexLeadingTailingSpaceChars), ''); 47 field.setValue(val); 48 } 49 } 50 }; 51 52 this.description = { 53 xtype: 'textareafield', 54 name: 'description', 55 cls: 'description', 56 itemId: 'description', 57 fieldLabel: Ozone.ux.DashboardMgmtString.description, 58 labelSeparator: '', 59 labelWidth: undefined, 60 value: '', 61 maxLength: 4000, 62 enforceMaxLength: true 63 }; 64 65 if (this.existingDashboardRecord != null) { 66 this.titleBox.value = this.existingDashboardRecord.get('name'); 67 this.description.value = this.existingDashboardRecord.get('description'); 68 } 69 70 this.existingViewRadio = { 71 boxLabel: Ozone.layout.CreateViewWindowString.createFromExisiting, 72 name: 'viewSelectRadio', 73 inputValue: "copiedDashboard", 74 cls:'existingViewRadio', 75 //tabIndex: 2, 76 listeners: { 77 'change': { 78 fn: function(radio, newValue, oldValue) { 79 if(newValue) 80 { 81 // var cmp = this.down('#viewCb'); 82 // cmp.reset(); 83 // cmp.disable(); 84 85 var existViewCb = this.down('#existViewCb'); 86 existViewCb.enable(); 87 existViewCb.validate(); 88 89 var importFileupload = this.down('#importFileupload'); 90 importFileupload.reset(); 91 importFileupload.disable(); 92 } 93 }, 94 scope: this 95 } 96 }, 97 vtype: 'copiedDashboard', 98 copiedDashboardField: 'existViewCb' // id of the field to validate 99 }; 100 101 this.importedViewRadio = { 102 boxLabel: Ozone.layout.CreateViewWindowString.importView, 103 name: 'viewSelectRadio', 104 inputValue: "importedDashboard", 105 cls:'importedViewRadio', 106 //tabIndex: 3, 107 listeners: { 108 //this listener works for both since we can use the 'isSelected' param 109 'change': { 110 fn: function(radio, newValue, oldValue) { 111 if(newValue) { 112 var existViewCb = this.down('#existViewCb'); 113 existViewCb.reset(); 114 existViewCb.disable(); 115 116 var importFileupload = this.down('#importFileupload'); 117 importFileupload.enable(); 118 importFileupload.validate(); 119 } 120 }, 121 scope: this 122 } 123 }, 124 vtype: 'importedDashboard', 125 importedDashboardField: 'importFileupload' // id of the field to validate 126 }; 127 128 // Set default layout for creating a new dashboard 129 //this.newView.value = this.config.layout; 130 131 this.existingView = { 132 xtype: 'combo', 133 //tabIndex: 2, 134 //id: 'existViewCb', 135 itemId: 'existViewCb', 136 store: this.dashboardContainer.dashboardStore, 137 valueField:'guid', 138 displayField:'name', 139 hideLabel: true, 140 typeAhead: true, 141 queryMode: 'local', 142 value: null, 143 triggerAction: 'all', 144 editable: true, 145 selectOnFocus:true, 146 allowBlank:true, 147 forceSelection: true, 148 disabled: true, 149 width: 400 150 }; 151 this.existingView.value = this.views[0].guid; 152 153 function handleInvalidFileUpload(current) { 154 dashboardJson = null; 155 Ozone.Msg.alert(Ozone.util.ErrorMessageString.dashboardConfig, "Invalid configuration file.", function () { 156 current.focusTitleBox(); 157 }, current, null, current.dashboardContainer.modalWindowManager); 158 } 159 160 var container = this; 161 var dashboardJson = null; 162 var isSubmittingForm = false; 163 164 this.importedView = { 165 xtype: 'filefield', 166 //tabIndex: 3, 167 //id: 'importFileupload', 168 itemId: 'importFileupload', 169 cls: 'importFileupload', 170 name: 'importFileupload', 171 hideLabel: true, 172 label: '', 173 width: 400, 174 emptyText: Ozone.ux.DashboardMgmtString.uploadConfig, 175 allowBlank: true, 176 disabled: true, 177 buttonText:Ozone.ux.DashboardMgmtString.browse, 178 // buttonConfig: { 179 // ui: 'button' 180 // }, 181 listeners: { 182 afterrender: function (cmp) { 183 cmp.setupFocus = function() { 184 /* 185 * We need to have the file input be focusable, but 186 * have it appear that the button is what actually has focus 187 */ 188 189 var btnEl = this.button.getEl(); 190 var innerBtnEl = this.button.btnEl; 191 var fileInputEl = this.fileInputEl; 192 var allowFocus = true; 193 194 //set the <button> element and the text field to not be focusable 195 innerBtnEl.dom.tabIndex = -1; 196 cmp.inputEl.dom.tabIndex = -1; 197 198 fileInputEl.dom.tabIndex = 0; 199 fileInputEl.dom.hideFocus = true; 200 fileInputEl.dom.style.outlineStyle = 'none'; 201 202 cmp.mon(fileInputEl, 'focus', function() { 203 this.addCls('x-focus'); 204 }, btnEl); 205 206 cmp.mon(fileInputEl,'blur', function() { 207 this.removeCls('x-focus'); 208 }, btnEl); 209 210 function enableBorder() { 211 allowFocus = true; 212 } 213 214 cmp.mon(fileInputEl, { 215 mouseup: enableBorder, 216 mouseout: enableBorder 217 }); 218 }; 219 220 cmp.setupFocus(); 221 222 //override the reset function 223 cmp._reset = cmp.reset; 224 cmp.reset = function() { 225 226 if (!isSubmittingForm) { 227 this._reset.apply(this, arguments); 228 dashboardJson = null; 229 } 230 // this small block does exactly what the extjs reset does, except 231 // it does not clear out the inputEl value because we want to see 232 // the file in the input text field after selecting it. if the 233 // fileInputEl is not removed then created again, the browse button 234 // will not work a second time. 235 else { 236 if (this.rendered) { 237 this.fileInputEl.remove(); 238 this.createFileInput(); 239 } 240 this.callParent(); 241 } 242 243 this.setupFocus(); 244 } 245 }, 246 change: function( cmp, value, eOpts ) { 247 248 isSubmittingForm = true; 249 container.getForm().submit({ 250 clientValidation: false, 251 reset: false, 252 url: Ozone.util.contextPath() + '/servlet/FileServlet', 253 waitMsg: 'Reading file...', 254 success: function (fp, action) { 255 256 dashboardJson = Ozone.util.parseJson(action.response.responseText).value; 257 258 if (!Ozone.util.validateDashboardJSON(dashboardJson)) { 259 handleInvalidFileUpload(); 260 } 261 else { 262 263 // if the description field is empty, fill it in with the imported description field, otherwise do nothing 264 if (container.getComponent('description').getValue() == null || container.getComponent('description').getValue() == "") { 265 container.getComponent('description').setValue(dashboardJson.description); 266 } 267 } 268 isSubmittingForm = false; 269 }, 270 failure: Ext.bind(function (form, action) { 271 handleInvalidFileUpload(container); 272 isSubmittingForm = false; 273 }, container) 274 }); 275 } 276 } 277 }; 278 279 280 //RadioGroup and CheckboxGroup does not properly validate other form fields that are not radio/checkboxes 281 //when mixed with radio/checkbox fields because it assumes if any radio/checkbox is checked it can assume the 282 //entire group is valid 283 this.viewSelectRadio = { 284 layout: { 285 type: 'hbox', 286 align: 'stretchmax' 287 }, 288 cls: 'createSelector', 289 region: 'center', 290 allowBlank: false, 291 hideLabel: true, 292 hidden: this.hideViewSelectRadio, 293 items: [ 294 [ 295 { 296 xtype: 'radiogroup', 297 flex: 1, 298 cls: 'viewSelect', 299 itemId: "viewSelect", //OWF-2558 300 layout: { 301 type: 'vbox', 302 align: 'stretch' 303 }, 304 defaults: { 305 flex: 1 306 }, 307 items: [ 308 this.existingViewRadio, 309 this.importedViewRadio 310 ] 311 }, 312 { 313 layout: { 314 type: 'vbox', 315 align: 'stretch' 316 }, 317 cls: 'viewSelectBoxes', 318 flex: 1, 319 defaults: { 320 flex: 1 321 }, 322 items: [ 323 this.existingView, 324 this.importedView 325 ] 326 } 327 ] 328 ] 329 }; 330 331 this.layout = { 332 type: 'vbox', 333 align: 'stretch' 334 }; 335 this.items = [ 336 this.titleBox, 337 this.description, 338 this.viewSelectRadio 339 ]; 340 341 this.dockedItems = [{ 342 xtype: 'toolbar', 343 dock: 'bottom', 344 defaults: { 345 minWidth: this.minButtonWidth 346 }, 347 items: [{ 348 xtype: 'tbfill' 349 },{ 350 xtype:'button', 351 scale: 'small', 352 text: Ozone.layout.DialogMessages.ok, 353 itemId: 'saveButton', 354 //iconCls: 'okSaveBtnIcon', 355 //tabIndex: 4, 356 handler: function (button, event) { 357 if (this.getForm().isValid() && this.createViewContainer_FormValid) { 358 Ozone.util.formField.removeLeadingTrailingSpaces(this.getComponent('titleBox')); 359 //make sure name is unique 360 Ext.getCmp('mainPanel').saveActiveDashboardToServer(); 361 362 var title = this.getComponent('titleBox').getValue(); 363 var desc = this.getComponent('description').getValue(); 364 365 // add a space to the field if it is empty or null so that it will 366 // store an empty string to the db instead of it thinking its a null value 367 if (desc == null || desc == '') 368 desc = ' '; 369 370 //edit an existing dashboard if a record was passed in 371 if (this.existingDashboardRecord != null) { 372 this.existingDashboardRecord.set('name',title); 373 this.existingDashboardRecord.set('description',desc); 374 this.dashboardContainer.editDashboard(this.existingDashboardRecord); 375 this.close(); 376 } 377 //else create a new one 378 else { 379 380 var radioSelection = this.down('#viewSelect').getValue().viewSelectRadio; 381 var isCreateFromExisting = (radioSelection == "copiedDashboard") ? true : false; 382 var isImport = (radioSelection == "importedDashboard") ? true : false; 383 384 //create new from existing 385 if (isCreateFromExisting) { 386 var existingViewSelected = this.down('#existViewCb').getValue(); 387 388 if (Ext.isEmpty(existingViewSelected)) { 389 this.down('#existViewCb').markInvalid("This field cannot be blank."); 390 Ozone.Msg.alert(Ozone.util.ErrorMessageString.invalidForm, Ozone.util.ErrorMessageString.invalidFormMsg, function () { 391 this.focusTitleBox(); 392 }, this, null, this.dashboardContainer.modalWindowManager); 393 return; 394 } 395 396 var existingViewToDuplicate = this.dashboardContainer.dashboardStore.getById(existingViewSelected).data; 397 existingViewToDuplicate = Ozone.util.cloneDashboard(existingViewToDuplicate, true); 398 399 existingViewToDuplicate.name = title; 400 existingViewToDuplicate.description = desc; 401 existingViewToDuplicate.isdefault = false; 402 403 Ext.getCmp('mainPanel').createDashboard( 404 Ext.create('Ozone.data.Dashboard', existingViewToDuplicate) 405 ); 406 407 this.close(); 408 } 409 //create new from import 410 else if (isImport) { 411 //check if the dashboardJson has been set from file upload 412 if (dashboardJson != null) { 413 414 // Reset title 415 dashboardJson.name = title; 416 dashboardJson.description = desc; 417 418 // make sure the right type of json is being imported 419 if (!Ozone.util.validateDashboardJSON(dashboardJson)) { 420 Ozone.Msg.alert(Ozone.util.ErrorMessageString.dashboardConfig, "Invalid " + dashboardJson.layout + " configuration file.", function () { 421 this.focusTitleBox(); 422 }, this, null, this.dashboardContainer.modalWindowManager); 423 } 424 else { 425 delete dashboardJson.state; 426 427 Ext.getCmp('mainPanel').createDashboard( 428 Ext.create('Ozone.data.Dashboard', Ozone.util.cloneDashboard(dashboardJson, true)) 429 ); 430 this.close(); 431 } 432 } 433 else { 434 Ozone.Msg.alert(Ozone.util.ErrorMessageString.invalidForm, Ozone.util.ErrorMessageString.invalidFormMsg, function () { 435 this.focusTitleBox(); 436 }, this, null, this.dashboardContainer.modalWindowManager); 437 } 438 } 439 //create new using name, and description 440 else { 441 Ext.getCmp('mainPanel').createDashboard( 442 Ext.create('Ozone.data.Dashboard', { 443 "name": title, 444 "description": desc 445 }) 446 ); 447 this.close(); 448 } 449 } 450 } 451 else { 452 Ozone.Msg.alert(Ozone.util.ErrorMessageString.invalidForm, Ozone.util.ErrorMessageString.invalidFormMsg, function () { 453 this.focusTitleBox(); 454 }, this, null, this.dashboardContainer.modalWindowManager); 455 } 456 }, 457 scope: this, 458 listeners: { 459 afterrender: function(button) { 460 button.getEl().on('keydown', function(e) { 461 e.stopPropagation(); //prevent keydown from bubbling up to the toolbar 462 }); 463 } 464 } 465 },{ 466 xtype:'button', 467 scale: 'small', 468 text: 'Cancel', 469 itemId: 'cancelBtn', 470 // iconCls: 'cancelBtnIcon', 471 scope: this, 472 handler: this.cancel 473 }] 474 }]; 475 476 //Need this to get rid of destory errors with ExtJS 477 this.on('beforedestroy', function(cmp){ 478 cmp.dockedItems = null; 479 }); 480 481 // this.on("afterrender", function(cmp) { 482 // cmp.focusTitleBox(); 483 // }); 484 485 this.callParent(); 486 }, 487 488 refreshData: function(){ 489 this.config = this.dashboardContainer.activeDashboard.config; 490 this.views = this.dashboardContainer.dashboards; 491 492 // Reset fields 493 var txtTitle = this.getComponent('titleBox'); 494 if (txtTitle) { 495 txtTitle.setRawValue(''); 496 } 497 498 var txtDescription = this.getComponent('description'); 499 if (txtDescription) { 500 txtDescription.setRawValue(''); 501 } 502 503 var txtImportFile = this.down('#importFileupload'); 504 if (txtImportFile) { 505 txtImportFile.setRawValue(''); 506 } 507 508 var cboViewSelect = this.getComponent('viewSelect'); 509 if (cboViewSelect) { 510 cboViewSelect.reset(); 511 } 512 513 var existingView = this.down('#existViewCb'); 514 existingView.setValue(this.views[0].guid); 515 }, 516 517 focusTitleBox: function() { 518 /* 519 * Have to defer this so that it happens after a focus that Ext does 520 * internally that is also deffered 521 */ 522 Ext.defer(function() { 523 this.getComponent('titleBox').focus(); 524 }, 500, this); 525 }, 526 527 cancel: function () { 528 this.close(); 529 }, 530 531 close: function() { 532 Ext.getCmp(this.winId).close(); 533 } 534 });