понедельник, 18 июня 2012 г.

SharePoint: Столбцы метаданных. Часть 1: Использование веб-служб в DisplayPattern

Однажды возникла необходимость хранения в списках SharePoint данных о … самих же списках.
Первая идея, которая приходила в голову, а именно, воспользоваться стандартным набором типов данных SharePoint претерпевала всё больший крах по мере последовательного рассматривания в качестве подходящего для решения задачи того или иного типа данных:

Текст (однострочный, многострочный)
Значение: ID списка
Недостатки:
  • Неприглядность со стороны конечного пользователя.
  • Неактуальность данных.
Возникающие нелепости: «Информацию о товарах найдёте в списке с ID {30431E5A-7D75-438f-B786-716690DBDAE2}»

Гиперссылка или рисунок
Значение: 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 == nullreturn 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(&quot;]]> </HTML>
  <HttpVDir/>
  <HTML ><![CDATA[&quot;, &quot;]]></HTML>
  <Column />
  <HTML><![CDATA[&quot;, &quot;div_div]]></HTML>
  <Property Select="Name"/>
  <Field Name="ID"/>
  <HTML>
    <![CDATA[&quot;);"></iframe>]]>
  </HTML>
  <HTML>
    <![CDATA[<div id="div_div]]>
  </HTML>
  <Property Select="Name"/>
  <Field Name="ID"/>
  <HTML>
    <![CDATA["></div>]]>
  </HTML>
</RenderPattern>

Результат стараний выглядит так:

SharePoint сustom field type in ListViewWebPart
(Кликабельно)

Во второй части статьи будет рассматриваться отображение значений столбцов в 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.

Комментариев нет:

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