@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;