本文介绍SharePoint 2013 中开发可以被标记为未读和已读的列表之代码实现,只介绍核心代码,完整代码请到codeplex 下载:http://readmarkablelist.codeplex.com/ 。
ReadMarkAction.js:
function EnableUnRead() { // Get the client context first var ctx = SP.ClientContext.get_current(); var items = SP.ListOperation.Selection.getSelectedItems(ctx); if (items.length == 0) { return false; } // Check whether all the selected items are read, otherwise disable the unread button for (i = 0; i < items.length ; i++) { var currentItem = items[i]; for (j = 0; j < listData.Row.length; j++) { var currentRow = listData.Row[j]; if (currentRow.ID == currentItem.id) { if (currentRow.Readed != "1") { return false; } } } } return true; } function EnableUnReadContextMenu() { // To do: Add your logical for how to determine enable or disable the unread context menu for current item // Seems the item context menu don't support EnabledScript, need further investigation here return false; } function ClickUnReadRibbonButton() { // To do: Add your logical for operating the items once the end use click UnReadRibbonButton var selectedRows = GetSelectedDataRows(); var ctx = SP.ClientContext.get_current(); var readList = ctx.get_web().get_lists().getByTitle("ReadList"); for (i = 0; i < selectedRows.length; i++) { var currentRow = selectedRows[i]; var deleteItem = readList.getItemById(currentRow.readItemId); deleteItem.deleteObject(); currentRow.Readed = currentRow.readMarkId; var readMarkPlaceHolder = document.getElementById(currentRow.Readed); BoldItemRow(readMarkPlaceHolder); } ctx.executeQueryAsync( Function.createDelegate(this, this.onDeleteSucceeded), Function.createDelegate(this, this.onDeleteFailed) ); // alert("ClickUnReadRibbonButton"); } function ClickUnReadContextMenu() { // Check whether the selected item is read, it not dispaly a message says that message is already unread status var ctx = SP.ClientContext.get_current(); var items = SP.ListOperation.Selection.getSelectedItems(ctx); var currentRow; for (j = 0; j < listData.Row.length; j++) { currentRow = listData.Row[j]; if (currentRow.ID == items[0].id) { if (currentRow.Readed != "1") { alert("This item already unread"); return; } break; } } // To do: Add your logical for operating the items once the end use click UnReadContextMenu // Delete the remarkId from read list currentRow.readItemId var readList = ctx.get_web().get_lists().getByTitle("ReadList"); var deleteItem = readList.getItemById(currentRow.readItemId); deleteItem.deleteObject(); ctx.executeQueryAsync( Function.createDelegate(this, this.onDeleteSucceeded), Function.createDelegate(this, this.onDeleteFailed) ); // Update the readed property to readMarkId currentRow.Readed = currentRow.readMarkId; // Update the item row style to bold var readMarkPlaceHolder = document.getElementById(currentRow.Readed); BoldItemRow(readMarkPlaceHolder); } // Bold the item row function BoldItemRow(readMarkPlaceHolder) { readMarkPlaceHolder.innerText = "Unread"; var parentTR = getParentNode_TR(readMarkPlaceHolder.parentNode); parentTR.style.fontWeight = 'bold'; } // Handle the on delete successed event function onDeleteSucceeded() { } // Handle the on delete failed event function onDeleteFailed(sender, args) { alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace()); } // Get the selected data rows function GetSelectedDataRows() { var ctx = SP.ClientContext.get_current(); var items = SP.ListOperation.Selection.getSelectedItems(ctx); var selectdRows = new Array(items.length); for (i = 0; i < items.length ; i++) { var currentItem = items[i]; for (j = 0; j < listData.Row.length; j++) { var currentRow = listData.Row[j]; if (currentRow.ID == currentItem.id) { selectdRows[i] = currentRow; } } } return selectdRows; }
ReadMarkFieldType.js
(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 ); })(); // The ReadMarkViewTemplate provides the rendering logic // the custom field type when it is displayed in the view form. function ReadMarkViewTemplate(ctx) { var readMarkId = ctx.listUrlDir.replace(/\//g, "_") + "$" + ctx.CurrentItem.ID + "$" + ctx.CurrentUserId; ctx.CurrentItem.Readed = readMarkId; ctx.CurrentItem.readMarkId = readMarkId; return "<span class='ReadMarkFiledPlaceHloderClass' id='" + readMarkId + "' >data loading</span>"; } var readMarkIdForDisplayForm; function RenderDisplayFormForReadMark(ctx) { // var readMarkId = ctx.listUrlDir.replace(/\//g, "_") + "$" + ctx.CurrentItem.ID + "$" + ctx.CurrentUserId; // readMarkIdForDisplayForm = readMarkId + "DisplayFormForReadMark"; // Insert one item into ReadList ExecuteOrDelayUntilScriptLoaded(InsertReadMarkItem, "sp.js"); return "<span class='ReadMarkFiledPlaceHloderClass' id='readMarkIdPlaceHolderForDisplayForm' >data loading...</span>"; } // user for storing current user object var currentUser; function InsertReadMarkItem() { var ctx = SP.ClientContext.get_current(); var currentweb = ctx.get_web(); ctx.load(currentweb); currentUser = currentweb.get_currentUser(); currentUser.retrieve(); ctx.load(currentweb); ctx.executeQueryAsync(onLoadCurrentUserSuccessed, onLoadCurrentUserFailed); } // Once load the current user successfully, then generate the read mark by list name + itemId + currentUserId function onLoadCurrentUserSuccessed() { var currentUserId = currentUser.get_id(); var itemId = getUrlParam("ID"); var path = window.location.pathname; var index = path.lastIndexOf('/', path.length); var listPath = path.substring(0, index); var readMarkId = listPath.replace(/\//g, "_") + "$" + itemId + "$" + currentUserId; UpdateReadMarkItem(readMarkId); } // Insert the read mark into ReadList function UpdateReadMarkItem(readMarkId) { var clientContext = new SP.ClientContext(); var readList = clientContext.get_web().get_lists().getByTitle("ReadList"); var itemCreateInfo = new SP.ListItemCreationInformation(); var readItem = readList.addItem(itemCreateInfo); readItem.set_item("Title", readMarkId); readItem.update(); clientContext.load(readItem); clientContext.executeQueryAsync( Function.createDelegate(this, ReadMarkInsertSuccessed), Function.createDelegate(this, ReadMarkInsertFailed) ); } function onLoadCurrentUserFailed(sender, args) { alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace()); } function ReadMarkInsertSuccessed() { var readMarkIdPlaceHolderForDisplayForm = document.getElementById("readMarkIdPlaceHolderForDisplayForm"); readMarkIdPlaceHolderForDisplayForm.innerText = "read"; } function ReadMarkInsertFailed(sender, args) { alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace()); } function getUrlParam(name) { var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); var r = window.location.search.substr(1).match(reg); if (r != null) return unescape(r[2]); return null; }
ReadMarkListView.js:
(function () { // Initialize the variable that store the objects. var overrideCtx = {}; overrideCtx.Templates = {}; overrideCtx.BaseViewID = 2; overrideCtx.ListTemplateType = 10057; // Assign a function to handle the // PreRender and PostRender events overrideCtx.OnPreRender = preRenderHandler; overrideCtx.OnPostRender = postRenderHandler; // Register the template overrides. SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideCtx); })(); var listData; // This function builds the output for the item template, // it uses the context object to access announcement data. function customItem(ctx) { // Build a listitem entry for every announcement in the list. var ret = "<li>" + ctx.CurrentItem.Title + "</li>"; return ret; } // The preRenderHandler handles the // OnPreRender event function preRenderHandler(ctx) { // Override the default title with user input // ctx.ListTitle = prompt("Type a title", ctx.ListTitle); } // The postRenderHandler handles the // OnPostRender event function postRenderHandler(ctx) { listData = ctx.ListData; ExecuteOrDelayUntilScriptLoaded(RefreshReadMark, "sp.js"); } // Used for storing list item collection which return by caml query var collListItem; var readMarkPlaceHolders; // Refresh read mark for the list view function RefreshReadMark() { readMarkPlaceHolders = $(".ReadMarkFiledPlaceHloderClass"); var clientContext = new SP.ClientContext(); var targetList = clientContext.get_web().get_lists().getByTitle("ReadList"); var query = new SP.CamlQuery(); query.set_viewXml(GenerateCaml(readMarkPlaceHolders)); collListItem = targetList.getItems(query); clientContext.load(collListItem, "Include(Title,ID)"); clientContext.executeQueryAsync( Function.createDelegate(this, onCamlQuerySucceeded), Function.createDelegate(this, onCamlQueryFailed) ); } // Generate the caml function GenerateCaml(readMarkPlaceHolders) { 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>'; } function onCamlQuerySucceeded(sender, args) { // Set all rows fontWeight to bold implies these rows are unread readMarkPlaceHolders.each(function () { $(this)[0].innerText = "Unread"; var parentTR = getParentNode_TR($(this)[0].parentNode); parentTR.style.fontWeight = 'bold'; }); var listItemEnumerator = collListItem.getEnumerator(); // Set the rows(which is read) fontWeight to normal implies these rows are read while (listItemEnumerator.moveNext()) { var readItem = listItemEnumerator.get_current(); var currentReadMarkPlaceHolder = document.getElementById(readItem.get_item('Title')); currentReadMarkPlaceHolder.innerText = "Read"; var currentParentTR = getParentNode_TR(currentReadMarkPlaceHolder.parentNode); currentParentTR.style.fontWeight = 'normal'; for (index = 0; index < listData.Row.length; index++) { var currentRow = listData.Row[index]; if (currentRow.Readed == readItem.get_item('Title')) { // Set the readed to 1 implies that row has been read by the current user // and the unread button in the rbbion area will be enable for this item(row) // unread context menu will be enable for this item(row) currentRow.Readed = '1'; currentRow.readItemId = readItem.get_item('ID'); } } } } // Handle the caml query failed event function onCamlQueryFailed(sender, args) { alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace()); } // Get the elelemt's TR parent function getParentNode_TR(parent) { while (parent && parent.tagName != 'TR') { parent = parent.parentNode; } return parent; }