Interactive eScript playground

What if you can run eScript code without even opening Siebel Tools. Right from the Siebel client.
Need to code a new service? Click your favourite bookmarklet button and prototype it immediately, no need of recompilations/restarts.
Need to hook into a current BO context and manipulate active BCs? Easy!

Before I start, I have to say this idea haven't visited my head first. If you need a full immersion you should ask my masterminds - Jason or Roy.

So, here is how you build a lightweight eScript interactive playground.


Back-end


As you may have guessed, it is all around eval() function. First step is to make it invokable from the browser:

1. Create a Business Service, as simple as this one:

function Service_PreInvokeMethod (MethodName, Inputs, Outputs) {
	if (MethodName == “EvalScript”){
		try {
			Outputs.SetProperty(“Result”, eval(Inputs.GetProperty(“Expr”)));
		} catch(e) {
			Outputs.SetProperty(“Result”, e.toString());
		}
	}
	return (CancelOperation);
}

A little trick here is to create the BS as a client-side business service, so it wouldn't be a part of repository => neither part of regular migrations => no security bleach on production.

2. Publish the service, so it can be accessible from a browser:


Front-end


You will need a dialog with input and output text areas and a button to run the BS. Here is how your JS will look like:

// dialog html
var s = '<div title="eScript">'
+ '<textarea id = "SiebelEvalScript" style="height:150px"></textarea>'
+ '<textarea id = "SiebelEvalScriptOut" rows="4" disabled></textarea>'
+ '<style>textarea{width:100%!Important}</style>'
+ '</div>';

// display dialog
$(s).dialog({
    modal: true,
    width: 1024,
    buttons: [{text:'Run', click: Eval}]
});

// run Business Service
function Eval(){
    var sRes = "";
    var ps = SiebelApp.S_App.NewPropertySet();
    ps.SetProperty("Expr", $('#SiebelEvalScript').val());
    var outputSet = SiebelApp.S_App.GetService("FWK Runtime").InvokeMethod("EvalScript", ps);
    if (outputSet.GetProperty("Status") == "Error"){
        sRes = outputSet.GetChildByType("Errors").GetChild(0).GetProperty("ErrMsg");
    }else{
        sRes = outputSet.GetChildByType("ResultSet").GetProperty("Result");
    }
    $('#SiebelEvalScriptOut').text(sRes);
}

Try it in browser console or compile into a bookmarklet.


Recent release


Don't have time building your own playground? Try mine, it is free and has some advanced features you might enjoy:

  • JavaScript code editor;
  • log() function to print intermediate results also works with PropertySets;
  • Prints outputs into browser console;
  • Run full snippet or a select a partucular peace of code to run it;
  • Orginise a library of your favourite code snippets;
  • Key bindings (Ctrl+Enter, Ctrl+S);

Front: Source code, Bookmarklet code, Bookmarklet

/* 
@desc Framework allowing to run/evaluate eScript code
@author VB(xapuk.com)
@version 1.3 2018/12/05
@requires BS=FWK Runtime to be published
*/

if ("undefined" == typeof SiebelApp){
    alert("It works only in Siebel OUI session!");
}else{
    var editor; // AceJS editor object
    var func = "SiebelEvalScript"; // function identifier
    var snip; // an array of saved snippets
    var last; // current snippet name

    // dialog html
    var s = '<div title="eScript">'
    + '<select id = "' + func + 'List" style="display:block"><option value="*">New...</option></select>'
    + '<textarea id = "' + func + '" placeholder="eSciript code..." style="height:150px"></textarea>'
    + '<label id = "' + func + '_lbl" for="' + func + '">Initialised</label>'
    + '<textarea id = "' + func + 'Out" rows="4" disabled></textarea>'
    + '<style>select,textarea{width:100%!Important}.ui-dialog-content{padding:0.5em 1em}</style>'
    + '</div>';

    // hard-remove dialog object from DOM, just in case
    $("#"+func + "List").parent().remove();

    var d = $(s).dialog({
        modal: true,
        width: 1024,
        open: function(){

            $('#'+func).focus();

            // load acejs plugin
            if (typeof(ace) == "undefined"){
                // injecting a script tag, also you can use require() function instead
                var jsCode = document.createElement('script');    
                jsCode.setAttribute('src', "https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.2/ace.js");
                jsCode.setAttribute('async', true);
                jsCode.onload = attachACE;
                document.body.appendChild(jsCode);
            }else{
                attachACE();
            }

            // List onchange
            $("#"+func+"List").change(function(event) {
                var n = $(this).val();
                if (n != "*" && n > ""){
                    if (editor){
                        editor.setValue(snip[n]);
                    }else{
                        $("#"+func).text(snip[n]);
                    }
                    window.localStorage[func+"Last"] = n;
                }

            });

            // key bindings
            $("#"+func+"Out").parent().keydown(function(event) {
                if (event.ctrlKey && event.keyCode === 13) { // ctrl + Enter
                    Eval();
                    return false;
                }else if (event.ctrlKey && event.keyCode === 83) { // ctrl + S
                    Save();
                    return false;
                }
            });

            Load(); // load presaved params

        },
        close: function(){
            $(this).dialog('destroy').remove();
        },
        buttons: [
            {
                text:'Run (Ctrl+Enter)',
                click: Eval
            },
            {
               text:'Save (Ctrl + S)',
               click: Save
            },
            {
               text:'Remove',
               click: Delete
            },
            {
               text:'Close (Esc)',
               click: function() {
                $(this).dialog('close');
               }
            }
        ]
    });
}

function Eval(){

    var sExpr = GetCode();
    var sRes = "";
    var dTS = new Date();
    var isChrome = !!window.chrome;
    var isFirefox = typeof InstallTrigger !== 'undefined';

    // execution timestamp
    $('#'+func + "_lbl").text("Last executed at " + dTS.toISOString().replace("T", " ").replace("Z", " "));

    Save(); // save snippets every time you run it

    // invoke BS
    var service = SiebelApp.S_App.GetService("FWK Runtime");
    var ps = SiebelApp.S_App.NewPropertySet();
    ps.SetProperty("Expr", sExpr);
    var outputSet = service.InvokeMethod("EvalScript", ps);
    if (outputSet.GetProperty("Status") == "Error"){
        sRes = outputSet.GetChildByType("Errors").GetChild(0).GetProperty("ErrMsg");
    }else{
        sRes = outputSet.GetChildByType("ResultSet").GetProperty("Result");
    }
    $('#'+func + "Out").text(sRes);

    // show results in browser console
    if (console) {
        var a = sRes.split(String.fromCharCode(13));
        for(var i = 0; i < a.length; i++) {
            // split into 3 parts for styling
            var a2 = a[i].split('\t|\t');
            var s1 = "", s2 = "", s3= "";
            if (a2.length > 1){
                if (a2.length > 2){
                    s1 = a2[0];
                    s2 = a2[1];
                    for(var j = 2; j < a2.length; j++) {
                        s3 += "\t" + a2[j];
                    }
                } else {
                    s1 = a2[0];
                    s3 = a2[1];
                }
            } else {
                s3 = a[i];
            }
            
            // collapse miltiline results
            if (s3.indexOf("\n") > -1) {
                if (isFirefox  || isChrome ) {
                    console.groupCollapsed("%c" + s1 + " \t%c" + s2, "color:DarkCyan;", "color:Maroon;font-weight:bold");
                } else {
                    console.groupCollapsed(s1 + " \t" + s2);
                }
                console.log(s3);
                console.groupEnd();
            } else {
                if (isFirefox  || isChrome ) {
                    console.log("%c" + s1 + " \t%c" + s2 + " \t%c" + s3, "color:DarkCyan;", "color:Maroon;font-weight:bold", "color:black;font-weight:normal");
                } else {
                    console.log(s1 + " \t" + s2 + " \t" + s3);
                }
            }
        }
    }
}

// attach acejs plugin
function attachACE(){
    editor = ace.edit(func);
    editor.session.setMode("ace/mode/javascript");
    $(".ace_editor").css("height","300");
}

// save button
function Save(){
    var n = $('#' + func + "List").val();
    if (n == "*" || n == null){ // new
        n = prompt("Snippet name");
        if(n){
            if (n.match(/.{2,}/)){
                snip[n] = GetCode(true);
                window.localStorage[func] = JSON.stringify(snip);
                $('#' + func + "List").append('<option value="' + n + '">' + n +'</option>');
                $('#' + func + "List").val(n).change();
            }else{
                alert("Invalid snippet name!");
            }
        }
    }else{ // existing
        snip[n] = GetCode(true);
        window.localStorage[func] = JSON.stringify(snip);
    }
}

// Remove button
function Delete(){
    var n = $('#' + func + "List").val();
    if (confirm("Are you sure you want to delete a snippet: " + n)){
        if (n && n != "*"){
            delete snip[n]; // remove item
            window.localStorage[func] = JSON.stringify(snip);
            delete window.localStorage[func + "Last"];
            Load(); // reload list
        }
    }
}

// loads preserved code snippets
function Load() {

    var s = window.localStorage[func];
    
    // remove all dropdown items
    $("#" + func + "List option").remove();

    //clear editor
    if (editor){
        editor.setValue("");
    }else{
        $("#"+func).text("");
    }

    // retrieve code snippets saved in local storage
    var li = '';
    if (s){
        snip = JSON.parse(s);
        for (k in snip){
            li += '<option value="' + k + '">' + k + '</option>';
        }
    }else{
        snip={};
    }
    $("#" + func + "List").append(li);

    //last snippet
    last = window.localStorage[func+"Last"];
    if(last){
        $('#' + func + "List").val(last).change();
    }
}

// returns either selected peace of code or full value from text area or ACEJS plugin
function GetCode(bFull)
{
    var sRes;
    if (editor){
        if (bFull || editor.getSelectedText() === ""){
            sRes = editor.getValue();
        }else{
            sRes = editor.getSelectedText();
        }
    }else{
        var textComponent = document.getElementById(func);
        if (bFull){
            sRes = $('#'+func).val();
        }else if(textComponent.selectionStart !== undefined && textComponent.selectionStart != textComponent.selectionEnd){// Normal browsers
            sRes = textComponent.value.substring(textComponent.selectionStart, textComponent.selectionEnd);
        }else if(document.selection !== undefined){// IE
            textComponent.focus();
            var sel = document.selection.createRange();
            sRes = sel.text;
        }else{
            sRes = $('#'+func).val();
        }
    }
    return sRes;
}  
javascript:void function(){function e(){var e=n(),t="",l=new Date,i=!!window.chrome,a="undefined"!=typeof InstallTrigger;$("#"+s+"_lbl").text("Last executed at "+l.toISOString().replace("T"," ").replace("Z"," ")),o();var r=SiebelApp.S_App.GetService("FWK Runtime"),c=SiebelApp.S_App.NewPropertySet();c.SetProperty("Expr",e);var d=r.InvokeMethod("EvalScript",c);if(t="Error"==d.GetProperty("Status")?d.GetChildByType("Errors").GetChild(0).GetProperty("ErrMsg"):d.GetChildByType("ResultSet").GetProperty("Result"),$("#"+s+"Out").text(t),console)for(var p=t.split(String.fromCharCode(13)),u=0;u<p.length;u++){var f=p[u].split("	|	"),g="",v="",S="";if(f.length>1)if(f.length>2){g=f[0],v=f[1];for(var y=2;y<f.length;y++)S+="	"+f[y]}else g=f[0],S=f[1];else S=p[u];S.indexOf("\n")>-1?(a||i?console.groupCollapsed("%c"+g+" 	%c"+v,"color:DarkCyan;","color:Maroon;font-weight:bold"):console.groupCollapsed(g+" 	"+v),console.log(S),console.groupEnd()):a||i?console.log("%c"+g+" 	%c"+v+" 	%c"+S,"color:DarkCyan;","color:Maroon;font-weight:bold","color:black;font-weight:normal"):console.log(g+" 	"+v+" 	"+S)}}function t(){a=ace.edit(s),a.session.setMode("ace/mode/javascript"),$(".ace_editor").css("height","300")}function o(){var e=$("#"+s+"List").val();"*"==e||null==e?(e=prompt("Snippet name"),e&&(e.match(/.{2,}/)?(r[e]=n(!0),window.localStorage[s]=JSON.stringify(r),$("#"+s+"List").append('<option value="'+e+'">'+e+"</option>"),$("#"+s+"List").val(e).change()):alert("Invalid snippet name!"))):(r[e]=n(!0),window.localStorage[s]=JSON.stringify(r))}function l(){var e=$("#"+s+"List").val();confirm("Are you sure you want to delete a snippet: "+e)&&e&&"*"!=e&&(delete r[e],window.localStorage[s]=JSON.stringify(r),delete window.localStorage[s+"Last"],i())}function i(){var e=window.localStorage[s];$("#"+s+"List option").remove(),a?a.setValue(""):$("#"+s).text("");var t="";if(e){r=JSON.parse(e);for(k in r)t+='<option value="'+k+'">'+k+"</option>"}else r={};$("#"+s+"List").append(t),c=window.localStorage[s+"Last"],c&&$("#"+s+"List").val(c).change()}function n(e){var t;if(a)t=e||""===a.getSelectedText()?a.getValue():a.getSelectedText();else{var o=document.getElementById(s);if(e)t=$("#"+s).val();else if(void 0!==o.selectionStart&&o.selectionStart!=o.selectionEnd)t=o.value.substring(o.selectionStart,o.selectionEnd);else if(void 0!==document.selection){o.focus();var l=document.selection.createRange();t=l.text}else t=$("#"+s).val()}return t}if("undefined"==typeof SiebelApp)alert("It works only in Siebel OUI session!");else{var a,r,c,s="SiebelEvalScript",d='<div title="eScript"><select id = "'+s+'List" style="display:block"><option value="*">New...</option></select><textarea id = "'+s+'" placeholder="eSciript code..." style="height:150px"></textarea><label id = "'+s+'_lbl" for="'+s+'">Initialised</label><textarea id = "'+s+'Out" rows="4" disabled></textarea><style>select,textarea{width:100%!Important}.ui-dialog-content{padding:0.5em 1em}</style></div>';$("#"+s+"List").parent().remove();{$(d).dialog({modal:!0,width:1024,open:function(){if($("#"+s).focus(),"undefined"==typeof ace){var l=document.createElement("script");l.setAttribute("src","https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.2/ace.js"),l.setAttribute("async",!0),l.onload=t,document.body.appendChild(l)}else t();$("#"+s+"List").change(function(e){var t=$(this).val();"*"!=t&&t>""&&(a?a.setValue(r[t]):$("#"+s).text(r[t]),window.localStorage[s+"Last"]=t)}),$("#"+s+"Out").parent().keydown(function(t){return t.ctrlKey&&13===t.keyCode?(e(),!1):t.ctrlKey&&83===t.keyCode?(o(),!1):void 0}),i()},close:function(){$(this).dialog("destroy").remove()},buttons:[{text:"Run (Ctrl+Enter)",click:e},{text:"Save (Ctrl + S)",click:o},{text:"Remove",click:l},{text:"Close (Esc)",click:function(){$(this).dialog("close")}}]})}}}(); 

Back: Service, and don't forget about Application UserProp