jQuery Plugin – MyNewTabs (3): Javascript

Vandaag is het zover, we gaan de jQuery plugin afmaken. Het is tijd voor wat magie van javascript. Je kunt de code trouwens downloaden, of de demo vast bekijken (vergeet dan niet je browser scherm te verkleinen om het effect te zien):

Javascript

In principe is het mogelijk om de CSS die we eerder schreven te verwerken in je CSS bestand voor de rest van de site en de Javascript code van vandaag gewoon te includen aan het einde van de code, vlak voor de sluitende </body>. Maar dan heb je geen plugin die je later nog eens kunt gebruiken. Omdat het doel van deze hele exercitie nu eenmaal is om een jQuery plugin te schrijven, gaan we dat ook doen. De beginselen van jQuery worden uitgelegd in het jQuery learning center. Dit lijkt me een goede en duidelijke resource en ik ga er dan ook vanuit dat je weet dat een plugin voor jQuery schrijven neerkomt op het uitbreiden van het $.fn object. Daarnaast wordt de hele plugin code binnen een Immediately-Invoked Function Expression (IIFE) gezet zodat de heleboel wordt afgesloten van buiten en we dus de globale scope niet vervuilen met allerlei variabelen en functies. Onderstaand de eerste regels van deze plugin (rest van de code komt zo):

(function ( $ ) {
 
    $.fn.mynewtabs = function( options ) {
 
        var $this = $(this);

        // rest of the code comes here
    
    };

}( jQuery )); 

Overigens is het vrij gebruikelijk om de variabele $this aan te maken als $(this). Dit verwijst dan naar het jQuery element waar de plugin op wordt toegepast. De $ voor this in de variabele naam is niks meer dan een gewoonte om te laten zien dat deze variabele een jQuery object is.

jQuery Plugin opties en defaults

Om je jQuery plugin naar smaak van een ander te kunnen aanpassen is het belangrijk om niet alle opties gewoonweg te coderen. Sommige dingen moeten andere developers zelf kunnen aanpassen. Omdat ik het niet te moeilijk wilde maken (voor mezelf) heb ik besloten om in deze versie alleen de achtergrond kleur en de tekstkleur optioneel te maken. Als default kleuren heb ik gekozen voor een

een tekst in deze kleur op deze achtergrond.

De volgende stap is nu om ervoor te zorgen dat jij andere kleuren kunt kiezen (zoals in de demo). Daarvoor wordt gebruik gemaakt van $.extend:

(function ( $ ) {
 
    $.fn.mynewtabs = function( options ) {
 
        var $this = $(this);

        var settings = $.extend({
            // These are the defaults.
            color: "#5a531e",
            backgroundColor: "#409bbf"
        }, options );

        // rest of the code comes here
    
    };

}( jQuery )); 

Wat er moet gebeuren

Laten we even terugkeren naar het begin. We wilden een jQuery plugin bouwen die afhankelijk van de breedte van het scherm een lijstje met links zou weergeven en een blokje content. Voor brede pagina’s moet het blokje content naast de links komen en voor smalle pagina’s er direct onder. Afhankelijk van de breedte van de pagina moeten we dus wat Javascript code uitvoeren om voor elkaar te krijgen wat we willen. Maar let op: ook op het moment dat de pagina geladen wordt. Het is namelijk zo dat de HTML mark-up die we in deel 1 gemaakt hebben de content in een aparte div zet buiten het lijstje met links. Dit is precies wat we willen op brede schermen en met wat CSS krijgen we het tab systeem precies zoals we het hebben willen. Maar wat als de pagina nu geladen wordt op een smal scherm? Met alleen een functie die uitgevoerd wordt op het moment van het resizen van je scherm komen we er dus niet. Het komt er dus op neer dat we een init() functie moeten schrijven en een resizer() functie. De code ziet er nu zo uit:

(function ( $ ) {
 
    $.fn.mynewtabs = function( options ) {
 
        var $this = $(this);

        var settings = $.extend({
            // These are the defaults.
            color: "#5a531e",
            backgroundColor: "#409bbf"
        }, options );

        var div_in_ul = false;
        var viewportwidthG;
        if (typeof window.innerWidth != 'undefined')
	{
	     viewportwidthG = window.innerWidth;
	}
        
        // On pageload do:
        init();
        
        // Event: window is resized        
        $(window).resize(function(){		
            resizer();
        });

        // rest of the code comes here
    
    };

}( jQuery )); 

Maar wacht, er is nog een andere valkuil waar ik onlangs in terecht kwam. Eerder in de CSS hebben we een breakpoint gezet op 672px. Nu blijkt dat de als we in javascript uitgaan van de normale window.width(), de horizontale scrollbar wordt meegenomen in de breedte, terwijl dat in CSS niet gebeurt. Dat resulteert erin dat de CSS en de Javascript niet op hetzelfde moment worden uitgevoerd. Lang verhaal kort: gebruik window.innerWidth. We hebben trouwens ook nog een boolean vlaggetje aangemaakt zodat we weten of de div met de content al dan niet binnen de ul staat, vandaar de naam div_in_ul.

De functie init()

Zoals hierboven beschreven is de HTML mark-up al helemaal klaar voor het brede scherm. Is het scherm dus breed genoeg (in dit geval met een breedte > 672px, het breakpoint) dan hoeven we bijna niks te doen. Bijna niks, want zoals ik in deel 2 met de CSS schreef, door de border om de content heen zit er een lelijk streepje tussen de active link en de content. We plaatsen hier een wit blokje overheen met behulp van Javascript (functie add_wit_blokje_to_active_li). Is het scherm echter minder dan 672px breed, dan willen we de content binnen de ul halen. Dat doen we door de inhoud van de div met de content even op te halen met jQuery en vervolgens achter het actieve li element een nieuwe li te maken met deze content als inhoud. Niet vergeten om de oorspronkelijke content te verwijderen natuurlijk (remove) en om het vlaggetje op true te zetten! Hier is de code van de init functie:

function init()
{
    if (viewportwidthG < 672)
    {
        // Find active li:
        var divdescription = $("div.descr");
        //$(".content-wrapper ul.list li.active").after('
  • ‘+divdescription.html()+’

‘); $this.find(“ul.list li.active”).after(‘

  • ‘+divdescription.html()+’

 

‘); divdescription.remove(); div_in_ul = true; } else { // Voeg een wit blokje toe aan active li om de lelijke border te verwijderen! add_wit_blokje_to_active_li(); } }

De functie resizer

Wanneer de gebruiker het scherm smaller of breder maakt wordt het resize event getriggered op het window object. De callback op dit event noemen we resizer en die functie gaan we nu behandelen. Allereerst moeten we de huidige breedte van het scherm ophalen, uiteraard weer met window.innerWidth. Dan is het een kwestie van kijken of het scherm smaller of breder is dan het breakpoint en vervolgens kijken of er iets moet gebeuren of niet. Dit laatste gaat weer met behulp van het vlaggetje div_in_ul.

Op het moment dat het scherm smaller is dan het breakpoint EN div_in_ul is false (!div_in_ul is true), herhalen we de stappen uit de functie init. Andersom, als het scherm breder is dan het breakpoint EN div_in_ul is true, dan doen we eigenlijk precies het omgekeerde: We halen de content op uit de lijst en kopieren die naar de div die buiten de ul staat. Vervolgens wordt de nu nutteloze li verwijdert.

Het witte blokje

Zoals eerder besproken vond ik de streep van de border van de content tussen de actieve li en de content niet mooi. Dit is opgelost met behulp van de functie add_wit_blokje_to_active_li. Maar toen had ik ook nog via de CSS de lettergrootte van de tab items aangepast: die lettergrootte werd groter voor brede schermen, terwijl het blokje even groot bleef. Het resultaat: onder en boven het blokje kwam nog een stukje border tevoorschijn omdat de hoogte van de li meegroeit met de lettergrootte. De oplossing was om de hoogte van het witte blokje dynamisch te maken, afhankelijk van de hoogte van de actieve li dus.

Laatste loodjes

Na de functies init() en resizer() moeten we nog een stukje code toevoegen voor de plugin klaar is. Een return statement, waar we het jQuery object waar de plugin op wordt toegepast teruggeven zodat de chaining van jQuery in stand wordt gehouden. Hier passen we ook direct de mogelijk aangepaste kleuren (de opties weet je nog!) aan via $.css:

return this.css({
    color: settings.color,
    backgroundColor: settings.backgroundColor
});

Tenslotte is nog van belang het aanroepen van de plugin. Dat is waarlijk het eenvoudigste van deze blog. Weet je nog welke class we de wrapper om de verpichte HTML hadden gegeven? Ik heb het ook even moeten opzoeken! Maar dat is wel het element dat we met behulp van jQuery selecteren en waar we de plugin op los laten:

<script>
    $(function(){
        $(".mynewtabs-cntr").mynewtabs({
            backgroundColor: '#fc3000',
            color: '#FFFFFF'
        });
    });
</script>

Onderstaand volgt dan nog de gehele Javascript code voor de plugin en daaronder de demo en download knop nogmaals:

(function ( $ ) {
 
    $.fn.mynewtabs = function( options ) {
 
        $this = $(this);
 
        // This is the easiest way to have default options.
        var settings = $.extend({
            // These are the defaults.
            color: "#5a531e",
            backgroundColor: "#409bbf"
        }, options );
 
        // Do your magic here!
        var div_in_ul = false;
        var viewportwidthG;
        if (typeof window.innerWidth != 'undefined')
	{
	     viewportwidthG = window.innerWidth;
	}
        
        // On pageload do:
        init();
        
        // Event: window is resized        
        $(window).resize(function(){		
            resizer();
        });
        
        /*=================================================*/
        /*         Functions init, resizer and helper      */
        /*=================================================*/
        function init()
        {
            if (viewportwidthG < 672)
            {
                // Find active li:
                var divdescription = $("div.descr");
                //$(".content-wrapper ul.list li.active").after('
  • ‘+divdescription.html()+’

‘); $this.find(“ul.list li.active”).after(‘

  • ‘+divdescription.html()+’

 

‘); divdescription.remove(); div_in_ul = true; } else { // Voeg een wit blokje toe aan active li om de lelijke border te verwijderen! add_wit_blokje_to_active_li(); } } function resizer() { var viewportwidth; var viewportheight; // the more standards compliant browsers (mozilla/netscape/opera/IE7) use window.innerWidth and window.innerHeight if (typeof window.innerWidth != ‘undefined’) { viewportwidth = window.innerWidth, viewportheight = window.innerHeight; } if ( viewportwidth >= 672 ) { /* Voor brede schermen moet de beschrijving van de behandeling aan de rechterkant getoond worden */ if (div_in_ul) { var li = $(“li.descr”); var div = li.find(“div”); $(“div.list”).after(‘

‘+div.html()+’

‘); li.remove(); div_in_ul = false; } if (!div_in_ul) { $this.find(“ul.list li.active div#white_block”).remove(); add_wit_blokje_to_active_li(); } } else { if (!div_in_ul) { var divdescription = $(“div.descr”); var li_active = $this.find(“ul.list li.active”); li_active.after(‘

  • ‘+divdescription.html()+’

 

‘); divdescription.remove(); div_in_ul = true; /* Verwijder het witte blokje */ li_active.find(“div#white_block”).remove(); } } } function add_wit_blokje_to_active_li() { var active_li = $this.find(“ul.list li.active”); var li_height = active_li.height(); active_li.css(“position”, “relative”).append(‘

‘); } // Greenify the collection based on the settings variable. return this.css({ color: settings.color, backgroundColor: settings.backgroundColor }); }; }( jQuery ));


Mijn Twitter profiel Mijn Facebook profiel
Pim Hooghiemstra Webdeveloper and founder of PLint-sites. Loves to build complex webapplications using Vue and Laravel! All posts
Alle berichten tonen van Pim Hooghiemstra

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *