<commit_before>/**
 * Tooltip Widget
 * @author Peng Wang <peng@pengxwang.com>
 * @version 1.2
 * @requires jQuery 1.4+
 * @package jQuery.hlf
 * @subpackage jQuery.hlf.tip
**/
;(function ($) {
    var log = function(x) { console.log(x); };
    log = $.noop; // comment to start debugging
    //---------------------------------------
    // STATIC VARIABLES
    //---------------------------------------
    $.extend(true, $, {
        // $.hlf.tip
        hlf: { tip: {
            opt: {
                // direction: '',
                // millis
                inDuration: 300,
                outDuration: 300,
                // pixels
                cursorHeight: 16,
                // class names
                innerClass: 'inner',
                contentClass: 'content',
                stemClass: 'stem',
                northClass: 'north',
                eastClass: 'east',
                southClass: 'south',
                westClass: 'west',
                followClass: 'tip-follow',
                tipClass: 'tip'
            }
        }}
    });
    /**
     * Base Tip
     * prevents hover queueing
     * slots for display and movement
    **/
    var Tip = function ($context, $triggers, opt) {
        //---------------------------------------
        // PRIVATE VARIABLES / CONSTRUCTOR
        //---------------------------------------
        var $tip,
            $trigger, $triggerP,
            self = this;
        //---------------------------------------
        // PRIVATE METHODS
        //---------------------------------------
        var saveTriggerContent = function ($trigger) {
            title = $trigger.attr('title');
            if (title) {
                $trigger.data('hlfTipContent', title)
                        .attr('data-tip-content', 'hlfTipContent')
                        .removeAttr('title');
            }
        };
        var bindTrigger = function ($trigger) {
            $trigger.bind({
                'truemouseenter.hlf.tip': function (evt) {
                    self.wake($trigger);
                    log('truemouseenter');
                },
                'truemouseleave.hlf.tip': function (evt) {
                    self.sleep($trigger);
                    log('truemouseleave');
                }
            });
            if (self.doFollow) {
                $trigger.bind('mousemove.hlf.tip', onMouseMove);
            }
        };
        var renderDefaultTip = function () {
            var builder = [],
                html;
            builder.push('
');
            builder.push('
');
            if (self.doStem) {
                builder.push('
');
                builder.push('
');
            }
            builder.push('
');
            builder.push('
');
            builder.push('
', '
');
            html = builder.join('');
            html = self.onRenderDefault(html);
            return html;
        };
        var renderTip = function ($trigger) {
            if ($tip.html && $tip.html().length > 0) {
                return;
            }
            var html = self.onRender(),
                isCustom = (html.length > 0);
            if (!isCustom) {
                html = renderDefaultTip();
            }
            $tip = $(html);
            if (isCustom) {
                $tip.addClass(opt.followClass);
            }
            $tip.prependTo($context);
        };
        var positionTip = function ($trigger) {
            var offset = $trigger.offset();
            offset = self.onPosition(offset);
            if (self.doFollow) {
                $trigger.trigger('mousemove.hlf.tip');
                return;
            }
            $tip.css(offset);
            log('positionTip');
        };
        var hydrateTip = function ($trigger) {
            var content = $trigger.data('hlfTipContent');
            $tip.find("." + opt.contentClass).text(content);
        };
        var checkBounds = function (position) {

        };
        //---------------------------------------
        // EVENT HANDLERS
        //---------------------------------------
        var onMouseMove = function (evt) {
            var offset = {
                top: evt.pageY,
                left: evt.pageX
            };
            offset = self.onMouseMove(evt, offset);
            offset.top += opt.cursorHeight;
            $tip.css(offset);
            log('onMouseMove');
        };
        $.extend(self, {
            //---------------------------------------
            // PUBLIC VARIABLES
            //---------------------------------------
            doStem: true,
            doFollow: true,
            //---------------------------------------
            // PUBLIC METHODS
            //---------------------------------------
            init: function () {
                $tip = $('
');
                self.doStem = (opt.stemClass !== '');
                self.doFollow = (opt.followClass !== '' && opt.cursorHeight > 0);
                $triggers.each(function () {
                    var $t = $(this);
                    saveTriggerContent($t);
                    bindTrigger($t);
                });
                renderTip();
            },
            getOptions: function () {
                return opt;
            },
            getTip: function () {
                return $tip;
            },
            wake: function ($trigger) {
                if ($trigger !== $triggerP) {
                    hydrateTip($trigger);
                    positionTip($trigger);
                }
                self.onShow();
                // TODO - no fade if immediated retriggered
                if ($tip.is(':hidden, :animated')) {
                    $tip.fadeIn(opt.inDuration, self.afterShow);
                }
            },
            sleep: function ($trigger) {
                if ($trigger !== $triggerP) {
                    $triggerP = $trigger;
                }
                self.onHide();
                if ($tip.is(':visible')) {
                    $tip.fadeOut(opt.outDuration, self.afterHide);
                }
            },
            //---------------------------------------
            // EXTENSION SLOTS
            //---------------------------------------
            onShow: function () {},
            onHide: function () {},
            afterShow: function () {},
            afterHide: function () {},
            onRender: function (content) { return ''; },
            onRenderDefault: function (html) { return html; },
            onPosition: function (offset) { return offset; },
            onMouseMove: function (evt, offset) { return offset; }
        });
        self.init();
    };
    // one tip per context
    // links the tip to everything selected
    $.fn.hlfTip = function (opt, $context) {
        $context = $context || $('body');
        var instance = $context.data('hlfTip');
        if (instance) {
            return instance;
        }
        opt = $.extend({}, $.hlf.tip.opt, opt);
        // instantiate
        instance = new Tip($context, this, opt);
        $context.data('hlfTip', instance);
        // other
        $context.attr('data-tip', 'hlfTip');
        return this;
    };

})(jQuery);
(function ($) {
    var log = function(x) { console.log(x); };
    log = $.noop; // comment to start debugging
    //---------------------------------------
    // STATIC VARIABLES
    //---------------------------------------
    $.extend(true, $, {
        // $.mouse
        mouse: {
            x: {current: 0, previous: 0},
            y: {current: 0, previous: 0},
            hoverIntentSensitivity: 8,
            hoverIntentInterval: 300
        }
    });
    //---------------------------------------
    // EVENT HANDLERS
    //---------------------------------------
    var checker = function (evt) {
        var $trigger = $(this),
            intentional = $trigger.data('hoverIntent') || true,
            timer = $trigger.data('hoverIntentTimer') || null,
            sensitivity = $trigger.data('hoverIntentSensitivity') || $.mouse.hoverIntentSensitivity,
            interval = $trigger.data('hoverIntentInterval') || $.mouse.hoverIntentInterval,
            mouse = $.mouse;
        // update timer
        $trigger.data('hoverIntentTimer',
            setTimeout(function () {
                var intentional = ((Math.abs(mouse.x.previous - mouse.x.current) +
                    Math.abs(mouse.y.previous - mouse.y.current)) > sensitivity ||
                    evt.type === 'mouseleave');
                cache(evt);
                $trigger.data('hoverIntent', intentional);
                if (intentional) {
                    $trigger.trigger('true'+evt.type);
                    switch (evt.type) {
                        case 'mouseleave':
                            clear($trigger);
                            break;
                    }
                    log(evt.type);
                }
                log('timer');
            }, interval)
        );
        log('checker');
    };
    var tracker = function (evt) {
        var mouse = $.mouse;
        mouse.x.current = evt.pageX;
        mouse.y.current = evt.pageY;
        log('tracker');
    };
    //---------------------------------------
    // PRIVATE METHODS
    //---------------------------------------
    var cache = function (evt) {
        evt = evt || false;
        var mouse = $.mouse;
        if (evt) {
            mouse.x.previous = evt.pageX;
            mouse.y.previous = evt.pageY;
        } else {
            mouse.x.previous = mouse.x.current;
            mouse.y.previous = mouse.y.current;
        }
        log('cache');
    };
    var clear = function ($trigger) {
        clearTimeout($trigger.data('hoverIntentTimer'));
        log('clear');
    }
    $.event.special.truemouseenter = {
        setup: function (data, namespaces) {
            $(this).bind({
               mouseenter: checker,
               mousemove: tracker
            });
        },
        teardown: function (namespaces) {
            $(this).unbind({
               mouseenter: checker,
               mousemove: tracker
            });
        }
    };
    $.event.special.truemouseleave = {
        setup: function (data, namespaces) {
            $(this).bind('mouseleave', checker);
        },
        teardown: function (namespaces) {
            $(this).unbind('mouseleave', checker);
        }
    };
})(jQuery);
(function ($) {
    var log = function(x) { console.log(x); };
    // log = $.noop; // comment to start debugging
    //---------------------------------------
    // STATIC VARIABLES
    //---------------------------------------
    $.extend(true, $, {
        // $.hlf.tip.snap
        hlf: { tip: { snap: {
            opt: {
                snapClass: 'tip-snap',
                railXClass: 'rail-x',
                railYClass: 'rail-y'
            }
        }}}
    });
    //---------------------------------------
    // CLASSES
    //---------------------------------------
    var SnapTip = function ($context, $triggers, opt) {
        //---------------------------------------
        // PRIVATE VARIABLES / CONSTRUCTOR
        //---------------------------------------
        var self = this,
            tip = $context.data('hlfTip'),
            tipOptions = tip.getOptions(),
            offsetStart;
        //---------------------------------------
        // PRIVATE METHODS
        //---------------------------------------
        var bindTrigger = function ($trigger) {
            $trigger.bind({
                'truemouseenter.hlf.tip': function (evt) {
                    offsetStart = {
                        top: evt.pageX,
                        left: evt.pageY
                    };
                    log('truemouseenter');
                },
                'truemouseleave.hlf.tip': function (evt) {
                    log('truemouseleave');
                }
            });
        };
        $.extend(self, {
            //---------------------------------------
            // PUBLIC VARIABLES
            //---------------------------------------
            doRailX: true,
            doRailY: false,
            doSnap: true,
            //---------------------------------------
            // PUBLIC METHODS
            //---------------------------------------
            init: function () {
                self.doRailX = (opt.railXClass !== '');
                self.doRailY = (opt.railYClass !== '');
                self.doSnap = (opt.snapClass !== '' && (self.doRailX || self.doRailY));
                $triggers.each(function () {
                    var $t = $(this);
                    bindTrigger($t);
                });
                // allow us to extend tip api
                $context.data('hlfTip', tip);
            },
            move: function () {

            }
        });
        $.extend(tip, {
            onPosition: function (offset) {
                log('onPosition');
                return offset;
            },
            onMouseMove: function (evt, offset) {
                if (offsetStart === undefined) {
                    offsetStart = {
                        top: evt.pageX,
                        left: evt.pageY
                    };
                }
                if (self.doRailX) {
                    offset.top = (offsetStart.top + tipOptions.cursorHeight);
                    log('railX');
                } else if (self.doRailY) {
                    offset.left = offsetStart.left;
                    log('railY');
                }
                log('onMouseMove');
                return offset;
            }
        });
        self.init();
    };
    $.fn.hlfSnapTip = function (opt, $context) {
        $context = $context || $('body');
        var instance = $context.data('hlfSnapTip');
        if (instance) {
            return instance;
        }
        opt = $.extend({}, $.hlf.tip.snap.opt, opt);
        instance = new SnapTip($context, this, opt);
        $context.data('hlfSnapTip', instance);
        $context.attr('data-snap-tip', 'hlfSnapTip');
        return this;
    };
})(jQuery);

<commit_msg>hlftip - fixes, mostly for waking and sleeping tip<commit_after>/**
 * Tooltip Widget
 * @author Peng Wang <peng@pengxwang.com>
 * @version 1.2
 * @requires jQuery 1.4+
 * @package jQuery.hlf
 * @subpackage jQuery.hlf.tip
**/
;(function ($) {
    var log = function(x) { console.log(x); };
    // log = $.noop; // comment to start debugging
    //---------------------------------------
    // STATIC VARIABLES
    //---------------------------------------
    $.extend(true, $, {
        // $.hlf.tip
        hlf: { tip: {
            opt: {
                // direction: '',
                // millis
                inDuration: 300,
                inDelay: 0,
                outDuration: 300,
                outDelay: 500,
                // pixels
                cursorHeight: 16,
                // class names
                innerClass: 'inner',
                contentClass: 'content',
                stemClass: 'stem',
                northClass: 'north',
                eastClass: 'east',
                southClass: 'south',
                westClass: 'west',
                followClass: 'tip-follow',
                tipClass: 'tip'
            }
        }}
    });
    /**
     * Base Tip
     * prevents hover queueing
     * slots for display and movement
     * @todo truemouseenter sometimes doesn't fire when moving to adjacent trigger
    **/
    var Tip = function ($context, $triggers, opt) {
        //---------------------------------------
        // PRIVATE VARIABLES / CONSTRUCTOR
        //---------------------------------------
        var $tip,
            $trigger, $triggerP,
            visibility,
            wakeCountdown,
            sleepCountdown,
            self = this;
        //---------------------------------------
        // PRIVATE METHODS
        //---------------------------------------
        var saveTriggerContent = function ($trigger) {
            title = $trigger.attr('title');
            if (title) {
                $trigger.data('hlfTipContent', title)
                        .attr('data-tip-content', 'hlfTipContent')
                        .removeAttr('title');
            }
        };
        var bindTrigger = function ($trigger) {
            $trigger.bind({
                'truemouseenter.hlf.tip': function (evt) {
                    self.wake($trigger);
                }, 'truemouseleave.hlf.tip': function (evt) {
                    self.sleep($trigger);
                }
            });
            if (self.doFollow) {
                $trigger.bind('mousemove.hlf.tip', onMouseMove);
            }
        };
        var bindTip = function ($trigger) {
            $tip.bind({
                'mouseenter.hlf.tip': function (evt) {
                    log('enter tip');
                    $trigger.data('activeState', true);
                }, 'mouseleave.hlf.tip': function (evt) {
                    log('leave tip');
                    $trigger.data('activeState', false);
                }
            });
        }
        var renderDefaultTip = function () {
            var builder = [],
                html;
            builder.push('
');
            builder.push('
');
            if (self.doStem) {
                builder.push('
');
                builder.push('
');
            }
            builder.push('
');
            builder.push('
');
            builder.push('
', '
');
            html = builder.join('');
            return html;
        };
        var renderTip = function ($trigger) {
            if ($tip.html && $tip.html().length > 0) {
                return;
            }
            var html = self.onRender(),
                isCustom = (html.length > 0);
            if (!isCustom) {
                html = renderDefaultTip();
            }
            $tip = $(html);
            if (isCustom) {
                $tip.addClass(opt.followClass);
            }
            $tip.prependTo($context);
        };
        var positionTip = function ($trigger) {
            var offset = $trigger.offset();
            offset = self.onPosition(offset);
            if (self.doFollow) {
                $trigger.trigger('mousemove.hlf.tip');
                return;
            }
            // default adjustment
            offset.top += opt.cursorHeight;
            $tip.css(offset);
            log('positionTip');
        };
        var hydrateTip = function ($trigger) {
            var content = $trigger.data('hlfTipContent');
            $tip.find("." + opt.contentClass).text(content);
        };
        var checkBounds = function (position) {

        };
        //---------------------------------------
        // EVENT HANDLERS
        //---------------------------------------
        var onMouseMove = function (evt) {
            if (evt.pageX === undefined) {
                return;
            }
            // #HACK
            if (self.isAsleep()) {
                self.wake($(evt.target));
            }
            var offset = {
                top: evt.pageY,
                left: evt.pageX
            };
            offset = self.onMouseMove(evt, offset);
            offset.top += opt.cursorHeight;
            $tip.css(offset);
            log('onMouseMove');
        };
        $.extend(self, {
            //---------------------------------------
            // PUBLIC VARIABLES
            //---------------------------------------
            doStem: true,
            doFollow: true,
            //---------------------------------------
            // PUBLIC METHODS
            //---------------------------------------
            init: function () {
                $tip = $('
');
                self.doStem = (opt.stemClass !== '');
                self.doFollow = (opt.followClass !== '' && opt.cursorHeight > 0);
                $triggers.each(function () {
                    var $t = $(this);
                    saveTriggerContent($t);
                    bindTrigger($t);
                    bindTip($t);
                });
                renderTip();
            },
            getOptions: function () {
                return opt;
            },
            getTip: function () {
                return $tip;
            },
            isAwake: function () {
                return visibility === 'truevisible';
            },
            isAsleep: function () {
                return visibility === 'truehidden';
            },
            wake: function ($trigger) {
                if ($trigger !== $triggerP) {
                    hydrateTip($trigger);
                    positionTip($trigger);
                }
                wakeCountdown = setTimeout(function () {
                    clearTimeout(sleepCountdown);
                    if (self.isAwake()) {
                        return;
                    }
                    self.onShow();
                    $tip.fadeIn(opt.inDuration, function () {
                        visibility = 'truevisible';
                        self.afterShow();
                    });
                }, opt.inDelay);
            },
            sleep: function ($trigger) {
                if ($trigger !== $triggerP) {
                    $triggerP = $trigger;
                }
                sleepCountdown = setTimeout(function () {
                    clearTimeout(wakeCountdown);
                    if (self.isAsleep()) {
                        return;
                    }
                    self.onHide();
                    $tip.fadeOut(opt.outDuration, function () {
                        visibility = 'truehidden';
                        self.afterHide();
                    });
                }, opt.outDelay);
            },
            //---------------------------------------
            // EXTENSION SLOTS
            //---------------------------------------
            onShow: function () {},
            onHide: function () {},
            afterShow: function () {},
            afterHide: function () {},
            onRender: function (content) { return ''; },
            onPosition: function (offset) { return offset; },
            onMouseMove: function (evt, offset) { return offset; }
        });
        self.init();
    };
    // one tip per context
    // links the tip to everything selected
    $.fn.hlfTip = function (opt, $context) {
        $context = $context || $('body');
        var instance = $context.data('hlfTip');
        if (instance) {
            return instance;
        }
        opt = $.extend({}, $.hlf.tip.opt, opt);
        // instantiate
        instance = new Tip($context, this, opt);
        $context.data('hlfTip', instance);
        // other
        $context.attr('data-tip', 'hlfTip');
        return this;
    };

})(jQuery);
(function ($) {
    var log = function(x) { console.log(x); };
    // log = $.noop; // comment to start debugging
    //---------------------------------------
    // STATIC VARIABLES
    //---------------------------------------
    $.extend(true, $, {
        // $.mouse
        mouse: {
            x: {current: 0, previous: 0},
            y: {current: 0, previous: 0},
            hoverIntentSensitivity: 8,
            hoverIntentInterval: 300
        }
    });
    //---------------------------------------
    // EVENT HANDLERS
    //---------------------------------------
    var checker = function (evt) {
        var $trigger = $(this),
            intentional = $trigger.data('hoverIntent') || true,
            timer = $trigger.data('hoverIntentTimer') || null,
            sensitivity = $trigger.data('hoverIntentSensitivity') || $.mouse.hoverIntentSensitivity,
            interval = $trigger.data('hoverIntentInterval') || $.mouse.hoverIntentInterval,
            mouse = $.mouse;
        // update timer
        $trigger.data('hoverIntentTimer',
            setTimeout(function () {
                var intentional = ((Math.abs(mouse.x.previous - mouse.x.current) +
                    Math.abs(mouse.y.previous - mouse.y.current)) > sensitivity ||
                    evt.type === 'mouseleave');
                // cache
                mouse.x.previous = evt.pageX;
                mouse.y.previous = evt.pageY;
                $trigger.data('hoverIntent', intentional);
                // go
                if (intentional) {
                    switch (evt.type) {
                        case 'mouseleave':
                            if ($trigger.data('activeState') === true) {
                                log('activeState');
                                return;
                            }
                            clear($trigger);
                            break;
                    }
                    $trigger.trigger('true'+evt.type);
                    log(evt.type);
                }
                // log('timer');
            }, interval)
        );
        // log('checker');
    };
    var tracker = function (evt) {
        var mouse = $.mouse;
        mouse.x.current = evt.pageX;
        mouse.y.current = evt.pageY;
        // log('tracker');
    };
    //---------------------------------------
    // PRIVATE METHODS
    //---------------------------------------
    var cache = function (evt) {
        evt = evt || false;
        // log('cache');
    };
    var clear = function ($trigger) {
        clearTimeout($trigger.data('hoverIntentTimer'));
        // log('clear');
    }
    $.event.special.truemouseenter = {
        setup: function (data, namespaces) {
            $(this).bind({
               mouseenter: checker,
               mousemove: tracker
            });
        },
        teardown: function (namespaces) {
            $(this).unbind({
               mouseenter: checker,
               mousemove: tracker
            });
        }
    };
    $.event.special.truemouseleave = {
        setup: function (data, namespaces) {
            $(this).bind('mouseleave', checker);
        },
        teardown: function (namespaces) {
            $(this).unbind('mouseleave', checker);
        }
    };
})(jQuery);
(function ($) {
    var log = function(x) { console.log(x); };
    log = $.noop; // comment to start debugging
    //---------------------------------------
    // STATIC VARIABLES
    //---------------------------------------
    $.extend(true, $, {
        // $.hlf.tip.snap
        hlf: { tip: { snap: {
            opt: {
                snapClass: 'tip-snap',
                railXClass: 'rail-x',
                railYClass: 'rail-y'
            }
        }}}
    });
    //---------------------------------------
    // CLASSES
    //---------------------------------------
    var SnapTip = function ($context, $triggers, opt) {
        //---------------------------------------
        // PRIVATE VARIABLES / CONSTRUCTOR
        //---------------------------------------
        var self = this,
            tip = $context.data('hlfTip'),
            tipOptions = tip.getOptions(),
            offsetStart;
        //---------------------------------------
        // PRIVATE METHODS
        //---------------------------------------
        var bindTrigger = function ($trigger) {
            $trigger.bind({
                'truemouseenter.hlf.tip': function (evt) {
                    offsetStart = {
                        top: evt.pageX,
                        left: evt.pageY
                    };
                    log('truemouseenter');
                },
                'truemouseleave.hlf.tip': function (evt) {
                    offsetStart = undefined;
                    log('truemouseleave');
                }
            });
        };
        $.extend(self, {
            //---------------------------------------
            // PUBLIC VARIABLES
            //---------------------------------------
            doRailX: true,
            doRailY: false,
            doSnap: true,
            //---------------------------------------
            // PUBLIC METHODS
            //---------------------------------------
            init: function () {
                self.doRailX = (opt.railXClass !== '');
                self.doRailY = (opt.railYClass !== '');
                self.doSnap = (opt.snapClass !== '' && (self.doRailX || self.doRailY));
                $triggers.each(function () {
                    var $t = $(this);
                    bindTrigger($t);
                });
                // allow us to extend tip api
                $context.data('hlfTip', tip);
            },
            move: function () {

            }
        });
        $.extend(tip, {
            onPosition: function (offset) {
                log('onPosition');
                return offset;
            },
            onMouseMove: function (evt, offset) {
                if (offsetStart === undefined) {
                    return offset;
                }
                if (self.doRailX) {
                    offset.top = offsetStart.top;
                    log('railX');
                } else if (self.doRailY) {
                    offset.left = offsetStart.left;
                    log('railY');
                }
                return offset;
            }
        });
        self.init();
    };
    $.fn.hlfSnapTip = function (opt, $context) {
        $context = $context || $('body');
        var instance = $context.data('hlfSnapTip');
        if (instance) {
            return instance;
        }
        opt = $.extend({}, $.hlf.tip.snap.opt, opt);
        instance = new SnapTip($context, this, opt);
        $context.data('hlfSnapTip', instance);
        $context.attr('data-snap-tip', 'hlfSnapTip');
        return this;
    };
})(jQuery);

<|endoftext|>


<commit_before>var serialport = require("serialport");
var colors = require('colors');
var SerialPort = serialport.SerialPort;
var EventEmitter = require('events').EventEmitter;

/**
 * constructor function
 */
var DeskLamp = function() {

	var self = this;

	this.device = "/dev/tty.usbmodem1421";
	this.baudrate = 9600;
	this.serialPort;

	this.r;
	this.g;
	this.b;
};

/**
 * Event emmitter goodness!
 */
DeskLamp.prototype.__proto__ = EventEmitter.prototype;

/**
 * Initilize the DeskLamp, connects to the serial port.
 */
DeskLamp.prototype.connect = function (callback) {
	var self = this;

	this.serialPort = new SerialPort(this.device, {
		baudrate: this.baudrate,
		parser: serialport.parsers.readline("\n")
	});

	this.serialPort.on("open", function() {
		// need to wait for a second, who knows why.
		setTimeout(function() {
			self.connected();
			callback();
		}, 1000);
	});
};

/**
 * connected handler for when the serial connection is open.
 */
DeskLamp.prototype.connected = function() {
	console.log('DeskLamp '.green + this.device.yellow + ' @ ' + this.baudrate.toString().blue + ' bps'.blue);

	this.serialPort.on('data', function(data) {
		console.info('∞ '.magenta + data);
	});
};

/**
 * Sets the color of the leds
 */
DeskLamp.prototype.setColor = function(r, g, b) {
	this.serialPort.write(r + ',' + g + ',' + b + '\n');
};

module.exports = new DeskLamp();

//function pulse() {
	//if(pulseInhale) {
		//r+=5;
		//g+=5;
		//b+=5;
		//if(r >= 255) pulseInhale = false;
	//} else {
		//r-=5;
		//g-=5;
		//b-=5;
		//if(r <= 50) pulseInhale = true;
	//}

	//setColor(r, g, b);
//}
<commit_msg>add color event handler<commit_after>var serialport = require("serialport");
var colors = require('colors');
var SerialPort = serialport.SerialPort;
var EventEmitter = require('events').EventEmitter;

/**
 * constructor function
 */
var DeskLamp = function() {

	var self = this;

	this.device = "/dev/tty.usbmodem1421";
	this.baudrate = 9600;
	this.serialPort;

	this.r;
	this.g;
	this.b;

	this.on('color', function(r, g, b) {
		this.setColor(r, g, b);
	});
};

/**
 * Event emmitter goodness!
 */
DeskLamp.prototype.__proto__ = EventEmitter.prototype;

/**
 * Initilize the DeskLamp, connects to the serial port.
 */
DeskLamp.prototype.connect = function (callback) {
	var self = this;

	this.serialPort = new SerialPort(this.device, {
		baudrate: this.baudrate,
		parser: serialport.parsers.readline("\n")
	});

	this.serialPort.on("open", function() {
		// need to wait for a second, who knows why.
		setTimeout(function() {
			self.connected();
			callback();
		}, 1300);
	});
};

/**
 * connected handler for when the serial connection is open.
 */
DeskLamp.prototype.connected = function() {
	console.log('DeskLamp '.green + this.device.yellow + ' @ ' + this.baudrate.toString().blue + ' bps'.blue);

	this.serialPort.on('data', function(data) {
		console.info('∞ '.magenta + data);
	});
};

/**
 * Sets the color of the leds
 */
DeskLamp.prototype.setColor = function(r, g, b) {
	//console.log(r.toString().red + ',' + g.toString().green + ',' + b.toString().blue);
	this.serialPort.write(r + ',' + g + ',' + b + '\n');
};

module.exports = new DeskLamp();

//function pulse() {
	//if(pulseInhale) {
		//r+=5;
		//g+=5;
		//b+=5;
		//if(r >= 255) pulseInhale = false;
	//} else {
		//r-=5;
		//g-=5;
		//b-=5;
		//if(r <= 50) pulseInhale = true;
	//}

	//setColor(r, g, b);
//}
<|endoftext|>


<commit_before>/**
* rovingtabindex.js
* @author Ian McBurnie
*
* Implements a roving tabindex on a collection of elements.
* http://www.w3.org/TR/wai-aria-practices/#kbd_general_within
*
* Triggers 'rovingtabindex' event when tabindex changes
*
* @dependencies jquery.keyhandlers.js
*/

(function ( $ ) {

    $.fn.rovingtabindex = function rovingTabIndex(id, options) {

        var _idx = 0;

        options = options || {};

        return this.each(function onEach() {

            var $this = $(this);

            // store collection index pos in element dataset
            $this.attr('data-{0}'.replace('{0}', id), JSON.stringify({'rovingtabindex': _idx++}));

            $this.onLeftOrUpArrowKey(function onLeftOrUpArrowKey() {
                var itemIdx = $this.data(id).rovingtabindex,
                    $siblings = $('[data-{0}]'.replace('{0}', id)),
                    $prevEl = $siblings.eq(itemIdx - 1),
                    hasPrevEl = $prevEl.length === 1,
                    $lastEl = $siblings.eq($siblings.length-1),
                    $roveToEl = (hasPrevEl) ? $prevEl : $lastEl;

                $this.attr('tabindex', '-1');
                $roveToEl.attr('tabindex', '0');
                $this.trigger('rovingtabindex', $roveToEl);
            });

            $this.onRightOrDownArrowKey(function onRightOrDownArrowKey() {
                var itemIdx = $this.data(id).rovingtabindex,
                    $siblings = $('[data-{0}]'.replace('{0}', id)),
                    $nextEl = $siblings.eq(itemIdx + 1),
                    hasNextEl = $nextEl.length === 1,
                    $firstEl = $siblings.eq(0),
                    $roveToEl = (hasNextEl) ? $nextEl : $firstEl;

                $this.attr('tabindex', '-1');
                $roveToEl.attr('tabindex', '0');
                $this.trigger('rovingtabindex', $roveToEl);
            });
        });
    };

}( jQuery ));
<commit_msg>Added options.cursorDirection<commit_after>/**
* @function jquery.rovingtabindex.js
* @author Ian McBurnie <ianmcburnie@hotmail.com>
* @description Implements a roving tabindex on a collection of elements.
* @summary http://www.w3.org/TR/wai-aria-practices/#kbd_general_within
* @requires jquery.keyhandlers.js
* @param {string} id
* @param {Object} options
* @param {string} options.cursorDirection
* @fires rovingtabindex
*/
(function ($, window, document, undefined) {

    $.fn.rovingtabindex = function rovingTabIndex(id, options) {

        var _idx = 0,
            options = options || {},
            wrap = options.wrap,
            cursorDirection = options.cursorDirection || 'both';

        return this.each(function onEach(i) {

            var $this = $(this);

            // store collection index pos in element dataset
            $this.attr('data-{0}'.replace('{0}', id), JSON.stringify({'rovingtabindex': _idx++}));

            if (cursorDirection === 'horizontal') {
                $this.on('leftkeydown', function onLeftArrowKey() {
                    $this.trigger('prev');
                });

                $this.on('rightkeydown', function onRightArrowKey() {
                    $this.trigger('next');
                });
            }
            else if (cursorDirection === 'vertical') {
                $this.on('downkeydown', function onDownArrowKey() {
                    $this.trigger('next');
                });

                $this.on('upkeydown', function onUpArrowKey() {
                    $this.trigger('prev');
                });
            }
            else {
                $this.on('leftkeydown upkeydown', function onLeftOrUpArrowKey() {
                    $this.trigger('prev');
                });

                $this.on('rightkeydown downkeydown', function onRightOrDownArrowKey() {
                    $this.trigger('next');
                });
            }

            $this.on('prev', function onPrev(e) {
                var itemIdx = $this.data(id).rovingtabindex,
                    $siblings = $('[data-{0}]'.replace('{0}', id)),
                    $prevEl = $siblings.eq(itemIdx - 1),
                    hasPrevEl = $prevEl.length === 1,
                    $lastEl = $siblings.eq($siblings.length-1),
                    $roveToEl = (hasPrevEl && itemIdx !== 0) ? $prevEl : (options.wrap !== false) ? $lastEl : $this;

                $this.attr('tabindex', '-1');
                $roveToEl.attr('tabindex', '0');
                $this.trigger('rovingtabindex', $roveToEl);
            });

            $this.on('next', function onNext(e) {
                var itemIdx = $this.data(id).rovingtabindex,
                    $siblings = $('[data-{0}]'.replace('{0}', id)),
                    $nextEl = $siblings.eq(itemIdx + 1),
                    hasNextEl = $nextEl.length === 1,
                    $firstEl = $siblings.eq(0),
                    $roveToEl = (hasNextEl) ? $nextEl : (options.wrap !== false) ? $firstEl: $this;

                $this.attr('tabindex', '-1');
                $roveToEl.attr('tabindex', '0');
                $this.trigger('rovingtabindex', $roveToEl);
            });

        });
    };

}(jQuery, window, document));
<|endoftext|>


<commit_before>// Copyright 2017-2020, University of Colorado Boulder

/**
 * Assists "changing" options for types of nodes where the node does not support modifying the option.
 * This will create a new copy of the node whenever the options change, and will swap it into place.
 *
 * @author Jonathan Olson (PhET Interactive Simulations)
 */

import Property from '../../axon/js/Property.js';
import inherit from '../../phet-core/js/inherit.js';
import merge from '../../phet-core/js/merge.js';
import Node from '../../scenery/js/nodes/Node.js';
import sun from './sun.js';

/**
 * @constructor
 *
 * Given a type that has an option that can only be provided on construction (e.g. 'color' option for NumberPicker),
 * MutableOptionsNode can act like a mutable form of that Node. For example, if you have a color property:
 *
 * var colorProperty = new Property( 'red' );
 *
 * You can create a NumberPicker equivalent:
 *
 * var pickerContainer = new MutableOptionsNode( NumberPicker, [ arg1, arg2 ], {
 *   font: new PhetFont( 30 ) // normal properties that are passed in directly
 * }, {
 *   color: colorProperty // values wrapped with Property. When these change, a new NumberPicker is created and swapped.
 * }, {
 *   // Options passed to the wrapper node.
 * } );
 *
 * Now pickerContainer will have a child that is a NumberPicker, and pickerContainer.nodeProperty will point to the
 * current NumberPicker instance. The NumberPicker above will be created with like:
 *
 * new NumberPicker( arg1, arg2, {
 *   font: new PhetFont( 30 ),
 *   color: colorProperty.value
 * } )
 *
 * @param {Function} nodeSubtype - The type of the node that we'll be constructing copies of.
 * @param {Array.<*>} parameters - Arbitrary initial parameters that will be passed to the type's constructor
 * @param {Object} staticOptions - Options passed in that won't change (will not unwrap properties)
 * @param {Object} dynamicOptions - Options passed in that will change. Should be a map from key names to
 *                                  Property.<*> values.
 * @param {Object} [wrapperOptions] - Node options passed to MutableOptionsNode itself (the wrapper).
 */
function MutableOptionsNode( nodeSubtype, parameters, staticOptions, dynamicOptions, wrapperOptions ) {
  Node.call( this );

  // @public {Property.<Node|null>} [read-only] - Holds our current copy of the node (or null, so we don't have a
  //                                              specific initial value).
  this.nodeProperty = new Property( null );

  // @private {Function} - The constructor for our custom subtype
  this._type = function MutableOptionsNodeConstructor() {
    // Unwrap the properties in dynamicOptions
    const options = merge( _.mapValues( dynamicOptions, function( property ) {
      return property.value;
    } ), staticOptions );

    // NOTE: In the future, we won't need to subtype if we can rely on Reflect.construct:
    // return Reflect.construct( this.nodeSubtype, this.parameters.concat( [ options ] ) );
    nodeSubtype.apply( this, parameters.concat( [ options ] ) );
  };

  // Have our copies inherit directly (for now, use Reflect.construct when IE11 support is dropped?)
  inherit( nodeSubtype, this._type );

  // @private {Multilink} - Make a copy, and replace it when one of our dyanmic options changes.
  this.multilink = Property.multilink( _.values( dynamicOptions ), this.replaceCopy.bind( this ) );

  // Apply any options that make more sense on the wrapper (typically like positioning)
  this.mutate( wrapperOptions );
}

sun.register( 'MutableOptionsNode', MutableOptionsNode );

inherit( Node, MutableOptionsNode, {
  /**
   * Creates a copy of our type of node, and replaces any existing copy.
   * @private
   */
  replaceCopy: function() {
    const Type = this._type; // avoids our linter complaining about uncapitalized types with 'new'
    const newCopy = new Type();
    const oldCopy = this.nodeProperty.value;
    this.nodeProperty.value = newCopy;

    // Add first, so that there's a good chance we won't change bounds (depending on the type)
    this.addChild( newCopy );
    if ( oldCopy ) {
      this.removeChild( oldCopy );
      this.disposeCopy( oldCopy );
    }
  },

  /**
   * Attempt to dispose an instance of our node.
   * @private
   *
   * @param {Node} copy
   */
  disposeCopy: function( copy ) {
    copy.dispose && copy.dispose();
  },

  /**
   * Handles disposal.
   */
  dispose: function() {
    this.multilink.dispose();
    this.disposeCopy( this.nodeProperty.value );
    this.nodeProperty.dispose();
    Node.prototype.dispose.call( this );
  }
} );

export default MutableOptionsNode;<commit_msg>Use Reflect.construct, see https://github.com/phetsims/sun/issues/627<commit_after>// Copyright 2017-2020, University of Colorado Boulder

/**
 * Assists "changing" options for types of nodes where the node does not support modifying the option.
 * This will create a new copy of the node whenever the options change, and will swap it into place.
 *
 * @author Jonathan Olson (PhET Interactive Simulations)
 */

import Property from '../../axon/js/Property.js';
import inherit from '../../phet-core/js/inherit.js';
import merge from '../../phet-core/js/merge.js';
import Node from '../../scenery/js/nodes/Node.js';
import sun from './sun.js';

/**
 * @constructor
 *
 * Given a type that has an option that can only be provided on construction (e.g. 'color' option for NumberPicker),
 * MutableOptionsNode can act like a mutable form of that Node. For example, if you have a color property:
 *
 * var colorProperty = new Property( 'red' );
 *
 * You can create a NumberPicker equivalent:
 *
 * var pickerContainer = new MutableOptionsNode( NumberPicker, [ arg1, arg2 ], {
 *   font: new PhetFont( 30 ) // normal properties that are passed in directly
 * }, {
 *   color: colorProperty // values wrapped with Property. When these change, a new NumberPicker is created and swapped.
 * }, {
 *   // Options passed to the wrapper node.
 * } );
 *
 * Now pickerContainer will have a child that is a NumberPicker, and pickerContainer.nodeProperty will point to the
 * current NumberPicker instance. The NumberPicker above will be created with like:
 *
 * new NumberPicker( arg1, arg2, {
 *   font: new PhetFont( 30 ),
 *   color: colorProperty.value
 * } )
 *
 * @param {Function} nodeSubtype - The type of the node that we'll be constructing copies of.
 * @param {Array.<*>} parameters - Arbitrary initial parameters that will be passed to the type's constructor
 * @param {Object} staticOptions - Options passed in that won't change (will not unwrap properties)
 * @param {Object} dynamicOptions - Options passed in that will change. Should be a map from key names to
 *                                  Property.<*> values.
 * @param {Object} [wrapperOptions] - Node options passed to MutableOptionsNode itself (the wrapper).
 */
function MutableOptionsNode( nodeSubtype, parameters, staticOptions, dynamicOptions, wrapperOptions ) {
  Node.call( this );

  // @public {Property.<Node|null>} [read-only] - Holds our current copy of the node (or null, so we don't have a
  //                                              specific initial value).
  this.nodeProperty = new Property( null );

  // @private {Function} - The constructor for our custom subtype
  this._type = function MutableOptionsNodeConstructor() {
    // Unwrap the properties in dynamicOptions
    const options = merge( _.mapValues( dynamicOptions, function( property ) {
      return property.value;
    } ), staticOptions );

    return Reflect.construct( nodeSubtype, parameters.concat( [ options ] ) );
  };

  // Have our copies inherit directly (for now, use Reflect.construct when IE11 support is dropped?)
  inherit( nodeSubtype, this._type );

  // @private {Multilink} - Make a copy, and replace it when one of our dyanmic options changes.
  this.multilink = Property.multilink( _.values( dynamicOptions ), this.replaceCopy.bind( this ) );

  // Apply any options that make more sense on the wrapper (typically like positioning)
  this.mutate( wrapperOptions );
}

sun.register( 'MutableOptionsNode', MutableOptionsNode );

inherit( Node, MutableOptionsNode, {
  /**
   * Creates a copy of our type of node, and replaces any existing copy.
   * @private
   */
  replaceCopy: function() {
    const Type = this._type; // avoids our linter complaining about uncapitalized types with 'new'
    const newCopy = new Type();
    const oldCopy = this.nodeProperty.value;
    this.nodeProperty.value = newCopy;

    // Add first, so that there's a good chance we won't change bounds (depending on the type)
    this.addChild( newCopy );
    if ( oldCopy ) {
      this.removeChild( oldCopy );
      this.disposeCopy( oldCopy );
    }
  },

  /**
   * Attempt to dispose an instance of our node.
   * @private
   *
   * @param {Node} copy
   */
  disposeCopy: function( copy ) {
    copy.dispose && copy.dispose();
  },

  /**
   * Handles disposal.
   */
  dispose: function() {
    this.multilink.dispose();
    this.disposeCopy( this.nodeProperty.value );
    this.nodeProperty.dispose();
    Node.prototype.dispose.call( this );
  }
} );

export default MutableOptionsNode;<|endoftext|>


<commit_before>//  Copyright 2002-2014, University of Colorado Boulder

/**
 * Indicates a user's progress on a level by illuminating stars.
 *
 * @author John Blanco
 */
define( function( require ) {
  'use strict';

  // modules
  var HalfStar = require( 'VEGAS/HalfStar' );
  var inherit = require( 'PHET_CORE/inherit' );
  var Node = require( 'SCENERY/nodes/Node' );
  var StarNode = require( 'SCENERY_PHET/StarNode' );
  var HBox = require( 'SCENERY/nodes/HBox' );

  /**
   * @param {number} numStars
   * @param {number} starDiameter
   * @param {Property<Number>} scoreProperty
   * @param {number} perfectScore
   * @constructor
   */
  function ProgressIndicator2( numStars, starDiameter, scoreProperty, perfectScore, options ) {

    options = _.extend( {
    }, options );

    HBox.call( this, {spacing: 3, children: []} );
    var progressIndicator2 = this;

    // Update visibility of filled and half-filled stars based on score.
    // TODO: Could be rewritten to use deltas if it needs to animate
    scoreProperty.link( function( score ) {
      var children = [];

      var proportion = score / perfectScore;
      var numFilledStars = Math.floor( proportion * numStars );

      var options = {outerRadius: 10, innerRadius: 5, filledLineWidth: 1.5, emptyLineWidth: 1.5};

      for ( var i = 0; i < numFilledStars; i++ ) {
        children.push( new StarNode( _.extend( {value: 1}, options ) ) );
      }
      var remainder = proportion * numStars - numFilledStars;
      if ( remainder > 1E-6 ) {
        children.push( new StarNode( _.extend( {value: remainder}, options ) ) );
      }
      var numEmptyStars = numStars - children.length;
      for ( i = 0; i < numEmptyStars; i++ ) {
        children.push( new StarNode( _.extend( {value: 0}, options ) ) );
      }

      progressIndicator2.children = children;
    } );

    this.mutate( options );
  }

  return inherit( HBox, ProgressIndicator2 );
} );<commit_msg>moved options to the top<commit_after>//  Copyright 2002-2014, University of Colorado Boulder

/**
 * Indicates a user's progress on a level by illuminating stars.
 *
 * @author John Blanco
 */
define( function( require ) {
  'use strict';

  // modules
  var HalfStar = require( 'VEGAS/HalfStar' );
  var inherit = require( 'PHET_CORE/inherit' );
  var Node = require( 'SCENERY/nodes/Node' );
  var StarNode = require( 'SCENERY_PHET/StarNode' );
  var HBox = require( 'SCENERY/nodes/HBox' );

  /**
   * @param {number} numStars
   * @param {number} starDiameter
   * @param {Property<Number>} scoreProperty
   * @param {number} perfectScore
   * @constructor
   */
  function ProgressIndicator2( numStars, starDiameter, scoreProperty, perfectScore, options ) {

    options = _.extend( {
      outerRadius: 10,
      innerRadius: 5,
      filledLineWidth: 1.5,
      emptyLineWidth: 1.5
    }, options );

    HBox.call( this, {spacing: 3, children: []} );
    var progressIndicator2 = this;

    // Update visibility of filled and half-filled stars based on score.
    // TODO: Could be rewritten to use deltas if it needs to animate
    scoreProperty.link( function( score ) {
      var children = [];

      var proportion = score / perfectScore;
      var numFilledStars = Math.floor( proportion * numStars );

      for ( var i = 0; i < numFilledStars; i++ ) {
        children.push( new StarNode( _.extend( {value: 1}, options ) ) );
      }
      var remainder = proportion * numStars - numFilledStars;
      if ( remainder > 1E-6 ) {
        children.push( new StarNode( _.extend( {value: remainder}, options ) ) );
      }
      var numEmptyStars = numStars - children.length;
      for ( i = 0; i < numEmptyStars; i++ ) {
        children.push( new StarNode( _.extend( {value: 0}, options ) ) );
      }

      progressIndicator2.children = children;
    } );

    this.mutate( options );
  }

  return inherit( HBox, ProgressIndicator2 );
} );<|endoftext|>


<commit_before>function pageViewModel(gvm) {
    // Page specific i18n bindings
    gvm.title = ko.computed(function(){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("AdminPage");}, gvm);
    gvm.pageHeaderEditUser = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("UserEditTitle");}, gvm);

    gvm.edituserid = $("#usereditHeader").data('value');

    gvm.userName = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("UserName");}, gvm);
    gvm.firstName = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("Firstname");}, gvm);
    gvm.lastName = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("Lastname");}, gvm);
    gvm.userStatus = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("UserStatus");}, gvm);

    gvm.permissionRole = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("PermissionRole");}, gvm);
    gvm.permissionDescription = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("PermissionDescription");}, gvm);

    getAllUserDataById(gvm.edituserid);

    gvm.rights = ko.observableArray([]);
    gvm.user = ko.observableArray([]);

    gvm.updateUser = function(user)
    {
        gvm.user.push(user);
    },

    gvm.updatePermissions = function(permission)
    {
        gvm.rights.push(permission);
    },

    gvm.removeUser = function(user) {
        gvm.user.remove(user);
        removeUser(user);
    },

    gvm.clearStructure = function() {
        gvm.rights.destroyAll();
        gvm.user.destroyAll();
    }
}

function initPage() {

}

function getAllUserDataById(edituserid){
    console.log("Get data from user " + edituserid);

    $.getJSON("/api/edituser/" + edituserid, function(data)
    {
        console.log(data);
        var addedUsername = "";
        $.each(data, function(i, item){
            console.log(i + " " + item);
            console.log(item.username);

            var current = item.username;
            $.each(data, function(i, itemdata)
            {
                if(item.username == current){
                    console.log(itemdata.roleid + " " + itemdata.role );
                    viewModel.updatePermissions(new Permission(itemdata.roleid, itemdata.role))
                }
            });

            if (addedUsername != current){
                addedUsername = item.username
                console.log(addedUsername);
                viewModel.updateUser(new User(item.userid, item.username, item.firstname, item.lastname, viewModel.rights()));
            }
        });
    });
}

function Permission(id, permissions) {
    return {
        id: ko.observable(id),
        permissions: ko.observable(permissions)
    };
}

function User(id, username, firstname, lastname, status) {
    return {
        id: ko.observable(id),
        username: ko.observable(username),
        firstname: ko.observable(firstname),
        lastname: ko.observable(lastname),
        status: ko.observable(status),

        removeThisUser: function() {
            if(confirm('Are you sure you want to remove this user?'))
            {
                viewModel.removeUser(this);
            }
        },

        changeStatus: function() {
            if (this.status() == "ACTIVE"){
                this.status("DISABLED");
            } else if (this.status() == "DISABLED") {
                this.status("ACTIVE");
            } else {
                this.status("WAIT_ACTIVATION");
            }
            updateUserStatus(this);
        }
    };
}<commit_msg>Admin edit user<commit_after>function pageViewModel(gvm) {
    // Page specific i18n bindings
    gvm.title = ko.computed(function(){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("AdminPage");}, gvm);
    gvm.pageHeaderEditUser = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("UserEditTitle");}, gvm);

    gvm.edituserid = $("#usereditHeader").data('value');

    gvm.userName = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("UserName");}, gvm);
    gvm.firstName = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("Firstname");}, gvm);
    gvm.lastName = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("Lastname");}, gvm);
    gvm.userStatus = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("UserStatus");}, gvm);

    gvm.permissionRole = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("PermissionRole");}, gvm);
    gvm.permissionDescription = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("PermissionDescription");}, gvm);

    getAllUserDataById(gvm.edituserid);

    gvm.rights = ko.observableArray([]);
    gvm.user = ko.observableArray([]);

    gvm.updateUser = function(user)
    {
        gvm.user.push(user);
    },

    gvm.updatePermissions = function(permission)
    {
        gvm.rights.push(permission);
    },

    gvm.removeUser = function(user) {
        gvm.user.remove(user);
        removeUser(user);
    },

    gvm.clearStructure = function() {
        gvm.rights.destroyAll();
        gvm.user.destroyAll();
    }
}

function initPage() {

}

function getAllUserDataById(edituserid){
    console.log("Get data from user " + edituserid);

    $.getJSON("/api/edituser/" + edituserid, function(data)
    {
        console.log(data);
        var addedUsername = "";
        $.each(data, function(item, i){
            console.log(item.username);

            var current = item.username;
            $.each(data, function(i, itemdata)
            {
                if(item.username == current){
                    console.log(itemdata.roleid + " " + itemdata.role );
                    viewModel.updatePermissions(new Permission(itemdata.roleid, itemdata.role))
                }
            });

            if (addedUsername != current){
                addedUsername = item.username
                console.log(addedUsername);
                viewModel.updateUser(new User(item.userid, item.username, item.firstname, item.lastname, viewModel.rights()));
            }
        });
    });
}

function Permission(id, permissions) {
    return {
        id: ko.observable(id),
        permissions: ko.observable(permissions)
    };
}

function User(id, username, firstname, lastname, status) {
    return {
        id: ko.observable(id),
        username: ko.observable(username),
        firstname: ko.observable(firstname),
        lastname: ko.observable(lastname),
        status: ko.observable(status),

        removeThisUser: function() {
            if(confirm('Are you sure you want to remove this user?'))
            {
                viewModel.removeUser(this);
            }
        },

        changeStatus: function() {
            if (this.status() == "ACTIVE"){
                this.status("DISABLED");
            } else if (this.status() == "DISABLED") {
                this.status("ACTIVE");
            } else {
                this.status("WAIT_ACTIVATION");
            }
            updateUserStatus(this);
        }
    };
}<|endoftext|>


<commit_before>/* eslint-disable max-classes-per-file */

'use strict';

// ----------------------------------------------------------------------------
//
// Upto 10x faster after initializing memory for the floating point array
// Author: github.com/frosty00
// Email: carlo.revelli@berkeley.edu
//

function bisectLeft(array, x) {
    let low = 0
    let high = array.length - 1
    while (low <= high) {
        const mid = (low + high) >>> 1;
        if (array[mid] - x < 0) low = mid + 1;
        else high = mid - 1;
    }
    return low;
}

const SIZE = 1024
const SEED = new Float64Array (new Array (SIZE).fill (Number.MAX_VALUE))

class OrderBookSide extends Array {
    constructor (deltas = [], depth = undefined) {
        super ()
        // a string-keyed dictionary of price levels / ids / indices
        Object.defineProperty (this, 'index', {
            __proto__: null, // make it invisible
            value: new Float64Array (SEED),
            writable: true,
        })
        Object.defineProperty (this, 'depth', {
            __proto__: null, // make it invisible
            value: depth || Number.MAX_SAFE_INTEGER,
            writable: true,
        })
        Object.defineProperty (this, 'hidden', {
            __proto__: null, // make it invisible
            value: new Map (),
            writable: true,
        })
        // sort upon initiation
        this.length = 0
        for (let i = 0; i < deltas.length; i++) {
            this.storeArray (deltas[i].slice ())  // slice is muy importante
        }
    }

    storeArray (delta) {
        const price = delta[0]
        const size = delta[1]
        const index_price = this.side ? -price : price
        const index = bisectLeft (this.index, index_price)
        if (size) {
            if (index < this.length && this.index[index] == index_price) {
                this[index][1] = size
            } else {
                this.length++
                this.index.copyWithin (index + 1, index, this.length)
                this.index[index] = index_price
                const innerIndex = this.side ? this.length - index - 1: index;
                this.copyWithin (index + 1, index, this.length)
                this[index] = delta
                // in the rare case of very large orderbooks being sent
                if (this.length > this.index.length - 1) {
                    const existing = Array.from (this.index)
                    existing.length = this.length * 2
                    existing.fill (Number.MAX_VALUE, this.index.length)
                    this.index = new Float64Array (existing)
                }
            }
        } else if (this.index[index] == index_price) {
            this.index.copyWithin (index, index + 1, this.length)
            this.index[this.length - 1] = Number.MAX_VALUE
            this.copyWithin (index, index + 1, this.length)
            this.length--
        }
    }

    // index an incoming delta in the string-price-keyed dictionary
    store (price, size) {
        this.storeArray ([ price, size ])
    }

    // replace stored orders with new values
    limit (n = undefined) {
        if (n === undefined) {
            if (this.hidden.size) {
                const end = this.length + this.hidden.size
                for (let i = this.length; i < end; i++) {
                    this.push (this.hidden.get (this.index[i]))
                }
                this.hidden.clear ()
            }
        } else {
            if (n < this.length) {
                // we store some hidden stuff for when the book is temporarily limited to the user
                for (let i = n; i < this.length; i++) {
                    this.hidden.set (this.index[i], this[i])
                }
                this.length = n
            }
            this.length = Math.min (n, this.length)
        }
        if (this.length > this.depth) {
            for (let i = this.depth; i < this.length; i++) {
                this.index[i] = Number.MAX_VALUE
            }
            this.length = this.depth
        }
    }
}

// ----------------------------------------------------------------------------
// overwrites absolute volumes at price levels
// or deletes price levels based on order counts (3rd value in a bidask delta)
// this class stores vector arrays of values indexed by price

class CountedOrderBookSide extends OrderBookSide {
    store (price, size, count) {
        this.storeArray ([ price, size, count ])
    }

    storeArray (delta) {
        const price = delta[0]
        const size = delta[1]
        const count = delta[2]
        const index_price = this.side ? -price : price
        const index = bisectLeft (this.index, index_price)
        if (size && count) {
            if (index < this.length && this.index[index] == index_price) {
                this[index][1] = size
                this[index][2] = count
            } else {
                this.length++
                this.index.copyWithin (index + 1, index, this.length)
                this.index[index] = index_price
                const innerIndex = this.side ? this.length - index - 1: index;
                this.copyWithin (index + 1, index, this.length)
                this[index] = delta
            }
        } else if (this.index[index] == index_price) {
            this.index.copyWithin (index, index + 1, this.length)
            this.index[this.length - 1] = Number.MAX_VALUE
            this.copyWithin (index, index + 1, this.length)
            this.length--
        }
    }
}

// ----------------------------------------------------------------------------
// stores vector arrays indexed by id (3rd value in a bidask delta array)

class IndexedOrderBookSide extends Array  {
    constructor (deltas = [], depth = Number.MAX_SAFE_INTEGER) {
        super (deltas.length)
        // a string-keyed dictionary of price levels / ids / indices
        Object.defineProperty (this, 'hashmap', {
            __proto__: null, // make it invisible
            value: new Map (),
            writable: true,
        })
        Object.defineProperty (this, 'index', {
            __proto__: null, // make it invisible
            value: new Float64Array (SEED),
            writable: true,
        })
        Object.defineProperty (this, 'depth', {
            __proto__: null, // make it invisible
            value: depth || Number.MAX_SAFE_INTEGER,
            writable: true,
        })
        Object.defineProperty (this, 'hidden', {
            __proto__: null, // make it invisible
            value: new Map (),
            writable: true,
        })
        // sort upon initiation
        for (let i = 0; i < deltas.length; i++) {
            this.length = i
            this.storeArray (deltas[i].slice ())  // slice is muy importante
        }
    }

    store (price, size, id) {
        this.storeArray([ price, size, id ])
    }

    storeArray (delta) {
        const price = delta[0]
        const size = delta[1]
        const id = delta[2]
        let index_price
        if (price !== undefined) {
            index_price = this.side ? -price : price
        } else {
            index_price = undefined
        }
        if (size) {
            if (this.hashmap.has (id)) {
                const old_price = this.hashmap.get (id)
                index_price = index_price || old_price
                // in case price is not sent
                delta[0] = Math.abs (index_price)
                if (index_price === old_price) {
                    const index = bisectLeft (this.index, index_price)
                    this.index[index] = index_price
                    this[index] = delta
                    return
                } else {
                    // remove old price from index
                    const old_index = bisectLeft (this.index, old_price)
                    this.index.copyWithin (old_index, old_index + 1, this.length)
                    this.index[this.length - 1] = Number.MAX_VALUE
                    this.copyWithin (old_index, old_index + 1, this.length)
                    this.length--
                }
            }
            // insert new price level
            this.hashmap.set (id, index_price)
            const index = bisectLeft (this.index, index_price)
            // insert new price level into index
            this.length++
            this.index.copyWithin (index + 1, index, this.length)
            this.index[index] = index_price
            const innerIndex = this.side ? this.length - index - 1: index;
            this.copyWithin (index + 1, index, this.length)
            this[index] = delta
            // in the rare case of very large orderbooks being sent
            if (this.length > this.index.length - 1) {
                const existing = Array.from (this.index)
                existing.length = this.length * 2
                existing.fill (Number.MAX_VALUE, this.index.length)
                this.index = new Float64Array (existing)
            }
        } else if (this.hashmap.has (id)) {
            const old_price = this.hashmap.get (id)
            const index = bisectLeft (this.index, old_price)
            this.index.copyWithin (index, index + 1, this.length)
            this.index[this.length - 1] = Number.MAX_VALUE
            this.copyWithin (index, index + 1, this.length)
            this.hashmap.delete (id)
            this.length--
        }
    }

    // replace stored orders with new values
    limit (n = undefined) {
        if (n === undefined) {
            if (this.hidden.size) {
                const end = this.length + this.hidden.size
                for (let i = this.length; i < end; i++) {
                    this.push (this.hidden.get (this.index[i]))
                }
                this.hidden.clear ()
            }
        } else {
            if (n < this.length) {
                // we store some hidden stuff for when the book is temporarily limited to the user
                for (let i = n; i < this.length; i++) {
                    this.hidden.set (this.index[i], this[i])
                }
                this.length = n
            }
            this.length = Math.min (n, this.length)
        }
        if (this.length > this.depth) {
            for (let i = this.depth; i < this.length; i++) {
                // only difference from OrderBookSide.limit
                this.hashmap.delete (this.index[i])
                // end diff
                this.index[i] = Number.MAX_VALUE
            }
            this.length = this.depth
        }
    }
}

// ----------------------------------------------------------------------------
// a more elegant syntax is possible here, but native inheritance is portable

class Asks extends OrderBookSide { get side () { return false }}
class Bids extends OrderBookSide { get side () { return true }}
class CountedAsks extends CountedOrderBookSide { get side () { return false }}
class CountedBids extends CountedOrderBookSide { get side () { return true }}
class IndexedAsks extends IndexedOrderBookSide { get side () { return false }}
class IndexedBids extends IndexedOrderBookSide { get side () { return true }}

// ----------------------------------------------------------------------------

module.exports = {

    // basic
    Asks,
    Bids,
    OrderBookSide,

    // count-based
    CountedAsks,
    CountedBids,
    CountedOrderBookSide,

    // order-id based
    IndexedAsks,
    IndexedBids,
    IndexedOrderBookSide,

}
<commit_msg>minor-book-edit<commit_after>/* eslint-disable max-classes-per-file */

'use strict';

// ----------------------------------------------------------------------------
//
// Upto 10x faster after initializing memory for the floating point array
// Author: github.com/frosty00
// Email: carlo.revelli@berkeley.edu
//

function bisectLeft(array, x) {
    let low = 0
    let high = array.length - 1
    while (low <= high) {
        const mid = (low + high) >>> 1;
        if (array[mid] - x < 0) low = mid + 1;
        else high = mid - 1;
    }
    return low;
}

const SIZE = 1024
const SEED = new Float64Array (new Array (SIZE).fill (Number.MAX_VALUE))

class OrderBookSide extends Array {
    constructor (deltas = [], depth = undefined) {
        super ()
        // a string-keyed dictionary of price levels / ids / indices
        Object.defineProperty (this, 'index', {
            __proto__: null, // make it invisible
            value: new Float64Array (SEED),
            writable: true,
        })
        Object.defineProperty (this, 'depth', {
            __proto__: null, // make it invisible
            value: depth || Number.MAX_SAFE_INTEGER,
            writable: true,
        })
        Object.defineProperty (this, 'hidden', {
            __proto__: null, // make it invisible
            value: new Map (),
            writable: true,
        })
        // sort upon initiation
        this.length = 0
        for (let i = 0; i < deltas.length; i++) {
            this.storeArray (deltas[i].slice ())  // slice is muy importante
        }
    }

    storeArray (delta) {
        const price = delta[0]
        const size = delta[1]
        const index_price = this.side ? -price : price
        const index = bisectLeft (this.index, index_price)
        if (size) {
            if (index < this.length && this.index[index] == index_price) {
                this[index][1] = size
            } else {
                this.length++
                this.index.copyWithin (index + 1, index, this.length)
                this.index[index] = index_price
                const innerIndex = this.side ? this.length - index - 1: index;
                this.copyWithin (index + 1, index, this.length)
                this[index] = delta
                // in the rare case of very large orderbooks being sent
                if (this.length > this.index.length - 1) {
                    const existing = Array.from (this.index)
                    existing.length = this.length * 2
                    existing.fill (Number.MAX_VALUE, this.index.length)
                    this.index = new Float64Array (existing)
                }
            }
        } else if (this.index[index] == index_price) {
            this.index.copyWithin (index, index + 1, this.length)
            this.index[this.length - 1] = Number.MAX_VALUE
            this.copyWithin (index, index + 1, this.length)
            this.length--
        }
    }

    // index an incoming delta in the string-price-keyed dictionary
    store (price, size) {
        this.storeArray ([ price, size ])
    }

    // replace stored orders with new values
    limit (n = undefined) {
        if (n === undefined) {
            if (this.hidden.size) {
                const end = this.length + this.hidden.size
                for (let i = this.length; i < end; i++) {
                    this.push (this.hidden.get (this.index[i]))
                }
                this.hidden.clear ()
            }
        } else {
            if (n < this.length) {
                // we store some hidden stuff for when the book is temporarily limited to the user
                for (let i = n; i < this.length; i++) {
                    this.hidden.set (this.index[i], this[i])
                }
                this.length = n
            }
            this.length = Math.min (n, this.length)
        }
        if (this.length > this.depth) {
            for (let i = this.depth; i < this.length; i++) {
                this.index[i] = Number.MAX_VALUE
            }
            this.length = this.depth
        }
    }
}

// ----------------------------------------------------------------------------
// overwrites absolute volumes at price levels
// or deletes price levels based on order counts (3rd value in a bidask delta)
// this class stores vector arrays of values indexed by price

class CountedOrderBookSide extends OrderBookSide {
    store (price, size, count) {
        this.storeArray ([ price, size, count ])
    }

    storeArray (delta) {
        const price = delta[0]
        const size = delta[1]
        const count = delta[2]
        const index_price = this.side ? -price : price
        const index = bisectLeft (this.index, index_price)
        if (size && count) {
            if (index < this.length && this.index[index] == index_price) {
                this[index][1] = size
                this[index][2] = count
            } else {
                this.length++
                this.index.copyWithin (index + 1, index, this.length)
                this.index[index] = index_price
                const innerIndex = this.side ? this.length - index - 1: index;
                this.copyWithin (index + 1, index, this.length)
                this[index] = delta
                // in the rare case of very large orderbooks being sent
                if (this.length > this.index.length - 1) {
                    const existing = Array.from (this.index)
                    existing.length = this.length * 2
                    existing.fill (Number.MAX_VALUE, this.index.length)
                    this.index = new Float64Array (existing)
                }
            }
        } else if (this.index[index] == index_price) {
            this.index.copyWithin (index, index + 1, this.length)
            this.index[this.length - 1] = Number.MAX_VALUE
            this.copyWithin (index, index + 1, this.length)
            this.length--
        }
    }
}

// ----------------------------------------------------------------------------
// stores vector arrays indexed by id (3rd value in a bidask delta array)

class IndexedOrderBookSide extends Array  {
    constructor (deltas = [], depth = Number.MAX_SAFE_INTEGER) {
        super (deltas.length)
        // a string-keyed dictionary of price levels / ids / indices
        Object.defineProperty (this, 'hashmap', {
            __proto__: null, // make it invisible
            value: new Map (),
            writable: true,
        })
        Object.defineProperty (this, 'index', {
            __proto__: null, // make it invisible
            value: new Float64Array (SEED),
            writable: true,
        })
        Object.defineProperty (this, 'depth', {
            __proto__: null, // make it invisible
            value: depth || Number.MAX_SAFE_INTEGER,
            writable: true,
        })
        Object.defineProperty (this, 'hidden', {
            __proto__: null, // make it invisible
            value: new Map (),
            writable: true,
        })
        // sort upon initiation
        for (let i = 0; i < deltas.length; i++) {
            this.length = i
            this.storeArray (deltas[i].slice ())  // slice is muy importante
        }
    }

    store (price, size, id) {
        this.storeArray([ price, size, id ])
    }

    storeArray (delta) {
        const price = delta[0]
        const size = delta[1]
        const id = delta[2]
        let index_price
        if (price !== undefined) {
            index_price = this.side ? -price : price
        } else {
            index_price = undefined
        }
        if (size) {
            if (this.hashmap.has (id)) {
                const old_price = this.hashmap.get (id)
                index_price = index_price || old_price
                // in case price is not sent
                delta[0] = Math.abs (index_price)
                if (index_price === old_price) {
                    const index = bisectLeft (this.index, index_price)
                    this.index[index] = index_price
                    this[index] = delta
                    return
                } else {
                    // remove old price from index
                    const old_index = bisectLeft (this.index, old_price)
                    this.index.copyWithin (old_index, old_index + 1, this.length)
                    this.index[this.length - 1] = Number.MAX_VALUE
                    this.copyWithin (old_index, old_index + 1, this.length)
                    this.length--
                }
            }
            // insert new price level
            this.hashmap.set (id, index_price)
            const index = bisectLeft (this.index, index_price)
            // insert new price level into index
            this.length++
            this.index.copyWithin (index + 1, index, this.length)
            this.index[index] = index_price
            const innerIndex = this.side ? this.length - index - 1: index;
            this.copyWithin (index + 1, index, this.length)
            this[index] = delta
            // in the rare case of very large orderbooks being sent
            if (this.length > this.index.length - 1) {
                const existing = Array.from (this.index)
                existing.length = this.length * 2
                existing.fill (Number.MAX_VALUE, this.index.length)
                this.index = new Float64Array (existing)
            }
        } else if (this.hashmap.has (id)) {
            const old_price = this.hashmap.get (id)
            const index = bisectLeft (this.index, old_price)
            this.index.copyWithin (index, index + 1, this.length)
            this.index[this.length - 1] = Number.MAX_VALUE
            this.copyWithin (index, index + 1, this.length)
            this.hashmap.delete (id)
            this.length--
        }
    }

    // replace stored orders with new values
    limit (n = undefined) {
        if (n === undefined) {
            if (this.hidden.size) {
                const end = this.length + this.hidden.size
                for (let i = this.length; i < end; i++) {
                    this.push (this.hidden.get (this.index[i]))
                }
                this.hidden.clear ()
            }
        } else {
            if (n < this.length) {
                // we store some hidden stuff for when the book is temporarily limited to the user
                for (let i = n; i < this.length; i++) {
                    this.hidden.set (this.index[i], this[i])
                }
                this.length = n
            }
            this.length = Math.min (n, this.length)
        }
        if (this.length > this.depth) {
            for (let i = this.depth; i < this.length; i++) {
                // only difference from OrderBookSide.limit
                this.hashmap.delete (this.index[i])
                // end diff
                this.index[i] = Number.MAX_VALUE
            }
            this.length = this.depth
        }
    }
}

// ----------------------------------------------------------------------------
// a more elegant syntax is possible here, but native inheritance is portable

class Asks extends OrderBookSide { get side () { return false }}
class Bids extends OrderBookSide { get side () { return true }}
class CountedAsks extends CountedOrderBookSide { get side () { return false }}
class CountedBids extends CountedOrderBookSide { get side () { return true }}
class IndexedAsks extends IndexedOrderBookSide { get side () { return false }}
class IndexedBids extends IndexedOrderBookSide { get side () { return true }}

// ----------------------------------------------------------------------------

module.exports = {

    // basic
    Asks,
    Bids,
    OrderBookSide,

    // count-based
    CountedAsks,
    CountedBids,
    CountedOrderBookSide,

    // order-id based
    IndexedAsks,
    IndexedBids,
    IndexedOrderBookSide,

}
<|endoftext|>


<commit_before>/* ============================================================
 * bootstrap-dropdown.js v2.2.2
 * http://twitter.github.com/bootstrap/javascript.html#dropdowns
 * ============================================================
 * Copyright 2012 Twitter, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ============================================================ */

!function ($) {

  "use strict"; // jshint ;_;

 /* DROPDOWN CLASS DEFINITION
  * ========================= */

  var toggle = '[data-foundry-toggle=dropdown]'
    , Dropdown = function (element) {
        var $el = $(element).on('click._dropdown.data-foundry-api', this.toggle)
        $('html').on('click._dropdown.data-foundry-api', function () {
          $el.parent().removeClass('open')
        })
      }

  Dropdown.prototype = {

    constructor: Dropdown

  , toggle: function (e) {
      var $this = $(this)
        , $parent
        , isActive

      if ($this.is('.disabled, :disabled')) return

      $parent = getParent($this)

      isActive = $parent.hasClass('open')

      clearMenus()

      if (!isActive) {
        $parent.toggleClass('open')
        $this.focus()
      }

      return false
    }

  , keydown: function (e) {
      var $this
        , $items
        , $active
        , $parent
        , isActive
        , index

      if (!/(38|40|27)/.test(e.keyCode)) return

      $this = $(this)

      e.preventDefault()
      e.stopPropagation()

      if ($this.is('.disabled, :disabled')) return

      $parent = getParent($this)

      isActive = $parent.hasClass('open')

      if (!isActive || (isActive && e.keyCode == 27)) return $this.click()

      $items = $('[role=menu] li:not(.divider) a', $parent)

      if (!$items.length) return

      index = $items.index($items.filter(':focus'))

      if (e.keyCode == 38 && index > 0) index--                                        // up
      if (e.keyCode == 40 && index < $items.length - 1) index++                        // down
      if (!~index) index = 0

      $items
        .eq(index)
        .focus()
    }

  }

  function clearMenus() {
    $(toggle).each(function () {
      getParent($(this)).removeClass('open')
    })
  }

  function getParent($this) {
    var selector = $this.attr('data-target')
      , $parent

    if (!selector) {
      selector = $this.attr('href')
      selector = selector && /#/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
    }

    $parent = $(selector)
    $parent.length || ($parent = $this.parent())

    return $parent
  }

  /* DROPDOWN PLUGIN DEFINITION
   * ========================== */

  $.fn.dropdown = function (option) {
    return this.each(function () {
      var $this = $(this)
        , data = $this.data('dropdown')
      if (!data) $this.data('dropdown', (data = new Dropdown(this)))
      if (typeof option == 'string') data[option].call($this)
    })
  }

  $.fn.dropdown.Constructor = Dropdown

  /* APPLY TO STANDARD DROPDOWN ELEMENTS
   * =================================== */

  $(document)
    .on('click._dropdown.data-foundry-api touchstart._dropdown.data-foundry-api', clearMenus)
    .on('click._dropdown touchstart._dropdown.data-foundry-api', '._dropdown form', function (e) { e.stopPropagation() })
    .on('click._dropdown.data-foundry-api touchstart._dropdown.data-foundry-api'  , toggle, Dropdown.prototype.toggle)
    .on('keydown._dropdown.data-foundry-api touchstart._dropdown.data-foundry-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown)

}($);
<commit_msg>Revert "Use click._dropdown instead of click.dropdown."<commit_after>/* ============================================================
 * bootstrap-dropdown.js v2.2.2
 * http://twitter.github.com/bootstrap/javascript.html#dropdowns
 * ============================================================
 * Copyright 2012 Twitter, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ============================================================ */

!function ($) {

  "use strict"; // jshint ;_;

 /* DROPDOWN CLASS DEFINITION
  * ========================= */

  var toggle = '[data-foundry-toggle=dropdown]'
    , Dropdown = function (element) {
        var $el = $(element).on('click.dropdown.data-foundry-api', this.toggle)
        $('html').on('click.dropdown.data-foundry-api', function () {
          $el.parent().removeClass('open')
        })
      }

  Dropdown.prototype = {

    constructor: Dropdown

  , toggle: function (e) {
      var $this = $(this)
        , $parent
        , isActive

      if ($this.is('.disabled, :disabled')) return

      $parent = getParent($this)

      isActive = $parent.hasClass('open')

      clearMenus()

      if (!isActive) {
        $parent.toggleClass('open')
        $this.focus()
      }

      return false
    }

  , keydown: function (e) {
      var $this
        , $items
        , $active
        , $parent
        , isActive
        , index

      if (!/(38|40|27)/.test(e.keyCode)) return

      $this = $(this)

      e.preventDefault()
      e.stopPropagation()

      if ($this.is('.disabled, :disabled')) return

      $parent = getParent($this)

      isActive = $parent.hasClass('open')

      if (!isActive || (isActive && e.keyCode == 27)) return $this.click()

      $items = $('[role=menu] li:not(.divider) a', $parent)

      if (!$items.length) return

      index = $items.index($items.filter(':focus'))

      if (e.keyCode == 38 && index > 0) index--                                        // up
      if (e.keyCode == 40 && index < $items.length - 1) index++                        // down
      if (!~index) index = 0

      $items
        .eq(index)
        .focus()
    }

  }

  function clearMenus() {
    $(toggle).each(function () {
      getParent($(this)).removeClass('open')
    })
  }

  function getParent($this) {
    var selector = $this.attr('data-target')
      , $parent

    if (!selector) {
      selector = $this.attr('href')
      selector = selector && /#/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
    }

    $parent = $(selector)
    $parent.length || ($parent = $this.parent())

    return $parent
  }

  /* DROPDOWN PLUGIN DEFINITION
   * ========================== */

  $.fn.dropdown = function (option) {
    return this.each(function () {
      var $this = $(this)
        , data = $this.data('dropdown')
      if (!data) $this.data('dropdown', (data = new Dropdown(this)))
      if (typeof option == 'string') data[option].call($this)
    })
  }

  $.fn.dropdown.Constructor = Dropdown

  /* APPLY TO STANDARD DROPDOWN ELEMENTS
   * =================================== */

  $(document)
    .on('click.dropdown.data-foundry-api touchstart.dropdown.data-foundry-api', clearMenus)
    .on('click.dropdown touchstart.dropdown.data-foundry-api', '.dropdown form', function (e) { e.stopPropagation() })
    .on('click.dropdown.data-foundry-api touchstart.dropdown.data-foundry-api'  , toggle, Dropdown.prototype.toggle)
    .on('keydown.dropdown.data-foundry-api touchstart.dropdown.data-foundry-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown)

}($);
<|endoftext|>