Tuesday, February 16, 2016

Grunt: sass, scss, autoprefixer, cssmin, and watch Notes with Sample Files

Example Gruntfile.js

module.exports = function(grunt) {
    'use strict'

    var processdate = (new Date).toString();

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),

        //Watch objects
        //----------------------------------
        watch: {
            scripts: {
                files: ['scss/**/*.scss'],
                tasks: ['sass','autoprefixer','cssmin'],
                options: {
                    interval: 500,
                    spawn: false
                }
            }
        },

        sass: {
            options: {
                includePaths: require('node-bourbon').includePaths,
                outputStyle: 'nested',  // Values: 'nested', 'compressed'
                precision: 3,
                sourceMap: true, // Without this being true the resulting map file isn't linked at the bottom of the generated .css file
                sourceMapEmbed: false,
                sourceComments: false
            },
            dist: {
                files: {
                    'global.css': ['scss/master.scss']
                }
            }
        },

        //Plugins
        //----------------------------------
        autoprefixer: {
            options: {
                browsers: ['last 2 versions'],
                cascade: false,
                map: {
                    prev: false,
                    inline: false,
                    annotation: false,
                    sourcesContent: false
                }
            },
            multiple_files: {
                src: 'global.css',
                dest: 'global.css'
            }
        },

        cssmin: {
            add_banner: {
                options: {
                    banner: '/* Author: **Your Name\n * Created: 2016-02-16\n * Last Updated: '+processdate+'\n */'
                },
                files: {
                    'global.min.css': ['global.css']
                }
            }
        }

    });


    //Load NPM Tasks
    //----------------------------------
    grunt.loadNpmTasks ('grunt-contrib-watch');
    grunt.loadNpmTasks ('grunt-sass');
    grunt.loadNpmTasks ('grunt-autoprefixer');
    grunt.loadNpmTasks ('grunt-contrib-cssmin');


    grunt.registerTask('default', ['sass','autoprefixer','cssmin']);
    grunt.registerTask('c', ['sass']);  // c=compile
    grunt.registerTask('w', ['watch']);

};


Example package.json:

{
    "name": "grunt",
    "version": "0.1.1",
    "private": true,
    "devDependencies": {
        "grunt": "latest",
        "grunt-autoprefixer": "latest",
        "grunt-contrib-cssmin": "latest",
        "grunt-contrib-watch": "latest",
        "grunt-sass": "latest",
        "node-bourbon": "latest"
    }
}


Example master.scss:

// Manually list all files to be included in specific order, skip .scss extensions
@import "./fonts";
@import "./variables";
@import "./base";
@import "./layout";
@import "./partials";
@import "./global";


And then command line:

$ npm update
$ npm install
$ grunt
$ grunt w



That's it.

Better JS functions than previous attempts at similar functionality

Some code notes for later reference:


A better number formatting function:
            function toDecimal (number) {  // CREDITS: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString
                return number.toLocaleString("en-US",{ style: 'decimal', minimumIntegerDigits: 1, maximumFractionDigits: 2, minimumFractionDigits: 2 });
            };



A better currency format function:
            function toDollar (number) {  // CREDITS: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString
                return number.toLocaleString("en-US",{ style: 'currency', currency: 'USD' });
            };



I've always wanted a good one of these:
            function guid () {  // CREDITS: http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript
                function s4() {
                    return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
                }
                return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
            };


Saturday, January 23, 2016

Native HTML5 Ternary Checkbox - With Labels!

I worked through creating a html ternary checkbox (a checkbox with a tertiary option) this morning - with labels! Woohoo!

Now that we can create a third option we need to tell the user what it means, so we probably need labels.

Here are some images of the results on-screen:





Given a checkbox like this:

<input id="example" name="example" type="checkbox" class="ternaryCheckbox" value="1" />

We can use the default 'Yes', 'No', 'All' options with this HTML:

<input id="example" name="example" type="checkbox" class="ternaryCheckbox" value="1" />
<span class="ternaryLabelsYesNoAll"></span>


OR, use custom labels:

Show Archived: <input id="example" name="example" type="checkbox" class="ternaryCheckbox" value="1" />
<span class="ternary-option checked">Active Only</span>
<span class="ternary-option unchecked">Archived Only</span>
<span class="ternary-option alternate">All Records</span>


We add this JS to attach the handler and the function to run the ternary checkbox:

$(document).ready(function(){
    $(":checkbox.ternaryCheckbox").on("click",ternaryCheckbox);
});

function ternaryCheckbox(e){
    var $t = $(this),
        that = this,
        originalVal = $t.val(),
        checkedVal = originalVal,
        alternateVal = ($t.data("ternary") != undefined ? $t.data("ternary") : 2);
    // This should only be undefined the first time to cache the original value
    if ($t.data("primary") == undefined) {
        $t.data("primary",checkedVal);
    } else {
        checkedVal = $t.data("primary");
    }
    // if 'un-checking', and NOT in tern state, go to tern state, else normal checked or unchecked
    if($t.prop("checked")==false && $t.prop("indeterminate")==false && originalVal!=alternateVal) {
        $t.val(alternateVal);
        $t.prop("checked",true);
        $t.prop("indeterminate",true);
    } else {
        $t.val(checkedVal);
        $t.prop("indeterminate",false);
    }
};


Here is the Raw CSS:

.ternaryCheckbox ~ .ternaryLabelsYesNoAll {
    display: inline-block;
    font-weight: 100;
    margin-right: 21px;
    position: relative;
    width: 1px;
}
.ternaryCheckbox ~ .ternaryLabelsYesNoAll:after {
    content: "No";
    display: inline-block;
}
.ternaryCheckbox:checked ~ .ternaryLabelsYesNoAll:after {
    content: "Yes";
}
.ternaryCheckbox:indeterminate ~ .ternaryLabelsYesNoAll:after {
    content: "All";
}

.ternaryCheckbox ~ .ternary-option {
    display: inline-block;
    font-weight: 100;
    min-width: 22px;
}
.ternaryCheckbox ~ .ternary-option.alternate, .ternaryCheckbox ~ .ternary-option.checked {
    display: none;
}
.ternaryCheckbox:checked ~ .ternary-option.checked {
    display: inline-block;
}
.ternaryCheckbox:indeterminate ~ .ternary-option.checked, .ternaryCheckbox:checked ~ .ternary-option.alternate, .ternaryCheckbox:checked ~ .ternary-option.unchecked {
    display: none;
}
.ternaryCheckbox:indeterminate ~ .ternary-option.alternate {
    display: inline-block;
}



Here is the Sass CSS:

/* Ternary Checkbox and Option Labels */

/* Using default 'No', 'Yes', 'All' default labels:
    <input id="example" name="example" type="checkbox" class="ternaryCheckbox" value="1"<? if (local.example != 0)> checked</?><? if (local.example == 2)> indeterminate</?> />
    <span class="ternaryLabelsYesNoAll"></span>
    // Nothing else is needed, CSS does the rest.
*/
.ternaryCheckbox {
    ~ .ternaryLabelsYesNoAll {
        display: inline-block;
        font-weight: 100;
        margin-right: 21px;
        position: relative;
        width: 1px;
        &:after {
            content: 'No';
            display: inline-block;
        }
    }
    &:checked  {
        ~ .ternaryLabelsYesNoAll:after {
            content: 'Yes';
        }
    }
    &:indeterminate ~ .ternaryLabelsYesNoAll:after {
        content: 'All';
    }
}


/* Using custom ternary labels:
    <input id="example" name="example" type="checkbox" class="ternaryCheckbox" value="1"<? if (local.example != 0)> checked</?><? if (local.example == 2)> indeterminate</?> />
    <span class="ternary-option checked">Checked</span>
    <span class="ternary-option unchecked">Unchecked</span>
    <span class="ternary-option alternate">Alternate</span>
*/
.ternaryCheckbox {
    ~ .ternary-option {
        display: inline-block;
        font-weight: 100;
        min-width: 22px;  /* Override this if longer values are being used, inline style is fine */
        &.checked,
        &.alternate {
            display: none;
        }
    }
    &:checked {
        ~ .ternary-option.checked {
            display: inline-block;
        }
        ~ .ternary-option {
            &.unchecked,
            &.alternate {
                display: none;
            }
        }
        &:indeterminate ~ .ternary-option {
            &.checked {
                display: none;
            }
            &.alternate {
                display: inline-block;
            }
        }
    }
}

-GBuilt

[This solution is completely open source, absolutly free to use without any restriction. Please give creative to this blog post URL.