Thursday, October 13, 2016

Web-distribution of plain-old HTML/JS/CSS solution in Office 365

One of the many capabilities of SharePoint is that of webserver platform: host and distribute HTML/JavaScript/CSS based (mini)applications. With the birth of the SharePoint Framework (SPFx), I expect this role to be utilized a lot more in near future. The typical SharePoint setup for this web-distribution role is 1) a SharePoint page, 2) a ScriptEditor (or good-old ContentEditor webpart), and 3) the (mini)application itself consisting of an html-file for UI, potential javascript and/or css file(s), all stored as (SharePoint) content entities in a document library, or in a CDN.
SharePoint Online / Office 365 also supports this setup, and thus should be an equal fit for the role of web-distribution. However, you need to be aware of 3 aspects:
  1. Default, custom script is not allowed in Office 365 tenant.

    You'll notice the effect of this when you try to add custom script in a ScriptEditor, or on using PageViewer webpart which refuses to remember the url to the (mini)application html file - (Office 365 SharePoint Online - Page Viewer Web Part Not Working)

    The resolution is to set in SharePoint Online Admin settings the allowance for custom script - (Turn scripting capabilities on or off). Be aware that it can take up to 24 hours before the effect of the change is actually applied in your Office 365 tenant.

  2. ContentEditor prohibits 'FORM'tags in content:

    The resolution is to indeed use a PageViewer webpart, that is if the HTML contains a FORM tag. If not, good old CEWP accept the HTML as included content.

  3. SharePoint Online only supports download action on .htm(l) file

    The Microsoft SharePoint team made an explicit design decision to only allow download of html files, and no rendering in browser - (Office 365 - Open html document in browser in document library).

    The simple resolution is to change the extension of the .htm(l) files into .axpx, then SharePoint (Online) will no longer include the "X-Download-Options: noopen" header in the HTTP response, and the file is opened in the browser rendering the html code.

Friday, October 7, 2016

On-the-fly extend ECB-menu

Say you have business data administrated in a SharePoint list/library, and you want to enable a custom action on the items. In the "old days" one would create a Feature that deploys a CustomAction. But nowadays we intend to / or even must (Office 365 /SharePoint Online) avoid server-side (or sandbox) deployments. Clientside-development is the new mantra. SharePoint as webapplication is strongly javascript-based, from 2007 and beyond. Also the handling of the Edit-Control-Block menu is via SharePoint javascript code. This makes it possible to "break" into that execution, and inject some own handling. Via F12 DeveloperTools I identified where to 'break into'/extend:
var EnrichListView = window.EnrichListView || {}; EnrichListView.UI = function () { function MyCustomItemAction(itemId) { // do something with the item identified by 'itemId' } function OverloadMenuHtc_show() { $.prototype.base_MenuHtc_show = MenuHtc_show; MenuHtc_show = function(oMaster, oParent, fForceRefresh, fFlipTop, yOffset) { if ($(oMaster).find("SPAN[id='ID_EditItem']").length == 1) { var itemId = oParent.childNodes[0].id; var spanInsert = $("<SPAN text='Custom Action on item' onMenuClick='EnrichListView.UI.MyCustomItemAction(" + itemId + ")' type='option' iconAltText sequence='200' CUICommand='CustomActionItems' ></SPAN>"); $(oMaster).append(spanInsert); } $.prototype.base_MenuHtc_show( oMaster, oParent, fForceRefresh, fFlipTop, yOffset); return false; }; } var ModuleInit = (function() { ExecuteOrDelayUntilScriptLoaded(OverloadMenuHtc_show, "core.js"); })(); // Public interface return { MyCustomItemAction: MyCustomItemAction } }();
Result:
This client-side approach is on itself future-proof, and also works online. The only caveat is that online Microsoft may change the javascript handling/code on which this code breaks into, without you knowing. The javascript code can also change due an update to SharePoint on-premise installation, but then you're aware of a change in the SharePoint installation and can prepare for the change in advance.

Tuesday, October 4, 2016

Automatic revert-to-self for InfoPath forms

(Functional) users working with more complex InfoPath forms may be familiar with below notorious error dialog:
A typical cause is that after saving the listitem, in the SharePoint background one or more workflows are triggered that also update the listitem. And that makes the state as loaded in the form (stateless setup) outdated, and InfoPath refuses next save due optimistic locking. Pragmatic way out is to force data reload in the form, and most simple approach to that is close the form as last action in the ‘Save’ rule. Drawback is that the user must self relocate the listitem again, reopen and set into edit modus.
Via javascript injection the standard InfoPath Forms Services handling can be overruled, and instead automate the relocate/reload/edit - revertToSelf:
var InfoPathCheck; var maxNrChecks = 10; $(document).ready(function(){ InfoPathCheck = setInterval(function() { //Wait for InfoPath to finish loading HasInfoPathLoaded(); }, 200); }); function HasInfoPathLoaded() { var selectAppl = $("#<form-id>"); if (selectAppl.length > 0 || --maxNrChecks === 0) { clearInterval(InfoPathCheck); if (selectAppl.length > 0) { var saveBtns = $("input[id^='<form-id>_FormControl'][value^='Save']"); if (saveBtns.length > 0) { $(saveBtns).click(function() { // Overload IP-function to return-to-self upon 'Save'. CurrentFormData_UrlToNavigateToOnClose = function(a) { return document.location.toString(); } }); } } } }