Great news, a freshly baked version of the About View bookmarklet has arrived.

Been working on it slowly for quite a long time. Started this version from scratch to get rid of EJS and experiment more with plain ES6 JS. Hope it deserves a separate post.

New features in version 2.0:

  • First of all, the source code is now much more friendly, so don't hesitate to make your hands dirty and tune it to your needs.
  • It now has settings that are stored in localStorage:
    • Advanced properties - turn it off when overwhelmed with unnecessary OUI properties
    • Options to customize how applets and controls are listed
    • Event handlers for links, whitespace, bookmark icon clicks
    • Focus feature to highlight the deepest expanded element
  • Applets arranged hierarchically from primary BC at the top to indented child BC and popup applets at the bottom
  • Hierarchy of custom PR, PM, and PW classes for each element
  • Current workspace name and version. Keep in mind it is not refreshed when inspected through my quick inspect tool until you refresh a page.
  • Plenty of new attributes including a screen name, current page recordset, search spec (when available) and others.
  • Also fixed several defects here and there.

As I mentioned it is relatively fresh, so stay tuned for further upgrades and I'll greatly appreciate all feedback.

Recent version:

  • About View 2.0 source code
  • (() => {
    
        if ("undefined" == typeof SiebelApp) {
            alert("It works only in Siebel OUI session!");
            return;
        }
    
        const Id = "XapuksAboutView2";
    
        // read options localStorage
        let options = {};
        if (localStorage.getItem(Id)) {
            options = JSON.parse(localStorage.getItem(Id));
        } else {
            resetOptions();
        }
    
        let $d = $(`.ui-dialog.${Id}`);
    
        // event handling
        const handlers = {
            "None": (e) => {
                return true;
            },
            "Expand / Special": (e) => {
                id = $(e.target).attr("data-ul");
                if (id) {
                    $d.find(`ul.ul_show:not(#${id}):not(:has(#${id})):not(.keep_open)`).removeClass("ul_show").addClass("ul_hide");
                    $d.find("#" + id).toggleClass(['ul_show', 'ul_hide']);
                    e.stopPropagation();
                    return false;
                } else {
                    e.stopPropagation();
                    return true;
                }
            },
            "Expand active context": (e) => {
                const a = SiebelApp.S_App.GetActiveView().GetActiveApplet();
                if (a) {
                    $d.find(`ul#${a.GetFullId()}, ul#${a.GetFullId()}_controls, ul#${a.GetActiveControl()?.GetInputName()}`).removeClass("ul_hide").addClass("ul_show");
                }
                e?.stopPropagation();
                return false;
            },
            "Copy active applet": (e) => {
                const a = SiebelApp.S_App.GetActiveView().GetActiveApplet();
                if (a) {
                    handlers["Copy value"]({
                        target: $d.find(`a[data-ul=${a.GetFullId()}]`)[0]
                    });
                }
            },
            "Collapse item": (e) => {
                $d.find(`ul.ul_show:not(:has(.ul_show:not(.keep_open))):not(.keep_open)`).removeClass("ul_show").addClass("ul_hide");
                e.stopPropagation();
                return false;
            },
            "Collapse all": (e) => {
                $d.find(`ul.ul_show:not(.keep_open)`).removeClass("ul_show").addClass("ul_hide");
                e.stopPropagation();
                return false;
            },
            "Close dialog": (e) => {
                $d.dialog("close");
                e.stopPropagation();
                return false;
            },
            "Options": (e) => {
                rOptions();
                e.stopPropagation();
                return false;
            },
            "Copy value and close": (e) => {
                handlers["Copy value"](e);
                handlers["Close dialog"](e);
                e.stopPropagation?.call(this);
                return false;
            },
            "Copy value": (e) => {
                const scope = e.target;
                // replacing link with intput and select the value
                const val = $(scope).text();
                $(scope).hide().after("<input id='" + Id + "i'>");
                $d.find("#" + Id + "i").val(val).select();
                // attempt to copy value
                if (document.execCommand("copy", false, null)) {
                    // if copied, display a message for a second
                    $d.find("#" + Id + "i").attr("disabled", "disabled").css("color", "red").val("Copied!");
                    setTimeout(() => {
                        $d.find("#" + Id + "i").remove();
                        $(scope).show();
                    }, 700);
                } else {
                    // if failed to copy, leave input until blur, so it can be copied manually
                    $d.find("#" + Id + "i").blur(() => {
                        $(this).remove();
                        $d.find("a").show();
                    });
                }
                e.stopPropagation?.call(this);
                return false;
            },
            "Invoke applet method": (e) => {
                var $target = $(e.target);
                var applet = SiebelApp.S_App.GetActiveView().GetAppletMap()[$target.attr("data-applet")];
                const method = $target.text();
                applet.InvokeMethod(method);
                e.stopPropagation?.call(this);
                return false;
            },
            "Invoke control method": (e) => {
                var $target = $(e.target);
                var applet = SiebelApp.S_App.GetActiveView().GetAppletMap()[$target.attr("data-applet")];
                var control = applet.GetControls()[$target.attr("data-control")];
                const method = $target.text();
                SiebelApp.S_App.uiStatus.Busy();
                try {
                    applet.GetPModel().OnControlEvent(SiebelApp.Constants.get("PHYEVENT_INVOKE_CONTROL"), control.GetMethodName(), control.GetMethodPropSet(), {
                        async: true,
                        cb: () => SiebelApp.S_App.uiStatus.Free()
                    });
                } catch (e) {
                    console.error(e.toString());
                    SiebelApp.S_App.uiStatus.Free();
                }
                e.stopPropagation?.call(this);
                return false;
            },
            "Focus": (e) => {
                var $target = $(e.target);
                const $el = $($target.attr("data-focus"));
                $d.dialog('close');
                $el.focus();
                e.stopPropagation?.call(this);
                return false;
            },
            "Expand related": (e) => {
                var $target = $(e.target);
                var sel = $target.attr("data-selector");
                $d.find(`ul.ul_show:not(.keep_open)`).removeClass("ul_show").addClass("ul_hide");
                $d.find(sel).toggleClass(['ul_show', 'ul_hide']);
                e.stopPropagation?.call(this);
                return false;
            }
    
        };
    
        // handle double click
        if ($d.length) {
            var o = options["bmk_dbl"];
            handlers[o]();
            return;
        }
    
        // render the dialog
        let guid = 0;
        const css = [`<style>`, ...[
            `ul {margin-left:20px}`,
            `a.x_active {text-decoration:underline}`,
            `a.x_hidden {font-style:italic}`,
            `select {display:block; margin-bottom:15px}`,
            `.options {background-color:lightgray; padding:15px; margin:10px}`,
            `.ul_hide {display:none}`,
            `.ul_show {border-bottom: 1px solid; border-top: 1px solid; margin: 5px; padding: 5px; border-color: lightgray;}`,
            options["focus_feature"] == "true" ? `ul:has(.ul_show:not(.keep_open)) :is(label,a) {color:darkgray!important}` : ``,
            options["focus_feature"] == "true" ? `ul.ul_show:not(:has(.ul_show:not(.keep_open))) :is(label,a) {color:black!important}` : ``,
            `a[data-ul] {font-weight:bold}`,
            `a[data-ul]:before {content:"> "; opacity:0.5; font-style:normal}`,
            `a[data-handler]:before, a[data-focus]:before {content:"<["; opacity:0.5; font-style:normal}`,
            `a[data-handler]:after, a[data-focus]:after {content:"]>"; opacity:0.5; font-style:normal}`,
            `label {font-size:1rem; margin:0px; font-weight:bold;}`,
            `table {display:block; overflow-x:auto; whitespace: nowrap}`,
            `td {border:solid 1px}`,
            `.options select {width:250px}`,
        ].map((i) => i ? `.${Id} ${i}` : ``), `</style>`].join("\n");
    
        $d = $(`<div class="container" title="About View 2.0">${rApplication()}${css}</div>`).dialog({
            dragStop: () => $d.dialog({ height: 'auto' }),
            classes: { "ui-dialog": Id },
            modal: true,
            width: options["width"],
            close: () => $d.dialog('destroy').remove(),
            buttons: [
                {
                    text: 'Help',
                    click: () => window.open('http://xapuk.com/index.php?topic=145', '_blank')
                }, {
                    text: 'Feedback',
                    click: () => window.location.href = "mailto:[email protected]?subject=AboutView2"
                }, {
                    text: 'Settings',
                    click: rOptions,
                }, {
                    text: 'Reset Settings',
                    click: resetOptions
                }, {
                    text: 'Close (esc)',
                    click: () => $d.dialog('close')
                }
            ]
        });
    
        function dispatchEvent(e, cb) {
            var $target = $(e.target);
            if (cb.name?.indexOf("Special") > 0) {
                if ($target.attr("data-handler") == "applet method") {
                    return handlers["Invoke applet method"](e);
                } else if ($target.attr("data-handler") == "control method") {
                    return handlers["Invoke control method"](e);
                } else if ($target.attr("data-selector")) {
                    return handlers["Expand related"](e);
                }
            }
            if ($target.attr("data-focus")) {
                return handlers["Focus"](e);
            }
            return cb(e);
        }
    
        $d.contextmenu(handlers[options["ws_right"]]);
        $d.click(handlers[options["ws_click"]]);
        $d.find("a").off("click").click((e) => dispatchEvent(e, handlers[options["link_click"]]));
        $d.find("a").off("contextmenu").contextmenu((e) => dispatchEvent(e, handlers[options["link_right"]]));
        $(".ui-widget-overlay").click(handlers[options["out_click"]]);
        $(".ui-widget-overlay").contextmenu(handlers[options["out_right"]]);
    
        function resetOptions(e) {
            options = {
                "bmk_dbl": "Expand active context",
                "ws_click": "None",
                "ws_right": "Collapse item",
                "link_click": "Copy value",
                "link_right": "Expand / Special",
                "out_click": "Close dialog",
                "out_right": "Close dialog",
                "adv": "true",
                "width": "1000",
                "ctrl_list_by": "name",
                "applet_list": "applet / bc",
                "applet_list_by": "name",
                "focus_feature": "false"
            };
            localStorage.setItem(Id, JSON.stringify(options));
        }
    
        // render functions
        function rDropdown(caption, field, list) {
            const id = field;
            const value = options[field];
            return [`<li>`,
                `<label for="${id}">${caption}</label>`,
                `<select id="${id}">`,
                list.map((i) => `<option value="${i}" ${i == value ? 'selected' : ''}>${i}</option>`),
                `</select>`,
                `<li>`].join("");
        }
    
        function rOptions() {
            if ($d.find(".options").length) {
                $d.find(".options").remove();
            } else {
                let html = [
                    `<div class="options">`,
                    `<h4>SETTINGS</h4>`,
                    rDropdown(`Advanced properties`, `adv`, [`false`, `true`]),
                    rDropdown(`Dialog width`, `width`, [`600`, `800`, `1000`]),
                    rDropdown(`Show in main list`, `applet_list`, [`applet`, `applet / bc`, `applet / bc / rowid`]),
                    rDropdown(`List applets by`, `applet_list_by`, [`name`, `title`]),
                    rDropdown(`List controls by`, `ctrl_list_by`, [`name`, `caption`]),
                    rDropdown(`Link click`, `link_click`, [`Copy value`, `Copy value and close`, `Expand / Special`, `None`]),
                    rDropdown(`Link right click`, `link_right`, [`Copy value`, `Copy value and close`, `Expand / Special`, `None`]),
                    rDropdown(`Bookmarklet double click`, `bmk_dbl`, [`Expand active context`, `Copy active applet`]),
                    rDropdown(`Whitespace click`, `ws_click`, [`None`, `Close dialog`, `Options`, `Expand active context`, `Collapse item`, `Collapse all`]),
                    rDropdown(`Whitespace right click`, `ws_right`, [`None`, `Close dialog`, `Options`, `Expand active context`, `Collapse item`, `Collapse all`]),
                    rDropdown(`Outside click`, `out_click`, [`Close dialog`, `Expand active context`, `Collapse item`, `Collapse all`]),
                    rDropdown(`Outside right click`, `out_right`, [`Close dialog`, `Expand active context`, `Collapse item`, `Collapse all`]),
                    rDropdown(`Focus feature`, `focus_feature`, [`false`, `true`]),
                    `<\div>`
                ].join("\n");
                $d.append(html);
                $d.find("select").change((e) => {
                    const c = e?.target;
                    if (c) {
                        options[c.id] = c.value;
                        localStorage.setItem(Id, JSON.stringify(options));
                    }
                });
            }
        }
    
        function rPS(prop) {
            return rItem(`<a href='#'>${prop[0]}</a>`, prop[1]);
        }
    
        function rHierarchy(caption, value, advanced) {
            var a = [];
            while ("object" === typeof value && value?.constructor?.name?.length > 1) {
                a.push(value.constructor.name);
                value = value.constructor.superclass;
            }
            return rItem(caption, a, advanced);
        }
    
        function rItem(caption, value, advanced, attribs = {}) {
            if (value && (!Array.isArray(value) || value.length) || "boolean" === typeof value) {
                if (!advanced || options["adv"] === `true`) {
                    guid++;
                    let id = Id + guid;
                    let sAttr = Object.entries(attribs).map(([p, v]) => `${p}="${v}"`).join(" ");
                    return (Array.isArray(value) ? [
                        `<li>`,
                        `<label for="${id}_0">`, caption, `:</label> `,
                        value.map((e, i) => `<a href="#" id="${id}_${i}" ${sAttr}>${e}</a>`).join(" > "),
                        `</li>`
                    ] : [
                        `<li>`,
                        `<label for="${id}">`, caption, `:</label> `,
                        `<a href="#" id="${id}" ${sAttr}>`, escapeHtml(value), `</a>`,
                        `</li>`
                    ]).join("");
                }
            }
            return "";
        }
    
        function rControl(control) {
            const id = control.GetInputName();
            const applet = control.GetApplet();
            const pr = SiebelAppFacade.ComponentMgr.FindComponent(applet.GetName())?.GetPR();
            const bc = applet.GetBusComp();
            const ps = control.GetMethodPropSet();
            const up = control.GetPMPropSet();
            const con = SiebelApp.Constants;
            let sel = `#${applet.GetFullId()} [name=${control.GetInputName()}]`;
            if (con.get("SWE_CTRL_RTCEMBEDDED") === control.GetUIType()) {
                sel = `#${applet.GetFullId()} #cke_${control.GetInputName()}`;
            }
            const cls = control === applet.GetActiveControl() ? 'x_active' : $(sel).length == 0 || $(sel).is(":visible") ? '' : 'x_hidden'
            return [`<li>`,
                `<a href="#" data-ul="${id}_c" class="${cls}">`,
                options["ctrl_list_by"] == 'caption' && control.GetDisplayName() ? control.GetDisplayName() : control.GetName(),
                `</a>`,
                `<ul id="${id}_c" class="ul_hide">`,
                rItem(control.GetControlType() == con.get("SWE_PST_COL") ? "List column" : control.GetControlType() == con.get("SWE_PST_CNTRL") ? "Control" : control.GetControlType(), control.GetName()),
                rItem("Display name", control.GetDisplayName()),
                rItem("Field", control.GetFieldName(), false, { "data-handler": "field", "data-selector": `ul#${applet.GetFullId()}_bc,ul#${applet.GetFullId()}_bc_${applet.GetBusComp().GetFieldMap()[control.GetFieldName()]?.index}` }),
                rItem("Value", bc?.GetFieldValue(control.GetFieldName())),
                rItem("Message", control.GetControlMsg()),
                ...(control.GetMessageVariableMap() && Object.keys(control.GetMessageVariableMap()).length ?
                    [`<li><a href="#" data-ul="${id}_var">Message variables (${Object.keys(control.GetMessageVariableMap()).length}):</a></li>`,
                    `<ul id="${id}_var" class="ul_hide">`,
                    Object.entries(control.GetMessageVariableMap()).map(rPS).join("\n"),
                        `</ul>`] : []),
                rItem("Type", control.GetUIType()),
                rItem("LOV", control.GetLovType()),
                rItem("MVG", control.IsMultiValue()),
                rItem("Method", control.GetMethodName(), false, { "data-handler": "control method", "data-applet": applet.GetName(), "data-control": control.GetName() }),
                ...(options["adv"] === `true` && ps && ps.propArrayLen ?
                    [`<li><a href="#" data-ul="${id}_method">Method properties (${ps.propArrayLen}):</a></li>`,
                    `<ul id="${id}_method" class="ul_hide">`,
                    Object.entries(ps.propArray).map(rPS).join("\n"),
                        `</ul>`] : []),
                //rItem("Id", id),
                rItem("Id", options["adv"] === `true` && $(sel).is(":focusable") ? [id, `<a href="#" data-focus='${sel}'>Focus</a>`] : id),
                rItem("Immidiate post changes", control.GetPostChanges()),
                rItem("Display format", control.GetDisplayFormat()),
                rItem("HTML attribute", control.GetHTMLAttr(), true),
                rItem("Display mode", control.GetDispMode()),
                rItem("Popup", control.GetPopupType() && [control.GetPopupType(), control.GetPopupWidth(), control.GetPopupHeight()].join(" / ")),
                rHierarchy("Plugin wrapper", SiebelApp.S_App.PluginBuilder.GetPwByControl(pr, control), true),
                rItem("Length", control.GetFieldName() ? control.GetMaxSize() : ""),
                ...(options["adv"] === `true` && up && up.propArrayLen ?
                    [`<li><a href="#" data-ul="${id}_up">User properties (${up.propArrayLen}):</a></li>`,
                    `<ul id="${id}_up" class="ul_hide">`,
                    Object.entries(up.propArray).map(rPS).join("\n"),
                        `</ul>`] : []),
                rItem("Object", `SiebelApp.S_App.GetActiveView().GetAppletMap()["${applet.GetName()}"].GetControls()["${control.GetName()}"]`, true),
                $(sel).length > 0 ? rItem("Node", `$("${sel}")`, true) : ``,
                `</ul>`, `</li>`].join("");
        }
    
        function rApplet(applet) {
            const cm = Object.values(applet.GetControls());
            const mm = applet.GetCanInvokeArray();
            const id = applet.GetFullId();
            return [`<ul id="${id}" class="ul_hide">`,
            rItem("Applet", applet.GetName()),
            rItem("BusComp", applet.GetBusComp()?.GetName(), false, { "data-handler": "buscomp", "data-selector": `ul#${applet.GetFullId()}_bc` }),
            rItem("Title", SiebelApp.S_App.LookupStringCache(applet.GetTitle())),
            rItem("Mode", applet.GetMode()),
            rItem("Record counter", applet.GetPModel().GetStateUIMap().GetRowCounter, true),
            rHierarchy("PModel", applet.GetPModel(), true),
            rHierarchy("PRender", SiebelAppFacade.ComponentMgr.FindComponent(applet.GetName())?.GetPR(), true),
            rItem("Object", `SiebelApp.S_App.GetActiveView().GetAppletMap()["${applet.GetName()}"]`, true),
            rItem("Node", `$("#${applet.GetFullId()}")`, true),
            `<li><a href="#" data-ul="${id}_methods">Methods (${mm.length}):</a></li>`,
            `<ul id="${id}_methods" class="ul_hide">`,
            mm.map(m => [`<li>`, `<a href="#" data-handler="applet method" data-applet="${applet.GetName()}">`, m, `</a>`, `</li>`].join("")).join("\n"),
                `</ul>`,
            `<li><a href="#" data-ul="${id}_controls">Controls (${cm.length}):</a></li>`,
            `<ul id="${id}_controls" class="ul_show keep_open">`, //<ul id="${id}_controls" class="ul_show">
            ...cm.map(rControl),
                `</ul>`,
                `</ul>`].join("\n");
        }
    
        function rField(field, id) {
            const bc = field.GetBusComp();
            const name = SiebelApp.S_App.LookupStringCache(field.GetName());
            return [`<li>`,
                `<a href="#" data-ul="${id}">`, name, `</a>`,
                `<ul id="${id}" class="ul_hide">`,
                rItem("Field", name),
                rItem("Value", field.GetBusComp().GetFieldValue(name)),
                rItem("Type", field.GetDataType()),
                rItem("Length", field.GetLength()),
                rItem("Search spec", field.GetSearchSpec()),
                rItem("Calculated", !!field.IsCalc()),
                rItem("Bounded picklist", !!field.IsBoundedPick()),
                rItem("Read only", !!field.IsReadOnly()),
                rItem("Immediate post changes", !!field.IsPostChanges()),
                rItem("Object", `SiebelApp.S_App.GetBusObj().GetBusCompByName("${bc.GetName()}").GetFieldMap()["${name}"]`, true),
                `</ul>`, `</li>`].join("\n");
        }
    
        function rBC(a, id) {
            var bc = a.GetBusComp();
            const fields = Object.values(bc.GetFieldMap());
            return [`<ul id="${id}" class="ul_hide">`,
            rItem("BusComp", bc.GetName()),
            rItem("Commit pending", !!bc.commitPending, true),
            rItem("Can update", !!bc.canUpdate),
            rItem("Search spec", bc.GetSearchSpec()),
            rItem("Sort spec", bc.GetSortSpec()),
            rItem("Current row id", bc.GetIdValue()),
            rItem("Object", `SiebelApp.S_App.GetBusObj().GetBusComp("${a.GetBCId()}")`, true),
            `<li><label><a href="#" data-ul="${id}_rec">Records: ${Math.abs(bc.GetCurRowNum())} of ${bc.GetNumRows()}${bc.IsNumRowsKnown() ? '' : '+'}</a></label></li>`,
            `<ul id="${id}_rec" class="ul_hide">`,
                `<table>`,
                `<tr>`,
            ...Object.keys(bc.GetFieldMap()).map((i) => `<th>${i}</th>`),
                `</tr>`,
            ...bc.GetRecordSet().map((r, i) => [
                `<tr>`,
                ...Object.values(r).map(v => [
                    `<td><a href="#" ${bc.GetSelection() == i ? ` class="x_active"` : ``}>`,
                    v,
                    `</a></td>`
                ].join("")),
                `</tr>`
            ].join("")),
                `</table>`,
                `</ul>`,
            `<li><label><a href="#" data-ul="${id}_fields">Fields(${bc.GetFieldList()?.length}):</a></label></li>`,
            `<ul id="${id}_fields" class="ul_show keep_open">`,
            ...fields.map((field, i) => rField(field, id + "_" + field.index)),
                `</ul>`,
                `</ul>`].join("\n");
        }
    
        function rApplication() {
            const app = SiebelApp.S_App;
            const view = app.GetActiveView();
            const bo = app?.GetBusObj();
            const bm = bo?.GetBCArray();
            const scrPM = SiebelApp.S_App.NavCtrlMngr()?.GetscreenNavigationPM();
            let am = Object.values(view?.GetAppletMap());
            var ws = SiebelApp.S_App.GetWSInfo().split("_");
            var wsver = ws.pop();
    
            var amCache = {};
            Object.assign(amCache, view?.GetAppletMap());
    
            // Identifying a primary BC
            var paa = Object.values(SiebelApp.S_App.GetActiveView().GetAppletMap()).filter((a) => !a.GetParentApplet() && (!a.GetBusComp() || !a.GetBusComp().GetParentBusComp()));
            if (!paa.length) {
                alert("Failed to identify a primary BusComp!")
            }
    
            return [`<ul>`,
                rItem("Application", app.GetName()),
                rItem("Screen", scrPM?.Get("GetTabInfo")[scrPM?.Get("GetSelectedTabKey")]?.screenName),
                rItem("View", view.GetName()),
                rItem("Task", view.GetActiveTask()),
                rHierarchy("PModel", SiebelAppFacade.ComponentMgr.FindComponent(view.GetName())?.GetPM(), true),
                rHierarchy("PRender", SiebelAppFacade.ComponentMgr.FindComponent(view.GetName())?.GetPR(), true),
                rItem("BusObject", bo?.GetName()),
                rItem("Workspace", [ws.join("_"), wsver]),
                `<label>Applets (${am.length}) / BusComps (${bm.length}):</label>`,
                `<ul>`,
                hierBC(paa[0].GetBusComp(), 0, amCache),
                ...Object.values(amCache).map((a) => rAppletName(a, 0, amCache)),
                `</ul></ul>`].join("\n");
        }
    
        // prints applet name
        function rAppletName(a, l, amCache) {
            delete amCache[a.GetName()];
            return [`<li>`,
                `<ul>`.repeat(l),
                `<a href="#" data-ul="${a.GetFullId()}" class="${a === SiebelApp.S_App.GetActiveView().GetActiveApplet() ? 'x_active' : $(`#${a.GetFullId()}`).is(":visible") ? '' : 'x_hidden'}">`,
                options['applet_list_by'] == 'title' && SiebelApp.S_App.LookupStringCache(a.GetTitle()) ? SiebelApp.S_App.LookupStringCache(a.GetTitle()) : a.GetName(),
                `</a>`,
                a.GetBusComp() && options["applet_list"].indexOf("bc") > -1 ? ` / <a href="#" data-ul="${a.GetFullId()}_bc">${a.GetBusComp().GetName()}</a>` : ``,
                a.GetBusComp() && a.GetBusComp().GetIdValue() && options["applet_list"].indexOf("rowid") > -1 ? ` / <a href="#">${a.GetBusComp().GetIdValue()}</a>` : ``,
                rApplet(a),
                a.GetBusComp() && rBC(a, a.GetFullId() + "_bc"),
                `</ul>`.repeat(l),
                `</li>`].join("");
        }
    
        // prints applets based on bc or parent applet (rec)
        function hierApplet(bc, pa, l, amCache) {
            return Object.values(amCache).filter((a) => bc && a.GetBusComp() === bc || pa && a.GetParentApplet() === pa).map((a) => !(a.GetName() in amCache) ? "" : [
                rAppletName(a, l, amCache),
                hierApplet(null, a, l + 1, amCache) // look for child applets
            ].join("\n"));
        }
    
        // prints applets based on BC hierarchy (rec)
        function hierBC(bc, l, amCache) {
            return [
                hierApplet(bc, null, l, amCache)?.join("\n"),
                ...SiebelApp.S_App.GetActiveBusObj().GetBCArray().filter((e) => e.GetParentBusComp() === bc).map((b) => hierBC(b, l + 1, amCache))
            ].join("\n");
        }
    
        // utilities
        function escapeHtml(html) {
            return html.toString()
                .replace(/&/g, "&")
                .replace(/</g, "<")
                .replace(/>/g, ">")
                .replace(/"/g, """)
                .replace(/'/g, "'");
        }
    })() 
  • About View 2.0 bookmarklet code to copy and paste into bookmark URL.
  • javascript:(function()%7B%2F*%0A%20%20%20%20%2B1.%20%5BClick%5D%20option%20should%20be%20against%20Type%3A%20Button%2C%20not%20method%0A%20%20%20%20%2B2.%20%5BInvoke%5D%20option%20should%20be%20available%20against%20every%20control%20with%20InvokeMethod%0A%09%2B3.%20Reorginize%20the%20code%2C%20so%20it%20is%20granular%20and%20can%20be%20easily%20reconfigured%20%0A%094.%20Fetch%20Applet%20and%20view%20UPs%20through%20PM%3A%0A%09%09var%20appletComponent%20%3D%20SiebelAppFacade.ComponentMgr.FindComponent(%7B%0A%09%09%09id%3A%20%5BopenAppletPopupJSON.AppletName%5D%5B0%5D%0A%09%09%7D)%3B%0A%09%09var%20popupAppletPM%20%3D%20appletComponent.GetPM()%3B%0A%20%20%20%20%2B5.%20Display%20a%20hierarchy%20of%20PM%2FPR%20classes%20for%20View%2FApplet%2FControl%20%0A%20%20%20%20%09-%20use%20Siebel%20facade%20hierarchy%20code%20snippet%0A%20%20%20%20%09-%20on%20click%20of%20PM%2FPR%20run%20inspect%20to%20open%20a%20source%20file%20when%20in%20Chrome%20DevTools%0A%20%20%20%20%2B6.%20BusComp%20object%20selector%20(make%20object%20selector%20hidden%20and%20coppy%20on%20double%20click%3F)%0A%20%20%20%207.%20make%20focus%20button%20a%20link%20and%20put%20it%20outside%20the%20spoiler%0A%20%20%20%20%2B8.%20another%20spoiler%20at%20the%20bottom%20with%20Options%3A%0A%20%20%20%20%09-%20left%2Fright%20click%20%3D%20copy%20%2B%20close%20%2B%20copy%20and%20close%20%2B%20expand%0A%20%20%20%20%09-%20advanced%20checkbox%20-%20if%20N%20-%20hide%20all%20OUI%20related%20properties%0A%20%20%20%20%09-%20store%20options%20in%20localStorage%0A%20%20%20%20%09-%20checkbox%20-%20always%20expand%20active%20applet%0A%20%20%20%20%09-%20checkbox%20-%20always%20expand%20active%20control%20(available%20only%20if%20prev%20option%20%3D%20Y)%0A%20%20%20%20-9.%20applet%20%2F%20control%20DOM%20selectors%20to%20have%20Inspect%20option%20-%20on%20click%20run%20inspect()%20-%20not%20possible%20to%20call%20inspect%20from%20JS%20%0A%20%20%20%20%2B10.%20IP19%20compatible%0A%20%20%20%20-11.%20Renders%20hidden%20content%20when%20expanded%2C%20not%20in%20advance%20-%20more%20reliable%20and%20fast%0A%20%20%20%2012.%20for%20applets_div%20and%20controls%20container%20print%20out%20event%20listeners%20(event%2C%20selector%2C%20inspect(function))%20-%20code%20snippet%20%3D%20Node%20event%20listeners%0A%20%20%20%20%2B13.%20display%20applets%2FBCs%20in%20a%20hierarchycal%20order%20(use%20space%20or%20a%20glyph%20to%20indent)%0A%20%20%20%2014.%20Display%20a%20tree%20of%20all%20pm.Get()%20properties%20for%20view%20and%20applet%20-%20in%20our%20case%20it%20is%20where%20all%20portal%20config%20is%20stored%0A%20%20%20%2015.%20also%20display%20all%20SiebelApp.Constants%3F%20How%20to%20get%20a%20list%3F%0A%20%20%20%20%2B16.%20Get%20value%20through%20GetControlMsg()%20if%20GetFieldName()%20doesn't%20exist%20in%20the%20BC%20recordset%0A%20%20%20%2017.%20dblclick%20to%20run%20special%20methods%20(configurable)%20-%20focus%2C%20inspect%2C%20invoke%2C%20force%20show%2C%20etc%2C%20dblclick%20on%20whitespace%20gives%20you%20advanced%20look%0A%20%20%20%2018.%20print%20standalone%20applet%20in%20collapsed%20section%3F%20Through%20SiebelAppFacade.%0A%20%20%20%20-19.%20applet%2C%20application%20UPs%20and%20other%20staff%20comming%20from%20the%20server%20through%20SiebelApp.S_App.GetAppPropertySet()%20-%20nope%2C%20not%20applet%20UPs%0A%20%20%20%20%2B21.%20cater%20for%20empty%20applets%20with%20no%20records%2C%20export%20and%20import%20applets%0A%20%20%20%2022.%20expose%20RO%20attributte%20for%20all%20controls%20and%20have%20an%20option%20to%20update%20a%20field%20right%20away%0A%20%20%20%2023.%20commands%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20bookmarklet%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20-%20double%20click%20%3D%20expand%20active%20applet%20and%20control%2Fcopy%20active%20applet%2Fcopy%20active%20control%20name%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20-%20tripple%20click%20%3D%20reset%20all%20options%20to%20default%0A%20%20%20%20%20%20%20%20%20%20%20%20whitespace%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20-%20click%20%3D%20show%20more%20options%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20-%20right%20click%20%3D%20close%20window%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20-%20double%20click%20%3D%20expand%20all%20or%20collapse%20all%20if%20expanded%0A%20%20%20%20%20%20%20%20%20%20%20%20links(%3Ca%3E)%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20-%20left%20click%20%3D%20special%20command%20(expand%2C%20run%20method%2C%20inspect%2C%20etc)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20-%20right%20click%20%3D%20copy%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20-%20doule%20click%20%3D%20%0A%20%20%20%20%20%20%20%20%20%20%20%20other%20option%20example%20-%20right%20mb%20down%20while%20left%20mb%20is%20down%0A%20%20%20%20%2B24.%20need%20another%20way%20of%20fetching%20PR%20class%2C%20through%20FindComponent%3F%0A%20%20%20%20%20%20%20%20%20%20%20%20SiebelAppFacade.ComponentMgr.FindComponent(SiebelApp.S_App.GetActiveView().GetAppletMap()%5B'FaCS%20UX2%20NQSC%20Applicant%20Portal%20Application%20Left%20Pane%20Menu%20Items%20Applet'%5D.GetName()).GetPR()%3B%0A%20%20%20%20%2B25.%20Double%20click%20BM%20to%20expand%20current%20applet%20%2B%20carrent%20control%2C%20third%20click%20will%20expand%20all%0A%20%20%20%2026.%20wrap%20render%20functions%20into%20try%2Fcatch%20and%20return%20error%20text%20istead%20of%20html%0A%20%20%20%20%2B27.%20Print%20the%20entire%20RecordSet%20and%20hightlight%20an%20active%20record%20instead%20of%20just%20active%20record%0A%20%20%20%2028.%20option%20to%20print%20jquery%20selector%20%24(%22%23123%22)%20or%20node%20selector%20%24(%22%23123%22)%5B0%5D%0A%20%20%20%20%2B29.%20expose%20view%20and%20applet%20title%20as%20applet%20attribute%20and%20as%20a%20value%20for%20AppletTitle%20control%0A%20%20%20%2030.%20option%20to%20toggle%20collapse%20all%20sections%20when%20expanding%20a%20neighbour%0A%20%20%20%20%2B31.%20toggle%20to%20show%20control%2Fapplet%20display%20name%20(GetDisplayName)%20or%20physical%20name%20(GetName)%20in%20the%20list%0A%20%20%20%20%2B32.%20get%20record%20count%20from%20SiebelApp.S_App.GetActiveView().GetAppletMap()%5B'FaCS%20UX2%20NQSC%20Application%20List%20Applet'%5D.GetPModel().GetStateUIMap().GetRowCounter%0A%20%20%20%20%2B34.%20escape%20field%20and%20message%20values%0A%09%2B34.%20invokable%20methods%2C%20swe%20properties%20of%20invokable%20control%0A%09%2B34.%20buscomp%20selector%20should%20be%20by%20id%0A%20%20%20%20%2B35.%20option%20to%20autoclose%20after%20copy%20%0A%20%20%20%20%2B36.%20Option%20to%20display%20a%20current%20rowid%20next%20to%20the%20applet%20%2F%20bc%0A%20%20%20%20%2B37.%20control%20UP%0A%20%20%20%20%2B38.%20link%20from%20the%20control%20to%20the%20field%20or%20just%20expand%20another%20level%20(call%20of%20the%20same%20renderer%20function)%20on%20right%20click%0A%20%20%20%20%2B39.%20fetch%20screen%20name%20using%20SiebelApp.S_App.NavCtrlMngr().GetscreenNavigationPM().Get(%22GetTabInfo%22)%2C%20active%20screen%20%3D%20SiebelApp.S_App.NavCtrlMngr().GetscreenNavigationPM().Get(%22GetSelectedTabKey%22)%0A%20%20%20%20%2B40.%20expandable%20items%20should%20have%20an%20indication%20like%20%22(%3E)%20(%5E)%20(%2B)%20collapsed%20item%22%20%22(V)%20(-)%20expanded%20item%22%0A%20%20%20%20%2B41.%20%5BReset%20options%5D%20button%20intead%20of%20event%20action%0A%20%20%20%20%2B42.%20Expand%20option%20should%20do%20applets%20and%20controls%0A%20%20%20%20%2B43.%20Keep%20Applet%20Controls%20list%20opened%20by%20default%0A%20%20%20%20%2B44.%20Special%20event%3A%0A%20%20%20%20%20%20%20%20-%20special%20attrib%20data-handler%20%3D%20%5Bfield%2C%20buscomp%2C%20applet%20method%2C%20control%20method%2C%20focus%5D%0A%20%20%20%20%20%20%20%20-%20special%20highlight%20that%20supports%20special%20event%20-%20%5Bvalue%5D%20(value)%20%3Cvalue%3E%0A%20%20%20%20%20%20%20%20-%20should%20be%20configurable%20for%20each%20instance%20or%20once%20for%20all%20SE%3F%0A%20%20%20%20%20%20%20%20-%20event%3F%20-%20%0A%20%20%20%20%20%20%20%20%20%20%20%20-%20dbl%20click%20also%20triggers%20single%20click%0A%20%20%20%20%20%20%20%20%20%20%20%20-%20right%20click%20already%20has%20an%20event%20handler%20(expand)%0A%20%20%20%20%20%20%20%20%2B%20(field%2C%20buscomp)%20SE%20on%20control%20field%20is%20to%20open%20a%20field%0A%20%20%20%20%20%20%20%20%2B%20(field)%20SE%20on%20applet%20buscomp%20is%20to%20open%20a%20buscomp%20-%20check%20how%20it%20works%20when%20buscomp%20is%20hidden%0A%20%20%20%20%20%20%20%20%2B%20(applet)%20SE%20on%20available%20method%20is%20to%20call%20it%0A%20%20%20%20%20%20%20%20%2B%20(applet%2C%20control)%20SE%20on%20control%20method%20is%20to%20call%20it%20-%20for%20all%20controls%20with%20InvokeMethod%0A%20%20%20%20%20%20%20%20%2B%20(applet%2C%20control)%20SE%20on%20control%20or%20control%20node%20selector%20or%20separate%20link%20%3Cfocus%3E%20is%20to%20focus%20on%20it%20-%20only%20works%20on%20visible%20elements%0A%20%20%20%20%2B45.%20right%20click%20on%20regular%20links%20(values)%20triggers%20right%20click%20on%20whitespace%0A%20%20%20%20%2B46.%20proper%20indent%20for%20expanded%20section%20is%20to%20wrap%20it%20into%20ul%20insted%20of%20indent%20-%20noticable%20on%20grandchild%20applets%0A%20%20%20%20%2B47.%20translate%20control%20type%20through%20the%20constants%20-%20check%20the%20full%20list%20in%20pwinfra%20and%20other%20PW%20%0A%20%20%20%20%2B48.%20Fancy%20CSS%20to%20fade%20everything%20otside%20the%20deepest%20expanded%20section%20to%20put%20atention%20to%20the%20expanded%20one%0A%20%20%20%20%20%20%20%20-%20not%20possible%20without%20js%20since%20(%3Anot%20and%20%3Ahas)%20are%20not%20supported%0A%20%20%20%20%20%20%20%20-%20append%20a%20special%20class%20%0A%20%20%20%20%2B49.%20fix%20all%20event%20handlers%20to%20be%20configurable%0A%20%20%20%2050.%20code%20review%0A%20%20%20%20%20%20%20%20-%20reorganise%20as%20class%3F%0A%20%20%20%20%2B51.%20revisit%20advanced%2Fdefauklt%20options%20(a%3Arecord%20counter%2C%20c%3Auser%20props%2C%20method%20props%2C%20focus%2C%20b%3Acommit%20pending%2C%20)%0A%20%20%20%20%2B52.%20value%20link%20right%20click%20should%20have%20a%20default%20handler%20(open%20menu%3F)%0A%20%20%20%20%2B53.%20option%20for%20focus%20border%20feature%0A%20%20%20%20%2B54.%20whitespace%20right%20click%20to%20collapse%20last%20expanded%20item%0A%20%20%20%2055.%20Check%20if%20there%20something%20else%20to%20expose%0A%20%20%20%20%2B58.%20list%20applet%20column%20visibility%3F%0A%20%20%20%20%2B59.%20view%20PR%2FPM%20doesn't%20work%20in%20fins%0A%20%20%20%20%2B61.%20rtf%20field%20visibility%2Fselector%0A%09%2B62.%20Show%20control%20length%20only%20if%20there%20a%20field%0A%20%20%20%20%0AVersion%203.0%20features%3A%0A%20%20%20%201.%20New%20concept%20-%20separate%20renderer%20and%20ref-data%3A%20%0A%20%20%20%20%20%20%20%20-%20ref-data%20example%3A%20%7B%0A%20%20%20%20%20%20%20%20%09%22Applet%22%3A%7B%0A%20%20%20%20%20%20%20%20%09%09%22Name%22%3A%22GetName%22%2C%0A%20%20%20%20%20%20%20%20%09%09%22PModel%22%3A%22GetPModel%22%0A%20%20%20%20%20%20%20%20%09%7D%2C%0A%20%20%20%20%20%20%20%20%09%22Control%22%3A%7B%0A%20%20%20%20%20%20%20%20%09%09...%0A%20%20%20%20%20%20%20%20%09%7D%0A%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20-%20store%20the%20structure%20in%20localStorage%0A%20%20%20%20%20%20%20%20-%20on%20label%20rightclick%20-%20exclude%20the%20prop%20from%20the%20tree%2C%20so%20user%20won't%20see%20it%20anymore%0A%20%20%20%20%20%20%20%20-%20under%20options%20-%20have%20a%20list%20of%20properties%20included%20and%20excluded%0A%20%20%20%2060.%20Make%20label%20also%20a%20link%20and%20copy%20function%20path%20on%20click%3F%0A%20%20%20%2056.%20Container%20page%20name%20expandable%20with%20a%20list%20of%20page%20items%20under%20it%20SiebelApp.S_App.GetChildren()%5B3%5D%0A%20%20%20%2057.%20Application%20UP%20%3D%20SiebelApp.S_App.GetPMPropSet()%0A%20%20%20%2033.%20print%20real%20event%20listeners%20since%20chrome%20leads%20to%20the%20jquery%20only%3F%0A%0A*%2F%0A%0A(()%3D%3E%7B%0A%0A%09if%20(%22undefined%22%20%3D%3D%20typeof%20SiebelApp)%7B%0A%09%09alert(%22It%20works%20only%20in%20Siebel%20OUI%20session!%22)%3B%0A%09%09return%3B%0A%09%7D%0A%09%0A%09const%20Id%20%3D%20%22XapuksAboutView2%22%3B%0A%0A%09%2F%2F%20read%20options%20localStorage%0A%09let%20options%20%3D%20%7B%7D%3B%0A%09if%20(localStorage.getItem(Id))%20%7B%0A%09%09options%20%3D%20JSON.parse(localStorage.getItem(Id))%3B%0A%09%7D%20else%20%7B%0A%09%09resetOptions()%3B%0A%09%7D%0A%0A%09let%20%24d%20%3D%20%24(%60.ui-dialog.%24%7BId%7D%60)%3B%09%0A%0A%20%20%20%20%2F%2F%20event%20handling%0A%09const%20handlers%20%3D%20%7B%0A%09%09%22None%22%3A(e)%3D%3E%7B%0A%09%09%09return%20true%3B%0A%09%09%7D%2C%0A%09%09%22Expand%20%2F%20Special%22%3A(e)%3D%3E%7B%0A%09%09%09id%20%3D%20%24(e.target).attr(%22data-ul%22)%3B%0A%09%09%09if%20(id)%20%7B%0A%09%09%09%09%24d.find(%60ul.ul_show%3Anot(%23%24%7Bid%7D)%3Anot(%3Ahas(%23%24%7Bid%7D))%3Anot(.keep_open)%60).removeClass(%22ul_show%22).addClass(%22ul_hide%22)%3B%0A%09%09%09%09%24d.find(%22%23%22%20%2B%20id).toggleClass(%5B'ul_show'%2C'ul_hide'%5D)%3B%0A%09%09%09%20%20%20%20e.stopPropagation()%3B%0A%09%09%09%09return%20false%3B%0A%09%09%09%7D%20else%20%7B%0A%09%09%09%09e.stopPropagation()%3B%0A%09%09%09%09return%20true%3B%0A%09%09%09%7D%0A%09%09%7D%2C%0A%09%09%22Expand%20active%20context%22%3A(e)%3D%3E%7B%0A%09%09%09const%20a%20%3D%20SiebelApp.S_App.GetActiveView().GetActiveApplet()%3B%0A%09%09%09if%20(a)%20%7B%0A%09%09%09%09%24d.find(%60ul%23%24%7Ba.GetFullId()%7D%2C%20ul%23%24%7Ba.GetFullId()%7D_controls%2C%20ul%23%24%7Ba.GetActiveControl()%3F.GetInputName()%7D%60).removeClass(%22ul_hide%22).addClass(%22ul_show%22)%3B%0A%09%09%09%7D%0A%09%09%09e%3F.stopPropagation()%3B%0A%20%20%20%20%09%20%20%20%20return%20false%3B%0A%09%09%7D%2C%0A%09%09%22Copy%20active%20applet%22%3A(e)%3D%3E%7B%0A%09%09%09const%20a%20%3D%20SiebelApp.S_App.GetActiveView().GetActiveApplet()%3B%0A%09%09%09if%20(a)%20%7B%0A%09%09%09%09handlers%5B%22Copy%20value%22%5D(%7B%0A%09%09%09%09%09target%3A%24d.find(%60a%5Bdata-ul%3D%24%7Ba.GetFullId()%7D%5D%60)%5B0%5D%0A%09%09%09%09%7D)%3B%0A%09%09%09%7D%0A%09%09%7D%2C%0A%09%09%22Collapse%20item%22%3A(e)%3D%3E%7B%0A%09%09%09%24d.find(%60ul.ul_show%3Anot(%3Ahas(.ul_show%3Anot(.keep_open)))%3Anot(.keep_open)%60).removeClass(%22ul_show%22).addClass(%22ul_hide%22)%3B%0A%09%09%09e.stopPropagation()%3B%0A%20%20%20%20%09%20%20%20%20return%20false%3B%0A%09%09%7D%2C%0A%09%09%22Collapse%20all%22%3A(e)%3D%3E%7B%0A%09%09%09%24d.find(%60ul.ul_show%3Anot(.keep_open)%60).removeClass(%22ul_show%22).addClass(%22ul_hide%22)%3B%0A%09%09%09e.stopPropagation()%3B%0A%20%20%20%20%09%20%20%20%20return%20false%3B%0A%09%09%7D%2C%0A%09%09%22Close%20dialog%22%3A(e)%3D%3E%7B%0A%09%09%09%24d.dialog(%22close%22)%3B%0A%09%09%09e.stopPropagation()%3B%0A%20%20%20%20%09%20%20%20%20return%20false%3B%0A%09%09%7D%2C%0A%09%09%22Options%22%3A(e)%3D%3E%7B%0A%09%09%09rOptions()%3B%0A%09%09%09e.stopPropagation()%3B%0A%20%20%20%20%09%20%20%20%20return%20false%3B%0A%09%09%7D%2C%0A%09%09%22Copy%20value%20and%20close%22%3A(e)%3D%3E%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20handlers%5B%22Copy%20value%22%5D(e)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20handlers%5B%22Close%20dialog%22%5D(e)%3B%0A%09%09%09e.stopPropagation%3F.call(this)%3B%0A%20%20%20%20%09%20%20%20%20return%20false%3B%0A%09%09%7D%2C%0A%09%09%22Copy%20value%22%3A(e)%3D%3E%7B%0A%09%09%09const%20scope%20%3D%20e.target%3B%0A%09%09%09%2F%2F%20replacing%20link%20with%20intput%20and%20select%20the%20value%0A%09%09%09const%20val%20%3D%20%24(scope).text()%3B%0A%09%09%09%24(scope).hide().after(%22%3Cinput%20id%3D'%22%20%2B%20Id%20%2B%20%22i'%3E%22)%3B%0A%09%09%09%24d.find(%22%23%22%20%2B%20Id%20%2B%20%22i%22).val(val).select()%3B%0A%09%09%09%2F%2F%20attempt%20to%20copy%20value%0A%09%09%09if%20(document.execCommand(%22copy%22%2C%20false%2C%20null))%7B%0A%09%09%09%09%2F%2F%20if%20copied%2C%20display%20a%20message%20for%20a%20second%0A%09%09%09%09%24d.find(%22%23%22%20%2B%20Id%20%2B%20%22i%22).attr(%22disabled%22%2C%20%22disabled%22).css(%22color%22%2C%22red%22).val(%22Copied!%22)%3B%0A%09%09%09%09setTimeout(()%3D%3E%7B%0A%09%09%09%09%09%24d.find(%22%23%22%20%2B%20Id%20%2B%20%22i%22).remove()%3B%0A%09%09%09%09%09%24(scope).show()%3B%0A%09%09%09%09%7D%2C%20700)%3B%0A%09%09%09%7D%20else%20%7B%0A%09%09%09%09%2F%2F%20if%20failed%20to%20copy%2C%20leave%20input%20until%20blur%2C%20so%20it%20can%20be%20copied%20manually%0A%09%09%09%09%24d.find(%22%23%22%20%2B%20Id%20%2B%20%22i%22).blur(()%3D%3E%7B%0A%09%09%09%09%09%24(this).remove()%3B%0A%09%09%09%09%09%24d.find(%22a%22).show()%3B%0A%09%09%09%09%7D)%3B%20%20%20%20%09%0A%09%09%09%7D%0A%09%09%09e.stopPropagation%3F.call(this)%3B%0A%20%20%20%20%09%20%20%20%20return%20false%3B%0A%09%09%7D%2C%0A%09%09%22Invoke%20applet%20method%22%3A%20(e)%20%3D%3E%20%7B%0A%09%09%09var%20%24target%20%3D%20%24(e.target)%3B%0A%09%09%09var%20applet%20%3D%20SiebelApp.S_App.GetActiveView().GetAppletMap()%5B%24target.attr(%22data-applet%22)%5D%3B%0A%09%09%09const%20method%20%3D%20%24target.text()%3B%0A%09%09%09applet.InvokeMethod(method)%3B%0A%09%09%09e.stopPropagation%3F.call(this)%3B%0A%20%20%20%20%09%20%20%20%20return%20false%3B%0A%09%09%7D%2C%0A%09%09%22Invoke%20control%20method%22%3A%20(e)%20%3D%3E%20%7B%0A%09%09%09var%20%24target%20%3D%20%24(e.target)%3B%0A%09%09%09var%20applet%20%3D%20SiebelApp.S_App.GetActiveView().GetAppletMap()%5B%24target.attr(%22data-applet%22)%5D%3B%0A%09%09%09var%20control%20%3D%20applet.GetControls()%5B%24target.attr(%22data-control%22)%5D%3B%0A%09%09%09const%20method%20%3D%20%24target.text()%3B%0A%09%09%09SiebelApp.S_App.uiStatus.Busy()%3B%0A%09%09%09try%20%7B%0A%09%09%09applet.GetPModel().OnControlEvent(SiebelApp.Constants.get(%22PHYEVENT_INVOKE_CONTROL%22)%2C%20control.GetMethodName()%2C%20control.GetMethodPropSet()%2C%20%7B%0A%09%09%09%09async%3A%20true%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20cb%3A%20()%3D%3ESiebelApp.S_App.uiStatus.Free()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D)%3B%0A%09%09%09%7D%20catch(e)%20%7B%0A%09%09%09%09console.error(e.toString())%3B%0A%09%09%09%09SiebelApp.S_App.uiStatus.Free()%3B%0A%09%09%09%7D%0A%09%09%09e.stopPropagation%3F.call(this)%3B%0A%20%20%20%20%09%20%20%20%20return%20false%3B%0A%09%09%7D%2C%0A%09%09%22Focus%22%3A%20(e)%20%3D%3E%20%7B%0A%09%09%09var%20%24target%20%3D%20%24(e.target)%3B%0A%09%09%09const%20%24el%20%3D%20%24(%24target.attr(%22data-focus%22))%3B%0A%09%09%09%24d.dialog('close')%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24el.focus()%3B%0A%09%09%09e.stopPropagation%3F.call(this)%3B%0A%20%20%20%20%09%20%20%20%20return%20false%3B%0A%09%09%7D%2C%0A%09%09%22Expand%20related%22%3A%20(e)%20%3D%3E%20%7B%0A%09%09%09var%20%24target%20%3D%20%24(e.target)%3B%0A%09%09%09var%20sel%20%3D%20%24target.attr(%22data-selector%22)%3B%0A%09%09%09%24d.find(%60ul.ul_show%3Anot(.keep_open)%60).removeClass(%22ul_show%22).addClass(%22ul_hide%22)%3B%0A%09%09%09%24d.find(sel).toggleClass(%5B'ul_show'%2C'ul_hide'%5D)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20e.stopPropagation%3F.call(this)%3B%0A%20%20%20%20%09%20%20%20%20return%20false%3B%0A%09%09%7D%0A%0A%09%7D%3B%0A%0A%20%20%20%20%2F%2F%20handle%20double%20click%0A%09if%20(%24d.length)%20%7B%0A%20%20%20%20%20%20%20%20var%20o%20%3D%20options%5B%22bmk_dbl%22%5D%3B%0A%20%20%20%20%20%20%20%20handlers%5Bo%5D()%3B%0A%20%20%20%20%20%20%20%20return%3B%0A%20%20%20%20%7D%0A%0A%09%2F%2F%20render%20the%20dialog%0A%09let%20guid%20%3D%200%3B%0A%09const%20css%20%3D%20%5B%60%3Cstyle%3E%60%2C%20...%5B%0A%09%09%60ul%20%7Bmargin-left%3A20px%7D%60%2C%0A%09%09%60a.x_active%20%7Btext-decoration%3Aunderline%7D%60%2C%0A%09%09%60a.x_hidden%20%7Bfont-style%3Aitalic%7D%60%2C%0A%09%09%60select%20%7Bdisplay%3Ablock%3B%20margin-bottom%3A15px%7D%60%2C%0A%09%09%60.options%20%7Bbackground-color%3Alightgray%3B%20padding%3A15px%3B%20margin%3A10px%7D%60%2C%0A%09%09%60.ul_hide%20%7Bdisplay%3Anone%7D%60%2C%0A%09%09%60.ul_show%20%7Bborder-bottom%3A%201px%20solid%3B%20border-top%3A%201px%20solid%3B%20margin%3A%205px%3B%20padding%3A%205px%3B%20border-color%3A%20lightgray%3B%7D%60%2C%0A%09%09options%5B%22focus_feature%22%5D%20%3D%3D%20%22true%22%20%3F%20%60ul%3Ahas(.ul_show%3Anot(.keep_open))%20%3Ais(label%2Ca)%20%7Bcolor%3Adarkgray!important%7D%60%3A%60%60%2C%0A%20%20%20%09%09options%5B%22focus_feature%22%5D%20%3D%3D%20%22true%22%20%3F%20%60ul.ul_show%3Anot(%3Ahas(.ul_show%3Anot(.keep_open)))%20%3Ais(label%2Ca)%20%7Bcolor%3Ablack!important%7D%60%3A%60%60%2C%0A%09%09%60a%5Bdata-ul%5D%20%7Bfont-weight%3Abold%7D%60%2C%0A%09%09%60a%5Bdata-ul%5D%3Abefore%20%7Bcontent%3A%22%3E%20%22%3B%20opacity%3A0.5%3B%20font-style%3Anormal%7D%60%2C%0A%09%09%60a%5Bdata-handler%5D%3Abefore%2C%20a%5Bdata-focus%5D%3Abefore%20%7Bcontent%3A%22%3C%5B%22%3B%20opacity%3A0.5%3B%20font-style%3Anormal%7D%60%2C%0A%09%09%60a%5Bdata-handler%5D%3Aafter%2C%20a%5Bdata-focus%5D%3Aafter%20%7Bcontent%3A%22%5D%3E%22%3B%20opacity%3A0.5%3B%20font-style%3Anormal%7D%60%2C%0A%09%09%60label%20%7Bfont-size%3A1rem%3B%20margin%3A0px%3B%20font-weight%3Abold%3B%7D%60%2C%0A%09%09%60table%20%7Bdisplay%3Ablock%3B%20overflow-x%3Aauto%3B%20whitespace%3A%20nowrap%7D%60%2C%0A%09%09%60td%20%7Bborder%3Asolid%201px%7D%60%2C%0A%09%09%60.options%20select%20%7Bwidth%3A250px%7D%60%2C%0A%09%5D.map((i)%3D%3Ei%20%3F%20%60.%24%7BId%7D%20%24%7Bi%7D%60%3A%60%60)%2C%60%3C%2Fstyle%3E%60%5D.join(%22%5Cn%22)%3B%0A%0A%09%24d%20%3D%20%24(%60%3Cdiv%20class%3D%22container%22%20title%3D%22About%20View%202.0%22%3E%24%7BrApplication()%7D%24%7Bcss%7D%3C%2Fdiv%3E%60).dialog(%7B%0A%09%09dragStop%3A%20()%20%3D%3E%20%24d.dialog(%7Bheight%3A'auto'%7D)%2C%20%0A%09%09classes%3A%20%7B%22ui-dialog%22%3A%20Id%7D%2C%0A%09%09modal%3A%20true%2C%0A%09%09width%3A%20options%5B%22width%22%5D%2C%0A%09%09close%3A%20()%20%3D%3E%20%24d.dialog('destroy').remove()%2C%0A%09%09buttons%3A%20%5B%0A%09%09%09%7B%0A%09%09%09%20%20%20text%3A'Help'%2C%0A%09%09%09%20%20%20click%3A%20()%20%3D%3E%20window.open('http%3A%2F%2Fxapuk.com%2Findex.php%3Ftopic%3D145'%2C'_blank')%0A%09%09%09%7D%2C%7B%0A%09%09%09%20%20%20text%3A'Feedback'%2C%0A%09%09%09%20%20%20click%3A%20()%20%3D%3E%20window.location.href%3D%22mailto%3Avbabkin%40gmail.com%3Fsubject%3DAboutView2%22%0A%09%09%09%7D%2C%7B%0A%09%09%09%20%20%20text%3A'Settings'%2C%0A%09%09%09%20%20%20click%3A%20rOptions%2C%0A%09%09%09%7D%2C%7B%0A%09%09%09%20%20%20text%3A'Reset%20Settings'%2C%0A%09%09%09%20%20%20click%3A%20resetOptions%0A%09%09%09%7D%2C%7B%0A%09%09%09%20%20%20text%3A'Close%20(esc)'%2C%0A%09%09%09%20%20%20click%3A%20()%20%3D%3E%20%24d.dialog('close')%0A%09%09%09%7D%0A%09%09%5D%0A%09%7D)%3B%0A%09%0A%09function%20dispatchEvent(e%2C%20cb)%20%7B%0A%09%09var%20%24target%20%3D%20%24(e.target)%3B%0A%09%09if%20(cb.name%3F.indexOf(%22Special%22)%20%3E%200)%20%7B%0A%09%09%09if%20(%24target.attr(%22data-handler%22)%20%3D%3D%20%22applet%20method%22)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20handlers%5B%22Invoke%20applet%20method%22%5D(e)%3B%0A%09%09%09%7D%20else%20if%20(%24target.attr(%22data-handler%22)%20%3D%3D%20%22control%20method%22)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20handlers%5B%22Invoke%20control%20method%22%5D(e)%3B%0A%09%09%09%7D%20else%20if%20(%24target.attr(%22data-selector%22))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20handlers%5B%22Expand%20related%22%5D(e)%3B%0A%09%09%09%7D%0A%09%09%7D%0A%09%09if%20(%24target.attr(%22data-focus%22))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20handlers%5B%22Focus%22%5D(e)%3B%0A%09%09%7D%0A%20%20%20%20%20%20%20%20return%20cb(e)%3B%0A%09%7D%0A%0A%20%20%20%20%24d.contextmenu(handlers%5Boptions%5B%22ws_right%22%5D%5D)%3B%0A%20%20%20%20%24d.click(handlers%5Boptions%5B%22ws_click%22%5D%5D)%3B%0A%20%20%20%20%24d.find(%22a%22).off(%22click%22).click((e)%3D%3EdispatchEvent(e%2C%20handlers%5Boptions%5B%22link_click%22%5D%5D))%3B%0A%20%20%20%20%24d.find(%22a%22).off(%22contextmenu%22).contextmenu((e)%3D%3EdispatchEvent(e%2C%20handlers%5Boptions%5B%22link_right%22%5D%5D))%3B%0A%20%20%20%20%24(%22.ui-widget-overlay%22).click(handlers%5Boptions%5B%22out_click%22%5D%5D)%3B%0A%20%20%20%20%24(%22.ui-widget-overlay%22).contextmenu(handlers%5Boptions%5B%22out_right%22%5D%5D)%3B%0A%0A%20%20%20%20function%20resetOptions(e)%20%7B%0A%09%09options%20%3D%20%7B%0A%09%09%09%22bmk_dbl%22%3A%20%22Expand%20active%20context%22%2C%0A%09%09%09%22ws_click%22%3A%20%22None%22%2C%0A%09%09%09%22ws_right%22%3A%20%22Collapse%20item%22%2C%0A%09%09%09%22link_click%22%3A%20%22Copy%20value%22%2C%0A%09%09%09%22link_right%22%3A%20%22Expand%20%2F%20Special%22%2C%0A%09%09%09%22out_click%22%3A%20%22Close%20dialog%22%2C%0A%09%09%09%22out_right%22%3A%20%22Close%20dialog%22%2C%0A%09%09%09%22adv%22%3A%20%22true%22%2C%0A%09%09%09%22width%22%3A%20%221000%22%2C%0A%09%09%09%22ctrl_list_by%22%3A%20%22name%22%2C%0A%09%09%09%22applet_list%22%3A%20%22applet%20%2F%20bc%22%2C%0A%09%09%09%22applet_list_by%22%3A%20%22name%22%2C%0A%09%09%09%22focus_feature%22%3A%22false%22%0A%09%09%7D%3B%0A%09%09localStorage.setItem(Id%2C%20JSON.stringify(options))%3B%0A%09%7D%0A%0A%20%20%20%20%2F%2F%20render%20functions%0A%20%20%20%20function%20rDropdown(caption%2C%20field%2C%20list)%20%7B%0A%20%20%20%20%09const%20id%20%3D%20field%3B%0A%20%20%20%20%09const%20value%20%3D%20options%5Bfield%5D%3B%0A%20%20%20%20%20%20%20%20return%20%5B%60%3Cli%3E%60%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%60%3Clabel%20for%3D%22%24%7Bid%7D%22%3E%24%7Bcaption%7D%3C%2Flabel%3E%60%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%60%3Cselect%20id%3D%22%24%7Bid%7D%22%3E%60%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20list.map((i)%3D%3E%60%3Coption%20value%3D%22%24%7Bi%7D%22%20%24%7Bi%3D%3Dvalue%3F'selected'%3A''%7D%3E%24%7Bi%7D%3C%2Foption%3E%60)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%60%3C%2Fselect%3E%60%2C%0A%20%20%20%20%20%20%20%20%60%3Cli%3E%60%5D.join(%22%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20rOptions()%20%7B%0A%20%20%20%20%20%20%20%20if%20(%24d.find(%22.options%22).length)%20%7B%0A%20%20%20%20%20%20%20%20%09%24d.find(%22.options%22).remove()%3B%0A%20%20%20%20%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20%09let%20html%20%3D%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%60%3Cdiv%20class%3D%22options%22%3E%60%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%60%3Ch4%3ESETTINGS%3C%2Fh4%3E%60%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20rDropdown(%60Advanced%20properties%60%2C%20%60adv%60%2C%20%5B%60false%60%2C%20%60true%60%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20rDropdown(%60Dialog%20width%60%2C%20%60width%60%2C%20%5B%60600%60%2C%20%60800%60%2C%20%601000%60%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20rDropdown(%60Show%20in%20main%20list%60%2C%20%60applet_list%60%2C%20%5B%60applet%60%2C%20%60applet%20%2F%20bc%60%2C%20%60applet%20%2F%20bc%20%2F%20rowid%60%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20rDropdown(%60List%20applets%20by%60%2C%20%60applet_list_by%60%2C%20%5B%60name%60%2C%20%60title%60%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20rDropdown(%60List%20controls%20by%60%2C%20%60ctrl_list_by%60%2C%20%5B%60name%60%2C%20%60caption%60%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20rDropdown(%60Link%20click%60%2C%20%60link_click%60%2C%20%5B%60Copy%20value%60%2C%20%60Copy%20value%20and%20close%60%2C%20%60Expand%20%2F%20Special%60%2C%20%60None%60%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20rDropdown(%60Link%20right%20click%60%2C%20%60link_right%60%2C%20%5B%60Copy%20value%60%2C%20%60Copy%20value%20and%20close%60%2C%20%60Expand%20%2F%20Special%60%2C%20%60None%60%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20rDropdown(%60Bookmarklet%20double%20click%60%2C%20%60bmk_dbl%60%2C%20%5B%60Expand%20active%20context%60%2C%20%60Copy%20active%20applet%60%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20rDropdown(%60Whitespace%20click%60%2C%20%60ws_click%60%2C%20%5B%60None%60%2C%20%60Close%20dialog%60%2C%20%60Options%60%2C%20%60Expand%20active%20context%60%2C%20%60Collapse%20item%60%2C%20%60Collapse%20all%60%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20rDropdown(%60Whitespace%20right%20click%60%2C%20%60ws_right%60%2C%20%5B%60None%60%2C%20%60Close%20dialog%60%2C%20%60Options%60%2C%20%60Expand%20active%20context%60%2C%20%60Collapse%20item%60%2C%20%60Collapse%20all%60%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20rDropdown(%60Outside%20click%60%2C%20%60out_click%60%2C%20%5B%60Close%20dialog%60%2C%20%60Expand%20active%20context%60%2C%20%60Collapse%20item%60%2C%20%60Collapse%20all%60%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20rDropdown(%60Outside%20right%20click%60%2C%20%60out_right%60%2C%20%5B%60Close%20dialog%60%2C%20%60Expand%20active%20context%60%2C%20%60Collapse%20item%60%2C%20%60Collapse%20all%60%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20rDropdown(%60Focus%20feature%60%2C%20%60focus_feature%60%2C%20%5B%60false%60%2C%20%60true%60%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%60%3C%5Cdiv%3E%60%0A%20%20%20%20%20%20%20%20%09%5D.join(%22%5Cn%22)%3B%0A%20%20%20%20%20%20%20%20%09%24d.append(html)%3B%0A%20%20%20%20%20%20%20%20%09%24d.find(%22select%22).change((e)%3D%3E%7B%0A%09%09%09%09const%20c%20%3D%20e%3F.target%3B%0A%09%09%09%09if%20(c)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20options%5Bc.id%5D%20%3D%20c.value%3B%0A%09%09%09%09%20%20%20%20localStorage.setItem(Id%2C%20JSON.stringify(options))%3B%0A%09%09%09%09%7D%0A%09%09%09%7D)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20rPS(prop)%20%7B%0A%20%20%20%20%09return%20rItem(%60%3Ca%20href%3D'%23'%3E%24%7Bprop%5B0%5D%7D%3C%2Fa%3E%60%2C%20prop%5B1%5D)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20rHierarchy(caption%2C%20value%2C%20advanced)%20%7B%0A%20%20%20%20%09var%20a%20%3D%20%5B%5D%3B%0A%20%20%20%20%20%20%20%20while%20(%22object%22%20%3D%3D%3D%20typeof%20value%20%26%26%20value%3F.constructor%3F.name%3F.length%20%3E%201)%20%7B%0A%20%20%20%20%20%20%20%20%09a.push(value.constructor.name)%3B%0A%20%20%20%20%20%20%20%20%09value%20%3D%20value.constructor.superclass%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%09return%20rItem(caption%2C%20a%2C%20advanced)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20rItem(caption%2C%20value%2C%20advanced%2C%20attribs%3D%7B%7D)%20%7B%0A%20%20%20%20%20%20%20%20if%20(value%20%26%26%20(!Array.isArray(value)%20%7C%7C%20value.length)%20%7C%7C%20%22boolean%22%20%3D%3D%3D%20typeof%20value)%20%7B%0A%20%20%20%20%20%20%20%20%09if%20(!advanced%20%7C%7C%20options%5B%22adv%22%5D%20%3D%3D%3D%20%60true%60)%20%7B%0A%09%09%09%09guid%2B%2B%3B%0A%09%09%09%09let%20id%20%3D%20Id%20%2B%20guid%3B%0A%09%09%09%09let%20sAttr%20%3D%20Object.entries(attribs).map((%5Bp%2Cv%5D)%3D%3E%60%24%7Bp%7D%3D%22%24%7Bv%7D%22%60).join(%22%20%22)%3B%0A%09%09%09%09return%20(Array.isArray(value)%20%3F%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%60%3Cli%3E%60%2C%0A%09%09%09%09%09%60%3Clabel%20for%3D%22%24%7Bid%7D_0%22%3E%60%2Ccaption%2C%60%3A%3C%2Flabel%3E%20%60%2C%0A%09%09%09%09%09value.map((e%2C%20i)%20%3D%3E%60%3Ca%20href%3D%22%23%22%20id%3D%22%24%7Bid%7D_%24%7Bi%7D%22%20%24%7BsAttr%7D%3E%24%7Be%7D%3C%2Fa%3E%60).join(%22%20%3E%20%22)%2C%0A%09%09%09%09%09%60%3C%2Fli%3E%60%0A%09%09%09%09%5D%20%3A%20%5B%0A%09%09%09%09%09%60%3Cli%3E%60%2C%0A%09%09%09%09%09%60%3Clabel%20for%3D%22%24%7Bid%7D%22%3E%60%2Ccaption%2C%60%3A%3C%2Flabel%3E%20%60%2C%0A%09%09%09%09%09%60%3Ca%20href%3D%22%23%22%20id%3D%22%24%7Bid%7D%22%20%24%7BsAttr%7D%3E%60%2CescapeHtml(value)%2C%60%3C%2Fa%3E%60%2C%0A%09%09%09%09%09%60%3C%2Fli%3E%60%0A%09%09%09%09%5D).join(%22%22)%3B%0A%20%20%20%20%20%20%20%20%09%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20return%20%22%22%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20rControl(control)%20%7B%0A%20%20%20%20%09const%20id%20%3D%20control.GetInputName()%3B%0A%20%20%20%20%09const%20applet%20%3D%20control.GetApplet()%3B%0A%20%20%20%20%09const%20pr%20%3D%20SiebelAppFacade.ComponentMgr.FindComponent(applet.GetName())%3F.GetPR()%3B%0A%20%20%20%20%09const%20bc%20%3D%20applet.GetBusComp()%3B%0A%20%20%20%20%09const%20ps%20%3D%20control.GetMethodPropSet()%3B%0A%20%20%20%20%09const%20up%20%3D%20control.GetPMPropSet()%3B%0A%20%20%20%20%09const%20con%20%3D%20SiebelApp.Constants%3B%0A%20%20%20%20%09let%20sel%20%3D%20%60%23%24%7Bapplet.GetFullId()%7D%20%5Bname%3D%24%7Bcontrol.GetInputName()%7D%5D%60%3B%0A%20%20%20%20%09if%20(con.get(%22SWE_CTRL_RTCEMBEDDED%22)%20%3D%3D%3D%20control.GetUIType())%20%7B%0A%20%20%20%20%09%09sel%20%3D%20%60%23%24%7Bapplet.GetFullId()%7D%20%23cke_%24%7Bcontrol.GetInputName()%7D%60%3B%0A%20%20%20%20%09%7D%0A%20%20%20%20%09const%20cls%20%3D%20control%20%3D%3D%3D%20applet.GetActiveControl()%20%3F%20'x_active'%20%3A%20%24(sel).length%20%3D%3D%200%20%7C%7C%20%24(sel).is(%22%3Avisible%22)%20%3F%20''%20%3A%20'x_hidden'%0A%20%20%20%20%20%20%20%20return%20%5B%60%3Cli%3E%60%2C%0A%09%09%20%20%20%20%60%3Ca%20href%3D%22%23%22%20data-ul%3D%22%24%7Bid%7D_c%22%20class%3D%22%24%7Bcls%7D%22%3E%60%2C%20%0A%09%09%09%20%20%20%20options%5B%22ctrl_list_by%22%5D%20%3D%3D%20'caption'%20%26%26%20control.GetDisplayName()%20%3F%20control.GetDisplayName()%20%3A%20control.GetName()%20%2C%20%0A%09%09%09%60%3C%2Fa%3E%60%2C%0A%09%09%09%60%3Cul%20id%3D%22%24%7Bid%7D_c%22%20class%3D%22ul_hide%22%3E%60%2C%0A%09%09%09rItem(control.GetControlType()%20%3D%3D%20con.get(%22SWE_PST_COL%22)%3F%22List%20column%22%3Acontrol.GetControlType()%20%3D%3D%20con.get(%22SWE_PST_CNTRL%22)%3F%22Control%22%3Acontrol.GetControlType()%2C%20control.GetName())%2C%0A%09%09%09rItem(%22Display%20name%22%2C%20control.GetDisplayName())%2C%0A%09%09%09rItem(%22Field%22%2C%20control.GetFieldName()%2C%20false%2C%20%7B%22data-handler%22%3A%22field%22%2C%22data-selector%22%3A%60ul%23%24%7Bapplet.GetFullId()%7D_bc%2Cul%23%24%7Bapplet.GetFullId()%7D_bc_%24%7Bapplet.GetBusComp().GetFieldMap()%5Bcontrol.GetFieldName()%5D%3F.index%7D%60%7D)%2C%0A%09%09%09rItem(%22Value%22%2C%20bc%3F.GetFieldValue(control.GetFieldName()))%2C%0A%09%09%09rItem(%22Message%22%2C%20control.GetControlMsg())%2C%0A%09%09%09...(control.GetMessageVariableMap()%20%26%26%20Object.keys(control.GetMessageVariableMap()).length%20%3F%20%0A%09%09%09%09%5B%60%3Cli%3E%3Ca%20href%3D%22%23%22%20data-ul%3D%22%24%7Bid%7D_var%22%3EMessage%20variables%20(%24%7BObject.keys(control.GetMessageVariableMap()).length%7D)%3A%3C%2Fa%3E%3C%2Fli%3E%60%2C%0A%09%09%09%09%60%3Cul%20id%3D%22%24%7Bid%7D_var%22%20class%3D%22ul_hide%22%3E%60%2C%0A%09%09%09%09Object.entries(control.GetMessageVariableMap()).map(rPS).join(%22%5Cn%22)%2C%0A%09%09%09%09%60%3C%2Ful%3E%60%5D%20%3A%20%5B%5D)%2C%09%0A%09%09%09rItem(%22Type%22%2C%20control.GetUIType())%2C%0A%09%09%09rItem(%22LOV%22%2C%20control.GetLovType())%2C%0A%09%09%09rItem(%22MVG%22%2C%20control.IsMultiValue())%2C%0A%09%09%09rItem(%22Method%22%2C%20control.GetMethodName()%2C%20false%2C%20%7B%22data-handler%22%3A%22control%20method%22%2C%20%22data-applet%22%3Aapplet.GetName()%2C%22data-control%22%3Acontrol.GetName()%7D)%2C%0A%09%09%09...(options%5B%22adv%22%5D%20%3D%3D%3D%20%60true%60%20%26%26%20ps%20%26%26%20ps.propArrayLen%20%3F%20%0A%09%09%09%09%5B%60%3Cli%3E%3Ca%20href%3D%22%23%22%20data-ul%3D%22%24%7Bid%7D_method%22%3EMethod%20properties%20(%24%7Bps.propArrayLen%7D)%3A%3C%2Fa%3E%3C%2Fli%3E%60%2C%0A%09%09%09%09%60%3Cul%20id%3D%22%24%7Bid%7D_method%22%20class%3D%22ul_hide%22%3E%60%2C%0A%09%09%09%09Object.entries(ps.propArray).map(rPS).join(%22%5Cn%22)%2C%0A%09%09%09%09%60%3C%2Ful%3E%60%5D%20%3A%20%5B%5D)%2C%0A%09%09%09%2F%2FrItem(%22Id%22%2C%20id)%2C%0A%09%09%09rItem(%22Id%22%2C%20options%5B%22adv%22%5D%20%3D%3D%3D%20%60true%60%20%26%26%20%24(sel).is(%22%3Afocusable%22)%20%3F%20%5Bid%2C%20%60%3Ca%20href%3D%22%23%22%20data-focus%3D'%24%7Bsel%7D'%3EFocus%3C%2Fa%3E%60%5D%3Aid)%2C%09%0A%09%09%09rItem(%22Immidiate%20post%20changes%22%2C%20control.GetPostChanges())%2C%0A%09%09%09rItem(%22Display%20format%22%2C%20control.GetDisplayFormat())%2C%0A%09%09%09rItem(%22HTML%20attribute%22%2C%20control.GetHTMLAttr()%2C%20true)%2C%0A%09%09%09rItem(%22Display%20mode%22%2C%20control.GetDispMode())%2C%0A%09%09%09rItem(%22Popup%22%2C%20control.GetPopupType()%20%26%26%20%5Bcontrol.GetPopupType()%2C%20control.GetPopupWidth()%2C%20control.GetPopupHeight()%5D.join(%22%20%2F%20%22))%2C%0A%09%09%09rHierarchy(%22Plugin%20wrapper%22%2C%20SiebelApp.S_App.PluginBuilder.GetPwByControl(pr%2C%20control)%2C%20true)%2C%0A%09%09%09rItem(%22Length%22%2C%20control.GetFieldName()%20%3F%20control.GetMaxSize()%20%3A%20%22%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20...(options%5B%22adv%22%5D%20%3D%3D%3D%20%60true%60%20%26%26%20up%20%26%26%20up.propArrayLen%20%3F%20%0A%09%09%09%09%5B%60%3Cli%3E%3Ca%20href%3D%22%23%22%20data-ul%3D%22%24%7Bid%7D_up%22%3EUser%20properties%20(%24%7Bup.propArrayLen%7D)%3A%3C%2Fa%3E%3C%2Fli%3E%60%2C%0A%09%09%09%09%60%3Cul%20id%3D%22%24%7Bid%7D_up%22%20class%3D%22ul_hide%22%3E%60%2C%0A%09%09%09%09Object.entries(up.propArray).map(rPS).join(%22%5Cn%22)%2C%0A%09%09%09%09%60%3C%2Ful%3E%60%5D%20%3A%20%5B%5D)%2C%09%0A%09%09%09rItem(%22Object%22%2C%20%60SiebelApp.S_App.GetActiveView().GetAppletMap()%5B%22%24%7Bapplet.GetName()%7D%22%5D.GetControls()%5B%22%24%7Bcontrol.GetName()%7D%22%5D%60%2C%20true)%2C%0A%09%09%09%24(sel).length%20%3E%200%20%3F%20rItem(%22Node%22%2C%20%60%24(%22%24%7Bsel%7D%22)%60%2C%20true)%20%3A%20%60%60%2C%0A%09%09%60%3C%2Ful%3E%60%2C%60%3C%2Fli%3E%60%5D.join(%22%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20rApplet(applet)%20%7B%0A%20%20%20%20%09const%20cm%20%3D%20Object.values(applet.GetControls())%3B%0A%20%20%20%20%09const%20mm%20%3D%20applet.GetCanInvokeArray()%3B%0A%20%20%20%20%09const%20id%20%3D%20applet.GetFullId()%3B%0A%20%20%20%20%20%20%20%20return%20%5B%60%3Cul%20id%3D%22%24%7Bid%7D%22%20class%3D%22ul_hide%22%3E%60%2C%0A%09%09%09rItem(%22Applet%22%2C%20applet.GetName())%2C%0A%09%09%09rItem(%22BusComp%22%2C%20applet.GetBusComp()%3F.GetName()%2C%20false%2C%20%7B%22data-handler%22%3A%22buscomp%22%2C%20%22data-selector%22%3A%60ul%23%24%7Bapplet.GetFullId()%7D_bc%60%7D)%2C%0A%09%09%09rItem(%22Title%22%2C%20SiebelApp.S_App.LookupStringCache(applet.GetTitle()))%2C%0A%09%09%09rItem(%22Mode%22%2C%20applet.GetMode())%2C%0A%09%09%09rItem(%22Record%20counter%22%2C%20applet.GetPModel().GetStateUIMap().GetRowCounter%2C%20true)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20rHierarchy(%22PModel%22%2C%20applet.GetPModel()%2C%20true)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20rHierarchy(%22PRender%22%2C%20SiebelAppFacade.ComponentMgr.FindComponent(applet.GetName())%3F.GetPR()%2C%20true)%2C%0A%09%09%09rItem(%22Object%22%2C%20%60SiebelApp.S_App.GetActiveView().GetAppletMap()%5B%22%24%7Bapplet.GetName()%7D%22%5D%60%2C%20true)%2C%0A%09%09%09rItem(%22Node%22%2C%20%60%24(%22%23%24%7Bapplet.GetFullId()%7D%22)%60%2C%20true)%2C%0A%09%09%09%60%3Cli%3E%3Ca%20href%3D%22%23%22%20data-ul%3D%22%24%7Bid%7D_methods%22%3EMethods%20(%24%7Bmm.length%7D)%3A%3C%2Fa%3E%3C%2Fli%3E%60%2C%0A%09%09%09%60%3Cul%20id%3D%22%24%7Bid%7D_methods%22%20class%3D%22ul_hide%22%3E%60%2C%0A%09%09%09mm.map(m%3D%3E%5B%60%3Cli%3E%60%2C%20%60%3Ca%20href%3D%22%23%22%20data-handler%3D%22applet%20method%22%20data-applet%3D%22%24%7Bapplet.GetName()%7D%22%3E%60%2C%20m%2C%20%60%3C%2Fa%3E%60%2C%20%60%3C%2Fli%3E%60%5D.join(%22%22)).join(%22%5Cn%22)%2C%0A%09%09%09%60%3C%2Ful%3E%60%2C%0A%09%09%09%60%3Cli%3E%3Ca%20href%3D%22%23%22%20data-ul%3D%22%24%7Bid%7D_controls%22%3EControls%20(%24%7Bcm.length%7D)%3A%3C%2Fa%3E%3C%2Fli%3E%60%2C%0A%09%09%09%60%3Cul%20id%3D%22%24%7Bid%7D_controls%22%20class%3D%22ul_show%20keep_open%22%3E%60%2C%20%2F%2F%3Cul%20id%3D%22%24%7Bid%7D_controls%22%20class%3D%22ul_show%22%3E%0A%09%09%09...cm.map(rControl)%2C%0A%09%09%09%60%3C%2Ful%3E%60%2C%0A%09%09%60%3C%2Ful%3E%60%5D.join(%22%5Cn%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20rField(field%2C%20id)%20%7B%0A%20%20%20%20%09const%20bc%20%3D%20field.GetBusComp()%3B%0A%20%20%20%20%09const%20name%20%3D%20SiebelApp.S_App.LookupStringCache(field.GetName())%3B%0A%20%20%20%20%09return%20%5B%60%3Cli%3E%60%2C%0A%09%09%09%60%3Ca%20href%3D%22%23%22%20data-ul%3D%22%24%7Bid%7D%22%3E%60%2C%20name%2C%20%60%3C%2Fa%3E%60%2C%0A%09%09%09%60%3Cul%20id%3D%22%24%7Bid%7D%22%20class%3D%22ul_hide%22%3E%60%2C%0A%09%09%09rItem(%22Field%22%2C%20name)%2C%0A%09%09%09rItem(%22Value%22%2C%20field.GetBusComp().GetFieldValue(name))%2C%0A%09%09%09rItem(%22Type%22%2C%20field.GetDataType())%2C%0A%09%09%09rItem(%22Length%22%2C%20field.GetLength())%2C%0A%09%09%09rItem(%22Search%20spec%22%2C%20field.GetSearchSpec())%2C%0A%09%09%09rItem(%22Calculated%22%2C%20!!field.IsCalc())%2C%0A%09%09%09rItem(%22Bounded%20picklist%22%2C%20!!field.IsBoundedPick())%2C%0A%09%09%09rItem(%22Read%20only%22%2C%20!!field.IsReadOnly())%2C%0A%09%09%09rItem(%22Immediate%20post%20changes%22%2C%20!!field.IsPostChanges())%2C%0A%09%09%09rItem(%22Object%22%2C%20%60SiebelApp.S_App.GetBusObj().GetBusCompByName(%22%24%7Bbc.GetName()%7D%22).GetFieldMap()%5B%22%24%7Bname%7D%22%5D%60%2C%20true)%2C%0A%09%09%60%3C%2Ful%3E%60%2C%20%60%3C%2Fli%3E%60%5D.join(%22%5Cn%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20rBC(a%2C%20id)%20%7B%0A%20%20%20%20%09var%20bc%20%3D%20a.GetBusComp()%3B%0A%20%20%20%20%09const%20fields%20%3D%20Object.values(bc.GetFieldMap())%3B%0A%20%20%20%20%20%20%20%20return%20%5B%60%3Cul%20id%3D%22%24%7Bid%7D%22%20class%3D%22ul_hide%22%3E%60%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20rItem(%22BusComp%22%2C%20bc.GetName())%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20rItem(%22Commit%20pending%22%2C%20!!bc.commitPending%2C%20true)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20rItem(%22Can%20update%22%2C%20!!bc.canUpdate)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20rItem(%22Search%20spec%22%2C%20bc.GetSearchSpec())%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20rItem(%22Sort%20spec%22%2C%20bc.GetSortSpec())%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20rItem(%22Current%20row%20id%22%2C%20bc.GetIdValue())%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20rItem(%22Object%22%2C%20%60SiebelApp.S_App.GetBusObj().GetBusComp(%22%24%7Ba.GetBCId()%7D%22)%60%2C%20true)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%60%3Cli%3E%3Clabel%3E%3Ca%20href%3D%22%23%22%20data-ul%3D%22%24%7Bid%7D_rec%22%3ERecords%3A%20%24%7BMath.abs(bc.GetCurRowNum())%7D%20of%20%24%7Bbc.GetNumRows()%7D%24%7Bbc.IsNumRowsKnown()%3F''%3A'%2B'%7D%3C%2Fa%3E%3C%2Flabel%3E%3C%2Fli%3E%60%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%60%3Cul%20id%3D%22%24%7Bid%7D_rec%22%20class%3D%22ul_hide%22%3E%60%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%60%3Ctable%3E%60%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%60%3Ctr%3E%60%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20...Object.keys(bc.GetFieldMap()).map((i)%3D%3E%60%3Cth%3E%24%7Bi%7D%3C%2Fth%3E%60)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%60%3C%2Ftr%3E%60%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20...bc.GetRecordSet().map((r%2C%20i)%3D%3E%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%60%3Ctr%3E%60%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20...Object.values(r).map(v%3D%3E%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%60%3Ctd%3E%3Ca%20href%3D%22%23%22%20%24%7Bbc.GetSelection()%20%3D%3D%20i%20%3F%20%60%20class%3D%22x_active%22%60%20%3A%20%60%60%7D%3E%60%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20v%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%60%3C%2Fa%3E%3C%2Ftd%3E%60%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D.join(%22%22))%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%60%3C%2Ftr%3E%60%0A%20%20%20%20%20%20%20%20%20%20%20%20%5D.join(%22%22))%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%60%3C%2Ftable%3E%60%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%60%3C%2Ful%3E%60%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%60%3Cli%3E%3Clabel%3E%3Ca%20href%3D%22%23%22%20data-ul%3D%22%24%7Bid%7D_fields%22%3EFields(%24%7Bbc.GetFieldList()%3F.length%7D)%3A%3C%2Fa%3E%3C%2Flabel%3E%3C%2Fli%3E%60%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%60%3Cul%20id%3D%22%24%7Bid%7D_fields%22%20class%3D%22ul_show%20keep_open%22%3E%60%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20...fields.map((field%2C%20i)%20%3D%3E%20rField(field%2C%20id%20%2B%20%22_%22%20%2B%20field.index))%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%60%3C%2Ful%3E%60%2C%0A%20%20%20%20%20%20%20%20%60%3C%2Ful%3E%60%5D.join(%22%5Cn%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20rApplication()%20%7B%0A%20%20%20%20%20%20%20%20const%20app%20%3D%20SiebelApp.S_App%3B%0A%20%20%20%20%20%20%20%20const%20view%20%3D%20app.GetActiveView()%3B%0A%20%20%20%20%20%20%20%20const%20bo%20%3D%20app%3F.GetBusObj()%3B%0A%20%20%20%20%20%20%20%20const%20bm%20%3D%20bo%3F.GetBCArray()%3B%0A%20%20%20%20%20%20%20%20const%20scrPM%20%3D%20SiebelApp.S_App.NavCtrlMngr()%3F.GetscreenNavigationPM()%3B%0A%20%20%20%20%20%20%20%20let%20am%20%3D%20Object.values(view%3F.GetAppletMap())%3B%0A%20%20%20%20%20%20%20%20var%20ws%20%3D%20SiebelApp.S_App.GetWSInfo().split(%22_%22)%3B%0A%20%20%20%20%20%20%20%20var%20wsver%20%3D%20ws.pop()%3B%0A%0A%20%20%20%20%20%20%20%20var%20amCache%20%3D%20%7B%7D%3B%0A%20%20%20%20%20%20%20%20Object.assign(amCache%2C%20view%3F.GetAppletMap())%3B%0A%0A%09%09%2F%2F%20Identifying%20a%20primary%20BC%0A%09%09var%20paa%20%3D%20Object.values(SiebelApp.S_App.GetActiveView().GetAppletMap()).filter((a)%20%3D%3E%20!a.GetParentApplet()%20%26%26%20(!a.GetBusComp()%20%7C%7C%20!a.GetBusComp().GetParentBusComp()))%3B%0A%09%09if%20(!paa.length)%20%7B%0A%09%09%09alert(%22Failed%20to%20identify%20a%20primary%20BusComp!%22)%0A%09%09%7D%0A%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20return%20%5B%60%3Cul%3E%60%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20rItem(%22Application%22%2C%20app.GetName())%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20rItem(%22Screen%22%2C%20scrPM%3F.Get(%22GetTabInfo%22)%5BscrPM%3F.Get(%22GetSelectedTabKey%22)%5D%3F.screenName)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20rItem(%22View%22%2C%20view.GetName())%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20rItem(%22Task%22%2C%20view.GetActiveTask())%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20rHierarchy(%22PModel%22%2C%20SiebelAppFacade.ComponentMgr.FindComponent(view.GetName())%3F.GetPM()%2C%20true)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20rHierarchy(%22PRender%22%2C%20SiebelAppFacade.ComponentMgr.FindComponent(view.GetName())%3F.GetPR()%2C%20true)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20rItem(%22BusObject%22%2C%20bo%3F.GetName())%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20rItem(%22Workspace%22%2C%20%5Bws.join(%22_%22)%2C%20wsver%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%60%3Clabel%3EApplets%20(%24%7Bam.length%7D)%20%2F%20BusComps%20(%24%7Bbm.length%7D)%3A%3C%2Flabel%3E%60%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%60%3Cul%3E%60%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20hierBC(paa%5B0%5D.GetBusComp()%2C%200%2C%20amCache)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20...Object.values(amCache).map((a)%3D%3ErAppletName(a%2C%200%2C%20amCache))%2C%0A%20%20%20%20%20%20%20%20%60%3C%2Ful%3E%3C%2Ful%3E%60%5D.join(%22%5Cn%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%2F%2F%20prints%20applet%20name%0A%20%20%20%20function%20rAppletName(a%2C%20l%2C%20amCache)%20%7B%0A%20%20%20%20%09delete%20amCache%5Ba.GetName()%5D%3B%0A%20%20%20%20%09return%20%5B%60%3Cli%3E%60%2C%0A%09%09%09%09%20%20%20%20%60%3Cul%3E%60.repeat(l)%2C%0A%09%09%09%09%09%60%3Ca%20href%3D%22%23%22%20data-ul%3D%22%24%7Ba.GetFullId()%7D%22%20class%3D%22%24%7Ba%20%3D%3D%3D%20SiebelApp.S_App.GetActiveView().GetActiveApplet()%20%3F%20'x_active'%20%3A%20%24(%60%23%24%7Ba.GetFullId()%7D%60).is(%22%3Avisible%22)%20%3F%20''%20%3A%20'x_hidden'%7D%22%3E%60%2C%0A%09%09%09%09%09%09options%5B'applet_list_by'%5D%20%3D%3D%20'title'%20%26%26%20SiebelApp.S_App.LookupStringCache(a.GetTitle())%20%3F%20SiebelApp.S_App.LookupStringCache(a.GetTitle())%20%3A%20a.GetName()%2C%0A%09%09%09%09%09%60%3C%2Fa%3E%60%2C%0A%09%09%09%09%09a.GetBusComp()%20%26%26%20options%5B%22applet_list%22%5D.indexOf(%22bc%22)%20%3E%20-1%20%3F%20%60%20%2F%20%3Ca%20href%3D%22%23%22%20data-ul%3D%22%24%7Ba.GetFullId()%7D_bc%22%3E%24%7Ba.GetBusComp().GetName()%7D%3C%2Fa%3E%60%20%3A%20%60%60%2C%0A%09%09%09%09%09a.GetBusComp()%20%26%26%20a.GetBusComp().GetIdValue()%20%26%26%20options%5B%22applet_list%22%5D.indexOf(%22rowid%22)%20%3E%20-1%20%3F%20%60%20%2F%20%3Ca%20href%3D%22%23%22%3E%24%7Ba.GetBusComp().GetIdValue()%7D%3C%2Fa%3E%60%20%3A%20%60%60%2C%0A%09%09%09%09%09rApplet(a)%2C%0A%09%09%09%09%09a.GetBusComp()%20%26%26%20rBC(a%2C%20a.GetFullId()%20%2B%20%22_bc%22)%2C%0A%09%09%09%09%09%60%3C%2Ful%3E%60.repeat(l)%2C%0A%09%09%09%09%60%3C%2Fli%3E%60%5D.join(%22%22)%3B%0A%20%20%20%20%7D%0A%0A%09%2F%2F%20prints%20applets%20based%20on%20bc%20or%20parent%20applet%20(rec)%0A%09function%20hierApplet(bc%2C%20pa%2C%20l%2C%20amCache)%20%7B%0A%09%09return%20Object.values(amCache).filter((a)%20%3D%3E%20bc%20%26%26%20a.GetBusComp()%20%3D%3D%3D%20bc%20%7C%7C%20pa%20%26%26%20a.GetParentApplet()%20%3D%3D%3D%20pa).map((a)%20%3D%3E%20!(a.GetName()%20in%20amCache)%20%3F%20%22%22%20%3A%20%5B%0A%09%09%09rAppletName(a%2C%20l%2C%20amCache)%2C%0A%09%09%09hierApplet(null%2C%20a%2C%20l%20%2B%201%2C%20amCache)%20%2F%2F%20look%20for%20child%20applets%0A%09%09%5D.join(%22%5Cn%22))%3B%0A%09%7D%0A%0A%09%2F%2F%20prints%20applets%20based%20on%20BC%20hierarchy%20(rec)%0A%09function%20hierBC(bc%2C%20l%2C%20amCache)%20%7B%0A%09%09return%20%5B%0A%09%09%09hierApplet(bc%2C%20null%2C%20l%2C%20amCache)%3F.join(%22%5Cn%22)%2C%0A%09%09%09...SiebelApp.S_App.GetActiveBusObj().GetBCArray().filter((e)%20%3D%3E%20e.GetParentBusComp()%20%3D%3D%3D%20bc).map((b)%20%3D%3E%20hierBC(b%2C%20l%20%2B%201%2C%20amCache))%0A%09%09%5D.join(%22%5Cn%22)%3B%0A%09%7D%0A%0A%09%2F%2F%20utilities%0A%09function%20escapeHtml(html)%20%7B%0A%09%09return%20html.toString()%0A%09%09%20%20%20%20.replace(%2F%26%2Fg%2C%20%22%26amp%3B%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20.replace(%2F%3C%2Fg%2C%20%22%26lt%3B%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20.replace(%2F%3E%2Fg%2C%20%22%26gt%3B%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20.replace(%2F%22%2Fg%2C%20%22%26quot%3B%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20.replace(%2F'%2Fg%2C%20%22%26%23039%3B%22)%3B%0A%09%7D%0A%7D)()%7D)()%3B 
  • About View 2.0 bookmarklet link for drag and drop install.

I used Caio's tool to convert source code into a bookmarklet.

Previous version can be found here and on GitHub.

If you are not quite satisfied with out-of-the-box [Inspect Workspace UI], in this article I offer you to build your own UI or to check out my version.

As usual, the front-end going to be based on a JQuery dialog and compiled into a bookmarklet while the back-end is another method in the [FWK Runtime] business service (BS).


Back-end


The idea is simple: to find a workspace record in [Repository Workspace] BusComp by name and run OpenWS and PreviewWS methods.

Here is how your BS method might look like:

function InspectWS(Inputs, Outputs) {
    var name = Inputs.GetProperty("Name");
    var bo = TheApplication().GetBusObject("Workspace");
    var bc = bo.GetBusComp("Repository Workspace");
    try {
        bc.SetSearchExpr('[Name] = "' + name + '"');
        bc.SetViewMode(AllView);
        bc.ExecuteQuery(ForwardBackward);
        if (bc.FirstRecord()) {
            bc.InvokeMethod("OpenWS");
            bc.InvokeMethod("PreviewWS");
        } else {
            throw "Workspace name not found: " + name;
        }
    } catch (e) {
        throw e;
    } finally {
        bc = null;
        bo = null;
    }
}

Don't forget to publish your BS through [ClientBusinessService] application user property and probably make it a client-side business service, so you won't have a problem with the upstream migration.


Front-end


Here is a simplified dialog with a text field where you paste a workspace name and a button to run a BS method:

(() => {
    if ("undefined" === typeof SiebelApp) {
        alert("It works only in Siebel OUI session!");
        return;
    }
    const func = "SiebelInspectWS";
    const html = `<div title="Inspect Workspace"><input type="text" id = "${func}" style="width:100%"></div>`;
    const $d = $(html).dialog({
        modal: true,
        width: 640,
        buttons: [{
            text: 'Inspect',
            click: () => {
                const service = SiebelApp.S_App.GetService("FWK Runtime");
                let ps = SiebelApp.S_App.NewPropertySet();
                ps.SetProperty("Name", $('#' + func).val());
                let config = {
                    async: false,
                    cb: function (methodName, inputSet, outputSet) {
                        if (outputSet.GetProperty("Status") == "Error") {
                            sRes = outputSet.GetChildByType("Errors").GetChild(0).GetProperty("ErrMsg");
                        }
                        alert(sRes || "Done!");
                    }
                };
                service.InvokeMethod("InspectWS", ps, config);
            }
        }, {
            text: 'Close (Esc)',
            click: () => $(this).dialog('close')
        }]
    });
})();

To open the UI just run the above snippet from the browser console, snippet, file or compile it into a bookmarklet. Make sure you transform/compile it before using in old browsers like IE.


My implementation


I've advanced the initial version of Inspect Workspace UI with quite a few features, so check out my latest implementation below.

Features:

  • The text field accepts multiple formats:
    • an exact workspace name: vbabkin_20200924_d419_1
    • a search pattern of workspace name: *d419*
    • a full search specification for the Repository Workspace BC: [Parent Name] = "Release 21" AND [Created By] = LoginId()
    • leave it empty to search or inspect most recent undelivered workspaces created by the active user
  • Hit Enter or click [Search button] to search for 10 most recent workspaces matching the provided name/pattern/spec.
  • Click one of the workspaces link in the search result list to inspect the workspace.
  • Hit Ctrl+Enter or click [Inspect] button to inspect the most recent workspaces matching the provided name/pattern/spec.
  • Run the snippet twice or double-click the bookmark to inspect your latest undelivered workspace.
  • The text field remembers a history of 5 recent calls.
  • It highlights searching pattern in result list.
  • It prints calls, errors and success messages with a timestamp.
  • Click [Help] button to toggle help instructions.
  • To close the dialog:
    • click the [X] or [Close] button
    • hit the [Escape] key
    • click outside the dialog
  • Right-click a workspace link to copy it.

Source code (v1.5):

  • Business service: File
  • Front-end: Snippet | File
  • /* 
    @desc Inspect Workspace UI
    @author VB(xapuk.com)
    @version 1.5 2020/11/08
    @requires "FWK Runtime" business service to be published (Application ClientBusinessService usep property)
    @features
        +elements: help text hidden by default, input field with the history, message bar, 3 buttons
        +don't accept value shorter then 3 chars excluding *
        +async call with busy overlay
        +highlight search pattern in all found results
        +shows a text if number of results = limit
        +cut history to 5 items and don't store empty requests
        +insect ws on click of <a>
        +close on right-click of whitespace
        +change a default ws filter to only filter out Delivered WSs
        +copy ws name on right-click of link
        +make a ws name in a sucess message a link
        +put a timestamp in the message
        +fix contextmenu on text input
        +before opening a dialog check if it exists, and if so run auto inspect
        +clicking a ws name inspects the first in the list
        +dialog should have a unique selector itself so we don't mess with other dialogs
        +print a message before server call, like inspecting ws blabla, or searching for workspace blabla
        +use a function to print the message, keep a history of 3 messages
        +close when click outside
        +make it work and test in IE/Edge/Firefox
        +ES6 => Babel => ES5 => Bookmarklet
    @Fixed in 1.2:
        +print placeholder text on empty call
        +don't highlight search specs
        +clear results before next search
        +fix char limit error
        +fix hightlight
        +print user name instead of "my"
    @Fixed in 1.3:
        +placeholder text color
        +<> in placeholder text
        +when searching for exact ws name, shouldn't highlight it
        +link click doesn't work if clicked on highlighted part (<b>)
        +don't close on whitespace click
    @Fixed in 1.4
        +change to the layout
        +fixed empty call problem
        +instruction changes
    @fixed in 1.5
        +remove "workspace" from messages so inspecting latest workspace wording make sence
        +search results shouldn't be empty - when inspecting should spool a ws name, while search/inspect in progress put ...
        +more instructions
    */
    
    (() => {
        if ("undefined" === typeof SiebelApp) {
            alert("It works only in Siebel OUI session!");
            return;
        }
        // snippet id
        const func = "SiebelInspectWS";
        // selector preffix
        const id = "#" + func;
        const cls = "." + func;
        // max number of output records
        const iLimit = 10;
        // history of recent calls
        let aHistory = JSON.parse(window.localStorage[func] || "[]");
        // messages
        let aMsg = [];
        // double click of bookmarklet
        if ($("." + func).length) {
            $("." + func).find(id + "IBtn").click();
            return;
        }
    
        const placeholder = `${SiebelApp.S_App.GetUserName()||"my"} recent undelivered workspace`;
    
        const help = `<i><p>Welcome to Inspect Workspace UI</p>
        Text field accepts several formats:<br>
        <ul><li> - an exact workspace name: vbabkin_20200924_d419_1</li>
        <li> - a search pattern of workspace name: *d419*</li>
        <li> - an exact search spec for Repository Workspace BC: [Parent Name] = "Release 21" AND [Created By] = LoginId()</li>
        <li> - leave it empty to search / inspect most recent undelivered workspaces created by active user</li></ul>
        <p>Hit Enter to search for 10 most recent workspaces matching the provided name/pattern/spec and then click one of the workspaces in the list to inspect it.</p>
        <p>Hit Ctrl+Enter to inspect the most recent workspaces matching the provided name/pattern/spec.</p>
        <p>If you want to inspect/re-inspect your recent undelivered workspace, just hit Ctrl+Enter upon opening a dialog or double click a bookmark link.</p>
        <p>Right click on workspace name to copy it.</p>
        <p>Click anywhere outside of the dialog to close it.</p>
        <p>Check out <a href="http://xapuk.com/index.php?topic=125" target="_blank">http://xapuk.com/</a> for details.</p></i>`;
    
        const html = `<div title="Inspect workspace">
                <span id = "${func}Help" style = "display:none">${help}</span>
                <input placeholder = "<${placeholder}>" type="text" id = "${func}" list="${func}History" autocomplete="off">
                <ul id="${func}List">Provide a search criteria above and run [Search] to see a list of available workspaces<br>and/or run [Inspect] directly to inspect the most recent workspace matching the criteria</ul>
                <p id = "${func}Msg"></p>
                <datalist id = "${func}History"></datalist>
                <style>
                    .${func} input {
                        width: 100%!Important;
                        margin-bottom: 10px;
                    }
                    #${func}::placeholder {
                        color: lightslategrey;
                    }
                    #${func}List {
                        margin-left: 15px;
                    }
                    #${func}Help i {
                        font-size: 0.9rem;
                    }
                    .${func} li {
                        list-style-type: disc;
                        margin-left: 30px;
                    }
                    #${func}Msg {
                        border-top: 1px solid lightslategrey;
                        padding-top: 5px;
                    }
                </style>
            </div>`;
    
        const $d = $(html).dialog({
            modal: true,
            width: 640,
            classes: {
                "ui-dialog": func
            },
            buttons: [{
                text: 'Search (Enter)',
                click: () => Run(false)
            }, {
                id: func + "IBtn",
                text: 'Inspect (Ctrl+Enter)',
                click: () => Run(true)
            }, {
                text: 'Help',
                click: () => $d.find(id + "Help").toggle()
            }, {
                text: 'Close (Esc)',
                click: () => $d.dialog('close')
            }],
            open: function () {
                const $this = $(this);
                // autofocus
                $this.find('#' + func).focus();
                // key bindings
                $this.parent(".ui-dialog").contextmenu(function (e) {
                    const scope = e.target;
                    if (scope.nodeName === "A") {
                        // copy value on right-click of link
                        e.stopPropagation();
                        e.preventDefault();
                        // replace link with an input
                        $(scope).hide().after(`<input id='${func}Copy'>`);
                        $d.find(id + "Copy").val($(scope).text()).select();
                        // attempt to copy value
                        if (document.execCommand("copy", false, null)) {
                            // if copied, display a message for a second
                            $d.find(id + "Copy").attr("disabled", "disabled").css("color", "red").val("Copied!");
                            setTimeout(() => {
                                $d.find(id + "Copy").remove();
                                $(scope).show();
                            }, 700);
                        } else {
                            // if failed to copy, keep input element until blur, so it can be copied manually
                            $d.find(id + "Copy").blur(() => {
                                $(this).remove();
                                $d.find("a").show();
                            });
                        }
                    }
                }).click((e) => {
                    var a = $(e.target).closest("a");
                    if (a.length && a.closest(id + "List").length) {
                        Run(true, a.text());
                    }
                }).find(id).keydown((event) => {
                    if (event.keyCode === 13) {
                        Run(event.ctrlKey);
                    }
                });
                // close dialog when click outside
                $('.ui-widget-overlay').click(() => $d.dialog("close"));
                // render history
                aHistory.forEach((i) => $this.find(id + "History").append(`<option>${i}</option>`));
            },
            close: () => {
                $d.dialog('destroy').remove();
            }
        });
    
        function Run(bInspect, inpname) {
            const name = inpname ? inpname : $('#' + func).val();
            // don't accept specs shorter then 3 chars
            if (name && name.replace(/\*/gm, "").length < 3) {
                printMsg(`Value should be longer then 3 characters! ${name}`);
                return;
            }
            //clean up results before search
            if (!bInspect) {
                $d.find(id + "List").empty();
            }
            // save last query
            if (name) {
                if (aHistory.indexOf(name) > -1) {
                    aHistory.splice(name, 1);
                }
                aHistory.unshift(name);
                // limit history stack volume to 5
                if (aHistory.length > 5) {
                    aHistory.pop();
                }
                window.localStorage[func] = JSON.stringify(aHistory);
            }
            // invoke BS
            const service = SiebelApp.S_App.GetService("FWK Runtime");
            let ps = SiebelApp.S_App.NewPropertySet();
            ps.SetProperty("Name", name);
            ps.SetProperty("Inspect", bInspect ? "Y" : "N");
            ps.SetProperty("Limit", iLimit);
            let config = {
                async: true,
                scope: this,
                mask: true,
                cb: function (methodName, inputSet, outputSet) {
                    if (outputSet.GetProperty("Status") == "Error") {
                        sRes = outputSet.GetChildByType("Errors").GetChild(0).GetProperty("ErrMsg");
                    } else {
                        let psRS = outputSet.GetChildByType("ResultSet");
                        if (psRS) {
                            sRes = psRS.GetProperty("Result");
                            sWorkspaces = psRS.GetProperty("Workspaces");
                            if (!sRes) {
                                if (bInspect) {
                                    sRes = `Workspace <b><a href='#'>${sWorkspaces||"?"}</a></b> inspected successfully!`;
                                } else {
                                    if (sWorkspaces) {
                                        // print a list of workspaces
                                        $d.find(id + "List").empty();
                                        let aWorkspaces = sWorkspaces.split(",");
                                        aWorkspaces.forEach((w) => $d.find(id + "List").append(`<li><a href='#'>${highlightText(name, w)}</a></li>`));
                                        if (aWorkspaces.length == iLimit) {
                                            $d.find(id + "List").append(`<p><i>${iLimit} most recent workspaces are shown.</i></p>`);
                                        }
                                    }
                                }
                            } else if (sRes.indexOf("No workspace found") > -1) {
                                $d.find(id + "List").html(`Workspace not found, please provide a valid search criteria and run [Search] again...`);
                            }
                        }
                    }
                    if (sRes) {
                        printMsg(sRes);
                    }
                }
            };
            printMsg(`${bInspect?'Inspecting':'Searching for'} ${name||placeholder}`);
            service.InvokeMethod("InspectWS", ps, config);
        }
    
        function highlightText(pattern, value) {
            if (pattern && value && !pattern.match(/\[.*\]/gm) && pattern.replace(/\*/gm, "").length < value.length) {
                const patterns = pattern.split("*");
                let i, lastIndex = -1;
                value = patterns.reduce((res, p) => {
                    let i = res.indexOf(p, lastIndex);
                    if (p && i > -1) {
                        res = `${res.substr(0, i)}<b>${p}</b>${res.substr(i + p.length)}`;
                        lastIndex = i;
                    }
                    return res;
                }, value);
            }
            return value;
        }
    
        function printMsg(txt) {
            txt = (new Date).toLocaleTimeString() + ' >> ' + txt;
            // limit a message stack to 3 items
            aMsg.push(txt);
            if (aMsg.length > 3) {
                aMsg.shift();
            }
            $d.find(id + "Msg").html(aMsg.join("<br>"));
        }
    })();
  • Bookmarklet code: Snippet
  • javascript:(function(){function e(e,a){var c=a?a:$("#"+n).val();if(c&&c.replace(/\*/gm,"").length<3)return void i("Value should be longer then 3 characters! "+c);e||d.find(r+"List").empty(),c&&(s.indexOf(c)>-1&&s.splice(c,1),s.unshift(c),s.length>5&&s.pop(),window.localStorage[n]=JSON.stringify(s));var l=SiebelApp.S_App.GetService("FWK Runtime"),u=SiebelApp.S_App.NewPropertySet();u.SetProperty("Name",c),u.SetProperty("Inspect",e?"Y":"N"),u.SetProperty("Limit",o);var f={async:!0,scope:this,mask:!0,cb:function(n,s,a){if("Error"==a.GetProperty("Status"))sRes=a.GetChildByType("Errors").GetChild(0).GetProperty("ErrMsg");else{var p=a.GetChildByType("ResultSet");if(p)if(sRes=p.GetProperty("Result"),sWorkspaces=p.GetProperty("Workspaces"),sRes)sRes.indexOf("No workspace found")>-1&&d.find(r+"List").html("Workspace not found, please provide a valid search criteria and run [Search] again...");else if(e)sRes="Workspace <b><a href='#'>"+(sWorkspaces||"?")+"</a></b> inspected successfully!";else if(sWorkspaces){d.find(r+"List").empty();var l=sWorkspaces.split(",");l.forEach(function(e){return d.find(r+"List").append("<li><a href='#'>"+t(c,e)+"</a></li>")}),l.length==o&&d.find(r+"List").append("<p><i>"+o+" most recent workspaces are shown.</i></p>")}}sRes&&i(sRes)}};i((e?"Inspecting":"Searching for")+" "+(c||p)),l.InvokeMethod("InspectWS",u,f)}function t(e,t){return e&&t&&!e.match(/\[.*\]/gm)&&e.replace(/\*/gm,"").length<t.length&&function(){var i=e.split("*"),n=-1;t=i.reduce(function(e,t){var i=e.indexOf(t,n);return t&&i>-1&&(e=e.substr(0,i)+"<b>"+t+"</b>"+e.substr(i+t.length),n=i),e},t)}(),t}function i(e){e=(new Date).toLocaleTimeString()+" >> "+e,a.push(e),a.length>3&&a.shift(),d.find(r+"Msg").html(a.join("<br>"))}if("undefined"==typeof SiebelApp)return void alert("It works only in Siebel OUI session!");var n="SiebelInspectWS",r="#"+n,o=10,s=JSON.parse(window.localStorage[n]||"[]"),a=[];if($("."+n).length)return void $("."+n).find(r+"IBtn").click();var p=(SiebelApp.S_App.GetUserName()||"my")+" recent undelivered workspace",c='<i><p>Welcome to Inspect Workspace UI</p>Text field accepts several formats:<br><ul><li> - an exact workspace name: vbabkin_20200924_d419_1</li><li> - a search pattern of workspace name: *d419*</li><li> - an exact search spec for Repository Workspace BC: [Parent Name] = "Release 21" AND [Created By] = LoginId()</li><li> - leave it empty to search / inspect most recent undelivered workspaces created by active user</li></ul><p>Hit Enter to search for 10 most recent workspaces matching the provided name/pattern/spec and then click one of the workspaces in the list to inspect it.</p><p>Hit Ctrl+Enter to inspect the most recent workspaces matching the provided name/pattern/spec.</p><p>If you want to inspect/re-inspect your recent undelivered workspace, just hit Ctrl+Enter upon opening a dialog or double click a bookmark link.</p><p>Right click on workspace name to copy it.</p><p>Click anywhere outside of the dialog to close it.</p><p>Check out <a href="http://xapuk.com/index.php?topic=125" target="_blank">http://xapuk.com/</a> for details.</p></i>',l='<div title="Inspect workspace"><span id = "'+n+'Help" style = "display:none">'+c+'</span><input placeholder = "<'+p+'>" type="text" id = "'+n+'" list="'+n+'History" autocomplete="off"><ul id="'+n+'List">Provide a search criteria above and run [Search] to see a list of available workspaces<br>and/or run [Inspect] directly to inspect the most recent workspace matching the criteria</ul><p id = "'+n+'Msg"></p><datalist id = "'+n+'History"></datalist><style>.'+n+" input {width: 100%!Important;margin-bottom: 10px;}#"+n+"::placeholder {color: lightslategrey;}#"+n+"List {margin-left: 15px;}#"+n+"Help i {font-size: 0.9rem;}."+n+" li {list-style-type: disc;margin-left: 30px;}#"+n+"Msg {border-top: 1px solid lightslategrey;padding-top: 5px;}</style></div>",d=$(l).dialog({modal:!0,width:640,classes:{"ui-dialog":n},buttons:[{text:"Search (Enter)",click:function(){return e(!1)}},{id:n+"IBtn",text:"Inspect (Ctrl+Enter)",click:function(){return e(!0)}},{text:"Help",click:function(){return d.find(r+"Help").toggle()}},{text:"Close (Esc)",click:function(){return d.dialog("close")}}],open:function(){var t=$(this);t.find("#"+n).focus(),t.parent(".ui-dialog").contextmenu(function(e){var t=this,i=e.target;"A"===i.nodeName&&(e.stopPropagation(),e.preventDefault(),$(i).hide().after("<input id='"+n+"Copy'>"),d.find(r+"Copy").val($(i).text()).select(),document.execCommand("copy",!1,null)?(d.find(r+"Copy").attr("disabled","disabled").css("color","red").val("Copied!"),setTimeout(function(){d.find(r+"Copy").remove(),$(i).show()},700)):d.find(r+"Copy").blur(function(){$(t).remove(),d.find("a").show()}))}).click(function(t){var i=$(t.target).closest("a");i.length&&i.closest(r+"List").length&&e(!0,i.text())}).find(r).keydown(function(t){13===t.keyCode&&e(t.ctrlKey)}),$(".ui-widget-overlay").click(function(){return d.dialog("close")}),s.forEach(function(e){return t.find(r+"History").append("<option>"+e+"</option>")})},close:function(){d.dialog("destroy").remove()}})})();
  • Bookmarklet link: InspectWS
  • Version history is available in GitHub

Thanks to Manan for his contribution!

If "Siebel Workflow Process" (WF) is your primary tool for business process automation as they are for me, it might be a useful topic for you.

Familiar with the error "The value entered in field Process Business Object of buscomp Workflow Process Deployment does not match any value in the bounded pick list FOW SRF Business Object." (SBL-DAT-00225) when activating a custom BO-based workflow process in Siebel Tools? The usual way to solve it is to activate a process through [Administration - Business Process] screen. It is still annoying, as you will lose your current context, and extremely annoying when you don't have BP screen or access to it in the test application. In this topic, I offer you another, effortless way to activate a WF process. On the same view/session where you are testing it, and with just a couple clicks.

Ok, let's get down to implementation.

1. Publishing the service.

As you might have guessed, we will be using the "Workflow Admin Service". Out of many ways to run the BS, I'll cover OUI scripts.

So, let's make the BS accessible from a browser script. Here, I recommend using a service runner - straight forward concept when you publish one to run any other service in the system. If you are not comfortable with granting access to all services in production, use a client-side business service for service runner. So, it wouldn't be automatically migrated to higher environments along with a repository.

Here is how your service runner method can look like:

function InvokeServiceMethod(Inputs, Outputs) {
    var bs;
    var sBS = Inputs.GetProperty("Service");
    Inputs.RemoveProperty("Service");
    var sMethod = Inputs.GetProperty("Method");
    Inputs.RemoveProperty("Method");
    
    try {
        bs = TheApplication().GetService(sBS);
        bs.InvokeMethod(sMethod, Inputs, Outputs);
    } catch(e) {
        throw e;
    } finally {
        bs = null;
    }
}

Here is a full version of my client-side Business Service - FWK Runtime. Simply, download and import it on Administration - Business Service screen.

And finally, granting access to run a service runner from browser scripts:

2. JS code with UI and service call.

We will need a UI to enter a WF process name and a button to run the BS. We will be using JQuery dialog with just a couple of elements. It is going to look like this:

Source code and installation links are below.

  • Front-end: Snippet
  • /* 
    @desc bookmarklet UI to activate Siebel Workflow Process
    @author VB (xapuk.com)
    @version 1
    */
    if ("undefined" == typeof SiebelApp) {
        alert("It works only in Siebel OUI session!");
    } else {
    
        // snippet id
        var id = "SiebelWFDeploy";
    
        // localStorage to store the history
        var aHist = window.localStorage[id]?JSON.parse(window.localStorage[id]):[];
    
        // just in case (experimental)
        $("#" + id).parent().remove();
    
        // constructing dialog content
        var s = '<div title="Activate workflow">';
        s += '<input id = "' + id + '" type="text" list="' + id + 'List" style="width:100%" value="' + (aHist.length?aHist[0]:"") + '">'; // most recent
        s += '<label class="pt-3">Recent workflows:</label><ul>';
        for (var i =0; i < aHist.length && i < 5; i++){ // five recent values as links
            s += '<li><a href="#">' + aHist[i] + '</a></li>';
        }
        s += '</ul></div>';
    
        // open dialog
        var $d = $(s).dialog({
            modal: true,
            width: 640,
            open: function() {
                $('#' + id).autocomplete({source: aHist});
                $('#' + id).focus().select(); // autofocus
            },
            close: function() {
                $(this).dialog('destroy').remove();
            },
            buttons: [{
                text: 'Activate (Enter/Click)',
                click: function(){
                    go($d.find('#' + id).val());
                }
            }, {
                text: 'Close (Esc)',
                click: function() {
                    $(this).dialog('close');
                }
            }]
        });
    
        // key bindings
        $d.keyup(function(event) {
            // enter
            if (event.keyCode === 13) { 
                go($d.find('#' + id).val());
            }
        });
    
        // running function on anchor link click
        $d.find("a").click(function(event) {
            go($(this).html());
        });
    }
    
    // Activate
    function go(name) {
        if (name){
            // moving recent view to the top
            if (aHist.indexOf(name) > -1){
               aHist.splice(aHist.indexOf(name),1);
            }
            aHist.unshift(name);
            window.localStorage[id] = JSON.stringify(aHist); 
            $d.dialog('close');
    
            // invoke BS
            var service = SiebelApp.S_App.GetService("FWK Runtime");
            var ps = SiebelApp.S_App.NewPropertySet();
            ps.SetProperty("Service", "Workflow Admin Service");
            ps.SetProperty("Method", "Activate");
            ps.SetProperty("FlowSearchSpec", "[Process Name] = '" + name + "'");
            var outputSet = service.InvokeMethod("InvokeServiceMethod", ps);
            if (console){
                console.log(outputSet);
            }
            if (outputSet.GetProperty("Status") == "Error"){
                alert(outputSet.GetChildByType("Errors").GetChild(0).GetProperty("ErrMsg"));    
            }else{
                if (outputSet.GetChildByType("ResultSet").GetProperty("NumFlowActivated") === "0"){
                    alert("Process definition [" + name + "] not found");
                }else{
                    alert("Done!");
                }
            }
        }
    }
  • Bookmarklet code: Snippet
  • javascript:function go(e){if(e){aHist.indexOf(e)>-1&&aHist.splice(aHist.indexOf(e),1),aHist.unshift(e),window.localStorage[id]=JSON.stringify(aHist),$d.dialog("close");var i=SiebelApp.S_App.GetService("FWK Runtime"),t=SiebelApp.S_App.NewPropertySet();t.SetProperty("Service","Workflow Admin Service"),t.SetProperty("Method","Activate"),t.SetProperty("FlowSearchSpec","[Process Name] = '"+e+"'");var o=i.InvokeMethod("InvokeServiceMethod",t);console&&console.log(o),alert("Error"==o.GetProperty("Status")?o.GetChildByType("Errors").GetChild(0).GetProperty("ErrMsg"):"0"===o.GetChildByType("ResultSet").GetProperty("NumFlowActivated")?"Process definition ["+e+"] not found":"Done!")}}if("undefined"==typeof SiebelApp)alert("It works only in Siebel OUI session!");else{var id="SiebelWFDeploy",aHist=window.localStorage[id]?JSON.parse(window.localStorage[id]):[];$("#"+id).parent().remove();var s='<div title="Activate workflow">';s+='<input id = "'+id+'" type="text" list="'+id+'List" style="width:100%" value="'+(aHist.length?aHist[0]:"")+'">',s+='<label class="pt-3">Recent workflows:</label><ul>';for(var i=0;i<aHist.length&&5>i;i++)s+='<li><a href="#">'+aHist[i]+"</a></li>";s+="</ul></div>";var $d=$(s).dialog({modal:!0,width:640,open:function(){$("#"+id).autocomplete({source:aHist}),$("#"+id).focus().select()},close:function(){$(this).dialog("destroy").remove()},buttons:[{text:"Activate (Enter/Click)",click:function(){go($d.find("#"+id).val())}},{text:"Close (Esc)",click:function(){$(this).dialog("close")}}]});$d.keyup(function(e){13===e.keyCode&&go($d.find("#"+id).val())}),$d.find("a").click(function(e){go($(this).html())})}
  • Bookmarklet link: Activate WF

3. Disable cache.

Workflow Process cache is controlled by VerCheckTime (Workflow Version Checking Interval) server parameter .

If the parameter is on, a new WF version wouldn't take in action in existing session right away after activating it. It makes sense to have it on production, but I recommend to turn it off on DEV environment.

Also, turn it off on your dedicated client in .cfg file:

...
[Workflow]
VerCheckTime = -1

Bonus

Same story with TBUI. Simply run [Task Activation Automation] service from JavaScript. Service runner is paying off already, by the way.

  • Bookmarklet code: Snippet
  • javascript:function go(e){if(e){aHist.indexOf(e)>-1&&aHist.splice(aHist.indexOf(e),1),aHist.unshift(e),window.localStorage[id]=JSON.stringify(aHist),$d.dialog("close");var t=SiebelApp.S_App.GetService("FWK Runtime"),i=SiebelApp.S_App.NewPropertySet();i.SetProperty("Service","Task Activation Automation"),i.SetProperty("Method","Activate Task"),i.SetProperty("TaskName",e);var o=t.InvokeMethod("InvokeServiceMethod",i);console&&console.log(o),alert("Error"==o.GetProperty("Status")?o.GetChildByType("Errors").GetChild(0).GetProperty("ErrMsg"):"0"===o.GetChildByType("ResultSet").GetProperty("NumFlowActivated")?"Process definition ["+e+"] not found":"Done!")}}if("undefined"==typeof SiebelApp)alert("It works only in Siebel OUI session!");else{var id="SiebelTaskDeploy",aHist=window.localStorage[id]?JSON.parse(window.localStorage[id]):[];$("#"+id).parent().remove();var s='<div title="Activate task">';s+='<input id = "'+id+'" type="text" list="'+id+'List" style="width:100%" value="'+(aHist.length?aHist[0]:"")+'">',s+='<label class="pt-3">Recent tasks:</label><ul>';for(var i=0;i<aHist.length&&5>i;i++)s+='<li><a href="#">'+aHist[i]+"</a></li>";s+="</ul></div>";var $d=$(s).dialog({modal:!0,width:640,open:function(){$("#"+id).autocomplete({source:aHist}),$("#"+id).focus().select()},close:function(){$(this).dialog("destroy").remove()},buttons:[{text:"Activate (Enter/Click)",click:function(){go($d.find("#"+id).val())}},{text:"Close (Esc)",click:function(){$(this).dialog("close")}}]});$d.keyup(function(e){13===e.keyCode&&go($d.find("#"+id).val())}),$d.find("a").click(function(e){go($(this).html())})}
  • Bookmarklet: Activate Task

Starting a series "Runtime objects cache". And the first runtime object I'll be covering is Runtime Events (RTE).

Background:

If you are working with RTE you probably know about "Reload Runtime Events" menu command, which allows you to clear RTE cache in your current session. But, what if you are working with multiple sessions? For example, doing your configuration under one user / application and testing it under another, where you don't have access to RTE screen. It could also be a case where you don't want to lose a context. And finally, you might be creating RTE indirectly, from workflows start connector. It all leads you to restarting a Siebel client or losing a context.

Solution:

It turns out "Reload Runtime Events" command is an implicit BC method supported by generic CSSBusComp class. It means we can run that command from any applet and let it propagate to BC. Thanks to Siebel OUI we can run any applet method right from the browser console. As simple as that:

SiebelApp.S_App.GetActiveView().GetActiveApplet().InvokeMethod("ClearCTEventCache");

Here I've made a bookmarklet out of it, so you can run Reload RTE command from browsers bookmark toolbar in any application/view/context without any pre-configuration:

  • Source code: Snippet
  • /* 
    @desc Reloads Runtime Events
    @author VB(xapuk.com)
    @version 1.1 2019/04/20
    */
    if("undefined" === typeof SiebelApp){
        alert("Please, log into Siebel application first!");
    }else{
        var v = SiebelApp.S_App.GetActiveView();
        var ap = v.GetActiveApplet();
        if ("undefined" === typeof ap) {
            ap = v.GetAppletMap()[Object.keys(v.GetAppletMap())[0]];
        }
        if ("undefined" === typeof ap) {
            alert("No applet found!");
        } else {
            ap.InvokeMethod("ClearCTEventCache", null, {
                "cb": function(e) {
                    alert("Runtime Events were reloaded!");
                },
                "errcb": function(e) {
                    console.log("Err", e);
                    alert(e.toString());
                }
            });
        }
    }
    
  • Bookmarklet code: Snippet
  • javascript:void function(){if("undefined"==typeof SiebelApp)alert("Please, log into Siebel application first!");else{var e=SiebelApp.S_App.GetActiveView(),t=e.GetActiveApplet();"undefined"==typeof t&&(t=e.GetAppletMap()[Object.keys(e.GetAppletMap())[0]]),"undefined"==typeof t?alert("No applet found!"):t.InvokeMethod("ClearCTEventCache",null,{cb:function(e){alert("Runtime Events were reloaded!")},errcb:function(e){console.log("Err",e),alert(e.toString())}})}}();
    
  • Bookmark link: Drag&drop me

Bonus:

You can use the same approach to reset List of Values cache:

SiebelApp.S_App.GetActiveView().GetActiveApplet().InvokeMethod("ClearLOVCache");

 

and View/Responsibility cache:

SiebelApp.S_App.GetActiveView().GetActiveApplet().InvokeMethod("ClearResponsibilityCache");

 

Another playground for you Guys. This time it is to evaluate a "calc field" expressions. The official name of the syntax is Siebel Query Language and it is used widely through Siebel apps, for example:

  • Field calculated value, pre/post-default, validation
  • Data Validation Manager
  • User properties
  • Workflow processes and UI Tasks
  • Predefined queries
  • Runtime events
  • EAI/BC Data Map

A playground is very handy when it comes to prototyping or debugging expressions or simply if you need to get a value of an active field or profile attribute.

Less words more code, let's get down to the implementation.


Back end


This time we will be invoking a built-in BusComp method EvalExpr. So let's create another method in runtime business service:

function EvalExpr (Inputs, Outputs) {
    var bc:BusComp;
    try {
        bc = TheApplication().ActiveBusObject().GetBusComp(Inputs.GetProperty("BC"));
        Outputs.SetProperty("Result", bc.InvokeMethod("EvalExpr", Inputs.GetProperty("Expr")));
    } catch(e) {
        Outputs.SetProperty("Result", e.toString());
    } finally {
        bc = null;
    }
}

Here is a full version of my client-side Business Service.


Front end


For UI we will be using a bookmarklet with a dialog which contains a drop-down with active BusComps, two text areas for input expression and a result, and a button to run the service.

Here is the code from my most recent version: Snippet
/* 
@desc UI allowing to evaluate expressions (EvalExpr) on active BCs
@author VB(xapuk.com)
@version 1.2 2018/07/23
@requires BS "FWK Runtime" to be published
*/

if ("undefined" == typeof SiebelApp){
    alert("It works only in Siebel OUI session!");
}else{
    var func = "SiebelEvalExpr";
    $("#" + func).parent().remove();

    var a = LoadBCs();
    if (a.length === 0){
        alert("No BusComps/Records available!");
    }else{

        var s = '<div title="Runtime calculations">' +
        '<label for="' + func + 'List">Business Component:</label>' +
        '<select id = "' + func + 'List" style="display:block"></select>' +
        '<label for="' + func + '">Expression:</label>' +
        '<textarea id = "' + func + '" rows="3"></textarea>' +
        '<label for="' + func + 'Out">Results:</label>' +
        '<textarea id = "' + func + 'Out" disabled rows="2"></textarea>' +
        '<style>select,textarea{width:100%!Important}</style>' +
        '</div>';

        var d = $(s).dialog({
            modal: true,
            width: 1024,
            heigth: 640,
            open: function(){
                $('#'+func).focus();

                // key bindings
                $("#"+func+"Out").parent().keydown(function(event) {
                    if (event.ctrlKey && event.keyCode === 13) { // ctrl + Enter
                        EvalExpr();
                    }
                });

                // list of BCs
                $("#" + func + "List").append("<option>" + a.join("</option><option>") + "</option>");
                $("#" + func + "List").val(SiebelApp.S_App.GetActiveView().GetActiveApplet().GetBusComp().GetName());

                // recent expression
                $("#" + func).val(JSON.parse(window.localStorage[func]));

                //style
                $(this).append('<style type="text/css">textarea, select { height:auto; width:100% }</style>');
            },
            close: function(){
                $(this).dialog('destroy').remove();
            },
            buttons: [
                {
                    text:'Run (Ctrl+Enter)',
                    click: EvalExpr
                },
                {
                   text:'Close (Esc)',
                   click: function() {
                    $(this).dialog('destroy').remove();
                   }
                }
            ]
        });

        // bind and trigger auto-adjust
        $(d).find("#" + func).keyup(function(){
            TextAdjust(this, 3);
        }).keyup();
    }
}

function EvalExpr(){
    var sExpr = $('#'+func).val();
    var sRes = "";

    // save last query
    window.localStorage[func] = JSON.stringify(sExpr);

    // if there is a selection
    var ele = document.getElementById(func);
    if(ele.selectionStart !== undefined && ele.selectionStart != ele.selectionEnd){// Normal browsers
        sExpr = ele.value.substring(ele.selectionStart, ele.selectionEnd);
    }else if(document.selection !== undefined){// IE
        ele.focus();
        var sel = document.selection.createRange();
        sExpr = sel.text;
    }

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

// auto-ajust textarea height
function TextAdjust(scope, minrows, maxrows) {

    maxrows = maxrows>0?maxrows:10; 
    minrows = minrows>0?minrows:2;
    var txt = scope.value;
    var cols = scope.cols;

    var arraytxt = txt.split('\n');
    var rows = arraytxt.length; 

    if (rows > maxrows) {
        scope.rows = maxrows;
    } else if (rows < minrows) { 
        scope.rows = minrows;
    } else {
        scope.rows = rows;
    }
}

// gather the list of active BCs
function LoadBCs(){
    var a = [];
    for(var i in SiebelApp.S_App.GetActiveBusObj().GetBCMap()){
        var bc = SiebelApp.S_App.GetActiveBusObj().GetBCMap()[i];
        if (a.indexOf(bc.GetName()) == -1 && bc.GetNumRows() > 0){
            a.push(bc.GetName());
        }
    }
    return a;
} 
Bookmarklet code: Snippet
javascript:void function(){function e(){var e=$("#"+i).val(),o="";window.localStorage[i]=JSON.stringify(e);var l=document.getElementById(i);if(void 0!==l.selectionStart&&l.selectionStart!=l.selectionEnd)e=l.value.substring(l.selectionStart,l.selectionEnd);else if(void 0!==document.selection){l.focus();var r=document.selection.createRange();e=r.text}var s=SiebelApp.S_App.GetService("FWK Runtime"),a=SiebelApp.S_App.NewPropertySet();a.SetProperty("Expr",e),a.SetProperty("BC",$("#"+i+"List").val());var n=s.InvokeMethod("EvalExpr",a);"Error"==n.GetProperty("Status")?o=n.GetChildByType("Errors").GetChild(0).GetProperty("ErrMsg"):(o=n.GetChildByType("ResultSet").GetProperty("Result"),console.log(n)),t($("#"+i+"Out").show().text(o)[0])}function t(e,t,o){o=o>0?o:10,t=t>0?t:2;var i=e.value,l=(e.cols,i.split("\n")),r=l.length;r>o?e.rows=o:t>r?e.rows=t:e.rows=r}function o(){var e=[];for(var t in SiebelApp.S_App.GetActiveBusObj().GetBCMap()){var o=SiebelApp.S_App.GetActiveBusObj().GetBCMap()[t];-1==e.indexOf(o.GetName())&&o.GetNumRows()>0&&e.push(o.GetName())}return e}if("undefined"==typeof SiebelApp)alert("It works only in Siebel OUI session!");else{var i="SiebelEvalExpr";$("#"+i).parent().remove();var l=o();if(0===l.length)alert("No BusComps/Records available!");else{var r='<div title="Runtime calculations"><label for="'+i+'List">Business Component:</label><select id = "'+i+'List" style="display:block"></select><label for="'+i+'">Expression:</label><textarea id = "'+i+'" rows="3"></textarea><label for="'+i+'Out">Results:</label><textarea id = "'+i+'Out" disabled rows="2"></textarea><style>select,textarea{width:100%!Important}</style></div>',s=$(r).dialog({modal:!0,width:1024,heigth:640,open:function(){$("#"+i).focus(),$("#"+i+"Out").parent().keydown(function(t){t.ctrlKey&&13===t.keyCode&&e()}),$("#"+i+"List").append("<option>"+l.join("</option><option>")+"</option>"),$("#"+i+"List").val(SiebelApp.S_App.GetActiveView().GetActiveApplet().GetBusComp().GetName()),$("#"+i).val(JSON.parse(window.localStorage[i])),$(this).append('<style type="text/css">textarea, select { height:auto; width:100% }</style>')},close:function(){$(this).dialog("destroy").remove()},buttons:[{text:"Run (Ctrl+Enter)",click:e},{text:"Close (Esc)",click:function(){$(this).dialog("destroy").remove()}}]});$(s).find("#"+i).keyup(function(){t(this,3)}).keyup()}}}(); 
And a bookmarklet: Bookmarklet

Updated


Here is a new version with a built-in beautifier from another topic:

  • A parser to be placed at /public/scripts/3rdParty/SiebelQueryLang.js: file
  • Source code: Snippet
  • /* 
    @desc UI allowing to evaluate expressions (EvalExpr) on active BCs
    @author VB(xapuk.com)
    @version 1.3 2019/03/10
    @requires BS "FWK Runtime" to be compiled and published
    */
    
    if ("undefined" == typeof SiebelApp){
        alert("It works only in Siebel OUI session!");
    } else {
        var func = "SiebelEvalExpr";
        $("#" + func).parent().remove();
        var bBeauty = false;
        var a = LoadBCs();
        if (a.length === 0){
            alert("No BusComps/Records available!");
        }else{
    
            var s = '<div title="Runtime calculations">' +
            '<label for="' + func + 'List">Business Component:</label>' +
            '<select id = "' + func + 'List" style="display:block"></select>' +
            '<label for="' + func + '">Expression:</label>' +
            '<textarea id = "' + func + '" rows="5" nowrap></textarea>' +
            '<label for="' + func + 'Out">Results:</label>' +
            '<textarea id = "' + func + 'Out" disabled rows="2"></textarea>' +
            '<style type="text/css">.ui-dialog textarea, .ui-dialog select {height:auto; width:100%; margin-bottom:10px} .ui-dialog label{margin-top:20px!}</style>'
            '</div>';
    
            var d = $(s).dialog({
                modal: true,
                width: 1024,
                heigth: 640,
                open: function(){
                    $('#'+func).focus();
    
                    // key bindings
                    $("#"+func+"Out").parent().keydown(function(event) {
                        if (event.ctrlKey && event.keyCode === 13) { // ctrl + Enter
                            EvalExpr();
                        }
                    });
    
                    // list of BCs
                    $("#" + func + "List").append("<option>" + a.join("</option><option>") + "</option>");
                    $("#" + func + "List").val(SiebelApp.S_App.GetActiveView().GetActiveApplet().GetBusComp().GetName());
    
                    // recent expression
                    $("#" + func).val(JSON.parse(window.localStorage[func]));
    
                },
                close: function(){
                    $(this).dialog('destroy').remove();
                },
                buttons: [
                    {
                        text:'Format/Linarise',
                        click: Beauty,
                        id: 'BeautyBtn'
                    },{
                        text:'Run (Ctrl+Enter)',
                        click: EvalExpr
                    },{
                       text:'Close (Esc)',
                       click: function() {
                        $(this).dialog('destroy').remove();
                       }
                    }
                ]
            });
    
            // bind and trigger auto-adjust
            $(d).find("#" + func).keyup(function(){
                TextAdjust(this, 5);
            }).keyup();
    
            // bind a beautifier
            $(".ui-dialog #BeautyBtn").hide();
            require(["3rdParty/SiebelQueryLang"], function(e){
                console.log("Beautifier loaded!");
                $(".ui-dialog #BeautyBtn").show();
            });
        }
    }
    
    function Beauty(){
        var s = $('#'+func).val();
        if (s){
            if (bBeauty){
                // linarise
                s = s.replace(/\n(\t|\s)*/gm,"");
                $('#'+func).val(s).attr("wrap", "on");
                bBeauty = false;
                
            } else {
                // beautify
                try {
                    var o = SiebelQueryLang.parse(s);
                    s = trav(o.expression, "");
                    $('#'+func).val(s).attr("wrap", "off");
                    bBeauty = true;
                } catch(e) {
                    // silence the error
                    console.log(e);
                }
            }
            TextAdjust($('#'+func)[0]);
        }
    }
    
    function trav(o, t, f) {
    	var r = "";
    	if ("object" === typeof o) {
    		var p = o.par;
    		var n = o.not;
    
    		if (o.type === "bin") {
    			r =  trav(o.left, t) + " " + o.operator + " " + trav(o.right, t);
    		} else if (o.type === "log") {
    			if(p) { // format logical operators eclosed in brackets
    				tt = t + "\t";
    				r = "(\n";
    				r += tt + trav(o.left, tt, true);
    				r += "\n" + tt + o.operator + " " + trav(o.right, tt, true);
    				r += "\n" + t + ")";
    				p = false;
    			} else {
    				if(f) {
    					r = trav(o.left, t, true);
    					r += "\n" + t + o.operator + " " + trav(o.right, t, true);
    				} else {
    					r = trav(o.left, t) + " " + o.operator + " " + trav(o.right, t);
    				}
    			}
    		} else if (o.type === "func") {
    			var l = o.arguments.length;
    			var f = l > 2; // split params when more then 2
    			var s = (f ? "\n" + t : "");
    			var st = (f ? s + "\t" : "");
    			r = o.name + "(";
    			o.arguments.forEach(function(a, i) {
    				r += st + trav(a, t + "\t") + (i < l - 1 ? ", " : "");
    			});
    			r += s + ")";
    		} else if (o.type === "field") {
    			r = "[" + o.field + "]";
    		} else if (o.type === "param") {
    			r =  "[&" + o.param + "]";
    		} else if (o.type === "num") {
    			r =  o.value;
    		} else if (o.type === "str") {
    			r = '"' + o.value +'"';
    		}
    
    		if (p) {
    			r = "(" + r + ")";
    		}
    		if (n) {
    			r = "NOT " + r;
    		}
    
    	} else {
    		r = o;
    	}
        return r;
    }
    
    
    function EvalExpr(){
    
        var sExpr = $('#'+func).val();
        var sRes = "";
    
        // save last query
        window.localStorage[func] = JSON.stringify(sExpr);
    
        // if there is a selection
        var ele = document.getElementById(func);
        if(ele.selectionStart !== undefined && ele.selectionStart != ele.selectionEnd){// Normal browsers
            sExpr = ele.value.substring(ele.selectionStart, ele.selectionEnd);
        }else if(document.selection !== undefined){// IE
            ele.focus();
            var sel = document.selection.createRange();
            sExpr = sel.text;
        }
    
        // invoke BS
        var service = SiebelApp.S_App.GetService("FWK Runtime");
        var ps = SiebelApp.S_App.NewPropertySet();
        ps.SetProperty("Expr", sExpr);
        ps.SetProperty("BC", $("#" + func + "List").val());
        var outputSet = service.InvokeMethod("EvalExpr", ps);
        if (outputSet.GetProperty("Status") == "Error"){
            sRes = outputSet.GetChildByType("Errors").GetChild(0).GetProperty("ErrMsg");
        }else{
            sRes = outputSet.GetChildByType("ResultSet").GetProperty("Result");
            console.log(outputSet);
        }
        TextAdjust($('#'+func + "Out").show().text(sRes)[0]);
    }
    
    // auto-ajust textarea height
    function TextAdjust(scope, minrows, maxrows) {
    
        maxrows = maxrows>0?maxrows:30;
        minrows = minrows>0?minrows:5;
        var txt = scope.value;
        var cols = scope.cols;
    
        var arraytxt = txt.split('\n');
        var rows = arraytxt.length; 
    
        if (rows > maxrows) {
            scope.rows = maxrows;
        } else if (rows < minrows) { 
            scope.rows = minrows;
        } else {
            scope.rows = rows;
        }
    }
    
    // put active BC in the list with active applet's bc as selected
    function LoadBCs(){
        var a = [];
        for(var i in SiebelApp.S_App.GetActiveBusObj().GetBCMap()){
            var bc = SiebelApp.S_App.GetActiveBusObj().GetBCMap()[i];
            if (a.indexOf(bc.GetName()) == -1 && bc.GetNumRows() > 0){
                a.push(bc.GetName());
            }
        }
        return a;
    } 
  • Bookmarklet code: Snippet
  • javascript:void function(){function e(){var e=$("#"+a).val();if(e){if(l)e=e.replace(/\n(\t|\s)*/gm,""),$("#"+a).val(e).attr("wrap","on"),l=!1;else try{var o=SiebelQueryLang.parse(e);e=t(o.expression,""),$("#"+a).val(e).attr("wrap","off"),l=!0}catch(r){console.log(r)}i($("#"+a)[0])}}function t(e,o,i){var r="";if("object"==typeof e){var a=e.par,l=e.not;if("bin"===e.type)r=t(e.left,o)+" "+e.operator+" "+t(e.right,o);else if("log"===e.type)a?(tt=o+"	",r="(\n",r+=tt+t(e.left,tt,!0),r+="\n"+tt+e.operator+" "+t(e.right,tt,!0),r+="\n"+o+")",a=!1):i?(r=t(e.left,o,!0),r+="\n"+o+e.operator+" "+t(e.right,o,!0)):r=t(e.left,o)+" "+e.operator+" "+t(e.right,o);else if("func"===e.type){var n=e.arguments.length,i=n>2,s=i?"\n"+o:"",p=i?s+"	":"";r=e.name+"(",e.arguments.forEach(function(e,i){r+=p+t(e,o+"	")+(n-1>i?", ":"")}),r+=s+")"}else"field"===e.type?r="["+e.field+"]":"param"===e.type?r="[&"+e.param+"]":"num"===e.type?r=e.value:"str"===e.type&&(r='"'+e.value+'"');a&&(r="("+r+")"),l&&(r="NOT "+r)}else r=e;return r}function o(){var e=$("#"+a).val(),t="";window.localStorage[a]=JSON.stringify(e);var o=document.getElementById(a);if(void 0!==o.selectionStart&&o.selectionStart!=o.selectionEnd)e=o.value.substring(o.selectionStart,o.selectionEnd);else if(void 0!==document.selection){o.focus();var r=document.selection.createRange();e=r.text}var l=SiebelApp.S_App.GetService("FWK Runtime"),n=SiebelApp.S_App.NewPropertySet();n.SetProperty("Expr",e),n.SetProperty("BC",$("#"+a+"List").val());var s=l.InvokeMethod("EvalExpr",n);"Error"==s.GetProperty("Status")?t=s.GetChildByType("Errors").GetChild(0).GetProperty("ErrMsg"):(t=s.GetChildByType("ResultSet").GetProperty("Result"),console.log(s)),i($("#"+a+"Out").show().text(t)[0])}function i(e,t,o){o=o>0?o:30,t=t>0?t:5;var i=e.value,r=(e.cols,i.split("\n")),a=r.length;a>o?e.rows=o:t>a?e.rows=t:e.rows=a}function r(){var e=[];for(var t in SiebelApp.S_App.GetActiveBusObj().GetBCMap()){var o=SiebelApp.S_App.GetActiveBusObj().GetBCMap()[t];-1==e.indexOf(o.GetName())&&o.GetNumRows()>0&&e.push(o.GetName())}return e}if("undefined"==typeof SiebelApp)alert("It works only in Siebel OUI session!");else{var a="SiebelEvalExpr";$("#"+a).parent().remove();var l=!1,n=r();if(0===n.length)alert("No BusComps/Records available!");else{var s='<div title="Runtime calculations"><label for="'+a+'List">Business Component:</label><select id = "'+a+'List" style="display:block"></select><label for="'+a+'">Expression:</label><textarea id = "'+a+'" rows="5" nowrap></textarea><label for="'+a+'Out">Results:</label><textarea id = "'+a+'Out" disabled rows="2"></textarea><style type="text/css">.ui-dialog textarea, .ui-dialog select {height:auto; width:100%; margin-bottom:10px} .ui-dialog label{margin-top:20px!}</style>',p=$(s).dialog({modal:!0,width:1024,heigth:640,open:function(){$("#"+a).focus(),$("#"+a+"Out").parent().keydown(function(e){e.ctrlKey&&13===e.keyCode&&o()}),$("#"+a+"List").append("<option>"+n.join("</option><option>")+"</option>"),$("#"+a+"List").val(SiebelApp.S_App.GetActiveView().GetActiveApplet().GetBusComp().GetName()),$("#"+a).val(JSON.parse(window.localStorage[a]))},close:function(){$(this).dialog("destroy").remove()},buttons:[{text:"Format/Linarise",click:e,id:"BeautyBtn"},{text:"Run (Ctrl+Enter)",click:o},{text:"Close (Esc)",click:function(){$(this).dialog("destroy").remove()}}]});$(p).find("#"+a).keyup(function(){i(this,5)}).keyup(),$(".ui-dialog #BeautyBtn").hide(),require(["3rdParty/SiebelQueryLang"],function(e){console.log("Beautifier loaded!"),$(".ui-dialog #BeautyBtn").show()})}}}(); 
  • And a bookmarklet link: Bookmarklet

 

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

I have this idea since the release of OpenUI - to pull all useful info from SiebelApp object (BO, BCs, View, Applets, Controls etc.) into a dialog which can be opened with a hit of a button. And maybe also to built in some features for a better user experience.

Check out my version of "About View" bookmarklet:

Source code & Installation
  • Drag&drop it over the browser favourites toolbar: About View
  • Or replace a bookmark URL with this code: Snippet
  • javascript:{var id="SiebelAboutView",$d,tmp='<div title="About View" id="<%=id%>"><%var v=SiebelApp.S_App.GetActiveView(),am=v.GetAppletMap()%><b>Application:</b> <a><%=SiebelApp.S_App.GetName()%></a><br><b>View:</b> <a><%=v.GetName()%></a><br><b>BusObject:</b> <a><%=SiebelApp.S_App.GetActiveBusObj().GetName()%></a><br><%if(v.GetActiveTask()){%><b>Task:</b> <a><%=v.GetActiveTask()%></a><br><%}%><b>Applets(<%=Object.keys(am).length%>) / BusComps(<%=Object.keys(SiebelApp.S_App.GetActiveBusObj().GetBCMap()).length%>):</b><br><ul style="padding-left:20px"><%for(sa in am){var a=am[sa];var bc=a.GetBusComp();var r = bc.GetSelection() < bc.GetRecordSet().length?bc.GetRecordSet()[bc.GetSelection()]:{};var os="SiebelApp.S_App.GetActiveView().GetAppletMap()[\'"+sa+"\']";var $ds=$("#"+a.GetFullId());%><li><a data-target="controls"><b style="<%if($ds.is(":hidden")){%>font-style:italic;<%}if(a===v.GetActiveApplet()){%>text-decoration:underline<%}%>"><%=sa%></b></a> / <a data-target="fields"><b><%=bc.GetName()%></b></a><ul id="controls" style="display:none"><hr><b>Applet:</b> <a><%=a.GetName()%></a><br/><b>BusComp:</b> <a><%=bc.GetName()%></a><br/><b>Mode:</b> <a><%=a.GetMode()%></a><br/><b>Title:</b> <a><%=a.GetAppletLabel()%></a><br/><%var at=a.GetToggleApplet();if(at){%><b>Toggle:</b> <a><%=at%></a><br/><%}%><b>Object Selector:</b> <a><%=os%></a><br><b>DOM Selector:</b> <a>$("<%=$ds.selector%>")</a><br><b>Controls (<%=Object.keys(a.GetControls()).length%>): </b><ul><%for(control in a.GetControls()){var c=a.GetControls()[control];var $cds=$ds.find("[name=\'"+c.GetInputName()+"\']")%><li><a data-target="control"><b style="<%if($cds.is(":hidden")){%>font-style:italic;<%}if(c===a.GetActiveControl()){%>text-decoration:underline<%}%>"><%=c.GetDisplayName()||control%></b></a><ul id="control"><hr><%if($cds.is(":visible")&&$cds.is(":focusable")){%><button data-eval="$(\'<%=$cds.selector%>\').focus()">Focus</button><br><%}%><b>Control:</b> <a><%=control%></a><br><%if(c.GetFieldName()){%><b>Field:</b> <a><%=c.GetFieldName()%></a><br><%if(r){%><b>Value:</b> <a><%=r[c.GetFieldName()]%></a><br><%}%><b>Immediate post changes:</b> <a><%=c.IsPostChanges()%></a><br><%}%><b>Type:</b> <a><%=c.GetUIType()%></a> <br><b>Input:</b> <a><%=c.GetInputName()%></a><br><b>Object Selector:</b> <a><%=os+".GetControls()[\'"+control+"\']"%></a><br><b>DOM Selector:</b> <a>$("<%=$cds.selector%>")</a><br><%if(c.GetMethodName()){%><b>Method:</b> <a><%=c.GetMethodName()%></a><br><%}%><%if(c.GetPMPropSet()&&c.GetPMPropSet().propArrayLen > 0){%><b>User Props (<%=Object.keys(c.GetPMPropSet().propArray).length%>):</b><br><ul><%for(p in c.GetPMPropSet().propArray){%><%if("string"===typeof c.GetPMPropSet().propArray[p]){%><li><a><%=p%></a>=<a><%=c.GetPMPropSet().propArray[p]%> </a></li><%}%><%}%></ul><%}%><%if(c.GetMethodPropSet()&&c.GetMethodPropSet().propArrayLen > 0){%><b>Method PS (<%=Object.keys(c.GetMethodPropSet().propArray).length%>):</b><ul><%for(p in c.GetMethodPropSet().propArray){%><%if("string"===typeof c.GetMethodPropSet().propArray[p]){%><li><a><%=p%></a>=<a><%=c.GetMethodPropSet().propArray[p]%> </a></li><%}%><%}%></ul><%}%><hr></ul></li><%}%></ul><hr></ul><ul id="fields" style="display:none"><hr><b>BusComp:</b> <%=bc.GetName()%><br/><b>Commit pending:</b> <%=bc.commitPending%><br/><b>Fields:</b> <%=Object.keys(bc.GetFieldList()).length%><br/><b>Row:</b> <%=bc.GetCurRowNum()==-1?0:bc.GetCurRowNum()%> of <%=bc.GetNumRows()%><%=bc.IsNumRowsKnown()?"":"+"%><br/><ul><%for(var f in r){%><li><a><%=f%></a>=<a><%=r[f]%></a></li><%}%></ul><hr></ul></li><%}%></ul></div>';function AV(){var html=new EJS({text:tmp}).render(SiebelApp.S_App);$d=$(html).dialog({modal:!0,width:1024,open:function(){$(this).find("li").find("ul[id]").hide(),$(this).find("a").click(function(){copy(this)}),$(this).find("a").contextmenu(function(){return $(this).siblings("#"+$(this).attr("data-target")).toggle(),$(this).siblings("ul[id]:not([id='"+$(this).attr("data-target")+"'])").hide(),!1}),$(this).find("button").click(function(){var s=$(this).attr("data-eval");$d.dialog("close"),eval(s)})},close:function(){$(this).dialog("destroy").remove()},buttons:[{text:"Help",click:function(){window.open("http://xapuk.com/index.php?topic=80","_blank")}},{text:"Close (esc)",click:function(){$(this).dialog("close")}}]}),$d.css("padding-left","20px").find("ul").css("padding-left","20px"),$d.find("hr").css("margin","5px"),$d.find("a").hover(function(e){$(this).css({"text-decoration":"mouseenter"==e.type?"underline":"none"})})}function copy(e){var t=$(e).text();$(e).hide().after("<input id='"+id+"i'>"),$d.find("#"+id+"i").val(t).select(),document.execCommand("copy")?($d.find("#"+id+"i").attr("disabled","disabled").css("color","red").val("Copied!"),setTimeout(function(){$d.find("#"+id+"i").remove(),$(e).show()},700)):$d.find("#"+id+"i").blur(function(){$(this).remove(),$d.find("a").show()})}$("#"+id).parent().remove(),"undefined"==typeof SiebelApp?alert("It works only in Siebel OUI session!"):"undefined"==typeof EJS?requirejs(["3rdParty/ejs/ejs_production"],AV,function(){alert("Failed to load EJS")}):AV();};void(0) 
  • You are also free to fork it. Here is a source code: Snippet
/* 
@desc advanced AboutView plugin
@author VB(xapuk.com)
@version 1.3 2018/07/10
*/

var id = "SiebelAboutView";

// template
var $d;
var tmp = ''+
'<div title="About View" id = "<%= id%>">'+
  '<% var v = SiebelApp.S_App.GetActiveView() %>'+
  '<b>Application:</b> <a><%= SiebelApp.S_App.GetName() %></a><br>'+
  '<b>View:</b> <a><%= v.GetName() %></a><br>'+
  '<b>BusObject:</b> <a><%= SiebelApp.S_App.GetActiveBusObj().GetName() %></a><br>'+
  '<% if(v.GetActiveTask()) { %>'+
    '<b>Task:</b> <a><%= v.GetActiveTask() %></a><br>'+
  '<% } %>'+
  '<b>Applets(<%= Object.keys(v.GetAppletMap()).length %>) / BusComps(<%= Object.keys(SiebelApp.S_App.GetActiveBusObj().GetBCMap()).length %>):</b><br>'+
  '<ul style="padding-left:20px">'+
    '<% for(applet in v.GetAppletMap()) { var a = v.GetAppletMap()[applet]; var bc = a.GetBusComp(); var r = bc.GetSelection() < bc.GetRecordSet().length?bc.GetRecordSet()[bc.GetSelection()]:{}; var os = "SiebelApp.S_App.GetActiveView().GetAppletMap()[\'" + applet + "\']"; var $ds = $("#" + a.GetFullId()); %>'+
      '<li>'+
        '<a data-target="controls"><b style="<% if($ds.is(":hidden")){ %>font-style:italic;<% } if(a===v.GetActiveApplet()){ %>text-decoration:underline<% } %>"><%= applet %></b></a> / '+ 
        '<a data-target="fields"><b><%= bc.GetName() %></b></a>'+
        '<ul id="controls" style="display:none">'+
          '<hr>'+
          '<b>Applet:</b> <a><%= a.GetName() %></a><br/>'+
          '<b>BusComp:</b> <a><%= bc.GetName() %></a><br/>'+
          '<b>Mode:</b> <a><%= a.GetMode() %></a><br/>'+
          '<b>Title:</b> <a><%= a.GetAppletLabel() %></a><br/>'+
          '<% if(a.GetToggleApplet()){ %>'+
            '<b>Toggle:</b> <a><%= a.GetToggleApplet() %></a><br/>'+
          '<% } %>'+
          '<b>Object Selector:</b> <a><%= os %></a><br>'+
          '<b>DOM Selector:</b> <a>$(\"<%= $ds.selector %>\")</a><br>'+
          '<b>Controls (<%= Object.keys(a.GetControls()).length %>): </b>'+
          '<ul>'+
          '<% for(control in a.GetControls()) { var c = a.GetControls()[control]; var $cds = $ds.find("[name=\'" + c.GetInputName() + "\']") %>'+
            '<li>'+
              '<a data-target="control"><b style="<% if($cds.is(":hidden")){ %>font-style:italic;<% } if(c===a.GetActiveControl()){ %>text-decoration:underline<% } %>"><%= c.GetDisplayName()||control %></b></a>'+
              '<ul id="control">'+
                '<hr>'+
                '<% if($cds.is(":visible") && $cds.is(":focusable")){ %>'+
                  '<button data-eval="$(\'<%= $cds.selector %>\').focus()">Focus</button><br>'+
                '<% } %>'+
                '<b>Control:</b> <a><%= control %></a><br>'+
                '<% if(c.GetFieldName()){ %>'+
                  '<b>Field:</b> <a><%= c.GetFieldName() %></a><br>'+
                  '<% if(r){ %>'+
                    '<b>Value:</b> <a><%= r[c.GetFieldName()] %></a><br>'+
                  '<% } %>'+
                  '<b>Immediate post changes:</b> <a><%= c.IsPostChanges() %></a><br>'+
                '<% } %>'+
                '<b>Type:</b> <a><%= c.GetUIType() %></a> <br>'+ // to decode value trhough SiebelJS.Dependency("SiebelApp.Constants");
                '<b>Input:</b> <a><%= c.GetInputName() %></a><br>'+
                '<b>Object Selector:</b> <a><%= os+".GetControls()[\'" + control + "\']" %></a><br>'+
                '<b>DOM Selector:</b> <a>$(\"<%= $cds.selector %>\")</a><br>'+
                '<% if(c.GetMethodName()){ %>'+
                  '<b>Method:</b> <a><%= c.GetMethodName() %></a><br>'+
                '<% } %>'+
                '<% if(c.GetPMPropSet() && c.GetPMPropSet().propArrayLen > 0){ %>'+
                  '<b>User Props (<%= Object.keys(c.GetPMPropSet().propArray).length %>):</b><br>'+
                  '<ul>'+
                    '<% for(p in c.GetPMPropSet().propArray){ %>'+
                      '<% if("string" === typeof c.GetPMPropSet().propArray[p]){ %>'+
                        '<li><a><%= p %></a> = <a><%= c.GetPMPropSet().propArray[p] %> </a></li>'+
                      '<% } %>'+
                    '<% } %>'+
                  '</ul>'+
                '<% } %>'+
                '<% if(c.GetMethodPropSet() && c.GetMethodPropSet().propArrayLen > 0){ %>'+
                  '<b>Method PS (<%= Object.keys(c.GetMethodPropSet().propArray).length %>):</b>'+
                    '<ul>'+
                      '<% for(p in c.GetMethodPropSet().propArray){ %>'+
                        '<% if("string" === typeof c.GetMethodPropSet().propArray[p]){ %>'+
                          '<li><a><%= p %></a> = <a><%= c.GetMethodPropSet().propArray[p] %> </a></li>'+
                        '<% } %>'+
                      '<% } %>'+
                    '</ul>'+
                  '<% } %>'+
                '<hr>'+
              '</ul>'+
            '</li>'+
          '<% } %>'+
          '</ul>'+
          '<hr>'+
        '</ul>'+
        '<ul id="fields" style="display:none">'+
          '<hr>'+
          '<b>BusComp:</b> <%= bc.GetName() %><br/>'+
          '<% if(r && r.hasOwnProperty("Id")){ %>'+
            '<b>Row Id:</b> <a><%= r.Id %></a><br/>'+
          '<% } %>'+
          '<% if(r && r.hasOwnProperty("Created")){ %>'+
            '<b>Created:</b> <a><%= r.Created %></a><br/>'+
          '<% } %>'+
          '<% if(r && r.hasOwnProperty("Updated")){ %>'+
            '<b>Updated:</b> <a><%= r.Updated %></a><br/>'+
          '<% } %>'+
          '<b>Commit pending:</b> <%= bc.commitPending %><br/>'+
          '<b>Fields:</b> <%= Object.keys(bc.GetFieldList()).length %><br/>'+
          '<b>Row:</b> <%= bc.GetCurRowNum()==-1?0:bc.GetCurRowNum() %> of <%= bc.GetNumRows() %><%= bc.IsNumRowsKnown()?"":"+" %><br/>'+
          '<ul>'+
            '<% for(var f in r){ %>'+
              '<li><a><%= f %></a> = <a><%= r[f] %></a></li>'+
            '<% } %>'+
          '</ul>'+
          '<hr>'+
        '</ul>'+
      '</li>'+
    '<% } %>'+
'</ul>'+
'</div>';

// to support single session
$("#" + id).parent().remove();

// show the dialog
function SiebelAboutView(){

    var html = new EJS({text: tmp}).render(SiebelApp.S_App);

    $d = $(html).dialog({
        modal: true,
        width: "1024",
        open:function(){
            // hide all expandable ULs by default
            $(this).find("li").find("ul[id]").hide();
            // attempt to copy span content (click)
            $(this).find("a").click(function(){
                copy(this);
            });
            // expand (right click)
            $(this).find("a").contextmenu(function(){
                $(this).siblings("#"+$(this).attr("data-target")).toggle();
                $(this).siblings("ul[id]:not([id='"+$(this).attr("data-target")+"'])").hide();
                return false;
            });
            // focus on control
			$(this).find("button").click(function(){
				var str = $(this).attr("data-eval");
				$d.dialog('close');
				eval(str);
			});
        },
        close: function(){
            $(this).dialog('destroy').remove();
        },
        buttons: [
            {
               text:'Help',
               click: function(){
                   window.open("http://xapuk.com/index.php?topic=80", "_blank");
               }
            },
            {
               text:'Copy (left click)',
               disabled: true
            },
            {
               text:'Expand (right click)',
               disabled: true
            },
            {
               text:'Close (esc)',
               click: function() {
				 $(this).dialog('close');
               }
            }
        ]
    });
	
	// styling
	$d.css("padding-left","20px");
	$d.find("ul").css("padding-left","20px");
	$d.find("hr").css("margin","5px");
	$d.find("a").hover(function(e){
		$(this).css({"text-decoration":e.type=="mouseenter"?"underline":"none"});
	});
}

// copy value
function copy(scope){
	// replacing link with intput and select the value
	var val = $(scope).text();
    $(scope).hide().after("<input id='" + id + "i'>");
    $d.find("#" + id + "i").val(val).select();
    // attempt to copy value
    if (document.execCommand("copy", false, null)){
    	// if copied, display a message for a second
        $d.find("#" + id + "i").attr("disabled", "disabled").css("color","red").val("Copied!");
        setTimeout(function(){
        	$d.find("#" + id + "i").remove();
        	$(scope).show();
        }, 700);
    }else{
    	// if failed to copy, leave input until blur, so it can be copied manually
		$d.find("#" + id + "i").blur(function(){
			$(this).remove();
			$d.find("a").show();
		});    	
    }
}

if ("undefined" === typeof SiebelApp || "undefined" === typeof SiebelApp.S_App){
	alert("Please launch Siebel application first.");
}else if ("undefined" === typeof EJS){
	var src = "3rdParty/ejs/ejs_production";
	requirejs([src], SiebelAboutView, function(){alert("Failed to load EJS library ! \n" + src);});
}else{
	SiebelAboutView();
}
  

Quick tips
  • All values can be copied with a mouse click.
  • Values in bold can be expanded with right click.
  • Underlined style indicates active items.
  • Italic style indicates hidden items.
  • Unlike the original About View (server side) it works with popup applets and in expired session.

A new version is available here.

Since OpenUI release, browser console became a powerful tool in hands of confident Siebel developer. In this topic I'll give you an idea how to organise your browser code snippets and will share couple of examples how to take an advantage of SiebelApp object.


Browser console


Traditional way of injecting browser code.

How to run: F12 => Console tab => type the command or use up key to flip through history => enter


SiebelApp.S_App.GetActiveView().GetActiveApplet().GetName();

Chrome code snippets


Useful if you need to store more than oneliners.

How to run: F12 => Source tab => Snippets => right click => run

Here is an example why you might need it.


console.log(SiebelApp.S_App.GetActiveView().GetName());
var am = SiebelApp.S_App.GetActiveView().GetAppletMap();
for (sAppletName in am) {
  console.log('\t' + sAppletName + '(' + am[sAppletName].GetBusComp().GetName() + ')');
}

Bookmarklets


Easiest way to run a code snippet. It is not only takes one click to run your code but it also allows 'endless' features (fancy UI, working with clipboard, history of queries). I see bookmarklets as an open source, cross-browser, cross-environment Siebel plugin. If you manage to use Chrome code snippets to build and debug snippets and then compile them into bookmarklets.

I usually use Chrome snippets as a source code vault and as GUI to build and debug my code. Once the code is stable, I make it a bookmarklet and enjoy it.

How to create: Linearise your JS code, remove comments or simply minify it (for example, JSCompress or JS/CSS Minifier, thanks Emma!), escape quotes and finally wrap it with "javascript:{...};void(0)". Here is how the code from above example will look like as a bookmarklet:


javascript:{var s=SiebelApp.S_App.GetActiveView().GetName();var am=SiebelApp.S_App.GetActiveView().GetAppletMap();for(sAppletName in am){s+='\n\t'+sAppletName+'('+am[sAppletName].GetBusComp().GetName()+')';}alert(s);};void(0)

You can always use online bookmarklet converters. Here are couple examples:

How to install: Easiest way is to drag & drop a link on your favourites toolbar. I'm a bookmarklet Drag & Drop me. Here is a full article on how to install bookmarklets for different browsers.

How to run: Click

Check out how powerful and convenient bookmarklets could be:

/* 
@desc fancy UI wrapper for GetProfileAttr Siebel function
@author VB(xapuk.com)
@version 1.1 2018/06/08
*/
if ("undefined" == typeof SiebelApp) {
    alert("It works only in Siebel OUI session!");
}

// snippet id
var id = "SiebelProfileAttr";

// localStorage to store the history
var aHist = window.localStorage[id] ? JSON.parse(window.localStorage[id]) : [];

// just in case (experimental)
$("#" + id).parent().remove();

// constructing dialog content
var s = '<div title="Get Profile Attribute">';
s += '<input id = "' + id + '" type="text" list="' + id + 'List" style="width:100%" value="' + (aHist.length ? aHist[0] : "") + '">';
s += '<datalist id="' + id + 'List">';
for (var i = 0; i < aHist.length; i++){
    s += '<option>' + aHist[i] + '</option>';
}
s += '</datalist>';
s += '<input id="' + id + 'Out" type ="text" style="display:none">';
s += '<ul></ul></div>';

// open dialog
var $d = $(s).dialog({
    modal: true,
    width: 640,
    open: function() {
        $('#' + id).focus().select(); // autofocus
    },
    close: function() {
        $(this).dialog('destroy').remove();
    },
    buttons: [{
        text: 'Get (Enter)',
        click: go
    }, {
        text: 'Close (Esc)',
        click: function() {
            $(this).dialog('close');
        }
    }]
});

listHistory();

function go() {
    var name = $d.find('#' + id).val();
    if (name) {
        // moving recent query to the top
        if (aHist.indexOf(name) > -1) {
            aHist.splice(aHist.indexOf(name), 1);
        }
        aHist.unshift(name);
        window.localStorage[id] = JSON.stringify(aHist);

        //rerender history
        listHistory();
    }
    return name;
}

// print a list of recent queries
function listHistory() {
    var $ul = $d.find("ul").empty();
    for (var i = 0; i < aHist.length && i < 5; i++) {
        // five recent values
        $ul.append('<li><b>' + aHist[i] + '</b> = <a href="#">' + SiebelApp.S_App.GetProfileAttr(aHist[i]) + '</a></li>');
    }
    // copy value on click
    $d.find("a").click(function(event) {
        var val = $(this).html();
        $("#" + id + "Out").show().val(val).select();
        var r = document.execCommand("copy");
        $("#" + id + "Out").hide();
        if(r){
            $(this).hide().after('<span id="tmp" style="color:red">Copied!</span>');
            setTimeout(function(){
                $d.find("a").show();
                $d.find("#tmp").remove();
            }, 500);
        }
    });
}

// key bindings
$d.keyup(function(event) {
    // enter
    if (event.keyCode === 13) {
        go();
    }
});
/* 
@desc fancy wrapper for GotoView Siebel function
@author VB(xapuk.com)
@version 1.0 12/06/2018
*/
if ("undefined" == typeof SiebelApp){
    alert("It works only in Siebel OUI session!");
}

// snippet id
var id = "SiebelGotoView";

// localStorage to store the history
var aHist = window.localStorage[id]?JSON.parse(window.localStorage[id]):[];

// just in case (experimental)
$("#" + id).parent().remove();

// constructing dialog content
var s = '<div title="Goto View">';
s += '<input id = "' + id + '" type="text" list="' + id + 'List" style="width:100%" value="' + (aHist.length?aHist[0]:"") + '">'; // most recent
s += '<datalist id="' + id + 'List">';
for (var i =0; i < aHist.length; i++){ // full history into unbounded picklist
    s += '<option>' + aHist[i] + '</option>';
}
s += '</datalist><ul>';
for (var i =0; i < aHist.length && i < 5; i++){ // five recent values as links
    s += '<li><a href="#">' + aHist[i] + '</a></li>';
}
s += '</ul></div>';

// open dialog
var $d = $(s).dialog({
    modal: true,
    width: 640,
    open: function() {
        $('#' + id).focus().select(); // autofocus
    },
    close: function() {
        $(this).dialog('destroy').remove();
    },
    buttons: [{
        text: 'Go (Enter)',
        click: function(){
            go($d.find('#' + id).val());
        }
    }, {
        text: 'Close (Esc)',
        click: function() {
            $(this).dialog('close');
        }
    }]
});

// GotoView
function go(name) {
    if (name){
        // moving recent view to the top
        if (aHist.indexOf(name) > -1){
           aHist.splice(aHist.indexOf(name),1);
        }
        aHist.unshift(name);
        window.localStorage[id] = JSON.stringify(aHist); 
        $d.dialog('close');
        SiebelApp.S_App.GotoView(name); //running GotoView command
    }
}

// running GotoView on Enter
$d.keyup(function(event) {
    // enter
    if (event.keyCode === 13) { 
        go($d.find('#' + id).val());
    }
});

// running GotoView on link click
$d.find("a").click(function(event) {
    go($(this).html());
});
Stay tuned - best snippets are yet to come :)

Copy below script in browser console (F12) and run it once. It will keep Siebel client alive during the day.


function keepAlive(iHour, iNum)
{
	var iStep = 60; // will send the request every minnute
	iNum = iNum>0?iNum:0;

	if (iHour*60*60 > iNum*iStep){
		setTimeout(function(){
			if (typeof(SiebelApp.S_App.GetProfileAttr("ActiveViewName")) != "undefined"){
				SiebelJS.Log("keep alive / " + iNum + " / " + (new Date()));
				keepAlive(iHour, ++iNum);
			}
		}, iStep * 1000);
	}
}
keepAlive(8); // 8 = number of hours you want Siebel to live

It is helpful when you are working with Siebel client all day long and you don't want to re-login after a short pause. Very handy during Siebel frontend development.


Updates

A fancy version with a pulsing indicator and on / off toggle.

  • Bookmarklet link: About View
  • Bookmarklet source: Snippet
  • javascript:{function keepAlive(e,i){i=0<i?i:0,console&&console.log("keep alive / "+i+" / "+new Date),60*i<60*e*60?(0===$("#SiebelKeepAlive").length?$("body").append("<div id='SiebelKeepAlive' style='position:fixed;top:5px;left:5px;background-color:#ff5e00;border:solid 2px;border-radius:5px;padding:5px'><b>KA</b></div>"):$("#SiebelKeepAlive").fadeTo(100,1),$("#SiebelKeepAlive").fadeTo(54e3,.2),window.timerId=setTimeout(function(){void 0!==SiebelApp.S_App.GetProfileAttr("ActiveViewName")&&keepAlive(e,++i)},6e4)):keepAlive_stop()}function keepAlive_stop(){clearTimeout(window.timerId),delete window.timerId,$("#SiebelKeepAlive").remove(),console.log("keep alive time stopped")}"undefined"==typeof SiebelApp?alert("It works only in Siebel OUI session!"):void 0===window.timerId?keepAlive(4):keepAlive_stop();};void(0) 
  • Source code: Snippet
/* 
@desc Keeps Siebel session alive for a certain amount of time
@author VB(xapuk.com)
@version 2.0 2018/07/20
*/


if ("undefined" == typeof SiebelApp){
    alert("It works only in Siebel OUI session!");
}else{
	if ("undefined" === typeof window.timerId){
		keepAlive(4); // number of hours you want Siebel to live
	}else{
        keepAlive_stop();
	}
}

function keepAlive(iHour, iNum)
{
	var iStep = 60; // frequency in secs
	iNum = iNum>0?iNum:0;
	if (console) console.log("keep alive / " + iNum + " / " + (new Date()));
	if (iHour*60*60 > iNum*iStep){
	    if($("#SiebelKeepAlive").length === 0){
	        $("body").append("<div id='SiebelKeepAlive' style='position:fixed;top:5px;left:5px;background-color:#ff5e00;border:solid 2px;border-radius:5px;padding:5px'><b>KA</b></div>");
	    }else{
	        $("#SiebelKeepAlive").fadeTo(100, 1);
	    }
	    $("#SiebelKeepAlive").fadeTo(iStep * 900, 0.2);
		window.timerId = setTimeout(function(){
			if (typeof(SiebelApp.S_App.GetProfileAttr("ActiveViewName")) != "undefined"){
				keepAlive(iHour, ++iNum);
			}
		}, iStep * 1000);
	}else{
		keepAlive_stop();
	}
}

function keepAlive_stop(){
    clearTimeout(window.timerId);
    delete window.timerId;
    $("#SiebelKeepAlive").remove();
    console.log("keep alive time stopped");
}