Пропустить до основного содержимого

Статьи

Найти
Домашняя
Заказчикам
Разработчикам
Администраторам
Русская UG
Форум на GotDotNet
Поиск
  

Российское сообщество Sharepoint > Статьи
Библиотека с раздельным доступом к элементам
Здесь размещён действующий пример библиотеки документов, доступ к которым имееют администратор и пользователь, загрузивший документ.
Соответствующие разрешения устанавливаются рабочим процессом, созданным при помощи Sharepoint Designer 2007.
Поиск решений в интернете при установленном пакете локализации

Оригинал в моем блоге, http://mossdevel.blogspot.com/2009/07/sharepoint-2007-custom-fields-and-edit.html 

Возникла проблема: при добавлении  Custom Field в библиотеку документов появилось предупреждение:

В большинстве клиентских программ данный тип поля не допускает изменения и может препятствовать сохранению документов в этой библиотеке.

Поиск по тексту сообщения результатов не дал, тогда пришлось найти, откуда WSS берет этот nекст. Оказалось - из файла

12\Config\Resources\wss.ru-ru.resx и ключа fldedit_FieldTypeWarningForDocLibSupport.

В файле 12\Config\Resources\wss.resx текст сообщения на английском выглядит так:

This field type cannot be edited from most client programs and might block the programs from saving documents to this library.

И решение проблемы сразу нашлось вот здесь: http://nickgrattan.wordpress.com/2008/01/06/sharepoint-2007-custom-fields-and-edit-property-on-server/

Уникальное значение поля при вводе.

Sharepoint Unique Column (PK) : Using event handler

Оригинал тут:

http://jpy-tech.com/post/2009/02/05/Sharepoint-Unique-Column-(PK)-Using-event-handler.aspx

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

Решение: Написать EventHandler и внести логику для проверки введенного значения.  

Исходный код немного кривоват так что используйте поправленный мною вариант.

Пояснения, после установки этого обработчика, достаточно будет добавить в описание поля метку [$UNIQUE$] и это поле будет проверяться на уникальность, конечно вы можете изменить это значение на свое и использовать более удобное для чтения именование.

 

const string _QUERY = @"<Where><Eq><FieldRef Name=""{0}"" /><Value Type=""Text"">{1}</Value></Eq></Where>"; 
public override void ItemAdding(SPItemEventProperties properties) 
{ 
using (SPWeb web = properties.OpenWeb()) 
    { 
/*get the current list*/ 
        SPList list = web.Lists[properties.ListId]; 
string columnName = ""; 
foreach (SPField fld in list.Fields) 
        { 
if (fld.Description.Contains("[$UNIQUE$]")) 
            { 
                columnName = fld.InternalName; 
break; 
            } 
        }

if (properties.AfterProperties[columnName] != null) 
        { 
string currentValue = properties.AfterProperties[columnName].ToString(); 
            SPQuery _query = new SPQuery(); 
            _query.Query = string.Format(_QUERY, columnName, currentValue); 
            SPListItemCollection itemsWithSameValue = list.GetItems(_query); 
if (itemsWithSameValue.Count > 0) 
            { 
                properties.Cancel = true; 
                properties.ErrorMessage = "There is already an item with the same value(" + currentValue + ") for the column / Field(" + columnName + ") in this list."; 
            } 
        } 
    } 
}

Вывод дочернего списка на странице DispForm.aspx

Задача:

Предположим, есть два списка: «Проекты» и «Задачи». В списке "Задачи" есть поле "проект" типа подстановка. В это поле попадают названия проектов из списка "Проекты".

На странице просмотра проекта (DispForm.aspx) нужно показать задачи связанные с просматриваемым проектом.

 

Идея состоит в том, что бы вывести на страницу DispForm.aspx  веб-часть со списком «Задачи» и отфильтровать его по нужному проекту.

 

Попытка использовать самописную веб-чать фильтр (на основе интерфейса ITransformableFilterValues)  провалилась . Веб-часть фильтра работает корректно, но не на странице DispForm.aspx.В этом случае веб-чать выводящая список к которой проводится подключение фильтра выводит следующий текст:

"Ошибка веб-части: На этой странице превышен порог получения данных для присоединенных веб-частей. Попробуйте отсоединить одну или несколько веб-частей."

 

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

 

Веб-части списков поддерживают передачу параметров фильтрации через URL.

При открытии страницы DispForm.aspx с помощью JavaScript мы будем добавлять в URL необходимые параметры.

 

Прежде всего, напишем объект помогающий работать с GET-параметрами

 

LocationHelper = function() { }

LocationHelper.prototype = {

    _GetParams: function(value) {

        var crumbs, crumb, hash = {};

        crumbs = value.split('&');

        for (var i = 0; i < crumbs.length; i++) {

            if (crumbs[i] === '')

                continue;   

            crumb = crumbs[i].split('=', 2);

            crumb[0] = decodeURIComponent(crumb[0]);

            if (crumb.length == 0)

                crumb.push('');    

            else

                crumb[1] = decodeURIComponent(crumb[1]);

            crumb[1] = crumb[1].split(',');

 

            hash[crumb[0]] = crumb[1];

        }

        return hash;

    },

 

    ParamsToStr: function(params) {

        var str = '';

        for (var prop in params) {

            if (params.hasOwnProperty(prop)) {

                str = str + '&' + prop + '=' + params[prop];

            }

        }

        return str.slice(1);

    },

 

    GetParams: function(str) {

        var hash = {};

 

        if (str == undefined || str == null) {

            hash = this._GetParams(

                window.location.search.replace('?', ''));

        }

        else if (str.indexOf('?') > 0) {

            hash = this._GetParams(str.replace(/^[\s\S]*[?]/, ''));

        }

       

        return hash;

    },

 

    ChangeParams: function(params) {

        var s = '?' + this.ParamsToStr(params);

        if (window.location.search != s) {

            window.location.search = s;

        }

    },

 

    AddParams: function(params) {

        var curParams = {};

        if (window.location.search !== '') {

            curParams =

                this._GetParams(

                    window.location.search.replace('?', ''));

        }

 

        for (var prop in params) {

            if (params.hasOwnProperty(prop)) {

                curParams[prop] = params[prop];

            }

        }

 

        this.ChangeParams(curParams);

    }

}

 

Вот так его можно использовать:

 

var LHelper = new LocationHelper();

var params = LHelper.GetParams();

alert(params['ID']);

 

Ссылка для фильтра имеет следующий вид:

FilterField1=%5Fx041f%5F%5F…F%5Fx0435%5F%5Fx04&FilterValue1=%D0%91%D0%95%...

Где FilterField1 это поле по которому производится фильтрация, а   FilterValue1 это значение фильтра.

 

Что бы получить FilterField1 сделайте фильтрацию списка вручную и скопируйте соответствующую строку из адресной строки браузера.

FilterValue1 (для данной задачи) это название проекта. Следующий простенький скрипт поможет получить строковое значение поля списка, если будет размещен на странице со стандартной формой просмотра элемента.

 

    var GetListItemValue = function(fieldName) {

        // mootools needed

       

        var trs = $$('table.ms-formtable')[0].getElements('tr');

        var value = null;

 

        for (var i = 0; i < trs.length; i++) {

            var h3 = trs[i].getElements('h3.ms-standardheader')[0];

            if (h3.get('text').clean() == fieldName) {

                value =

                    trs[i].getElements('td.ms-formbody')

                        .get('text').toString().clean();

                break;

            }

        }

        return value;

    }

 

Для работы скрипта требуется JavaScript библиотека mootools.

 

Собирем все вместе. Разместите на странице DispForm.aspx веб-часть с дочерним списком «Задачи».

Добавить веб-часть на страницу DispForm.aspx можно, если ввести в адресную строку javascript:MSOTlPn_ShowToolPane('2') и нажать ентер (я себе сделал закладку).

Между двумя этими веб-частями разместите веб-часть редактора содержимого со следующим кодом:

 

<script src="/CustomControls/mootools-1.2.2-core-yc.js" type="text/javascript"></script>

<script type="text/javascript">

    var GetListItemValue = function(fieldName) {

        // Код см. выше

       

    }

 

    LocationHelper = function() { }

    LocationHelper.prototype = {

        // Код см. выше

       

    }

 

 

    var filterVal = GetListItemValue('Название');

 

    var LHelper = new LocationHelper();

    if (filterVal != null) {

        var hh = LHelper.GetParams();

        hh['FilterField1'] = '%5Fx0…35%5F%5Fx04';

        hh['FilterValue1'] =

            encodeURIComponent(filterVal).replace('-', '%2D');

 

        LHelper.ChangeParams(hh);

    }

</script>

 

Теперь  веб-часть со списком «Задачи» будет отфильтрована по текущему проекту. Однако, если кликнуть на какой-либо задаче и войти в форму её просмотра, после нажатия «Закрыть» пользователь будет перенаправлен не на ту страницу с которой пришел.

Такой эффект наблюдается только если на странице DispForm.aspx главного списка «Проекты» в урл уже есть параметр Source. Похоже, что это ошибка стандартной JS функции GoToLink, которая вызывается когда вы кликаете на названии элемента списка.

Что бы побороть это явление, сразу за веб-частью выводящую список «Задачи» разместите еще одну веб-часть редактора содержимого:

 

<script type="text/javascript">

    var MyGoToLink = function() {

        var pp = LHelper.GetParams(this.href);

        pp['Source'] = encodeURIComponent(window.location.href);

 

        window.location.href = this.href.replace(/[?][\s\S]*$/, '')

            + '?' + LHelper.ParamsToStr(pp);

        return false;

    }

 

    var aa = $$('a');

    for (var i = 0; i < aa.length; i++) {

        var js = aa[i].get('onclick');

        if ($chk(js)) {

          if (js.toString().contains('GoToLink(this);return false;')) {

                aa[i].removeProperty('onclick');

                aa[i].addEvent('click', MyGoToLink);

          }

        }

    }

</script>

 

 

Публикация в блог из Windows Live Writer

На нашем сайте используется Live ID Authentication и каждый может внести свои изменения на сайт – добавить запись, оставить комментарий. Даже пост в блоге Статьи может сделать – только вот делать это из HTML формы, даже с удобным контролом, не очень удобно, особенно когда используется много изображений.

Обзор

Есть замечательная, бесплатная программа - Windows Live Writer, но она, к сожалению, не поддерживает LiveID Authentication для SharePoint сайтов. Конечно, это упущение и, надеюсь, оно будет исправлено. Но что же делать сейчас? Надо сказать, что один и тот же сайт SharePoint может быть опубликован в  разные зоны – Intranet, Internet, Extranet и каждая может использовать свой способ аутентификации и, соответственно, свой URL и порт. Наш сайт опубликован еще и по HTTPS протоколу, где включена Windows Authentication. У меня есть windows account на этот сайт и я попробовал подключить WLW по адресу https://sharepoint-community.ru. Меня опять постигла неудача, т.к. сертификат куплен не был и он недействительный, а WLW не дал возможности его игнорировать – опять столкнулся с проблемой.

К счастью проблема “решабельная” – надо всего лишь запустить WLW из командной строки с ключом /allowunsafecertificates

C:\Program Files (x86)\Windows Live\Writer\WindowsLiveWriter.exe /allowunsafecertificates

Теперь ничто меня не останавливает от заполнения списка Готовых решений на этом сайте с множеством картинок :)

Как обработать ссылку в меню (добавить JavaScript обработчик, изменить цвет или css-стиль)

При создании пункта меню (Действия узла -> Параметры узла ->   Переходы) бывает нужно задать ссылке JavaScript обработчик. Форма добавления пункта меню не позволяет этого.

Как вариант, можно с помощью JavaScript получить нужную ссылку и повесить на нее требующийся обработчик.

Разместите на странице следующий JavaScript код:

// Объект, обрабатывающий ссылки

LinkHandlerFormer = function(indication, funk) {

    this._Funk = funk;              // Обработчик клика по ссылке

    this._Indication = indication;  // Признак на конце URL

    this._init();

}

LinkHandlerFormer.prototype = {

    _init: function() {

        var ll = this._Indication.length;

 

        var links = document.links;

        for (var ii = 0; ii < links.length; ii++) {

            if (links[ii].href.substr(links[ii].href.length - ll, ll)

                == this._Indication) {

 

                var hh = links[ii].href.substr(0,

                    links[ii].href.length - ll);

 

                links[ii].href = hh;

                links[ii].onclick = this._Funk;

            }

        }

    }

}

 

// Добавим обработчик клика по ссылке

var lhFormer = new LinkHandlerFormer('PPP',

    // Обработчик клика по ссылке

    function() {

        alert(this.href);

        return false;

    });

 

Этот скрипт находит все ссылки, которые кончаются на магическую строку-признак, в данном примере это 'PPP'.

При создании ссылки в меню просто допишите на конце 'PPP'.

 

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

 

К счастью, в SharePoint предусмотрена возможность задать адрес страницы, на которую будет направлен пользователь после добавления элемента списка. Для этого нужно дописать к URL параметр «Source=урл_страницы_куда_направить_пользователя»

 

Например:

http://portal-test/business/Lists/test/NewForm.aspx?Source=http%3A%2F%2Fportal-test%2Fbusiness%2Fdefault.aspx

 

С помощью незначительной модификации приведенного выше скрипта мы можем динамически дописывать параметр к ссылке в зависимости от того на какой странице мы находимся:

 

// Объект обрабатывающий ссылки

BackLinkFormer = function(indication) {

    this._Indication = indication; // Признак на конце URL

    this._init();

}

BackLinkFormer.prototype = {

    _init: function() {

        var ll = this._Indication.length;

 

        var links = document.links;

        for (var ii = 0; ii < links.length; ii++) {

            if (links[ii].href.substr(links[ii].href.length - ll, ll)

                == this._Indication) {

 

                var hh = links[ii].href.substr(0,

                    links[ii].href.length - ll);

                   

                // Если в ссылке уже есть параметры

                if (hh.indexOf("?") >= 0) {

                    links[ii].href = hh + "&Source=" +

                        document.location;

                }

                else {

                    links[ii].href = hh + "?Source=" +

                        document.location;

                }

            }

        }

    }

}

 

var blFormer = new BackLinkFormer('PPP');

Как обрабатывать данные списка с использованием XSLT трансформации
Любой набор логически связанных списоков SharePoint можно легко превратить в интерактивную страничку, умеющую представлять данные в отфильтрованном, отсортированном и сгрупированном виде. Для этого необходимо воспользоваться такими веб частями как DataViewWebPart или XmlListViewer 2007 в сочетании с параметрами строки запросов.
 
Пример использующий вебчасть XmListViewer 2007, находится на странице:
 
 
В этом примере происходит фильтрация данных списка решений, в зависимости от выбранной категории. Первая вебчасть использует скрипт трансформации, создающий фильтр посредством параметра строки запроса (URL):
 

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="no"/>
<xsl:template match="/">
<
ul>
  <
xsl:for-each select="Items/Item">
    <
li>
      <
a href="?kod={@ID}">
        <
xsl:value-of select="Название" />
      </
a>
    </li>
  </
xsl:for-each>
</
ul>
</
xsl:template>
</
xsl:stylesheet>

 
Вторая вебчасть принимает этот параметр и фильтрует список решений, используя его значение:
 

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<
xsl:output method="html" indent="no"/>
<
xsl:param name="kod"/>
<
xsl:template match="/">
<
ul>
  <
xsl:for-each select="Items/Item[substring-before(concat('!#',Категория),concat('#',$kod,';#'))!='' or $kod='']">
    <
li>
      <
a href="/Lists/WebParts/DispForm.aspx?ID={@ID}">
        <
xsl:value-of select="Название" />
      </
a>
    </
li>
  </
xsl:for-each>
</
ul>
</
xsl:template>
</
xsl:stylesheet>

Видеозапись доклада на данную тему можно посмотреть на сайте TechDays, по ссылке:
http://www.techdays.ru/videos/1244.html

 

Как спрятать ссылку "Просмотреть все содержимое узла"
Иногда хочется скрыть ссылку "Просмотреть все содержимое узла" от пользоватлей.
 
Ссылка эта является объектом SPLinkButton, у которого есть свойство PermissionsString благодяря которому можно ограничивать её видимость в зависмоти от прав текущего пользователя.
 
Если мы хотим что бы ссылка была видна только тем кто имеет право изменять параметры узла (Действия узла -> Параметры узла) то строка эта должна выглядеть так:
 
PermissionsString=
"EnumeratePermissions,ManageWeb,ManageSubwebs,
AddAndCustomizePages,ApplyThemeAndBorder,ManageAlerts,
ManageLists,ViewUsageData"
 
Примечание. Строка в тексте страницы записывается без разрывов.
 
Вы можете внести это изменение с помощью SharePoint Designer для одного или нескольких узлов.
Если же хотите оставить ссылку "Просмотреть все содержимое узла" видной только администратором для всех узлом разом, то найдите файл:
 

C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\GLOBAL\default.master

 

В районе 267 строки и есть эта ссылка:

<div class="ms-quicklaunchheader"><SharePoint:SPLinkButton id="idNavLinkViewAll" runat="server" NavigateUrl="~site/_layo...

 

После внесения изменений новая строка полностью будет выглядеть так:

<div class="ms-quicklaunchheader"><SharePoint:SPLinkButton id="idNavLinkViewAll" runat="server" NavigateUrl="~site/_layouts/viewlsts.aspx" Text="<%$Resources:wss,quiklnch_allcontent%>" AccessKey="<%$Resources:wss,quiklnch_allcontent_AK%>" PermissionsString="EnumeratePermissions,ManageWeb,ManageSubwebs,
AddAndCustomizePages,ApplyThemeAndBorder,ManageAlerts,ManageLists,
ViewUsageData"/></div>

 

 

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

Работа с большими списками
Исследования быстродействия различных операций со списками, содержащими большое количество элементов. Даются рекомендации по организации данных в таких списках.
Полный текст статьи в xps-формате - здесь.
Запуск рабочих процессов по событию изменения через объектную модель
Для того чтобы при изменении элемента срабатывали триггеровые рабочие процессы, необходимо в коде получить объект под текущим пользователем с использованием SPUserToken. При этом у нас появляется возможность не нарушать историю изменений элемента, так как пользователь изменений будет не системная запись, как в случае обычной работы с объектной моделью, а именно текущий пользователь.
Так же необходимо учитывать, что у этого пользователя должны быть разрешения к искомому объекту.
 
Вот как это выглядит в коде:

// получить SPUserToken текущего пользователя, используя имперсанализацию        

   SPUserToken token = null;
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                using (SPSite ssite = new SPSite(this.__Context.Site.ID))
                {
                    using (SPWeb wweb = ssite.AllWebs[this.__Context.Web.ID])
                    {
                        SPUser targetUser = wweb.SiteUsers[__Context.Web.CurrentUser.LoginName];
                        token = targetUser.UserToken;
                    }
                }
            });

//получить объект с использованием полученного   SPUserToken

using (SPSite site = new SPSite(this.__Context.Site.ID, token))
            {
                using (SPWeb web = site.OpenWeb(this.__Context.Web.ID))
                {
                // ***  изменения в данных  ***************
                // все изменения будут от имени пользователя
                }
            }

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

1 - 10 Далее

 ‭(скрыто)‬ Ссылки администрирования