Thursday, February 18, 2016

Directly open attachment from XsltListView UI

A business department composed a knowledge system as SharePoint-enabled Business App. The knowledge items are structured information about defects, with aspects as system, impact, fix available, owner. At a conceptual level, the correct SharePoint information architecture to administrate this is as list items. Some, not all, of the knowledge items can have associated documents. Important to realize is that the document(s) accompanying a knowledge item is/are secondary level information, it is not the main entity. So it is a valid decision to not set up as SharePoint document library.
However, on document level a library has convenient user experience. You click on the title of a document item, and it opens up: in browser or in native client, dependent on library settings and type of the document item. Our business requested the same convenient user experience for those knowledge items that have an associated document as attachment. Direct open from list, avoid the cumbersome usage path to first open the item and from the item dialog open the attachment in case present for the item.
A javascript approach can be applied to modify/extend the native XsltListViewWebPart behavior to deliver on the above. It relies on a combination of dynamic javascript overloading, SharePoint REST service, and SharePoint OWA viewers. Below the code snippet.
var EnrichKnownIssuesView = window.EnrichKnownIssuesView || {}; EnrichKnownIssuesView.UI = function () { function OverloadEditLink() { EditLink2 = function(target,nr) { var href = $(target).attr('href'); var idStart = href.substr(href.indexOf("&ID=") + 4); var id = idStart.substr(0, idStart.indexOf("&")); var siteUrl = window.location.href.substr(0, window.location.href.indexOf("/default.aspx")); if (siteUrl.length > 0) { var getAttachmentsUrl = siteUrl + "/_vti_bin/ListData.svc/KnownIssuesList(" + id + ") ?$expand=Attachments&$select=Id,Attachments"; $.getJSON(getAttachmentsUrl, function (data) { if ( data.d.Attachments != null && data.d.Attachments.results != null && data.d.Attachments.results.length > 0 ) { for (var i = 0; i < data.d.Attachments.results.length; i++) { var attachmentsUrl = siteUrl + "/Lists/Known Issues List/Attachments/" + data.d.Id + "/" + data.d.Attachments.results[i].Name; /* For some files, open in Office Web Applications results in error "Service not available". To prevent that the user then will not be able to view the document, configure the web-address of native document as source --> it will then open in native client. */ var fileName = data.d.Attachments.results[i].Name.toLowerCase(); if (fileName.endsWith(".docx") || fileName.endsWith(".doc")) { attachmentsUrl = siteUrl + "/_layouts/WordViewer.aspx?id=" + encodeURI(attachmentsUrl) + "&Source=" + encodeURI(attachmentsUrl) + "&DefaultItemOpen=1"; } else if (fileName.endsWith(".xlsx") || fileName.endsWith(".xls")) { attachmentsUrl = siteUrl + "/_layouts/xlviewer.aspx?id=" + encodeURI(attachmentsUrl) + "&Source=" + encodeURI(attachmentsUrl) + "&DefaultItemOpen=1"; } else if (fileName.endsWith(".pptx") || fileName.endsWith(".ppt")) { attachmentsUrl = siteUrl + "/_layouts/PowerPoint.aspx?PowerPointView=ReadingView&PresentationId=" + encodeURI(attachmentsUrl) + "&Source=" + encodeURI(attachmentsUrl) + "&DefaultItemOpen=1"; }, '_blank'); } } }); } }; } var ModuleInit = (function() { ExecuteOrDelayUntilScriptLoaded(OverloadEditLink, "inplview.js"); })(); }();
Special attention in the above for the usage of the 'Source' querystring parameter. During testing of the overloaded EditLink2 function, I occassional encountered an error in which OWA reports an error:
Opening the document in native Office client does succeed. I could have resorted to just always let the document open in native Office, but honestly I dislike that. With the OWA usage model, there is no need to download the document to the client system (consider Information Rights Management and Data Loss Protection), nor a need to have MS Office installed on the specific client device. To give that completely up, just for the rare occurence of a document on which OWA opening fails is a pitty. Instead I apply a 2-step approach: I let the Business App first try to open the Office document in OWA, which in most of the cases succeeds. In the rare case this fails, after the user clicks 'away' the above error message, the browser next 'returns' to the url specified in the 'Source' querystring parameter thus opening the document in the native Office client. Via this 2-steps approach, it is assured that the user can view the document: preferable in the browser, or in the rare problem situation in the native Office client. Simple and pragmatic.

Monday, February 15, 2016

Overload Library behavior to open Pdf in browser

A business request is to deliver via SharePoint an "e-books" functionality in which the site visitors can read documents, without need to download them. For Microsoft Office file formats, SharePoint supports this via Office Web Apps (OWA). But the majority of publication documents is in Acrobat PDF format. Even when a document library is configured to open documents in browser, SharePoint defaults to open PDF documents in the native PDF client. However, with the power of JavaScript at hand this default behavior can simple be overloaded:
var EnrichEBooksView = window.EnrichEBooksView || {}; EnrichEBooksView.UI = function () { function OverloadDispEx() { var baseDispEx = DispEx; DispEx = function(o,n,e,a,d,i,g,m,k,b,h,j,f,c,l) { if (m == 'PdfFile.OpenDocuments') { m = 'SharePoint.OpenDocuments'; } return baseDispEx(o,n,e,a,d,i,g,m,k,b,h,j,f,c,l); }; } var ModuleInit = (function() { ExecuteOrDelayUntilScriptLoaded(OverloadDispEx, "core.js"); })(); }();