本文介绍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);
整个思路介绍到这里了,代码我会在随后的文章中分享给大家。