Create custom editors

An editor is a special Dojo container widget that contains the logic to open a task in the application. The editor contains some UI components, which provide consistent appearance for similar tasks. For example, order modification tasks.

To create custom editors, the following JavaScript files must be present that contains the JavaScript screen definition.
  • <Editor Name.js> - The JS file corresponding to the editor. You can define all your behavior logic in this file.
  • templates/<Editor name>.html - The HTML file that contains all the UI information.
  • <Editor name>BehaviorController.js - The JS file that contains the mashuprefs details that are called on some action or behavior on the editor.
  • <Editor name>InitController.js - The JS file that contains the mashuprefs details that are called when you start the editor.

In addition to JavaScript files, ensure that the <Editor name>BehaviorController.xml and <Editor name>InitController.xml Controller XML files are also present.

For more information about creating the <Editor name>BehaviorController.js, <Editor name>InitController.js, <Editor name>BehaviorController.xml, and <Editor name>InitController.xml, see Customize controllers.

For custom editors, the following events are raised by a wizard or screen.
  • setScreenTitle - This event is raised to set the title and subtitle on the Editor Title panel. For example, in the Create Order wizard, the title is Create Order and subtitle is Customer Search, which is the first screen in the wizard page.
  • setEditorInput - This event is raised to update the editor input, which is used for opening a wizard or screen in the existing editor. For example, in the create order wizard, on selecting a customer, the setEditorInput event is raised by the Customer identification page to update the customer information in the editor input.

Create the <Editor name>.js file

Ensure that the <Editor name>.js file syntax adheres to Dojo version 1.8 standards. The custom editor must extend sc/plat/dojo/widgets/Editor. Additionally, you can use the following application-provided standards:

  • You can use scDefine instead of define.
  • You can precede the imported JavaScript modules with scbase/loader! string. The scbase/loader string is a Dojo loader plug-in that is provided by the application. Precede an html file path with a dojo/text! string according to the Dojo syntax.

Sample MyOrderEditor.js file

scDefine(["dojo/text!./templates/MyOrderEditor.html", 
"scbase/loader!dojo/_base/declare", 
"scbase/loader!idx/layout/ContentPane", 
"scbase/loader!sc/plat", 
 "scbase/loader!sc/plat/dojo/binding/CurrencyDataBinder", 
 "scbase/loader!sc/plat/dojo/binding/ImageDataBinder", 
 "scbase/loader!sc/plat/dojo/layout/AdvancedTableLayout", 
 "scbase/loader!sc/plat/dojo/widgets/Editor",
 "scbase/loader!sc/plat/dojo/widgets/Image", 
 "scbase/loader!sc/plat/dojo/widgets/Label", 
 "scbase/loader!sc/plat/dojo/widgets/Link"], function(
templateText, _dojodeclare,  _idxContentPane, _scplat, _scCurrencyDataBinder, _scImageDataBinder, _scAdvancedTableLayout,  
 _scEditor,  _scImage, _scLabel, _scLink) {
    return _dojodeclare("extn.editors.MyOrderEditor", [_scEditor], {
        templateString: templateText,
        uId: "MyOrderEditor",
        packageName: "extn.editors",
        className: "MyOrderEditor",
        namespaces: {
            targetBindingNamespaces: [],
            sourceBindingNamespaces: [{
                description: 'Holds the initial editor input passed into the editor on open.',
                value: 'InitialEditorInput'
            }]
        },

// comparisonAttributes are used to create a model object (JSON Object), which is used for 
// comparing two different instances for the editor. If the model object that is created by using 
// comparisonAttributes for two instances of the editor are similar, they are identified as the 
// matching editor. This is mainly used to determine whether the new instance of the editor 
// must be opened in a new tab or focused on the matching editor. 
// This is used when using the sc.plat.dojo.utils.ControllerUtils.openScreenInEditor utility 
	      comparisonAttributes: ["Order.OrderHeaderKey"],    
        hotKeys: [],
        events: [ {
            name: 'setEditorInput'
        }],
        subscribers: {
            local: [ {
                eventId: 'setEditorInput',
                sequence: '25',
                handler: {
                    methodName: "setEditorInput"
                }
            }],
        },
      
        getScreenTitle: function() {

        },

        showOrHideRelTask: function(
        event, bEvent, ctrl, args) {
            var isWizardinitialized = null;
            var isRTscreeninitialized = null;
            isWizardinitialized = _scBaseUtils.getAttributeValue("isWizardinitialized", false, args);
            isRTscreeninitialized = _scBaseUtils.getAttributeValue("isRTscreeninitialized", false, args);
            if (!(
            _scBaseUtils.isVoid(
            isRTscreeninitialized))) {
                this.isRTscreeninitialized = isRTscreeninitialized;
            }
            if (!(
            _scBaseUtils.isVoid(
            isWizardinitialized))) {
                this.isWizardinitialized = isWizardinitialized;
            }
            if (!(
            _isccsWidgetUtils.isWizardInstance(
            _scEditorUtils.getScreenInstance(
            this)))) {
                _isccsBaseTemplateUtils.hideRelatedTask(
                this);
            } else {
                if (
                _scBaseUtils.and(
                _scBaseUtils.equals(
                this.isWizardinitialized, "true"), _scBaseUtils.equals(
                this.isRTscreeninitialized, "true"))) {
                    _isccsBaseTemplateUtils.hideRelatedTask(
                    this);
                }
            }
        },

        updateScreenWithEditorInput: function(
			model) {

        },
        onScreenInit: function(
			event, bEvent, ctrl, args) {

        },
        setInitialEditorInput: function(
			screenInput) {

        },
        setScreenTitle: function(
			event, bEvent, ctrl, args) {

        },
        setEditorInput: function(
			event, bEvent, ctrl, args) {
		}
    });
});

Create the templates/<Editor name>.html file

The templates/<Editor name>.html file renders the UI for an editor. It contains all the widgets present in the editor and adheres to Dojo 1.8 syntax. It is used for creating widgets declaratively by using an HTML file.

Sample MyOrderEditor.html file

<div class="sc-platform-screen-default myordereditor">

	<div data-dojo-type="idx/layout/ContentPane" data-dojo-props="spanLabel : true , 
		'class' : 'screenTitleContainer', 
		uId : 'titleMessagePanel'  
		">
		<div data-dojo-type="idx/layout/ContentPane" data-dojo-props="	 spanLabel : true , 
			'class' : 'screenTitlePanel' , 
			uId : 'pnlTitleBar'  
			">
			<div data-dojo-type="sc/plat/dojo/layout/AdvancedTableLayout" data-dojo-props=" showLabels : false , 
				cols : 2 , 
				customClass : 'screenTitleTableContainer'  
				">
				<div data-dojo-type="sc/plat/dojo/widgets/Image" data-dojo-props="	'class' : 'icon-screen-order screenTitleImage' , 
					uId : 'lb_titleImage'  
					"></div>
				<div data-dojo-type="idx/layout/ContentPane" data-dojo-props="	 spanLabel : true , 
					uId : 'pnlTitleContainer'  
					">
					<div data-dojo-type="sc/plat/dojo/widgets/Label" data-dojo-props="	spanLabel : true , 
						'class' : 'screenTitle' , 
						uId : 'lb_screenTitle'  
						"></div>
					<div data-dojo-type="sc/plat/dojo/widgets/Label" data-dojo-props="	spanLabel : true , 
						'class' : 'screenSubTitle' , 
						uId : 'lb_screenSubTitle'  
						,scParamDataFn :
						function() { 
						return { 
						title : this.getSimpleBundleString('blank')
						,	
						value : this.getSimpleBundleString('blank')
						}
						}
						"></div>
				</div>
			</div>
		</div>

		<div data-dojo-type="idx/layout/ContentPane" data-dojo-props="	'class' : 'enterpriseHolder' , 
			uId : 'pnlEnterpriseHolder' , 
			'aria-label' : 'Current Enterprise'  
			" role='region'>
			<div data-dojo-type="sc/plat/dojo/widgets/Image" data-dojo-props="	'class' : 'icon-enterprise' , 
				uId : 'imgEnterprise'  
				"></div>
			<div data-dojo-type="sc/plat/dojo/widgets/Label" data-dojo-props="	'class' : 'icon-image-label groupHeader' , 
				uId : 'lblEnterprise'  
				,scParamDataFn :
				function() { 
				return { 
				bindingData : 	{
				sourceBinding : 	{
				path : 'Order.EnterpriseName'
				,
				namespace : 'enterpriseContext'
				}
				}
				}
				}
				"></div>
		</div>
	</div>
	<div data-dojo-type="idx/layout/ContentPane" data-dojo-props="	 spanLabel : true , 
		'class' : 'csrMessagePanel' , 
		uId : 'customerMessagePanel'  
		" role='alert'>
		<div data-dojo-type="idx/layout/ContentPane" data-dojo-props="	 spanLabel : true , 
			'class' : 'customerMessageBox' , 
			uId : 'lb_customerMessageBox' , 
			renderHidden : true  
			">
			<div data-dojo-type="sc/plat/dojo/widgets/Image" data-dojo-props="	'class' : 'customer-message' , 
				uId : 'imgCustomer'  
				,scParamDataFn :
				function() { 
				return { 
				title :this.getSimpleBundleString('CUST_ImageAlt')
				,	
				imageAlt :this.getSimpleBundleString('CUST_ImageAlt')
				}
				}
				"></div>
			<div data-dojo-type="sc/plat/dojo/widgets/Link" data-dojo-props="imageStyleClass : 'idxMessageCloseIcon' , 
				hasImage : true , 
				'class' : 'idxMessageRightAligned' , 
				uId : 'linkclose'  
				,scParamDataFn :
				function() { 
				return { 
				title : this.getSimpleBundleString('CUST_closeAlt')
				,	
				imageAlt : this.getSimpleBundleString('CUST_closeAlt')
				}
				}
				"></div>
			<div data-dojo-type="idx/layout/ContentPane" data-dojo-props="	 'class' : 'customerMessageText' , 
				uId : 'pnlCustomerMessageText'  
				">
				<div data-dojo-type="sc/plat/dojo/widgets/Label" data-dojo-props="	uId : 'messageDescriptionText'  
					"></div>
			</div>
		</div>
	</div>
	<div data-dojo-type="idx/layout/ContentPane" data-dojo-props=" spanLabel : true , 
		uId : 'systemMessagePanel' , 
		renderHidden : true  
		"></div>
	<div data-dojo-type="idx/layout/ContentPane" data-dojo-props="	 spanLabel : true , 
		'class' : 'editorContent' , 
		uId : 'editorContent'  
		" role='main'>
		<div data-dojo-type="idx/layout/ContentPane" data-dojo-props="	 spanLabel : true , 
			uId : 'scScreenHolder'  
			" role='main'></div>

<!--The following div element is required to embed the Related Task screen -->
<div data-dojo-type="sc/plat/dojo/widgets/ControllerWidget" data-dojo-props="
	uId: 'RelatedTaskScreenHolder',
	packageName: 'wsc.editors',
	className: 'HomeEditorRT',
	handleInit: false,
	'class': 'relatedTaskHolder',
   dynamicLoading: true,
   renderHidden: true,
	 scParamDataFn: function() {
		return {
		}
	}">
</div>

<!--End of code to embed the Related Task screen -->
	</div>
	<div data-dojo-type="idx/layout/ContentPane" data-dojo-props="		spanLabel : true , 
		resourceId : 'WSCFO0TER001' , 
		'class' : 'footer' , 
		uId : 'scFooterHolder'  
		" role='main'>
		<div data-dojo-type="sc/plat/dojo/widgets/Link" data-dojo-props=" uId : 'siteMapLink'  
			,scParamDataFn :
			function() { 
			return { 
			value : this.getSimpleBundleString('SiteMap')
			}
			}
			"></div>
	</div>
</div>

According to the application standard, data-dojo-props contain the scParamDataFn function attribute. This attribute returns a JSON object with any dynamically evaluated values such as label, title, or bindingData for the widget.

Embed the related tasks screen

You can embed the related tasks screen in any of the following ways:
  • If the custom editor does not have a wizard, add the related tasks screen in the editor by following these instructions:
    • Set the value of showRelatedTask attribute to true for the screen that is opened in the custom editor. For more information about the showRelatedTask attribute, see Sample MyOrderScreen.js file.
    • In the screen that is opened in the editor, add a subscriber to the afterScreenLoad event. In the event handler, raise an event for the parent, which is the editor. In the corresponding event handler of the editor, which is based on the value of showRelatedTask attribute, the Related Task screen is created dynamically by calling the showOrHideRelatedTaskScreen method of EditorRelatedTaskUtils.
    • In the Related Task screen, add a subscriber to the afterParentScreenStartup event. In the event handler, raise an event for the parent, which is the editor. In the corresponding event handler of the editor, show the related task by calling the showRelatedTaskScreenHolder method of EditorRelatedTaskUtils. Pass the editor instance as the argument. For example, isccseditorRelatedTaskUtils.showRelatedTaskScreenHolder(this).

    For an application-provided editor, in the event handler of the afterScreenLoad event, raise the showOrHideRelatedTask event from the screen that is opened in the editor. In the Related Task screen, raise the afterRTScreenStartup event in the event handler of the afterParentScreenStartup event.

  • If the custom editor has a wizard, add the related tasks screen in the editor as follows:
    • Set the value of showRelatedTaskInWizard attribute to true in the wizard. For more information about the showRelatedTaskInWizard attribute, see Sample CustomWizard.js file.
    • In the wizard, add a subscriber to the start event. In the event handler, raise an event for the editor as shown in the following sample code.
                  var eventDefn = null;
                  eventDefn = _scBaseUtils.getNewBeanInstance();
                  _scEventUtils.fireEventToParent(this, "showOrHideRelatedTask", eventDefn);
    • In the corresponding event handler of the editor, which is based on the value of showRelatedTaskInWizard attribute, the Related Task screen is created dynamically by calling the showOrHideRelatedTaskScreen method of EditorRelatedTaskUtils.
    • In the Related Task screen, add a subscriber to the afterParentScreenStartup event. In the event handler, raise an event for the parent, which is the editor. In the corresponding event handler of the editor, show the related task by calling the showRelatedTaskScreenHolder method of EditorRelatedTaskUtils. Pass the editor instance as the argument. For example, isccseditorRelatedTaskUtils.showRelatedTaskScreenHolder(this).

    For an application-provided editor, in the event handler of the start event, raise the showOrHideRelatedTask event from the wizard that is opened in the editor. In the Related Task screen, raise the afterRTScreenStartup event in the event handler of the afterParentScreenStartup event.

The procedure to create related tasks screen is same as creating custom screen. Embed the related tasks screen in the corresponding editor HTML file.

After you embed the related tasks screen, you can hide or unhide the related tasks. To hide or unhide related tasks, in the custom screens add a subscriber and handler for the afterScreenLoad event. For example, in the custom screen, the updateEditorHeader event handler contains the updateTitle method that enables to hide or unhide related tasks.

Reuse an editor

To reuse an editor, select the appropriate editor from the <war_dir>/wsc/editors folder, and pass the comparison attributes as input to the editor. For example, in the OrderEditorUI.js file, the Order.OrderHeaderKey is the comparison attribute. Pass OrderHeaderKey as input to the Order editor. For more information about the comparison attribute, see Sample MyOrderEditor.js file.
To determine the list of mashup calls present in an existing editor, do the following steps:
  1. Browse to <INSTALL_DIR>/wsc/editors.
  2. Open the appropriate BehaviorController.js file. For example, to determine the list of mashups applicable for the Item Search editor, open theItemSearchBehaviorController.js file. All the mashups are present under the mashupRefs object.