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!
You never know when you might need a list of NamedSearches Siebel uses internally.
So, I thought to put it here along with some info where I've found it and some tips on how I usually use it. As you might've already guessed the main use of the list is to check you are not using these names with SetNamedSearch method in the production environment.
Name | Description |
---|---|
System Search | BusComp search specification |
Applet Search Spec Named Search | Applet search specification |
VisibilitySearch | View mode |
Link Search Spec Named Search | Link search specification |
PickListSearch | PickList search specification |
Drill Down By Id Named Search | After you drilled down into a view |
Task UI Search Spec Named Search | When using a [Task Step Context] tab in the Task UI steps |
Content Targeting Named Search | Personalization rules |
Sort Search Optimization | Sometimes sort spec performance can be optimised with search spec |
Private Filter Search | From BusComp User Prop = Private Activity Search Spec |
Active Field Flag Search | If you are using active flag property on BusComp |
MVG Type Field Named Search | When using Type field and value filter on MVG |
Bookmark Id Named Search | When you get to the view through a bookmark |
Auxiliary Id Named Search | ? |
Snapshot | ? |
Override Filter Search | ? |
Link Spec Substitute | ? |
This comes handy when using eScript playground. For example, this is how you test an applet search spec without a compilation:
var bo = TheApplication().ActiveBusObject();
var bc = bo.GetBusComp("Account");
bc.SetNamedSearch("Applet Search Spec Named Search", '[Updated] > Today()-10');
bc.ExecuteQuery(ForwardBackward);
And below eScript snippet tells you all filters applied to an active BusComp if you don't feel like reading logs:
var bo = TheApplication().ActiveBusObject();
var bc = bo.GetBusComp("Account");
var aSpecs = [
"System Search",
"Applet Search Spec Named Search",
"VisibilitySearch",
"Link Search Spec Named Search",
"PickListSearch",
"Drill Down By Id Named Search",
"Task UI Search Spec Named Search",
"Content Targeting Named Search",
"Sort Search Optimization",
"Active Field Flag Search",
"MVG Type Field Named Search",
"Auxiliary Id Named Search",
"Snapshot",
"Bookmark Id Named Search"
];
if (bc.GetSearchExpr()) {
log("User Search Spec", bc.GetSearchExpr());
}
for (var i in aSpecs) {
var name = aSpecs[i];
var spec = bc.GetNamedSearch(name);
if (spec) {
log(name, spec);
}
}
Stay tuned and take care, folks!
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