Однажды возникла необходимость хранения в списках SharePoint данных о … самих же списках.
Первая идея, которая приходила в голову, а именно, воспользоваться стандартным набором типов данных SharePoint претерпевала всё больший крах по мере последовательного рассматривания в качестве подходящего для решения задачи того или иного типа данных:
Значение: ID списка
Недостатки:
- Неприглядность со стороны конечного пользователя.
- Неактуальность данных.
Гиперссылка или рисунок
Значение: URL списка и его название
Недостатки:
- Неактуальность данных.
- Отсутствие использования множественных значений.
Возникающие нелепости: «Список сотрудников уже давно доступен под другим URL, список контрагентов давно переименован в список “Клиенты”, а библиотеки с описаниями товаров год как нет»
Бизнес-данные
Значение: Полученная информация о списке из БД SharePoint
Недостаток: Отсутствие типа данных в WSS.
Возникающие нелепости: «Мы используем WSS и знать не знаем про бизнес-данные»
Похоже, что подходящим решением задачи будет создание настраиваемого типа данных.
Технология создания настраиваемых типов столбцов подробно описана на сайте Microsoft - Типы настраиваемых полей. Здесь же хотелось бы остановиться на двух ключевых моментах в решении, а именно на отображении значений столбцов в шаблонах отображения полей (RenderPattern) в файле FLDTYPES_*.XML:
- DisplayPattern (порой, самый краеугольный камень в создании настраиваемых типов столбцов)
- HeaderPattern (фильтрация значений столбца настраиваемого типа данных в ListViewWebPart )
Первый и самый важный ключевой момент в решении данной задачи - это отображение значений столбцов в RenderPattern под названием DisplayPattern. Вполне разумно в данном шаблоне отображать значение(я) столбца в виде веб-ссылки(ок) на список(ки), значение которого(ых) задано(ы) в данном столбце (далее использование в единственном числе). URL выводимой веб-ссылки будет URL представления списка по умолчанию, а её текст – название этого списка в режиме реального времени.
Разметки CAML для решения такой задачи будет явно недостаточно. Да и чтоб не нагромождать саму разметку в шаблоне лучше воспользоваться вызовами веб-служб SharePoint из JavaScript. Получить информацию о списке посредством веб-служб SharePoint можно применяя метод GetList стандартной веб-службы Lists.asmx. Ниже приведена функция JavaScript, которая возвращает название списка и URL его представления по умолчанию с использованием данного метода:
function GetListData(weburl, listName) { // weburl – URL узла, содержащий список // listName - ID списка var resArray = new Array(2); var a = new ActiveXObject("Microsoft.XMLHTTP"); if (a == null) return null; a.Open("POST", weburl + "/_vti_bin/Lists.asmx", false); a.setRequestHeader("Content-Type", "text/xml; charset=utf-8"); a.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/sharepoint/soap/GetList"); var d = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" + "<soap:Body>" + "<GetList xmlns=\"http://schemas.microsoft.com/sharepoint/soap/\">" + "<listName>" + listName + "</listName>" + "</GetList>" + "</soap:Body>" + "</soap:Envelope>"; a.Send(d); if (a.status != 200) { resArray[0] = "err"; } else { // получим Url представления списка по умолчанию (можно ссылаться и на // страницу параметров списка – непринципиально важно) и название списка resArray[0] = a.responseXML.selectSingleNode("//List").getAttribute("DefaultViewUrl"); resArray[1] = a.responseXML.selectSingleNode("//List").getAttribute("Title"); } return resArray; }
Исходя из определения функции ясно, что значение столбца должно содержать в себе ID списка и URL узла, в котором находится сам список. Оно может быть представлено в следующем виде: [URL узла][Разделитель][ID списка].
Примерная (все зависит, ведь, от личных пожеланий) функция вывода единичного значения столбца в шаблоне отображения полей DisplayPattern:
function GetListDataInDiv(siteurl, val, divid) { // siteurl – URL текущего семейства узлов // val – значение поля // divid – id блочного элемента, в котором осуществяляется вывод значения поля var resStr = ""; var sVals = val.split(';'); // ; - разделитель значений WebUrl и ListID // получим данные о списке var res = GetListData(sVals[0], sVals[1]); if (res[0] != "err") { resStr = "<tr>"; resStr += "<td Class=\"ms-vb2\">" + GetWebTitle(sVals[0]) + "</td>"; resStr += "<td Class=\"ms-vb2\"><a href=\"" + res[0] + "\">" + res[1] + "</a></td>"; resStr += "</tr>"; } var div = document.getElementById(divid); if (resStr.length > 0) { // вывод значения в виде таблицы div.innerHTML = "<table class=\"ms-listviewtable\"><tr><th> " + GetResLabelTitle("MetaControl_WebColumnTitle") + "</th><th> " + GetResLabelTitle("MetaControl_ContentTypeColumnTitle") + " </th></tr>" + resStr + "</table>"; } return resStr; }
Функция GetResLabelTitle, используемая в приведенной функции, возвращает значение по заданному ключу данных, хранящихся в .resx-файле. Её реализация сводится к написанию пользовательской веб-службы (по методике, указанной в Пример: создание пользовательской веб-службы) и вызова оной из JavaScript аналогично веб-службе Lists.asmx. Функция GetWebTitle возвращает текущее название узла и аналогична функции GetListData с использованием соответствующей веб-службы Webs.asmx и метода GetWeb.
Вызвать функцию GetListDataInDiv необходимо, когда веб-страница полностью загружена, тогда она корректно выведет таблицу с данными значения столбца. Здесь лучше всего воспользоваться событием onload тэга iframe.
Таким образом, RenderPattern под названием DisplayPattern будет выглядеть, опять же примерно, следующим образом:
<RenderPattern Name="DisplayPattern"> <HTML><![CDATA[<iframe height="0" width="0" onload="GetListDataInDiv("]]> </HTML> <HttpVDir/> <HTML ><![CDATA[", "]]></HTML> <Column /> <HTML><![CDATA[", "div_div]]></HTML> <Property Select="Name"/> <Field Name="ID"/> <HTML> <![CDATA[");"></iframe>]]> </HTML> <HTML> <![CDATA[<div id="div_div]]> </HTML> <Property Select="Name"/> <Field Name="ID"/> <HTML> <![CDATA["></div>]]> </HTML> </RenderPattern>
Результат стараний выглядит так:
![]() |
| (Кликабельно) |
Во второй части статьи будет рассматриваться отображение значений столбцов в RenderPattern под названием HeaderPattern, фильтрация значений столбца в ListViewWebPart. Хотя сейчас уже имеет место также «его выход». Все JavaScript функции будут храниться в одном файле Metadata.js, ссылку на который вполне уместно объявить именно в этом шаблоне отображения полей:
<RenderPattern Name=" HeaderPattern "> <HTML><![CDATA[<script src="/_layouts/Metadata.js"></script>]]></HTML> </RenderPattern>
P.S. см. также - SharePoint: Расширенная подстановка - Вывод значений в ListViewWebPart с использованием jQuery + JSON.
English version - SharePoint Metadata field. Part 1: Web Services in DisplayPattern.

Комментариев нет:
Отправить комментарий