//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 = '
' +
' | ' +
'   | ' +
'{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")