13 maart 2015

Display Templates: Slider

In deze blogpost ga ik uitleggen hoe je door middel van een Display Template een slider kan maken die de hele breedte van je scherm bedekt. Ik ga daar de Revolution Slider in Unify voor gebruiken. Dat is een hele mooie, responsive slider en daarmee meteen geschikt voor mobiele devices. Unify is gebaseerd op Bootstrap, wat een veel gebruikt responsive platform is, een aanrader.

We gaan de slider baseren op het Search Results Web Part, en omdat de slider even breed als ons scherm moet worden, gaan we ook een aangepaste Page Layout maken. De slider komt er uiteindelijk zo uit te zien:



Start

De eerste stap die we nemen is het downloaden van de Starter Display Templates, die vind je in mijn andere blogpost. Sla de bestanden op onder een duidelijk herkenbare naam. In het geval van de slider zou dat iets als 'SliderControl' en 'SliderItem' kunnen zijn.

Upload de Display Templates (via de browser) naar Display Templates -> Search, in de Masterpage Gallery (Site Settings -> Web Designer Galleries -> Master pages and page layouts). Als je de bestanden hebt geüpload, zie je dat er vanzelf JS bestanden bij worden gegenereerd. Zo niet, dan is er iets niet goed gegaan.

Je kan ook via de 'New' button in de Display Templates-map nieuwe Display Templates aanmaken. De keuzes 'Control Display Template' en 'Item Display Template' zijn te vinden in de dropdown lijst.

Je kan vanaf nu het beste de Masterpage Gallery mappen (als je dat nog niet hebt gedaan, lees dan hier hoe je dat doet). De betreffende Display Templates kan je vanaf nu direct vanuit de verkenner openen in Notepad++ of een andere editor naar keuze.

Maak nu een Picture library aan in SharePoint. Geef deze een naam zonder spaties! Dit is belangrijk, want SharePoint vind spaties niet zo leuk, dus als er spaties in de url voorkomen, werkt het niet. Upload vervolgens de afbeeldingen die je in de slider wilt zien, in de library. Let er op dat je slider heel breed kan worden (zo breed als je scherm), maar wel een vaste hoogte heeft. De afbeeldingen moeten dus laag en breed zijn. Vul ook de velden van de titels en beschrijvingen in, die gaan we ook gebruiken in de slider.

Page Layout

De slider die we gaan maken is flexibel in breedte, maar altijd net zo breed als je scherm. Omdat voor elkaar te krijgen, moeten we de markup(HTML) op de betreffende pagina aanpassen. We maken de pagina 80% breed, behalve de slider, die wordt 100% breed.

Maak een nieuwe Page Layout aan. Dat kan je doen door een bestaande te kopiëren, maar ook door in de browser naar de Masterpage Library te navigeren (~/_catalogs/masterpage/Forms/AllItems.aspx) en in de ribbon op het pijltje bij New Document te klikken. Je krijgt dan een lijst te zien waar ook de Page Layout in staat.
Een derde optie is om de Design Manager te openen en daarin een Page Layout aan te maken. Die optie gebruik ik zelf meestal.

Voeg nu onderstaande CSS code toe aan de <!--MS:<asp:ContentPLaceHolder id="PlaceHolderAdditionalPageHead" runat="server">--> van de Page Layout (helemaal onderaan, dus vlak voor de sluit-tag): <!--MS:<style type="text/css">-->
/* De standaard contentBox heeft margins. Dat willen we niet, want de slider moet de hele paginabreedte innemen. De margins halen we dus weg. */
#contentBox {
margin: 0;
}

/* De sidenav staat nu standaard boven de slider. Die willen we er graag onder hebben, naast de rest van de content. Doen we dat niet, dan zal de sidenav de slider omlaag duwen en dat is niet mooi. De slider is nu flexibel in hoogte, maar die gaan we later nog beperken tot max 400px, vandaar deze waarde bij top. */
#sideNavBox {
position:relative;
top:500px;
}

/* Omdat de slider flexibel is (met een max-height van 400px), wordt hij steeds kleiner en minder hoog naarmate je scherm kleiner wordt. De mediaqueries gebruiken we om de relatieve afstand van de sidenav hierop aan te passen. In geval van IE werkte het alleen vanaf versie 9 en hoger.*/
@media screen and (max-width: 1024px) {
#sideNavBox {
top:450px;
}
}

@media screen and (max-width: 880px) {
#sideNavBox {
top:450px;
}
}

@media screen and (max-width: 730px) {
#sideNavBox {
top:450px;
}
}

/* Het is zeer waarschijnlijk dat er meer inhoud op je pagina komt dan alleen de slider. De contentPositioner positioneert een <div> op een breedte van 80% van je scherm en centreert deze op de pagina */
.contentPositioner {
margin: 0 auto 0 220px;
padding-top: 15px;
}

/* Hieronder staan 3 Web Part zones, twee smallere aan de zijkanten en een bredere in het midden */
.wpzLeft {
float: left;
width:25%;
margin:0 2% 0 0;
}

.wpzCenter {
float: left;
width: 46%;
}

.wpzRight {
float: left;
width: 25%;
margin: 0 0 0 2%;
}
<!--ME:</style>-->

Het is 'best practise' om zo min mogelijk inline CSS te gebruiken, dus normaal gesproken kun je de styling van Page Layouts het beste in je 'algemene' style sheet vanuit de custom Masterpage, of de Additional CSS instelling definiëren. Nu doe ik het even zo, omdat we ons hier willen richten op deze specifieke pagina, zonder alle rompslomp eromheen. In de CSS heb ik d.m.v. comments aangegeven waar de regels precies voor dienen, mocht je dat interessant vinden :-)

De volgende stap is de HTML op de Page Layout. Die vind je hier.
Vervang alle code die in de <!--MS:<asp:ContentPlaceHolder id="PlaceHolderMain" runat="server">--> tag staat, op de Title snippet na. In de code staan de Web Part zones er al in. Die hebben ieder een eigen ID. Het zou kunnen dat dat op jouw installatie problemen geeft. Als dat zo is, genereer dan zelf nieuwe IDs via de Snippet Tool of SharePoint Designer.

Als laatste moet je je Page Layout instellen op de gewenste pagina. Dat doe je door naar die pagina te navigeren, op het PAGE tabje te klikken van de ribbon en vervolgens op de Page Layout knop te klikken. You zou hier je custom Page Layout moeten kunnen kiezen, maar alleen als je hem eerst hebt gepubliceerd.

Web Part

Om de resultaten te kunnen zien van de aanpassingen die je straks in de Display Templates gaat maken, moeten we eerst het Web Part aanmaken. Zoals eerder vermeldt gebruiken we hiervoor het Search Results Web Part.

  1. Ga naar de pagina waar je de slider wilt plaatsen.
  2. Voeg een Web part toe aan de zone Slider Zone.
  3. Kies het Search Results Web Part en klik op Add.
  4. De volgende stap is het maken van de query zodat de juiste gegevens worden opgehaald.


  5. Ga naar het Edit Web Part menu (zie het pijltje rechts bovenin het Web Part)
  6. Klik op Change Query
  7. In het tabje Basics (zorg dat de Quick mode aan staat, dat zie aan het linkje rechts bovenin het tabje Switch to Advanced Mode/Switch to Quick Mode) selecteer je bij Select a query de optie Pictures (System).
  8. Bij Restrict by app kies je voor Specify a URL en geef je de volledige url naar je eerder aangemaakte Pictures library in.
  9. Restrict by tag moet blijven staan op Don't restrict by any tag.
  10. Klik op OK.
  11. Klik in het Web Part menu op Apply (nog niet op OK!).
  12. Waarschijnlijk wint wat je nu ziet niet de schoonheidsprijs, maar je zou wel wat content uit de Pictures Library moeten zien nu. Klik het Web Part Edit menu nog niet weg, want we gaan nu de juiste Display Templates instellen.


  13. Klik nu op de + bij Display Templates.
  14. Als eerste zie je nu een dropdown met Results Control Display Template. staan. In die dropdown zou je je eigen Control Display Template moeten zien, die je eerder hebt aangemaakt. Selecteer die. (Zie je hem niet? Heb je hem gepubliceerd?)
  15. Er onder staan twee radiobuttons. Selecteer de onderste waarbij staat: Use a single template to display items.
  16. Hieronder zie je weer een dropdown menu. Ook hier zou je eigen Item Display Template tussen de opties moeten staan. Selecteer die.
  17. Klik de + bij Display Templates nu weer dicht.
  18. De Display Templates zijn nu ingesteld, maar er zijn ook nog wat instellingen die andere dingen weergeven buiten de Templates. Die willen we niet zien, dus dat moeten we nog even uitschakelen.


  19. klik op de + bij Settings.
  20. Vink alles uit, behalve Show ranked results (Als we die ook uit zouden zetten, zouden we helemaal geen data zien in het Web Part).
  21. Het getal bij Number of results per page doet er niet toe, dat regelt jQuery straks. Kan je dus laten staan zoals t staat.
  22. Klik de + next bij Settings weer dicht.
  23. Standaard laat een SharePoint Web Part een titlebar zien, die willen we natuurlijk niet bij de slider, dus dat passen we ook nog even aan.


  24. Klik de + bij Appearance open.
  25. Onderin zie je nu Chrome Type staan, met een dropdown menu. Kies de optie None.
  26. Voor de netheid kan je bovenin bij title nog even een naam voor je slider invullen. Die naam is niet direct zichtbaar, want dat hebben we net uitgezet.

Zo, dat was het v.w.b. de instellingen. Het lijkt nu nog helemaal niet op een slider, dus we gaan aan de slag met de invulling van de Display Templates.

Display Templates

Zoals ik in mijn eerdere blogpost heb vermeld, werken Display Templates met z’n tweeën, één als 'hoesje' voor het geheel (Control Display Template) en de ander voor individuele items (Item Display Template). Laten we beginnen met de eerste.

Control Display Template

De Control Display Template is niet alleen maar de markup voor het Web Part, het bevat ook alle referenties naar CSS en Javascript bestanden. Dat laatste beginnen we mee. Hieronder kan je de betreffende bestanden downloaden (upload ze zelf naar de gewenste locatie in SharePoint):

Als eerste gaan we de slider even beperken tot maximaal 400px hoogte, alles daaronder zal hij flexibel blijven. Open hiervoor het bestand 'plugins.css'. Op regel 76 vind je de selector '.revolution-mch-1:after'. Voeg hierin de regel 'max-height:400px;' toe en sla op.

Open je Control Display Template in Notepad++ (of een andere editor naar keuze) en vervang alles tussen de <script> tags met onderstaande:
$includeScript(this.url, "~sitecollection/[Pad naar het bestand]/jquery.min.js");
$includeCSS(this.url, "~sitecollection/[Pad naar het bestand]/style.css");
$includeCSS(this.url, "~sitecollection/[Pad naar het bestand]/settings.css");

Dan is er nog een fallback voor oude IE browsers, die voeg je als volgt direct na de </script> tag toe:
<!--[if lt IE 9]>
<script>
$includeCSS(this.url, "~sitecollection/[pad naar het bestand]/settings-ie8.css");
</script>
<![endif]-->

Er is hier nog wel een potentieel addertje. In het bestand 'style.css' zijn via @import verwijzingen opgenomen naar een aantal andere css bestanden. Die bestanden staan in dezelfde map, dus het pad bestaat uit slechts de bestandsnaam. Nu wil het wel eens zo zijn dat SharePoint deze paden relatief aan de siteroot ziet i.p.v. relatief aan de map waarin ze staan. Dat kan dus betekenen dat je de gehele url moet specificeren in de @import verwijzingen.
Daarnaast heb ik op één van mijn SPO omgevingen dat bij het navigeren zonder server refresh (dus F5 ipv CTRL + F5), de aanvullende CSS bestanden ineens helemaal niet meer worden geladen. Mocht je hetzelfde probleem ervaren, dan kan je de plugins.css op dezelfde manier in je Control Display Template aanroepen als de style.css.
Je ziet het overigens heel gemakkelijk aan de slider als het laden van deze aanvullende CSS bestanden niet werkt, dan gaat de slider zich raar gedragen en de titel is bijvoorbeeld heel klein.
Zelf heb ik dit probleem op de ene SharePoint Online omgeving wel en op de andere SharePoint Online omgeving niet. Het is me een raadsel waarom… Dus wie het weet mag het zeggen!

De volgende stap is het inladen en gebruiken van de Javascript voor de slider zelf. Dat voeg je toe binnen de <!--#_ en _#--> tags, onder de regel var siteURL = SP.PageContextInfo.get_siteAbsoluteUrl();:
AddPostRenderCallback(ctx, function() {
$.getScript(siteURL + "/[pad naar het bestand]/jquery.themepunch.revolution.min.js", function(){
$.getScript(siteURL + "/[pad naar het bestand]/jquery.themepunch.tools.min.js", function(){
$.getScript(siteURL + "/[pad naar het bestand]/revolution-slider.js", function(){
jQuery(document).ready(function() {
RevolutionSlider.initRSfullWidth();
});
});
});
});
});

Om te zorgen dat de slider foutloos werkt, moeten de javascript bestanden in een bepaalde volgorde worden ingeladen. Aangezien SharePoint alles asynchroon inlaadt tussen de <script> tags, ontstaan er bugs (sommige js bestanden worden niet altijd geladen, waardoor de slider stuk gaat). Met bovenstaande code maken we dus telkens een function die een bestand inlaadt en vervolgens weer een nieuwe function aanroept, die op zijn beurt weer een bestand inlaadt, etc. Net zo lang tot we alle bestanden hebben geladen.

We hebben nu alles ingeladen en geactiveerd wat we nodig hebben om de slider werkend te krijgen. Nu moeten we de slider zelf nog maken, de HTML dus. Voeg als eerste een class 'RevolutionSlider' aan de allereerste <div> toe (die staat boven de code waarmee we de externe files hebben ingeladen). Vervang daarna de HTML vanaf de <div> met CSS-class ‘container’ door onderstaande HTML:
<div class="tp-banner-container">
<div class="tp-banner">
<ul>

</ul>
<div class="tp-bannertimer tp-bottom"></div>
</div>
</div>

Let op: Laat wel de buitenste <div> (waaraan je de class 'RevolutionSlider' hebt toegevoegd) helemaal intact! Als je die weg haalt gaat het stuk.

Als laatste voegen we de code toe die het Item Display Template straks gaat inladen. Zet onderstaande code tussen de <ul> tags:
_#= ctx.RenderItems(ctx) =#_

Om het geheel af te maken kan je nog een titel invullen tussen de <title> tags. Dat was het v.w.b. de Control Display Template, we gaan nu verder met het Item Display Template.

Item Display Template

In het Item Display Template moeten we als eerste aan gaan geven welke velden we willen ophalen. Dat doen we in de <mso:ManagedPropertyMapping msdt:dt="string"> tag. Je ziet hierin al wat velden staan. We missen er echter nog één, namelijk de afbeelding. Voeg de volgende code toe aan de ManagedPropertyMapping tag:
‘PictureURL’:’ PictureURL’ Zorg ervoor dat deze setjes steeds door een komma gescheiden blijven.

Vervolgens moeten we het 'PictureURL' veld aan een Javascript variabele koppelen. Dat doe je binnen de <!--#_ en _#--> tags, onder de regel 'var siteURL = SP.PageContextInfo.get_siteAbsoluteUrl();':
var pictureURL = $getItemValue(ctx, "PictureURL");

Als laatste voegen we de HTML toe die we per item willen renderen. Vervang alle HTML vanaf de <div> met de CSS-class 'item' door onderstaande:
<li class="revolution-mch-1" data-transition="fade" data-slotamount="5" data-masterspeed="1000" data-title="_#= $htmlEncode(title) =#_">
<img src="_#= pictureURL =#_" alt="_#= $htmlEncode(title) =#_" data-bgfit="cover" data-bgposition="left top" data-bgrepeat="no-repeat">
<div class="tp-caption revolution-ch1 sft start"
data-x="center"
data-hoffset="0"
data-y="100"
data-speed="1500"
data-start="500"
data-easing="Back.easeInOut"
data-endeasing="Power1.easeIn"
data-endspeed="300">
_#= $htmlEncode(title) =#_
</div>

<div class="tp-caption revolution-ch2 sft" style="z-index: 6"
data-x="center"
data-hoffset="0"
data-y="190"
data-speed="1400"
data-start="2000"
data-easing="Power4.easeOut"
data-endspeed="300"
data-endeasing="Power1.easeIn"
data-captionhidden="off">
_#= $htmlEncode(description) =#_
</div>

<div class="tp-caption sft" style="z-index: 6"
data-x="center"
data-hoffset="0"
data-y="310"
data-speed="1600"
data-start="2800"
data-easing="Power4.easeOut"
data-endspeed="300"
data-endeasing="Power1.easeIn"
data-captionhidden="off">
<a href="_#= linkURL =#_" class="btn-u btn-brd btn-brd-hover btn-u-light">Read More</a>
</div>
</li>

Let op: Laat wel de buitenste <div> intact! Als je die weg haalt gaat het stuk.

zie ook hier weer alle code stukjes die beginnen met '_#='. Hierin worden, via de variabelen, de SharePoint velden aangeroepen.

Dat was m! Als je nu de pagina ververst waarop je de slider hebt geplaatst, dan zou hem nu in al zijn glorie moeten kunnen bewonderen ☺

Voor het gemak zijn hier nog voorbeelden van de volledige bestanden te downloaden: