Microsoft SharePoint — корпоративная платформа с давней историей и огромным разнообразием функций; по этой причине она не всегда может быстро реагировать на новейшие тенденции в веб-технологиях. Несмотря на широкое признание SharePoint в корпоративной среде и колоссальные усилия в расширении его функциональности, SharePoint все же отстает от современных CMS-продуктов в плане впечатляющих UI, создание которых возможно, например, на основе HTML5 и CSS3.
По моему мнению, HTML5 — это не только популярная новинка, но и технология, дающая множество преимуществ на практике: она проста в использовании, удобна, функциональна и поддерживается — более или менее — всеми современными браузерами (включая мобильные). Кроме того, HTML5 и JavaScript становятся основными технологиями в программировании настольных приложений для Windows.
Поэтому HTML5 явно заслуживает применения в SharePoint для того, чтобы сделать порталы намного более простыми в использовании. А улучшение интерфейсов SharePoint может реально помочь бизнес-пользователям, давая им возможность работать эффективнее и быстрее.
В SharePoint, к сожалению, нет встроенной функциональности HTML5, зато есть очень высокая гибкость. В этой статье я намерен продемонстрировать, насколько легко добавить HTML5-поддержку операций «drag-and-drop» («перетащить и отпустить») в SharePoint и насколько удобнее можно сделать стандартный интерфейс, как показано на рис. 1.
Рис. 1. Операции «drag and drop» в SharePoint
Чтобы реализовать это, я воспользуюсь одним из фундаментальных строительных блоков SharePoint, который также является одним из моих любимых инструментов в SharePoint, — XsltListViewWebPart и его XSL-преобразованиями (подробности см. на странице MSDN Library по ссылке bit.ly/wZVSFx).
А почему не собственный веб-фрагмент?
Как всегда, когда дело доходит до реализации, SharePoint предлагает широкий набор возможностей, и крайне важно выбрать ту из них, которая подходит вам лучше всего.
Для задачи с HTML5-поддержкой операций drag-and-drop (учитывая, что такие операции в основном используются для управления данными) многие SharePoint-разработчики, вероятно, предпочли бы создать собственный веб-фрагмент (Web Part), который в этом случае действует просто как обычный элемент управления ASP.NET: данные хранятся в стандартном списке SharePoint, извлекаются через объектную модель или элемент управления SPDataSource и визуализируются с помощью ASCX-разметки и элементов управления ASP.NET.
Просто, ясно, незатейливо..., но лучший ли это выбор?
Два года назад я так и думал. Сегодня я предпочел бы адаптировать XsltListViewWebPart, используя его XSL-преобразования. Почему я передумал?
Начиная с SharePoint 2010, почти все виды списочных представлений (кроме Calendars) отображаются через этот самый веб-фрагмент. Только вообразите: все типы данных, представления, стили и типы списков — все это огромное разнообразие данных визуализируется с использованием XsltListViewWebPart и его XSL-преобразований. Это очень гибкий и мощный функционал.
Если вы создаете собственный веб-фрагмент для рендеринга какой-либо HTML5-разметки с целью последующего отображения данных списка, то теряете всю встроенную функциональность. И исходя из моего опыта, это огромная потеря. Кстати, я еще не видел ни одного собственного веб-фрагмента, где в итоге не приходилось самому реализовать минимум половины готовой функциональности XsltListViewWebPart.
Вот что я собираюсь сделать: встроить HTML5-поддержку операций «drag and drop» в списочные представления SharePoint.
Поэтому я решил повторно использовать существующую функциональность вместо создания собственного аналогичного веб-фрагмента, который вдобавок скорее всего оказался бы намного хуже в плане гибкости и эффективности.
По сути, XsltListViewWebPart включает целый набор полезного функционала. Он интегрируется в SharePoint Designer, поддерживает все возможные соединения веб-фрагментов и корректно отображает все типы данных SharePoint. Он также поддерживает группирование, промежуточные результаты (subtotals), разбиение на страницы, контекстные меню элементов, встроенные средства редактирования, выделение элементов, индикаторы присутствия и др. У него есть контекстно-зависимый ленточный интерфейс, UI для сортировки и фильтрации, некоторые базовые стили представления и т. д. В общем, XsltListViewWebPart имеет множество полезных функций, которые было бы очень трудно реализовать заново, используя подход с собственным веб-фрагментом.
XsltListViewWebPart
XsltListViewWebPart предоставляет разработчикам много точек интеграции: программный интерфейс, CAML-интерфейс и, конечно, XSL-преобразования в сочетании с привязками параметров (parameter bindings). И не забудьте, что все эти объекты и свойства имеют представления и в Client Object Model, поэтому вы можете обращаться к своему XsltListViewWebPart даже из JavaScript или Silverlight.
XsltListViewWebPart — действительно мощный инструмент. Да, весь этот XML, специфичный для SharePoint (или XSLT) выглядит на первый взгляд немного устрашающе, но я покажу вам несколько примеров из практики, которые помогут вам разобраться в нем.
Сценарий
Прежде чем углубляться в детали реализации, позвольте мне описать сценарий в целом.
Вот что я собираюсь сделать: встроить HTML5-поддержку операций «drag and drop» в списочные представления SharePoint, чтобы пользователи могли перетаскивать ячейки из одного списка в другой. В моем примере будут задействованы списки Tasks (задачи) и Executors (исполнители), поэтому менеджер проекта сможет легко назначать и переназначать задачи, перетаскивая исполнителей в соответствующие ячейки списка Tasks.
Как вам, возможно, известно, HTML5 вводит несколько новых атрибутов для операций «drag and drop», и самый важный из них — атрибут draggable. Существует также ряд событий для обработки различных стадий процесса «drag-and-drop». Функции-обработчики этих событий можно подключать, используя соответствующие атрибуты, такие как ondragstart, ondragend и т. д. (Более подробную информацию см. в проекте W3C-спецификации HTML5 в главе 7.6 по ссылке bit.ly/lNL0FO.)
В случае моего примера это означает, что мне нужно просто использовать XSLT, чтобы добавить некоторые базовые атрибуты к определенным ячейкам списочного представления и, возможно, какие-то дополнительные собственные атрибуты для подключения значений данных (которые будут передаваться при перетаскивании). В конечном счете мне потребуется написать соответствующий код на JavaScript для функций-обработчиков.
Первые шаги
Мне нужны два списка. Список Tasks можно создать по стандартному одноименному шаблону, или просто создать собственный список и добавить несколько столбцов, в том числе обязательный «Assigned To». Второй список, Executors, я создаю как собственный список, добавляя «Executor» как столбец типа «Person or group», а затем указываю, что он обязательный, индексируемый и уникальный.
В списке Executors должны показываться только имена пользователей; таким образом, в нем не нужен стандартный столбец «Title». Чтобы скрыть этот столбец, перейдите в параметры списка, включите управление типами контента, затем перейдите к типу контента «Item», щелкните столбец Title и сделайте его скрытым, как показано на рис. 2.
Рис. 2. Скрываем столбец Title в параметрах списка SharePoint
Я заполнил эти списки образцами данных, а затем создал страницу веб-фрагмента для своей цифровой панели (dashboard), где расположил эти списки рядом друг с другом (Tasks слева и Executors справа), как показано на рис. 3.
Рис. 3. Добавление списков в цифровую панель SharePoint
Итак, у меня есть списки и данные. Теперь пришло время заняться реализацией функциональности «drag-and-drop».
SharePoint Designer
Microsoft SharePoint Designer — бесплатный инструмент для быстрой разработки приложений SharePoint. SharePoint 2010 значительно усовершенствован по сравнению с SharePoint 2007 и теперь гораздо удобнее даже для программистов. Идея в том, что вы можете задействовать SharePoint Designer GUI для генерации по-настоящему сложного XSLT-кода, а затем просто скопировать сгенерированный код и вставить в свой проект Visual Studio вместо того, чтобы вручную набирать не всегда хорошо документированный XML/XSLT. Я часто пользуюсь таким приемом в реальных проектах, и, поверьте мне, это экономит уйму времени.
Откройте SharePoint Designer и перейдите на ранее созданную страницу цифровой панели. Выделите какую-нибудь ячейку в столбце Assigned To (щелкните правой кнопкой мыши и выберите Select | Cell). А теперь фокус: в строке состояния вы видите путь к XSL-шаблону (и соответствующему HTML-тегу в этом шаблоне), который отвечает за отображение данной ячейки (рис. 4).
Рис. 4. Путь к текущему XSL-шаблону в SharePoint Designer
Эта информация может оказаться очень полезной для того, чтобы понять, какой XSL-шаблон нужно переопределить для изменения разметки ячейки. Исходный код шаблонов вы можете найти в папке 14/TEMPLATE/LAYOUTS/XSL и использовать в своих XSLT-файлах или в теге <Xsl> в XsltListViewWebPart.
Но для моих целей эти огромные и сложные XSLT-файлы не нужны. Вместо этого я могу воспользоваться функцией условного форматирования в SharePoint Designer, которая позволяет выделять определенные строки или ячейки особым форматированием в зависимости от конкретных условий. Для использования этой функции никаких специальных навыков не требуется — GUI упрощает эту задачу. Но «за кулисами» все это реализуется с помощью XSLT. Таким образом, SharePoint Designer включает своего рода готовый графический генератор XSLT, и теперь я задействую его для своих потребностей.
Выделяем ячейку, щелкаем на ленте кнопку Conditional Formatting, а затем выбираем Format Column, как показано на рис. 5.
Рис. 5. Задание условного форматирования в SharePoint Designer
Затем я создаю неправдоподобное условие — идентификатор, равный 0, как представлено на рис. 6.
Рис. 6. Диалог условного форматирования в SharePoint Designer
Далее щелкаю кнопку Set Style и выбираю произвольный стиль (например, «text-decoration: underline»). Нажимаю OK и переключаюсь на вкладку Code View, где нахожу сгенерированный код; разумеется, он содержится в теге <Xsl> элемента управления XsltListViewWebPart.
XSL-преобразования
Теперь можно модифицировать разметку ячеек «Assigned To». Столбец «Assigned To» является приемником данных, в который я перетаскиваю исполнителей, поэтому мне нужно предоставить атрибуты ondragover, ondragenter, ondragleave и ondrop, указывающие на соответствующие функции-обработчики событий JavaScript.
Код, сгенерированный SharePoint Designer, содержит XSL-шаблон со следующей сигнатурой:
<xsl:template name="FieldRef_printTableCell_EcbAllowed.
AssignedTo" match="FieldRef[@Name='AssignedTo']"
mode="printTableCellEcbAllowed" ddwrt:dvt_mode="body"
ddwrt:ghost="" xmlns:ddwrt2="urn:frontpage:internal">
Возможно, вы знаете, что XSL-шаблоны могут вызывать друг друга по имени или условию. Первый тип вызова осуществляется с применением элемента «xsl:call-template», и он очень похож на вызов функции, например на используемый в C#.
Второй вариант предпочтительнее и гораздо более гибкий: используя элемент «xsl:apply-templates», можно указывать режим и параметр (который выбирается с помощью XPath и поэтому на самом деле может содержать много элементов), не задавая имя конкретного шаблона. Для каждого элемента параметра соответствующий шаблон будет подбираться по атрибуту match. Этот подход можно рассматривать как нечто аналогичное перегрузкам в C#.
Как видно из предыдущего кода, этот шаблон будет проверять на совпадение с элементами FieldRef, где атрибут Name равен «AssignedTo». Кроме того, атрибут mode соответствующего вызова xsl:apply-template должен быть равен «printTableCellEcbAllowed». Так что этот шаблон, по сути, является перегруженной версией для стандартной функции, которая отображает значения полей. И эта перегруженная версия будет подбирать только значения поля «Assigned To».
Теперь посмотрим, что содержится внутри этого шаблона (рис. 7) (часть кода опущена для большей ясности общей картины).
Рис. 7. Содержимое XSL-шаблона
<xsl:template match="FieldRef[@Name='AssignedTo']"
mode="printTableCellEcbAllowed" ...>
<xsl:param name="thisNode" select="."/>
<xsl:param name="class" />
<td>
<xsl:attribute name="style">
<!-- ... -->
</xsl:attribute>
<xsl:if test="@ClassInfo='Menu' or @ListItemMenu='TRUE'">
<xsl:attribute name="height">100%</xsl:attribute>
<xsl:attribute name="onmouseover">OnChildItem(this)
</xsl:attribute>
</xsl:if>
<xsl:attribute name="class">
<!-- ... -->
</xsl:attribute>
<xsl:apply-templates select="." mode="PrintFieldWithECB">
<xsl:with-param name="thisNode" select="$thisNode"/>
</xsl:apply-templates>
</td>
</xsl:template>
Как видите, этот шаблон содержит два элемента xsl:param, один элемент <td>, несколько элементов xsl:attribute и элемент xsl:apply-templates, который вызывает применение некоторых более низкоуровневых шаблонов.
SharePoint 2010 значительно усовершенствован по сравнению с SharePoint 2007 и теперь гораздо удобнее даже для программистов.
Чтобы добиться реализации поддержки «drag-and-drop», я просто добавляю атрибуты этой поддержки к элементу <td>:
<td ondragover="return UserDragOver(event, this)" ondragenter=
"return UserDragOver(event, this)" ondragleave=
"UserDragLeave(event, this)" ondrop="UserDrop(event, this)">
Довольно просто, не правда ли?
В качестве альтернативы, если вы развертываете jQuery-код в среде SharePoint, можно было бы подумать о подключении обработчиков событий JavaScript, используя jQuery-метод .on.
Разметка для столбца «Assigned To» готова (обработчики я напишу чуть позже). Теперь займемся настройкой списка Executors.
Переключаемся вновь на вкладку Design View, выделяем ячейку в столбце Executors и повторяем фокус с условным форматированием для генерации XSLT-кода. Затем добавляем атрибут onstartdrag, чтобы обеспечить корректное начало операций «drag and drop» (атрибут draggable здесь не нужен, так как значения поля «Person or Group» визуализируются в виде ссылок, а у них, согласно спецификации, атрибут draggable установлен в true по умолчанию):
<td ondragstart="UserDragStart(event, this)">
Отлично. Но как отслеживать данные? Как определять, какой исполнитель перетаскивается? Очевидно, мне нужно его регистрационное имя (login name) или, что лучше, идентификатор. Выделение идентификатора в элементе TD, на мой взгляд, неоправданно сложно. Дело в том, что идентификатор пользователя доступен в XSLT для любого поля типа «Person or Group» и его можно легко извлечь простым XPath-запросом.
В этом запросе нужно указать на значения текущего элемента. Во всех стандартных шаблонах XsltListViewWebPart на текущий элемент обычно ссылаются как на параметр $thisNode. Чтобы получить идентификатор пользователя, вы указываете на атрибут параметра $thisNode, имя которого совпадает с именем столбца «Person or Group», и в конец добавляете «.id».
Вот мой запрос:
<td ondragstart="UserDragStart(event, {$thisNode/Executor.id}, this)">
Фигурные скобки позволяют включать XPath-выражение прямо в значение атрибута.
Разметка готова, и ее можно использовать прямо сейчас, но, по-видимому, было бы неплохо еще немного поработать над этим кодом и сделать его в большей мере повторно используемым.
Делаем шаблоны повторно используемыми
Вероятно, вы заметили, что шаблоны жестко связаны с именами конкретных столбцов и что эти шаблоны предназначены только для определенных списков. Однако эти шаблоны очень легко модифицировать так, чтобы их можно было повторно использовать для других списков с другими именами столбцов.
Начнем с того, что, если вы изучили представленную ранее сигнатуру шаблона, то видели следующий атрибут:
match="FieldRef[@Name='AssignedTo']"
Очевидно, он связывает шаблон со столбцом «Assigned To». Чтобы сделать этот шаблон более универсальным, можно перейти от связывания с именем к связыванию с типом, и тогда будет обнаруживаться совпадение с любым столбцом «Person or Group». Так и сделаем! Вот код:
match="FieldRef[@Type='User']"
То же изменение нужно внести во второй шаблон, где элемент FieldRef сопоставляется с внутренним именем поля «Executor».
Теперь, поскольку я могу работать с любым столбцом типа «Person or Group» и любым списком, мне нужно передавать дополнительную информацию JavaScript-обработчикам. При выполнении операции «drag and drop» требуется обновлять значение поля «Assigned To» в списке Tasks, поэтому я должен знать имя столбца и GUID списка.
Как уже упоминалось, в SharePoint XSLT есть стандартные параметры, доступные глобально. Один из таких параметров — $List, в котором хранится GUID текущего списка. А внутреннее имя поля можно легко получить из совпадающего элемента FieldRef.
Итак, я буду передавать GUID списка и внутреннее имя столбца в обработчик UserDrop следующим образом (атрибуты ondragenter, ondragover и ondragleave опущены для ясности):
<td ... ondrop="UserDrop(event, this, '{$List}', '{./@Name}'">
Точка («.») указывает на текущий элемент FieldRef (ранее найденный шаблоном).
SharePoint Designer включает своего рода готовый графический генератор XSLT.
Далее мне нужно избавиться от строки «Executor» в параметре id в XSLT списка Executors, используя следующий код:
<td ondragstart="UserDragStart(event, {$thisNode/@*[name()=
concat(current()/@Name, '.id')]}, this)">
Теперь шаблоны готовы и являются повторно используемыми. С этого момента я перехожу к написанию соответствующего кода на JavaScript для реализации обработчиков.
Написание обработчиков на JavaScript
Хотя нужно написать несколько разных обработчиков, большинство из них элементарны, и все они довольно очевидны.
Обычно я советую помещать этот код в отдельный JavaScript-файл. И, как правило, лучше использовать для его создания Visual Studio, так как в этом случае вы можете задействовать преимущества IntelliSense. Однако в некоторых ситуациях разумнее помещать этот код в XSLT, переопределяя с этой целью корневой шаблон (match="/"). Это позволяет использовать некоторые переменные и параметры XSLT в коде на JavaScript, а также избавляет от забот с развертыванием JavaScript-файлов.
Рассмотрим код обработчиков DragStart, DragEnter, DragOver, DragLeave и Drop.
В обработчике UserDragStart нужно инициализировать передачу данных. То есть вы должны сохранять перетаскиваемые данные в специальном HTML5-объекте DataTransfer, например:
function UserDragStart(e, id, element) {
e.dataTransfer.effectAllowed = 'copy';
e.dataTransfer.setData('Text', id + '|' + element.innerHTML);
}
Заметьте, что идентификатор пользователя — не единственные передаваемые данные. Я также добавил вложенный HTML-элемент <td>, чтобы избежать обновления страницы после отпускания данных (детали см. в коде обработчика UserDrop на рис. 8).
Рис. 8. Обработчик событий Drop
function UserDrop(e, toElement, listGuid, columnName) {
// Завершение обработки события
if (e.stopPropagation)
e.stopPropagation();
// Предотвращаем операцию браузера по умолчанию
if (e.preventDefault)
e.preventDefault();
// Удаляем стили из заполнителя (placeholder)
toElement.style.backgroundColor = '';
//toElement.className = '';
// Атрибут iid подключается к элементу tr через SharePoint
// и содержит идентификатор текущего элемента
var elementId = toElement.parentNode.getAttribute('iid').split(',')[1];
// Передаваемые данные
var data = e.dataTransfer.getData('Text');
var userId = data.split('|')[0];
var userLinkHtml = data.split('|')[1];
// Задаем значение поля, используя SharePoint
// EcmaScript Client Object Model
var ctx = new SP.ClientContext.get_current();
var list = ctx.get_web().get_lists().getById(listGuid);
var item = list.getItemById(elementId);
item.set_item(columnName, userId);
item.update();
// Асинхронный вызов
ctx.executeQueryAsync(
function () { toElement.innerHTML = userLinkHtml; },
function (sender, args) { alert('Drag-and-drop failed.
Message: ' + args.get_message()) }
);
return false;
}
В данном случае обработчики для событий DragEnter и DragOver идентичны, поэтому я использую для них одну функцию. В этих событиях вы должны указывать, что пользователь может отпустить здесь перетаскиваемые данные. Согласно спецификации, для этой цели следует вызывать метод event.preventDefault (если применим), а затем возвращать false.
Обработчик DragEnter/DragOver — отличное место для применения собственных стилей к заполнителю «drag-and-drop», чтобы уведомлять пользователя о том, что он может отпустить здесь перетаскиваемые данные. Чтобы упростить пример, я воспользуюсь подставляемыми в строку CSS-стилями, но в реальном проекте я бы порекомендовал применять CSS-классы (см. строки комментариев в коде на рис. 9).
Рис. 9. Обработчики событий DragOver и DragLeave
function UserDragOver(e, toElement) {
// Выделяем заполнитель
toElement.style.backgroundColor = '#efe';
// toElement.className = 'userDragOver';
// Обозначаем возможность отпускания
if (e.preventDefault)
e.preventDefault();
e.dataTransfer.dropEffect = 'copy';
return false;
}
function UserDragLeave(e, toElement) {
// Удаляем стили
toElement.style.backgroundColor = '';
// toElement.className = '';
Очевидно, в DragLeave мне нужно удалять ранее примененные стили, как показано на рис. 9.
При обработке события Drop в коде на рис. 8 необходимо выполнить две важные операции.
- Применить изменения. Используя SharePoint EcmaScript Client Object Model, присвойте значению поля переданный идентификатор пользователя.
- Замените внутренний HTML-код в текущей ячейке (TD) кодом из переданного HTML, чтобы изменения вступили в силу без обновления страницы.
Теперь все обработчики реализованы, и вы можете развертывать JavaScript. Делать это можно по-разному: настроить эталонную страницу (master page), использовать элемент управления Delegate, создать собственную операцию с Location, установленным в «ScriptLink», или, как уже упоминалось, включить JavaScript прямо в XSLT.
Самый простой способ — настроить файл эталонной страницы с помощью SharePoint Designer, так как это не требует никаких специфических навыков. Но как разработчик вы скорее всего предпочтете собрать воедино все эти изменения в виде JavaScript и XSLT и создать развертываемое решение. Так и сделаем!
Создание развертываемого решения
Чтобы создать готовое к использованию решение, которое вы можете отправить своим заказчикам, нужно выполнить несколько очень простых операций.
- Откройте Visual Studio создайте Empty SharePoint Project. В диалоге параметров проекта выберите «deploy as a farm solution».
- Добавьте в свой проект SharePoint «Layouts» Mapped Folder и включите в него три новых файла: UserDragHandlers.js, UserDragProvider.xsl и UserDragConsumer.xsl.
- Вставьте в соответствующие файлы ранее созданный JavaScript- и XSLT-код (сгенерированный в SharePoint Designer).
- Добавьте элемент проекта Empty Element, откройте Elements.xml и вставьте в него следующий код:
<CustomAction ScriptSrc="/_layouts/SPDragAndDrop/UserDragHandlers.js" Location="ScriptLink" Sequence="10" />
Это приведет к развертыванию данной ссылки на ваш JavaScript-файл на всех страницах сайта. - Наконец, добавьте Event Receiver к Feature1 (которая была создана автоматически, когда вы добавили Empty Element), раскомментируйте метод FeatureActivated и вставьте в него такой код:
var web = properties.Feature.Parent as SPWeb;
SPList list;
SPView view;
list = web.Lists["Tasks"];
view = list.DefaultView;
view.XslLink = "../SPDragAndDrop/UserDragConsumer.xsl";
view.Update();
list = web.Lists["Executors"];
view = list.DefaultView;
view.XslLink = "../SPDragAndDrop/UserDragProvider.xsl";
view.Update();
И на этом все! Весьма просто, не так ли? Теперь, если создаете и развертываете решение с ранее созданными списками Tasks и Executors, а затем создаете цифровую панель, содержащую исходные представления каждого из них, ваша цифровая панель будет поддерживать удобную функциональность «drag-and-drop».
Поддержка браузеров
К настоящему времени почти все основные браузеры, кроме Opera, поддерживают HTML5-функциональность «drag and drop». Я проверил это в Internet Explorer 9.0.8112.16421, Chrome 16.0.912.75 и Firefox 3.6.12 — все они полностью совместимы с описанным решением. Полагаю, что некоторые более старые версии этих браузеров тоже будут работать. В принципе, решение должно было бы работать и в Safari, но на момент написания этой статьи в его реализации HTML5-поддержки «drag-and-drop» отмечались какие-то странные ошибки, которые не позволили работать этому решению ожидаемым образом.
Что дальше?
В моем решении ни XSLT-шаблоны, ни JavaScript не содержат никакого специфического для списков кода — нет «зашитых» в код GUID, имен, заголовков и прочих подобных вещей. Поэтому данные преобразования потенциально могли бы быть применимы к любым спискам или библиотекам документов, а вы могли бы добавлять поддержку «drag-and-drop» к любому столбцу типа «Person or Group». Разве это не здорово?
Очевидно, что аналогичным образом можно сделать перетаскиваемыми и другие типы столбцов, так что вы могли бы создать решение, где перетаскиваемыми были бы все ячейки во всех списках SharePoint и на страницах цифровой панели пользователи свободно перетаскивали бы ячейки между списками, что также очень удобно.
К настоящему времени почти все основные браузеры, кроме Opera, поддерживают HTML5-функциональность «drag and drop».
На основе перетаскивания строк можно было бы реализовать очень интересную задачу. Идея в основном та же, но для получения правильного шаблона вы должны были бы использовать условное форматирование строк. Это можно было бы использовать для связывания элементов списков, чтобы, например, изменять их порядок. Скажем, вы могли бы сделать ссылку «Recycle Bin» из меню быстрого запуска такой, чтобы она работала как приемник операции «drag-and-drop», и это было бы интересным способом удаления элементов из списков.
Вы можете сделать очень многое. Просто размышляйте, экспериментируйте и пробуйте — ваш портал SharePoint станет гораздо более дружественным к пользователям.