<@script name="InputMgr" also="Enum Events Window" hide="y"> Implements the %STUDIO% input manager (c) SAP AG 2003-2006. All rights reserved. #DEPENDENCIES[ lib:EnumMgr.js lib:EventsMgr.js lib:PopupMgr.js lib~skin:styles.Input.css lib:Freeze.js ] #INCLUDE[gml:defs.inc] #INCLUDE[env:global_hotkeys.inc] ////////////////////////////////////////////////////////////////////////////////////// // FUNCTIONS <@func name="ENABLE_INPUTS" also="DISABLE_INPUTS Window!SETUP"> Enables the %STUDIO% glboal input manager The HTML container to hook (usually the document body) This function is automatically invoked by @Window!SETUP. Therefore, use this function only in windows where the @Window! script is not installed. function ENABLE_INPUTS(obj) { obj.onactivate = __INPUTS.focus; obj.ondeactivate = __INPUTS.blur; obj.onclick = __INPUTS.click; obj.ondblclick = __INPUTS.click; obj.onfocusout = __INPUTS.focusout; } <@func name="DISABLE_INPUTS" also="ENABLE_INPUTS Window!SETUP"> Disables the %STUDIO% global input manager The HTML container to unhook (usually the document body) function DISABLE_INPUTS(obj) { obj.onactivate = null; obj.ondeactivate = null; obj.onclick = null; obj.ondblclick = null; for (var i=0, E=obj.all, len=E.length; i Gets the value of a given input field The input field object Default value to return if the input field is empty The input field value (depends on the input field's data type) function GET_INPUT(obj, dflt) { if (!obj || !obj.dt) return null; switch (obj.dt) { case 'bool': return obj && (obj.data != null) ? obj.data : dflt || null; case 'float': case 'int': return obj && (obj.data != null) ? obj.data : dflt || 0; default: return obj && obj.data || dflt || ''; break; } } <@func name="SET_INPUT" also="GET_INPUT RESET_INPUT"> Sets the value of a given input field The input field object The value to set (depends on the input field's data type) Indicates whether to notify changes to the input field if called from DynExpEdit function Returns ~true if the input field value has actually changed; otherwise, returns ~false function SET_INPUT(obj, value, notifyChange, fromDEEditor) { if (!obj || !obj.dt) return false; var olddata = obj.data, data; var empty = (value === undefined || value === null || value === ''); switch (obj.dt) { case 'bool': data = empty ? null : BOOL(value); value = !empty && data ? CHR(252) : ''; olddata = !data; break; case 'color': data = empty ? null : (value+''); value = value || ''; try { obj.runtimeStyle.backgroundColor = value; } catch (e) { data = null; value = ''; } break; // IE10 - enum is used as a span, as there is no need to // edit the value in the input. see also BUILD_INPUT(). case 'enum': data = empty ? null : (value+''); value = data ? GET_ENUM_ITEM(UNESCAPE(obj['enum']), data) : ''; if (typeof(value)=="string" && value.indexOf('isHTMLVal') != -1) value = trimHTML(value); obj.innerHTML = value; break; case 'toggle': data = empty ? null : (value+''); value = data ? GET_ENUM_ITEM(UNESCAPE(obj['enum']), data) : ''; if (typeof(value)=="string" && value.indexOf('isHTMLVal') != -1) value = trimHTML(value); break; case 'icon': data = empty ? null : (value+''); value = data ? GET_ENUM_ITEM(UNESCAPE(obj['enum']), data) : ''; obj.innerHTML = value; break; case 'colorenum': data = empty ? null : (value+''); if (data && data.indexOf('$__color')==0 && obj['enum']) { // we hope that dropdown value can't be '$__color' var res = MODAL('#URL[dev:common.Color.htm]', null, false); if (res) SET_INPUT(obj, res, true); return; } value = data ? GET_ENUM_ITEM(UNESCAPE(obj['enum']), data) : ''; // apply the formatting template for items selected from the color palette: if (!value && data && typeof(data)=="string" && data.indexOf('#')==0) { value = obj['format'] ? UNESCAPE(obj['format']).replace(/{data}/g, data) : data; } obj.innerHTML = value; break; case 'float': case 'int': if (empty || isNaN(value)) { data=null; value=''; break; } data = (obj.dt == 'int') ? parseInt(value) : parseFloat(value); if (obj.min) data = MAX(data, parseFloat(obj.min)); if (obj.max) data = MIN(data, parseFloat(obj.max)); value = data+''; break; case 'date': case 'time': if (empty || !value) { data=null; value=''; break; } try { data = DVAL(value); if (isNaN(data)) { data=null; value=''; } else value = DSTR(data, UPPER(obj.dt)); } catch (e) { alert('INTERNAL ERROR: Date/Time macros are not installed'); } break; case 'datetime': if (empty || !value) { data=null; value=''; break; } try { data=null; value=''; //data = DVAL(value); //if (isNaN(data)) { data=null; value=''; } else value = DSTR(data, UPPER(obj.dt)); } catch (e) { alert('INTERNAL ERROR: Date/Time macros are not installed'); } break; case 'expr': // TODO: Find what this CSN meant, and if it's irrelevant, delete this part: // For solving painting problems in DE (caused in cases where '=' is used freely) // I force the update of the field by the following: (fix bug number 2619737 - mhoter) // olddata = null; if (value == '$__expr' && obj['enum']) { // we hope that dropdown value can't be '$__expr' EDIT_INPUT(obj, true); return; } var comments = ''; var result = ''; var exprSplit = ''; //clean the expression from /* chars, they're not allowed if (!empty && !fromDEEditor && notifyChange) { //loop because replace replaces first occurance only, and regular expr is difficult becuase of /* chars while(value.indexOf("#[COMMENTIN]") >= 0) value = value.replace("#[COMMENTIN]",""); } exprSplit = $ENV.dynexp.handleExprComments(value); //if (notifyChange && fromDEEditor==true) if(exprSplit[0].charAt(0) == "=") //if expression save comments. for literal - not saving the comments { if (fromDEEditor==true) comments = $ENV.dynexp.setExprComments(exprSplit[1]); else comments = $ENV.dynexp.getExprComments(obj.data); } exprSplit = exprSplit[0]; result = validateDynExp(obj, exprSplit, !notifyChange); // if !notify -> we're validating for UI, otherwise for setProperty if (notifyChange) { //data = result data = result + comments; //value = exprSplit[0]+comments; //in case value=/**/ we want to return value="" (blank) value = exprSplit; } else { //data = value + comments + ''; // convert to string to avoid boolean true->"true" conversion to be dirty //value = result + comments; data = exprSplit + comments + ''; value = result; } if (obj.checkbox) { var check = obj.previousSibling; if (check) { //check.value = BVAL(data); check.value = BVAL(result); check.className = 'FIELD-EXPR-BOOL' + ' FIELD-EXPR-BOOL-'+check.value; } } // In very long strings, show only the first 20 chars - presentation size limitation -mhoter // value = ELLIPSIS(value, 20); break; case 'htmledit': case 'text': data = empty ? null : (value+''); value = value || ''; break; case 'obj': case 'ref': case 'user': if (value == '$__popup' && obj['enum']) { EDIT_INPUT(obj, true); return; } data = empty ? null : (value+''); value = value || ''; var k=value.indexOf('~'); if (k >= 0) value = value.substring(0,k); break; case 'html': data = empty ? null : (value+''); value = value || ''; obj.innerHTML = value; break; case 'combo': case 'str': case 'url': default: data = empty ? null : (value+''); value = value || ''; break; } obj.data = data; obj.value = value; if (data == olddata) { // callback in case the input didn't change // CSN#2055319 2008 var fn=__INPUTS.getcallback(obj, 'handleInputNotChangeed'); if (fn) fn(obj); return false; } if (notifyChange) { var fn=__INPUTS.getcallback(obj, 'onInputChange'); if (fn) fn(obj); } return true; } function trimHTML(html){ var splitgt = html.split('>'), txt; // check if exists an indication to the numbers of tags left to the value: var i = html.indexOf("htmlValCol="); if (i != -1) { var sub = html.substr(i); var col = sub.substring(sub.indexOf('=')+1, sub.indexOf(' ')); txt = TRIM(splitgt[col]); txt = TRIM((txt.split('<'))[0]); } else { txt = TRIM(splitgt[1]); txt = TRIM((txt.split('<'))[0]); } // The icon input type include nbsp for text padding - below removes it txt = txt.replace(/ /g, ''); return txt; } <@func name="RESET_INPUT" also="SET_INPUT"> Resets a given input field The input field object Indicates whether to notify changes to the input field Returns ~true if the input field value has actually changed; otherwise, returns ~false function RESET_INPUT(obj, notifyChange) { if (!obj || !obj.dt) return false; var olddata = obj.data || null; obj.data = null; obj.value = ''; if (!obj.readOnly && !obj.parentElement.readOnly) { if (obj.arrow == 'auto' && obj.glyph) obj.className = obj.glyph; } if ('color' == obj.dt) { obj.runtimeStyle.backgroundColor = ''; } if (olddata === null) return false; if (notifyChange) { var fn=__INPUTS.getcallback(obj, 'onInputChange'); if (fn) fn(obj); } return true; } <@func name="EDIT_INPUT" also="SET_INPUT"> Open the input field's specific popup The input field object Specifies if the editor should be a dialog (if defined for this field), or in-place editor/dropdown function EDIT_INPUT(obj, dlg) { if (!obj || !obj.dt) return; var prm = {id:obj.owner||'', data:obj.data||'', value: obj.value||'', label:obj.label||'', dlg:dlg}; var fn=__INPUTS.getcallback(obj, 'getInputEditor'); if (fn) fn(obj, prm); switch (obj.dt) { case 'text': var res=MODAL('#URL[dev:common.EditTextDlg.htm]', prm, true); if (typeof res == 'string') SET_INPUT(obj, res, true); break; case 'htmledit': var res=MODAL('#URL[dev:common.EditHtmlDlg.htm]', prm, true); if (typeof res == 'string') SET_INPUT(obj, res, true); break; case 'expr': if (obj['enum'] && !dlg) { // open dropdown if there is enum and dialog editor is not requested var en = GET_ENUM(UNESCAPE(obj['enum'])); if (!en) return; ENUM_APPEND(en, '$__expr', UNESCAPE(obj.hint||'#TEXT[XLST_INPUT_ENTER_FORMULA]')); DROPDOWN_LIST(en, obj, obj.maxrows || 10, (obj.dt == 'icon' ? 16 : 14)); } else { // either no dropdown defined, or 'Enter formula...' selected in the dropdown - open DE dialog if (!obj.readOnly) editDynExp(obj, prm.value); } break; case 'url': var res=MODAL('#URL[dev:common.EditUrnDlg.htm]', prm, true); if (typeof res == 'string') SET_INPUT(obj, res, true); break; case 'obj': case 'ref': case 'user': if (obj['enum'] && !dlg) { var en = GET_ENUM(UNESCAPE(obj['enum'])); if (!en) return; ENUM_APPEND(en, '$__popup', UNESCAPE(obj.hint||'#TEXT[XLST_INPUT_MORE]')); DROPDOWN_LIST(en, obj, obj.maxrows || 10, (obj.dt == 'icon' ? 16 : 14)); } else if (obj.popup) { var unit = $ENV.contextUnit; var splitted = (obj.gmlid || '').split('@'); var data = unit && unit.getElement(splitted[0], true); if(obj.paramsFN) prm.popupParams = obj.paramsFN(data); try { if(obj.transactive)BEGIN('#TEXT[XMIT_TRANS_EDIT_ATTRIBUTE_OF]' .replace('{0}',obj.parentElement.innerText) .replace('{1}',"'" + data.name + "'")); // eyal - allow popup property to be function var popup = obj.popupFN ? obj.popupFN.apply(data, [data, obj.dt]) : obj.popup; if (popup) { var P = popup.split('@@@'); if(UPPER(P[1]) == 'FLOATING') { // open as floating window var onCloseCallback = function(res) { if (typeof res == 'string') SET_INPUT(obj, res, true); } FLOATING_WINDOW(P[0], prm, false, true, undefined, undefined, onCloseCallback); } else { var res=MODAL(popup, prm, true); if (typeof res == 'string') SET_INPUT(obj, res, true); } } if(obj.transactive) COMMIT(); } catch (e) { #TRACE[4, e.description]; if(obj.transactive) ROLLBACK(); } } break; case 'color': POPUP_COLORS(obj); break; case 'bool': case 'toggle': break; case 'combo': case 'enum': case 'icon': case 'colorenum': var en = GET_ENUM(UNESCAPE(obj['enum'])); if (!en) return; DROPDOWN_LIST(en, obj, obj.maxrows || 10, (obj.dt == 'icon' || obj.dt == 'colorenum' ? 16 : 14), obj.dropdownWidth); break; } } <@func name="BUILD_INPUT"> Returns the HTML code for a specified input field definition The input field definition The input field glyph Additional HTML/CSS attributes to apply to the input field Optional. For QTP use only The input field HTML code function BUILD_INPUT(def, glyph, attrs, qtp) { var arrow = LOWER(def.arrow || 'auto'); var glyph = 'FIELD' + (glyph && glyph !='FIELD' ? ' '+glyph : ''); var type = def.password ? 'password' : 'text'; var en = def['enum'] ? ' enum="'+ESCAPE(def['enum'])+'"' : ''; var className = glyph+((arrow == 'always') ? ' FIELD-'+def.type : '')+(en ? ' FIELD-'+def.type+'-ENUM' : ''); var css = ' glyph="'+glyph+'" class="'+className+'" arrow="'+arrow+'"'; var fld = ''; case 'expr': var chk = (def.exprType == #[BOOLEAN]) ? '' : ''; return chk+fld+ro1+en+(chk ? ' checkbox="true"' : '') + '>'; case 'htmledit': return fld+ro1+ro2+'>'; case 'obj': case 'ref': case 'user': // NadavL - New feature to allow defining 'user' as editable. // To make this generic, a new attribute - contentEditable - was defined. // Currently it is supported only for 'user'. // 'readonly' has precedence over the 'contentEditable' property if (def.readonly) { ro1 = ' readonly=true style="color:#[DIS]"'; } else if (def.contentEditable) { ro1 = ''; ro2 = ' contenteditable=true'; } return fld+ro1+ro2+en+' popup="'+def.popup+'">'; case 'float': case 'int': return fld+ro1+ (def.min || def.min === 0 ? ' min="' + def.min+'"' : '')+ (def.max || def.max === 0 ? ' max="' + def.max+'"' : '')+ (def.step ? ' step="' + def.step+'"' : '')+'>'; case 'bool': return fld+ro1+ro2+' style="text-align:center;font:normal 12pt wingdings">'; case 'combo': if (!(def.readonly) && ("contentEditable" in def)) { ro1 = ro1 + ' contenteditable='+ def.contentEditable; } return fld+ro1+en+'>'; case 'toggle': return fld+ro1+ro2+en+'>'; // IE10 - use enum as a span as well, as there is no need to // edit the value in the input. see also SET_INPUT(). case 'icon': case 'colorenum': case 'enum': fld = fld.replace(''; case 'html': fld = fld.replace(''; default: return ''; } } <@func name="GET_INPUT_OBJ" also="SET_INPUT GET_INPUT RESET_INPUT"> Returns input object found among children of given HTML element The HTML element to search in The input field object, or ~null if not found function GET_INPUT_OBJ(elem) { if (!elem) return null; if (elem.dt) return elem; var children = elem.childNodes; for (var i = 0; i < children.length; i++) { var child = children[i]; if (child.dt) return child; } return null; } <@func name="MARK_INPUT" scope="private"> Marks or unmarks input field object with error indicator The input field object The error text. If ommited or empty, the mark is removed function MARK_INPUT(obj, err) { var st = obj.runtimeStyle; if (err) { st.oldcolor = st.color; st.cssText = 'color:#D0001D; background-position-y:center; background-repeat: no-repeat; background-image: url(#URL[~skin:images.error_triangle.gif]);'; obj.err_text = err; obj.onmouseenter = showErrorMsg; //function see bottom obj.onmouseleave = hideErrorMsg; //function see bottom } else { if (obj.err_text) { st.color = st.oldcolor||''; st.cssText = 'background-position-y:; background-repeat:; background-image:;'; } obj.err_text = undefined; obj.onmouseenter = null; obj.onmouseleave = null; obj.document.parentWindow.INFORM(); // clear existing error box, if any } } function showErrorMsg() { var e=event&&event.srcElement||this; //input element var win = e.document.parentWindow; win.INFORM(e.err_text,-1,-1,e, 'bottom'); } function hideErrorMsg() { var e=event&&event.srcElement||this;//input element var win = e.document.parentWindow; win.INFORM(); } /////////////////////////////////////////////////////////////////////////////////////////////////// // INTERNAL var __INPUTS = {}; __INPUTS.activeField = null; __INPUTS.cancelClick = false; __INPUTS.focus = function() { var e=event.srcElement, p=e.parentElement; __INPUTS.activeField = e; if (e.currentStyle.particle != 'field') return; __INPUTS.cancelClick = true; if (!e.readOnly && !(p && p.readOnly)) { if (e.arrow == 'auto' && e.glyph) e.className = e.glyph+' FIELD-'+e.dt; } e.onkeydown = __INPUTS.keydown; var fn=__INPUTS.getcallback(e, 'onFieldEnter'); if (fn) fn(e); } __INPUTS.focusout = function() { _selectedEnum = ''; _selItem = ''; } __INPUTS.blur = function() { var e=event.srcElement, p=e.parentElement; if (e.currentStyle.particle != 'field') return; __INPUTS.cancelClick = false; if (!e.readOnly && !(p && p.readOnly)) { if (e.arrow == 'auto' && e.glyph) e.className = e.glyph; } if ('color' == e.dt) { e.runtimeStyle.backgroundColor = ''; } switch (e.dt) { case 'color': case 'combo': case 'date': case 'datetime': case 'float': case 'int': case 'str': case 'time': case 'url': case 'expr': case 'user': case 'text': // if the context (selected in the storyboard) element supports translation handling, check if we are about to lose translation if ($ENV.model && $ENV.model.isTranslationFreeze) { //if we are in translation freeze mode var splitted = (e.gmlid || '').split('@'); var gmlObj = $ENV.getElement(splitted[0]); if (ISA(gmlObj, "gml:TransObject")) // only TransObject supports translation handling (via the method translationHandling) if ($ENV.model.isTranslationFreeze) { var msgs={ #[TRANSLATE_NOP]: null, //no impact on translation #[TRANSLATE_MOD]: '#TEXT[YMSG_MODIFY_TRANSLATION]', //need to retranslate #[TRANSLATE_NEW]: '#TEXT[YMSG_MODIFY_TRANSLATION]', //need to retranslate #[TRANSLATE_DEL]: '#TEXT[XMSG_LOSE_TRANSLATION]' }; //translation will be lost // willTranslationBeDeleted returns an emuneration, and the messages in the msgs object conform to the return code: // 0=no change 1=translation modified 2=new translation 3=translation deleted ; see the contstants in gml:defs.inc var msg = msgs[gmlObj.willTranslationBeDeleted(e.id || e.owner, e.value, e.value, e.data, true)]; if (msg && !canDeleteTextObjects(null, true, msg, null)) { // ask the modeler if he agrees to lose translation IDs SET_INPUT(e, e.data, false); break; // if modeler elects to cancel the operation - break } } } SET_INPUT(e, e.value, true); break; } var fn=__INPUTS.getcallback(e, 'onFieldExit'); if (fn) fn(e) } __INPUTS.click = function() { var e=event.srcElement, p=e.parentElement; if (e.className && e.className.indexOf('FIELD-EXPR-BOOL') >= 0) { var check = e; e = e.nextSibling; } //Enable to extend the click action by the developer. var fn=__INPUTS.getcallback(e, 'onFieldClick'); if (fn) fn(e); var fcancel=__INPUTS.cancelClick; __INPUTS.cancelClick = false; if (fcancel) { var fn=__INPUTS.getcallback(e, 'onFieldFirstClick'); if (!fn || !fn(e)) fcancel=false; } var dt = e.dt; if (e.disabled || (p && p.disabled)) return; if (e.readOnly || (p && p.readOnly)) { if ((dt != 'expr') && (dt != 'obj') && (dt != 'ref') && (dt != 'user')) return; } if (!e.currentStyle || e.currentStyle.particle != 'field') return; if (dt == 'bool') { SET_INPUT(e, !GET_INPUT(e), true); return; } if (dt == 'toggle') { var list=GET_ENUM(UNESCAPE(e['enum'])), data=GET_INPUT(e); if (!list || !list.$ORDER) return; list = list.$ORDER; for (var i=0, len=list.length; i Handles the keydown event in order to select the item (on any enum type) that has Common prefix (user type - full prefix, all others - one char). The input field object function handleKeyDown(e) { var code = event.keyCode; // Up-down keypads implemented @ PopupMgr.js in popupHandlers keyDown event! if (code == #[UP] || code== #[DOWN]) return; var selObj = _selectedEnum.split('^'); if (selObj && !selObj[0]) selObj[0] = getCurPopupSelection() || ''; var enumObj = GET_ENUM(UNESCAPE(e['enum'])); var isTypeUser = (e.dt == 'user') ? true : false; var isTypeIcon = (e.dt == 'icon' || e.dt == 'colorenum') ? true : false; var firstEnum = null; var firstSelEnum = null; var madeMark = false; if (!_curPopup) _curPopup = getCurPopup(); /////// Selection of value case Enter key ////////////////////// if (code == #[ENTER]) { if (selObj && selObj[0]) { var j = null; for (j in enumObj) if (enumObj[j] == selObj[0]) break; var tmpVal = CLONE(e.value); if (j) SET_INPUT(e, j, true); if (_curPopup) _curPopup.hide(); _selectedEnum = ''; // Clear cache event.cancelBubble=true; // Cancel bubbeling when open } return; } if (code > 95 && code < 106) code -= 48; // Formatting keypad numbers var sChar = String.fromCharCode(code).toLowerCase(); if (isTypeUser) { if (code == 8) _selItem = _selItem.substr(0, _selItem.length -1); // Backspace else _selItem = (_selItem || '') + sChar; } if (!sChar) return; var isCEdit = false if (BOOL(e.contentEditable)) isCEdit = true; var index = 0; if (isTypeIcon) selObj[0] = trimHTML(selObj[0]); for (var i in enumObj) { if (i.charAt(0) != '$') { var enm = CLONE(enumObj[i]); if (isTypeIcon || (enm.indexOf('<') == 0)) enm = trimHTML(enm); if (!isCEdit) { if (enm.charAt(0).toLowerCase() == sChar) { if (!firstEnum) { // Cyclic selection first choise firstEnum = enm; firstSelEnum = enumObj[i] + '^' + index; } if ((enumObj[i] != selObj[0] && index > (selObj[1] || 0)) || (sChar != enm.charAt(0).toLowerCase())) { madeMark = true; markSelected(enm); _selectedEnum = enumObj[i] + '^' + index; return; } } } else { // This block handle 'user' dropdown var tmpEnm = enm.toLowerCase(); if ((_selItem) && (tmpEnm.substr(0, _selItem.length) == _selItem)) { SET_INPUT(e, null, true); // Reset input e.value = enm; markSelected(enm); SELECT_RANGE(e, _selItem.length, i.length - _selItem.length); event.returnValue = false; // Not assign the new value for the input control return; } else markSelected(null); } index++; } } // Mark cyclic selection if (firstEnum && !madeMark) { markSelected(firstEnum); _selectedEnum = firstSelEnum; } } function markSelected(val, selGlyph) { var pops = __POPUP.allPopups; if (ISEMPTY(pops)) return; // Done only once to find referance to dropdown's SPAN element if (!_curPopup) _curPopup = getCurPopup(); if (!_curPopup) return; var activeElemChilds = getCurPopupChilds(); var len = (activeElemChilds && activeElemChilds.length) || 0; for (var m=0; m= len-1) return null; } return null; } __INPUTS.getcallback = function(obj, name) { if (obj[name]) return (obj[name] == 'NONE' ? null : obj[name]); for (var e=obj; e && !e[name]; e=e.parentElement); obj[name] = e ? e[name] : 'NONE'; return e ? (e[name] == 'NONE' ? null : (typeof e[name] == 'function' ? e[name] : null)) : null; } //////////////////////////////////////////////////////////////////////// // Dynamic Expressions support <@func name="validateDynExp" also="editDynExp" scope="private"> Converts expression from its UI representation to persistent representation or vice versa. Validates the expression while converting and marks input field with error text, if any. The input field object The dynamic expression ~true if expr should be converted to UI representation, ~false if expr should be converted to persistency representation The converted and validated expression function validateDynExp(obj, expr, forUI) { var id = obj.gmlid; if (!id) return null; // only gmlobject-bound DE properties are supported var prop = obj.owner; // get bound property name var type = obj.exprType || null; // get optional expected type if (expr === '' || expr === null || expr === undefined) { if( !$CTL.isFreestyle() && type=="Boolean" && !obj.isDisabled){ MARK_INPUT(obj,'#TEXT[XMSG_EMPTY_BOOLEAN]'); return ''; } else{ MARK_INPUT(obj); // empty expr is a valid literal expression (implicit conversion is defined to all types) return ''; } } expr = expr+''; // Just make sure this is a string representation for the parser var dynexp = $ENV.dynexp; // Getting the DynExp engine if (!dynexp) throw new Error(-1, '#TEXT[XMSG_NOT_GET_DE_ENGINE]'); // Fatal error, cannot continue try { var unit = $ENV.contextUnit; var splitted = (id || '').split('@'); var element = unit.getElement(splitted[0], true); // TODO: try to see how to get rid of DOM dependency var nodeName = null; if (splitted.length > 1 && ISA(element, 'gml2:PInfoset')) { nodeName = splitted[1]; if (!element.getInfoHelper().findNode(nodeName)) nodeName = null; } if (obj.exprTypeFN) type = obj.exprTypeFN.apply(element, [element, prop]); } catch (e) { #LOG[4, 'Error getting dynamic expression context element or expression type: '+e.description]; // don't return - we can still make it working for literals in the 'if' below } // If expr doesn't start with '=', then it's a literal and we don't need full parsing, but only type checking /*if (expr.charAt(0) != '=') { var errText = []; if (type == null) type= #[STRING]; var err = (type != #[STRING] && !dynexp.isValidType(expr, type, errText)) ? errText[0] : ''; MARK_INPUT(obj, err); return expr; }*/ // Expr starts with '=' (can be literal or or not) - do full parsing and validation if (!RULE('setDynExpContext', unit, element, prop)) { #LOG[4, 'Error setting dynamic expressions context']; return null; } if ($CTL.isFreestyle() && nodeName) dynexp.setContextNode(nodeName); dynexp.setExpectedType(type); dynexp.setParsingByID(forUI); dynexp.parse(expr); var result = expr; MARK_INPUT(obj, dynexp.error); if (!dynexp.isLiteral) { // if expression is not literal - perform UI->ID conversion or ID->UI conversion (even if there was error) result = dynexp.genericPrint(forUI); //if (dynexp.error || result.length == 0) result = expr; if(dynexp.error) MARK_INPUT(obj, dynexp.error); if(result.length == 0) result = expr; } return result; } <@func name="editDynExp" also="validateDynExp" scope="private"> Opens DE editor dialog and handles it's result. The input field object The dynamic expression function editDynExp(obj, expr) { var id = obj.gmlid; if (!id) return; // only gmlobject-bound DE properties are supported var prop = obj.owner; // get bound property name var type = obj.exprType || null; // get optional expected type var dynexp = $ENV.dynexp; // Getting the DynExp engine if (!dynexp) throw new Error(-1, '#TEXT[XMSG_NOT_GET_DE_ENGINE]'); // Fatal error, cannot continue try { var unit = $ENV.contextUnit; var splitted = (id || '').split('@'); var element = unit.getElement(splitted[0], true); // TODO: try to see how to get rid of DOM dependency var nodeName = null; if ($CTL.isFreestyle() && splitted.length > 1 && ISA(element, 'gml2:PInfoset')) { nodeName = splitted[1]; if (!element.getInfoHelper().findNode(nodeName)) nodeName = null; } if (obj.exprTypeFN) type = obj.exprTypeFN.apply(element, [element, prop]); } catch (e) { #LOG[4, 'Error setting dynamic expression context element: '+e.description]; return; } var result = RULE('setDynExpContext', unit, element, prop); if (!result) { #LOG[4, 'Error setting dynamic expressions context']; return; } if ($CTL.isFreestyle() && nodeName) dynexp.setContextNode(nodeName); //if (ISA(result, 'dev:DynExpContext')) { // GML version of the rule // result.setPrevExprTxt(expr); // var params = {dynExpCtxParam: result}; //} //else { // GML+ version of the rule // var params = {exprType: type, exprText: expr}; //} var params = {exprText: expr, comments: dynexp.handleExprComments(obj.data)[1]}; //var params = {exprText: expr}; dynexp.setExpectedType(type); var res = MODAL('#URL[dev:common.DynExpDlg.htm]', params, true); if (res) { SET_INPUT(obj, res.ui, true, true); } } <@func name="SELECT_RANGE" scope="public"> Select part of the input field's text HTML input Index to start selection Index to end selection function SELECT_RANGE(input, start, end) { if (!input) return; var txtRange = input.createTextRange(); txtRange.moveStart("character", start); txtRange.moveEnd("character", end); txtRange.select(); } <@func name="GET_CARET" scope="public"> Returns the cursor position in a TEXTAREA element a given TEXTAREA element Cursor position in the TEXTAREA function GET_CARET(node) { if(node.selectionStart) { return node.selectionStart; } else if(!document.selection) { return 0 } // Creating a special char for caret position marking var c = "\001"; // Creating selection for all text var sel = document.selection.createRange(); // Creating a duplicate selection var dul = sel.duplicate(); // Move to end of text dul.moveToElementText(node); sel.text = c; // Get Caret position var len = (dul.text.indexOf(c)); // Clear selection sel.moveStart('character',-1); sel.text = ""; return len; } //////////////////////////////////////////////// // INTERNAL var _selectedEnum = '', _curPopup=null, _selItem=null;