SharePoint JSLink – disable the filter and sorting pane on list view headers

I had the requirement to disable the functionality to sort and filter on column headers in the list view. I could not find a lot about it online so here is my solution using CSR/JSLink and Jquery

(function () {
var Context = {};
Context.OnPostRender = disableHeaderFilter;

function disableHeaderFilter(renderCtx)
var linkTitleField = renderCtx.ListSchema.Field[5];
$("div[name="+ linkTitleField.Name + "]").parent().replaceWith('<th class="ms-vh2">' + linkTitleField.DisplayName + '</th>');

The 5 in the code is the column number order in the header

Tags :

MUI Refinements panel in SharePoint 2013

Just as it was the case in SharePoint 2010, in SharePoint 2013 the refinement panel only shows in the default language, even if the translations were added in the term store manager.

There was a solution for SharePoint 2010 (Thanks to Timmy Gilissen) but I could not find a lot of resources for a 2013 solution. With the help of Didier Danse, Timmy Gilissen and some online blogs (I learned a lot from the blog of Elio Struyf), I managed to reach a solution.

This solution is still under development and can be improved so I am open for suggestions. Following improvements are still lacking:

  • Obtain the translation purely by GUID and that way, avoid searching for the GUID of a term first (i had not found this yet)
  • Rewrite the scripts so that no DIV output is done until all translations are loaded (no idea if this is possible)
  • Following to the above, outputting the translated value by calling the outputFilter function and not modifying the innerHTML of the DIV

In SharePoint 2013 we can no longer use the solution by creating a farm solution and inheriting from the WebPart class as it was the case in 2010. We should now modify the refinements behavior through javascripts and by using JSOM in the Filter Display Templates.

So let’s start by opening SharePoint Designer:

1) Add the ScriptLinks to your master page. We are going to use sp.js, sp.runtime.js and sp.taxonomy.js (optionally to provide user feedback, we can add sp.ui.dialog.js and sp.init.js) . I put them in the master page because sometimes I have issues with them not being loaded before I want to use them. As my Enterprise Search Center only exists out of a page or two, I assume this can’t be a problem nor generates extra load.

	<SharePoint:ScriptLink ID="customScriptLink1" Name="sp.js" runat="server" OnDemand="false" LoadAfterUI="true" Localizable="false" />
	<SharePoint:ScriptLink ID="customScriptLink2" Name="sp.runtime.js" runat="server" OnDemand="false" LoadAfterUI="true" Localizable="false" />
	<SharePoint:ScriptLink ID="customScriptLink3" Name="sp.taxonomy.js" runat="server" OnDemand="false" LoadAfterUI="true" Localizable="false" />
	<SharePoint:ScriptLink ID="customScriptLink4" Name="sp.init.js" runat="server" OnDemand="false" LoadAfterUI="true" Localizable="false" />
	<SharePoint:ScriptLink ID="customScriptLink5" Name="sp.ui.dialog.js" runat="server" OnDemand="false" LoadAfterUI="true" Localizable="false" />

2) Copy the default filter HTML found in

_catalogs > masterpage > Display Templates > Filters

and paste it. Rename it to something like “Filter_MultiLang.html”. Don’t mind the .js-file, it will be auto-generated by SharePoint.

3) Rename the title in the Filter_MultiLang.html

<title>Multilanguage Refinement Item</title>

This will be the title that will be shown in the refiners configuration of the Refinement webpart

4) First we define some global variables we will use. I created ‘termstorename’ which is a hardcoded string containing the name of the Managed Metadata Service. You are supposed to modify this. Next we have ‘client_language’ which will hold the current browser language of the user (LCID, such as 1033, 1036,…). Next we have ‘context’ which will hold the ClientContext object, ‘taxSession’ which will hold the Taxonomy Session Object and a variable which will hold the TermStore, called ‘termStore’.

var termstorename = "Omptranet Managed Metadata Service";
var client_language = _spPageContextInfo.currentLanguage;
var context = SP.ClientContext.get_current();
var taxSession;
var termStore;

The function that will initialize the Taxonomy Session Object is the following:

function initTax(termstorename){
taxSession = SP.Taxonomy.TaxonomySession.getTaxonomySession(context);
var termStores = taxSession.get_termStores();
termStore = termStores.getByName(termstorename);

Notice that we just create the Term Store object and we will query this to obtain our translations. We could also use a TermSet object for this but I will explain in the next step why I choosed to use the global Term Store.

5) Now we create a function that returns the refinement GUID given the refinementName. I did not yet found a way to directly retrieve the GUID from the standard code. I thought it was the refinementToken object but that does not resemble a correct GUID so that’s why I will lookup the GUID by passing the default value of the refinement. So we are searching for strings, which is never a good idea but for now I did not find a proper solution yet.

function getGUID(refinername, termstorename, success, error){

var matchInfo = new SP.Taxonomy.LabelMatchInformation(context);
var termMatches = termStore.getTerms(matchInfo);

function() {
if(termMatches.get_data().length &gt; 0){
error("getGUID FAILED for " + refinername);
error("getGUID FAILED");

We use the getTerms(matchInfo) function of the termStore object to retrieve our data. Querying against the Term Store will search in all TermSets of the MM Service. We could also query against a separate TermSet but this would imply that each time we want to search, we should create a corresponding TermSet object. That’s why I just use the global Term Store.

Notice that when there is data found, I just take the first result as the GUID. It is possible that a result of the query actually shows a value from another Term Set. I did not see this as a problem because eventually it are the same words, so they should have the same translation.

6)After that, we create a function that searches the refinement name in a language we can specify. As refinerguid parameter we give the GUID that our previous function returns. For the language we can use our global variable which returns the language LCID (1033, 1036, etc…). We still pass it as a parameter to the function; this is actually not needed.

function getTranslation(refinerguid, language, termstorename, success, error){

var translated_term = "";
translated_term = termStore.getTerm(refinerguid).getAllLabels(language);
function() {
if(translated_term.get_count() &gt; 0){
error("No translations found for " + refinerguid);

7)Now we adjust the default outputFilter function :

            function outputFilter(refinementName, refinementCount, refiners, method, aClass, showCounts, refinementToken) {
                var aOnClick = "$getClientControl(this)." + method + "('" + $scriptEncode(Sys.Serialization.JavaScriptSerializer.serialize(refiners)) + "');";
                var nameClass = "ms-ref-name " + (showCounts ? "ms-displayInline" : "ms-displayInlineBlock ms-ref-ellipsis");

		if(!(method == "updateRefinersJSON")){
		  var guid = refinementToken.match(/"+([^"]*)/g)[0].replace('"','').substring(2);

		        getGUID(refinementName, termstorename,
		         	 console.log("GUID found for " + refinementName + " -> " + refinerGUID);
					 getTranslation(refinerGUID, client_language, termstorename,
			 				document.getElementById("RefinementName" + guid).innerHTML = ">" + translation;
            <div id='Value' name='Item'>
                <a id='FilterLink' class='_#= $htmlEncode(aClass) =#_' onclick="_#= aOnClick =#_" href='javascript:{}' title='_#= $htmlEncode(String.format(Srch.U.loadResource("rf_RefineBy"), refinementName)) =#_'>
                    <div id='RefinementName_#= guid =#_' class='_#= nameClass =#_'> _#= $htmlEncode(refinementName) =#_ </div>
                if (showCounts) {
                    <div id='RefinementCount' class='ms-ref-count ms-textSmall'> (_#= $htmlEncode(Srch.U.toFormattedNumber(refinementCount)) =#_) </div>


Notice that I pass the refinementToken parameters as an extra (because I thought It would equals the refinement GUID) but It may be deleted.

Notice that we call our two custom functions to retrieve the translation. We show the translation on the page by calling

document.getElementById("RefinementName" + guid).innerHTML = ">" + translation;

This might not be the right way to do it. Ideally, we would pass the translated term to the outputFilter function but by using our async calls, the divs are already displayed on the page. If there is a way to let the div-output wait the finishing of the async calls, that would be great but for the moment I have not found the solution.

That is also why we concatenate the (incorrect) guid to the div’s ID so that we can get the div-object in the DOM and modify the innerHTML.

Also the if-statement that checks the method not to be “updateRefinersJSON” is there for a reason. We don’t want to force translations on the “All Items”-link (that shows after you have refined). There is a chance that otherwise the “All items”-link is overwritten by a translation. And what’s even better, that link will be translated OOTB.

7) Another thing is that when we have to modify the show / hide refiners function. By default some things are (re-)loaded and it might interact with our translations that were added by our javascripts. That’s why I modified the default code to:

                <a id='unselToggle' class='ms-ref-unsel-toggle ms-commandLink' onclick='if(this.parentNode.querySelector("#unselLongList").style.display == "none"){this.parentNode.querySelector("#unselLongList").style.display="block";for(i=0;i &#60; 5;i++){this.parentNode.querySelector("#unselLongList").querySelectorAll("#Value")[i].style.display="none";}}else{this.parentNode.querySelector("#unselLongList").style.display="none";};'>
                    <div class="ms-displayInlineBlock">_#= $htmlEncode(Srch.U.loadResource("rf_RefinementLabel_More")) =#_</div>


Actually it’s just a javascript toggle.

8) To see your code in action on the search refinements, edit your refinement panel, click Refinements… and modify the Filter Display Template per section. You should be able to select your custom Filter there (as the title you gave your custom HTML-page).

9) Result: In the screenshot, my browser language is French. Where my code found a translation, the refinement is prefixed with a >

10) as an extra, we could add some notifications to alert the user that there is some extra translation code going on. Attention: you have to add the ScriptLinks to sp.init.js and sp.ui.Dialog.js as described in step 1

Add the following function to the page:

	function showFeedback(message){
//the round loading gif is = PROGRESS-CIRCLE-24.GIF (i suggest to add some resizing attributes eg. width='12' in the img-tag)
		SP.UI.Notify.addNotification("<img src='" + _spPageContextInfo.siteAbsoluteUrl + "/" + _spPageContextInfo.layoutsUrl + "/images/progress.gif'>&nbsp;&nbsp;" + message, false);

Next, place the following code

showFeedback("Translating " + refinerCatTitle);

beneath this code:

var refinerCatTitle = Srch.Refinement.getRefinementTitle(ctx.RefinementControl);

The result will be a notification that refinements are translated (per block)

Now, for different reasons it can occur that terms are not translated. For example, the content type names still aren’t displayed multilingual. Or non-managed metadata that is used as refinements. Thanks to the search against the global termstore, we can fix these lacking translations by just adding a new termset eg. “UntranslatedContent”, and add the terms there (with the translation of course)

Full source: Download Filter_MultiLang.html

Tags : , ,

SharePoint 2013 – Can’t approve or reject access requests

We had a problem that a specific group (site owner) should be able to approve or reject access requests to their sites. By default, only site collection administrators can do this.

As the ‘Access requests’-list is a hidden library we should use a little trick to reach the permissions of the list.

  1. Open your SharePoint Designer and connect to your site
  2. Go to ‘All Files’ in the navigation
  3. You should now see the ‘Access requests’ list – Right click on it > Properties
  4. You can now reach the permissions settings for this list
  5. Add your group and give it full control

This should fix it. If it doesn’t then possibly your group is not known as a ‘real’ owner group in your site. Fix it by following these steps:

Take your site url and paste the following behind it: /_layouts/15/permsetup.aspx . You can now re-define the default groups for your site. Be sure to select your group at the ‘Site Owners’ category below.

Hope this helps


Tags :

Android tablet – Belgische kranten

Apps om kranten digitaal te bestellen bestaan zowel voor Het Laatste Nieuws, De Standaard, De Morgen etc… helaas is mijn, wat verouderde, tablet niet meer in staat deze apps te draaien of zijn de apps op z’n minst niet echt snel.

Indien ik op reis ben, lees ik mijn krant meestal via PressDisplay (althans via hun app). Het probleem is dat dit énkel werkt wanneer u niet in België bent. Aan de hand van uw IP of internetverbinding kan dit gecontroleerd worden. Alle kranten kosten trouwens slechts .99€, goedkoper dacht ik dan via de normale apps van de uitgevers.

Om de krantendownload toch te laten werken vanuit België, dient u op uw Android tablet Hideman te installeren. Deze brengt een (gratis) VPN-connectie tot stand zodat de pressdisplay app denkt dat u in het buitenland zit.

Indien u dan uw krant wenst te downloaden, werkt dit perfect.

FourPoly – Foursquare meets MonoPoly

I started a new android project inspired by the, well, really badly written LandLord – app. The idea of combining Foursquare and Monopoly was excellent to me and i tried to code it myself.

Resulting in a beta now which can be downloaded from the Google Play Store.

Current working functionality:
Buy and sell Foursquare venues
Hourly you’ll receive money depending on new checkins, distinct users and likes
Attack venues and take them over by force
Make offers to buy venues ‘legally’

I’m urgently looking for users who want to test and play the game and give me feedback/input to make the game more appealing and fun to play.


Verschil tussen Sharepoint 2010 Standard en Enterprise

De Sharepoint 2010 Standard versie mist bepaalde functionaliteit vergeleken met de enterprise versie. Sommige van deze beperkingen kunnen weliswaar opgevangen worden met eigen programmatie, andere dan weer niet.

Grootste verschillen – ontbrekende features in standard versie

Business Intelligence (BI) – “Insights”

  • BD Web Parts – Chart Web Parts: Bepaalde web parts zullen niet beschikbaar zijn zoals bvb. ‘status indicators / KPI’ (data wordt gemarkeerd, of icoontjes wijzigen wanneer bepaalde data voldoet aan voorwaarden). Er kunnen ook geen grafieken worden gegenereerd op basis van lijsten of externe data.
  • Data Connection Library: Zorgen er hoofdzakelijk voor dat er data kan worden aangesproken uit Office documenten (ODC). Ook externe data  (UDC) zal slechts in mindere mate geïntegreerd kunnen worden (data uit SQL server, webservice, XML files,…).  Doordat InfoPath toch niet beschikbaar is in de standard versie, heeft het ontbreken van deze feature weinig impact.
  • Excel Services: het zal niet mogelijk zijn om Exceldocumenten weer te geven binnen Sharepoint als een webpagina. Ze kunnen natuurlijk wel in een document library geplaatst worden maar directe weergaves zullen niet lukken.
  • Performance Point – Status Indicators: Performance Point wordt gebruikt om een soort van ‘Dashboard’ te creëren die een reeks data samenvat. Het zou bijvoorbeeld een realtime weergave kunnen zijn van de bezoekers per pagina in de vorm van grafieken, tabellen, enz…
  • Visio Services: Visio is een programma dat gebruikt wordt om schema’s en diagrammen te maken. Met de Visio Services kunnen tekeningen en diagrammen externe data(Database, andere lijsten,…) bevatten dat realtime geupdate wordt. Dit zal dus niet mogelijk zijn in de standard versie.


Via een apart programma ”InfoPath” kunnen formulieren op een makkelijke manier worden ontworpen of aangepast, zonder zelf code te gaan schrijven. Voor simpele formulieren is dit een goeie oplossing maar voor meer geavanceerde formulieren lijkt het me niet echt geschikt, alhoewel Microsoft het soms anders beweert.


Search – FAST

  • Contextual search results (Afhankelijk van het profiel van de gebruiker worden andere zoekresultaten getoond)
  • Thumbnails and previews (Inhoud van documenten (ppt, doc, xls) wordt getoond in de zoekresultaten en kan doorbladert worden zonder het document expliciet te openen)
  • Extreme Scale Search (Scalability)



Impact en eventuele ‘oplossingen/workarounds’


Wat betreft de BI kunnen we kort zijn. De meeste features zijn gericht op het weergeven van data in grafieken en tabellen eventueel aangevuld met KPI’s en indicatoren. Op zich is dit gebrek niet zo erg want in principe kunnen we toch nog grafieken gaan tonen (weliswaar met eigen scripting in ASPX).

Het is belangrijk om te weten dat we toch nog steeds externe data (vb. uit een Oracledatabank) kunnen binnenhalen en weergeven in een ‘external list’. Er zullen gewoon een reeks beperkingen zijn zoals het ontbreken van een zoekfunctionaliteit in externe lijsten.

Gezien we in de eerste plaats aan document management zullen doen, is het geen ramp dat enkele van deze features ontbreken.


We kunnen geen formulieren aanpassen of ontwerpen met InfoPath maar eventueel wel met eigen codering in Visual Studio.  Op zich ook geen echte ramp want de infopathformulieren zijn goed voor basic invoer. Voor geavanceerde data-input zal er toch snel moeten worden overgeschakeld op programmatie in .net.


Het ontbreken van de FAST-zoekserver is misschien het spijtigste. Toch bevat de Standard Sharepoint 2010 versie een zoekfunctie die ook wel niet slecht zal zijn. We kunnen het hier nog niet onmiddellijk testen maar de features die ontbreken zijn eigenlijk geavanceerde toeters en bellen die niet altijd ‘need to have’ zijn .

De previews van documenten bijvoorbeeld, is een leuke feature maar wanneer die er niet is kan er nog steeds gezocht worden.



Licentiekosten (bij intranet-gebruik) [1]

Misschien wel nuttig bij dit document is om de kostprijs de vermelden van het ganse Sharepoint –verhaal.

De totale kostprijs dient berekend te worden op basis van de kosten van de server én een licentiekost per gebruiker.

  • Elke server in de Sharepoint Farm heeft een licentiekost:  5000€
  • Elke gebruiker heeft een CAL (Client Access License) nodig.
    • Standard: 99€
    • Enterprise: 88€ (+ de standard CAL!!!)
    • Eventuele FAST Search Server: 23000€


Het is de CAL die bepaalt of er met de standard of enterprise versie kan worden gewerkt. De server kan sowieso beide versies aan.


2 server farm met 5000 gebruikers:

Standard Sharepoint 2010:

2 Servers 5.000,00 € 10.000,00 €
5000 Gebruikers (STANDARD CAL) 99,00 € 495.000,00 €
505.000,00 €




Enterprise Sharepoint 2010 zonder FAST:

2 Servers 5.000,00 € 10.000,00 €
5000 Gebruikers (STANDARD CAL) 99,00 € 495.000,00 €
5000 Gebruikers (ENTERPRISE CAL) 88,00 € 440.000,00 €
945.000,00 €




Enterprise Sharepoint 2010 mét FAST:

2 Servers 5.000,00 € 10.000,00 €
5000 Gebruikers (STANDARD CAL) 99,00 € 495.000,00 €
5000 Gebruikers (ENTERPRISE CAL) 88,00 € 440.000,00 €
1 FAST Search Server 23.000,00 € 23000
968.000,00 €

Om maar duidelijk te maken dat de kostprijs enorm verschilt, wat ons tot de hamvraag leidt:  “Is de extra functionaliteit de meerprijs wel waard? “

[1] De bedragen zijn afkomstig van en werden afgerond maar geven toch een goeie indicatie van het verschil in kostprijs tussen de standard en de enterprise versie.

Sing Something for Android alternative (Android 2.1+) – SingGuess

Well, it’s been a while since the Sing Something app for Iphone has been released. Eager to play it on my Android phone I couldn’t wait any longer and started, just for the fun of it, to develop my own Sing Something application, named “SingGuess”. I’m trillion percent sure the original app will be a lot better in terms of performance, functionality and especially GUI but anyway, I’ve become to the point that it is playable (I guess). So I’m actually looking for betatesters who are willing to test the app and give me some feedback on the three subjects I described above.

The app was developed on a HTC Wildfire so low spec-phones should be able to run it. Also, the minimum version of Android should be 2.1. As seen with the Draw Something app, I’m expecting the real Sing Something app won’t be supported for low-spec phones such as my HTC Wildfire.

So, please react if interested.




















You can the app in the Google Play Store

Low-carbohydrate diet

After a couple of years living the good life, i encouraged myself that the time is come to do something about my overweight. It’s still not that bad, but a great time to start working on it. I want to lose 10kg.

I read about the low-carb-diet at the internet and it seems promising. One can keep eating a lot but just no or very few carbohydrates. From now of on, it seems i can only eat vegetables, red meat, low-fat fish and nuts.What you can’t eat is bread, pasta, peas, most of the fruits.

The idea behind is, is that if you eat a lot of proteines instead of carbs, your body will decide to go in ketose - state which means that it will start burning your own fat (and not the carbs u used to take in). Sounds good to me!

More info on this diet

Spotify – premium account without visa (part II)

Ok, apparently, the service which was offered by the dutch website doesn’t work anymore. Spotify doesn’t allow other users to resell premium codes. We pay spotify premium now by visa or driving to holland where the cards are sold in Albert Heijn stores. Bummer.

Oracle Portal 10g to Microsoft Sharepoint 2010 Migration

At work we have been planning a migration from Oracle Portal 10g to Microsoft Sharepoint. Currently holding more than 100gig of data and documents, it’s understandable we can not migrate it manually. It seemed a big problem to get an automated tool which migrates all our pages (and the structure) and the underlaying document (including the title and description). We did not need to migrate the OID groups, page security rights and so on. Just the folder structure and its contents.

Consultants couldn’t be found that easily and time kept on ticking away. That’s why i developed a tool myself. All it does is automatically copying the selected Oracle Portal folder and contents to the selected Sharepoint Library. I must say it works flawlessly.

Tools used:, Sharepoint webservices (especially lists.asmx & dws.asmx). If any questions, i am glad to explain more.