Friday, 27 May 2016

Add TermStore Managers and Contributors using CSOM

A new version of CSOM was released today for SharePoint Online. You can find more information about that here:

This version adds the ability to add/retrieve Managers and Contributors to a Term Group in the SharePoint Online Term Store.

Here is a quick code snippet I put together for achieving this:

Once executed, you can see that the Term Group in the Term Store is updated:

Monday, 23 May 2016

Minify custom SharePoint themable CSS with Gulp

The ability to create your own themable CSS has been present in SharePoint for a long time:

How to: Make custom CSS files themable in SharePoint 2013

Working with the SharePoint Theming Engine

You can even define custom names/properties in your .spcolor files which can be used in your custom CSS. My colleague Matt Holden has a great post on this here:

Custom .spcolor files for SharePoint Composed Looks

We were using this method in one of our SharePoint Online projects along with Gulp tasks to bundle and minify all our JavaScript/CSS files as per my previous post Simple bundle, minify and upload JS to SharePoint using Gulp

Now, the SharePoint theming engine uses CSS comments to determine the color replacement:

As per Matt's post, the theming engine replaces the values at run-time to the color defined in the ContentAccess1 section in the spcolor file.

For the theming engine to successfully carry out this replacement, the ReplaceColor comment needs to be present in the CSS file we load in SharePoint.

When I minified the Themable.css file using the clean-css gulp plugin, it stripped out all the comments which made the replacement not work:

Then I noticed that the clean-css plugin provides an option to keepSpecialComments when it does the minification. I tired using that but it still did not work as special comments have to start with an exclamation mark:

Adding an exclamation mark before the comment was not going to work as that would be invalid syntax for the SharePoint theming engine.

So my final solution was to convert the ReplaceColor comment to a special comment before processing it through the minifier, then letting the minifier do it's thing by minifying the css file but preserving the special comments, and then after the minification, again converting the special comment to a regular comment suitable for the SharePoint theming engine:

Which then gave me the minified CSS along with the required comments preserved:

Thanks for reading!

Monday, 2 May 2016

Simple bundle, minify and upload JS to SharePoint using Gulp

I recently started playing around with Gulp and was not really impressed until I came across the gulp-spsave plugin. This plugin will let you upload your JS/CSS files directly to SharePoint right from Visual Studio 2015! This meant that I no longer had to manually upload my JS files to SharePoint or use SharePoint Designer to edit my JS/CSS files!

This got me more interested in Gulp and I started exploring how can I further improve my debugging and build workflow with Gulp. After spending some more time, I came up with a basic workflow which will definitely get you interested in Gulp as a SharePoint/Office 365 Developer!

This is a simple workflow which will look for predefined JavaScript files in your Visual Studio 2015 project. If any of your files change, it will be bundled into a single JavaScript file, minified and uploaded to SharePoint.

Here is my project on GitHub:

The plugins used in this demo are:

gulp-concat : Used to bundle js files.

gulp-uglify : Used to minify the js files

gulp-rename : Used to rename the minified file to .min.js

gulp-spsave : Used to upload files to SharePoint

Here is the file structure of my Visual Studio 2015 project. It is a simple ASP.NET project where I have removed all unnecessary files. Since this is a strictly front-end/UI project, you could also open a folder in Visual Studio as described in this StackOverflow post.

The Scripts folder contains the JS files I will be working on. For demo purposes, I have copied the files from the Core.JavaScriptCustomization project in PnP.

The Output folder is where my output files GulpDemo.js and GulpDemo.min.js will be created. These will also be uploaded to SharePoint.

The GulpFile.js is where all my Gulp tasks will be defined. 

The package.json file is where all the NPM packages required for my tasks will be defined. 

So without further ado, here is the code for my Gulp tasks:

After creating your gulp tasks, you can run them from the Task Runner Explorer window in Visual Studio 2015:

After changing the scenario1.js file, I can see that the concat, minify and upload to sp tasks are triggered as well:

Thanks for reading!

Wednesday, 23 March 2016

Search a Taxonomy term in a TermSet using JSOM

Here is some code I put together to search a term within a term set. This is for scenarios when you have a large term set and need to efficiently find a term with a specific label.

In this code, I am searching for all terms which start with an "A" in a term set which contains locations from around the world:

Note: I am using JSOM here but this also works with CSOM


Wednesday, 25 November 2015

Using Office 365 Connectors for Groups in ASP.NET MVC

At Connect(); 2015, a new feature for Office 365 Groups called custom connectors was launched. With custom connectors, a new conversation can be started within an Office 365 Group programmatically, from your own custom application.

A very handy guide to custom connectors is available on the Outlook Dev Center: Office 365 Connectors for Groups (Developer Preview)

In this post, lets have a very simple look at how to use a custom connector from your ASP.NET MVC application.

The sample code for this post is available here:

Before we get started, it is recommended to have SSL configured for your ASP.NET MVC application:
Configuring an ASP.NET project for development with SSL

1) The Connect to Office 365 button:

The way the connect to Office 365 button works is really simple, all it does is to redirect the user to the connectors page for Outlook and then after authentication, redirects the user back to a specified callback page. Here is the html for the button

And the description for each query string parameter from the Outlook Dev Center page:

stateYou can use the state parameter to save your application state. If you supply a value for state it is returned back to the specified callback_url when the application returns. This is an optional parameter.
app_nameProvide your application name. This name will show up in the authorization popup and in the connector list page that your users would see. The app_name is a mandatory parameter and can range from 1 to 100 characters.
app_logo_urlProvide the URL to your application logo. Ensure that the link is not behind an authentication wall and is publicly reachable. Use a logo of size under 10KB (preferably 256x256px) and type JPEG, PNG, GIF, TIFF, BPM, X-ICON or SVG+XML. The app_logo_url is a mandatory parameter.
callback_urlThe callback URL should be a valid HTTPS URL without any query parameters. When the application returns successfully, the state passed, name and webhook URL of the selected group are returned as query parameters to the callback_url. If the application encounters a failure the state passed and the error code are returned to the callback_url.

This is how the button is rendered on your custom page:

2) Authentication:

When you click on the button, you are taken to the Office 365 Sign-in page if you are not already signed in. Next, you get a list of Office 365 Groups which you are a member of. You have to select a group in which the message will be posted, and click on Allow:

3) The Code:

The next step is to actually post the Office 365 Group card. Behind the scenes, I have used RestSharp in an MVC controller to make the post:

4) Navigate to the Office 365 Group:

And if you now navigate to the Office 365 Group in Outlook, you will see 2 new messages, the first one is when the connection to the custom application is set:

And the next one is the actual message we posted from the MVC controller:

Thanks for reading!

Tuesday, 17 November 2015

Custom multilingual text in SharePoint Online using Taxonomy and JSOM

I have been working on an Office 365 intranet which will be rolled out globally. Naturally, one of the core requirements of the solution is that it should be multilingual. In my previous posts on this topic, Modify Site Regional and Language settings with JSOM and JavaScript, we had a look at how to set alternate languages for a site and in Update user language and regional settings with CSOM, we saw how to set the preferred display languages for a user.

This allows a user to see the SharePoint site chrome in their own preferred language. Now in this post, lets have a look at how to have localized custom text so that the user can see custom labels, headings etc. in their preferred language.

Some notes around this:

1) This approach is based on the multilingual features of SharePoint Term Sets:

It is possible to have multi-lingual term sets because each term in a term set has a unique ID and each term can have multiple labels. You can designate a default label for a term in each language available for a term store. A term can then have multiple synonyms in each of these languages, as well as labels and synonyms in other languages.

Users will also see managed terms displayed in their preferred language, regardless of the actual default language of the term store.

If no labels are specified for terms in the language in which a user is viewing a term, then the default label for the term in the default language of the term store will be displayed to users.

3) Based completely on JSOM, JavaScript and the SharePoint Term Store.

4) This approach is built on top of the MUI features in SharePoint. Which means that the user created content such as list item data, documents etc. will NOT be translated.

5) The SharePoint Online Term Store is treated as a "data source" for custom multilingual text. Each custom text is a term in the "Translations" term set. For each language that you have to support add a new label to the term for that language.

Lets get started:

1) Setup the Term Store to support term labels in multiple languages

I have set the default language of the Term Store as English and then added Dutch as a Working Language. This means that the term store will be able to support labels for a term in English as well as Dutch.

After adding the working languages, I have created a new Term Group called "My Group".
Under "My Group", I have created a Term Set called "Translations".
Under "Translations", I have created 3 terms: Communications, Marketing and News.
We will use these 3 terms to show the custom multilingual text.

We need to add the default language labels for each term:

After a label has been specified for each term, they will appear in the following way:

When English (default) is selected:

When Dutch is selected:

The translation framework will work in the following way:

If I am an English user and I have set my preferred language as English, when the terms for the "Translations" term set will be returned,  JSOM will return the English language labels by default. 

If I am a Dutch user and I have set my preferred language as Dutch, when the terms for the "Translations" term set will be returned,  JSOM will return the Dutch language labels by default. 

If I am an Italian user and have set Italian as my preferred language in my user profile,  SharePoint will return the English labels for the Translations term set as we have not selected Italian as one of the Working Languages of the Term store, nor have we set any labels in Italian.

2) Add Local Custom Properties to Terms

Next, we will add a local custom property for each term to identify it regardless of the language. This will serve as the ID of the term when we fetch it from JSOM:

This is the list of the local custom properties I have created for my terms:

Local Property Name

We could use the Term GUID here but I prefer using a custom ID as it is more readable. Also, if someone deletes one of the terms by mistake, it is easy to create a new Term and set the custom ID in the properties. If we were using a GUID, we would have to use code to create a new term with a specific GUID.

3) The Translation framework

After the Term Store is correctly setup, all we need to do is get the terms from the "Translations" term using the JavaScript Client Object Model (JSOM) and display them in the UI:
  • Query the term store to get the terms from the "Translations" term set.
  • SharePoint will return the term labels in the current user's preferred language if:
    • The alternate language is enabled on the current site
    • The current user has set the language as a preferred language in their user profile
    • The term store supports the language as a "Working Language" as shown in step 1
    • A default label is defined for the terms in that language.
  • If any one of these conditions is not fulfilled, then the English labels for the terms will be fetched as it is the default language of the Term Store. 
  • The term labels will be stored in the cache.

4) Performance/Caching

Since it is not advisable to make a call to the Term Store on every page load, it is a good idea to cache the labels for a particular user. My recommendation would be to use the browser web storage. Whether you use session storage or local storage depends on the implementation of the solution. MDN has a great article on this

For demo purposes, I am using the sessionStorage and storing the term labels as a JSON object.

When the preferred language of the current user is English:

When the preferred language of the current user is Dutch:

5) Using the framework to show localized text

After the framework is correctly setup, all we need to do is call the framework correctly to show the custom text in the language of the current user:

When this code runs, if the preferred language of the current user is English, they will see the English text:

If the preferred language of the current user is Dutch, they will see the custom text in Dutch:

This way, you can utilize the multilingual features of the SharePoint Taxonomy Term Store to show multilingual custom text in your solution.

Monday, 16 November 2015

Install and Update Sandbox Solutions with CSOM

So recently, I was working on a SharePoint Online project and was looking for a way to automate the installation and update of a No Code Sandbox Solution (NCSS).

I was aware that you can install and activate Sandbox solutions in SPO with the following CSOM method:

There are a number of articles already covering this:

The Office Dev Patterns and Practices project also uses this method to install a solution:

Just so you know, there are a couple of caveats to this approach as mentioned in the PnP documentation:
// NOTE: The lines below (in OfficeDev PnP) wipe/clear all items in the composed looks aka design catalog (_catalogs/design, list template 124).
Also, installing and activating the solution with this method will also automatically activate all Site-Collection level features, even if they have been set to AutoActivate = False

What I have found is, by changing the Major and Minor version numbers (which renames the WSP), you can also use the same method to update an existing solution

Here is my PowerShell script which Installs a solution (if it does not already exist) or updates it if the solution already exists, and the Major or Minor version number is different.

The PowerShell script:

The script is straightforward and similar to the other posts. The main difference from the PnP version being I do not run the DesignPackage.Uninstall method before Installing the solution and I also run the DesignPackage.Apply method after Installing the solution

1) Install a Solution:

After the script is run, I can see my WSP installed in the solution gallery with the Major and Minor versions I specified:

2) Update a Solution:

To update the solution, first we will need an updated WSP. It should have the relevant sections specified in the UpgradeActions Feature XML element.
@cann0nf0dder has a great post on configuring a sandbox solution for update here: Upgrading Sandbox Solutions in SharePoint

Once you have the updated WSP, all you need to do is change the Major and Minor version numbers in the script and Install your new WSP.

After the script is run, I can see my WSP is updated to the new version in the solution gallery with the Major and Minor versions I specified:

This way, the same DesignPackage.Install and DesignPackage.Apply methods can be used for updating sandbox solutions in SharePoint Online.