Manage User Custom Actions in Office 365


Custom Actions offer a flexible way to extend capabilities of the SharePoint. The possibilities span the range of including custom JavaScript on every page to extending the Ribbon. In SharePoint 2013/SharePoint Online you can leverage the CSOM/REST  to manage custom actions. Below are demonstrated two simple examples of using custom actions in real world scenarios and I hope you you’ll find them useful.

Example 1. Enable jQuery

Let’s get started with an example that demonstrate how to add jQuery library to Office 365/SharePoint Online site. Unfortunately  it is not supported to reference external resources, for example from Microsoft Ajax Content Delivery Network (CDN) that hosts popular third party JavaScript libraries including jQuery. The prerequisite for referencing JavaScript files is that they could only be accesible when located within the site collection. So, the first step would be to save a jQuery library into Style Library: /Style Library/Scripts/jQuery/jquery-2.1.1.js.

The following Activate-JQuery.ps1 script  demonstrates how to enable jQuery library  in Office 365/SharePoint Online site

. ".\UserCustomActions.ps1"
Enable jQuery Library
Enable jQuery Library in Office 365/SharePoint Online site
.\Activate-JQuery.ps1 -SiteUrl "; -UserName "" -Password "password"
Function Activate-JQuery([string]$SiteUrl,[string]$UserName,[string]$Password)
$context = New-Object Microsoft.SharePoint.Client.ClientContext($SiteUrl)
$context.Credentials = Get-SPOCredentials UserName $UserName Password $Password
$sequenceNo = 1482
$jQueryUrl = "~SiteCollection/Style Library/Scripts/jQuery/jquery-2.1.1.js"
Add-ScriptLinkAction Context $Context ScriptSrc $jQueryUrl Sequence $sequenceNo
ActivateJQuery SiteUrl $SiteUrl UserName $UserName Password $Password

Dependencies: UserCustomActions.ps1

Example 2. Enable Google Analytics

The following Activate-GoogleAnalytics.ps1 script demonstrates how to activate tracking code in Office 365/SharePoint Online site

. ".\UserCustomActions.ps1"
Activate Google Analytics
Activate Google Analytics in Office 365/SharePoint Online site
.\Activate-GoogleAnalytics.ps1 -SiteUrl "; -UserName "" -Password "password"
Function Activate-GoogleAnalytics([string]$SiteUrl,[string]$UserName,[string]$Password)
$context = New-Object Microsoft.SharePoint.Client.ClientContext($SiteUrl)
$context.Credentials = Get-SPOCredentials UserName $UserName Password $Password
$sequenceNo = 1480
#Insert your Tracking code here or specify valid Tracking ID
$TrackingCode = "(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
ga('create', 'UA-XXXXXXXX-X', 'auto');
ga('send', 'pageview');"
Add-ScriptLinkAction Context $Context ScriptBlock $TrackingCode Sequence $sequenceNo
ActivateGoogleAnalytics SiteUrl $SiteUrl UserName $UserName Password $Password

Dependencies: UserCustomActions.ps1

Follow these instructions to use Google Analytics to collect data from Office 365/SharePoint Online sites.

To set up the web tracking code:

  1. Find the tracking code snippet for your property.
    Sign in to your Google Analytics account, and click Admin in the top menu bar. From the Account and Propertycolumns, select the property you’re working with. Click Tracking Info / Tracking Code.
  2. Find your tracking code snippet. It’s in a box with several lines of JavaScript in it. Everything in this box is your tracking code snippet. It starts with <script> and ends with </script>.
    The tracking code contains a unique ID that corresponds to each Google Analytics property. Don’t mix up tracking code snippets from different properties, and don’t reuse the same tracking code snippet on multiple domains. Click to expand this image and see where the tracking code snippet is in the interface.
  3. Open , paste the tracking code into $TrackingCode variable and run the script to register tracking code in Office 365/SharePoint Online site
  4. Check your set up.
    Make sure that the tracking snippet installed on your website matches the code shown in the view, and see more ways you can verify your set up.

Visualizing organizational structure in SharePoint with Google Chart Tools

Sometimes in SharePoint we need to visualize hierarchical  data as organizational chart. Prerequisites: not to use  Flash or Silverlight technologies here.

So, in our scenario for storage of organization structure will be used SharePoint List based on Custom List , for rendering engine  Google Chart Tools.


First, let’s take a look at list’s schema for storing organizational structure

Name Type Description
ParentOrgElement Lookup Used for parent/child relationship
OrgDescription Note Display text for chart box
OrgAdditionalProperties Note Visual behavior for chart box

From Google Charts library we’ll use Organizational Chart package only.

1. Google Charts Tools loading and package initialization

function visualizeOrgChart(orgChartProperties) {
google.load('visualization', '1', { packages: ['orgchart'] });
google.OrgChartData = orgChartProperties;

2. Fetch data using SharePoint Web Service from list that contains organizational structure

function loadOrgChart() {
var soapEnv =
"<soapenv:Envelope xmlns:soapenv=''&gt; \
<soapenv:Body> \
<GetListItems xmlns=''&gt; \
<listName>" + google.OrgChartData.ListName + "</listName> \
<viewFields> \
<ViewFields> \
<FieldRef Name='" + google.OrgChartData.TitleFieldName + "' /> \
<FieldRef Name='" + google.OrgChartData.TooltipFieldName + "' /> \
<FieldRef Name='" + google.OrgChartData.ParentFieldName + "' /> \
<FieldRef Name='" + google.OrgChartData.StyleFieldName + "' /> \
</ViewFields> \
</viewFields> \
</GetListItems> \
</soapenv:Body> \
url: L_Menu_BaseUrl + "/_vti_bin/lists.asmx",
type: "POST",
dataType: "xml",
data: soapEnv,
complete: onOrgChartDataLoaded,
contentType: "text/xml; charset=\"utf-8\""

view raw


hosted with ❤ by GitHub

3. Bind data source and draw chart

function onOrgChartDataLoaded(orgChartData, status) {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Name');
data.addColumn('string', 'Parent');
data.addColumn('string', 'ToolTip');
var chartFieldNames = { Title: generateOwsFieldName(google.OrgChartData.TitleFieldName),
Tooltip: generateOwsFieldName(google.OrgChartData.TooltipFieldName),
Parent: generateOwsFieldName(google.OrgChartData.ParentFieldName),
Properties: generateOwsFieldName(google.OrgChartData.StyleFieldName)
var orgChartRowProperties = {};
var orgChartDataRows = [];
var orgChartResult = ($.browser.msie ? orgChartData.responseXML : orgChartData.responseText);
$(orgChartResult).find("z\\:row").each(function (rowIndex) {
var orgChartRow = [];
//if ($(this).attr(chartFieldNames.Layout) == undefined)
orgChartRow[0] = $(this).attr(chartFieldNames.Title);
//else {
// orgChartRow[0] = { v: $(this).attr(chartFieldNames.Title), f: $(this).attr(chartFieldNames.Layout) };
orgChartRow[1] = ($(this).attr(chartFieldNames.Parent) != undefined ? $(this).attr(chartFieldNames.Parent).split(';#')[1] : '');
orgChartRow[2] = $(this).attr(chartFieldNames.Tooltip);
if ($(this).attr(chartFieldNames.Properties) != undefined) {
orgChartRowProperties[rowIndex] = parseChartRowProperties($(this).attr(chartFieldNames.Properties));
orgChartDataRows[orgChartDataRows.length] = orgChartRow;
$.each(orgChartRowProperties, function (rowIndex, rowProperty) {
data.setRowProperties(parseInt(rowIndex), rowProperty);
var chart = new google.visualization.OrgChart(document.getElementById('orgChartCanvas'));
chart.draw(data, { allowHtml: true, allowCollapse: true });


Result page with Org Structure rendered as Chart in List View


Initializing SharePoint People Editor using JavaScript in SharePoint 2010

Sometimes SharePoint PeopleEditor WebControl need to be initialized on the client side.

Initialize People Editor control

//Init People Picker
//peoplePickerId – SharePoint People Editor ClientID
//pickerEntityXml – PickerEntity in xml (see method ToXmlData for class PickerEntity)
function initPeoplePickerBox(peoplePickerId, pickerEntityXml) {
var $pe = $("#" + peoplePickerId);
var entityProps = {LoginName: pickerEntityXml.attr("Key"),
UserName: pickerEntityXml.attr("DisplayText"),
Description: pickerEntityXml.attr("Description")};
var entityExtendedProps = pickerEntityXml.find("ArrayOfDictionaryEntry");
var $peData = $pe.find("input[id$='hiddenSpanData']");
var $peDisplayArea = $pe.find("div[id$='_upLevelDiv']");
var displayData = "<span id='span{LoginName}' iscontenttype='true' tabindex='-1' class='ms-entity-resolved' contenteditable='false' title='{LoginName}'>" +
" <div style='display:none;' id='divEntityData' key='{LoginName}' displaytext='{UserName}' isresolved='True' description='{LoginName}'>" +
" <div data='{PickerEntityData}'></div>" +
" </div>" +
" <span id='content' tabindex='-1' contenteditable='false' onmousedown='onMouseDownRw(event);' oncontextmenu='onContextMenuSpnRw(event,ctx);'>{UserName}</span>" +
var pickerEntityData = convertFromXML(entityExtendedProps[0]);
displayData = displayData.replace(/{LoginName}/g, entityProps.LoginName);
displayData = displayData.replace(/{UserName}/g, entityProps.UserName);
displayData = displayData.replace('{PickerEntityData}', pickerEntityData);

Clear People Editor control

//Clear People Picker
//peoplePickerId – SharePoint People Editor ClientID
function clearPeoplePickerBox(peoplePickerId) {
var $pe = $("#" + peoplePickerId);
var $peData = $pe.find("input[id$='hiddenSpanData']");
var $peDisplayArea = $pe.find("div[id$='_upLevelDiv']");