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:
As I mentioned it is relatively fresh, so stay tuned for further upgrades and I'll greatly appreciate all feedback.
Recent version:
(() => {
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, "'");
}
})()
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
I used Caio's tool to convert source code into a bookmarklet.
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).
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.
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.
I've advanced the initial version of Inspect Workspace UI with quite a few features, so check out my latest implementation below.
Features:
One of the reasons this approach is so quick, is because it doesn't clear all cache every time. So, remember to clear the cache separately if required. For example, if you created a new view in the workspace, clear the responsibility cache after inspecting it.
Be careful when re-inspecting a workspace from the same view where changes are, it might crash the application. It helps if you step out of the test view before re-inspecting.
Source code (v1.5):
/*
@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>"));
}
})();
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()}})})();
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.
/*
@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!");
}
}
}
}
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())})}
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.
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())})}
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:
/*
@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());
}
});
}
}
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())}})}}();
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:
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.
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.
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.
/*
@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;
}
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()}}}();
Here is a new version with a built-in beautifier from another topic:
/*
@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;
}
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()})}}}();
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.
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:
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.
Don't have time building your own playground? Try mine, it is free and has some advanced features you might enjoy:
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:
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)
/*
@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();
}
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.
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();
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() + ')');
}
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());
});
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.
A fancy version with a pulsing indicator and on / off toggle.
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)
/*
@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");
}