Rethinking smartUI Part 4-B

Forms Rest command

Some weeks ago I published a new video on Rethinking smartUI on Youtube. Now we have Rethinking smartUI Part 4-B discussing the main part of gathering and displaying thr documents data.

If you havn’t it seen yet, here is the short video. In this posts, we’ll go though the technical aspects of this new kind of approach to smartUI. This demo is a Document Pad (or short DocPad), displaying all document properties in a SCIFI GUI arrangement.

A warning at the beginning: To use this code with IE11 is a perfect way to test all js error messages. Use this code only with the newest browsers. Its tested with Chrome (V98), Chrome Canary (V98), FF Developer (95.0b4), Edge (95.0) and Firefox (93.0)

The other parts of this post were

Part 4-A The Javascript Part 1

Part 3 The Infrastructure and the CSS

Part 2 The HTML

Part 1 Overview

In the part 4A, we had discussed all the js responsible for the perimeter of the whdgetz. Not lets discuss the main part which is responsible to gather and displad this data:

docdisplay

A CSS Grid

As you can see, there are 6 panels arranged in a CSS grid.

For infos on the css, please review this post, the part 3 of this series.

So let’s start with the panel at top left.

The documents metadata

This is more or less the data which is related directly to the document. The documents node number was the output from the node picker . The nodepicker was closed by the done() callback.

Nodepicker

Here we are in the this function of the nodepicker. We extract the node from the callbacks arguments an get the id with the topmost arrow. We extract the name of the node and put this name inside the id #document.

The loadDescriptions function does the work.

loadDescriptions

The prelude is simply to select the first face “.face.one”

Prelude
Begin

If this is not undefined (remember, smartUI always makes 2 runs, so its always a goot idea to test if its defined) the create and modify dates are extracted and translated in a standard js data. For non-US readers it will be always a difference between p.ex 04-05-20 and 4.Mai 2020 (US and german dates for the Star Wars day May the fourth), thats why we translate the dates.

Also we need to get the users of the creation and the modification. But these are numbers, so we want to translate them to names.

Next, extract the server from the connection and construct the members REST command to get these names.

First view: The fetch command

fetch is new in js 6. In this older, antique times you would have used some ajax variants like xmlhttprequest or some similar methods which we will use in other calls for comparism.

Fetch command

Technically, we have to issue two REST calls to /member/ to get the names of the createuser and the modifyuser. We use the fetch command.

Remark: the famous async/await would be much more handy for that, but we wanted to limit the language scope to js6 for these posts.

Once we get the responses, we’ll put that names simply as innerHTML on the panel.

Technically, you can use all other avaliable methods to put text on the panel, from template-strings to create a and fill a text nodein the DOM. You can even invite handlebars to do this for you.

loadDocumentThumbnail

In the top middle panel we added the document thumbnail, which is created automatically during indexing on the server.

Thumbnail

We must enter the nodeid in the REST command /thumbnails/medium/content to get the medium resolution version of the thumbnail.

To show the diffence to the fetch comand, the old archaic XMLHttpRequest was used.

The receiving image is put into a div with the id “Thumbnail”.

Image Correction

In the case the user selects another document the old thumbnail would remain. So we remove the old image element.

Almost done, we need to put our otcsticket in the request header and to send the request to the server.

loadNodeData

In this function, we use exactly one REST call to get all data at once. This is done by the function /forms/update?id=xx whick will deliver all data for that nodeid at once. Expecially the categories take a while, so a css-fog was used to cloak the image of the approaching grid until the data was received (revisit the video). Then the css fog is cleared and trhe categories are displayed.

The call is also done with the old XMLHttpRequest to show the diffences to the modern fetch command.

Local functions were used instead of those in “this” to keep the scope clean.

forms/update

The categories and the attributes

Categories

Categories were returned in an object with their category name a title in the entry. To get the attributes we have to do a little bit more.

Attributes

We split the result into several arrays to extract the values. If we have “date” in the type field, we have to use our date translation also on that to display the dates correct.

Security Clearances

All security related data is on the fouth face, the one on the lower left.

Security Clearances

Here, all security levels and markings were displayed inside a span.

Records Management Data

here we extract and fill the data on the lower middle panel.

Records Management

The Versions Data

Here, the REST commend has a problem. Versions are not included in the answer of the REST command, at least in the Content Server versions 21.3 and 21.4. So let’s ionform the user on this fact and display a local language string of this fact.

Tip: Maybe there will be a patch to fix this in the near future.

Versions Data

So we had all parts discussed.

We offer a one day remote training to understand the javascript code. If you are already a sophisticated Javascript Developer, you can get the free Sources also from https://github.com/ReinerMerz/reinerdemo (a public repository on Github).

Warning: This is only the sourcetree of the project, so you have to insert this in your own project file.

The data returned from the formsupdate?id=nn REST command

The whole data structure is send back in response to a forms/update?id=nnn REST call. Some of these entries take quite a while, so try using some css to cache this.

Forms Rest command

Have fun on discovering the endless possibilities of Dashboards and other Contentserver smartUI extensions using javascript6 and css3.

The sky is the limit.

Rethinking smartUI Part 4-A

Rethinking smartUI

Three weeks ago I published a new video on Rethinking smartUI on Youtube. Now we have Rethinking smartUI Part 4-A discussing Javascript. If you havn’t it seen yet, here is the short video. In this posts, we’ll go though the technical aspects of this new kind of approach to smartUI. This demo is a Document Pad (or short DocPad), displaying all document properties in a SCIFI GUI arrangement.

This is Part 4-A of a multipart post covering Javascript of DocPad. For the css refer to part 3 of Rethinking smartUI.

Warning: This is a lot of js code, so I subdivided this Part 4 into Part 4-A and 4-B (getting all documents infos with 1 Rest call). Part 4-B will be published next week.

We offer a one day remote training to understand the javascript code. If you are already a sophisticated Javascript Developer, you can get the Sources also from https://github.com/ReinerMerz/reinerdemo (a public repository on Github).

Warning: This is only the sourcetree of the project, so you have to insert this in your own project file.

The post parts until now

Part 4-A The Javascript Part 1

Part 3 The Infrastructure and the CSS

Part 2 The HTML

Part 1 Overview

But first to Rethinking smartUI Part 4-A.

The Javascript auxiliary files

Using the model factory

The idea of a model factory is to combine several functions in one.

a. Create a model and return it.

b. Load server data into this model for use in the main constructor function

A typical factory looks like this:

// the factory for the model
define([
‘csui/utils/contexts/factories/factory’, // Factory base to inherit from
‘csui/utils/contexts/factories/connector’, // Factory for the server connector
‘ademo/widgets/docpad/impl/docpad.model’ // Model to create the factory for
], function (ModelFactory, ConnectorFactory, DocpadModel) {

‘use strict’;
var DocpadModelFactory = ModelFactory.extend({
propertyPrefix: ‘docpad’,
constructor: function DocpadModelFactory(context, options) {
ModelFactory.prototype.constructor.apply(this, arguments);
var connector = context.getObject(ConnectorFactory, options);
// Expose the model instance in the property key on this factory instance to be // used by the context
this.property = new DocpadModel(undefined, {connector: connector});
},
fetch: function (options) {
return this.property.fetch(options);
}
});
return DocpadModelFactory;
});

The main Javascript files

The lang.js file(s)

The language system consists of those strings which are pupposed to change per language.

define({
helloMessage: ‘Hello {0} {1}!’,
waitMessage: ‘Please wait’,
seldoc: ‘Select a Document’,
printdoc: ‘Print the selected Document’,
pickerTitle: ‘Select a Document’,
selectPickerButtonLabel: ‘Select’,
descNodeID: ‘Node-ID’,
desDescription: ‘Description’,
desCreated: ‘Created’,
desModified: ‘Modified’,
……more …..
});

The standard model from Backbone.js

define([
‘csui/lib/backbone’,
‘csui/utils/url’
], function (Backbone, Url) {
‘use strict’;

let DocpadModel = Backbone.Model.extend({
defaults: {
name: ‘Unnamed’
},

constructor: function DocpadModel(attributes, options) {
Backbone.Model.prototype.constructor.apply(this, arguments);

// Enable this model for communication with the CS REST API
if (options && options.connector) {
options.connector.assignTo(this);
}
},
// Computes the REST API URL using the connection options
// /auth returns information about the authenticated user
// usage of => not possible because of “this” is used for urls
url: function () {
return Url.combine(this.connector.connection.url, ‘/auth’);
} ,

parse: (response) => response.data

}];

return DocpadModel;

}];

 

Remark: The Arrow Function at parse is pure js6. But let me quote developer.mozilla.com here

An arrow function expression is a compact alternative to a traditional function expression, but is limited and can’t be used in all situations.

Differences & Limitations:

(Endquote)

This means, its not possibe to use when any limitation will take place, like in the constructor.

The docpad.view.js

The stages of docpad.view.js

Get infos via the Bootstrap model

constructor: function DocpadView(options) {
options.model = options.context.getModel(DocpadModelFactory);
Marionette.ItemView.prototype.constructor.call(this, options);
this.listenTo(this.model, ‘change’, this.render);
}

First, we initiate the model (and read the data) via a standard model using the model factory. Then we call the constructor in the prototype with the cs options. Lastly we listen to a change of the data and (in case) we rerender the widget.

Load the photo

The user data contains (eventually) a photo of the user. This is loaded and inserted in the DOM with the function loadPhoto. Here the js6+ fetch function is exposed to get the photo and insert it into after the element woth the .photo class in the dom.

loadPhoto: function () {
let server = this.model.connector.connection.url;
server = server.substr(0, server.search(“api/v1”));
let url = server + this.photo_url;
let ticket = this.model.connector.connection.session.ticket;
fetch(url, {method: ‘GET’, headers: {“OTCSTicket”: ticket}})
.then(response => response.blob())
.then(function (myBlob) {
const URL = window.URL || window.webkitURL;
let photo = URL.createObjectURL(myBlob);
let img = document.createElement(“img”);
img.classList.add(“photo”);
img.src = photo;
document.querySelector(“#photo”).appendChild(img);
setTimeout(() => {
URL.revokeObjectURL(photo);
}, 100); // cleanup
}
);
},

       
Using the Node-Picker

The Node-Picker is a standard function in the sdk, so we use it.

The file ‘csui/dialogs/node.picker/node.picker’, // the csui node picker

is required at the beginning of the docpad.view.js file under the local name of NodePicker like this:

define([
‘csui/lib/underscore’, // Cross-browser utility belt
‘csui/lib/marionette’, // Marionetter
‘csui/lib/moment’, // the date/time lib in csui
‘ademo/widgets/docpad/impl/docpad.model.factory’, // Factory for the data model
‘csui/dialogs/node.picker/node.picker’, // the csui node picker
‘i18n!ademo/widgets/docpad/impl/nls/lang’, // Use localizable texts
‘hbs!ademo/widgets/docpad/impl/docpad’, // Template to render the HTML
‘css!ademo/widgets/docpad/impl/base’, // base Stylesheet needed for this view
‘css!ademo/widgets/docpad/impl/adv’, // adv stylesheet for this app
‘css!ademo/widgets/docpad/impl/print’ // print style sheet
], function ( _, Marionette, Moment, DocpadModelFactory, NodePicker, lang, template)

The picker is started by pressing the big button, this actually calls showThePicker. Types of 144 (only Documents) and on the enterprise volume are among the start conditions.

The title and other strings are extacted from the appropriate lang.js language file(s). The command nodePicker.show() at the beginn of the chain displays the nodePicker

showThePicker: function () {
if (undefined === this) {
return;
}
let btn = document.querySelector(“.btn”);
btn.classList.remove(“animate-large”);
btn.classList.add(“animate-large-backward”);

let nodePicker = new NodePicker({
connector: this.model.connector,
selectableTypes: [144],
dialogTitle: lang.pickerTitle,
selectButtonLabel: lang.selectPickerButtonLabel,
startLocation: ‘enterprise.volume’
});
nodePicker.s how()
.fail(function () {
console.error(“Picker fails to show”);
})
.done(_.bind(function (args) {
document.querySelector(“.printbtn”).classList.remove(“hide”);
document.querySelector(“#content”).classList
.replace(“hide”, “display”);
let node = args.nodes[0];
let id = node.attributes.id;
this.docname = node.attributes.name;
document.querySelector(“#document1”).innerHTML = this.docname;
this.loadDocumentThumbnail(id); // load the thumbnail and display it
this.loadDescriptions(node); // load node data and display it
this.loadNodeData(id); // inquire form update data and display it
}, this)
);

},

The callback in the .done clause simply extracts the node id and the name from the results and stores them in the docpad “this”.

In the next week part “Rethinking smartUI Part 4-B” we’ll discuss the REST Commad how to get all document data (nearly) at once.

Rethinking smartUI Part 3

The upper PART

Two weeks ago I published a new video on Rethinking smartUI on Youtube. If you havn’t it seen yet, here is the short video. In this posts, we’ll go though the technical aspects of this new kind of approach to smartUI. This demo is a Document Pad (or short DocPad), displaying all document properties in a SCIFI GUI arrangement.

This is Part 3 of a multipart post covering the technical start of DocPad and the associated CSS

The post parts until now

Part 4-A The Javascript Part 1

Part 3 The Infrastructure and the CSS

Part 2 The HTML

Part 1 Overview

A. The technical infrastructure

Die DocPad is started via the index.html, found in the test folder of the docpad. This is because of its much easier to test modifications via index.html compared to installing the finished widget in the content server and trying it then.

The first part of index.html

The first part of index html

The whole page is more or less standard. We habe 4 areas of interest in the first part. Dont forget, nuc was introduced in 21.2. In older versions nuc was not existant.

  • A. Here, you see the config is moved to the nuc area
  • B. Change A will also require to add the nuc-extensions to the list of dependancies for csui. Thed whole js code is loaded by the “ademo” extension.
  • C. My machine is on a VM. This means, if you put this on your machine, you’ll have to enter your url and your support directory (called supportPath) in the configuration.
  • D. I’ve used my ticket to provide the login. You can use username and password to login the more convential way or also provide a ticket of youfself here. The displayed ticket won’t work at your site.

The second part of index.html

Part 2 of index html

Here we have this points of interest

  • A. The require parts of needed modules. It is a docpad.mock.js in the list of modules, but its not recommended to use the mockup facility because there is lot of traffic from and to the server. Its much easier to add a real content server behind that index.html.
  • B. Standard procedure. Instanciate the widget with the context, display it in the region and fetch the context from the server. As mentioned, its easiere to use a real server as data source so switch the mockup off.
  • C. The marionette region is associated with the id=”widget” of this div, so the widget is displayed here.

At the end there is immediate function starting with

(function() {
var ws = new WebSocket('ws://' + window.location.host + '/jb-server-page?reloadServiceClientId=1');

This is inserted by Webstorm (my JS IDE) to allow auto-reload of changed files. You can ignore that, other IDEs will solve that differently.

B. The CSS

The CSS

Here, all css files used in the docpad are listed in the require.js list of required modules. For demo purposed and to keep things simple, I used 3 css files:

base.css

This file contains the basic css instructions to style the .hbd template shown at the top of list.

adv.css

contains the more advanced css instructions for docpad

print.css

is the print style sheet to provide a proper output on paper.

Disclaimer: The css instructions selected do not impose or propose any styles to be followed, instead they are used for pure demo purposes here.

The base.css File

Here the main functionality of the css is found. One of the feature of css3, the variables, is used. In the pseudo element :root all variables used in different rules are defined.

css setup

At the end of the snipped you’ll see a media query, saying the following is used tor screen display.

Lets discuss several stages:

The header + the footer

Header
Footer

These two structures exploit the standard userinfo with REST from the content server in a standard backbone model. “Hello xxxxxx” is a structure from the hello world demo with the word “hello” and the signed in user. The photo is downloaded from the content server and dosplayed.

The bottom structure simply prints out other user data on the screen .

Points of interest:

Font used

The nice digital effect is build with the font “digital-7”

The header is done with

The header

Ther photo is inserted at the position of the .photo class in the size of 80×60 pixel. Then the photo gets this nioce rounded look using border-radius.

the footer conststs of three divs, which are positioned in 3 columns

The footer

The divs have the classes .boxcell and .leftbox and are descendants of the .footerbox

The document display

The document display consists of six divs and are positioned using a css grid.

docdisplay

They have numbers, the numbers range from one (“card1”) to 6 (“card6”). The css part is (shown here only a fraction):

Cards

They are all children of the cube, using the display mode grid and displaying the 6 cards in two rows and threee columns.

cube

Using the diffent REST methods in the js code, these cards were filled by the standard methods of DOM interaction from js. This will be the main theme of next weeks post, the js code of “Rethinking smartUI” Part 3.

Rethinking smartUI Part 2

Last week I published a new video on Rethinking smartUI on Youtube. If you havnt seen yet, here is the short video. In this posts, we’ll go though the technical aspects of this new kind of approach to smartUI. This demo is a Document Pad (or short DocPad), displaying all document properties in a SCIFI GUI arrangement.

This is Part 2 of a multipart post covering all aspects of this Docpad.

The post parts until now

Part 4-A The Javascript Part 1

Part 3 The Infrastructure and the CSS

Part 2 The HTML

Part 1 Overview

The html

First, lets take a look on the html (in out case the .hbs file). This is the top part of the widget,

The HBS file, Part 1

The div with the class “topbox” contains the Username and the Photo. There is also a Print-Button, if a document is selected.

A button, class “picker” is sorted in a div with “picker”. This is the button used to start the node picker component. Its hidden now, will be used later, when a document is selected.

The documents data is displayed using a cube. A cube has six sides so all sides can be presented using a css grid or …. (arranged in a 3D cube which can be rotated in 3D. But thhis is not part of this demo).

The whole thing is arranged in a div with the id of “content”. The top element is a div with the class “cube”, holding six divs for the six sides

The html of the cude

Just for fun, the cube is surrounded by a div with the class “cam”. If you want to display the cube as 3d cube. This is used to set the perspective on a 3d Cube. If you are interested in learning more on 3D css cubes, refer to https://css-tricks.com/simplifying-css-cubes-custom-properties/

Lets see the Actions.

The Actions in Detail

After starting the aplication, there are several stages, They are

a. Application started

Docpad started
Docpad started

Here, the application is just started. the “Select a document” started from the top left and moved in the center of the window. This button will initiate the nodepicker, a standard component of the smartUI library.

Until now, we queried the user logged in. Then, we greet the user, extract the photo from the Content Server Database and display this photo in the top right. To make it more interesting, we displayed the photo in round form via css.

In the three panels at the bottom we displayed the rest of the user record. Just for fun we surrounded the three botton panels with a border animation.

b. Nodepicker selected

The next stage is the nodepicker. After pressing the “Select a document” button, it is started and delivers a list folders and documents on the associated Content Server. Meanwhile, the Button moved again back to upper left corner.

c. Document selected

After the user selects a document, all data of this document is read from the server. In this case, the “APAC Expense Report.xlsx” is selected. (Refer to part 1 to see which REST commmands are used).

As of do have a document, we can display the header and the print button.

As you can see when playing the video, the cube starts in some distance and is a little but foggy during the approach and clears when we receive all data.

Display of the document

The reason is, that the forms/update REST call takes longer and we use CSS animations ans css view filters to hide that fact from the user. When in doubt, view the video on top of this post again.

For beauty there are also some hovering effects added, on the panels and on the thumbnail.

d.Document to Print

The last stage is (besides selecting a new document to display) is to print the document.

Here we have the print previev in Chrome

Print stylesheet in action

As we can see. the node data is printed in the form of a css grid on paper. The display is in standard layout. A media query selects a print style sheet instead of the normal stylesheet(s).

In the next week we discuss in Part 3 the index.html to start the widget standalone and css stylesheets (there are really several). We’ll then conclude this series in Part 4 discussing the Javascript made for this demo.

We’ll use the 4 steps of the application as the schema for Part 3 and 4.

See you next week!

Asking your browser for help in smartUI developments

Browser Memory

When you think of smartgUI, you may always think of a lot of small js/css text files and a couple of resources to be loaded. All together act as smartUI Page like this:

A typical standard landing page

This is a typical landing page. With such a page you can control, how your perspective is working and also if certain commands, controls and widgets are correct. For example, the widget ot the top left is a modified Welcome Widget showing System Messages and other news channels.

What else can a browser do for you in your continuing quest to produce an awesome user experience for an enduser?

A lot! First, open the development tools in the browser. Here we are using Chrome, but this tools are available on all browsers.

Developer tools – a closer look

Developer Tools

Press Ctrl+Shift+I or the Develeloper tools entry in the menu.

The tabs in the developer tools

This will open up the develeloper tools. The functionality is subdivided in several tabs. The most important (from left to right) are

  • Elements. Gives you the possibility to see the actual DOM loaded, Here you can change css and other elements and you’ll see immediately the effect. The rightmost icon lets you identify any element on the screen (and display it in the DOM). Thaty a handy way to identify elements on the screen and to which js file they belong (Similar way as we had in legacy gui with oscript in these ancient times)
Identify Icon
  • Console. Gives you all messages from the browser. You can see all module messages, also missing modules are displayed in red. There are several levels of messages, which can be filtered. Here, since this is a develeopent VM, all levels are activated.
  • Sources. The main tab to work with.
The sources window

The complete smartUI is loaded in the browsers memory (except those data parts, which will be changed via REST/Ajax later on). So we can examine directly, whats happening in the browser.

Interesting is the treeview at left:

Loaded js parts

We see blue and orange folders, which can be opened. Lets open a blue folder, for example the “New Generation Desktop” ngd and the resubmission

Bundles and Sources

First, we see, the ngd has the name ngd/bundles. It contains the js and css bundles of ngd. Lets open another folder, the resubmission folder. Here you see a blue app/bundles folder and an orange folder named src. Here you have the standard SDK tree. If there sre orange folders, then you can browse into the source code, like this:

Load a souce file which is not in the SDK

Here we checked the AddReminder.js from the reminder package, which is one of these modules not part of the smartUI SDK.

Whats to do with that file(s)? Select the file (with js extension) in the tree and right klick. Here you can edit the file or save the file to your filesystem.

Save a loaded js file

Search a needle in a haystack

We have a lot of js files in the browser memory. How to search for a specific file?

First, display the search window by clicking on the to right 3 point menu. Goto More Tools and click on Search. Then a search bar opens at the lower left. Enter your search name (mostly part of the requirejs path) and you’ll see the results. Select the .js file (bundles are not very useful to read). The file is displayed in the source window.

Our requirejs paths in the browser

Sometimes its quite nice to inspect the loaded requirejs modules in the browsers memory.

At first, we have to switch to the debugger mode. So open the console tab and type “debugger” in the last line to put the browser in Debug mode.

Then our interestring things appear at the right of the developers tools.

We see, the scope is filled with the loaded objects. Go to the global scope. Scroll down, until you’ll find ther csui entry. Please note, this may change to nuc from 21.2!

There are several entries under csui. Open the first “require” entry (or “requirejs”). Then open s. Expand contexts. Open _ (underscore). Expand registry.

Then all loaded csui and extension parts are listed in the registry. Lets examine one entry (countryselector.view).

Under depmaps, we see the dependencies.

Under map we see all map related things, this is the place to override an original module with a custom one.

And we have access to the source code (if we click on the link at countryselector.view:13.)

Now you have the base for your own experiments. There are a lot of additional features in the developers tools, which could not be covered here. So: Happy experimenting.

How to check if the smartUI SDK is working

Test the sdk

If you get new Content Server Versions, you also have to upgrade your existing smartUI projects to the new version.

In this post, I’ll give a short receipe how to check the functionality of the sdk.

The primary component of the sdk is the generator. It contains the compete sdk and all infrastructural things (grundfiles etc) to build a project folder. All other zip files (except the style override kit for webdesigners) are secondary.

The following receipe builds on a running SDK of any older version.

The Check

So to check, if a new generator is working, do this: (can be done in parallel to existing versions).

  • Unzip the new generator to a folder.
  • if you do have older generator installed and you want to keep it:
    • change the name of the new generator to reflect the test, for example generator-test21.2.
    • Also configure this name in the generator. Click here for details
  • go inside the unzipped generator folder and link it to your npm
Yo Generator Links
Yo Generators
  • init the new test project with the new generator (here yo csui-21.1-standard). Then wait and check, if there are any issues. You can ignore minor issues, as long as the folder is initialized.
  • install the demo widget from the generator by typing yo <your-generatorname>:widget. Do not try to install the demo widget from different sources, you want to test if the generator runs.
  • run grunt from the commandline for the new project
    • Should not indicate any issues.
    • in the out-module folder should be the module to install in the Content Server
    • in the out-release folder should be at least a json file and a bundles folder with content.
Output files

But if you get a result like this:

Non working SDK

then the generator is broken und the whole SDK wont work. You can try to grunt –force, but the results will be not defined. In this case, you should wait for a working version of the SDK.

If the thing is working, you should be able to install the module and see the hello widget in the perspective manager.

Happy Testing

Yeoman & generator-csui-extension secrets

Yeoman and smartUI

Have you ever wondered about the yeoman and the genererator-csui-extension? And whats going up in the somewhat bumpy installation and generation of a project dir? This are the Yeoman & generator-csui-extension secrets.

Yeoman & generator-csui-extension secrets: Lets unveil this secrets

First, recap the installation steps from scratch:

  1. Download and install node.js Version 11.15.0 (In you try a newer version, you will be rewarded by the famous primordials not defined error on starting yo, see this post )
  2. Set npm (part of node.js) to npm version 3 globally (npm install -g npm@3 (I am using 3.3.10)
  3. Install the grunt cli globally (npm install -g grunt-cli@1)
  4. Optional path: Unpacking the sdk and setting up the sampes)
    1. Unpack the SDK in a folder (p.ex. sdk)
    2. go inside this folder
    3. Use npm to install all requirements (npm install)
    4. Then you can start the internal webserver (Default under post 7777) by npm start and browse to sample-index.html inthis dir. Here you will get a listing of certain samples.
    5. The doc folder contains a very basic documentation of the smartUI SDK
  5. But for practical work, you need to gererate at least one project folder. This is a complete structure, containing the actual sdk and a place to build your own packages. So lets generate a project folder named project
    1. Preparation, only to do once
      1. unpack the gererator-csui-extension to a dedicated folder (p.ex. generator)
      2. While not(!) in this folder, install yeoman globally (npm install -g yo@1)
      3. go inside the folder generator
      4. link this as an extension to npm (npm link)
    2. Lets generate the project folder
      1. make the folder named project
      2. go inside the folder named project. Its empty
      3. Start yo to execute the csui-extension (yo csui-extension)
        1. you need to define the name of your oscrippt module and the requirejs base name. Then its doing a lot.
        2. Now your project is really full. You can optionally add a demo widget (yo csui-extension:widget)
      4. Now, build the project (grunt)

Ok, now the project folder project is operable. Lets take a close look on the generator.

(Remark: The versions mentioned are the working versions in my dev machines. Other, newer versions may work, but this is not guaranteed.)

Close Look at the Generator

When you do a npm link, a symbolic link is is build from the folder to [roaming dir]\npm\node_modules\generator-csui-extension.

Symlink Generator and Yeoman

So the extension folder is used as input for the yo execution.

Our Generator source folder looks like

Mann Content of the Generator

The app folder here is interesting

App folder of the Generator

First lets take a look on the rest of the templates folder

Some deeper folders in the hierarchie

Here we see, we have the same structure as lib…. in the sdk. SO the complete SDK is copied fron the generator folder to the project dir unter lib. There is no need to use the sdk folder (except for docs and samples)

A closer look at index.js (Excerpt). This file is executed during “yo csui-extension”.

Index.js

Here you see, the whole structure is copied directly from the templates folder to the destination project. All contents in this templates folder are later in the project folder.

A closer look at package.js

Package.js

The package.json contains as always the definition of this generator extension like, name, description and depedencies of this extension.

Areas for Customizations are at this areas (for example):

  • Custom gruntfiles, which shoulkd apprear in all new generated project folders
  • A different setup for the linters which should apprear in all new generated project folders
  • Added libraries
  • Added documentation structures

How to do this

Simply modify the generatot folder, add your customizations and modifications. You can save this folder as .zip to distribute internal standards.

Happy Customizing

System Messages (in the smartUI Welcome Widget)

System Messages in smartUI

Remember the System Messages in the Content Server? This is an handy tool to display system related messages, like: “Next weekend we have maintenance” to inform users on issues with the system.

Normally, System Messages are added or deleted in the Admin pages. Here is an example:

How to add or delete system messages

A name of the Message, the message itself, an option URL for any explanatory pages and an effective date build together the System Message. Per default the System Message has a timeout period of 2 days after publishing, but this can be set in the opentext.ini file by setting a value to NewsDFTExpiration.

From this source the System Messages will be displayed in the legacy gui like this

System Messages are displayed in the legacy gui

But whats if somebody uses smartUI? Unfortunately, there is no possibility to display System Messages in smartUI.

Until the otherwise senseless Welcome Widget is amended. It can look like this:

System Messages in smartUI
System Messages – the new feature in the Welcome Widget.

(Disclaimer: This widget is NOT in the OpenText SDK. This is made by me. Contact me if you interested in using that)

The widget gets its system messages directly from an REST call which extracts this Messages and delivers them to the widget.

The news player is basically an unordered list with an <li> for each news entry. all news were rendered in the <ul> This is a screenshot of the handlebars template.

If any url is in the System Messages, the link opens up in a new tab or a new window.

The news entries scroll with a pure CSS3 animation, no additional Javascript is needed for that. Here is the animation part of the news

And the magic of animation is done with this:

And suddenly the Welcome Widget supports System Messages.

Nice, isn’t it.

Hidden Gems in the smartUI SDK: The side.panel

An overview of the side panel

One of the most interesting controls in the SDK is the side.panel. Reminds somehow to the good Documentum side panels, but is native in the new SDK for Content Server 20.4.

This can be used as a simple control to show things like search forms or oanything you like. Also, multiple views (slides) can be shown in a “Wizard Style”.

First lets take a look on the the sidepanel right out of the box. Quite astonishing, there is a index.html actually working under csui/controls/side.panel/test/index.html. If somebody starts this file, we’ll see side.panel in action:

Shows a nice panel sliding from left/right based on the configuration. This view can be used to show a single view or multiple views (as slides) as per configuration provided to it.

Quite interesting is the fact that if slides provided to the panel, panel’s footer include navigation buttons along with the button provided to the respective slide as part of configuration.

side.panel has modal (dialog) behaviour by default which optionally can pass using constructor param as well (options.modal).

There are several usage possibilities.

Simple Usage (on the right of the screenshot above):

var sidePanel = new SidePanelView({
title: 'Simple Usage Title',
content: new Backbone.View(),
buttons: [{
label: 'Button1'
}]
});
sidePanel.show();

If you want to have several buttons on the footer (in the middle of the screenshot above):

var sidePanel = new SidePanelView({
headerView: new Backbone.View(),
content: new Backbone.View(),
footer: {
leftButtons: [{
label: 'Button1'
}],
rightButtons: [{
label: 'Button2',
id: 'btn2'
}]
});
sidePanel.show();

An example for a “wizard style” sidepanel sliding from the left or the right into the screen

var sidePanel = new SidePanelView({
slides: [{
title: 'Step1',
content: new Backbone.View(),
buttons: [{
label: 'Reset Form',
className: 'binf-btn binf-btn-default'
},
{
label: 'Search',
disabled: true
}]
},
{
title: 'Step2',
content: new Backbone.View(),
buttons: [{
label: 'Finish',
close: true,
className: 'binf-btn binf-btn-primary'
}]
}]
});
sidePanel.show();

There is also a documentation available, at csui/controls/side.panel/doc/side.panel.view.md

Nice, isn’ it?

Happy sliding !

Remove Commands from Nodestable etc in the smartUI SDK

Command is Gone

From time to time you’ll need to remove commands from the widgets, like the nodeslist widget.

The magic spice is setting up a blacklist on the masks.js files during the initial phase:

csui.require.config({
  config: {
    'csui/widgets/search.results/toolbaritems.masks': {
      'mycustomer': {
        'otherToolbar': { blacklist: ['Properties', 'permissions'] },
        'inlineToolbar': { blacklist: ['Properties', 'permissions'] }
      }
    }
  }
})

There are several possibilities to do that.

1, The approved way

The approved way is to configure smartUI before its initialized from OScript.

This can be done by overriding the GetDynamicConfiguration in your base smartUI module (the one with the csuiextension orphan) like:

override function Assoc GetDynamicConfiguration(Object prgCtx, Record request)
  
    List blacklist = { "Copy", "Move" }
    return assoc{
      "csui/widgets/nodestable/toolbaritems.masks": assoc{
        "basecsui": assoc{
          "tableHeaderToolbar": assoc{ "blacklist": blacklist },
          "inlineToolbar": assoc{ "blacklist": blacklist },
        }
      },
      "csui/widgets/nodestable/headermenuitems.masks": assoc{ 
        "basecsui": assoc{ "blacklist": blacklist }     }    }
  end
end

Here in this example, the toolbaritem.masks and the headermenuitem.masks are set up with our magic spice (a blacklist containing all the signatures of the commands not desired). This will remove the “Copy” and “Move” commands from the list of commands permanently. And permanently means, this will survice a Page Reload.

2. The ugly way (but also surviving a Page Reload)

The ugly way is a way is the standard OpenText Way of overriding app.html and configuring the blacklists by yourself. Lets take a look at the app.html (found at ../core/module/csui/html).

Here is an example on a windows server:

Where to find app.html
app.html - the head

In the upper part you can see the csui.require calls. At the top you’ll notice a csui.require.config call, where you can put our magic spice (see above).

The disadvantage is, when you override app.html (directly or by using htmlmap) then you’ll have to check, if any future OpenText patches will override the app.html also.

BUT: If you override app.html, you can take advantage of this for example by implementing a permanent footer, which is always drawn at the bottom. You cannot do that with pure smartUI tools.

Here is an example of a permanent footer in the body part of the app.html.

Multiple usages of app.html - the body

3. The force way

There is also a brutal way to remove commands without that configuration of app.html. This requires

  • a widget or a command to do the removal
  • a couple of js lines

But on the other hand, this is the way which allows easy recovery of the command by doing a simple refresh of the page.

Here is a demo case (a wild version of the hello widget from my training installation). This is a widget with some demos and a new inserted button to delete a command.

a very chaotic demo

Behind the button are some js lines of code, which will remove the Copy-Command. Actually, the lines var b=commands.get(“Copy”); and commands.remove(b); do the job.

You will have to require /csui/utils/commands unter commands to use this two lines.

Two lines to decide the fate of the copy command.
Two Javascript Lines will decide the fate of the copy command

Lets see the initial command set. The Copy Command is here as usual.

Copy command lives

After the red button is pressed in the then the Copy Command is gone:

Copy Command is gone

We simply deleted the Copy command from the list of commands. This means, a simple Refresh will restore it.

Have much fun on playing around with commands!