Inside of the aBPM Framework exists a lot of features and functionalities that helps to realize a custom scenario very quickly, but sometimes the end user doesn’t want to click to much confirmation and close buttons to close a task window if the work on a task is completed. Inside of the following blog you will find a solution for the aBPM scenario side implementation to trigger an event into the local storage of the browser where an consumer can listen and close the task tab/window (see prerequisite).

Use case:

The work on an aBPM Task is completed and the task tab/window should be closed automatically. The end user should not click additionally confirmation buttons or tab/window close buttons to close the finished task.

Prerequisite:

Before the aBPM scenario side implementation can be done please visit the following blog:

Tab/window close management (Part 1 – Add an event listener to the aBPM link – provider side implementation)
https://blogs.sap.com/2017/12/06/add-an-event-listener-to-the-abpm-link-ui-element/

 

and build the prerequistes of an custom inbox/provider that open the task tab/window and holds a reference to this browser tab/window. The references should be stored in a map where the task instance id is the identifier of the map to manage the window reference.

The task id will be used later for the event mechanism to inform the custom inbox/provider which one of the tabs/windows should be closed from the map.

Solution:

The realization of this use case starts with the question:

When is an aBPM Task completed?

The answer is very simple when the buttons at the bottom disappear and the task comes into a “readonly” status. The prerequisites for this is that the developers follow the “aBPM Cookbook” and return a SimpleOptionHelper or a SimpleOption with an empty configuration to the browser (e.g. in case of success when a task was sucessfully completed or approved). The aBPM framework sends in such cases an update of the JSON Model “process” to the browser. Inside of this JSON model exists the boolean attribute with name “readonly” that stored this information. This attribute in an indicator if the aBPM Task is readonly thus completed or not.

Another important information is that SAPUI5 allows to set change listeners to the model via model binding. There exists an “attachChange” command that allows to assign a function that will be executed in case of model changes. In this solution the function checks if the attribute “readonly” is true. If yes an event will be created.

The next question is:

How can the custom inbox/provider be informed to close this task tab/window?

For this challange the local storage of the browser can be used. The local storage can be used to store data into the cache of the browser. Data can be set or removed programmatically and will not be removed if the browser will be closed. Items will be set with key value pairs into the local storage.

In this solution the item key will be the task instance id and for the value will be used two parameter values.

The first one is “closeWindow” that inform the custom inbox/provider to close this task tab/window. This value can be triggered via an event listener on the window event “beforeunload”.

The second value is “removeWindowRef” that only inform the custom inbox/provider to remove the window reference from the map. The reason is in case of an end user clicks the tab/window close “X” the custom inbox/provider must not execute the window.close() command again because the tab/window is already closed by the browser itself.

And the final question is:

How can this information be implemented in a short form of JavaScript source code?

The answer is the following code block:

function setAttachChange() { // register binding on model change binding = new sap.ui.model.Binding(processModel, "/readOnly", processModel .getContext("/readOnly")); binding.attachChange(function() { // in case the readOnly state was set to true // trigger storage event to close window if (processModel.getData().readOnly) { // alert("Task is now read only"); var params = location.search; var taskid = getParamByName("taskId", params); localStorage.setItem(taskid, 'closeWindow'); } }); } function sendStorageEventToRemoveWindowRef() { var params = location.search; var taskid = getParamByName("taskId", params); localStorage.setItem(taskid, 'removeWindowRef'); } function getParamByName(name, url) { if (!url) url = location.href; name = name.replace(/[[]/, "\[").replace(/[]]/, "\]"); var regexS = "[\?&]" + name + "=([^]*)"; var regex = new RegExp(regexS); var results = regex.exec(url); return results == null ? null : results[1]; } processModel = undefined; binding = undefined; sap.ui.getCore().byId("formView").attachModelContextChange( {}, function(event) { if (event.getSource().getModel("process") != undefined) { processModel = event.getSource().getModel("process"); setAttachChange(); } }, {}); if ('addEventListener' in window) { window.addEventListener('beforeunload', function(event) { sendStorageEventToRemoveWindowRef(); }); } else if ('attachEvent' in window) {// for IE < Version9 window.attachEvent('onbeforeunload', function(event) { sendStorageEventToRemoveWindowRef(); }); }

Hint: The task instance id of the task will be read from the task URL via a regular expression. A typical task URL of aBPM looks like this:

http/s://:/abpmui5/task?taskId=

Hint: This code snippet needs only to be loaded once if the UI will be initialized. A good place is the UI5TabletViewRenderer that was used in this example to insert those lines. An example for a custom UI5TabletViewRenderer can be found here (point 2):

https://blogs.sap.com/2016/12/27/extend-abpm-with-pdf.js-a-pdf-viewer-that-runs-inside-different-browser-environments/

After deployment and a hard reload the automatically close of the task tab/window should be executed if the task was set into a readonly state.