ClickableBlocks (ClickB)

Oracle APEX plugin/widget with clickable blocks interaction.

by araczkowski

HTML

<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css">
    <div class="ClickableBlocksContent" style="overflow: auto; width: 1200px; margin-right: 20px;padding-top: 20px;">
        <div id="P6_CB_1_parent">
        </div>
        <div id="clickB0_parent">
        </div>
        <div id="clickB1_parent">
        </div>
        <div id="clickB2_parent">
        </div>
        <div id="clickB3_parent">
        </div>
        <div id="clickB4_parent">
        </div>
        <div id="clickB5_parent">
        </div>
        <div id="clickB6_parent">
        </div>
        <div id="clickB7_parent">
        </div>
        <div id="clickB8_parent">
        </div>
        <div id="clickB9_parent">
        </div>
    </div>

CSS

/* apply a natural box layout model to all elements, but allowing components to change */

html {
    box-sizing: border-box;
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
}
*,
*:before,
*:after {
    box-sizing: inherit;
}
.ClickableBlocksContent {
    margin-top: 30px;
    margin-right: 30px;
    margin-left: 30px;
}
.ClickableBlocksSteps {
    position: relative;
    height: 2.2em;
}
.ClickableBlocksStep,
.ClickableBlocksMealSelector {
    float: left;
    height: 2.2em;
}
.ClickableBlocksAllBlockSelector {
    float: left;
    height: 2.2em;
    vertical-align: bottom;
    line-height: 2.2em;
}
.ClickableBlocksStep.ClickableBlocksStepFullHour {
    border-left: 2px solid #656565;
    height: 2.2em;
}
.ClickableBlocksStep.ClickableBlocksStepHalfHour {
    border-left: 1px solid #ffd6b8;
    height: 2.2em;
}
.ClickableBlocksStep.ClickableBlocksStepQuarter {
    border-left: 1px solid #ffd6b8;
    height: 2.2em;
}
.ClickableBlocksStep.ClickableBlocksStepEnd {
    border-right: 2px solid #656565;
    height: 2.2em;
}
.ClickableBlocksStep .ClickableBlocksStepContentFullHour {
    height: 1.8em;
}
.ClickableBlocksStep .ClickableBlocksStepContentHalfHour {
    height: 1.8em;
}
.ClickableBlocksStep .ClickableBlocksStepContentQuarter {
    height: 1.8em;
}
.ClickableBlocksStep .ClickableBlocksStepContentEnd {
    height: 1.8em;
}
.ClickableBlocksTick {
    position: absolute;
    margin-left: -.6em;
    margin-top: -20px;
    text-align: center;
    color: #656565;
    font-size: small;
}
div.ClickableBlocksStep.ClickableBlocksPlannedBlockBody {
    border-left: 0px;
    border-right: 0px;
}
div.ClickableBlocksPlannedBlockBody .ClickableBlocksStepContent {
    border-top: 2px solid white;
    border-bottom: 2px solid white;
    -webkit-box-shadow: 5px 5px 5px 0px rgba(0, 0, 0, 0.75);
    -moz-box-shadow: 5px 5px 5px 0px rgba(0, 0, 0, 0.75);
    box-shadow: 5px 5px 5px 0px rgba(0, 0, 0, 0.75);
    cursor: pointer;
    cursor:...

JavaScript

(function (w, $) {

    /**
     * @class ClickB
     *
     * @constructor
     * @param {String} elementID, this id will be used to create jQuery selector and apped a module code to this id
     * @param {Object} userOptions (optional) Custom options object that overrides default
     * {
     *      @property {Number} userOptions.min Block's scale minimum value
     *      @property {Number} userOptions.max Block's scale maximum value
     *      @property {Number} userOptions.step Block's scale step
     *      @property {Object} userOptions.stepLabelDispFormat Block's scale step Label format default hh24
     * }
     */
    w.ClickB = function (elementID, userOptions) {
        var _stepLabelDispFormat = function (steps) {
            var hours = Math.floor(Math.abs(steps) / 60);
            return Math.abs(steps) % 60 === 0 ? ((hours < 10 && hours >= 0) ? '0' : '') + hours : '';
        };

        var _options = {
            min: 0,
            max: 1440,
            step: 30,
            stepLabelDispFormat: _stepLabelDispFormat
        };

        var _onChange = null;


        function _init() {
            _mergeOptions();
            if ((_options.max - _options.min) % _options.step !== 0) {
                throw 'Blocks length should be multiple to step';
            }
            _build();
        }


        function _mergeOptions() {
            if (!userOptions) {
                return _options;
            }
            if (typeof (userOptions) === 'string') {
                userOptions = JSON.parse(userOptions);
            }

            if (typeof (userOptions.openBlocks) !== 'undefined') {
                if (typeof (userOptions.openBlocks) === 'string') {
                    userOptions.openBlocks = JSON.parse(userOptions.openBlocks);
                }
            }

            if (typeof (userOptions.stepLabelDispFormat) !== 'undefined') {
                if (typeof (userOptions.stepLabelDispFormat) === 'string') {
                  ...