WebIDE: How to Create Shell Plugin for Fiori Launchpad? - sapui5

This is to:
customize the Fiori Launchpad (e.g. modifying shell bar or adding footer)
work in NEO environment (not Cloud Foundry)
setup in WebIDE, not Business Application Studio
Other guides have pockets of outdated information such as the no-longer-existing option to create a 'Fiori Launchpad Plugin' from 'New Project from Template'

2020 Updated
Steps:
Create SAPUI5 template app
Add following code to Component.js (& modify to your liking). Everything will be stored in Component.js, MVC will be left untouched. Everything in .then() add custom code for modifications to FLP.
init: function () {
// call the base component's init function
UIComponent.prototype.init.apply(this, arguments);
var rendererPromise= this._getRenderer();
rendererPromise.then(function(oRenderer){
// var bFull= jQuery.sap.getUriParameters().get("plugin-full");
oRenderer.addHeaderItem("sap.ushell.ui.shell.ShellHeadItem", {
icon:"sap-icon://add"
,tooltip:"Current Stage"
},true,true);
});
// var oRenderer= sap.ushell.Container.getRenderer('fiori2');
// oRenderer.addHeaderItem({icon:'sap-icon://add'},true,true);
// enable routing
// this.getRouter().initialize();
// set the device model
// this.setModel(models.createDeviceModel(), "device");
},
_getRenderer:function(){
var that=this,
oDeferred= new jQuery.Deferred(),
oRenderer;
that._oShellContainer= jQuery.sap.getObject("sap.ushell.Container");
if(!that._oShellContainer){
oDeferred.reject("Illegal state: shell container not available. This component must be executed in a unified shell runtime context.");
} else{
oRenderer= that._oShellContainer.getRenderer();
if(oRenderer){oDeferred.resolve(oRenderer);}
else{ //renderer not initialized yet, listen to rendererCreated event
that._onRendererCreated= function(oEvent){
oRenderer= oEvent.getParameter('renderer');
if(oRenderer){oDeferred.resolve(oRenderer);}
else{oDeferred.reject('Illegal state: shell renderer not available after receiving rendererLoaded event');}
};
that._oShellContainer.attachRendererCreatedEvent(that._onRendererCreated);
}
}
return oDeferred.promise();
}
Deploy your app
Activate your plugin: Go to SCP's Portal service > Go to Service > Site Directory > *Choose a launchpad you want your plugin activated in > Content Management > Apps > *Add app ('+' icon)
Properties: *App Resource: select your deployed app > *App Type: select Shell Plugin
Catalogs: *select a Catalog to place your plugin in
Save
Publish site using top ribbon's right side Globe icon
How it Looks: *Note the additional '+' button on top ribbon. Success!
References:
Sample Plugin: this sample shows how to add header action items, footer, parameters, etc.
Activating plugin: see ONLY the "Configuring a Shell Plugin App" section
API Reference on what can be modified in FLP

Instead of using jQuery in the _getRenderer function, this at least works for me in a quick test.
Uses Promises instead of Deferred and ObjectPath (requires "sap/base/util/ObjectPath") which is the recommended replacement for "$.sap.getObject" as this is deprecated.
_getRenderer: function() {
return new Promise(function(fnResolve, fnReject) {
this._oShellContainer = ObjectPath.get("sap.ushell.Container");
if (!this._oShellContainer) {
fnReject(
"Illegal state: shell container not available; this component must be executed in a unified shell runtime context."
);
} else {
var oRenderer = this._oShellContainer.getRenderer();
if (oRenderer) {
fnResolve(oRenderer);
} else {
// renderer not initialized yet, listen to rendererCreated event
this._onRendererCreated = function(oEvent) {
oRenderer = oEvent.getParameter("renderer");
if (oRenderer) {
fnResolve(oRenderer);
} else {
fnReject(
"Illegal state: shell renderer not available after receiving 'rendererLoaded' event."
);
}
};
this._oShellContainer.attachRendererCreatedEvent(
this._onRendererCreated
);
}
}
}.bind(this));
}

Related

params for switch to favorites pane (Home Feature not loading favorites)

i have this requirement on IBM Content Navigator about a personalized (feature) homepage with various buttons used to switch between feature; i've made all works except for the one linked to the Home feature (favorites)
i've already tried to call the feature with thoose params:
params.repositoryId="FNOSARCHIVIO";
params.application="navigator";
params.desktop="OneFile";
params.userid="sys.filenetsvil";
but with no success, the feature is switched (after the button press it switch to the home feature) but it does not load the favorites of the user
here is my switch-feature method (taken for the ibm icn redbook + some modification)
switchFeature: function (featureIdToSwitch) {
//get layout from destop
var layout = ecm.model.desktop.getLayout();
// get the corresponding button of the LaunchBar Container
var feaButt = layout.launchBarContainer.getFeatureButtonByID(featureIdToSwitch);
var params = {};
// params.repositoryId="FNOSARCHIVIO";
// params.application="navigator";
// params.desktop="OneFile";
// params.userid="sys.filenetsvil";
// switching to the target feature
// feaButt.child.loadContent;
layout.launchBarContainer.selectContentPane(feaButt, featureIdToSwitch, params);
}
on the frontend i have 4 simple dojo buttons with onClick action, nothing special.
i use this feature id:
switchToHome: function () {
this.switchFeature('favorites');
},
this is what i mean when i say "it switch the feature but do not load the favorites:"
Home feature called from my button:
https://ibb.co/GMW7L2x
Home feature called from the standard toolbar:
https://ibb.co/BBgr36L
looks like it is loading the feature but it is not calling the listFavorites()
i cannot find any help on IBM docs or forum, any help here ? thanks!
At least i managed to do it, i post it here, hope helps someone:
1- override the default favorite feature (the java class), using the same js plugin, overriding this:
#Override
public String getContentClass() {
return "ecm.widget.layout.HomePane";
}
and set it to preLoaded:
#Override
public boolean isPreLoad() {
return true;
}
then, on the frontend, retrive the js feature, and load the content:
var targetFeature = layout.launchBarContainer.getContentPaneByID(featureIdToSwitch);
targetFeature.loadContent()
you can call the loadContent() only if the feature has been preLoaded or alredy invoke at leat once

How to change the shell title in Fiori App

I am looking at changing the ShellAppTitle in a Fiori app. Refer the highlighted part in the snapshot below:
I already know a way to to this which I am not proud of:
sap.ui.getCore().byId("shellAppTitle").getText() /.setText()
Is there any better approach to achieve this?
The only improvement I could think of is to implement this via the FLP ShellUIService rather than the getCore() method. The reason being that if SAP changes the id of the header text, your code will break since it is not designed to work this way.
To implement the service, first declare it in your manifest.json:
{
...
"sap.ui5": {
"services" : {
"ShellUIService": {
"factoryName": "sap.ushell.ui5service.ShellUIService"
}
}
}
...
}
Then, you can access it in your Component.js via the following code:
// Component.js (the app root component)
...
this.getService("ShellUIService").then( // promise is returned
function (oService) {
oService.setTitle("Application Title"); // also could use .getTitle() first
},
function (oError) {
jQuery.sap.log.error("Cannot get ShellUIService", oError, "my.app.Component");
}
);
...
The full documentation can be found in the SAPUI5 SDK

CKeditor: How to build a custom plugin?

I am trying to create a custom plugin for CKeditor following this guide. I created the files as indicated (myplugin.png, myplugin.js, plugin.js) and added
CKEDITOR_CONFIGS = {
'default': {
'extraPlugins': ','.join( [ 'myplugin' ] ),
'allowedContent' : True,
}
}
to the settings.
This is the content of my plugin.js file:
CKEDITOR.plugins.add( 'myplugin', {
icons: 'myplugin',
init: function( editor ) {
// Plugin logic goes here...
editor.addCommand( 'myplugin', new CKEDITOR.dialogCommand( 'mypluginDialog' ) );
editor.ui.addButton( 'myplugin', {
label: 'My Plugin',
command: 'myplugin',
toolbar: 'insert'
});
}
});
Yet, the icon of the custom plugin still doesn't show. I can see in the browser's tools that the plugin.js file is retrieved. I made a test by removing the icon file and it didn't create any difference (no error message, no 404). I suppose then that the file is not even called or accessed. so the initialization does not even try to render the button.
Thank you for your help.
Finally, I found the answer to the problem. It comes from the way CKEditor displays the toolbars. In the guide, the custom plugin is added to the "insert" group of the toolbars. However, this one will not be visible until it is explicitely set to be displayed.
Adding the extra plugin to the default configuration is not enough, the toolbar setting has to be specified properly (if for some reason, your platform doesn't default to null). In my case, with django-ckeditor, I had to add
'toolbar': None,
to the CKEDITOR_CONFIGS.

In AEM6, How do I hide a specific component field based on pages for certain country only?

In AEM6, How do I hide a specific component field based on pages for certain country only ?
You can write custom dialog/widget plugin to do that. This is how you attach plugin to your widget:
<title jcr:primaryType="cq:Widget"
fieldLabel="Field to hide"
plugins="hideFieldPlugin"
name="./fieldToHide"
xtype="textfield" />
Next, we need to write plugin and register it:
(function ($) {
var plugin = CQ.Ext.extend(CQ.Ext.emptyFn, {
init: function (fieldToHide) {
var url = CQ.HTTP.getPath();
if (this.shouldBeHidden(url)) {
fieldToHide.hide().disable();
}
},
shouldBeHidden: function (url) {
// some logic
return true;
}
});
CQ.Ext.ComponentMgr.registerPlugin("hideFieldPlugin", plugin);
}($CQ));
JavaScript file needs to be included in Classic UI edit mode. Best way to do that is to use your own custom clientlib or use already existing category, cq.wcm.edit.
If you have more complex logic which goes across multiple widgets, you can attach plugin on dialog level and navigate to the widget objects using dialog.find method.

Set preferences in the user branch and unset them on uninstall

I created a firefox add-on with the following lib/main.js:
const {Cc,Ci} = require("chrome");
var pref = Cc["#mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
pref.setIntPref("network.http.response.timeout", 3600*24);
It wasn't accepted with the following reason:
Add-ons which change critical settings must revert the changes when disabled or uninstalled. You should also make the changes in the default, rather than the user, branch.
You need to call getDefaultBranch("") on the preferences service, and call the preference methods on the returned object rather than on the preference service directly.
To revert a preference back to the default, set by setIntPref(), I found out that I have to do this on uninstall:
pref.clearUserPref("network.http.response.timeout")
This command works fine If I call it in another test-addon. I only have to find out How to implement a command, so it is executed when the firefox-addon is uninstalled?
So how do I have to understand these comments? How do I set the preferences in a "user branch"?
Here's how I did it just now:
function clearPrefBranch(aPrefBranchName) {
var defaultBranch = Services.prefs.getDefaultBranch(null);
defaultBranch.deleteBranch(aPrefBranchName);
}
Then, just call clearPrefBranch with an argument of extensions.mypluginname (assuming you used the naming convention, and you should be able to delete all of your extension's installed preferences.
EDIT:
The code I used inside of my main.js file:
const {Cc,Ci,Cm,Cr,Cu} = require("chrome");
Cu.import("resource://gre/modules/Services.jsm");
exports.onUnload = function(aOptions, aCallbacks) {
MyPlugin.shutdown();
};
function clearPrefBranch(aPrefBranchName) {
var defaultBranch = Services.prefs.getDefaultBranch(null);
defaultBranch.deleteBranch(aPrefBranchName);
}
var MyPlugin = {
shutdown: function() {
prefLoader.clearPrefBranch('extensions.oopstab');
}
};
I solved the second part (uninstall) like this, that in my main.js I added this code at the end:
exports.onUnload = function(reason) {
//called when add-on is
// uninstalled
// disabled
// shutdown
// upgraded
// downgraded
pref.clearUserPref("network.http.response.timeout");
};
That worked on disabling and uninstalling the add-on.