Apr 10, 2018

Modern SharePoint in Office365

During these past couple of years, the SharePoint field has changed drastically. Instead of loads of on-prem installations and massive brandings, intranets and team sites have largely migrated to the cloud, to Office 365 and gotten a truck load of new options and tools as time has passed.

Office 365 is so much more than just SharePoint. SharePoint still is at the core of everything and intranets and team sites can still be built as they always have been in SharePoint: by centrally creating site collections for different purposes. While this has still been and still is the chosen path by many companies, there is so much more to SharePoint and team work today, that it really should be considered in each and any organization instead of locking the usage to "the way it's always been".

The Office 365 tool pallette revolving around SharePoint today includes:
- Classic SharePoint sites - publishing, teams, blogs, project etc. "managed" site collection created either in Admin Portal by SharePoint global admins or usually offered to users via a site provisioning tool connected to a site order form
- Modern SharePoint sites - two types of sites: Team sites and Communication sites, which users can create using the self service site creation on the "SharePoint" page in O365 portal
- Office 365 groups - "AD groups" created by users; users have shared mailbox and calendar and group site (modern)
- Forms - app for creating polls, feedback forms etc.
- PowerApps - tool for creating interactive apps and modifying list forms
- Flow - app for workflows
- Power BI - app for all kinds of data
- Planner - Microsoft's answer to Trello, ie. canban board app connected to groups
- Teams - app for team/topic conversations; connected to groups
- Yammer - app for conversations

And more, but these are the most essential ones for modern team work, when we are looking at things from a SharePoint perspective. It is no wonder then, that so many times people are totally confused and lost in the jungle of possibilities. 

The above mentioned set of tools is more or less loosely connected to SharePoint but not necessarily immediately. Some of them can be used, or rather launched from SharePoint sites, e.g. Flow and PowerApps from a list or library page. Some of them provide a means to show data in a SharePoint page, e.g. Forms and Power BI. Some of them are linked to groups, like e.g. Planner and Teams, and a group also always has its own modern team site with (almost) all SharePoint functionalities. 

Modern Team sites however are only one type of SharePoint sites currently available. Modern Commucation sites are the modern version of classic publishing sites. Classic sites - publishing and teams - still exist also. A classic team site (site collection) can be groupified (soon) thus creating a "O365 group wrapper" around it, bringing the group functionalities to it.

In the world of modern intranets, there still are fully branded classic publishing site intranets, but also ones built using Communication sites only are quite a few already. Communication site intranets can be built either by creating subsites (like in the classic version) or in the future by using SharePoint Hub sites (currently available in targeted release) to network separate sites together into a more flexible web. 

Since pictures usually say things better than a million words, I will let my little diagram do the rest of the explaining. Hope it helps to understand the different philosophies and technologies behind the different site types!




Sep 29, 2016

List with Paging on the Bottom Control Template

One of our customers wanted to use the List with Paging control display template on their news page. For some strange reason this template positions the paging in the top right corner of the web part instead of at the bottom of the list, and preferably horizontally in the center.

I fugured there were two options to do this:
1) Use CSS only (usually my preferred way)
2) Create your own display template for the purpose

Now the problem with approach #1 is that there are other content search web parts on the page too, so if you make general rules to create space at the bottom of the ul.cbs-List, this will be applied to all of those CSWPs. There is no special CSS class to hook into in the paging template ul. So even at best, this approach is a bit of a hack because in order to target it properly, you would need to use some container identifier and thus cause the whole hack to break if the web part is moved to a different zone on the page.

Number 2 seems easy enough, though, and replicable, which is even better. I set to action, downloading the original Control_ListWithPaging.html template file and opening it for editing in Expression Web and saving it with a new name. 

First, I added another class to the ul.cbs-List element, in order to be able to target rules only to the CSWPs using my new template. Small enough change, don't you think? 

<ul class="cbs-List pagingbtm">

Of course I also changed the title of the html document to List with Paging on the Bottom.

<title>List with Paging on the Bottom</title>

No biggie, right? I then uploaded the file, just to check that it works. Which it didn't! This puzzled me immensely, especially since the error message said, that the div, body and html tags have not been closed. They are not closed in the original control template (at least not when I opened it in notepad to check) but that works fine. 

So fine, I closed those tags at the end of my new template file. The error message disappeared and instead my template worked perfectly. Well, almost. The little arrow icons weren't visible but at least there was no error anymore. I decided to ignore that for the time being and finalize my control template changes. 

As said, I could've done it all in CSS only (after adding the new class), but I decided to make one more minor change in html to make the css shorter and less vulnerable and avoid the extra space when there are less items than the paging limit. I moved the resultset to the beginning of the list, so that the paging became the last node instead of the first one.

The results are displayed by this variable:
_#= ctx.RenderGroups(ctx) =#_

It is originally right before the closing ul tag. By simply moving it right after the opening ul tag, the order is reversed.
<ul class="cbs-List pagingbtm>
_#= ctx.RenderGroups(ctx) =#_

When this was done and tested, I started looking into that arrow icon issue. Quirkily, the img src was pointing to a nonexistent file on my own computer! This can be blamed on Expression Web. It's a first, though! I'm quite used to SharePoint Designer pulling off sh*t like this, but Expression Web has generally been a very reliable editor and loyal to the original code. Not this time. 

I opened the original file in notepad and sure enough, the correct source string was there, intact. 

<img class="_#= $htmlEncode(nextPageImageClassName) =#_" alt="_#= $htmlEncode(lastPage.title) =#_" src="_#= $urlHtmlEncode(GetThemedImageUrl('spcommon.png')) =#_">

So I copied and pasted it to my template and all was well in SharePoint Land again.

Here's the CSS:
ul.cbs-List.pagingbtm li.ms-promlink-header {
    text-align: center;
}
ul.cbs-List.pagingbtm .ms-promlink-headerNav {
    float: none;
    margin-top: 6px;
}

May 18, 2016

Search Results vs. Content Search Web Parts: customizing and date formatting

The default way to display feeds from news, events etc. on an intranet front page is to use the Content Search Web Part. Used to be Content Query, but customizing the CQWP is way more complicated plus it is restricted to the same Site Collection only. This is still used, as is, by many of my customers, for it is easier for content managers to set up than the search queries. Anytime any custom templates are needed (or when I am setting up the feeds), definitely CSWP is the way to go.

Lately, though, I have had several customers with SharePoint Standard lisence only. Unfortunately this leaves out the CSWP completely. Search indexing and search driven content is still available, but building those said feeds is just a tad more complicated for you need to use the Search Results Web Part, which is not created for this kind of usage, even though it CAN be used. It requires some more work, but once you've figured out the basics, it's not that difficult. Just a bit different than the CSWP.

The display templates of CSWP consist of a control template and an item template (for more info, see my post "The Anatomy of SharePoint 2013 Display Templates"). Mostly the modifications and customizations are rather straightforward to make by following the example of things already there. The date formatting, however, is a bit tricky. What you need to do is:

1) Copy the item display template you want to modify from MasterPages gallery, Display Templates, Content Web Parts directory.

2) Create a managed property of the field you want to use, if not using Created or LastModifiedDate, in Search Schema.

3) Use the date field as value for desired line data, eg:

var line1 = $getItemValue(ctx, "Line 1");
var line2 = $getItemValue(ctx, "Line 2");
var eventdate = new Date(line2.inputValue);

4) Format the date as you wish in the HTML where the value is rendered:

 <div class="cbs-Line2 ms-noWrap" title="_#= $htmlEncode(line2.defaultValueRenderer(line2)) =#_" id="_#= line2Id =#_">_#= eventdate.format("d.MM.yyyy H:mm") =#_</div>

5) Upload your display template (remember to change the title in the HTML and rename your modified file) back to the same folder in MasterPages gallery and publish it. It's ready to be used.



As for the Search Results web part, the system is slightly more tricky. First off, there are more display templates involved: 
  • Control templates
  • Item templates
  • Item HoverPanel templates
Mostly, you need to work with Item templates and/or hoverpanel templates, if using the hover panel. In the case of displaying feeds on front page, the hover panel is seldom wanted. It can be removed. Simply delete highlighted parts from the display template you copied, eg. ItemDefault (note, that the Search Result templates are in the Search folder):

<div id="_#= $htmlEncode(itemId) =#_" name="Item" data-displaytemplate="DefaultItem" class="ms-srch-item" onmouseover="_#= ctx.currentItem_ShowHoverPanelCallback =#_" onmouseout="_#= ctx.currentItem_HideHoverPanelCallback =#_">

And then comment out the following line:

 <!--  <div id="_#= $htmlEncode(hoverId) =#_" class="ms-srch-hover-outerContainer"></div> -->

Other modifications that I have found useful and quite necessary in said use case are
  • removing the item URL - actually in default item template I just remove the whole default body render tag:
    _#=ctx.RenderBody(ctx)=#_
  • building your own stuff to show for each item, e.g. rollup image, a content summary, publish/create date eg. 
Adding fields to the display template is simple enough. The fields need to be managed properties in Search Schema, so remember to do this first for any custom fields. Then you add the properties to the template mso:ManagedPropertyMapping tag:

<mso:ManagedPropertyMapping msdt:dt="string">'Title':'Title','Path':'Path','Description':'Description','EditorOWSUSER':'EditorOWSUSER','LastModifiedTime':'LastModifiedTime','CollapsingStatus':'CollapsingStatus','DocId':'DocId','HitHighlightedSummary':'HitHighlightedSummary','HitHighlightedProperties':'HitHighlightedProperties','FileExtension':'FileExtension','ViewsLifeTime':'ViewsLifeTime','ParentLink':'ParentLink','FileType':'FileType','IsContainer':'IsContainer','SecondaryFileExtension':'SecondaryFileExtension','DisplayAuthor':'DisplayAuthor','Created':'Created','NewsSummary':'NewsSummary', 'PublishingImage':'PublishingImage' </mso:ManagedPropertyMapping>

Then you use this to build your own HTML for the items, eg.

<div id="_#= $htmlEncode(itemId) =#_" name="Item" data-displaytemplate="DefaultItem" class="ms-srch-item">
    <div class="newscontainer">
<div class="newstitle">
<a href="_#=ctx.CurrentItem.Path=#_">
_#=ctx.CurrentItem.Title=#_
</a><br>
               <span class=newsdate>
              _#=ctx.CurrentItem.Created=#_
</div>
<div class="newsbody">
<div class="newsimg">
_#=ctx.CurrentItem.PublishingImage=#_
</div>
<div class="newstext">
_#=ctx.CurrentItem.NewsSummary=#_
</div>
</div>
</div>

Note the date there, though. It will give you a very long date format by default, but in a Search Results template it is way easier to format the date than CSWP. Simply add format(yourdiesiredformatting) to the value in HTML. Like this:

_#=ctx.CurrentItem.Created.format("d.M.yyyy")=#_


Then there is only one little nuisance left: the hover background color. 


This comes from this CSS rule: 

.ms-srch-item:hover, .ms-scrch-resultHover:hover, .edisc-SearchResultItemContainer:hover{
background-color: rgba(...);
}

Now, if you override this as is, it will effect the search results pages too. So try to identify the targets in some way, use eg. .welcome or .article classes for targeting content pages only in removing the hover color.

Whew! All done!

May 4, 2016

SharePoint Dev Kitchen 2016

I was really happy when I heard that the embargo was being lifted on the current SharePoint development stuff, and I could finally tell the wolrd about the amazing SharePoint Dev Kitchen experience of this past March in Brussels. An invitation only -event for SharePoint dev community, the bootcamp was full of people with ideas, views and passion, and the core of the Microsoft SharePoint team.

The big meeting room was buzzing with electricity as we all settled into our seats to hear what the SharePoint team wished to share with us. The preparation emails had given but a little hint on what was happening in our SharePoint world. 

When the keynote ended, I felt a whoosh of delight. The SharePoint team was not only being candid with us but also looking to get feedback, thoughts and ideas from us who crowded the room. Still, the most exciting thing was the message [NOTE: this is purely PRE-RELEASE info]:

SharePoint is going towards more and more open source coding
Instead of doing a whole lot of behind the scenes closed-cirquit development, the SharePoint team has adopted the usage of JavaScript libraries and frameworks that enable the third-party developers to create add-ins and solutions for SharePoint with any JavaScript framework they wish to use.  
Mobile leads development
They were pretty clear on this one. All develoment is done mobile first. Not desktop first keeping mobile in mind but actually mobile first, then desktop experienve. 
SharePoint Home
If I had a euro for each time a customer has asked me: "But where's the SharePoint here in O365? There's only this Sites... is that it? But how do I find my workspaces if I haven't followed them?" As far as I understood, SharePoint Home will asnwer this question once and for all. It's where SharePoint is, it's where the workspaces are. 
A lot of nice new features are coming to SharePoint
Document libraries will get a bunch of new features. Publishing sites will get a new page model as an addition to the current one (i.e. the current publishing pages aren't going anywhere; your data is safe) with the feel of Sway to them - adding modules (or cotnrols or web parts, whatever the name will be) to a page canvas (or several). Publishing sites will get a gallery of these modules - new web parts - that are fully JavaScript based. 
Office UI Fabric
In addition to this new more open way of developing for SharePoint, Microsoft is providing a "fabric" of CSS and (HTML) controls for unified look and feel of any app or add-in that made for Office environments. It provides a grid for responsive design, fonts, animations etc. to be used freely - but no one is forcing it either.

One thing the Microsoft people really emphasized: the old way is not going away; this new model simply enable more.

Dev Kitchen was a very social three day "training". Sure, Microsoft people were giving sessions on what they are working on, the technologies that are used and there were hands-on labs to try out the things in a test environment. However, there was also a lot of discussion of ideas and questions and priorities and wishes and whatnot. There were a lot of people already getting their hands dirty with the new stuff, trying out real life scenarios and showing their work in demo sessions. 

Now the team is ready to come out with the stuff, but this is only the beginning. A lot is brewing in the SharePoint Dev Kitchen and it will be truly interesting to see the outcome! 

Apr 19, 2016

Removing reusable SPD workflows completely

Recently I have been working on a set of different custom SharePoint Designer workflows for different customers. Sometimes the process is not so straightforward that you get things right on the first try and sometimes the errors result in the need to actually remove some trial workflows from the system. 

Reusable workflows are slightly more tricky to remove from the SharePoint UI than the list workflows. In SharePoint Designer, the main way of managing workflows is in the Workflows section. This may well tempt you to remove the workflow simply from that list and be done with it. This, however, will not remove it from the SharePoint UI, and thus an old depracated workflow is still available for users. 



The right place to remove the workflow from is to open the All files section, find the Workflows directory there and delete the whole workflow directory. 

But what if you already deleted the workflow in the Workflows list and now you have no directory for it anymore but it still shows up in the SP UI? This is what I was researching this morning. The place to go in that case is - surprise surprise! - the _catalogs directory. There you will find a folder named wfpub. And in that wfpub folder, you still have the directories for even those workflows that were deleted from the Workflows section listing. Delete these directories with all their contents and you're good.


Mar 18, 2016

SharePoint Branding and the winds of change

Not that long ago, it was quite typical to create a major SharePoint UI solution for a SharePoint intranet. It would contain one or more Master Pages, CSS stylesheets, images, JavaScript, Page Layouts etc. The solution package was deployed to the server, the feature activated and automagically the intranet got its fancy custom UI and functionalities. A slight inconvenience though, that even the smallest change or improvement in any of the shipped files required updating the whole package.
It hasn’t been too long since I last was involved in such a big intranet solution. These days such projects are more of the exception than the rule. So, what’s changed?

One thing, or maybe I should say THE thing is Office 365. Cloud is becoming more and more popular and doesn’t even allow such huge full-trust solutions. Sandbox solutions are still an option, though according to Microsoft they are not the technology of the future – they already once declared them deprecated, but actually had to take it back pretty quickly. However, apps and other alternative ways of doing things (PowerShell, Azure powered functionalities etc.) are the modern and flexible way to build stuff on top of SharePoint, while keeping it separate from SharePoint.

I believe it’s not inaccurate to say that all the rest is just a byproduct of this. While more and more companies are switching to the cloud environments and Microsoft is developing “cloud first”, it is only natural for attitudes and ways to adapt to this change. Lightweight tweaking as opposed to heavy – especially with a heavy update process – custom software development sounds quite enticing.

Years ago, when SharePoint 2010 was launched and companies started to migrate from the old 2007 environment to the shiny new SharePoint in a fast pace, the game of the day was using OOB where ever possible and doing as little customization as possible. Mostly this still meant creating easily retractable solution packages for UI and custom web parts and services, distributed as features. SharePoint wasn’t re-coded anymore as it used to be in many cases with MOSS 2007; the solutions were built on top of SharePoint without touching the OOB stuff.

Then, along came SharePoint 2013. For quite some time the development and customization story was pretty same as with 2010, up until Online made its breakthrough and started to mold the models towards the more lightweight facelifts, apps, external services etc. The process of UI customization, branding, has shrunk from a heavy solution package to creating themes, some custom CSS and maybe a bit of JavaScript.

A color theme is a rather easy and quick way to apply the company branding colors to SharePoint. It already takes you a long way – the company colors are applied to the top suite nav, links, emphasis colors, headings etc. Creating a font scheme adds to this by implementing the company font – even a custom one – everywhere with one setting. What cannot be done by a theme is changing the placement and fancier styling of page elements.

The current default Master Pages seattle and oslo are built using div elements. This means that working with them – the placement, float, etc. – is pretty flexible and easy without needing to change the HTML of the Master Page, i.e. there is no need to create custom Master Pages simply to change how and where the elements are rendered on the page. There are limits to this, but you can do a lot with CSS.



Themes and an alternate CSS stylesheet are easy to implement in the UI of SharePoint, in the site settings, and they are inherited by any subsites with publishing feature activated. Implementing them to sites without publishing feature is a bit more work. Generally, this means pushing the inheritance from the top level each time a new site has been created.

JavaScript adds its own challenge to the equation. It is possible to globally inject JavaScript to all sites in a site collection using PowerShell. However, this should then be done for each new site too, when one is created. In single pages the Script Editor Web Part works nicely, but the global injection is always a bit of an issue. Mainly the options apart from the manual PowerShell injection are adding the script links to the Master Pages or creating an Azure powered service for provisioning the sites. 

The latter option is actually something to consider. Basically the idea is that people don’t create their sites manually but order them by creating a new item into an order list. A timer job polls the list and notices a new site order and launches a PowerShell script that then provisions the site with the exact settings, stylesheets, logos, Web Parts, lists, JavaScript links that are needed for each new site. 

Add responsive design to the equation. Currently SharePoint Online offers two view for mobile devices and the possibility to switch between them. One is the mobile list oriented view, the other one the full desktop view. The list oriented view works fine in team sites where all the content is mainly in lists, but publishing sites, the informative intranet pages, need to be viewed in full desktop experience on mobile devices too – in a responsive way so that it actually is readable.

Unfortunately, responsive SharePoint is still a bit of a everyone for their own – or has been, but I have just discovered that PnP has actually come forth with an awesome fully responsive solution that is purely CSS based! Previously the options have been e.g. bootstrap (heavy version), a responsive SharePoint solution from Codeplex (kinda heavy solution too); both of these require changes to the MasterPage. A bit of a no-no. 

Be as it may, responsive design is always more expensive for a customer than the basic design only. However, as the costs of branding have come down significantly with the lighter approach, it most definitely pays off to invest in responsive design, if not go mobile first. That’s where this world is headed anyway. 

[Originally published in Finnish in our company blog]

Mar 7, 2016

Tip: Fix List Issues After Migration 2010 -> 2013

Once again, faced with issue after issue. There was a SharePoint intranet that was migrated from SP2010 to SP2013. There was a list in the intranet, containing crucial information that should be easily searched. However, there was no list search available. Also, none of the columns were site columns. So I set out to create a search page for the list data. Everything runs cool if you just try to search with data in the title field (or author). However, there were some other fields including data to search wih.

Piece of cake, I thought to myself, disregarding the fact that most of the time the pieces of cake are tough to chew when it comes to SharePoint. I created some site columns and added them to the list, positioning them next to the original ones, with the intention to simply open the list in quick edit mode and copy values from list columns to site columns. Easy enough!

However, the list being a custom list originating in SP2010, the quick view was unavailable. I contemplated on exporting the data to Excel, modifying it there and creating a new list using that sheet. Before attempting that, I decided to google just a bit in hopes of finding a solution. And I did, hurray for Saludeen Rajack!

Since I had already tried most of the tricks in the blog post, in vain, I crossed my fingers and opened the list page for editing, opened list web properties and added clienttemplates.js to the JS Link property of the web part (at the very bottom of the Miscellaneous section).


And lo and behold! First of all, the list search box appeared at the top of the list and secondly, the quick edit button became active. 



Now I could proceed with my plans properly.

Feb 17, 2016

Javascript world clock with automatic time zones

One would imagine that getting a world clock - real time with automatic time zones including daylight savings - wouldn't be that difficult to include on your web site. On a standalone web site it probably isn't since there are several free or low cost solutions available. But in SharePoint it wasn't quite as straightforward.

One of my customers, a global company, already has one solution implemented on their intranet site, but there are two problems with it: it only refreshes the time on page refresh and the daylight savings (i.e. offset for each time zone) need to be adjusted manually every half a year. So I began to look into the options for modernizing this world clock of theirs.

First thing I realized was that most of the ready made solutions rely on PHP. This is already a no-no in SharePoint. Then I came accross this very cool site http://www.clocklink.com/ which has built in time zones and a multitude of analaog clocks (using html5 or flash). These could be used in SharePoint quite easily per se, and I even found a pretty neat solution using a SharePoint list to create a multitude of easily maintainable clocks. Check it out at Path to SharePoint

However, this requires cross-domain queries and moreover, when working in e.g. SharePoint Online, queries from https to http wich pretty much is a showstopper here. 

At this point I was starting to be pretty frustrated. Being so close and still so far away from a working solution. Then along came moment.js. A life saver, so to speak. Plus a very elegantly written tutorial for creating an analog clock using javascript and html5 canvas.

Combining all this plus a little bit of jquery I finally came up with a fully SharePoint (Online) compatible world clock solution (though I actually ripped the canvas part away, as I only needed a digital time display with some additional info). So, let's do a walk through for the benefit of the next one needing to do something similar:

1) Download moment.js (or min) and the suitable version of moment-timezone (from the Moment and Moment Timezone pages). Optionally also download jquery-file to avoid any cross-domain calls.

2) Upload the js-files into a suitable library in SharePoint, eg. Site Assets on the site.

3) Create a test file for compiling all the needed code to add to the script editor web part on your page and first off, add references to the js-files in the SharePoint library.

<script type="text/javascript" src="../SiteAssets/jquery-1.10.2.min.js"></script>
<script type="text/javascript" src="../SiteAssets/moment.min.js"></script>
<script type="text/javascript" src="../SiteAssets/moment-timezone-with-data.min.js"></script>

4) Add a bit of CSS:

<style type="text/css">
.current-time {
display: block;
font-weight: bold;
text-align: center;
width: 200px;
padding: 10px;
}
.clockcontainer {
  background-color: lightblue;
  border: 1px solid blue;
  border-radius: 5px;
  float: left;
  margin: 5px;
}
</style>

5) Add the javascript logic:

<script type="text/javascript">
document.addEventListener('DOMContentLoaded', startTimer);
function startTimer() {
    setInterval(displayTime, 1000);
    displayTime();

function displayTime() {
jQuery(".clockcontainer").each(function(){
var timezone = jQuery(this).attr("title");
var zonetitle = jQuery(this.firstElementChild).attr("title");
var now = moment().tz(timezone).format("h:mm:ss A");
var day = moment().tz(timezone).format("dddd MMMM DD, YYYY");

jQuery(this.firstElementChild).html(zonetitle + "<br/>" + day + "<br/>" + now);
});
}
</script>

(Note the jQuery instead of $ - in SharePoint this generally works more reliably)

6) Copy and paste all of the above to a Script Editor web part on the page where you are adding the world clocks, preferably somewhere close to the bottom of the page.

7. Add a Content Editor web part on the page where you want to display the clocks.

8) Edit the source of the CEWP content and add the clock elements (as many as you wish, but note the highlighted parts):

<div class="clockcontainer" title="Europe/London">
<div class="current-time" title="London">
time</div>
</div>

9) Modify each element to put out the correct time zone (title of the clockcontainer element) and the label for the clock (title of the current-time element). Check proper time zone names at the momentjs site.

That should be it, folks. Now, your SharePoint page should display correct times for your chosen time zones, e.g.


Momentjs offers plenty of options for time and date formatting. 

Dec 10, 2015

Tip: Targeting a specific SharePoint site with global CSS

Just a little css tip, that came out handy today. Generally, with a global css (say, an alternate style sheet that is deployed throughout the site collection), you don't even attempt targeting some specific site, but go with the global styles instead. Today, however, I was struggling to display the titlerow (logo and navigation) in the enterprise search center without having it become visible in the dialogs as well.

Some Microsoft logic it is, I guess, that the search center by default hides the site collection navigation using the same class as the dialogs, the .ms-dialogHidden. And as anyone working with SharePoint CSS knows, the sites have no IDs in the body tag so that you could e.g. tell your css to display the navigation in search site but not in the dialogs. None, except for the action attribute in the form tag.

I guess it never was as big of an issue before, since I never thought of it before, but indeed, in a site collection already populated with sites, you can target one specific site by using the attribute selector for form tag in your css rule, for the form action contains the relative address of the site in it + in SharePoint, the whole page is always inside of that form tag. So here's the rule for un-hiding the titlerow for this specific search center, just as an example:

form[action*="searchcenter"] #s4-titlerow.ms-dialogHidden {
    display: block !important;
}

And, yey, the dialogs remain untouched and furthermore, there is no need to impelemnt page level css on each and every search center page.

Nov 4, 2015

Choosing between publishing and team sites for your SharePoint intranet

I have noticed, that the tech oriented SharePoint architects tend to prefer team sites over publishing sites for practically any purpose. I cannot remember the reason, and frankly, during my years of building SharePoint intranets I have not come accross any real reason for this - more like on the contrary. An intranet built with team sites causes more problems than not, in most cases. Let me explain.

Team sites have a much more dynamic usage philosophy behind them than publishing sites. Team sites are meant to be virtual team workspaces, where a bunch of people collaborate, manage documents, manage team tasks, chat etc. The content is highly dynamic, based on lists and document libraries rather than text and images on web pages. Thus, the need to edit pages is ususally quite small. The owner creates lists and libraries, sets up the workspace and the content starts to live.

As for the informative intranet? This is not how it works! The content is highly static - text and images on pages, maybe some centrally managed documents that are published on for the large reader audience of the pages - I say pages, for even if the intranet is built with a site hierarchy, like it most commonly is, what users see and use, are pages. 

True, that you can do the same with team sites too. Nobody says that team sites must be collaboration sites. However, using team sites to build traditional intranet sites creates a series of issues for the content managers and designers of the intranet. Issues, that the more technically oriented architects never see, since they rarely step into the boots of the end-user.

Quite many times, I as the UI "guy" and the content management "guy", am called into these situations where someone, some tech person, has built the intranet for a compnay, a Site Collection created as a team site, created a hierarchy of team sites. the customer has started to build their intranet with the blocks they have been given and they run into issues.

1) "I  made changes to this page, but they disappeared". Most of the time the publishing features have been turned on in the site collection of team sites that are meant to act as the intranet. This results in a very strange hybrid situation, where one can edit a page without checking it out, but someone can also check it out and result in loss of data. 




2) "I was trying to edit this web part, but I get this message about checking out." Even when the check out is required for the pages, the whole editing and check out is occasionally quite confusing for the content editor. In some situations, the page allows you to edit it to an extent, until it suddenly hits the editor with the "Hey, you need to check this page out first!". Again, data may get lost in the process. 

3) "Pages or Site pages and what is the welcome page of the site?" When publishing features are activated for the site collection and for the sites in it, each site has two libraries for the site pages. The Site Pages library (originial for the team site) and the Pages library (created by the publishing feature). Now, this creates another funky situation there. 

If indeed pages are created within sites, they may be in each different library, depending on how they were created. And they function a bit differently when editing, not to mention that the whole page architechture is different. More confusion for the content editor. The deafult page of the site can either be the Home.aspx from the Site Pages library or the default.aspx from the Pages library. You need to choose, and set the welcome page in the site settings.


4) "But... this page layout is not consistant and we want it to be something like this [drawing]." When using simply the welcome page of each site in the intranet site collection, the issue that the HR, PR, marketing etc. department raises when getting involved with the intranet is the layout of pages. 

True, not an issue for all companies, but a whole lot of them. There is a need to create a consistent layout for the pages and while text layout offers some options, it rarely truly fullfills the needs here. Publishing pages with the page layouts options are required. All of a sudden you find yourself creating new welcome pages as publishing pages and building them all over again with the content that already was on the home page, the wiki type page of the team site.



So in order to avoit these hybrid versions of sites and the confusion of the people who actually need to work with the pages and manage the content of the intranet, I highly recommend creating the informative intranet hosting site collection using the publishing site template. Seriously, that's why it is there! If you need blogs or wikis or even team sites within, it is all still possible. If you need calendars etc. that are not orginally part of the publishing site, the team collaboration lists feature can be activated. 



This said, if your intranet is not a traditional informative publishing intranet but a collaborative dynamic intranet instead, or if you prefer the wiki type content management, please do use the team sites to get the most out of that scenario! There is nothing to lose and a lot to gain  to actually use the most suitable SharePoint site template for each specific purpose instead of going with the idea that one glove fits all. It doesn't! All it needs is a little bit of planning and understanding the actual use case scenario of the site collection at hand.

Oct 6, 2015

Scoped search results predefined empty

Many are the things you think should be simple in SharePoint, and yet they're not. Another day, another little issue to solve. 

We have made this JavaScript listing of subsites inside a site collection. A site directory. For certain reasons the Content Search Web Part nor the Table of Contents was the thing. That aside, I'm not going into that more deeply here, the other thing that was needed there, was the ability to search the directory.

One would imagine, that it would be simple enough to add a search box to the page, and a search results web part, and then configure it to show only results for search box queries, and show nothing unless a query is made.

Not so much. Not a big deal either, but requires a couple of tricks.

First of all, you need to set the query for the results web part. In this case, there are three things to set up: 
  1. The results need to be restricted to this site (or site collection, depending on where you're setting this up) only
  2. The results need to be site item type only
  3. The results need to be restricted instead of filtered by the search box query (as would be the default, the results web part showing a listing of all sites unless a query is made)
With all this noted, the query would look like this:
{?{searchTerms} path:"https://YourSiteOrSiteCollectionPath"  contentclass:STS_Web}

This can be either typed in, or if you need to modify the result types etc. use whatever query settings are provided. Just be sure to wrap the whole thing inside the {parentheses} with the
?{searchTerms}at the very beginning of the clause.

In the web part properties you might want to tick off some of the settings like eg. choose to not show the adanced search link, preferences link, language dropdown etc. The setting you won't find there, even though the search results display template actually hints that it should be there, is to select "Show nothing when there are no results". The Content Search Web Part does have this setting, so I was kinda surprised.

This just means, that when no query has been made or it does not provide results, you will see all these suggestions and tips in the web part:


In order to be rid of those (or at least the suggestions), depending on what you want - in this case, the web part needed to be completely empty unless there were some search results to show - you need to modify the display template for the search results. I.e. download a copy of the default one, make the necessary changes and upload your modified one to the gallery. 

All the display templates of a site collection are located in the Master Pages gallery, Display templates folder. Search results display template is in the Search folder. Download a copy of the original html file.



Open the downloaded file in an editor (I prefer Notepad...) and search for the div with the id of NoResult.

<div id="NoResult">

Inside that div you can see a bunch of JavaScript and html. If you only wish to get rid of the suggestions, delete only the <ul> element from the page, or replace it with something of your own. 



As it went, I wanted nothing to be shown unless there were some results, so I emptied the NoResult div completely. 

Change the title of your template (third row of the template) and save it locally with a new name. Upload your modified template to the same Search directory of the Display templates as the original one. Don't worry about any .js files; SharePoint will generate it upon upload. 

You most probably will need to publish your template before it can be used in the web part. When this is done, navigate back to the page with the search results web part you are setting up and open the we part properties. (Note, the page needs to be saved and reopened for editing before it can find the new display template)

In the Display Templates settings select your modified template.


Save web part properties, save (and publish) page and the search is ready.


Sep 24, 2015

Modify SharePoint List Alert to Show ID

There is a list in SharePoint, that seems to be quite overlooked. It is, however a pretty ok light weight ticketing system for a project. Yes, I'm talking about the issue list. One advantage the issue list has over a general task list is that it automatically notifies the person if he or she is set as the assignee of the issue. It used to be, that this notification email - alert - contained the issue ID both in the subject and the email body. Not anymore. 

One of my customers uses issue lists for project ticketing and after migrating from an older version of SharePoint they noticed that the emails no longer had this ID in them. It is quite important for them to have the ID easily available. So I set out to modify the alert templates.

There is no specific alert template for issue list. However, there is one for this assigned to notification email. See the MSDN article about alert templates for further reference on all of the different templates. 

In SharePoint 2013 all alert templates are in one XML file located in the C:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\TEMPLATE\XML directory on the SharePoint App server. The file you need is alerttemplates.xml.

As with anything located in the SharePoint root, you should not modify the original template file, but make a copy of it in the same directory and rename it, eg. alerttemplatesIssueId.xml. Then open this copy file for editing (notepad will do, VisualStudio is more colorful ;) ).

It is a long winded file. The AlertTemplate elements wrap each different template. Each has the template type set as value for Name attribute, e.g. Name="SPAlertTemplateType.GenericList".

In order to simply make the Issue ID visible in the notification email for changed "assigned to" value, find the SPAlertTemplateType.AssignedtoNotification template. Find the properties element. Remove ID from the ImmediateNotificationExcludedFields.


This will make the ID visible in the email body of this notification email. If you wish to have the ID visible in any alert a user subscribes to regarding the Issue list, you will need to remove the ID from the exclude fields of the properties in the GenericList template, since issue list does not have one of its own. Note, that all the other templates have two properties, the Immediate and Digest notification exclude  fields.


This was not enough for my customer, since they wanted to have the ID also in the email subject. This can be achieved rather easily by adding the ID field variable to the subject element. The trick, especially with the AssignedToNotification template, is to find the correct place. 

The ID field variable itself is added as a single tag element: <GetVar Name="NewValue#ID" />

The place to add it to, is next to the item name or list name, eg.


In the AssignedToNotification template this is crammed between two switch elements, inside the subject element. In the GenericList template, the subject element is far more simple:


This would already display the ID in the subject, but just to make it a bit more readable, you should add some HTML between the variables, eg.



Now, save your alert template. In order to get SharePoint to use this template, you need to run a little stsadm command. The easiest way is to open the SharePoint Management shell, run as admin, and then run the command:

stsadm -o updatealerttemplates -url http://<sitecollectionUrl> -filename "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\TEMPLATE\XML\alerttemplatesIssueID.xml"

(Note, copy-paste will probably not work for the command because of the quotation marks)

After running this command, you need to do an iisreset, and that's it. Your templates are ready and in use!


Sep 17, 2015

Broken Blog Post Filtering in SharePoint 2013

Some time last spring I created two blog sites to a customer SharePoint 2013 intranet. I set them up quite similarily, the only difference being that I added some custom fields to the other one. This should, in my logic, not affect anything in the different blog views - such as archives and category views - since I didn't touch any of the OOB fields. Whatever the reason, the end result was however, that last week the customer noticed (hmm, not very active blogging then ;) ) that on the other blog site the category and archive pages were broken. They did not filter the posts anymore as they should.

I banged my head against the wall for a while, googled, googled some more and tried this and that. Nothing seemed to help. One workaround I tried was this most commonly mentioned solution of adding a URL filter web part and setting it up as instructed eg. in this post here.

This, however, did not work for me, or this customer site. Be it due to the language pack (Finnish site) or something else, but it did not work. So I needed something else. This is what I did:

1) I created a new blog in the test environment. Really it doesn't matter where, just as long as you can access it in SharePoint Designer.

2) I opened both the new non-broken blog site and the old broken one in SharePoint Designer. I know. I sighed deep when I realized I really needed to go that far. But unfortunately the problem seems to reside in the corrupted query of the posts web part and in order to fix that, yes, SPD is required.

3) The two pages that are not working properly when categories and archive are not filtering posts, are Categories.aspx and Date.aspx. These are not in the Site Pages library of the blog site; you need to dig them out from the All files directory. 
All files > Lists > Categories > Category.aspx
All files > Lists > Posts > Date.aspx

Open both files on both your broken site and the new one created.

4) No, copying all code from one to the other will not work because of the GUIDs. As stated earlier, the broken part is the CAML query of the Posts web part. So the first thing to do is to locate the Posts web part. Since you are working in code view only, look for the main place holder with the blog-MainArea to find the correct web part.


5) Focus on the line starting <View Name="{...

6) Scroll horizontally (or set your page to wrap lines) until you find the <query> tag. This begins the CAML query for the web part. On the borken page it was missing parts. So I copied the query (everything between the <query> and </query> tags) from my new site category and date pages to the broken corresponding ones, replacing the broken queries.

7) I saved my files and tested them. The initial refresh filtered posts nicely, but the blog navigation (the categories list and the blog archive) links were broken, for the Blog tools web part was broken. It seems that any time you open a blog page into SharePoint Designer, this web part breaks.

8) So, I edited both pages in the browser, deleting the broken Blog tools part and adding it back in place and yes, things started functioning again! 

Hope this helps someone else save some time. Boy, there's never a boring day with SharePoint!

Sep 4, 2015

Using SharePoint Client Context JavaScript on Publishing Site

In order to use SharePoint Client Context (SP.ClientContext) in your own custom Javascript on a pafe, you need to ensure that sp.js is loaded. This is an onDemand file, which means it is loaded only when needed, i.e. when the browser requests it. In most cases it gets loaded because of something, most commonly the ribbon, on the page, so it is sufficient to start your custom Javascript with

ExecuteOrDelayUntilScriptLoaded(CustomFunctionUsingContext, "sp.js");

On Publishing sites, however, when the page is published, ribbon is hidden and sp.js does not get loaded unless there is some other code on the page to demand it. Thus, you might need to use a bit of force to get sp.js loaded. That is, you need to demand it yourself. The function for this would be

SP.SOD.executeFunc("sp.js", "SP.ClientContext", CustomFunctionUsingContext);

or

SP.SOD.executeFunc("sp.js", "SP.ClientContext", function(){
 YourCustomCodeHere
}); 

This is exactly what I was trying to use when inserting a code snippet on a Publishing page, using the Client Context to retrieve subwebs, for some odd reason the above did not do it, so I tried something that seemed totally crazy:

SP.SOD.executeFunc("sp.js", "SP.ClientContext", function(){
 ExecuteOrDelayUntilScriptLoaded(CustomFunctionUsingContext, "sp.js");
});

Strangely enough it started working after that. Later on, when none of the above seemed to work on a team site, except in page edit mode, I started to wonder if the problem really was this or something within SharePoint (throttling thresholds, script not loading every time, whatnot). I am not inclined to change it anymore since now it works. Anyway, might be wise to add some code there to avoid being throttled or blocked by SharePoint

Jun 25, 2015

Open documents in Office Web Apps from CSWP

One of my customers has a Content Search Web Part in their intranet home page, listing both documents and pages. They have Office Web Apps installed and are quite happy with the way documents open to OWA instead of the desktop client from the document library and search results. The CSWP, however, does not natively support opening documents in the OWA, so a bit of display template modification is required.

I was already using rather heavily modified item display template for the customer, so I simply needed to modify that one, but you can also copy any item display template (from the Master Pages gallery, Display Templates > Content Web Parts folder) that best fits your purposes and modify the copy. Mind you, you only copy the html template, modify it, save it with another name and upload it back to the library. The .js file will be automatically created.

The things you need to do to your display template in order to enable opening documents in OWA are: 

1) Add the managed property 'ServerRedirectedURL' to the managed properties: 


This is the property that provides the open in OWA url for documents. You could use this as a simple property for the LinkURL, but if you cannot be certain that each and every document that gets listed in the CSWP is in fact an office document, you need to add a bit more code to the template.

2) Right there, where the commented code of the display template begins, below the var encodedId line, insert the following code I intecepted from the common search result item template:

var useWACUrl = !$isEmptyString(ctx.CurrentItem.ServerRedirectedURL);
        if(ctx.ScriptApplicationManager && ctx.ScriptApplicationManager.states){
            useWACUrl = (useWACUrl && !ctx.ScriptApplicationManager.states.openDocumentsInClient);
        }
        var appAttribs = "";
        if(!useWACUrl)
        {
            if (!$isEmptyString(ctx.CurrentItem.csr_OpenApp)) { appAttribs += "openApp=\"" + $htmlEncode(ctx.CurrentItem.csr_OpenApp) + "\"" }; 
            if (!$isEmptyString(ctx.CurrentItem.csr_OpenControl)) { appAttribs += " openControl=\"" + $htmlEncode(ctx.CurrentItem.csr_OpenControl) + "\"" };
   
        }
        var url = ctx.CurrentItem.csr_Path;
          if($isEmptyString(url)){
            if(useWACUrl)
            {
                url = ctx.CurrentItem.ServerRedirectedURL;
    
            } else {
                url = ctx.CurrentItem.Path;
   
            }        
        }

3) Then modify the LinkURL variable to use the url instead of the default Path:
var linkURL = $urlHtmlEncode(url);

4) Finally, remove the line
linkURL.overrideValueRenderer($urlHtmlEncodeValueObject);

And that's it, folks.