SharePoint. Динамическая настройка видимости и возможности редактирования полей в зависимости от контекста

в 15:55, , рубрики: sharepoint, метки:

Данная заметка поможет решить например такие задачи как:

  • раздать права на поля списков*
  • управлять видимостью полей с помощью рабочего процесса
  • и т.п. манипуляции с полями на формах создания, просмотра и редактирования элементов списков SharePoint.

Intro

SharePoint предоставляет богатые возможности для разграничения прав доступа. Можно раздавать уникальные права на узлы, на списки внутри узлов, на элементы внутри списков. Но как бы хорошо не было всегда немного не хватает. Хорошо бы еще раздавать права на поля элементов списков — такой возможности “из коробки” не предусмотрено. Реализации этой хотелки и посвящена заметка.

Варианты реализации и их большое ограничение

Есть несколько вариантов раздать права на поля списка:

  • сделать свои формы редактирования (долго, сложно и часто overhead)
  • задействовать JS (простое решение, есть готовые JS-библиотечки)
  • управлять выводом полей на стандартных формах с помощью своего ListFieldIterator (это не сложнее а может и проще решения с JS, именно этот способ и рассмотрим).

Все варианты (без дополнительных мер) не применимы для случаев, когда требуется высокий уровень секретности. Если поле не выводится на форме, пользователь может увидеть его в представлении списка или выгрузить список в Excel. Если у пользователя есть права на список он может получать/редактировать данные с помощью специальных утилит. Продвинутые товарищи могут редактировать элементы списков прямо в браузере — набирая несложные JS-команды в отладчике.

Управление выводом полей с помощью ListFieldIterator

Теория

Шаблон по которому рисуются формы списков находится в файле DefaultTemplates.ascx (папка CONTROLTEMPLATES) и называется ListForm (Листинг 1).

<SharePoint:RenderingTemplate id="ListForm" runat="server">
	<Template>
		<span id='part1'>
			<SharePoint:InformationBar runat="server"/>
			<div id="listFormToolBarTop">
			<wssuc:ToolBar CssClass="ms-formtoolbar" id="toolBarTbltop" RightButtonSeparator=" " runat="server">
					<Template_RightButtons>
						<SharePoint:NextPageButton runat="server"/>
						<SharePoint:SaveButton runat="server"/>
						<SharePoint:GoBackButton runat="server"/>
					</Template_RightButtons>
			</wssuc:ToolBar>
			</div>
			<SharePoint:FormToolBar runat="server"/>
			<SharePoint:ItemValidationFailedMessage runat="server"/>
			<table class="ms-formtable" style="margin-top: 8px;" border="0" cellpadding="0" cellspacing="0" width="100%">
			<SharePoint:ChangeContentType runat="server"/>
			<SharePoint:FolderFormFields runat="server"/>
			<SharePoint:ListFieldIterator runat="server"/>
			<SharePoint:ApprovalStatus runat="server"/>
			<SharePoint:FormComponent TemplateName="AttachmentRows" runat="server"/>
			</table>
			<table cellpadding="0" cellspacing="0" width="100%"><tr><td class="ms-formline"><img src="/_layouts/images/blank.gif" width='1' height='1' alt="" /></td></tr></table>
			<table cellpadding="0" cellspacing="0" width="100%" style="padding-top: 7px"><tr><td width="100%">
			<SharePoint:ItemHiddenVersion runat="server"/>
			<SharePoint:ParentInformationField runat="server"/>
			<SharePoint:InitContentType runat="server"/>
			<wssuc:ToolBar CssClass="ms-formtoolbar" id="toolBarTbl" RightButtonSeparator=" " runat="server">
					<Template_Buttons>
						<SharePoint:CreatedModifiedInfo runat="server"/>
					</Template_Buttons>
					<Template_RightButtons>
						<SharePoint:SaveButton runat="server"/>
						<SharePoint:GoBackButton runat="server"/>
					</Template_RightButtons>
			</wssuc:ToolBar>
			</td></tr></table>
		</span>
		<SharePoint:AttachmentUpload runat="server"/>
	</Template>
</SharePoint:RenderingTemplate>

Листинг 1. Шаблон по которому рисуются формы списков — ListForm

Контрол
<SharePoint:ListFieldIterator runat=«server»/>
отвечает за вывод полей. Идея заключается в том, что бы сделать свой ListFieldIterator и подключить его для нужных списков.

Можно сделать несколько ListFieldIterator-оров для разных списков, можно даже для каждой формы (NewForm.aspx, DispForm.aspx, EditForm.aspx) одного и того же списка назначить свой итератор.

How to

1. Сделать наследника ListFieldIterator — Листинг 2.

public class MyFieldIterator : ListFieldIterator
{
    protected override void CreateChildControls()
    {
        // массивы названий полей можно получать динамически
        // здесь, для примера, они прохардкожены

        var readOnlyFieldsInternalNames = new string[] { "Title", "Status" };
        var excludeFieldsInternalNames = new string[] { "SalesPoint" };


        for (int ii = 0; ii < base.Fields.Count; ii++)
        {
            var currentFiledInternalName = base.Fields[ii].InternalName;

            if (base.IsFieldExcluded(base.Fields[ii]) || 
                                excludeFieldsInternalNames.Contains(currentFiledInternalName))
                continue;


            var fieldIterator = new ListFieldIterator()
            {
                ControlMode = readOnlyFieldsInternalNames.Contains(currentFiledInternalName) ? 
                                SPControlMode.Display : 
                                SPContext.Current.FormContext.FormMode,

                ExcludeFields = string.Join(";#", base.Fields.Cast<SPField>()
                            .Where(ff => ff.InternalName != currentFiledInternalName)
                            .Select(ff => ff.InternalName).ToArray())
            };

            this.Controls.Add(fieldIterator);
        }
    }
}

Листинг 2. Наследник ListFieldIterator который прячет и переводит в ReadOnly заданные поля

Ничего сложного. Здесь для каждого поля, которое нужно отобразить, создается свой ListFieldIterator с нужным ControlMode. В ExcludeFields передается строка содержащая поля которые нужно исключить, т.е. все кроме текущего.

2. Сделать файл MyListForm.aspx и положить его в папку CONTROLTEMPLATES
В MyListForm.aspx скопируйте весь <SharePoint:RenderingTemplate id=«ListForm» runat=«server»>, замените id=«ListForm» на id=«MyListForm”, <SharePoint:ListFieldIterator runat=»server"/> на <My:MyFieldIterator runat=«server»> — Листинг 3.

...
<%@ Register TagPrefix="My" Assembly="$SharePoint.Project.AssemblyFullName$" namespace="My" %>
<SharePoint:RenderingTemplate id="MyListForm" runat="server">
…
            <%--<SharePoint:ListFieldIterator runat="server"/>--%>
            <My:MyFieldIterator  runat="server" />
...
</SharePoint:RenderingTemplate>

Листинг 3. Свой шаблон вывода формы списков

Отметим, что MyListForm.aspx обязательно должен лежать в корне CONTROLTEMPLATES, если положить в под-папку не взлетит.

3. Указать для какой формы использовать шаблон MyListForm.
Для этого в ListDefinition укажите Template для нужной формы — Листинг 4.

...
    <Forms>
      <Form Type="DisplayForm" Url="DispForm.aspx" SetupPath="pagesform.aspx" WebPartZoneID="Main" />
      <Form Type="EditForm" Url="EditForm.aspx" SetupPath="pagesform.aspx" WebPartZoneID="Main" Template="MyListForm" />
      <Form Type="NewForm" Url="NewForm.aspx" SetupPath="pagesform.aspx" WebPartZoneID="Main" Template="MyListForm"/>
...

Листинг 4. ListDefinition с указанием шаблонов для вывода форм

Заключение

Теперь вы знаете как управлять отображением полей на стандартных формах списков SharePoint.

Пример можно развить в нечто более интересное. Например мы сделали активность для рабочего процесса Nintex которая в PropertyBag элемента списка пишет правила — какие поля показывать, какие скрывать и для каких групп пользователей. Потом наш ListFieldIterator читает и применяет эти настройки. Таким образом у пользователей появилась возможность создавать более сложные рабочие процессы.

Источники

spuser.blogspot.ru/2011/04/how-to-easily-implement-sharepoint.html

Автор: Alex_BBB

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js