Calendar Slider

by samih

HTML

<script src="http://knockoutjs.com/downloads/knockout-2.2.1.js"></script>
<div style="width: 800px;margin: 100px auto; background-color: #FFF;border-radius: 10px;padding: 5px;border: 1px solid lightgray;">
        <div>
            <label data-bind="text: 'Slider - range ' + CONSTANTS.SLIDER_MIN + ' - ' + CONSTANTS.SLIDER_MAX + ' days'" >
            </label>
        </div>
        <div class="slider-container" data-bind="uiSlider: true"></div>

        <div class="table-container">
            <div class="timeline-header months" data-bind="visible: daysRange() > CONSTANTS.WEEK_DAY_MAX,
                                                            style: {'width': 31*4*widthRatio() + 'px'},
                                                            foreach: months,
                                                            labelSwitch: daysRange(),
                                                            offsetPosition: daysRange()">
                <div>
                    <span data-bind="text: $data.long" class="long"></span>
                    <span data-bind="text: $data.short" class="short"></span>
                </div>
            </div>
            <div class="timeline-header weeks" data-bind="visible: daysRange() >= CONSTANTS.SLIDER_MIN,
                                                            style: {'width': (CONSTANTS.SLIDER_MAX/7 + 1) * 7 * widthRatio() + 'px'},
                                                            foreach: weeks,
                                                            labelSwitch: daysRange(),
                                                            offsetPosition: daysRange()">
                <div>
                    <span data-bind="text: $data.long" class="long"></span>
                    <span data-bind="text: $data.short" class="short"></span>
                </div>
            </div>
            <div class="timeline-header days" data-bind="visible: daysRange() <= CONSTANTS.WEEK_DAY_MAX,
               ...

CSS

.slider-container {
    margin: 40px;
}

.table-container {
    overflow: hidden;
}

.timeline-header {
    display: table;
    table-layout: fixed;
    border-collapse: collapse;
    border-spacing: 0;
    width: 99%;
    text-align: center;
    border: 1px solid black;
    position: relative;
}

.timeline-header > div {
    display: table-cell;
    border: 1px dotted gray;
    overflow: hidden;
    white-space: nowrap;
}

.short {
    display: none;    
}

.timeline-body {
    height: 300px;
    background-color: #FDFDFD;
    position: relative;
}

.event {
    position: absolute;
    height: 10px;
    background-color: #0000FF;
    border-radius: 5px;
}

JavaScript

//constants
window.CONSTANTS = {
    SLIDER_MAX: 120,
    SLIDER_MIN: 0,
    WEEK_DAY_MAX: 28,
    MONTH_NAMES: [{long: "January", short: "Jan"},
                    {long: "February", short: "Feb"},
                    {long: "March", short: "Mar"},
                    {long: "April", short: "Apr"},
                    {long: "May", short: "May"},
                    {long: "June", short: "Jun"},
                    {long: "July", short: "Jul"},
                    {long: "August", short: "Aug"},
                    {long: "September", short: "Sep"},
                    {long: "October", short: "Oct"},
                    {long: "November", short: "Nov"},
                    {long: "December", short: "Dec"}],
    DAY_NAMES: [{long: "Sunday", short: "S"},
                {long: "Monday", short:"M"},
                {long: "Tuesday", short: "T"},
                {long: "Wednesday", short: "W"},
                {long: "Thursday", short: "T"},
                {long: "Friday", short: "F"},
                {long: "Saturday", short: "S"}]
};

//custom knockout bindings
ko.bindingHandlers.uiSlider = {
    init: function(element, valueAccessor, allBindingsAccessor, viewModel){
        //initialize the slider UI element
        $(element).slider({
            animate: "fast",
            max: CONSTANTS.SLIDER_MAX,
            min: CONSTANTS.SLIDER_MIN,
            range: true,
            values: [CONSTANTS.SLIDER_MIN, CONSTANTS.SLIDER_MAX],
            slide: function(event, ui){
                viewModel.rangeValues[0](ui.values[0]);
                viewModel.rangeValues[1](ui.values[1]);
            }
        });
    }
};

ko.bindingHandlers.labelSwitch = {
    
    update: function(element, valueAccessor, allBindingsAccessor, viewModel) {
        var $tableCells = $(element).children('div');
        var $longNameElements = $tableCells.children('.long');
        var $shortNameElements = $tableCells.children(' .short');
        var firstContainer = $tableCells[0];
     ...