Портлеты

Общие сведения

Портлет – это компонент веб-страницы. Портлет имеет настройки от которых зависит его функциональность и внешний вид.

Пример: портлет Задачи:

Веб-страницы могут формироваться из произвольного набора портлетов, эту задачу может выполнять администратор или пользователь наделенный соответствующими правами.

Администратор может видеть список всех доступных в системе портлетов на странице Портлеты по адресу /ContentArea/Portlets, там же задаются настройки портлетов по умолчанию.

Настройки портлетов

Общий вид и содержимое страниц задается администратором, при этом пользователи могут настраивать интерфейс и менять логику работы. Инфраструктура портала позволяет это сделать за счет персонализации.

Персонализация позволяется сохранять настройки страниц и портлетов в долговременное хранилище с возможностью разделения индивидуальных данных.

Область персонализации – это круг пользователей, на которых распространяется изменения персонализации на данной странице (в портлете). Каждый порлет на странице может находится в одной из двух областей: Shared, User. Изменения в области Shared применяются ко всем пользователям, в области User – только к текущему пользователю.

Видимость портлета определяет является ли данный портлет видимым для отдельного пользователя или для всех пользователей. Видимость портлета определяется каким образом он добавлен на страницу, если добавлен как Shared, то портлет является общим, если как User, то – индивидуально настраиваемым.


Область свойства позволяет установить контроль над тем, какие свойства персонализации будут настраиваться всеми пользователями, а какие только администратором в зависимости от того в какой области находится портлет.

Таблица соответствия областей персонализации портлетов и свойств.

Портлет/Свойство Shared User
Shared Значение может менять только администратор или пользователь наделенный соответствующими правами. Отдельные пользователи могут менять персональные свойства. Поскольку свойства Zone, Order, Collapsed являются User Scope пользователи могут переносить портлеты, сворачивать и разворачивать (сворачивание может быть запрещено отдельно).
User Отдельный пользователь может менять настройки User и Shared Scope, поскольку портлет является недоступным для других пользователей. То же, что и для Shared.

Пример использования персонализации в главных страницах

Главные страницы работают следующим образом, администратор создает набор главных страниц, все портлеты добавляются в Shared Scope, из-за чего они выгладят для всех пользователей одинаково. Отдельно взятый пользователь может персонализировать страницы, менять расположение портлетов, настройки отображения, т.е. менять настройки User Scope, может добавлять другие портлеты, при этом персональные изменения не увидят другие пользователи. Таким образом, администратор может установить базовый набор портелтов на страницах, который пользователи могут настроить под себя, при этом остается контроль за общими портлетами, например, один из портлетов можно удалить и он исчезнет у всех пользователей

Базовые настройки портлетов

Все портлеты имеют базовый набор настроек, дополнительно к базовым настройкам каждый портлет может иметь дополнительные настройки.

Настройки доступные через диалог настроек.

Свойство Категория Описание

Название

Внешний вид

Текст в заголовке портлета. Если значение не введено, то будет показано значение по умолчанию для данного типа портлета.

Оформление

Внешний вид

Определяет стиль отображения границ портлета. Возможны четыре значения:

  • Заголовок и граница;
  • Граница;
  • Заголовок;
  • Нет.

Обратите внимание на то, что кнопки настройки портлета в режиме просмотра страницы будут видны только при первом выбранном значении, в других случаях диалог настройки портлета можно будет вызвать только из режима настройки страницы.

Запретить свертывание

Дополнительно

Запретить или разрешить пользователю сворачивать портлет.

URL-адрес названия

Дополнительно

Задает гипертекстовую ссылку в заголовке портлета, если значение не введено то будет использоваться значение по умолчанию для данного типа портлета.

URL-адрес изображения

Дополнительно

Задает адрес изображения в заголовке портлета. Если значение не введено, то будет использоваться значение по умолчанию для данного типа портлета.

Включить асинхронную загрузку

Параметры AJAX

Если выбрано значение Да, то содержимое портлета загружается после загрузки содержимого страницы по средствам отдельного http-запроса. Включение этой опции может ускорить загрузку страницы, на которой размещено много портлетов.

Показать кнопку ручного обновления

Параметры AJAX

Если включено, то в заголовке портлета появляется дополнительная кнопка, которая перезагружает содержимое портлета без перезагрузки всей страницы.

Неявные настройки:

Свойство Описание

Closed

Значения свойства устанавливается в true, когда пользователь закрывает портлет нажатием кнопки (Х).

Zone

Свойство хранит идентификатор зоны, в которой располагается портлет. Значение меняется, когда пользователь перетаскивает портлет методом drag’n’drop.

Order

Порядок расположения портлета в зоне, представляет из себя число. Значение меняется, когда пользователь перетаскивает портлет методом drag’n’drop.

Collapsed

Портлет свернут/развернут, значение меняется, когда пользователь сворачивает или разворачивает портлет.

Настройки портлетов по умолчанию

Администратор может установить значения настроек портлета по умолчанию, эти значения будут использованы при добавлении нового портлета на страницу. Например, в настройках по умолчанию для какого-то портлета можно включить асинхронную загрузку.

Как сделать свой портлет

Чтобы сделать новый портлет, следует реализовать точку расширения EleWise.ELMA.Web.Mvc.ExtensionPoints.IPortlet. Для большинства случаев можно использовать базовый класс EleWise.ELMA.Web.Mvc.Portlets.Portlet. Этот класс реализует большинство методов и по сути облегчает разработку новых компонентов. Новая версия плагина для Visual Studio 2010 позволяет создать портлет из уже готового шаблона. Для начала Вам требуется создать проект из шаблона – веб-модуль. Далее необходимо выбрать в обозревателе решений папку, в которую будет помещен портлет, и выбрать Добавить – Новый элемент – ELMA – Веб-портлет ELMA 3.

Пример веб-модуля
Вы можете обратиться к статье article-6130.html за более полным описанием шагов по созданию портлета.

После этого в Ваш проект будет добавлен файл, включающий в себя представление и сам класс, реализующий логику работы портлета. Уже сейчас Вы можете собрать свой проект, и добавить Ваш модуль в папку Modules установленной системы, для того чтобы увидеть Ваш портлет. Далее представлено более детальное описание каждого метода и свойства класса портлета.

Внимание
Жизненный цикл класса реализующего IPortlet таков, что не подразумевается никакого хранения информации между вызовами его методов, т.е. другими словами в классе не должно быть никаких переменных состояния.

Минимальный набор методов, который нужно определить, это:

        /// <summary>
        /// Идентификатор портлета
        /// </summary>
        public abstract Guid Uid { get; }
        /// <summary>
        /// Текст заголовка
        /// </summary>
        public abstract string Name { get; }
        /// <summary>
        /// Описание портлета
        /// </summary>
        public abstract string Description { get; }
        /// <summary>
        /// Вернуть содержимое портлета
        /// </summary>
        /// <param name="html">Html helper</param>
        /// <param name="data"></param>
        /// <returns></returns>
        public abstract MvcHtmlString Content(HtmlHelper html, TSettings data);
        /// <summary>
        /// Привилегия по которой пользователь может видеть портлет. Если нет привилегии то null.
        /// </summary>
        /// <returns></returns>
        protected abstract Permission PortletPermission();

Пример простого портлета, который показывает форму для запуска бизнес-процессов:

namespace EleWise.ELMA.Workflow.Processes.Web.Portlets
{
    /// <summary>
    /// Портлет "Запуск процесса"
    /// </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>
        /// Идентификатор портлета
        /// </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>
        /// Текст заголовка
        /// </summary>
        public override string Name
        {
            get { return SR.T("Запуск процесса"); }
        }
        /// <summary>
        /// Описание портлета
        /// </summary>
        public override string Description
        {
            get { return SR.T("Портлет для запуска процессов"); }
        }
        private readonly PortletProfile _profile;
        /// <summary>
        /// Дополнительные настройки веб части
        /// </summary>
        public override IPortletProfile Profile
        {
            get { return _profile; }
        }
        protected override Permission PortletPermission()
        {
            return WorkflowWebPermissionProvider.WorkflowAccessPermission;
        }
    }
}

В случае если для портлета требуются дополнительные настройки, следует создать класс наследующий EleWise.ELMA.Web.Mvc.Portlets.PortletPersonalization. Персонализируемые свойтва помечаются атрибутом EleWise.ELMA.Web.Mvc.Portlets.PersonalizationAttribute, который принимает один параметр типа EleWise.ELMA.Web.Mvc.Portlets.PersonalizationScope, который определяет область.

Пример персонализируемого свойства:

        /// <summary>
        /// Оформление
        /// </summary>
        [Category("Внешний вид")]
        [Model.Attributes.DisplayName("Название")]
        [Personalization(PersonalizationScope.Shared)]
        public string Name { get; set; }

В приведенном примере указана область Shared, кроме того, указаны категория и экранное название свойства, которые используется при генерации формы настроек.

Внимание
Типы персонализируемых свойств должны быть сериализуемыми, PortletManager использует бинарную сериализацию.
Внимание
Не следует переопределять свойства класса PortletPersonalization и вносить какую-либо логику в код персонализируемых свойств, последствием модет быть неопределенное поведение менеджера портлетов.

За хранение, изменение и загрузку настроек отвечает PortletManager, при разработке портлета достаточно пометить свойство соответствующим атрибутом.

Для редактирования свойств используется всплывающий диалог, есть два варианта встраивания дополнительный свойств в эту форму. Первый способ, он же самый простой, это автоматическая генерация формы. Все свойства помеченные атрибутом PersonalizationAttribute автоматически отображаются в этой форме, сохранение и отображение значений выполняется автоматически. Пример свойство Сортировать по для портлета Задачи:

    [Serializable]
    public class TasksPortletPersonalization : PortletPersonalization
    {
        [Personalization(PersonalizationScope.User)]
        [Category("Внешний вид")]
        [Model.Attributes.DisplayName("Сортировать по")]
        public TasksPortletSortExpression SortSettings { get; set; }
    }

Диалог настройки выгладит так:

Второй способ, это добавить в диалог свою форму, для этого следует переопределить метод:

/// <summary>
        /// Вернуть разметку формы настройки портлета
        /// </summary>
        /// <param name="html">Html helper</param>
        /// <param name="data"></param>
        /// <returns></returns>
        public virtual MvcHtmlString Settings(HtmlHelper html, TSettings data)

Возвращенная разметка будет вставлена в диалог, при сохранении будет использовать стандартный ASP.NET MVC Binding. Персонализируемые свойства должны быть помечены атрибутом HiddenInputAttribute с параметром DisplayValue=false. Пример настроек портлета Задачи от меня:

    /// <summary>
    /// Портлет Задачи от меня
    /// </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; }
        }
    }

Код представления:

@using EleWise.ELMA
@model EleWise.ELMA.BPM.Web.Tasks.Portlets.FromMeTasksPortletPersonalization
<table cellpadding="5">
    <tr>
        <td style="white-space:nowrap">@(SR.T("Отображение задач:"))</td>
        <td style="white-space:nowrap">@Html.TextBoxFor(m => m.DaysAgo, new { style = "width: 50px" }) @(SR.T("дней назад"))</td>
    </tr>
    <tr>
        <td> </td>
        <td style="white-space:nowrap">@Html.TextBoxFor(m => m.DaysAhead, new { style = "width: 50px" }) @(SR.T("дней вперед"))</td>
    </tr>
    <tr>
        <td style="white-space:nowrap" colspan="2">@Html.CheckBoxFor(m => m.ShowCompleted) @(SR.T("Отображать завершенные задачи (начиная с текущей даты)"))</td>
    </tr>
</table>

Форма настроек выглядит так:

Кроме того, можно менять персонализацию портлетов программно, для этого следует использовать PortletManager API.

Внимание
При реализации методов Content и Settings более эффективным будет использовать рендеринг PartialView, чем вызом метода контроллера, т.к. на это тратятся дополнительные ресурсы.

Дополнительные возможности для разработки портлетов

Несколько одинаковых портлетов на странице если свойство портлета AllowMultipleInstance равно false, то пользователь не сможет вывести на страницу второй такой портлет.

PortletManager – логика работы портлетов реализована в классе EleWise.ELMA.Web.Mvc.Portlets.PortletManager, с его помощью можно переиспользовать портлетную систему, что и сделано в модуле Управление проектами.

Permission Constraints – дополнительные ограничения на манипуляции с портлетами можно задать с помошью точки расширения EleWise.ELMA.Web.Mvc.Portlets.IPortletsRestrictionProvider.

Главная страница по умолчанию – при первом запуске системы ELMA автоматически создается одна общая главная страница, на которую автоматически добавляются портлеты. Чтобы портлет оказался на этой странице следует реализовать интерфейс EleWise.ELMA.Web.Mvc.ExtensionPoints.IDefaultHomePagePortletsProvider.

Прикрепленные файлы