1

I want to make a theme Switcher.

My idea is to make a div class with many anchor elements (the themes) containing a data-theme attribute which contains different swatches (a,b,c,d,e). I want to replace the data-theme attribute of every page with the data-theme selected when the user clicks a link. How can I make that using JavaScript?

Jasper
  • 75,717
  • 14
  • 151
  • 146
Eslam Hamdy
  • 7,126
  • 27
  • 105
  • 165
  • have you looked at the jquerymobile site? they have there this functionality... just look at their source. – Ido Green Mar 01 '12 at 15:52
  • You cannot just change the `data-theme` attributes of elements and expect that their theme will change, you have to change the theme-based-classes associated with widgets to get the theme to change on-the-fly (on already initialized widgets). To see this, just got to the documentation and inspect some code in your developer tools: http://jquerymobile.com/demos/1.1.0-rc.1/ – Jasper Mar 01 '12 at 18:53

4 Answers4

2

You can target specific widgets and update their themes by changing the theme-specific classes:

    //set a theme letter to change to
    var theme = 'a';

    //update the button widgets on the current page
    $.mobile.activePage.find('.ui-btn').not('.ui-li-divider')
                       .removeClass('ui-btn-up-a ui-btn-up-b ui-btn-up-c ui-btn-up-d ui-btn-up-e ui-btn-hover-a ui-btn-hover-b ui-btn-hover-c ui-btn-hover-d ui-btn-hover-e')
                       .addClass('ui-btn-up-' + theme)
                       .attr('data-theme', theme);
    
    //update the list-divider elements
    $.mobile.activePage.find('.ui-li-divider').each(function (index, obj) {
        if ($(this).parent().attr('data-divider-theme') == 'undefined') {
            $(this).removeClass('ui-bar-a ui-bar-b ui-bar-c ui-bar-d ui-bar-e')
                   .addClass('ui-bar-b')
                   .attr('data-theme', 'b');
        }
    })
                     
    //update the header, footer, and body  
    $.mobile.activePage.find('.ui-header, .ui-footer')
                       .removeClass('ui-bar-a ui-bar-b ui-bar-c ui-bar-d ui-bar-e')
                       .addClass('ui-bar-' + theme)
                       .attr('data-theme', theme);
    $.mobile.activePage.removeClass('ui-body-a ui-body-b ui-body-c ui-body-d ui-body-e')
                       .addClass('ui-body-' + theme)
                       .attr('data-theme', theme);

Here is a link to a demo of this code: http://jsfiddle.net/VNXb2/7/

Here is another answer I posted about this: How to change theme dynamically in jquery mobile?

The above code is for switching the theme after initialization (that's why there is all the class-switching), if you want to switch the theme before the jQuery Mobile framework has initialized anything, you can use an attribute selector to alter all the elements in the DOM:

//this will update any element with a `data-theme` attribute set so it's set to `a`
$('[data-theme]').attr('data-theme', 'a');

If you want to target different types of widgets to be different themes you can just make the selector a bit more specific:

//give all form inputs the `a` theme
$('input').attr('data-theme', 'a');

//give all the header elements the `a` theme
$('[data-role="header"]').attr('data-theme', 'a');

You could force a reload when the user chooses a swatch, then load the swatch as a GET variable, and read that variable when the page loads and before jQuery Mobile has a change to initialize anything:

<script src="jQuery-Core.js"></script>
<script>
//check if there are any GET variables
if (window.location.search != '') {
    var swatch = '',
        arr    = window.location.search.replace('?').split('&');

    //loop through the GET variable key/pairs
    for (var i = 0; len = arr.length; i < len; i++) {

        //split into key/pair
        var pair = arr[i].split('=');

        //check if the key is `swatch` and if so then set the `swatch` variable to its value
        if (pair[0] === 'swatch') {
            swatch = pair[1];
        }
    }

    //the `swatch` variable now holds the GET variable `swatch` if it was set
    if (swatch !== '') {
        $('[data-theme]').attr('data-theme', swatch);
    }
}
</script>
<script src="jQuery-Mobile.js"></script>

Notice the order of the <script> tags.

Community
  • 1
  • 1
Jasper
  • 75,717
  • 14
  • 151
  • 146
1

I would recommend using JQuery. You can then do something like this:

$('#selector').prop('data-theme') = 'newValue';

Selectors allow you to target one or many different elements.

YakovL
  • 7,557
  • 12
  • 62
  • 102
Spikeh
  • 3,540
  • 4
  • 24
  • 49
  • 1
    You have the right idea, but I think you would use this instead. $('#selector').data('theme', newValue); You should use the data() method to change a data value, not the prop(method) to change a data value. – Evik James Mar 01 '12 at 20:53
  • I only noticed that this was a mobile specific question after I answered :) Not done much mobile stuff myself! – Spikeh Mar 02 '12 at 07:27
1

There are a couple of ways. I'm going to do it using jQuery because I'm lazy :)

var divThatCanHaveItsAttributesChanged = $("#divThatCanHaveItsAttributesChanged");
$("a.linkThatCanBeClickedToChangeTheme").on('click', function () {
    var linkThatWasClicked = $(this);
    divThatCanHaveItsAttributesChanged.attr('data-theme', linkThatWasClicked.attr('data-theme'));
});

Pardon the super long variable names, but hopefully it's a bit clearer than just a/b/c.

Edit: Alright, after our conversation, what you want is something more like the following:

var divThatCanHaveItsAttributesChanged = $("#divThatCanHaveItsAttributesChanged");
$("a.linkThatCanBeClickedToChangeTheme").on('click', function () {
    var linkThatWasClicked = $(this);
    var theme = linkThatWasClicked.attr('data-theme');
    divThatCanHaveItsAttributesChanged.attr('data-theme', theme);
    eraseCookie('theme');
    createCookie('theme', theme, 365);
});

Grab the code near the bottom of http://www.quirksmode.org/js/cookies.html and use that as a starting point for setting and reading cookies. So, now that you've got a cookie with the name 'theme' set you have a few options. The preferred one I'm sure will be with having the backend language you are using read the cookie and alter the template you're using. For example with PHP:

$theme = empty($_COOKIE['theme']) ? 'default-theme' : $_COOKIE['theme'];

And then you could use that to put the 'theme' in the right spot. Alternatively if you don't have that kind of capability you could do it with javascript.

$.ready(function () {
    var theme = readCookie('theme');
    //Either the cookie has expired or it doesn't exist
    if(!theme) {return;} 
    $("#divThatCanHaveItsAttributesChanged").attr('data-theme', theme);
});

This might cause a flash though as the theme is changed. There are a huge number of ways of handling this, but at minimum you'll want to set that cookie or send the result to the server to attach to the person's account.. depending on complexity.

Stephen
  • 5,362
  • 1
  • 22
  • 33
  • it doesn't work, for more clarity, i have many links, each one contains a (data-theme) attribute,this is the attributes which will replace the others (data-theme) attributes in all the other pages – Eslam Hamdy Mar 01 '12 at 16:23
  • By 'all the other pages', are you saying that you want to save the selection for use on other distinct pages of the site? i.e. this is not a one page application, but many different pages? – Stephen Mar 01 '12 at 16:32
  • Gotcha. What you want to do then is store the data in a cookie, and read it back in on page load. If you want an example I can write one up in a few hours (have to get going to work and all that jazz). – Stephen Mar 01 '12 at 17:00
  • Give that a shot. Without knowing how you're generating the HTML it's a bit harder to 'solve' this, but hopefully the expanded example gives you something to work with that will set you in the right direction. – Stephen Mar 01 '12 at 20:16
  • to know how i generate my HTML, look at the source of this page http://jquerymobile.com/test/docs/pages/pages-themes.html , it seems to be the same as my HTML Construction, but it's applies the theme to only one page, what i want to do is to apply the theme for all the pages not only to one page,thanks – Eslam Hamdy Mar 02 '12 at 19:24
1

Like I do green says jquerymobile has the theme roller working.

But I think that a change isn't necessary because you can set a swatch let's say a and then in every theme change you only have to replace the css, so this way it's not necessary to modify the HTML DOM...

Good Luck!

YakovL
  • 7,557
  • 12
  • 62
  • 102