//Global Time Ext.Ajax.timeout = 10 * 60 *1000;//in ms = 10 mins #set ($UNRANKED_GROUP = $CommonFunctions.encodeJavaScriptString($CommonFunctions.getTermFromResourceBundle($currentUserId, "FocusBackend", "story.unranked"))) Ext.ImageButton = function(renderTo, config){ Ext.ImageButton.superclass.constructor.call(this, renderTo, config); }; Ext.extend(Ext.ImageButton, Ext.Button, { onRender : function(ct, position) { this.disabledImgPath = this.disabledImgPath || this.imgPath; this.pressedImgPath = this.pressedImgPath || this.imgPath; var tplHTML = '' + '' + '' + '' + '
{tooltip}    
  
{imgText}
' ; var tpl = new Ext.Template(tplHTML); var btn, targs = { imgPath : this.pressed ? this.pressedImgPath : this.imgPath, imgId: this.imgId || "", imgWidth : this.imgWidth || "", imgHeight : this.imgHeight || "", imgText : this.text || "", cursor : this.disabled ? "default" : "pointer", tooltip : this.tooltip || "" }; btn = tpl.append(ct, targs, true); btn.on("click", this.onClick, this); if (this.cls) { btn.addClass(this.cls); } this.el = btn; if (this.hidden) { this.hide(); } Ext.ButtonToggleMgr.register(this); }, disable : function(newImgPath) { var replaceImgPath = newImgPath || this.disabledImgPath; if (replaceImgPath) this.el.dom.firstChild.src = replaceImgPath; this.disabled = true; }, enable : function(newImgPath) { var replaceImgPath = newImgPath || this.imgPath; if (replaceImgPath) this.el.dom.firstChild.src = replaceImgPath; this.disabled = false; }, onPressed : function(id,newImgPath) { var replaceImgPath = newImgPath || this.pressedImgPath; if (replaceImgPath) { var im = document.getElementById(id); im.setAttribute("src", replaceImgPath); } // this.el.dom.firstChild.src = replaceImgPath; this.pressed = true; }, onUnPressed : function(id,newImgPath) { var replaceImgPath = newImgPath || this.imgPath; if (replaceImgPath) { var im = document.getElementById(id); im.setAttribute("src", replaceImgPath); } // this.el.dom.firstChild.src = replaceImgPath; this.pressed = false; } }); Ext.namespace("Bxt"); #set ($LOADING = $CommonFunctions.displayTermFromResourceBundle($currentUserId, "BacklogTable", "backlogtable.loadingmsg")) #set ($TIP_TITLE = $CommonFunctions.displayTermFromResourceBundle($currentUserId, "BacklogTable", "backlogtable.tiptitle")) #set ($ENUM_DIALOG_TIP= $CommonFunctions.displayTermFromResourceBundle($currentUserId, "BacklogTable", "backlogtable.enumdialogtip")) #set ($ERROR_TITLE= $CommonFunctions.displayTermFromResourceBundle($currentUserId, "gbacklogmgmt", "gbacklogmgmt.backlog.error")) #set ($WARNING_TITLE= $CommonFunctions.displayTermFromResourceBundle($currentUserId, "gbacklogmgmt", "gbacklogmgmt.backlog.warning")) #set ($ERROR_DATA_LOAD= $CommonFunctions.displayTermFromResourceBundle($currentUserId, "gbacklogmgmt", "gbacklogmgmt.backlog.dataloaderror")) #set ($ERROR_WIDGET_LOAD= $CommonFunctions.displayTermFromResourceBundle($currentUserId, "gbacklogmgmt", "gbacklogmgmt.backlog.errorloadwidget")) #set ($FAILED_SERVER_REQ= $CommonFunctions.displayTermFromResourceBundle($currentUserId, "gbacklogmgmt", "gbacklogmgmt.backlog.failedserverreq")) var FocusLibLabels = { WIDGET_JSON_PARSE_ERROR: '$ERROR_WIDGET_LOAD', REQUEST_FAILED: '$FAILED_SERVER_REQ' } // Javascript classes, scoped objects and functions for TeamFocus // --- 1. Misc Utility functions ----- var BxtElementType = { REQUIREMENT: 'REQUIREMENT', TASK: 'TASK', CHANGE_REQUEST: 'CHANGE_REQUEST', TEST_CASE: 'TEST_CASE' }; var BxtUtil ={ getDecimalDigits : function (val) { if(val == undefined || val == null || isNaN(parseFloat(val))) return 0; var str = new String(val); //If Decimal point exists then if(str.indexOf(".")!= -1 ) { var n=str.substr(str.indexOf(".") + 1 ); //Extract the decimal digits of the number return n.length; } return 0; }, rankSort : function (val) { var rank = parseFloat(val); return (isNaN(rank)) ? -1 : rank; }, formatId : function (id) { if (id.indexOf("-") === 0) return ''; var s = id.replace(/^0+/,''); return (s.length == 0) ? '0' : s; }, // generic load exception handler lexHandler : function(proxy, store, response, e) { BxtUtil.showErrorMsg('$ERROR_DATA_LOAD'); }, checkErrorInResponse : function(response) { var r = Ext.decode(response.responseText); if((r.success != undefined) && !r.success) { BxtUtil.showErrorMsg(r.data[0].msg); return true; } return false; }, showErrorMsg : function(message) { Ext.Msg.show({ title:'$ERROR_TITLE', msg: ''+message+'', buttons: Ext.Msg.OK, icon: Ext.MessageBox.ERROR }); }, // Displays error messaged embedded in action with the standard server error message. showActionError : function(action) { var respText = action.response.responseText; var respObj = Ext.util.JSON.decode(respText); BxtUtil.showErrorMsg(respObj.data[0].msg); }, showWarningMsg : function(message) { Ext.Msg.show({ title:'$WARNING_TITLE', msg: ''+message+'', buttons: Ext.Msg.OK, icon: Ext.MessageBox.WARNING }); }, sortNumber : function(a, b) { return a - b; }, handleBACKSPACEKey : function(k, e) { var id = e.getTarget().id.substr(0,7); if(id === 'ext-gen' ) { // for event targets that are generated (not controls of interest), // stop the event so that backspace will not close window (do history) e.stopEvent(); return true; } return false; } }; // --- 2. Common Functions for Story Rank Computations var BxtRanks = { formatRank: function(rank){ //var number = parseFloat(rank); //var result = ''; //if (!isNaN(number)) { // number = number.toFixed(4); // result = parseInt(number) + (number % 1); //} //Rank is now not visible to the user, so use decimals , no need to fix the precision return rank; }, calcNewRank : function(r1, r2, sdir) { // r1,r2 are floats if(r1 == undefined && r2 == undefined) { return 0.0; } else if(r1 == undefined) { return r2; } else if( r2 == undefined) { return r1; } var newrank = (r2 - r1)/2.0 + r1; var rnded = Math.round(newrank); if((rnded < r2) && (rnded > r1) && sdir || (rnded > r2) && (rnded < r1) && !sdir) { newrank = rnded; } return newrank; }, // calculates the delta between the number items ranging // from rank1 to rank2 calcRankDelta : function(r1, r2, numItems) { var result = 0; if (isNaN(r1)) { result = r1; } else if (r1 != r2 && numItems > 0) { result = (r1 - r2) / numItems; } //alert("(" + r1 + " - " + r2 + ") / " + numItems + " = " + result); return result; }, // Default function to build the rank string and calls a method that will rebuild // the story list. It assumes no grouping. // Build rank strings on the SPx tab // callback function to process after new ranks got calculated // cindex current row index // rows selected rows // ds data store of the grid. buildRankString : function(callback, cindex, rows, ds) { // check for current row in rows var containsCIndex = false; var rowlen = rows.length; for (var i = 0; i < rowlen; i++) { var rowidx = ds.indexOfId(rows[i].id); if(rowidx == cindex){ containsCIndex = true; break; } } var indexArray = null; if (containsCIndex) { if ((rowlen-1) == 0) { return; } else { indexArray = new Array(rowlen-1); } } else { indexArray = new Array(rowlen); } // sort indexes var index = 0; for (var i = 0; i < rowlen; i++) { var rowidx = ds.indexOfId(rows[i].id); if(rowidx == cindex){ continue; } indexArray[index] = rowidx; index++; } indexArray.sort(BxtUtil.sortNumber); var destRecord = ds.getAt(cindex); if(destRecord == null || destRecord == undefined) { return false; } var rankArray = new Array(indexArray.length); var paramString = ""; var currRank = parseFloat(destRecord.get('rank')); var prevRank = 0; if (cindex > 0) { prevRecord = ds.getAt(cindex - 1); prevRank = parseFloat(prevRecord.get('rank')); } var d = parseFloat(BxtRanks.calcRankDelta(currRank, prevRank, rowlen + 1)); // build reqid,newrank string and array var newRank = 0; if (isNaN(d)) { newRank = d; } else { newRank = BxtRanks.formatRank(prevRank + d); } rankArray[0] = BxtRanks.formatRank(newRank); paramString += ds.getAt(indexArray[0]).get('id') + "," + rankArray[0]; for (var i = 1; i < indexArray.length; i++) { if (isNaN(d)) { rankArray[i] = d; } else { newRank += d; rankArray[i] = BxtRanks.formatRank(newRank); } paramString += "|" + ds.getAt(indexArray[i]).get('id') + "," + rankArray[i]; } // persist new ranks if (callback) { callback(indexArray, rankArray, cindex, paramString, ds.getAt(cindex)); } }, // Build rank strings for the PBx tab // callback function to process after new ranks got calculated // cindex current row index // rows selected rows // ds data store of the grid. buildPBxRankString : function(callback, cindex, rows, ds) { // check for current row in rows var containsCIndex = false; var rowlen = rows.length; for (var i = 0; i < rowlen; i++) { var rowidx = ds.indexOfId(rows[i].id); if(rowidx == cindex){ containsCIndex = true; break; } } var indexArray = null; if (containsCIndex) { if ((rowlen-1) == 0) { return; } else { indexArray = new Array(rowlen-1); } } else { indexArray = new Array(rowlen); } // sort indexes var index = 0; for (var i = 0; i < rowlen; i++) { var rowidx = ds.indexOfId(rows[i].id); if(rowidx == cindex){ continue; } indexArray[index] = rowidx; index++; } // check for dragging the empty row: if(rowlen == 1 && ds.getAt(indexArray[0]).get('id') == '-'){ return false; } indexArray.sort(BxtUtil.sortNumber); var destRecord = ds.getAt(cindex); if(destRecord == null || destRecord == undefined) { return false; } var isSPx = true; var idField = 'ranked'; var destId = destRecord.get(idField); var sourceId = rows[0].get(idField); var isAcross = (sourceId == destId) ? false:true; var destUnRanked = (destId == '1$UNRANKED_GROUP'); // we are using 1 char to make unranked appear first if(!isAcross && destUnRanked) { // DD within Unranked -> do nothing return false; } var rankArray = new Array(indexArray.length); var paramString = ""; if (!destUnRanked) { // destination is Ranked // calculate ranks by retrieving the delta and building a list of ranks // corresponding to the list of reqs var currRank = parseFloat(destRecord.get('rank')); if (isNaN(currRank)) { if (null != destRecord.get(idField)) { currRank = 20; } } var prevRank = 0; if (cindex > 0) { prevRecord = ds.getAt(cindex - 1); if (prevRecord.get(idField) == destRecord.get(idField)) { prevRank = parseFloat(prevRecord.get('rank')); if (isNaN(prevRank)) { prevRank = 0; } } } else if (isNaN(currRank)) { prevRank = currRank; } var d = parseFloat(BxtRanks.calcRankDelta(currRank, prevRank, rowlen + 1)); //alert( 'd ' + d ); // build reqid,newrank string and array var newRank = 0; if (isNaN(d)) { newRank = d; } else { newRank = BxtRanks.formatRank(prevRank + d); } rankArray[0] = BxtRanks.formatRank(newRank); //alert( 'rankArray['+0+'] = ' + rankArray[0] ); paramString += ds.getAt(indexArray[0]).get('id') + "," + rankArray[0]; for (var i = 1; i < indexArray.length; i++) { if (isNaN(d)) { rankArray[i] = d; } else { newRank += d; rankArray[i] = BxtRanks.formatRank(newRank); } paramString += "|" + ds.getAt(indexArray[i]).get('id') + "," + rankArray[i]; //alert( 'rankArray['+i+'] = ' + rankArray[i] ); } } else { // destination is UnRanked // build reqid,newrank string and array rankArray[0] = '' ; paramString += ds.getAt(indexArray[0]).get('id') + "," + rankArray[0]; for (var i = 1; i < indexArray.length; i++) { rankArray[i] = ''; paramString += "|" + ds.getAt(indexArray[i]).get('id') + "," + rankArray[i]; } } // persist new ranks if (callback) { callback(indexArray, rankArray, cindex, paramString, ds.getAt(cindex)); } }, // Build rank strings on the SPx tab buildSPxRankString : function(callback, cindex, rows, ds) { // check for current row in rows var containsCIndex = false; var rowlen = rows.length; for (var i = 0; i < rowlen; i++) { var rowidx = ds.indexOfId(rows[i].id); if(rowidx == cindex){ containsCIndex = true; break; } } var indexArray = null; if (containsCIndex) { if ((rowlen-1) == 0) { return; } else { indexArray = new Array(rowlen-1); } } else { indexArray = new Array(rowlen); } // get destination Sprint Id var destRecord = ds.getAt(cindex); if(destRecord == null || destRecord == undefined) { return false; } var destSprintId = destRecord.get('sprintid'); // check if any stories are crossing the sprint boundary var isAcrossSprints = false; // sort indexes (and check if it is across sprints) var index = 0; for (var i = 0; i < rowlen; i++) { var rowidx = ds.indexOfId(rows[i].id); if(rowidx == cindex){ continue; } indexArray[index] = rowidx; index++; var rec = ds.getAt(rowidx); if(rec.get('sprintid') != destSprintId) { isAcrossSprints = true; } } // check for dragging the empty row: if(rowlen == 1 && ds.getAt(indexArray[0]).get('id') == '-'){ return false; } indexArray.sort(BxtUtil.sortNumber); var rankArray = new Array(indexArray.length); var paramString = ""; if (!isAcrossSprints) { // calculate ranks by retrieving the delta and building a list of ranks // cooresponding to the list of reqs var currRank = parseFloat(destRecord.get('rank')); if (isNaN(currRank)) { if (null != destRecord.get('sprintid')) { currRank = 20; } } var prevRank = 0; if (cindex > 0) { prevRecord = ds.getAt(cindex - 1); if (prevRecord.get('sprintid') == destRecord.get('sprintid')) { prevRank = parseFloat(prevRecord.get('rank')); if (isNaN(prevRank)) { prevRank = 0; } } } else if (isNaN(currRank)) { prevRank = currRank; } var d = parseFloat(BxtRanks.calcRankDelta(currRank, prevRank, rowlen + 1)); // build reqid,newrank string and array var newRank = 0; if (isNaN(d)) { newRank = d; } else { newRank = BxtRanks.formatRank(prevRank + d); } rankArray[0] = BxtRanks.formatRank(newRank); paramString += ds.getAt(indexArray[0]).get('id') + "," + rankArray[0]; for (var i = 1; i < indexArray.length; i++) { if (isNaN(d)) { rankArray[i] = d; } else { newRank += d; rankArray[i] = BxtRanks.formatRank(newRank); } paramString += "|" + ds.getAt(indexArray[i]).get('id') + "," + rankArray[i]; } } else { // calculate ranks by retrieving the last rank and building a list of ranks // incremented from the end var recordCount = ds.getCount(); var lastRecord = destRecord; // if the destination record is not the last record in the sprint // find the last record in the sprint to get the last rank var index = cindex; if (index < recordCount-1) { var destSprintId = destRecord.get('sprintid'); while (index < recordCount-1) { var record = ds.getAt(index+1); if (destSprintId == record.get('sprintid')) { lastRecord = record; } else { break; } index++; } } var lastRankInt = parseInt(lastRecord.get('rank')); if (isNaN(lastRankInt)) { lastRankInt = 0; } // build reqid,newrank string and array var newRank = ++lastRankInt; rankArray[0] = BxtRanks.formatRank(newRank); paramString += ds.getAt(indexArray[0]).get('id') + "," + rankArray[0]; for (var i = 1; i < indexArray.length; i++) { newRank++; rankArray[i] = BxtRanks.formatRank(newRank); paramString += "|" + ds.getAt(indexArray[i]).get('id') + "," + rankArray[i]; } } // persist new ranks if (callback) { callback(indexArray, rankArray, cindex, paramString, ds.getAt(cindex)); } } }; // --- 3. Widget related classes // ----- Star Tooltip button ----- /** * This button can placed in a tool bar to display a star icon with a tooltip. * This is typically used in providing usage hints to the user. User in * Enumeration Field set up dialogs and in PBx toolbar. * @param {Object} tip */ Bxt.StarTooltipButton = function(tip) { return new Ext.Toolbar.Button({ icon: '../themes/default/images/Tipstar.gif', text: '$TIP_TITLE', //tooltip: {text:tip}, disabled: true, cls: 'x-btn-text-icon' }); } // ----- Table renderer functions ----- #set ($YES = $CommonFunctions.displayTermFromResourceBundle($currentUserId, "Controls", "controls.common.yes")) var TBLRender = { Number : function(v,p) { p.attr = 'style="text-align:right;vertical-align:middle;"'; return v; }, Id : function(v,p) { return BxtUtil.formatId(v); }, Name : function(value, p, record, rowindex, colindex, store) { return "" + value + ""; }, YBoolean: function(v, p){ return (v == true) ? '$YES' : '-'; }, Rank: function(v, p){ return BxtRanks.formatRank(v); } }; var BxtLoadUtil = { loadWidget : function(url, params, settings, loadMask, loadFunc,showProgress) { // put up wait mask if (loadMask) { loadMask.show(); if (settings) { settings.loadMask = loadMask; } } // add error handling settings if (settings) { settings.show = true, settings.msg = FocusLibLabels.REQUEST_FAILED } if(showProgress) { BxtLoadUtil.waitbox = Ext.MessageBox.wait('$LOADING'); } // send request Ext.Ajax.request({ url: url, success: BxtLoadUtil.loadWidgetSuccess, failure: BxtLoadUtil.loadWidgetFailure, settings: settings, params: params, loadFunc: loadFunc, waitTitle: '$LOADING' }); }, loadWidgetSuccess : function(response, action) { if(BxtLoadUtil.waitbox ) { BxtLoadUtil.waitbox.hide(); } // remove wait mask if (action && action.settings && action.settings.loadMask) { action.settings.loadMask.hide(); } // handle callback if (response && response.responseText) { try { var jsonObj = Ext.util.JSON.decode(response.responseText); //alert(Ext.util.JSON.encode(jsonObj)); if (jsonObj) { if ((jsonObj.success != undefined) && !jsonObj.success) { ErrorHandlerLib.onAjaxFailure(response, action); } else { action.loadFunc(jsonObj, action); } } } catch (error) { BxtUtil.showErrorMsg(FocusLibLabels.WIDGET_JSON_PARSE_ERROR); } } }, loadWidgetFailure : function(response, action) { if(BxtLoadUtil.waitbox ) { BxtLoadUtil.waitbox.hide(); } // remove wait mask if (action && action.settings && action.settings.loadMask) { action.settings.loadMask.hide(); } // handle error if (response && action) { ErrorHandlerLib.onAjaxFailure(response, action); } } }; // --- 4. Functions for managing user settings ----- #set ($USER_SETTINGS_FAILED= $CommonFunctions.displayTermFromResourceBundle($currentUserId, "gbacklogmgmt", "gbacklogmgmt.backlog.usersettingsloaderror")) /* * Note: PBV and SPV user settings loading execution flow: * -->loadProjectList() * --> projectsLoaded() if only one project, setProjectValue() else call loadUserSettingsProkject * --> loadUserSettingsProject() * --> setProjectValue() * -->If new value set, call loadBacklogList()/loadReleaseList() * -->If same value already set, call loadUserSettingsBacklog()/loadUserSettingsRelease() * -->If no value matches with the user setting, show Choose.. in combobox. * --> loadBacklogList() (Same for loadReleaseList()) * --> if only one backlog, setBacklogValue() else call loadUserSettingsBacklog() * --> loadUserSettingsBacklog() * --> setBacklogValue() * -->If new value set, reload the backlog stories table * -->If no value matches with the user setting, clear table and show Choose.. in combobox */ var BxtUserSettings = { // Return status of setComoboboxValues cbNONE : 1, // no existing entry in combo list matches the user setting cbSET : 2, // combo is alreadyset to user setting cbNEW : 3, // combo is a new user setting. /** * Asynchronously load the user settings for the given user, view and key. * If successful, call the success function. * @param {Object} userid * @param {Object} viewid * @param {Object} keyid * @param {Object} successFn function to call on success * @param {Object} failureFn function to call on failure */ load : function( viewid, keyid, successFn, failureFn ) { Ext.Ajax.request({ url : 'pbv/PBVAsyncHandler?action=LOAD-USER-SETTING', success : successFn, failure : failureFn || BxtUserSettings.settingLoadError, params : {start:0, limit:25, userId: '$currentUserId', viewId: viewid, keyId: keyid}}); }, settingLoadError : function() { BxtUtil.errorDialog("$USER_SETTINGS_FAILED"); }, /** * Asynchronously load the user settings for the given user, view and key. * If successful, call the success function. * @param {Object} userid * @param {Object} viewid * * @param {Object} selection * @param {Object} keyid * @param {Object} successFn function to call on success * @param {Object} failureFn function to call on failure */ save : function( viewid, keyid, selection,successFn, failureFn ) { Ext.Ajax.request({ url : 'pbv/PBVAsyncHandler?action=SAVE-USER-SETTING', success : successFn, failure : failureFn || BxtUserSettings.settingSaveError, params : {start:0, limit:25, userId: '$currentUserId', viewId: viewid, keyId: keyid,selection:selection}}); }, settingSaveError : function() { BxtUtil.errorDialog("$USER_SETTINGS_FAILED"); }, /** * Check and set the combobox to a new selection value if it exists in the list. * The store reader on the combobox must have index enabled. * @param {Object} cb combobox * @param {Object} sel user setting selection index. * @return cbNONE , cbNEW or cbSET * cbNONE : 1, // no existing entry in combo list matches the user setting * cbSET : 2, // combo is alreadyset to user setting * cbNEW : 3, // combo is a new user setting. */ setComboboxValue : function (cb, sel) { var newsel = cb.store.getById(sel); if(newsel == null || newsel == undefined) { return BxtUserSettings.cbNONE; } if (cb.getValue() != sel) { cb.setValue(sel); return BxtUserSettings.cbNEW; } return BxtUserSettings.cbSET; } }; // --- 5. Enumeration related objects and ExtJS extension classes. /** * Record type for loading Enumertions */ Bxt.EnumRecordType = new Ext.data.Record.create( [ {name: 'id'}, {name: 'value'}, {name: 'seq'}, {name: 'isdefault'}, {name: 'deletable'}] ); /** * Javascript class to create an enumeration list table from Ext.grid.EditorGridPanel. * This is a grid table contained within Bxt.EnumDialog class and is meant to be called * by Bxt.EnumDialog. Its features are:- * 1. Drag and drop list ordering * 2. Double click to enter edit mode * 3. Add/Remove buttons on the header. * The config parameters are passed by Bxt.EnumDialog to this class when EnumDialog is instantiated. * * @param {Object} config * configuration settings available are the same as EditorGridPanel except the Store Record must * be Bxt.EnumRecordType. Settings that may be of interest are: * ds: caller can create its own Ext.data.Store and pass it in as this property * proxy : caller may pass in proxy instead of ds (if both are passed, proxy is ignored) * */ #set ($SAVE_BTN = $CommonFunctions.displayTermFromResourceBundle($currentUserId, "GStoryDialog", "dialog.button.save")) #set ($CANCEL_BTN = $CommonFunctions.displayTermFromResourceBundle($currentUserId, "GStoryDialog", "dialog.button.cancel")) #set ($ADD_ENUM = $CommonFunctions.displayTermFromResourceBundle($currentUserId, "FocusAdmin", "enumdialog.label.addval")) #set ($REMOVE_ENUM = $CommonFunctions.displayTermFromResourceBundle($currentUserId, "FocusAdmin", "enumdialog.label.removeval")) #set ($TT_ADD_ENUM = $CommonFunctions.displayTermFromResourceBundle($currentUserId, "FocusAdmin", "enumdialog.tooltip.addval")) #set ($TT_REMOVE_ENUM = $CommonFunctions.displayTermFromResourceBundle($currentUserId, "FocusAdmin", "enumdialog.tooltip.removeval")) #set ($ENUM_WARN1A = $CommonFunctions.encodeJavaScriptString($CommonFunctions.getTermFromResourceBundle($currentUserId, "FocusAdmin", "enumdialog.warn1a", "{0}"))) #set ($ENUM_WARN1B = $CommonFunctions.displayTermFromResourceBundle($currentUserId, "FocusAdmin", "enumdialog.warn1b")) #set ($ENUM_WARN2A = $CommonFunctions.displayTermFromResourceBundle($currentUserId, "FocusAdmin", "enumdialog.warn2a")) #set ($ENUM_WARN2B = $CommonFunctions.displayTermFromResourceBundle($currentUserId, "FocusAdmin", "enumdialog.warn2b")) #set ($ENUM_DELTITLE1 = $CommonFunctions.displayTermFromResourceBundle($currentUserId, "FocusAdmin", "enumdialog.deletetitle1")) #set ($ENUM_DELTITLE2 = $CommonFunctions.displayTermFromResourceBundle($currentUserId, "FocusAdmin", "enumdialog.deletetitle2")) #set ($ENUM_DUP_ERR = $CommonFunctions.displayTermFromResourceBundle($currentUserId, "FocusAdmin", "enumdialog.duperror")) #set ($ENUM_BLANK_ERR = $CommonFunctions.displayTermFromResourceBundle($currentUserId, "FocusAdmin", "enumdialog.blankval")) #set ($ENUM_ENTER_NEW = $CommonFunctions.displayTermFromResourceBundle($currentUserId, "FocusAdmin", "enumdialog.enterval")) #set ($ENUM_REMOVE_ERR = $CommonFunctions.displayTermFromResourceBundle($currentUserId, "FocusAdmin", "enumdialog.removeerr")) #set ($ENUM_NO_REMOVE = $CommonFunctions.encodeJavaScriptString($CommonFunctions.getTermFromResourceBundle($currentUserId, "FocusAdmin", "enumdialog.noremove", "{0}"))) #set ($ONE_ENUM_VAL = $CommonFunctions.displayTermFromResourceBundle($currentUserId, "FocusAdmin", "enumdialog.oneenumval")) #set ($ENUM_FIELD_SETUP = $CommonFunctions.displayTermFromResourceBundle($currentUserId, "FocusAdmin", "enumdialog.enumfieldsetup")) Bxt.EnumListTable = function(config) { var abtn = new Ext.Button({text:'$ADD_ENUM', tooltip:'$TT_ADD_ENUM', iconCls: 'add'}); var rbtn = new Ext.Button({text:'$REMOVE_ENUM', tooltip:'$TT_REMOVE_ENUM', iconCls: 'remove'}); var ds = config.ds; if(!config.ds) { // sample proxy settings -- proxy: new Ext.data.HttpProxy({url:'pbv/PBVAsyncHandler?action=LOAD-REQS'}), config.ds = new Ext.data.Store({ proxy: config.proxy, reader: new Ext.data.JsonReader( {id:'id'}, Bxt.EnumRecordType), sortInfo:{field: 'seq', direction: "ASC"} } ); } var defaultDDgrp = 'GridDDEnum'; var dflt = { reader: new Ext.data.ArrayReader({}, Bxt.EnumRecordType), sortInfo:{field: 'seq', direction: "ASC"}, cm: new Ext.grid.ColumnModel([ {header: 'ID',sortable: false, hidden:true, dataIndex: 'id', renderer: TBLRender.Id }, {id:'value', fixed: true, sortable: false, dataIndex: 'value', editor: new Ext.form.TextField({allowBlank:false, selectOnFocus: true, maxLength : 36, validator : function(v) { if(v.trim() == '') { return '$ENUM_BLANK_ERR'; } return true; } }) }, {header:'Seq', hidden: true, dataIndex:'seq'}, {header: 'Default', hidden: true, dataIndex: 'isdefault'}, {header: 'Deletable', hidden: true, dataIndex: 'deletable'} ]), clicksToEdit: 2, autoExpandColumn : 'value', loadMask: {msg: '$LOADING'}, frame : false, collapsible : false, animCollapse : false, tbar : [ abtn, {xtype: 'tbseparator'}, rbtn ], // bbar : [ new Bxt.StarTooltipButton ('$ENUM_DIALOG_TIP')], layout :'fit', header : false, hideHeaders: true, headerAsText :false, border : false, renderTo : document.body, enableDragDrop : true, sm : new Ext.grid.RowSelectionModel(), listeners : [{'loadexception': BxtUtil.lexHandler}], ddGroup : defaultDDgrp }; // apply settings Ext.apply(this, config, dflt); Bxt.EnumListTable.superclass.constructor.call(this); abtn.on('click', this.addValue.createDelegate(this)); rbtn.on('click', this.confirmRemoveValue.createDelegate(this)); this.on('afteredit', this.commitChanges.createDelegate(this)); this.abtn = abtn; this.rbtn = rbtn; this.warnMsg = config.warnMsg; this.ddGroup = (!config.ddGroup) ? defaultDDgrp : config.ddGroup; this.setupDD(); }; Ext.extend(Bxt.EnumListTable, Ext.grid.EditorGridPanel, { abtn : null, rbtn : null, ddGroup : null, warnMsg : null, addValue : function() { //alert("add Value"); var ds = this.getStore(); var idx = ds.getCount(); var rec = new Bxt.EnumRecordType({ id:'new', value: '$ENUM_ENTER_NEW', seq:'', isdefault:false, deletable: true }); ds.add([rec]); this.startEditing(idx, 1); }, confirmRemoveValue : function() { var selections = this.selModel.getSelections(); var selectlen = selections.length; if(selectlen > 0) { var ds = this.getStore(); for(var i=0; i < selectlen;i++) { var sel = selections[i]; var del = sel.get('deletable'); if((del != undefined) && !del) { var msg = '$ENUM_NO_REMOVE'; msg = msg.replace(/\{0\}/, '' + sel.get('value') + ''); Ext.Msg.show({ title: '$ENUM_REMOVE_ERR', msg: '' + msg + '', buttons: Ext.Msg.OK, icon: Ext.MessageBox.ERROR }); return; } } var total = this.getStore().getCount(); if( total == selectlen) { // cannot delete all. Ext.Msg.show({ title: '$ENUM_REMOVE_ERR', msg: '$ONE_ENUM_VAL', buttons: Ext.Msg.OK, icon: Ext.MessageBox.ERROR }); return; } var title = '$ENUM_DELTITLE1'; var warn = '' if(selectlen == 1) { var srow = selections[0]; msg = '$ENUM_WARN1A'; msg = msg.replace(/\{0\}/, '' + srow.get('value') + ''); warn = this.warnMsg || '$ENUM_WARN1B Defunct.'; } else { msg = '$ENUM_WARN2A'; title = '$ENUM_DELTITLE2'; warn = this.warnMsg || '$ENUM_WARN2B Defunct.' } Ext.Msg.show({ title: title, msg: '' + msg + '? ' + warn + '', buttons: Ext.Msg.OKCANCEL, fn: this.onRemove.createDelegate(this), icon: Ext.MessageBox.QUESTION, animEl : this.rbtn.getEl() }); } }, onRemove : function(val) { if(val == 'ok') { var ds = this.getStore(); var selections = this.selModel.getSelections(); var selectlen = selections.length; if(selectlen > 0) { for(var i=0; i < selectlen;i++) { ds.remove(selections[i]); } ds.commitChanges(); } } }, setupDD : function() { // set dragdroptext this.getDragDropText = function() { return this.selModel.getSelected().get('value'); } this.ddTarget = new Ext.dd.DropTarget(this.getEl(), { ddGroup : this.ddGroup, copy : false, containerScroll : true, notifyDrop : this.nDrop.createDelegate(this) } ); // For row drag and drop scrolling . Ext.dd.ScrollManager.register(this.view.scroller); }, nDrop : function(dd, e, data) { //alert("Dropped"); var ddat = dd.getDragData(e); var g = ddat.grid; if(g == undefined) { return false; } var ds = g.getStore(); var rows = data.selections; var dstidx = ddat.rowIndex; if(dstidx == undefined) { return false; } for (i = rows.length - 1; i >= 0; i--) { if(!this.copy) { var srowid = rows[i].id; var srcidx = ds.indexOfId(srowid); if(srcidx == dstidx || srcidx == undefined){ continue; } var v = ds.getAt(srcidx); dstidx = (srcidx < dstidx) ? dstidx-1 : dstidx; ds.remove(v); ds.insert(dstidx,v); } } ds.commitChanges(); return true; }, commitChanges : function(e) { var ds = this.getStore(); var len = ds.getCount(); var map = []; var dup =false; for(var i = 0;i < len; i++) { var value = ds.getAt(i); var val = value.get('value'); if(map[val] == null) { map[val] = 1; } else { dup = true; break; } } if(dup) { BxtUtil.showErrorMsg('$ENUM_DUP_ERR'); } else { this.getStore().commitChanges(); } } }); /** * Javascript class for Enumeration List dialog. It extends Ext.Window class and creates Bxt.EnumList * within the dialog. The configuration of the Bxt.EnumListTable can be passed by setting the property: * enumListConfig. Some settings that may be of interest are: * enumListConfig this is a config object with settings for the Bxt.EnumListTable class * saveFn : handler to call when the save button is clicked. It is called with the parameter: * rec : an array of records of the Bxt.EnumListTable. * cancelFn : handler to call when the cancel button is clicked. Internal default is to close the window. * * @param {Object} config */ Bxt.EnumDialog = function(config) { var enumList = new Bxt.EnumListTable(config.enumListConfig); var panelConfig = config.panelConfig; var sbtn = new Ext.Button({text : '$SAVE_BTN', minWidth:80}); var cbtn = new Ext.Button({text : '$CANCEL_BTN', minWidth:80}); var panelConfig = { items : [enumList], layout : 'fit', buttons : [ sbtn, cbtn ], buttonAlign : 'center' }; var panel = new Ext.Panel(panelConfig); var dflt = { title : '$ENUM_FIELD_SETUP', width : 300, height : 350, closeAction :'hide', plain : true, items : [panel], modal : true, resizable : true, closable : true, layout : 'fit', border : false, renderTo : document.body, bodyStyle : 'padding:5px 10px 5px 10px' }; Ext.apply(this, config, dflt); Bxt.EnumDialog.superclass.constructor.call(this); this.enumList = enumList; this.panel = panel; // hook in handlers this.uSave = config.saveFn; this.uCancel = config.cancelFn || this.onCancel; sbtn.on('click', this.onSave.createDelegate(this)); cbtn.on('click', this.uCancel.createDelegate(this)); this.sbtn = sbtn; this.cbtn = cbtn; this.hide(); } Ext.extend(Bxt.EnumDialog, Ext.Window, { enumList : null, panel : null, uSave : null, uCancel : null, sbtn : null, cbtn : null, onSave : function() { var ds = this.enumList.getStore(); var idx = ds.getCount()-1; var values = ds.getRange(0,idx); if(this.uSave) { var duprow = this.findDuplicates(values); if(duprow < 0) { this.uSave(values); } else { this.enumList.selModel.selectRow(duprow); BxtUtil.showErrorMsg('$ENUM_DUP_ERR'); } } }, onCancel : function() { this.hide(); }, load : function(param) { this.enumList.getStore().load(param); }, findDuplicates : function(values) { var len = values.length; var map = []; for(var i = 0;i < len; i++) { var val = values[i].get('value'); if(map[val] == null) { map[val] = 1; } else { return i;// return duplicate row index } } return -1; // no duplicate row. } }); #parse("/bmsWindow.vm")