#

# Example: Adjusting a Page Theme on the Fly

In this example, we'll use a snapshot of the W3C HTML 4.01 specification for Style Sheets and add a custom dynamic StyleSheet to apply some color and font size changes.

A Progressive enhancement strategy is used to extract a static form on the page into a draggable Overlay. Additionally, one of the form inputs is replaced with a Slider. Enter any valid CSS color value into the other inputs (e.g. `#123456`, `#135`, `rgb(0,0,0)`, or `red`).

View Example in New Window

### Full code listing

#### Markup

The markup as stated above is a local snapshot of the HTML 4.01 spec, but with the following markup added to the end of the `<body>` to show a progressive enhancement model.

    <div id="form_container">
        <form class="yui3-widget-bd" id="theme_form" action="#" method="get">
            <fieldset>
                <h3>Update Theme</h3>
                <label for="font_size">Font size:</label>
                <input type="text" size="3" id="font_size" value="16px">

                <label for="heading_color">Heading color:</label>
                <input type="text" size="12" id="heading_color" value="#005A9C">

                <label for="link_hover">Link hover backgound:</label>
                <input type="text" size="12" id="link_hover" value="#ffa">
            </fieldset>
            <input type="submit">
        </form>
    </div>

#### JavaScript

    <script src="../../build/yui/yui-min.js"></script>
    <script>
    // Create a new YUI instance, requiring stylesheet, overlay, slider, and the
    // dd-plugin to make the overlay draggable
    YUI().use("stylesheet","overlay","slider","dd-plugin", function (Y) {

        var myStyleSheet = new Y.StyleSheet(),
            overlayContent = Y.one('#form_container'),
            overlay,
            slider,
            slider_container,
            fontSizeInput,

        // Create the Overlay, using the form container as the contentBox.
        // The form is assigned a class yui-widget-bd that will be automatically
        // discovered by Overlay to populate the Overlay's body section.
        // The overlay is positioned in the top right corner, but made draggable
        // using Y.Plugin.Drag, provided by the dd-plugin module.
        overlay = new Y.Overlay({
            srcNode: overlayContent,
            alignOn: [],
            width: '225px',
            align: { points: [ Y.WidgetPositionAlign.TR, Y.WidgetPositionAlign.TR ] },
            plugins: [ Y.Plugin.Drag ]
        }).render();

        // Slider needs a parent element to have the sam skin class for UI skinning
        overlayContent.addClass('yui3-skin-sam');

        // Progressively enhance the font-size input with a Slider
        fontSizeInput = Y.one('#font_size');
        fontSizeInput.set('type','hidden');
        fontSizeInput.get('parentNode').insertBefore(
            Y.Node.create('6 <span></span> 36'),
            fontSizeInput);

        slider_container = fontSizeInput.previous( "span" );

        // Create a Slider to contain font size between 6px and 36px, using the
        // page's current font size as the initial value.
        // Set up an event subscriber during construction to update the replaced
        // input field's value and apply the change to the StyleSheet
        slider = new Y.Slider({
            length: '100px',
            min: 6,
            max: 36,
            value: parseInt(Y.one('body').getStyle('fontSize')) || 13,
            after: {
                valueChange: function (e) {
                    var size = e.newVal + 'px';

                    this.thumb.set('title', size);
                    fontSizeInput.set('value', size);

                    myStyleSheet.set('body', { fontSize: size });
                }
            }
        }).render( slider_container );

        // The color inputs are assigned keyup listeners that will update the
        // StyleSheet if the current input value is a valid CSS color value

        // The heading input affects all h1s, h2, and h3s
        Y.on('keyup', function (e) {
            var color = this.get('value');

            if (isValidColor(color)) {
                myStyleSheet.set('h1, h2, h3', { color: color });
            }
        }, '#heading_color');

        // The link hover affects the background color of links when they are
        // hovered.  There is no way other than via stylesheet modification to
        // change pseudo-class styles.
        Y.on('keyup', function (e) {
            var color = this.get('value');

            if (isValidColor(color)) {
                myStyleSheet.set('a:hover', { backgroundColor: color });
            }
        }, '#link_hover');

        // Progressive form enhancement complete, now prevent the form from
        // submitting normally.
        Y.one('#theme_form input[type=submit]').remove();

        Y.on('submit', function (e) {
            e.halt();
        }, '#theme_form');

    	// A rudimentary validator to make sure we're not trying to set
    	// invalid color values in StyleSheet.
    	function isValidColor(v) {
            return /^#[0-9a-f]{3}(?:[0-9a-f]{3})?$/i.test(v) ||
                   /^rgb\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*\)$/.test(v) ||
                   /^[a-z]{3,}$/i.test(v);
    	}

    });
    </script>

    <script>
    YUI.Env.Tests = {
        examples: [],
        project: '../assets',
        assets: '../assets/stylesheet',
        name: 'stylesheet-theme',
        title: 'Adjusting a Page Theme on the Fly',
        newWindow: 'true',
        auto:  false
    };
    YUI.Env.Tests.examples.push('stylesheet-theme');
    YUI.Env.Tests.examples.push('photo-browser');

    </script>
    <script src="../assets/yui/test-runner.js"></script>

#### CSS

This is the CSS added to the page to skin the Overlay and its content.

    <style>
    /* For supporting browsers, the overlay is rendered semi-transparent with
     * fancy rounded corners */
    .yui3-overlay {
        background: rgba(128,128,128,0.3);
        -moz-border-radius: 10px;
        -webkit-border-radius: 10px;
        border-radius: 10px;
        padding: 7px;
        cursor: move;
    }
    .yui3-overlay-content {
        background: rgba(205,205,205,0.3);
        -moz-border-radius: 10px;
        -webkit-border-radius: 10px;
        border-radius: 10px;
        padding: 1px;
    }
    .yui3-overlay form {
        background: #f2fbff url(../assets/stylesheet/gradient-promo.png) repeat-x scroll 0 0;
        border: 2px solid #fff;
        -moz-border-radius: 10px;
        -webkit-border-radius: 10px;
        border-radius: 10px;
        margin: 0;
        padding: 0;
        font-size: 13px;
    }
    .yui3-overlay fieldset {
        border: 1px solid #cde;
        -moz-border-radius: 10px;
        -webkit-border-radius: 10px;
        border-radius: 10px;
        margin: 0;
        padding: 20px;
    }
    .yui3-overlay h3 {
        border-bottom: 2px solid #fff;
        color: #479;
        background: transparent;
        margin: 0;
        font-size: 175%;
    }
    .yui3-overlay label {
        display: block;
        margin: 1.3em 0 0.5ex;
        font-weight: bold;
        color: #003;
    }
    .yui3-overlay p {
        margin: 2em 0 0;
    }
    /* override the move cursor for the Slider */
    .yui3-overlay .yui3-slider:hover {
        cursor: default;
    }
    </style>