Fancy code editor for Client-side Business Service

Here I want to share the way you can prettify Siebel built-in code editor and make Client-side Business Service development process a bit more pleasant.

Regarding to to my choice of online code editor. After a quick loop through "top 5 editors", I've picked AceJS - mostly because I had a recent experience working with it.


1. Download AceJS

After you download lib (https://github.com/ajaxorg/ace-builds/), place the content of "src-min-noconflict" subfolder in "\PUBLIC\enu\23048\SCRIPTS\3rdParty\ace\".


2. Create PM/PR files

Create Presentation Model and Physical Renderer files:

siebel/custom/CSBS_PM.js


if (typeof (SiebelAppFacade.CSBS_PM) === "undefined") {
	SiebelJS.Namespace("SiebelAppFacade.CSBS_PM");
	define("siebel/custom/CSBS_PM", ["siebel/pmodel"],
		function () {
			SiebelAppFacade.CSBS_PM = (function () {
				
				function CSBS_PM(pm) {
					SiebelAppFacade.CSBS_PM.superclass.constructor.apply(this, arguments);
				}
				
				SiebelJS.Extend(CSBS_PM, SiebelAppFacade.PresentationModel);

				CSBS_PM.prototype.Init = function () {
					SiebelAppFacade.CSBS_PM.superclass.Init.apply(this, arguments);
				}
				
				CSBS_PM.prototype.Setup = function (propSet) {
					SiebelAppFacade.CSBS_PM.superclass.Setup.apply(this, arguments);

					this.AddProperty("ScriptValue", ""); // property to pass field value PM->PR
					bc = this.Get("GetBusComp");
					var sField = "Script"; // hardcoded field name to attach ace plugin
					this.AddProperty("ScriptFieldName", sField);

					// update ace editor value everytime script field value changes
					this.AddMethod("GetFormattedFieldValue", function (control) {
						if (control.GetFieldName() == sField && bc.GetFieldValue(sField) != this.Get("ScriptValue")) {
							this.SetProperty("ScriptValue", bc.GetFieldValue(sField));
						}
					}, {
						sequence: false,
						scope: this
					});
				}
				
				return CSBS_PM;
				
			}());
			return "SiebelAppFacade.CSBS_PM";
		})
}

siebel/custom/CSBS_PR.js


if (typeof (SiebelAppFacade.CSBS_PR) === "undefined") {
	SiebelJS.Namespace("SiebelAppFacade.CSBS_PR");
	define("siebel/custom/CSBS_PR", ["3rdParty/ace/ace", // determines dependencies (path to ace.js file)
									 "siebel/phyrenderer"],
		function () {
			SiebelAppFacade.CSBS_PR = (function () {

				function CSBS_PR(pm) {
					SiebelAppFacade.CSBS_PR.superclass.constructor.apply(this, arguments);
				}

				SiebelJS.Extend(CSBS_PR, SiebelAppFacade.PhysicalRenderer);

				CSBS_PR.prototype.Init = function () {
					SiebelAppFacade.CSBS_PR.superclass.Init.apply(this, arguments);
				}

				CSBS_PR.prototype.ShowUI = function () {
					SiebelAppFacade.CSBS_PR.superclass.ShowUI.apply(this, arguments);

					var pm = this.GetPM(); // to use in global scope functions
					var bc = pm.Get("GetBusComp");
					var sField = pm.Get("ScriptFieldName");

					// get original control
					var oOrig = $("textarea[name='" + pm.Get("GetControls")[sField].GetInputName() + "']");

					// add control for ace editor
					var sNewId = "ace_code_editor";
					SiebelJS.Log($(oOrig).parent().after('<div id="' + sNewId + '"></div>'));
					var oNew = $("#" + sNewId);

					// attach ace editor
					var oAce = ace.edit(sNewId);
					oAce.setTheme("ace/theme/monokai");
					oAce.getSession().setMode("ace/mode/javascript");
					oAce.$blockScrolling = Infinity;

					// to be replaced with css file
					oNew.css("height", oOrig.height() + "px"); // copy control height 
					oOrig.remove(); // remove orig control
					$("#s_" + pm.Get("GetFullId") + "_div").find(".mceLabel").remove(); // remove labels

					// copy value from ace editor into the field
					oAce.getSession().on('change', function () {
						bc.SetFieldValue(sField, oAce.getValue());
					});

					// copy field value to ace editor
					this.AttachPMBinding("ScriptValue", function () {
						field_value = pm.Get("ScriptValue");
						if (field_value != oAce.getValue()) {
							oAce.setValue(field_value);
							oAce.gotoLine(1); // first line by default
						}
					});
				}

				CSBS_PR.prototype.BindEvents = function () {
					SiebelAppFacade.CSBS_PR.superclass.BindEvents.apply(this, arguments);
				}

				CSBS_PR.prototype.BindData = function () {
					SiebelAppFacade.CSBS_PR.superclass.BindData.apply(this, arguments);
				}

				return CSBS_PR;
			}());
			return "SiebelAppFacade.CSBS_PR";
		})
}

3. Manifest administration

Don't forget to attach PM/PR files to applet (Business Service Script Editor Applet2) on Application -> Manifest Administration view.


What's next ...

Optimise a view layout (custom .SWT?).

Maybe attach a custom CSS to prettify a view.

Put BS simulator applets on the same page and pre-default BS Name there.

Enjoy your runtime playground!