function isBrowserOffline(){ // returns TRUE if the browser is running Prophet in offline (DOLS) mode if (window.location.hostname.toLowerCase() == "localhost" || window.location.hostname == "127.0.0.1") { return true; } else { return false; } } function getContextQueryString(param){ var query = window.location.search.substring(1); var vars = query.split("&"); for (var i=0;i= 5) { var formID=document.forms[0].jsFormID; if (formID) { //only run in edit mode checkForcedHelp(formID.value); //execute ajax (asynchronous) page load ever 4 minutes (need the random piece or IE6 won't reload) code = 'dojo.xhrGet({ url : document.forms[0].jsDefinitionsDbURL.value + "/EmptyPage?OpenPage&" + Math.random(), sync: false ,load : function (response) {return(true);},error : function (response){ return(true);}}); setTimeout(code, 240000); '; setTimeout(code, 240000); } } if (formVersion == 6) { var formID=document.forms[0].jsFormID; if (formID) { //only run in edit mode refreshFormVisibilities(); } } return(true); } // this code prevents CR/LF and BACKSPACE from firing on forms (causing navigation/submission to occur) // it also prevents CR/LF in a text box from causing submission (IE/FF do this if there's only one on the screen, Safari does it always) // simply add it to the onKeyDown event of a form, and call by: return(checkKeys(event)); function checkKeys(theEvent) { var kc = theEvent.keyCode; var tgt =theEvent.srcElement ? theEvent.srcElement : theEvent.target; // if they pressed something besides CR/LF/BS or we're in a textarea, assume OK. if ((kc != 13 && kc != 10 && kc != 8) || tgt.type == "textarea") return true; // the various inputs: make sure CR/LF is not allowed. if (tgt.type == "password" || tgt.type == "text" || tgt.type == "file") { if (kc == 13 || kc == 10) { return false; } else { return true; } } //unknown (possibly body/window) - disallow. return false; } // PORTAL DRILLDOWN FUNCTIONS function prophetGraphDrilldown(newUrl) { // if contained in a portal, reaches out to the parent window, grabs the src of the iframe, and manipulates it to the newUrl // otherwise just opens the newUrl in the current window // we'll look for "prophetportalheight" in the url to determine if it's in a portal if (String(window.location).indexOf("prophetportalheight") == -1) { window.location.href = newUrl; } else { window.parent.document.getElementById(window.name).src = newUrl; } } // HELP FUNCTIONS //Used when somebody clicks the question mark on the action bar -- spawns a new window, showing the user a help page. function openHelpWindow() { // if we're entering shops, the partner may want to override the stock help with their own custom help. if (document.forms[0].jsHelpURL.value == "js-LoadedFormHelp") { helpOn = true; var defDbURL = document.forms[0].jsDefinitionsDbURL.value; var formID = document.forms[0].jsFormID.value; window.entryHelpWindowHandle = openEntryHelpWindow(defDbURL, formID, "", 0); } else { newURL = document.forms[0].jsHelpURL.value; window.open(newURL, "Help", "toolbar,menubar,scrollbars,resizable,WIDTH=800,HEIGHT=600"); }; return true; } function checkForcedHelp(formID) { if (document.forms[0].jsEditFlag.value == "1" && document.forms[0].jsForceHelp.value == "2") { var cookieData = document.cookie; //alert (cookieData); //alert (cookieData.length); if (cookieData == "") { //var exp = new Date(); //var nowPlusOneMonth = exp.getTime() + (30*86400000); //exp.setTime(nowPlusOneMonth) openHelpWindow(); document.cookie = "shown=" + formID; } else { cookieFlag = cookieData.substring(cookieData.indexOf("shown=")+6, cookieData.indexOf("shown=")+6+formID.length); //alert(cookieFlag); if (cookieFlag != formID) { //var exp = new Date(); //var nowPlusOneMonth = exp.getTime() + (30*86400000); //exp.setTime(nowPlusOneMonth) openHelpWindow(); document.cookie = "shown=" + formID; } } }; return true; }; function showMainMenuHelp(helpMessage) { getDocObject('HELP').className = "mainHelpOn" getDocObject('HELP').innerHTML = helpMessage return(0); } function clearMainMenuHelp() { getDocObject('HELP').className = "mainHelpOff" getDocObject('HELP').innerHTML = "" return(0); } function openEntryHelpWindow(defDbURL, M_ID, Q_ID, forceOpen) { var needsToLoad = false; //alert ("openEntryHelpWindow called with:\ndefDbURL: " + defDbURL + "\nM_ID: " + M_ID + "\nQ_ID: " + Q_ID + "\n"); if (Q_ID == "") { newURL = defDbURL + "/EntryHelpCtrl/" + M_ID; needsToLoad = true; } else if (entryHelpWindowHandle == null || forceOpen) { helpOn = true; newURL = defDbURL + "/EntryHelpCtrl/" + (Q_ID == "" ? M_ID : (String(Q_ID).substring(0,2) == "Q_" ? Q_ID : M_ID + "-" + Q_ID)); needsToLoad = true; } else { if (entryHelpWindowHandle.closed == true) { helpOn = false; return (entryHelpWindowHandle); } newURL = defDbURL + "/EntryHelpCtrl/" + (Q_ID == "" ? M_ID : (String(Q_ID).substring(0,2) == "Q_" ? Q_ID : M_ID + "-" + Q_ID)); if (entryHelpWindowHandle.location.pathname != newURL) needsToLoad = true; } if (needsToLoad == true) { newURL += "?OpenDocument&FormID=" + M_ID; if (forceOpen) newURL += "&Error=1"; try{ return (window.open(newURL, "EntryHelp", "menubar,resizable,scrollbars,toolbar,WIDTH=450,HEIGHT=270")); } catch (errorInfo) { return (null); } } else { return (entryHelpWindowHandle); } return false; }; // FULL SCREEN FUNCTIONS function openFullScreenWindow() { newURL = document.forms[0].jsFullScreenURL.value; window.open(newURL, "FullScreen", "status,resizable,scrollbars,menubar"); /****** Future V5 code here window.open(window.location); ********/ return true; } function openFullScreenPrintWindow() { newURL = document.forms[0].jsFullScreenPrintURL.value; window.open(newURL, "FullScreenPrint", "status,resizable,toolbar,menubar,scrollbars"); return true; } // VANILLA GENERIC FUNCTIONS THAT WE USE ALL THE TIME function getBrowserName () { if (navigator.userAgent.indexOf("Notes") != -1) { return "Notes"; }; if (navigator.userAgent.indexOf("MSIE") != -1) { return "MSIE"; } else return "Netscape"; } function getInputElement(inputName) { var e = eval("document.forms[0]." + inputName); return e; } function getDocObject(objName) { var e = (document.getElementById) ? document.getElementById(objName) : ((document.all) ? document.all(objName) : null); return (e); } function getDocObjectFromWindowHandle(objName, windowHandle) { var e = (windowHandle.document.getElementById) ? windowHandle.document.getElementById(objName) : ((windowHandle.document.all) ? windowHandle.document.all(objName) : null); return (e); } function fullTrimString(passedString) { return String(passedString.replace(/\s+/g,"")); } function getInputValue(inputName) { //though this function CANNOT be used reliably with multilists (though it will return '' or undefined) var e = getInputElement(inputName); return e.value; } //returns an array of the individual elements in the input //the caller can then iterate for validity, check .length for # of entries, etc. function getMultiInputValues(inputName) { var e = getInputElement(inputName); var s = String(e.value).split("\n"); for (var i = 0; i < s.length; i++) { s[i] = s[i].replace("\r", ""); } return s; } function getSelectedIndex(selectionName) { //though this function doesn't break with multilists, it only returns the first result var sel = getInputElement(selectionName); if (sel.selectedIndex != null) return sel.selectedIndex; //select boxes (single and multiple) for (var i = 0; i < sel.length; i ++) { //checkboxes if (sel[i].checked) return i; } return -1; } // The function below cannot be used reliably with multilsts. It doesn't break with them, but: In IE if there is no 'value' then a blank is returned. In Firefox this scenario // results in the 'text' attribute being returned instead! In any case, only the first selected option is returned. function getSelectedValue(selectionName) { //though this function doesn't break with multilists, it only returns the first result. var sel = getInputElement(selectionName); if (sel.selectedIndex != null) { //select boxes (single and multiple) if (sel.selectedIndex == -1) return(''); return sel.options[sel.selectedIndex].value; } else { for (var i = 0; i < sel.length; i++) { //checkboxes if (sel[i].checked) return sel[i].value; } return ''; } } function getSelectedText(selectionName) { //though this function doesn't break with multilists, it only returns the first result (checkboxes also return the value - not text) var sel = getInputElement(selectionName); if (sel.selectedIndex != null) { //select boxes (single and multiple) if (sel.selectedIndex == -1) return(''); return sel.options[sel.selectedIndex].text; } else { for (var i = 0; i < sel.length; i++) { //checkboxes if (sel[i].checked) return sel[i].value; } return ''; } } // cross-browser quirks here -- in IE if there is no 'value' then they will be blank as expected. FF however will use the 'text' attribute instead! function getIndexOfValue(selectionName, chkValue) { var sel = getInputElement(selectionName); if (sel.options != null) { for (var x = 0; x < sel.options.length; x++) { if (sel.options[x].value == chkValue) return x; } } else { for (var x = 0; x < sel.length; x++) { if (sel[x].value == chkValue) return x; } } return -1; } function getIndexOfText(selectionName, chkValue) { //though this function doesn't break with checkbox style multilists, it only checks against the value var sel = getInputElement(selectionName); if (sel.options != null) { for (var x = 0; x < sel.options.length; x++) { if (sel.options[x].text == chkValue) return x; } } else { for (var x = 0; x < sel.length; x++) { if (sel[x].value == chkValue) return x; } } return -1; } function getInputRadioIndex(inputName) { var e = getInputElement(inputName); if (e == null) return -1; indexCount = -1; for (var x = 0; x < e.length; x++) if (e[x].checked) indexCount = x; return indexCount; } function getSelectedRadioValue(inputName) { var e = getInputElement(inputName); if (e == null) return (""); //if we have a handle on e but e.length doesn't exist then we're looking at a single-option radio. check the input directly if (e.length == null) return(e.checked ? e.value : ""); //otherwise it's a typical set of radio buttons var index = getInputRadioIndex(inputName); if (index == -1) return (""); var e = getInputElement(inputName); return (e[index].value); } function setSelectedRadioValue(inputName, assignValue) { var e = getInputElement(inputName); for (var x = 0; x < e.length; x++) if (e[x].value == assignValue) e[x].checked = true; return true; } function clearRadioValue(inputName) { var e = getInputElement(inputName); for (var x = 0; x < e.length; x++) e[x].checked=false; return true; } function countInputSelectedOptions(inputName) { var e = getInputElement(inputName); if (e == null) return 0; var c = 0; //checkboxes return an array of inputs - we'll check the "type" property. If it exists we're dealing with a select object. if (e.type) { if (e.type=="checkbox") { // single checkbox if (e.checked) c++; } else { for (var x = 0; x < e.length; x++) if (e.options[x].selected) c++; // multi-select } } else { for (var x = 0; x < e.length; x++) if (e[x].checked) c++; // assume multiple checkboxes }; return c; } // cross-browser quirks here -- in IE if there is no 'value' then they will be blank as expected. FF however will use the 'text' attribute instead! function setSelectToValue(selectionName, assignValue) { //though this function doesn't break with multilists, it effectively clears all other selections var sel = getInputElement(selectionName); var x = getIndexOfValue(selectionName, assignValue); if (sel.selectedIndex != null) { sel.selectedIndex = x; // multi-select } else { for (var i = 0; i < sel.length; i ++) { sel[i].checked = (i == x); // checkboxes } } return true; } function setSelectToText(selectionName, assignValue) { //though this function doesn't break with multilists, it effectively clears all other selections // for checkbox-style-multilists it only checks against the value, not text! var sel = getInputElement(selectionName); var x = getIndexOfText(selectionName, assignValue); if (sel.selectedIndex != null) { sel.selectedIndex = x; // multi-select } else { for (var i = 0; i < sel.length; i ++) { sel[i].checked = (i == x); // checkboxes } } return true; } function setSelectedIndex(selectionName, indexNum) { //though this function doesn't break with multilists, it effectively clears all other selections var sel = getInputElement(selectionName); if (sel.selectedIndex != null) { // select (single and multi) sel.selectedIndex = indexNum; } else { for (var i = 0; i < sel.length; i++) { sel[i].checked = (i == indexNum); // checkboxes } } return true; } function replaceSelectOptions(inputName, newValueArr, newAliasArr) { //replaces the options for the select box passed with the values and aliases passed. //if newAliasArray is null, then newValueArr is simply used for both //clear the box var e = getDocObject(inputName); e.options.length = 0; for (var i=0; i < newValueArr.length; i++) { var opt = document.createElement("option"); opt.setAttribute('value', (newAliasArr == null ? newValueArr[i] : newAliasArr[i])); opt.innerHTML = newValueArr[i]; e.appendChild(opt); } return (false); } function setInputValue(inputName, assignValue) { var e = getInputElement(inputName); e.value = assignValue; return true; } function massSetCheckboxField (fieldName, isChecked) { e = getInputElement(fieldName); if (e == null) return false; if (e.length == null) {e.checked = isChecked;} else for (i = 0; i < e.length; i++) {e[i].checked = isChecked;} return true; } // end vanilla functions // IFRAME FUNCTIONS // call adjustIFrame() to resize an Iframe. It binds an onLoad event to the iFrame. function adjustIFrameSize(id) { var fr = getDocObject(id); if (fr) { if (fr.contentDocument && fr.contentDocument.body.offsetHeight) { fr.height = fr.contentDocument.body.offsetHeight + 25; //W3C DOM } else if (fr.document && fr.document.body.scrollHeight) { fr.height = fr.document.body.scrollHeight + 25; //IE DOM } if (fr.addEventListener) { fr.addEventListener("load", resizeIFrame, false); } else { fr.attachEvent("onload", resizeIFrame); } } return(0); } function resizeIFrame(evt) { evt = (evt) ? evt : event; var target = (evt.target) ? evt.target : evt.srcElement; if (target.nodeType == 9) { if (evt.currentTarget && evt.currentTarget.tagName.toLowerCase() == "iframe") { target = evt.currentTarget; } } if (target) { adjustIFrameSize(target.id); } return(0); } // DIALOG BOX FUNCTIONS function activateSelectionDialog(dialogURL) { if (isBrowserOffline()) { var newPathname = "/Sub_0" + dialogURL; } else { var newPathname = dialogURL; } selectionDialogWindowHandle = window.open(newPathname, "DialogBox3", "height=350,width=550,resizable=yes,scrollbars=yes"); return true; } function activateLargeSelectionDialog(dialogURL) { largeSelectionDialogWindowHandle = window.open(dialogURL, "DialogBox4", "height=600,width=775,resizable=yes,scrollbars=yes"); return true; } function activateShopAddCommentDialog(dialogURL) { window.open(dialogURL, "DialogBox7", "height=200,width=400,resizable=yes,scrollbars=yes"); } function activateDateDialog(destField) { newPathname = window.location.pathname.slice(0, (window.location.pathname.toLowerCase()).lastIndexOf(".nsf") + 4); newURL=window.location.protocol + "//" + window.location.host + newPathname + "/DBoxWebDate?OpenForm&destField=" + destField; window.open(newURL, "DialogBox3", "height=120,width=250,resizable=no,scrollbars=no"); return true; //newPathname = top.HeaderFrame.location.pathname.slice(0, top.HeaderFrame.location.pathname.lastIndexOf("/") + 1); //newURL = top.HeaderFrame.location.protocol + "//" + top.HeaderFrame.location.host + newPathname + "DBoxWebDate?OpenForm&destField=" + destField; //window.open(newURL, "DialogBox3", "height=120,width=250,resizable=no,scrollbars=no"); //return true; } function activateTimeDialog(destField) { //newPathname = window.location.pathname.slice(0, (window.location.pathname.toLowerCase()).lastIndexOf(".nsf") + 4); if (isBrowserOffline()) { newPathname = "/Sub_0/messiah/meta.nsf"; } else { newPathname = "/messiah/meta.nsf"; } //hack fix since our time picker doesn't support anything other than US times //if (document.getElementById('prophetSampleFormatEntryTimeAM').value != "hh:mm AM" || document.getElementById('prophetSampleFormatEntryTimePM').value != "hh:mm PM") { // return(false); //} newURL=window.location.protocol + "//" + window.location.host + newPathname + "/DBoxWebTime?OpenForm&destField=" + destField + "&" + document.forms[0].prophetSampleFormatEntryCGIArgs.value; window.open(newURL, "DialogBox4", "height=120,width=250,resizable=yes,scrollbars=no"); return true; } function activateViewDialog(dialogForm) { newPathname = top.HeaderFrame.location.pathname.slice(0, top.HeaderFrame.location.pathname.lastIndexOf("/") + 1); newURL = top.HeaderFrame.location.protocol + "//" + top.HeaderFrame.location.host + newPathname + dialogForm + "?OpenForm"; window.open(newURL, "DialogBox5", "height=300,width=450,resizable=yes,scrollbars=yes"); return true; } function activateDateTimePicker() { newURL = document.forms[0].jsDTPickerURL.value; window.open(newURL, "DialogBox6", "height=400,width=450"); return true; } function getParentForm() { if (window.opener == null) { return document.forms[0]; } if (typeof window.opener == "undefined") { return document.forms[0];} else { return window.opener.document.forms[0];}; } function getParentWindow() { if (window.opener == null) { return window; } if (typeof window.opener == "undefined") { return window;} else { return window.opener;}; } function getParentElement(inputName) { var parentForm = getParentForm(); var e = eval("parentForm." + inputName); return e; } function getParentValue(inputName) { var e = getParentElement; return e.value; } function loadParentValues() { var myForm = document.forms[0]; var parentForm = getParentForm(); // why not just use our other functions? Then we end up reloading the parent object over and over again. // JavaScript's global variable handling is insufficient for our purpose here. for (var x = 0; x < myForm.elements.length; x++) { curName = myForm.elements[x].name; parentChk = eval("parentForm." + curName); if (typeof parentChk != "undefined") { if (myForm.elements[x].type == "select-one") { // list boxes must be handled slightly differently for (z = 0; z < myForm.elements[x].options.length; z++) { if (myForm.elements[x].options[z].text == parentChk.value) myForm.elements[x].selectedIndex = z; }; } else {myForm.elements[x].value = parentChk.value;}; }; }; return true; } function setParentValues() { myForm = document.forms[0]; parentForm = getParentForm(); for (x = 0; x < myForm.elements.length; x++) { curName = myForm.elements[x].name; if (curName.substring(0,1) != "%") { //skip %%surrogate fields from Domino, etc. curType = myForm.elements[x].type; parentChk = eval("parentForm." + curName); if ((typeof parentChk != "undefined") && (curName.substring(0,1) != "_") && curName.substring(0,1) != "%") { if (curType.substring(0,6) == "select") { obj = eval("myForm." + curName); e = eval("parentForm." + curName); e.value = getSelectedText(curName); } else { e = eval("parentForm." + curName); e.value = eval("myForm." + curName + ".value"); }; }; } }; return true; } function setTimeInParent(parentField) { var timeString = ""; myForm = document.forms[0]; parentForm = getParentForm(); parentChk = eval("parentForm." + myForm.destField.value); if (typeof parentChk != "undefined") { timeString = myForm.hours.value + ":" + myForm.minutes.value; if (myForm.ampm[0].checked) timeString = timeString + " AM"; if (myForm.ampm[1].checked) timeString = timeString + " PM"; parentChk.value = timeString; }; return true; } function viewSetParentUNIDValues(parentField) { var UNIDSet = "" myForm = document.forms[0]; parentForm = getParentForm(); for (x = 0; x < myForm.elements.length; x++) { if ((myForm.elements[x].type == "checkbox") && (myForm.elements[x].name == "$$SelectDoc")) { if (myForm.elements[x].checked) { if (UNIDSet == "") { UNIDSet = myForm.elements[i].value } else { UNIDSet = UNIDSet + "·" + myForm.elements[i].value } } } }; parentChk = eval("parentForm." + parentField); if (typeof parentChk != "undefined") { parentChk.value = UNIDSet; }; return true; } function viewSetParentColumnValues(parentField, columnNumber) { var tmpObj; var resultsSet = ""; var columnCount = 0; myForm = document.forms[0]; parentForm = getParentForm(); for (x = 0; x < myForm.elements.length; x++) { if ((myForm.elements[x].type == "checkbox") && (myForm.elements[x].name == "$$SelectDoc")) { if (myForm.elements[x].checked) { tmpObj = myForm.elements[x]; while (tmpObj.tagName != "TR") { tmpObj = tmpObj.parentElement; if (tmpObj.parentElement.tagName == "BODY") return true; }; columnCount = 0; for (y = 0; y < tmpObj.children.length; y++) { if (tmpObj.children[y].innerHTML != "") { columnCount ++; if (columnCount == columnNumber) { if (resultsSet == "") { resultsSet = tmpObj.children[y].innerHTML; } else { resultsSet = resultsSet + "·" + tmpObj.children[y].innerHTML; } } } } } } }; parentChk = eval("parentForm." + parentField); if (typeof parentChk != "undefined") { parentChk.value = resultsSet; }; return true; } /* Reference example for selectable view HTML code - Associate Interaction X_02 */ function selectDialogOK() { setParentValues(); close(); return true; } function timeDialogOK() { setTimeInParent(); close(); return true; } function timeDialogCancel() { close(); return true; } function selectDialogCancel() { close(); // Why bother? In case we want to do more with it later, of course. return true; } function viewDialogUNIDOK(returnFieldName) { viewSetParentUNIDValues(returnFieldName); close(); return true; } function viewDialogColumnOK(returnFieldName, columnNumber) { viewSetParentColumnValues(returnFieldName, columnNumber) setParentValues(); close(); return true; } function viewDialogCancel() { close(); // Why bother? In case we want to do more with it later, of course. return true; } //END DIALOG BOX FUNCTIONS //MISC FUNCTIONS function VE_ProphetVideoPublishAction(path, duration, src) { //this function, called by VideoEgg after a video is published, populates the question with the VideoEgg path info, and swaps the iframe display from the publisher to the player var myId = String(window.name).replace("VideoFrame", ""); window.parent.document.getElementById(myId).value = "path=" + path + "&duration=" + duration + "&src=" + src; var s = String(window.location.search); var i = s.indexOf("shopsDbUrl="); var shopsDbUrl = s.slice(i + 11, 999); window.location = shopsDbUrl + "/VideoPlayer?OpenForm&" + window.parent.document.getElementById(myId).value; } function atRightBack(fullString,subString) { // mimics the Domino @Rightback() function var fString = String(fullString); var sString = String(subString); if(fString.lastIndexOf(sString) == -1) { return (""); } else { return (fString.substring(fString.lastIndexOf(sString)+1, fString.length)); } } function arrayContainsElement(srcArray, searchElem) { for (var i = 0; i < srcArray.length; i++) { if (srcArray[i] === searchElem) return (true); } return(false); } function arrayGetIndex(srcArray, searchElem) { for (var i = 0; i < srcArray.length; i++) { if(srcArray[i] === searchElem) return(i); } return(-1); } //used by shops, validates the L_Key field passed (part of an L_Key field's onBlur() event) function validateLKey(passedInput) { fieldOnBlurPreventingSave=false; passedInput.value = dojo.trim(passedInput.value).replace(/\s+/g," "); if (passedInput.value == "") { document.forms[0].L_UNID.value = ""; return (false); } //verify L_Key provided var lookupKey = encodeURIComponent(passedInput.value); var xhrOK = false; var newLUNID = ""; if (isBrowserOffline()) { var xhrURL = "/Sub_0" + jsg_shopsDbURL; } else { var xhrURL = jsg_shopsDbURL; } dojo.xhrGet({ url : xhrURL + "/AjaxResponder?OpenAgent&command=getLocationUNID&key=" + lookupKey, sync: true , //Run this function if the request is successful load : function (response) { //the response might have a CR at the end, strip it (and any other whitespace) var respStr = response.replace(/\s+/g, ""); if (respStr == "NOMATCH") { xhrOK = false; } else { xhrOK = true; newLUNID = respStr; } return(true); }, //Run this function if the request is not successful error : function (response){ xhrOK = false; return(true); } }); if (xhrOK) { document.forms[0].L_UNID.value = newLUNID; return (true); } else { fieldOnBlurPreventingSave = true; document.forms[0].L_UNID.value = ""; alert (jsValidateLKey.replace("%value%", passedInput.value)); if (getBrowserName() != 'MSIE') passedInput.value = ''; passedInput.focus(); return (false); } } // lines up checkbox columns for checkbox fields function lineUpCheckboxes (div) { if (typeof div === "string") { div = document.getElementById(div); } if (!div) { return; } var cbText = div.innerHTML; // this is for reformatting pre-8.5 checkbox fields to add