Portlets

General information

A portlet is a web page component. A portlet has settings on which its functions and appearance depend.
For example, this is the Tasks portlet:

An administrator or another authorized user can add portlets to web pages.
The administrator can see the list of all the available portlets in Administration - Portal Settings - Portlets. The default settings of the portlets are also configured in this section.

Portlet settings

The appearance and the content of pages are configured by the administrator, while users can customize the interface and change the logic. The portal infrastructure allows doing it by means of personalization.
Personalization allows saving the individual settings of pages and portlets.
Personalization area - is the users, covered by the personalization settings on this page (portlet). Each portlet on a page can be in one of two areas: Shared, User. Changes in the Shared area are applied to all users; changes in the User area are applied to the current user.
Portlet visibility defines whether this portlet is visible for a specific user or for all users. Portlet visibility is defined by how it was added to the page: if it is added as Shared, the portlet is common, if it is added as User, the portlet is custom.
Property area allows controlling which personalization properties will be configured by all users and which will be configured only by the administrator, depending on the area, in which the portlet is.
Table of portlet personalization and properties correspondence

Portlet/Property Shared User
Shared The value can be changed only by the administrator or by a user with the required permissions. Separate users can change personal properties. Since the Zone, Order, Collapsed properties are User Scope, users can move, collapse and expand portlets (collapsing can be forbidden independently.
User A user can change the settings of User and Shared Scope because the portlet is not available for other users. The same as for Shared.

Example of using personalization on main pages

Main pages work as follows: the administrator creates a set of main pages, all the portlets are added to Shared Scope and look the same for all users. Any user can customize the pages, change positions and display settings of portlets, i.e. change the User Scope settings, add other portlets, while these custom changes will not be visible to other users. Thus, an administrator can set a base set of portlets on pages, which users can customize. At the same time, the shared portlets can be managed, e.g. a portlet can be deleted and it will disappear for all users

Base portlet settings

All portlets have base settings. In addition, each portlet can have custom settings.
Settings, available in the settings dialog box

Property Category Description

Name

Appearance

The text in the portlet header, if this field is left empty, the default value for this portlet type will be used

Design

Appearance

Defines the style of portlet borders. Four values are available:

  • Full
  • No title
  • Simple title
  • No

Please note, that the portlet settings buttons will be visible when viewing the page only if the first value is selected. In other cases, the portlet settings can be accessed only via the page settings

Forbid to collapse

Additional

Forbid or allow users to collapse the portlet

Name hyperlink

Additional

Specify a link for the portlet header. If the field is left empty, the default value for this portlet type will be used

Image hyperlink

Additional

Specify a link for the portlet header image. If the field is left empty, the default value for this portlet type will be used

Enable asynchronous loading

AJAX parameters

If Yes is selected, the portlet content is loaded after the page content has been loaded by means of a separate http request. Enabling this option may make the loading of pages with multiple portlets faster

Show the update button

AJAX parameters

If enabled, an additional button will be available in the portlet header, which refreshes the portlet contents without refreshing the whole page

Hidden settings:

Property Description

Closed

The property values are set to true when the user closes the portlet by pressing (Х)

Zone

The property stores the ID of the zone, in which the portlet is placed. The value is changed when the user drags and drops the portlet.

Order

The order of the portlet in the zone; a number. The value is changed when the user drags and drops the portlet.

Collapsed

The portlet is collapsed/expanded. The value is changed when the user collapses or expands the portlet.

Default portlet settings

The administrator can define the default portlet settings values, which will be used when adding a portlet to a page. For example, asynchronous loading may be enabled in the default settings of a certain portlet.

Creating a custom portlet

To create a new portlet, implement the EleWise.ELMA.Web.Mvc.ExtensionPoints.IPortlet extension point. In most cases, you can use the EleWise.ELMA.Web.Mvc.Portlets.Portlet base class, this class implements most methods and facilitates the development of new components. The new version of the Visual Studio plugin allows creating a portlet by a ready-made template. First, you need to create a project based on the web module template. Next, in the solution explorer, select a folder for the portlet and add a new element ELMA - ELMA 3 Web Portlet.

Web module example
You can read this article to get more information about creating a portlet.

After that, a file will be added to your project, which includes the view and the class itself, which implements the portlet logic. At this point you can compile your portlet and add your module to the Modules folder in the ELMA installation directory, to be able to see your portlet. Keep reading for details on each portlet class property and method.

Attention
The lifecycle of the class that implements IPortlet does not imply information storage between invocations of its methods, in other words, the class must not contain any state variables

The minimum set of methods that must be defined:

/// <summary>
/// Portlet ID
/// </summary>
public abstract Guid Uid { get; }
/// <summary>
/// Header Text
/// </summary>
public abstract string Name { get; }
/// <summary>
/// Portlet Description
/// </summary>
public abstract string Description { get; }
/// <summary>
/// Return the portlet contents
/// </summary>
/// <param name="html">Html helper</param>
/// <param name="data"></param>
/// <returns></returns>
public abstract MvcHtmlString Content(HtmlHelper html, TSettings data);
/// <summary>
/// Permission that allows a user to see the portlet. If the permission is missing, then null.
/// </summary>
/// <returns></returns>
protected abstract Permission PortletPermission();
 

An example of a simple portlet, which shows a form for starting business processes:

namespace EleWise.ELMA.Workflow.Processes.Web.Portlets
{
    /// <summary>
    /// Start Process portlet
    /// </summary>
    [Component]
    public class StartProcessPortlet : Portlet<StartProcessPortletPersonalization>
    {
        public static string UID_S = "{FCEDD0AF-0C42-4606-AE79-1C06E27E709C}";
        public static Guid UID = new Guid(UID_S);
        public StartProcessPortlet()
        {
            _profile = base.Profile as PortletProfile ?? PortletProfile.Default;
            _profile.ImageUrl = "#x12/Process.gif";
            _profile.Customizable = true;
        }
        /// <summary>
        /// Portlet ID
        /// </summary>
        public override Guid Uid
        {
            get { return UID; }
        }
        public override MvcHtmlString Content(HtmlHelper html, StartProcessPortletPersonalization data)
        {
            return RenderContentAction(html, "StartProcessPortlet", "ProcessHeader", ProcessesRouteProvider.AreaName, data);
        }
        /// <summary>
        /// Header Text
        /// </summary>
        public override string Name
        {
            get { return SR.T("Start Process"); }
        }
        /// <summary>
        /// Portlet Description
        /// </summary>
        public override string Description
        {
            get { return SR.T("Portlet for starting processes"); }
        }
        private readonly PortletProfile _profile;
        /// <summary>
        /// Additional settings in Web Application
        /// </summary>
        public override IPortletProfile Profile
        {
            get { return _profile; }
        }
        protected override Permission PortletPermission()
        {
            return WorkflowWebPermissionProvider.WorkflowAccessPermission;
        }
    }
}
 

If you need additional settings for the portlet, create a class that inherits EleWise.ELMA.Web.Mvc.Portlets.PortletPersonalization. Customizable properties are marked with the EleWise.ELMA.Web.Mvc.Portlets.PersonalizationAttribute attribute, which takes one parameter of the EleWise.ELMA.Web.Mvc.Portlets.PersonalizationScope type, which defines the area.
Example of customized property:

/// <summary>
/// Design
/// </summary>
[Category("Appearance")]
[Model.Attributes.DisplayName("Name")]
[Personalization(PersonalizationScope.Shared)]
public string Name { get; set; }
 

In this example, the Shared area is specified. Additionally, the category and display name of the property are specified, which are used when generating the settings form.

Attention
The types of the personalized properties must be serializable, PortletManager uses binary serialization
Attention
Do not redefine the properties of the PortletPersonalization class and add any logic to the code of the personalized properties. It may result in unpredictable behavior of the portlet manager

PortletManager is responsible for storing, changing and loading settings. When developing a portlet, you only need to add the respective attribute to a property.

A pop-up window is used for editing properties. There are two ways of embedding additional properties in this form. The first way is the simplest: automatic form generation. All the properties, marked with the PersonalizationAttribute attribute are automatically displayed and saved on this form. For example, the Sort By property of the Tasks portlet:

[Serializable]
public class TasksPortletPersonalization : PortletPersonalization
{
    [Personalization(PersonalizationScope.User)]
    [Category("Appearance")]
    [Model.Attributes.DisplayName("Sort By")]
    public TasksPortletSortExpression SortSettings { get; set; }
}
 

Settings dialog box:

The second method is to add a custom form to the dialog box. For this, you need to redefine the method:

/// <summary>
        /// Return the portlet settings form markup
        /// </summary>
        /// <param name="html">Html helper</param>
        /// <param name="data"></param>
        /// <returns></returns>
        public virtual MvcHtmlString Settings(HtmlHelper html, TSettings data)
 

The returned markup will be inserted into the dialog box; when saving, the standard ASP.NET MVC Binding will be used. Personalized properties must be marked with the HiddenInputAttribute attribute with the DisplayValue=false parameter. Example of the Tasks from Me portlet settings:

/// <summary>
/// Tasks from Me portlet
/// </summary>
[Component]
public class FromMeTasksPortlet : Portlet<FromMeTasksPortletPersonalization>
{
    ................
    public override MvcHtmlString Settings(HtmlHelper html, FromMeTasksPortletPersonalization data)
    {
        return RenderSettingsPartialView(html, "FromMeTasks/FromMeTasksPortletSetting", data);
    }
}
[Serializable]
public class FromMeTasksPortletPersonalization : PortletPersonalization
{
    private int daysAgo = 1;
    [Personalization(PersonalizationScope.User)]
    [Required(true)]
    [HiddenInput(DisplayValue = false)]
    public int DaysAgo
    {
        get { return daysAgo; }
        set { daysAgo = value; }
    }
    private int daysAhead = 1;
    [Personalization(PersonalizationScope.User)]
    [Required(true)]
    [HiddenInput(DisplayValue = false)]
    public int DaysAhead
    {
        get { return daysAhead; }
        set { daysAhead = value; }
    }
    private bool showCompleted = true;
    [Personalization(PersonalizationScope.User)]
    [HiddenInput(DisplayValue = false)]
    public bool ShowCompleted
    {
        get { return showCompleted; }
        set { showCompleted = value; }
    }
}
 

View Code:

@using EleWise.ELMA
@model EleWise.ELMA.BPM.Web.Tasks.Portlets.FromMeTasksPortletPersonalization
<table cellpadding="5">
    <tr>
        <td style="white-space:nowrap">@(SR.T("Task display:"))</td>
        <td style="white-space:nowrap">@Html.TextBoxFor(m => m.DaysAgo, new { style = "width: 50px" }) @(SR.T("days ago"))</td>
    </tr>
    <tr>
        <td> </td>
        <td style="white-space:nowrap">@Html.TextBoxFor(m => m.DaysAhead, new { style = "width: 50px" }) @(SR.T("days ahead"))</td>
    </tr>
    <tr>
        <td style="white-space:nowrap" colspan="2">@Html.CheckBoxFor(m => m.ShowCompleted) @(SR.T("Show completed tasks (starting with the current date)"))</td>
    </tr>
</table>

The settings form looks like this:

In addition, you can change the portlet customization on the program level, by using PortletManager API

Attention
When implementing Content and Settings methods, it would be more efficient to use PartialView rendering, than invoking the controller method, since it requires additional resources

Additional portlet development capabilities

Several portlets of the same type on one page - If the AllowMultipleInstance portlet property is false, then the user will not be able to add another portlet of this type to the page.

PortletManager - the logic of portlets is implemented in the EleWise.ELMA.Web.Mvc.Portlets.PortletManager class. It allows reusing the portlet system, which is implemented in the Project Management module.

Permission Constraints - additional constraints for working with portlets can be set with the EleWise.ELMA.Web.Mvc.Portlets.IPortletsRestrictionProvider extension point.

Default main page - upon the first start of ELMA a shared main page is created, to which portlets are added automatically. For a portlet to be added to this page, implement the EleWise.ELMA.Web.Mvc.ExtensionPoints.IDefaultHomePagePortletsProvider interface.