Extending the List of Sites You can Embed From in SharePoint Using PowerShell

The Embed web part for modern pages lets you display content from secure websites right on your page. Want to show a YouTube video? Grab the embed code from youtube.com and slap it in the Embed web part. Wowee!

By default, modern pages support 30+ sites including the most common like YouTube, Vimeo, TED, and internal domains like Stream and OneDrive. But what about when you’ve got content from a site not on this list? You’ll end up with an error similar to this:

Don’t cry! Wipe those tears off that wet face! If you just need to allow the domain for a single site, the instructions are right there (here’s a quick summary):

  • Go to Site Settings
  • Click on HTML Field Security under Site Collection Administration
  • Type the domain from the error message (no https://) into the box and click Add
  • Click OK
  • Give it another try

But wait… Corporate just rolled out a video hosting platform for the enterprise and they want all sites to be able to embed content from this new site. Does the thought of repeating the above steps hundreds or even thousands of times make you weep in despair? Smack those tears off your moistened face!

Here’s a quick snippet of PowerShell which will show you how to add it to multiple sites:

In the PowerShell above, I’m using PnP PowerShell. You can technically do this without PnP PowerShell since it’s just CSOM, but… why would you make your life harder?

Here’s what’s happening:

  • The list of sites in line 1 is just an array of the URL portion of the site after /sites/. You could easily alter this to grab all associated sites for a hub or to get all sites within a classification, etc. But I find a simple list of URLs works pretty well.
  • We connect to the site in line 9 and grab the site object in line 11
  • We get the Client Context in line 12
  • We create a new ScriptSafeDomainEntityData object and set the only part we care about, DomainName, to the URL from the error message before
  • Then in line 17 we use the Create method to add it to the list of domains (there’s no problem if the site already has that domain, it won’t be added twice)
  • We execute the query for the client context to save our changes in line 19
  • Finally we disconnect from the site in line 21 and move on to the next site

You can easily adapt the script above as part of your provisioning process to ensure that new site have the correct domains whitelisted as well. So fun!

Now you can take content from all over the web and mash it together to bring all the relevant stuff directly to your users. WOWEE!

Dog, Pug, Bitch, Pet, Animal, Obedient, Funny, Cute

Thank you SPS Charlotte!

This past weekend I was pleased to speak at SharePoint Saturday Charlotte. It was an awesome time and is one of the best SPS events out there. I had a great time presenting both Getting Started with the SharePoint Framework (SPFx) and Office 365 List Formatting (Slides can be found below).

DkWaC6QXsAY2qD8
Photo courtesy of John Warner (@kingfumaster)

Both sessions were full of people asking great questions and actively participating. Presenting at these events can be a lot of work and requires not just the travel and the weekend time, but often many many hours of prep. Unfortunately, not every event feels worth it, but the attendees at SPS Charlotte were genuinely interested and engaged and I felt like I was able to both teach and encourage them to do awesome stuff.

Having spoken to several attendees (of not just my sessions) the overall sentiment was very positive. I wasn’t the only one amazed that these SharePoint Saturdays are FREE. The quality of speakers, sponsors, and attendees all put together by fantastic organizers is super impressive. If you missed it this year, be sure to correct that mistake next August!

P.S. – Charlotte has public electric scooters that are super cheap to ride. I rode all over downtown after the event and even went 4 miles on one the next day on my way to the airport. Even if you don’t use SharePoint, you gotta get to Charlotte just to feel the wind in your hair, the jealous stares of the walking pedestrians, and the unbridled feeling of freedom while traveling at 8 mph on a lime green scooter.

Resources

Column Formatting Client-Side Web Part: Column Formatter

Applies To: Office 365

Update

This solution is now officially a part of SharePoint PnP! Please use this repo for all updates, issues, contributions, and more. Whoo Whoo!


Modern listviews support the addition of custom formatting for most field types. This is an awesome feature designed to make custom formatting simpler and less administratively difficult than packaged solutions.

Unfortunately, the tooling is still very minimal. Users are given a simple text field within a panel to paste the JSON code and a preview and save button. The panel is clearly not designed to enable editing meaning that not only do users have to write code, they have to find someplace to do it.

The official suggestion is to use VS Code which will provide some auto completion using the standard schema. However, there are several downsides to this approach:

  • Requires a desktop client to be installed
    • Non developers that may have hung on past the initial mention of JSON are mostly gone by now
  • Once you do get VS Code up and running and begin editing your JSON:
    • The intellisense and syntax checking are very limited
    • There is no preview of your format
    • While some examples exist, there’s still a huge learning curve

I previously released a verbose schema which makes editing in VS Code a lot easier, but still doesn’t solve the preview problems, learning curve, or the need to use a tool outside of O365.

Column Formatter

ColumnFormattingChristmas4

Column Formatter is a SharePoint Framework client-side webpart I’ve created using React and Redux. It’s designed to give the full power of VS Code editing while providing easy to use templates and wizards all within the browser! The goal is to make writing and applying Column Formatting easier and quicker for both developers and end users.

Development Details

I originally set out to make an Application Customizer SPFx extension that would sit directly on the modern listview page. Unfortunately, there aren’t APIs available (at least that I could find) to load the CustomFormatter library on the page if none of the columns are using it yet, nor a way to trigger applying the formatting to the listview without actually changing the field’s CustomFormat value.

So I’ve extracted the CustomFormatter library into my project and am faking it by providing it only the dependencies it actually needs. While this gives me full control to enable “as you type” live preview of rendering, it also means that things could get out of sync with O365 development. For now, I’ll do my best to keep things updated but ultimately I’d like to be able to load the office CustomFormatter module on demand.

Similarly, I had to extract the styles of the modern listview and the unique classes for CustomFormatter.

The editor is a custom build of the Monaco Editor (the editor that powers VS Code). Getting this built as a module that worked in SPFx was a real challenge, but worth it because of the immense power it adds.

This was my first experience with Redux. It was hard to wrap my head around at first and there is a significant amount of boilerplate code required (largely to play nice with Typescript), but I wouldn’t do any React webpart of even minor complexity without it! It simplifies state management and makes additional iterations of features much easier.

What’s next

There are a few templates and wizards included currently, but there are way more that could be added. I plan to keep adding these and am open to both pull requests and suggestions.

DataBarsWizard
Wizards make it easy to generate Column Formatting without writing any code

TrendingTemplate
Templates provide you with starter code and sample data

I have submitted this webpart as an entry in the Hack Productivity 3 hackathon (Go vote for it, please!) which is why it’s currently hosted on my github. I’d like to get it included in SharePoint PnP if they’re open to it, although I’m not sure where it should go just yet.

More Information

You can find a lot more details about features and how to use Column Formatter in the ReadMe in the repo. I also created a demonstration video that covers a lot of the features:

Scroll SharePoint Search Results Back to the Top on Paging

Applies To: SharePoint 2013+

By default, when you click on a different page using SharePoint’s Search Results web part’s paging links (shown underneath the search results) the next page of results is shown but you remain at the bottom of the page. This is super dumb.

Paging

This is really easy to fix and requires no custom code at all! There is a property (not exposed in the UI for some reason) called ScrollToTopOnRedraw that is False by default.

To apply this setting to your Search Results web part, simply export the web part. You can do this by choosing to Edit the page and choosing Export… in the web part dropdown menu:

ExportWP

Now, open the .webpart file in a text editor like Notepad and do a quick find for ScrollToTopOnRedraw. Then change the value from False to True and save the file:

ScrcollToTopOnRedraw

Now, choose Delete in that same web part dropdown menu on the current Search Results web part. Then click the Add a Web Part button. Choose Upload a Web Part under the list of categories, then click Choose File and pick the .webpart file we saved a minute ago. Finally click the Upload button:

UploadWebPart

You’ll probably be asked if you want to leave the site. It’s safe to choose Leave.

Click the Add a Web Part button again. Choose the Imported Web Parts category and find your newly uploaded Search Results web part and click Add. You’ll likely have to update the Refinement Target for any refinement web parts on the page as well.

Now, when you page results you’ll be taken back to the top of the results each time!

Setting Your SharePoint Framework WebPart Icon

Applies To: SharePoint Framework

When you create a SharePoint Framework (SPFx) webpart, you can customize the icon displayed in the Authoring Canvas Toolbox. Here’s what it looks like by default:

DefaultToolboxIcon
Default “Page” icon for your webpart

By default, the Office Fabric Page icon is used but this can and should be changed before packaging up your app. This makes sure your webpart doesn’t get lost among all the other webparts and is a very simple way to add a professional touch.

There are 2 ways to customize this icon. You can specify the name of an icon from the Office UI Fabric icons or you can provide a URL to a custom image.

Both of these are accomplished by editing your webpart’s manifest.json file and changing a simple property.

Office UI Fabric Icon

The easiest way to customize your icon is to simply specify the name of an icon class in the Office UI Fabric. You can find all the icons here: https://dev.office.com/fabric#/styles/icons

The Page icon shown above is doing exactly this. You can find this setting in the src/webparts/[YOURWEBPARTNAME]/[YOURWEBPARTNAME].manifest.json file in the preconfiguredEntries/officeFabricIconFontName property:

DefaultManifest

You can simply change this value from Page to any of the available icon names. Here’s what it looks like with a value of Emoji2:

SmileyToolboxIcon

Keep in mind that this value is CASE SENSITIVE. Also, note that changes to your manifest file (unlike your code files) will require you to stop the gulp serve command and do it again to have those changes reflected in the workbench.

If you inspect the actual toolbox you’ll see that the class name for the span is simply concatenating “ms-Icon–“ and the property value:

IconMarkup

This approach is super easy (just change the name) and ensures your webpart matches the official Office styles. But what if you want your own custom icon or logo?

Custom Icon

There is another property available called preconfiguredEntries/iconImageUrl and allows you to specify an image URL.

In order to use this property, create a 40x28px icon and upload it somewhere. For this example I’m just going to use my blog, but ideally you would include it in the webpart and then pull this value from your CDN.

You’ll also have to remove the preconfiguredEntries/officeFabricFontIconName property (or the iconImageUrl will be ignored). Here’s what my property looks like:

imageIconUrlManifest

Again, note that changes to your manifest file (unlike your code files) will require you to stop the gulp serve command and do it again to have those changes reflected in the workbench.

So here’s what it looks like in my local workbench:

iconImageUrlLocalWorkbench
Smells like a bug to me

What happened!?! For whatever reason, the local workbench continues to try and use a class icon as seen above (You can even see it sets a class of ms-Icon–undefined). However, the O365 workbench (/_layouts/15/workbench.aspx) works just fine:

iconImageUrl365Workbench

A quick inspection shows that the property value is just being inserted as the src attribute for an img tag.

This means (and I’m not suggesting you should) that if you happen to have a weird Christopher Walken eyeball gif:

WalkenEyes

You could simply resize it and get something like this:

AnimatedIcon
Why you make Vesa cry?

Documentation Discrepancies

Looking at the documentation for the manifest properties (json schema) you may see some misleading outdated information. (If you haven’t setup config file intellisense in VSCode, go do it now! Here’s an awesome guide.)

The description for the officeFabricIconFontName property looks like this:

officeFabricFontIconNameTooltip

It directs you to a site with 600+ icons many of which are present in the UI Fabric Icon styles. However, these names do NOT often match the actual class names and so cannot be reliably depended on to locate your icons (for example, the “Emoji2” icon we used in the sample above is listed as “smiley2” on the font site. It took going to the Office UI Fabric Icons page to find the correct class name).

The description for the iconImageUrl property looks like this:

iconImageUrlTooltip

You are instructed to use an icon that is exactly 38x38px. This is no longer accurate. You can use whatever size you want but it will be scaled to 40x28px.

Targeted JSLink for List View Web Parts

Introduction

Standard Client Side Rendering (CSR) is a powerful technology introduced in SharePoint 2013. Out Of The Box (OOTB) you can apply this technology to list view web parts through use of the JS Link property. Using this technique, developers can quickly and easily apply display logic through JavaScript.

Unfortunately, despite its continued support in SharePoint 2016 and Office365, CSR with list view web parts still suffers from a major flaw. When you have multiple web parts that display list items from lists that share a ListTemplateType and BaseViewID, OOTB CSR provides no way to correctly target your display logic (JSLink) to individual web parts.

How to Get the Code

The example code used in this document can be found in full as part of the csrShim repository:
https://github.com/thechriskent/csrShim/tree/master/Examples/Multiple%20List%20Views

The full project can be found on GitHub:
https://github.com/thechriskent/csrShim

You can download or clone the repository directly from that site. You can also view the code directly on the site.

The Problem

When a user adds 2 or more web parts displaying list items from a list that share a ListTemplateType and BaseViewID, standard CSR has no way of distinguishing between the web parts.

The result is that if only a single web part has a JS Link property specified, all matching web parts will be drawn with that logic (even ones intended to use the OOTB display!). If more than one web part has the JS Link property, then only the last one loaded will be applied.

This is especially problematic because custom lists all share a ListTemplateType of 100 and will present with a BaseViewID of 1. This issue often surprises developers that have developed their web part in isolation where they worked perfectly just to have them break entirely when placed on a page with other web parts.

A Demonstration

  1. We will add a web part using JSLink as configured in the List View Client Side Rendering (JSLink) Primer to have a web part using JS Link (The example code can be downloaded from the repository mentioned above):
    Single CSR
    This is a pretty standard team site page with a Site Feed, a Document Library, and a custom list with JSLink applied using standard CSR (Hall of Fame)
  2. Now if we add another Custom List web part (just an OOTB view):
    Broken CSR
    Immediately we see the someList web part is full of errors (these are JS errors from missing fields where the CSR attempted to apply the JSLink file)
  3. Removing the Hall Of Fame web part from the page fixes the someList web part:
    No CSR Fixed

There are many solutions for this to be found online. Most of these solutions are hacky workarounds at best, at worst they create fragile code and dependencies on management code outside of the web parts themselves.

It is often suggested to “override” the standard CSR template registration function and then create your own system to route CSR requests by dynamically changing the BaseViewID of the ContextInfo (ctx) objects. This technique requires you to have knowledge ahead of time of all possible web parts on the page or to have some additional way to uniquely identify/register your parts. The override is just taking advantage of JavaScript’s ability to alter objects you don’t own and introduces serious risk to your solutions (upgrades, users adding unknown web parts, and more).

The Solution

Fortunately, there is a solution that addresses many of the risks laid out above. The best part is that it can be independently implemented for individual web parts. These web parts never need to know or care about other web parts on the page (no management system required).

The solution is to use csrShim with your list view web parts. csrShim was originally developed to bring CSR capabilities to web parts without JS Link properties (Content by Query Web Parts and XMLViewer), but it can easily be applied to XSLTListView web parts. When doing so, you can specify a BaseViewID that is not tied to the original value allowing you to target web parts very specifically to CSR templates!

In addition, using csrShim this way allows you to add as many web parts to the page with the same underlying ListTemplateTypes and BaseViewIDs as needed and each can direct which CSR (JSLink) should be used for themselves. This technique can even be used alongside the standard CSR JS Link usage without causing issues for those parts or themselves.

A Demonstration

  1. Going back to our csrSad page from above, let’s add the Hall Of Fame web part back to the page but this time we’ll skip specifying the JS Link property:
    No JSLink
    When the JS Link property is not used, the OOTB views of custom lists can live side by side on a single page. But that’s not very exciting!
  2. Instead of specifying the JS Link property, we will specify the csrShim Parameters of BaseViewID and JSLink:
    Parameters
  3. Now when we refresh the page:
    WorkingWow
    Voila, someList web part is just fine! (If you don’t have any profile pictures showing up be sure you used the halloffame.js for this example)
  4. We can even add additional views of the Hall of Fame list:
    Multiple Hall Of Fame
    We could apply CSR to this web part without issue as well by simply specifying a different BaseViewID (assuming we wanted it to render differently).

Benefits

  • A single property is all that’s required to distinguish web parts (BaseViewID)
    • This property is exported with the web part so that it can be added to the web part gallery and safely added to any unknown page without causing conflict
  • Utilizes OOTB XSL system
  • Utilizes OOTB Rendering system

Drawbacks

  • Some properties must be accessed differently
    • An example can be seen with how the user id was pulled to generate the link for the hall of fame. Standard CSR provides an array of user objects with individual properties. csrShim provides multiple strings for those values. Using the ctx.csrShim boolean property, you can easily create a JSLink file that can handle either:
var sip, userId;
if(ctx.csrShim){
    sip = ctx.CurrentItem["Person.sip"];
    userId = ctx.CurrentItem["Person.id"];
} else {
    sip = ctx.CurrentItem.Person[0].sip;
    userId = ctx.CurrentItem.Person[0].id
}
  • Reliance on another component (csrShim)
    • To solve this problem, you would have to introduce something, likely something requiring more overhead and support issues
  • csrShim only returns a subset of properties that standard CSR returns (all list values are returned) but nearly every property used in rendering is included

Client Side Rendering (JSLink) with RSS Feeds

Applies to SharePoint 2013, 2016, Office 365

Introduction

Standard Client Side Rendering (CSR) cannot be applied to RSS feeds when consumed through the RSSViewer or XMLViewer web parts. However, using the open source csrShim stylesheet, XMLViewer web parts can consume XML based feeds while utilizing JavaScript based rendering.

This is not a comprehensive guide to the XMLViewer web part or csrShim but provides the information necessary to enable CSR. For additional details about how to use csrShim see the csrShim Documentation on GitHub.

How to Get the Code

The example created using the steps in this post can be found in full as part of the csrShim repository:
https://github.com/thechriskent/csrShim/tree/master/Examples/XML%20Feeds

The full project can be found on GitHub:
https://github.com/thechriskent/csrShim

You can download or clone the repository directly from that site. You can also view the code directly on the site.

Background

Why the XMLViewer and not the RSSViewer

The RSSViewer does not allow the execution of code within script blocks generated by XSL. XMLViewer is able to support all of the same feed types as the RSSViewer but it allows csrShim script blocks to be executed.

Supported Feeds

  • RSS
  • RDF
  • Atom
  • Atom2

Additionally, csrShim can easily be extended to support custom XML Feeds.

Standard Client Side Rendering

Client Side Rendering (CSR), often referred to as JSLink, is a technology introduced with SharePoint 2013 that provides extension points to use JavaScript to render SharePoint data. CSR continues to be supported in SharePoint 2016 and Office 365.

Additional information about how to use standard client side rendering with list views can be found in my earlier List View Client Side Rendering (JSLink) Primer series.

SharePoint does not support using standard CSR with XMLViewers (No JS Link property is defined). However, csrShim exposes parameters that will enable this functionality including the same set of event callbacks and templates described in the above guide.

csrShim

csrShim is an open source solution that fills the gap of many of the limitations presented by the OOTB client side rendering.

csrShim is an XSLT solution that can be used to:

csrShim is available through GitHub at:
https://github.com/thechriskent/csrShim

Getting Started

In the following example, we will be targeting on premise SharePoint 2013. We will be using a publicly available RSS feed from Netflix regarding their DVD service. However, csrShim easily handles other common feed types as well.

csrShim Setup

To use csrShim, an XMLViewer web part only needs the csrShim.xsl stylesheet from the csrShim project. However, an XSL Wrapper will also be required to pass parameters.

Upload the csrShim.xsl stylesheet to a library on your site (The Style Library of the root site of a site collection is a great spot for this!).

XSL Wrapper

The XMLViewer webpart does not expose XSLT Parameter properties as do the XSLTListView and Content by Query web parts. There are no ParameterBindings elements to be found in their definition.

In order to pass parameters to csrShim, an XSL Wrapper stylesheet is required. This is a very simple file (A sample wrapper is included in the csrShim Examples folder). Here is what ours will look like:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:x="http://www.w3.org/2001/XMLSchema"   xmlns:d="http://schemas.microsoft.com/sharepoint/dsp"   version="1.0"   exclude-result-prefixes="xsl msxsl x d ddwrt asp SharePoint ddwrt2 o __designer"   xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime"   xmlns:asp="http://schemas.microsoft.com/ASPNET/20"   xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer"   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"   xmlns:msxsl="urn:schemas-microsoft-com:xslt"   xmlns:SharePoint="Microsoft.SharePoint.WebControls"   xmlns:ddwrt2="urn:frontpage:internal"   xmlns:o="urn:schemas-microsoft-com:office:office"   ddwrt:ghost="show_all">

    <xsl:import href="/Style Library/csrShim/csrShim.xsl"/>
    <xsl:variable name="BaseViewID" select="50"/>
    <xsl:variable name="JSLink" select="'/intranet/Style Library/csrShim/FeedDisplay.js'"/>
</xsl:stylesheet>

Here’s what’s happening up there:

  • Lines 1-14 are just standard XSL boilerplate. Just copy this into your own, you shouldn’t need to change this at all.
  • Line 16 imports the csrShim stylesheet (just adjust the href value to point to your csrShim location (relative to the site))
  • Line 17 sets the value for the BaseViewID parameter
  • Line 18 sets the value for the JSLink parameter. Update this to point to your JSLink file(s) relative to the domain

Upload the XSL Wrapper stylesheet to a library within your site (The Style Library of the root site of a site collection is a great spot!).

Script Setup

A simple JSLink file, FeedDisplay.js, has been put together (available in the Example folder in the csrShim project) to display this particular feed.

For details about how CSR templates and event callbacks work see the List View Client Side Rendering (JSLink) Primer series. For this sample, we’ll just take a look at the parts unique to this solution.

The header and footer templates take advantage of the csrShim ContextInfo (ctx) object’s RootData property since this contains additional information about the feed itself. In this case the title of the feed and the description are used. These values are not guaranteed and are up to the feed provider.

The item template could be an item template for standard list items. The only thing of note here is that the Netflix feed supplies an HTML description and we are breaking it apart to show the included picture next to the description (rather than above it as it comes from the feed).

Upload the FeedDisplay.js file to a library within your site (The Style Library of the root site of a site collection is a great spot!).

Configuring an XMLViewer to use csrShim

Adding an XMLViewer to a Page

On a web part page where you want to display your feed:

  1. Edit the page
  2. Click the Add a Web Part button in the zone where you wish your feed to end up
  3. Choose XML Viewer under Content Rollup

XMLViewer Configuration

  1. Using the web part dropdown, choose Edit Web Part to open the toolpane
  2. Set the value of the XML Link property to: http://dvd.netflix.com/Top25RSS?gid=307
    csrxml01

Using csrShim

  1. Set the value of the XSL Link to the XSL Wrapper uploaded earlier (NOT csrShim directly):
    csrxml02
  2. Click OK
  3. Stop Editing the Page

The RSS feed should now use the CSR display:

csrxml03

The craziest part of this whole solution is how outdated these movies are!

Best Practices for csrShim with XMLViewers

  • Always use an XSL Wrapper around csrShim so that you can set parameters
  • Provide a unique BaseViewID to prevent conflicts with the default value of 1 (standard CSR with list views uses this value)
  • If reusing JSLink files between CQWPs, list views, and/or feeds, use the ctx.ShimType property to create conditional property retrieval as needed
  • Explore the ctx object to see what properties are available in the RootData and the ListSchema objects
  • Feed properties are not guaranteed. Always check for the values existence before using it
  • Wrap your JS Link code in an Immediately Invoked Function Expression (IIFE)
  • Unlike an RSSViewer web part, there is no row limit property for the XMLViewer. If you wish to restrict the number of results, increment a count in the Item template and stop returning values when that count is exceeded