<@script name="Global"> Contains global %STUDIO% macros and data structures (c) SAP AG 2003-2006. All rights reserved. #DEPENDENCIES[ lib:Basic.js lib:EventsMgr.js lib:PopupMgr.js lib~skin:styles.Global.css ] //////////////////////////////////////////////////////////////////// // GMLSCRIPT MACROS <@func name="BEGIN" also="@gml:ModelRecorder" group="I. GmlScript Macros"> Begins a GMLDOM transaction A display name to assign to the transaction. function BEGIN(name, refreshMask) { if ($ENV){ if ($ENV.recorder) $ENV.recorder.begin(name, refreshMask); } } <@func name="COMMIT" also="@gml:ModelRecorder"> Commits a GMLDOM transaction A display name to assign to the transaction. function COMMIT(name, refreshMask, unitId) { if ($ENV){ if ($ENV.recorder) $ENV.recorder.commit(name, refreshMask, unitId); } } function RECORD(recordObj) { if ($ENV){ if ($ENV.recorder) $ENV.recorder.record(recordObj); } } function CANCEL(name) { if ($ENV){ if ($ENV.recorder) $ENV.recorder.cancel(name); } } function RESET(unitId) { if ($ENV){ if ($ENV.recorder) $ENV.recorder.reset(unitId); } } <@func name="CLASS"> Gets a specified classifier The classifier name The requested classifier function CLASS(className) { return $ENV.getClass(className); } <@func name="ISA"> Tests whether a given object is an instance of one or more GmlScript classes The object to test A variable list of qualified class names to test The test result function ISA(obj) { var cstor=obj && obj.Class || null; if (!cstor || !cstor.isClass) return false; if (arguments[1] in cstor.precedents) return true; // fast check the most common case for (var i=1, len=arguments.length; i Tests whether a given object has an attached aspect of specified type The object to test The qualified aspect name for more specific test The test result function HAS_ASPECT(obj, aspectName) { var cstor=obj && obj.Class || null, aspect=$ENV.getClass(aspectName); if (!cstor || !cstor.isClass || !aspect) return false; var dep=cstor.dependents[aspect.rolename]; if (!dep) return false; if (!aspectName || dep.fullname == aspectName) return true; var aspect2=$ENV.getClass(dep.fullname); return aspect2 && (aspect.fullname in aspect2.precedents); } <@func name="RULE"> Executes a specified rule The rule Id The rule arguments The rule execution result function RULE(id, p1, p2, p3, p4, p5, p6, p7, p8, p9) { return $ENV.executeRule(id, p1, p2, p3, p4, p5, p6, p7, p8, p9); } <@func name="ROLLBACK" also="@gml:ModelRecorder"> Rolls back a GMLDOM transaction function ROLLBACK() { if ($ENV){ if ($ENV.recorder) $ENV.recorder.rollback(); } } <@func scope="private" name="OPTIMIZED_ROLLBACK" also="@gml:SimpleModelRecorder"> Rolls back a GMLDOM transaction function OPTIMIZED_ROLLBACK() { if ($ENV){ if ($ENV.recorder) $ENV.recorder.optimizedRollback(); } } //////////////////////////////////////////////////////////////////// // JAVASCRIPT MACROS <@func name="CLONE" group="II. JavaScript Macros"> Clones a given object An object/array to clone Indicates whether to perform a deep or shallow operation The cloned object function CLONE(obj, deep, depth) { if (!obj || typeof obj != 'object') return obj; if (!depth) depth = 0; if (depth > 50) return null; if (ISARRAY(obj)) { var c=[]; for (var i=0, len=obj.length; i Truncates a string to the specified length and appends an ellipsis symbol, but only in case the string was actually truncated The string to truncate The maximum length The truncated string function ELLIPSIS(s,len) { if (s === undefined || s === null) return ''; return (s+'').substring(0,len) + ((s+'').length>len ? '...' : ''); } <@func name="ESCAPE" also="UNESCAPE"> Returns an encoded form of the given string that can be read on all computers The string to encode The endcoded string function ESCAPE(s) { if (s === undefined || s === null) return ''; return escape(s+'').replace(/\%20/g,' '); } <@func name="ESCAPE_TO_HTML"> Returns an encoded form of the given string. This is used for eliminating security hazards The string to encode The endcoded string function ESCAPE_TO_HTML(str) { if (str === undefined || str === null) return ''; return (str+'').replace(/([\"\&\<\>\'])/g, ESCAPE_TO_HTML.rep); } ESCAPE_TO_HTML.map = {'"':'"', '&':'&', '<':'<', '>':'>', '\'':'''} ESCAPE_TO_HTML.rep = function(a,b) { return ESCAPE_TO_HTML.map[b]||b; } <@func name="ISARRAY"> Tests whether a given object is an array An object to test Returns ~true if %0 is an array; otherwise, returns ~false function ISARRAY(obj) { // cannot use instanceof operator because tested object may reside in another execution context if (!obj || typeof obj != 'object') return false; var type = obj.constructor+''; return (type.substring(10, type.indexOf('(')) == 'Array'); } <@func name="ISDATE"> Tests whether a given object is a Date object An object to test Returns ~true if %0 is a Date object; otherwise, returns ~false function ISDATE(obj) { // cannot use instanceof operator because tested object may reside in another execution context if (!obj || typeof obj != 'object') return false; var type = obj.constructor+''; return (type.substring(10, type.indexOf('(')) == 'Date'); } <@func name="ISDATE"> Tests whether a given String is in DATE format An object to test Returns ~true if is in DATE format otherwise, returns ~false function ISSTRDATE(dateString) { if (dateString.match(/^(\d+)[\/\.\-](\d+)[\/.\-](\d+)/)) { this.lexpos += RegExp.lastIndex; var dd=parseInt(RegExp.$1,10), mm=parseInt(RegExp.$2,10), yy=parseInt(RegExp.$3,10); if (yy < 70) yy += 2000; else if (yy < 100) yy += 1900; if (mm<1 || mm>12 || dd<1 || dd>31 || (dd>30 && (mm==4||mm==6||mm==9||mm==11)) || (mm==2 && ((yy%4==0 && dd>29) || (yy%4!=0 && dd>28)))) return false; return (('00'+dd).slice(-2)+'/'+('00'+mm).slice(-2)+'/'+yy); } else return false; } <@func name="ISEMPTY"> Tests whether a given object is empty An object to test The test result function ISEMPTY(obj) { if (!obj || typeof obj != 'object') return true; for (var k in obj) return false; return true; } <@func name="ISFUNC"> Tests whether a given object is a function An object to test Returns ~true if %0 is a function; otherwise, returns ~false function ISFUNC(obj) { // cannot use instanceof operator because tested object may reside in another execution context if (typeof obj == 'function') return true; if (!obj || typeof obj != 'object') return false; var type = obj.constructor+''; return (type.substring(10, type.indexOf('(')) == 'Function'); } <@func name="ISURL"> Tests whether a given string represents a valid URL A string to test Returns ~true if %0 is a valid URL; otherwise, returns ~false function ISURL(url) { //var urlPattern = /^(?:(?:https?):\/\/)?(?:[a-z0-9](?:[-a-z0-9]*[a-z0-9])?\.)+(?:com|edu|biz|org|gov|int|info|mil|net|name|museum|coop|aero|[a-z][a-z])\b(?:\d+)?(?:\/[^;"'<>()\[\]{}\s\x7f-\xff]*(?:[.,?]+[^;"'<>()\[\]{}\s\x7f-\xff]+)*)?/; //var urlPattern = /^(?:(?:https?):\/\/)?(?:[a-z0-9](?:[-a-z0-9]*[a-z0-9])?\.)+(?:\d+)?(?:\/[^;"'<>()\[\]{}\s\x7f-\xff]*(?:[.,?]+[^;"'<>()\[\]{}\s\x7f-\xff]+)*)?/; //var urlPattern = /^((http|https):\/\/)?[\-a-z0-9]+(\.[\-a-z0-9]+)+[\-a-z0-9]{2,5}(:([0-9]{1,5})?\/.*)?$/; var urlPattern = /^((http|https):\/\/)[\-a-z0-9]+(\.[\-a-z0-9]+)*(:([0-9]{1,5}))?(\/.*)?$/; var result = urlPattern.test(url.toLowerCase()); return result; } <@func name="JOIN" also="SPLIT JOINN"> Concatenates an array of strings into a single string using a specified delimiter An array of strings Delimiter string (default is an empty string) The concatenated string function JOIN(arr,delim) { return (arr||[]).join(delim || ''); } <@func name="JOINN" also="SPLITN JOIN"> Concatenates an array of numbers into a single string using a specified precision An array of numbers The precision to use when converting a number to string The resulting string The numbers in %0 are rounded to precision %1 and then concatenated with spaces into the result string. function JOINN(a,prec) { prec=Math.pow(10,prec||4); for (var i=0, A=[], len=a.length; i Returns an object built from the keys listed in a given string A string containing the keys separated by whitespace An object function KEYS2OBJ(keys) { var obj = {}; if (!keys) return obj; var arr = keys.split(' '); for (var i=0,len=arr.length; i Converts a positive integer to a lexical sequence of letters (A,B,C,...Z,AA,AB,...) The number to convert The result lexical value function LEX_VAL(n) { for (var lex='', n=parseInt(n)||0; n>0; n = Math.floor((n-1)/26)) { lex = String.fromCharCode((n-1)%26+65) + lex; } return lex; } <@func name="LEX_NEXT" also="LEX_NUM LEX_VAL"> Returns the next lexical value after a given lexical value The input lexical value The next lexical value function LEX_NEXT(lex) { if (!lex) return 'A'; var pref=lex.slice(0,-1), suff=lex.slice(-1); if (suff<'Z') return pref + String.fromCharCode(suff.charCodeAt(0)+1); return LEX_NEXT(pref)+'A'; } <@func name="LEX_MAX" also="LEX_NUM LEX_VAL"> Returns the maximum value among a pair of lexical values The first lexical value The second lexical value The maximum lexical value function LEX_MAX(lex1, lex2) { if (!lex1) return lex2 || ''; if (!lex2) return lex1 || ''; var len1=lex1.length, len2=lex2.length; return (len1 > len2) ? lex1 : (len1 < len2) ? lex2 : (lex1 > lex2 ? lex1 : lex2); } <@func name="LEX_NUM" also="LEX_VAL LEX_NEXT"> Converts a lexical sequence of letters (A,B,C,...Z,AA,AB,...) into the number they represent The lexical value to convert The result numeric value function LEX_NUM(lex) { if (!lex) return 0; lex = (lex||'').toUpperCase(); for (var i=lex.length, n=0, e=1; i>0; i--, e*=26) { n += (lex.charCodeAt(i-1)-64)*e; } return n; } <@func name="OBJ2KEYS"> Returns a string listing the keys of the items in a given object An object Indicate whether to sort the results A string containing the object item keys separated by whitespace function OBJ2KEYS(obj, sort) { if (!obj || typeof obj != 'object') return ''; var arr = []; for (var x in obj) arr.push(x); if (sort) arr.sort(); return arr.join(' '); } <@func name="QUOTE"> Returns the given string enclosed in single quotes The string to quote The quoted string function QUOTE(s) { if (typeof s != 'string') s=(s||'')+''; return '\''+s.replace(/\\*\'/g, repQuote).replace(/\r/g,'').replace(/\n/g,'\\n')+'\''; function repQuote(a){ if (a.length % 2 == 1) { return(a.substring(0,a.length-2) + '\\\''); } else return(a); } } <@func name="SORT" also="SORTN"> Sorts an array of objects by a specified slot in alphabetical order An array to sort The slot to sort by (must exist in all object items) The sorted object items function SORT(obj , slot) { var arr = obj; try{ if (!(ISARRAY(obj))) { arr = []; for (var x in obj) arr.push(obj[x]); } return arr.sort(collate); } catch (e) { return arr; } function collate(a,b) { var a0=(a[slot]+'').toUpperCase(); var b0=(b[slot]+'').toUpperCase(); return (a0b0 ? 1 : 0)); } } <@func name="SORTF" > Sorts an array of objects by a specified compare function An array to sort The function to sort by The sorted object items function SORTF(obj , f) { var arr = obj; try{ if (!(ISARRAY(obj))) { arr = []; for (var x in obj) arr.push(obj[x]); } return arr.sort(f); } catch (e) { return arr; } } /* function newSORT(obj , slot) { var arr = obj; try{ if (!(ISARRAY(obj))) { arr = []; for (var x in obj) arr.push(obj[x]); } if ( (typeof slot) != 'function'){ return arr.sort(collate); }else{ return arr.sort(collateGetter); } } catch (e) { return arr; } function collateGetter(a,b){ var a0=(slot(a) +'').toUpperCase(); var b0=(slot(b) +'').toUpperCase(); return (a0b0 ? 1 : 0)); } function collate(a,b) { var a0=(a[slot]+'').toUpperCase(); var b0=(b[slot]+'').toUpperCase(); return (a0b0 ? 1 : 0)); } } */ <@func name="SORTN" also="SORT"> Sorts an array of objects by a specified slot in numeric order An array to sort The slot to sort by (must exist in all object items) The sorted object items function SORTN(obj, slot) { var arr = obj; try{ if (!(ISARRAY(obj))) { arr = []; for (var x in obj) arr.push(obj[x]); } return arr.sort(collate); } catch (e) { return arr; } function collate(a,b) { var a0=parseFloat(a[slot]||0); var b0=parseFloat(b[slot]||0); return (a0b0 ? 1 : 0)); } } <@func name="SPLIT" also="JOIN SPLITN"> Splits a string into an array of substrings separated by a specified delimiter A string Delimiter string or regular expression The resulting array of substrings function SPLIT(s,delim) { if (!s) return []; return (s+'').split(delim || /\s/); } <@func name="SPLITN" also="JOINN SPLIT"> Splits a string into an array of numbers A string Expected array length The resulting array of numbers The %0 string is assumed to contain a list of floating-point numbers separated by whitespace. function SPLITN(s, len) { var A=((s||'')+'').split(/\s/); var L=Math.max(A.length, len||0); for (var i=0; i Returns a formatted string representation of the given object Any JavaScript object Maximum depth to scan Number of spaces to use for indentation (0 means no indentation) If ~obj is a Javascript collection, then ~STR prints all the object's properties and their value, recursively until ~max depth.
If ~obj contains circular dependencies, the result of calling ~STR(obj) will be a very long string with impact on performance.
Therefore, always be sure that either your object is small enough, or that ~max is limited to a small value. Never use ~STR on GML objects without limiting ~max, becasue all GML objects contain circular dependencies:
obj.parent = p;
p.children[obj.id] = obj;
The formatted object string function STR(obj, max, indent) { indent = parseInt(indent) || 0; var cr = indent ? '\n' : ''; var sp = indent ? (arguments[3]||'')+FILL(' ',indent) : ''; var n1 = arguments[4] || 0; var n2 = parseInt(max)|| 20; switch (typeof obj) { case 'number': return obj+''; case 'boolean': return obj+''; case 'function': return func2str(obj); case 'string': return QUOTE(obj); case 'undefined': return ''; } if (!obj) return 'null'; if (obj.scopeName) return QUOTE(obj.outerHTML); if (obj.nodeName) return QUOTE(obj.xml); if (obj.fullname) return obj.type+' '+obj.fullname; if (obj.isMethod) return func2str(obj, obj.name); var type = obj.constructor+''; type = type.substring(10, type.indexOf('(')); switch (type) { case 'Date': return 'new Date('+obj.getTime()+')'; case 'Function': if (n1>n2) return '\'[function]\''; return obj+''; case 'Array': if (n1>n2) return '\'[array]\''; for (var i=0, A=[], len=obj.length; in2 || !obj.hasOwnProperty) return '\'[object]\''; var A=[]; for (var k in obj) { if (!obj.hasOwnProperty(k)) continue; var item = obj[k]; var pref = k+''; if (pref.search(/[^\w\$]/) >= 0 || pref.charAt(0).search(/\d/) == 0) pref = QUOTE(pref); pref = sp + pref + (indent ? ': ' : ':'); switch (typeof item) { case 'number': A.push(pref+item); break; case 'boolean': A.push(pref+item); break; case 'function': A.push(pref+func2str(item)); break; case 'string': A.push(pref+QUOTE(item)); break; case 'undefined': break; default: if (!item) { A.push(pref+'null'); break; } A.push(pref+STR(item,max,indent,sp,n1+1)); break; } } if (!indent) return '{'+JOIN(A,',')+'}'; return '{'+cr+JOIN(A,','+cr)+cr+sp.slice(0,-indent)+'}'; } function func2str(func, name) { if (func.fullname) return func.type+' '+func.fullname; var str=func+'', k1=str.indexOf('('), k2=str.indexOf(')'); if (k1<0 || k2<0 || k2 Returns the decoded form of a string encoded with the @ESCAPE. The string to decode The decoded string function UNESCAPE(s) { if (s === undefined || s === null) return ''; return unescape(s+''); } <@func name="VAL" also="STR"> Parses a string representing an object Any valid string representation of a JavaScript object The parsed object function VAL(str) { if (str === null || str === undefined) return null; if (typeof str != 'string') return str; if (str === '') return ''; try { var obj; eval('obj='+str); return obj; } catch(e) { return null; } } function dump(obj, max) { alert(STR(obj, max||2, 3)); } <@func name="QNAME"> Validate field names: Only the characters a-z (ignoring case), 0-9 and '_' (underscore) are allowed. Any sequence of unallowed characters is replaced with one '_'. Name can begin with the characters a-z (ignoring case) or '_'. If it begins with a number than the character 'F' is added in the beginning. The field name New valid name according to the field name conventions function QNAME(name) { if (name == null || name == undefined) return; name = TRIM(name); name = name.replace(/\W+/g,'_') if (name.search(/^[a-z_]/i) == -1) name = 'F' + name; return name; } <@func name="TOARRAY"> Transform JS Collection into JS Object of type Array JS Collection function TOARRAY(collection) { var arr = []; for (var k in collection) arr.push(collection[k]); return arr; } /////////////////////////////////////////////////////////////////////////////////////////////////// // WINDOW CONTROL var __WPARENT; var __WSTUDIO; var __WTYPE; var __WFRAME; var __WSIBLINGS = {} var __WIN_LISTENERS = {oninit:[], onexit:[], onshow:[], onhide:[], onresize:[], onoptionsmenu:[]}; var __STB_LISTENERS = []; var __DOM_LISTENERS = {}; <@func name="DISABLE" group="III. Window Control"> Disables a given HTML object An HTML object ~true=disabled, ~false=enabled Text tp display when disabled function DISABLE(obj, flag, str) { if (!obj) return; var suffix = 'DIS' var gl=(obj.currentStyle.glyph || obj.className), st=(flag ? suffix : ''); if (str) { if (UPPER(str) == 'TRUE') obj.innerText = '#TEXT[XFLD_LOADING_LABEL]'; else obj.innerText = str; } if (obj.currentStyle.state == st) return; obj.style.state = st; obj.disabled = flag; if (obj.currentStyle.glyph) obj.className = gl + (st ? ' '+gl+'-'+st : ''); else if (obj.className) { var cname = SPLIT(obj.className, ' '); var len = cname.length; var reg = new RegExp('-'+suffix+'$', 'i'); if (!cname[len-1].match(reg)){ if (st) cname.push(cname[len-1]+'-'+st); } else if (!st) cname = cname.slice(0, -1); obj.className = JOIN(cname, ' '); } } <@func name="FLIPVAR"> Toggles the value of a boolean variable Variable name function FLIPVAR(name) { $CTL.setVar(name, !$CTL.getVar(name)); } <@func name="FOCUS"> Moves the input focus to a given HTML object An HTML object function FOCUS(elm) { try { elm.focus(); } catch (e) {} } <@func name="GETTEMP"> Gets the value of a temporary variable Variable name Default value to use in case the variable is empty or undefined The requested variable value function GETTEMP(name, dflt) { return $CTL.getTempVar(name, dflt); } <@func name="GETVAR"> Gets the value of a specified kit or system variable. Variable name Default value to use in case the variable is empty or undefined The requested variable value In J2EE server, those variables are persisted on the server and on the IIS version it is persisted in the client. A default value may be supplied by a kit on the variable definition. (Those defaults would have to be known on the server implementation as well because if the user does not change the default, no value will be stored on the server for that user). function GETVAR(name, dflt) { return $CTL.getVar(name, dflt); } <@func name="ISSUP"> Checks if a feature is supported class, property, value, or feature is supported First key to search, e.g. fully-qualified class name Second key to search, e.g. case-sensitive property name Third key to search, e.g. case-sensitive property value Value to return if support for the feature is undefined. If ommited, ~false is returned in such case ~true if the requested feature is supported, ~false otherwise function ISSUP(key1, key2, key3, dflt) { if (dflt === undefined) dflt = false; var res = RULE('defineSupportedFeatures', key1, key2, key3); if (res !== true && res !== false) return dflt; return res; } <@func name="LISTEN"> Registers an event listener The event name The event listener Indicates the event listener's scope, according to: ~visible = only when the containing window is visible (the default), ~always = throughout the containing window's lifetime. Applies only to environment events.

Use this macro to register efficient event listeners. The %STUDIO% framework will ensure that any event listeners registered using this macro are attached just in time, and detached when no longer needed.

Event names are unqualified and case-insensitive. Event names are resolved in the following order:

Builtin window events (see table below) Installed GMLDOM events (available events depend on current kits configuration) Environment events (see @env:Environment!)

Even though it is not required, you can still qualify GMLDOM events with the $DOM prefix (e.g., $DOM.onUpdateObject) and environment events with the $ENV prefix (e.g., ~$ENV.onModelOpen). Any other %STUDIO% events must be qualified using their respective module prefix (e.g., $WIN.onWindowChange).

The builtin window events are listed below:

Event | Description onInit | Fires once during window initialization (before first call to ~onShow) onExit | Fires once during window termination (after last call to ~onHide) onShow | Fires whenever the window is exposed (applicable for boards, floating windows, and task panels) onHide | Fires whenever the window is concealed (applicable for boards, floating windows, and task panels) onResize | Fires whenever the window is resized onOptionsMenu | Fires whenever the window's options menu is requested (applicable only for task panels) onSettingsChange | Fires whenever a %STUDIO% settings value is changed onStudioExit | Fires when the %STUDIO% is being exited
function LISTEN(name, func, scope) { if (!name || !func) return; var prefix = '' ; var eventName = '' ; if (name.indexOf(':') > 0 ) eventName = LOWER(name); else{ var k=name.indexOf('.'); prefix = name.substring(0,k); eventName = LOWER(name.substring(k+1)); } if (!prefix) { if (eventName == 'onsettingschange' || eventName == 'onstudioexit') prefix = '$CTL'; } if (!prefix && (eventName in __WIN_LISTENERS)) { __WIN_LISTENERS[eventName].push(func); } else { var domEvents = $ENV.getEventTypesTable(), modules=__WSTUDIO.$CTL.modules; if (!prefix) prefix = (eventName in domEvents) ? '$DOM' : '$ENV'; if (prefix == '$DOM') { if (!(eventName in domEvents)) return; if (!(eventName in __DOM_LISTENERS)) { if (ISEMPTY(__DOM_LISTENERS)) { __STB_LISTENERS.push({module:modules.$ENV, name:'onModelEvent', func:__WIN_DOM_EVENTS}); } __DOM_LISTENERS[eventName] = []; } __DOM_LISTENERS[eventName].push({name:eventName, func:func}); } else if (prefix in modules) { __STB_LISTENERS.push({module:modules[prefix], name:eventName, func:func, always:(LOWER(scope) == 'always')}); } } } <@func name="SETTEMP"> Sets the value of a temporary variable Variable name New variable value (if the value is empty or omitted, the variable will be deleted) function SETTEMP(name, value) { $CTL.setTempVar(name, value); } <@func name="SETVAR"> Sets the value of a specified kit or system variable Variable name New variable value (if the value is empty or omitted, the variable will be deleted) function SETVAR(name, value) { $CTL.setVar(name, value); } <@func name="SIGNAL"> Executes a specified signal A signal definition to execute A variable list of arguments that, if provided, supercedes any arguments embedded in the signal Returns the signal execution results, if any function SIGNAL() { try { // get the signal specifier and arguments if (arguments.length == 0) return ''; var signal=arguments[0], args=[]; for (var i=1, len=arguments.length; i'); if (k <= 0) return eval(signal); // parse the signal specifier into its composite parts var target=signal.substring(0,k), method=signal.substring(k+2), args2=''; var k=target.indexOf(':'), modifier=''; if (k>0) { modifier=target.substring(k+1); target=target.substring(0,k); } if (method.charAt(0) == '>') { strong=true; method = method.substring(1); } var k=method.indexOf('('); if (k>0) { args2=method.substring(k+1, method.length-1); method=method.substring(0,k); } if (args.length == 0) args = eval('['+args2+']'); var a1=args[0], a2=args[1], a3=args[2], a4=args[3], a5=args[4]; target = target.toUpperCase(); // handle special case of a strong task panel signal if (strong && target == 'PANEL') { target = $TSK.getPanelWindow(modifier); if (!target) { $TSK.openPanel(modifier, true, function() { try { var target = $TSK.getPanelWindow(modifier); if (target) target[method](a1,a2,a3,a4,a5); } catch(e) {} }); } else { $TSK.openPanel(modifier, true); target[method](a1,a2,a3,a4,a5); } return; } // obtain a reference to the signal target and apply the signal method on it if (target.charAt(0) == '$') { target = $CTL.modules[target] || null; } else { switch (target) { case 'BOARD': return $WIN.signalBoard(method, a1,a2,a3,a4,a5); case 'PANEL': target = $TSK.getPanelWindow(modifier); break; case 'CONTEXT': target = $ENV.context && $ENV.context.object || null; break; case 'UNIT': target = $ENV.contextUnit; break; case 'ELEMENT': target = $ENV.contextElement; break; case 'FIELD': target = $ENV.contextField; break; case 'SELF': target = window; break; case 'DETAILS': return $DET.signalTab(method, a1,a2,a3,a4,a5); } } if (target) return target[method](a1,a2,a3,a4,a5); } catch (e) { var s = 'Warning: signal "'+arguments[0]+'" failed: '+e.description; #DEVTIME[ WRITE(s); ] return null; } } <@func name="WRITE"> Writes a message on the output console The message to write function WRITE(msg) { if (arguments.length > 1) { for (var i=0, A=[], len=arguments.length; i Resizes the window and centers it over a specified target Window width in pixels Window height in pixels Target object for the centering (SCREEN | STUDIO | WORKSPACE | PARENT) function WCENTER(width, height, centerOn) { try { var w0=screen.availWidth, h0=screen.availHeight; var w1=width||document.body.clientWidth, h1=height||document.body.clientHeight; switch (__WTYPE) { case 'PANEL': return; case 'FRAME': var frm=frameElement, bod=frm.document.body; WMOVE((bod.clientWidth-frm.offsetWidth)/2, (bod.clientHeight-frm.offsetHeight)/2); return; case 'WINFRAME': case 'WINFRAME_LYT': __WFRAME.centerOn(); return; case 'PRIMARY': w1+=8; h1+=136; // estimated break; case 'SECONDARY': w1+=8; h1+=48; // estimated break; } var x2=0, y2=0, w2=w0, h2=h0; switch ((centerOn||'').toUpperCase()) { case 'SCREEN': break; case 'PARENT': if (!__WPARENT) break; var pobj=__WPARENT, pbody=pobj.document.body; x2 = pobj.screenLeft; y2 = pobj.screenTop; w2 = pbody.clientWidth; h2 = pbody.clientHeight; break; case 'WORKSPACE': var pobj=__WSTUDIO, prect=pobj.$WIN.getBoundingClientRect(); x2 = pobj.screenLeft + prect.left; y2 = pobj.screenTop + prect.top; w2 = prect.right-prect.left; h2 = prect.bottom-prect.top; break; case 'STUDIO': default: var pobj=__WSTUDIO, pbody=pobj.document.body; x2 = pobj.screenLeft; y2 = pobj.screenTop; w2 = pbody.clientWidth; h2 = pbody.clientHeight; break; } var cx=x2+(w2-w1)/2, cy=y2+(h2-h1)/2; if (cx > w0 || cy > h0) { cx = (w0-w1)/2; cy = (h0-h1)/2; } WMOVE(cx, cy); } catch(e) {} } <@func name="WCLOSE" also="WPARAM"> Closes the window and returns the given value Optional value to return from the window function WCLOSE(value) { PROMPT(); switch (__WTYPE) { case 'WINFRAME': case 'WINFRAME_LYT': __WFRAME.close(); break; case 'PANEL': case 'FRAME': break; default: if (value != undefined) { window.returnValue = value; } window.close(); break; } } <@func name="WHIDE" also="WPARAM"> Closes the window and returns the given value Optional value to return from the window function WHIDE(value) { PROMPT(); switch (__WTYPE) { case 'WINFRAME': case 'WINFRAME_LYT': __WFRAME.close(false, true); __WFRAME.closeCallback(value); break; case 'PANEL': case 'FRAME': break; default: if (value != undefined) { window.returnValue = value; } window.close(); break; } } <@func name="WMOVE" also="WRESIZE WCENTER"> Moves the window to a specified position Window left coordinate Window top coordinate The coordinates are relative to the screen for a top-level window, and relative to the container for an inline frame. function WMOVE(left, top) { switch (__WTYPE) { case 'PRIMARY': window.moveTo(left, top); break; case 'SECONDARY': window.moveTo(left, top); break; case 'DIALOG': dialogLeft=left+'px'; dialogTop=top+'px'; break; case 'FRAME': frameElement.style.left=left; frameElement.style.top=top; break; case 'PANEL': break; case 'WINFRAME': case 'WINFRAME_LYT': __WFRAME.moveTo(left, top); break; } } <@func name="WPARAM" also="WCLOSE"> Gets the value of a specified window parameter The parameter name The parameter value If %0 is omitted, the complete window parameters object is returned. function WPARAM(name) { if (__WFRAME) { var prm=__WFRAME.params; try { return name ? prm[name] : prm; } catch (e) { return null; } } else if (frameElement) { if (frameElement.winFrame) { //WPARAM called before WSETUP var prm=frameElement.winFrame.params; try { return name ? prm[name] : prm; } catch (e) { return null; } } if (!name) return null; return frameElement.getAttribute(name) || null; } else if (typeof dialogArguments != 'undefined') { var prm=dialogArguments.$PARAMS; try { return name ? prm[name] : prm; } catch (e) { return null; } } else if (typeof __WIN_PARAMS != 'undefined') { try { return name ? __WIN_PARAMS[name] : __WIN_PARAMS; } catch (e) { return null; } } else { return null; } } <@func name="WRESIZE" also="WMOVE WCENTER"> Resizes the window to a specified size Window width in pixels Window height in pixels function WRESIZE(width, height) { switch (__WTYPE) { case 'PRIMARY': window.resizeTo(width, height); break; case 'SECONDARY': window.resizeTo(width, height); break; case 'DIALOG': __WIN_RESIZE(width, height); break; case 'FRAME': frameElement.style.width=width; frameElement.style.height=height; break; case 'PANEL': break; case 'WINFRAME': case 'WINFRAME_LYT': __WFRAME.resizeTo(width, height); break; } } <@func name="WSHOW"> Sets title and bounds for current window Title to display on the window caption Window width in pixels Window height in pixels Minimum window width in pixels Minimum window height in pixels function WSHOW(title, width, height, minw, minh) { var titleText = title || '#SYS[PRODUCT_NAME]'; switch (__WTYPE) { case 'DIALOG': if (!title) break; for (var i=0, buf=String.fromCharCode(160); i<8; i++) buf+=buf; document.title = title + buf; WMINSIZE(minw, minh); break; case 'PRIMARY': document.title = titleText; break; case 'SECONDARY': document.title = titleText; break; case 'WINFRAME': case 'WINFRAME_LYT': if (title) __WFRAME.setTitle(title); WMINSIZE(minw, minh); break; } if (width && height) { WRESIZE(width, height); WCENTER(width, height); } } <@func name="WINIT"> Setups the current window for work in the %STUDIO% framework Minimum window width in pixels Minimum window height in pixels This function must be called at the beginning of the global JavaScript code in any window, before attempting to invoke any %STUDIO% functionality. function WINIT(minw, minh) { __WSTUDIO = null; if (frameElement) { __WPARENT = frameElement.document.parentWindow; if (frameElement.winFrame) { __WTYPE = frameElement.winFrame.islayoutBoard ? 'WINFRAME_LYT' : 'WINFRAME'; __WFRAME = frameElement.winFrame; WMINSIZE(minw, minh); } else if (frameElement.taskPanel) { __WTYPE = 'PANEL'; } else { __WTYPE = 'FRAME'; } } else if (window.opener) { __WPARENT = window.opener; __WTYPE = 'SECONDARY'; } else if (typeof dialogArguments != 'undefined') { __WPARENT = dialogArguments.$PARENT; __WTYPE = 'DIALOG'; WMINSIZE(minw, minh); window.returnValue = null; } else { __WPARENT = null; __WTYPE = 'PRIMARY'; } if (__WPARENT) __WSTUDIO = __WPARENT.__WSTUDIO || null; if (!__WSTUDIO) { if (__WTYPE != 'PRIMARY') { setTimeout(function () { document.body.innerHTML = 'Error during window initialization'}, 1000); } return false; } var M=__WSTUDIO.$CTL.modules; for (var k in M) eval(k+'=M.'+k+';'); return true; } <@func name="WSETUP"> Setups the current window for work in the %STUDIO% framework Title to display on the window caption Window width in pixels Window height in pixels Target object for the centering (SCREEN | STUDIO | WORKSPACE | PARENT) Minimum window width in pixels Minimum window height in pixels This function must be called at the beginning of the global JavaScript code in any window, before attempting to invoke any %STUDIO% functionality. function WSETUP(title, width, height, centerOn, minw, minh) { if (!WINIT(minw, minh)) return; detectDialogParen(); var titleText = title || '#SYS[PRODUCT_NAME]'; switch (__WTYPE) { case 'DIALOG': for (var i=0, buf=' '; i<8; i++) buf+=buf; document.write(''+titleText+buf+''); LISTEN('onStudioExit', WCLOSE); break; case 'PRIMARY': document.title = titleText; break; case 'SECONDARY': document.title = titleText; LISTEN('onStudioExit', WCLOSE); break; case 'WINFRAME': case 'WINFRAME_LYT': if (title) __WFRAME.setTitle(titleText); break; } if (width && height) { WRESIZE(width, height); WCENTER(width, height, centerOn); } else if (__WTYPE == 'DIALOG') __WIN_RESIZE(); document.attachEvent('onreadystatechange', __WIN_INIT); window.attachEvent('onunload', __WIN_EXIT); window.attachEvent('onfocus', __WIN_FOCUS); function detectDialogParen() { var temp = self; while (temp && temp.__WTYPE != 'PRIMARY' && temp.__WTYPE != 'SECONDARY' && temp.__WTYPE != 'DIALOG') temp = temp.__WPARENT; if (temp && temp.__WTYPE == 'DIALOG') $ENV.dialogParent = self; } } function WMINSIZE(minw, minh) { var params = null; switch (__WTYPE) { case 'DIALOG': params = WPARAM(); break; case 'WINFRAME': case 'WINFRAME_LYT': params = __WFRAME; break; } if (!params) return; if (minw != undefined) params['minw'] = minw; if (minh != undefined) params['minh'] = minh; } function __WIN_RESIZE(p1, p2) { var minw = WPARAM("minw")||0; var minh = WPARAM("minh")||0; if (p2) { //p1 - width, p2 - height dialogWidth = MAX(p1, minw) + 'px'; dialogHeight = MAX(p2,minh) + 'px'; return; } // else p1 - event object if (INT(dialogWidth) < minw) dialogWidth = minw + 'px'; if (INT(dialogHeight) < minh) dialogHeight = minh + 'px'; } function WRECT(parent) { try { switch (__WTYPE) { case 'DIALOG': var _self = parent || self; return { x:INT(_self.dialogLeft), y:INT(_self.dialogTop), w:INT(_self.dialogWidth), h:INT(_self.dialogHeight) }; case 'WINFRAME': case 'WINFRAME_LYT': return { x:__WFRAME.x, y:__WFRAME.y, w:__WFRAME.w, h:__WFRAME.h }; break; } } catch (e) {} return { x:0, y:0, w:0, h:0 }; } function __WIN_FOCUS() { try { $ENV.topDialogParent = self; } catch(e) { //shutdown of IDE } } // Internal: window onInit handler function __WIN_INIT() { if (document.readyState != 'complete') return; SIGNAL('HIDE_POPUP()'); if (typeof __EVENTS != 'undefined') ENABLE_EVENTS(document.body); if (typeof __INPUTS != 'undefined') ENABLE_INPUTS(document.body); for (var i=0, L=__WIN_LISTENERS['oninit'], len=L.length; i Opens a modeless dialog box Dialog box url Dialog box parameters object Allow resizing the dialog box function AMODAL(url, params, resize, width, height) { return __DIALOG(url, params, true, resize, width, height); } <@func name="CONFIRM"> Opens a modal confirmation with a specified set of buttons The message to display A whitespace-separated combination of the buttons to show: Cancel, No, Ok, Yes, Retry. More information to display Indicates whether the "more information", if provided, should be initially displayed 0=~Cancel, -1=~No, 1=~Ok, ~Yes, or ~Retry The ~Ok, ~Yes, and ~Retry buttons are mutually exclusive. function CONFIRM(msg, buttons, moreinfo, showmore, width, height) { var features = {msg:msg, buttons:buttons||'OK Cancel', moreinfo:moreinfo||'', showmore:BOOL(showmore)}; if (width) features.width = width; if (height) features.height = height; return MODAL('#URL[dev:common.ConfirmDlg.htm]', features, true); } <@func name="CONFIRMONCE"> Opens a modal confirmation with a specified set of buttons Object encapsulate all data 0=~Cancel/~No, 1=~Continue/~Ok/~Yes The globalVariableId should be of a boolean type. function CONFIRMONCE(features) { return MODAL('#URL[dev:common.ConfirmOnceDlg.htm]', features, true); } <@func name="INPUT"> Opens a modal search dialog The message to display The parent window function INPUT(msg, win, init_str) { var features = {msg:msg,opener: win}; if (init_str) features.init_str = init_str; return MODAL('#URL[dev:common.InputDlg.htm]', features, false); } <@func name="CRITICAL"> Shows a critical error message The error message to display More information to display Indicates whether the "more information", if provided, should be initially displayed function CRITICAL(msg, moreinfo, showmore) { var features = {msg:msg, buttons:'OK', title:'#TEXT[XTIT_PRODUCT_NAME_ERROR]', icon:'#URL[dev~skin:images.critical.gif]', moreinfo:moreinfo||'', showmore:BOOL(showmore)}; return MODAL('#URL[dev:common.ConfirmDlg.htm]', features, true); } <@func name="INFORM" also="PROMPT"> Opens an auto-fit popup to display an information message Information message Horizontal displacement, relative to window (or to %3 if provided) Vertical displacement, relative to window (or to %3 if provided) Anchor target Anchor alignment: [left|center:right] [top|middle|bottom] function INFORM(msg, x, y, targetObj, targetAlign) { if (!msg) { if (INFORM.pop) INFORM.pop.hide(); return; } var pop=INFORM.pop; if (!pop) { pop = window.createPopup(); INFORM.pop = pop; var doc=pop.document, bod=doc.body, css=__INFORM_CSS; doc.onselectstart = doc.oncontextmenu = function() { return false; } bod.style.cssText = css.BODY; bod.innerHTML = ''; } var e = pop.document.all['MSG']; e.innerHTML = msg; pop.show(x, y, 1, 1, targetObj||null); var w=e.offsetWidth+10, h=e.offsetHeight+10, ta=targetAlign||''; if (ta.search(/center/i) >= 0) x -= w/2; if (ta.search(/right/i) >= 0) x -= w; if (ta.search(/middle/i) >= 0) y -= h/2; if (ta.search(/bottom/i) >= 0) y -= h; pop.show(x, y, w, h, targetObj||null); } <@func name="MODAL" also="AMODAL SUBWIN"> Opens a modal dialog box Dialog box url Dialog box parameters object Allow resizing the dialog box function MODAL(url, params, resize, width, height) { return __DIALOG(url, params, false, resize, width, height); } function FLOATING_WINDOW(url, params, amodal, resize, width, height, onCloseCallback) { if (GETVAR('FloatingDialogFrameworkEnable') && !$ENV.dialogParent) { BEGIN('Floating Framework Treatment'); var settings = { url: url, behavior: (amodal ? 'amodal' : 'modal'), sizable: resize, w: width, h: height, position: 'center', border: 'vc_editor', titlebar: 'vc_editor', btnMax: true }; if (amodal) { $WIN.openWindow(settings, params||{}); if (typeof onCloseCallback == 'function') { try { onCloseCallback(); } catch (e) {} } } else { $WIN.openWindow(settings, params||{}, onCloseCallback); } } else { try { if (typeof onCloseCallback == 'function') onCloseCallback(__DIALOG(url, params, amodal, resize, width, height)); else __DIALOG(url, params, amodal, resize, width, height); } catch (e) {} } } <@func name="NYI"> Prompts a "not yet implemented" message function NYI() { PROMPT('This feature is not yet implemented'); } /////////////////////////////////////////////////////////////////////////////////////// // Progress control /////////////////////////////////////////////////////////////////////////////////////// var _title, _pct = 0, _timeout = null; var _clearingTimeout = null; var _handle = null; <@func name="SET_POINTER_WAIT"> Changes the mouse pointer to wait state function SET_POINTER_WAIT() { var documents = document.parentWindow.document.documentElement.all; if (documents) { for (var i=0;i Reset the mouse pointer to default state function RESET_POINTER() { var documents = document.parentWindow.document.documentElement.all; if (documents) { for (var i=0;i Display a progress indicator (obsolete. available only for compatability considerations) Progress main message Percent completed (0-100) Progress sub-title function PROGRESS(title, pct, stage) { // send to old IFRAME return $CTL.showProgress(title, pct, stage); } <@func name="PROGRESS_START"> Allocates an action handle and displays the progress bar Progress bar title for the action If set - no other action will "catch" the progress bar until PROGRESS_FINISH is called Progress bar handle to be used in PROGRESS_UPDATE and PROGRESS_FINISH function PROGRESS_START(title, sticky) { // Default values if (!title) title = ''; _title = title; _pct = 0; // If not redirected into a splash - dispatch to the progress bar and clear any timeouted function if (!$CTL.progressRedirected()) { var ret = $WIN.progressBar.progressStart(title, sticky); if (ret && _clearingTimeout) { clearTimeout(_clearingTimeout); _clearingTimeout = null; } return ret; } else // show progress in splash (mostly for freestyle) $CTL.showProgress(title, 0); } <@func name="PROGRESS_UPDATE"> Updates info for an already initialized progress Handle of the action Sub-titles for progress bar Current percentage (absolute or relative) If set - the progress bar will show a fake progress for an action according to estimated time of execution. if no estimation is available send -1 function PROGRESS_UPDATE(handle, details, pct, estimatedTime) { // In case of redirection to a splash window, call the old-fashion CTLs progress IFRAME if ($CTL.progressRedirected()) { if (estimatedTime) _timeout = setInterval(function() {internal_progress_update(handle, details, '+4');}, 1000); else { if (_timeout) { clearInterval(_timeout); _timeout = null; } internal_progress_update(handle, details, pct); } } // Call progress bar's function and clear timeout if needed else if ($WIN.progressBar.progressUpdate(handle, details, pct, estimatedTime) && _clearingTimeout) { clearTimeout(_clearingTimeout); _clearingTimeout = null; } function internal_progress_update(handle, details, pct) { pct = pct+''; _pct = INT(pct) + ((AT(pct,0) == '+') ? _pct : 0); $CTL.showProgress(_title, _pct, details); } } <@func name="PROGRESS_FINISH"> Progress bar finish. Called when an action with a progress bar has been ended Handle of action Optional string for final stage If set - progress bar will be hidden immediately function PROGRESS_FINISH(handle, details, noDelay) { // Splash window redirection handling if ($CTL.progressRedirected()) { $CTL.showProgress(_title, 100, details); setTimeout(function () {$CTL.showProgress();}); if (_timeout) { clearInterval(_timeout); _timeout = null; } } // Progress bar's function + 2 seconds delay timeout // (The timeout is called here instead of within Progress.htc in order to support calls from // modal dialogs. if the timeout is within the HTC itself, it won't be executed until the modal // dialog is closed. But when the call is done here, the timeout is set for the window in focus else if ($WIN.progressBar.progressFinish(handle, details)) { if (_clearingTimeout) { clearTimeout(_clearingTimeout); _clearingTimeout = null; } if (noDelay) $WIN.progressBar.postProgress(); else _clearingTimeout = setTimeout(function() {$WIN.progressBar.postProgress();}, 2000); } } <@func name="PROMPT" also="PROGRESS INFORM"> Opens a fixed-size popup to display a prompt Prompt message Custom prompt features (see remarks) The %2 is an object with the following structure: Name | Type | Description | Default icon | Url | Prompt icon url. A bare name is taken relative to #URL[~skin:images.prompt-] | title | String | Prompt window title | (Information) width | Number | Prompt window width | (250) height | Number | Prompt window height | (40) target | DHTMLDOMNode | Anchor object | (null) where | Enum | Anchor position [before|after] [above|below] | (after above) dx | Integer | Anchor horizontal offset | (0) dy | Integer | Anchor vertical offset | (0) buttons | String | A whitespace-separated list of buttons to display | callback | Function | A callback function to call when one of the buttons is clicked | function PROMPT(msg, features,forceNew) { if (!msg) { if (PROMPT.pop) PROMPT.pop.hide(); return; } var pop=PROMPT.pop, ttl, css= __PROMPT_CSS; if (!pop || forceNew) { pop = window.createPopup(); PROMPT.pop = pop; var doc=pop.document, bod=doc.body; doc.onselectstart = doc.oncontextmenu = function() { return false; } bod.style.cssText = css.BODY; bod.innerHTML = ''+ ''+ ''+ ''+ '
'; bod.pop = pop; var ttl=doc.all['TTL']; ttl.onmousedown = startMove; } if (!features) features={}; var ttl = (features.title || ''), icon=features.icon+''; if (!icon || icon.indexOf('.') < 0) { switch (PREF(icon)) { case 'E': icon='error'; ttl=ttl||'#TEXT[XTIT_ERROR]'; break; case 'W': icon='warning'; ttl=ttl||'#TEXT[XTIT_WARNING]'; break; default: icon='info'; ttl=ttl||'#TEXT[XTIT_INFORMATION]'; break; } } if (!ttl) ttl = '#TEXT[XTIT_INFORMATION]'; var A = pop.document.all; A['ICON'].src = '#URL[~skin:images.prompt-%icon%.gif]'; A['TTL'].innerHTML = ttl; A['MSG'].innerHTML = (msg||''); if (!('buttons' in features)) features.buttons='#TEXT[XBUT_OK]'; for (var i=0, B=SPLIT(features.buttons||''), len=B.length; i'+B[i]+''; } A['BTNS'].innerHTML = JOIN(B); pop.document.callback = features.callback||null; var W = (features.width || 300); var H = (features.height || 40); var x=0, y=0, w=W, h=H, obj=null; if (features.target) { var tw=features.where||'after'; x = (features.dx||0); y = (features.dy||0); if (tw.search(/after/i) >= 0) { x += features.target.offsetWidth; } if (tw.search(/below/i) >= 0) { y += features.target.offsetHeight; w = features.target.offsetWidth; } obj = features.target||null; } else { var _self = self; if (__WTYPE == 'PANEL') _self = __WSTUDIO; x = _self.screenLeft+(_self.document.body.clientWidth-w)/2; y = _self.screenTop+(_self.document.body.clientHeight-h)/2; } A['TTL'].style.width = w-5; pop.show(x, y, w, h, obj); h = MAX(H, A['MSG'].scrollHeight+(features.buttons ? 48 : 28)); pop.show(x, y, w, h, obj); var dx, dy; function startMove() { var doc=pop.document, evt=doc.parentWindow.event, ttl=doc.all['TTL']; dx = evt.offsetX; dy = evt.offsetY; ttl.onmousemove = doMove; ttl.onmouseup = ttl.onlosecapture = endMove; ttl.setCapture(); } function doMove() { var doc=pop.document, evt=doc.parentWindow.event; pop.show(evt.screenX-dx, evt.screenY-dy, w, h); } function endMove() { var doc=pop.document, evt=doc.parentWindow.event, ttl=doc.all['TTL']; ttl.onmousemove = ttl.onmouseup = ttl.onlosecapture = null, ttl.releaseCapture(); } } <@func name="CLOSE_SUBWIN" > Close a floating sub-window Sub-window external name function CLOSE_SUBWIN(name){ try { var win = __WSIBLINGS[name]; if (win && !win.closed) win.close(); delete __WSIBLINGS[name]; } catch(e) {} } <@func name="SUBWIN" also="MODAL AMODAL"> Opens a floating sub-window Window url Parameters object to pass to the sub-window Sub-window external name The sub-window features The newly opened sub-window function SUBWIN(url, params, name, features, width, height) { if (!features) features = ''; var f=features||'', F=[]; if (f) F.push(f); if (f.search(/location/i) < 0 ) F.push('location=no'); if (f.search(/menubar/i) < 0 ) F.push('menubar=no'); if (f.search(/toolbar/i) < 0 ) F.push('toolbar=no'); if (f.search(/resizable/i) < 0 ) F.push('resizable=yes'); if (width || height) { var w=(width||300)-0, h=(height||300)-22, W=screen.availWidth, H=screen.AvailHeight; F.push ('left='+((W-w)/2-4)+',top='+((H-h)/2+1)+',width='+(w-10)+',height='+(h-7)); // estimated } else { F.push ('left=10000,top=10000,width=10,height=10'); } var win; if (!name) { win = window.open(url, '_blank', JOIN(F,',')); } else { win = __WSIBLINGS[name]; if (win && !win.closed) win.close(); win = window.open(url, name, JOIN(F,',')); __WSIBLINGS[name] = win; } win.__WIN_PARAMS = params||{}; return win; } function __DIALOG(url, params, amodal, resize, width, height) { var features = 'help:no;status:no;edge:no;scroll:no;resizable:'+(BOOL(resize) ? 'yes;' : 'no;')+(resize?'maximize:yes;':''); if (width && height) { var x = screenLeft + (document.body.clientWidth-width)/2; var y = screenTop + (document.body.clientHeight-height)/2; if (x > screen.availWidth || y > screen.availHeight) { x = (screen.availWidth - width)/2; y = (screen.availHeight - height)/2; } features += 'dialogLeft:'+x+'px;dialogTop:'+y+'px;'+'dialogWidth:'+width+'px; dialogHeight:'+height+'px;'; } var _self = $ENV.dialogParent || self; var obj = {$PARENT:_self, $PARAMS:(params||{})}; if (BOOL(amodal)) { return _self.showModelessDialog(url, obj, features); } else { return _self.showModalDialog(url, obj, features); } } var __PROMPT_CSS = { BODY: 'background:#[BG1]; border:outset #[WHT] 2; margin-right:1; overflow:hidden; cursor:default;', TTL: 'background:#[FG1]; position:absolute; left:0; top:0; width:100%; height:11; padding:0 2 1 2; font:bold 9px tahoma; color:#[WHT]; overflow:hidden; cursor:hand; ', CLOSE: 'position:absolute; top:0; right:1; cursor:hand; ', BTNS: 'position:absolute; right:8; bottom:8; text-align:right; ', BTN: 'background:#[BG1]; border:outset #[WHT] 1; font:normal 11px tahoma; width:60; padding:0 5; margin-left:5; overflow:visible; text-align:center;', ICON: 'position:absolute; left:6; top:20; width:12; height:12; ', MSG: 'position:absolute; left:0; top:12; width:100%; height:100%; padding:7 6 3 24; color:#[FG1]; font:normal 11px verdana; text-align:left; overflow-x:hidden; overflow-y:hidden;' }; var __INFORM_CSS = { BODY: 'background:#[CL2]; border:solid #[FG1] 1; color:#[FG1]; margin:0; padding:3; font:normal 11px verdana; text-align:left; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; cursor:default;' }; /////////////////////////////////////////////////////////////////////////////////////////////////// // INTERNAL: POSITIONING <@func name="GET_BOX"> Gets the bounding box of a boxed object A boxed object The object's bounding box function GET_BOX(obj) { var CS=obj.currentStyle; return { x:CS.x||'0', y:CS.y||'0', w:CS.w||'0', h:CS.h||'0'}; } <@func name="SET_BOX"> Sets the bounding box of a boxed object A boxed object The bounding box A boxed object The bounding box in string representation A boxed object Box X coordinate Box Y coordinate Box width Box height function SET_BOX(obj, x, y, w, h) { switch (arguments.length) { case 2: switch (typeof x) { case 'string': var a=SPLIT(TRIM(x)); h=a[3]; w=a[2]; y=a[1]; x=a[0]; break; case 'object': h=x.h; w=x.w; y=x.y; x=x.x; break; default: return; } break; case 5: break; default: return; } var ST=obj.style; ST.layout='box'; ST.x = ((x||0)+'').replace(/\%/g,'*W/100'); ST.y = ((y||0)+'').replace(/\%/g,'*H/100'); ST.w = ((w||0)+'').replace(/\%/g,'*W/100'); ST.h = ((h||0)+'').replace(/\%/g,'*H/100'); } <@func name="LAYOUT_BOX"> Layouts a boxed object and all its contained boxes A boxed object function LAYOUT_BOX(obj, pbox) { // recalculate the object position var PB=pbox||CALC_PBOX(obj.offsetParent), W=PB.w, H=PB.h; var ST=obj.style, CS=obj.currentStyle; var x=CS.x||0, y=CS.y||0, w=CS.w||0, h=CS.h||0; try { eval('w=POS('+w+')'); } catch (e) { w=0; } try { eval('h=POS('+h+')'); } catch (e) { h=0; } try { eval('x='+x); } catch (e) { x=0; } try { eval('y='+y); } catch (e) { y=0; } if (CS.position != 'absolute') ST.position = 'absolute'; ST.left=PB.l+x; ST.top=PB.t+y; ST.width=w; ST.height=h; // apply recursively on all relevant children if (!obj.hasChildBoxes && !CS.getAttribute('hasChildBoxes')) return; for (var i=0, C=obj.children, qbox=null, len=C.length; i Returns the intersection of two collections of objects The first collection of objects The second collection of objects The intersection collection function INTERSECT(collection1, collection2) { var res={}; for (var k in collection1) if (k in collection2) res[k] = collection1[k]; return res; } // Returns the union of two collections of objects <@func name="UNION"> Returns the union of two collections of objects The first collection of objects The second collection of objects The union collection function UNION(collection1, collection2) { var res={}; for (var k in collection1) res[k] = collection1[k]; for (var k in collection2) res[k] = collection2[k]; return res; } //////////////////////////////////////////////////////////////////// /////Performance macros <@func name="PTIMESTART"> Sets the starting time of the performance measurment. Important Notes: Make sure that for each PTIMESTART call there is a corresponding PTIMEEND call. The log is printed to the console and to the following folder C:\VCLogs so make sure that this folder exist on your machine. Configure the security setting in your browser to allow ActiveX component, so the logs could be written to your local hard-drive. Description to be printed to the log. function PTIMESTART(desc){ $ENV.perfMng.begin(desc); } <@func name="PTIMEEND"> Sets the ending time of the performance measurment. Description to be printed to the log. function PTIMEEND(){ $ENV.perfMng.end(); } // Clears the data structures used by the performance functions. function PTIMECLEAR(msg){ $ENV.perfMng.clear(msg); } // Prints the log to the console. function PTIMELOG(){ $ENV.perfMng.log(); } /////////////////////////////////////////////////////////////////////////////////////////////////// // STRUCTURES <@struct name="BOUNDING_BOX" group="V. Structures"> Represents a bounding box The bounding box members are: Name | Description | Values x | The box left coordinate | ~expr y | The box top coordinate | ~expr w | The box width | ~expr h | The box height | ~expr where ~expr is: An absolute number of pixels (e.g., 512) A percentage (e.g., 100%), taken relative to the corresponding dimension of the parent box A variable ~x, ~y, ~w, or ~h representing the corresponding dimension on this box A variable ~W, or ~H representing the corresponding dimension on the parent box A numeric expression involving any of the above (e.g., 10%+W/3-50) The BOUNDING_BOX structure can also be represented as a string in the following format: 'x y w h' (members separated by whitespace) <@struct name="SIGNAL_DEF"> Represents a %STUDIO% signal A signal is an action triggering expression. A signal can be defined using any of the following forms: Signal string to execute (see syntax below) Name of a command containing the signal to execute (see @env:KitCommands!COMMAND_DEF) Javascript expression to evaluate (in the context of the containing window) Javascript function to execute (in the global system window) Signal Syntax The signal syntax is: target -> method(args,...) Where ~target can be any of the following: Target | Description $XXX | Invokes a method on the corresponding %STUDIO% module (e.g., $CTL, $ENV, etc.) BOARD | Invokes a method on the current board, if any. CONTEXT | Invokes a method on the object currently in context, if any (see @gml:GmlObject). UNIT | Invokes a method on the unit currently in context, if any (see @gml:Unit). ELEMENT | Invokes a method on the element currently in context, if any (see @gml:Element). FIELD | Invokes a method on the field currently in context, if any (see @gml:Field). PANEL | Invokes a method on the active task panel, if any. PANEL:name | Invokes a method on the specified task panel, if found. SELF | Invokes a method in the containing window If the signal string does not match the syntax above, then it is assumed to be script block and will be evaulated in the context of the containing window. Strong Signals A strong signal is indicated by a double-arrow delimiter: PANEL:name ->> method(args,...) Strong signals are relevant only to signals whose target is a named task panel. Normally, if a signal is sent to a task panel and that task panel has not yet been loaded, the signal will be ignored. If a strong signal is used instead, then the task panel will be loaded and displayed before the signal is sent to it. Strong signals are sent asynchronously. <@enum name="DATA_TYPES"> An enumeration of the builtin data types The available data types are listed below: Type | Description BOOL | Boolean value COLOR | Color (RGB) value COMBO | Open enumeration DATE | Date value ENUM | Closed enumeration EXPR | GML expression FLOAT | Floating-point number HTML | HTML markup text INT | Integer number OBJ | Simple object REF | GML reference STR | Single line text TEXT | Multi-line text TIME | Time value DATETIME | DateTime value TOGGLE | Enumeration toggle URL | Url value USER | User-defined type <@struct name="ENUM_DEF" also="ENUM_OBJ ENUM_STR ENUM_ARR"> An enumeration definition The enumeration definition can be any of the following A name of a globally defined enumeration A string representation of an enumeration (@ENUM_STR) An object holding an enumeration (@ENUM_OBJ) An array representation of an enumeration (@ENUM_ARR) A function in the form: function(context), returning an enumeration in any of the previous forms (1-4). The ~context parameter is an object that defines the enumeration context, used for computing dynamic enumerations. Dynamic enumerations should be used sparingly, since they reevaluated each time the associated field(s) are repainted. <@struct name="ENUM_OBJ" also="ENUM_STR ENUM_ARR"> An object holding an enumeration The structure is basically a name-value lookup table: Name | Type | Description name1 | String | value1 name2 | String | value2 name3 | String | value3 ... | | $ORDER | Array | [name1, name2, name3, ...] The special ~$ORDER member is used to define the enumeration sorting order. <@struct name="ENUM_STR" also="ENUM_OBJ ENUM_ARR"> A string representation of an enumeration The string representation of an enumeration is a semi-colon separated list of value:text pairs. The order of the items in the list defines their display order. URI escape characters are used for encoding the delimiter characters, namely: ~%3A for colons (:), ~%3B for semi-colons (;) <@struct name="ENUM_ARR" also="ENUM_OBJ ENUM_STR"> An array representation of an enumeration The array representation of an enumeration is an array of {value,text} objects, each holding an enumeration item. The order of the items in the array defines their display order. //////////////////////////////////////////////////////////////////// // DEPRECATED FUNCTIONS // Deprecated. Returns the average value of its arguments function AVG() { #LOG[4, 'Deprecated macro AVG']; if (arguments.length == 0) return Number.NaN; for (var i=0, len=arguments.length, sum=0; in) n=m; return !f ? n : Math.round(n/f)*f; } // Deprecated. Returns the sum of its arguments function SUM() { #LOG[4, 'Deprecated macro SUM']; for (var i=0, len=arguments.length, sum=0; i= 0); } // Deprecated. Adds a keyword to a given keywords list function KWD_ADD(klist, kword) { #LOG[4, 'Deprecated macro KWD_ADD']; klist = ' '+(klist||'')+' '; if (klist.indexOf(' '+kword+' ') < 0) klist += ' '+kword; return klist.replace(/^\s+|\s+$/g,'').replace(/\s+/g,' '); } // Deprecated. Deletes a keyword from a given keywords list function KWD_DEL(klist, kword) { #LOG[4, 'Deprecated macro KWD_DEL']; klist = (' '+(klist||'')+' ').replace(' '+kword+' ',' '); return klist.replace(/^\s+|\s+$/g,'').replace(/\s+/g,' '); } function URL_PARAM(param, def, url) { var theUrl = (null == url)? UNESCAPE(this.document.URLUnencoded) : UNESCAPE(url); var retStr = def; if ( theUrl && theUrl.indexOf("?") > -1 ) { var strQueryString = theUrl.substr(theUrl.indexOf("?")); var aQueryString = strQueryString.split("&"); for ( var iParam = 0; iParam < aQueryString.length; iParam++ ) { if (aQueryString[iParam].indexOf(param + "=") > -1 ) { var aParam = aQueryString[iParam].split("="); retStr = aParam[1]; break; } } } return retStr; } function IS_FREESTLYE(flavor) { return flavor == "#SYS[FREESTYLE_FLAVOR]"; } <@func name="COUNT"> calculates the length of an array or collection an objects collection collection length function COUNT(collection) { if(!collection) return 0; if(ISARRAY(collection)) return collection.length; var count=0; for (var i in collection) count++; return count; } function IS_IE8() { return document.documentMode?true:false; } <@func scope="private">VC foundation use only function CALC_TOOLTIPS(lblTooltip, elemTooltip) { var label = lblTooltip; if (elemTooltip) { elemTooltip = (lblTooltip && lblTooltip != elemTooltip ? lblTooltip + '\n' : '') + elemTooltip; label = ''; } return {label:label||'', title:elemTooltip||''}; } <@func scope="private">VC foundation use only function CALC_BTN_GLYPH(text, glyph, _btnHelper) { var widths = { 'BUTTON' : 60, 'BUTTON2' : 75, 'BUTTON21' : 90, 'BUTTON3' : 120, 'BUTTON4' : 130, 'BUTTON5' : 150, 'BUTTON6' : 175, 'BUTTON7' : 200 }; var currentWidth = widths[UPPER(glyph)]; if (!currentWidth || !_btnHelper) return glyph; //do nothing var neededWidth = (_btnHelper.getButtonWidth(text, glyph)||0) + 4; //padding 2px if (neededWidth <= currentWidth) return glyph; for (var i in widths) if (neededWidth < widths[i]) return i; return widths[i]; //return the biggest glyph } // Converts offset coordinates (coords relative to elem.offsetParent, like event.offsetX/Y) // to client coordinates (coords relative to parent client area). // The calculation ignores scrolled distances. // Important: 'pos' must be in client/offset coordinates of 'elem' function OFFSET_TO_CLIENT(elem, pos, parent) { if (!pos) pos = {x:0, y:0}; if (!elem || (parent == elem)) return pos; var x = pos.x, y = pos.y, op = elem; while (op) { x += op.offsetLeft; y += op.offsetTop; // add distance from parent (including scrolled distance) op = op.offsetParent; if (!op) break; // move to next parent if (op == parent) break; x -= op.scrollLeft; y -= op.scrollTop; // remove scrolled distances } return {x: x, y: y}; } // Gets height of the @lines rows in the given html object. function INFO_HEIGHT(info, lines) { try { var clone = info.cloneNode(); clone.id = ''; clone.style.visibility = 'hidden'; info.insertAdjacentElement("BeforeBegin", clone); if (!lines) lines = 3; for (var i=0, test=[]; i<=lines; i++) test.push(''); clone.innerHTML = JOIN(test, '
') var height = clone.scrollHeight||0; clone.parentElement.removeChild(clone); return height; } catch (e) { return 0; } } function INFO_RESIZE(infoBox, nextSiblingBox, minInfoHeight) { if (!infoBox || !nextSiblingBox) return; if (!infoBox.maxh) infoBox.maxh = INFO_HEIGHT(infoBox); if (!minInfoHeight) minInfoHeight = 0; var infoH = MAX(MIN(INT(infoBox.scrollHeight), infoBox.maxh), minInfoHeight); infoBox.style.h = infoH; infoH += 5; nextSiblingBox.style.h = 'H-' + infoH; nextSiblingBox.style.y = infoH; try { infoBox.offsetParent.layout(); } catch(e) {} }