本文介绍SharePoint 2013中开发可以被标记为未读和已读的列表的思路。
1. 首先笔者考虑到每个User的ReadMark 信息是独立的,需要有一张列表了记录那些User读过某条记录,列表命名为ReadList,使用列表名称+ Item ID + User ID作为Read Mark的组成部分。当用户View这个Item 时通过API取得列表名称,ItemID , User ID拼接成Read Mark插入ReadList 中。
2. 接着问题是如何知道用户什么时候View该Item呢?我们知道Item 的Update, Create, Delete都是有Event Handler的,但是View是没有的,这里就要用到一个辅助字段Readed, 该字段使用客户化的Filed Type,SharePoint 2013中是可以客户化字段类型(Custom Filed Type)的http://msdn.microsoft.com/en-us/library/jj220061.aspx,SharePoint 2010 其实也是可以的, SharePoint 2013 强大的地方就是它可以使用JSLinkUrl 所指向的JS客户化Filed Type的显示模版
(function () {
var ReadMarkContext = {};
// you can provide templates for:
// View, DisplayForm, EditForm and NewForm
ReadMarkContext.Templates = {};
ReadMarkContext.Templates.Fields = {
"ReadMarkField": {
"View": ReadMarkViewTemplate,
"DisplayForm": RenderDisplayFormForReadMark
}
};
SPClientTemplates.TemplateManager.RegisterTemplateOverrides(
ReadMarkContext
);
})();
……….
这里我们只客户化该字段在DisplayForm中和在List View显示的模版,在JavaScript 函数中我们就可以RenderDisplayFormForReadMark向ReadList中插入Read Mark了
3. 解决插入问题后就要考虑List View如何判断哪个Item是否已读了,同样我们需要借助辅助字段 Readed,在ReadMarkViewTemplate函数中返回类似占位符的标记,如
return"<spanclass='ReadMarkFiledPlaceHloderClass' id='" + readMarkId + "' >dataloading</span>";
然后要用到的就是客户化List View了:http://msdn.microsoft.com/en-us/library/jj220045.aspx主要利用SharePoint 2013 可以使用JSLinkUrl 所指向的JS客户化List View的显示模版的特性:
var overrideCtx = {};
overrideCtx.Templates = {};
overrideCtx.OnPostRender = postRenderHandler;
SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideCtx);
其实这个Template有很多属性可以覆盖和重写,我们这里主要使用OnPostRender,就是当着个List View render 完成后会调用这个方法。(其他未覆盖属性SharePoint会使用默认模版中的值 clienttemplates.js)。
接下来我们在postRenderHandler函数中先找到我们先前留下的占位符
readMarkPlaceHolders = $(".ReadMarkFiledPlaceHloderClass");
然后遍历所有占位符,取得其id(readMarkId) ,拼接成CAML
var values ='';
readMarkPlaceHolders.each(function () {
values += " <Value Type = \'Text\'>" + $(this)[0].id + " </Value>"
});
return '<View><Query><Where><In><FieldRef Name=\'Title\'/>' +
'<Values>' + values +
'</Values></In></Where></Query>' +
'<RowLimit>200</RowLimit></View>';
}
到ReadList中去查询,遍历返回结果,我们在上面插入的Read Mark,所有返回的Read Mark和占位符的ID匹配上的表示该Item已经被当前用户读过了,将其余没匹配上的标记为Bold(加粗显示)且内容改为UnRead, 匹配上的内容改为Read
4. 接下来是如何让User可以使用Ribbonbutton和Context Menu将已读的Item标记为未读,相信过SharePoint都知道要用Custom action:
a. 添加内容菜单
CustomAction
Id="65695319-4784-478e-8dcd-4e541cb1d682.CustomAction"
RegistrationType="List"
RegistrationId="10057"
Location="EditControlBlock"
Sequence="10001"
Title="UnRead">
<!--
Update the Url below to the page you want the custom action to use.
Start the URL with the token ~remoteAppUrl if the page is in the
associated web project, use ~appWebUrl if page is in the app project.
-->
<UrlAction Url="javascript:ClickUnReadContextMenu();" />
b. 添加Ribbon button
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<!-- Adds a Ribbon custom action to a list in the host web site. -->
<!-- Create a new custom list and add a new item to it -->
<!-- RegistrationId attribute is the list type id,
in this case, a read mark list (id=10057). -->
<CustomAction Id="75dd24d9-0c16-4ef5-be0a-f52ed0e620fa.CustomAction"
RegistrationType="List"
RegistrationId="10057"
Location="CommandUI.Ribbon"
Sequence="10001"
Title="UnReadRibbon">
<CommandUIExtension>
<CommandUIDefinitions>
<CommandUIDefinition Location="Ribbon.ListItem.Manage.Controls._children">
<Button
Id="Ribbon.Library.Connect.PropertyViewer"
Alt="Invoke custom action"
Sequence="115"
Command="Invoke_CustomAction"
LabelText="UnReadRibbon"
TemplateAlias="o1"
Image32by32="_layouts/15/images/placeholder32x32.png"
Image16by16="_layouts/15/images/placeholder16x16.png" />
</CommandUIDefinition>
</CommandUIDefinitions>
<CommandUIHandlers>
<CommandUIHandler
Command="Invoke_CustomAction"
CommandAction="javascript:ClickUnReadRibbonButton()"
EnabledScript ="javascript:EnableUnRead()"/>
</CommandUIHandlers>
</CommandUIExtension>
</CustomAction>
<CustomAction
Id="Ribbon.ListItem.Manage.ReadMarkAction"
Location="ScriptLink"
ScriptSrc ="~site/_layouts/15/ReadMark/ReadMarkAction.js"/>
</Elements>
最后还是要用JavaScript当家,需要写JavaScript函数ClickUnReadContextMenu, ClickUnReadRibbonButton,EnableUnRead来处理这些事件,可以先用下列代码取得当前选中的数据,然后找到对应的Read Mark, 调用JavaScript OM来从ReadList中删除这些Read Mark,使用JS将对应的Item的字体改为Bold:
var ctx = SP.ClientContext.get_current();
var items = SP.ListOperation.Selection.getSelectedItems(ctx);
整个思路介绍到这里了,代码我会在随后的文章中分享给大家。