<commit_before>/*global
 define
 */
/*jslint
 browser: true,
 white: true
 */
define([
    'jquery',
    'kb.runtime',
    'kb.html',
    'q',
    'kb.session'],
    function ($, R, html, Q, Session) {
        'use strict';
        // ACTUALLY: a widget
        /*
         * Use the factory pattern.
         * This lets us create objects which don't use "this" and which use
         * natural closures for modularization rather than object construction
         * by way of Object.create()
         *
         */
        var factory = function () {
            var self = this;
            function setup() {
                return self;
            }
            function teardown() {
                // TODO: remove routes
                return false;
            }

            var isDirty = undefined;
            function dirty() {
                isDirty = true;
            }
            function clean() {
                isDirty = false;
            }

            var $mount = null;
            var $container = null;
            function attach(node) {
                return Q.Promise(function (resolve) {
                    if ($mount) {
                        throw new Error('Already attached');
                    }
                    $mount = $(node);
                    $container = $('

');
                    $mount.html($container);
                    var content = render();
                    $container.html(content);
                    attachEvents();
                    clean();
                    resolve();
                });
            }
            function reattach() {
                return Q.Promise(function (resolve) {
                    detach()
                        .then(function () {
                            return stop();
                        })
                        .then(function () {
                            $container = $('

');
                            $mount.empty().append($container);
                            var content = render();
                            $container.html(content);
                            attachEvents();
                            clean();
                        })
                        .then(function () {
                            return start();
                        })
                        .done();
                });
            }
            function detach() {
                return Q.Promise(function (resolve) {
                    detachEvents();
                    // $mount.empty();
                    $container.remove();
                    $container = null;
                    resolve();
                });
            }

            var subscriptions = [];
            var subscriptions2 = [];
            function start() {
                return Q.Promise(function (resolve) {
                    subscribeAll();
                    resolve();
                });
                /*

                 R.whenItem('userprofile')
                 .then(function (profile) {
                 attach($container).done();
                 })
                 .done();
                 */
            }
            function subscribeAll() {
                unsubscribeAll();
                subscriptions2.push(R.recv('app', 'loggedout', function () {
                    // all we care about is the avatar menu
                    // this will be automatically re-rendered if we set the dirty
                    // flag.
                    dirty();
                }));
                subscriptions2.push(R.recv('app', 'loggedin', function () {
                    // all we care about is the avatar menu
                    dirty();
                }));
                subscriptions2.push(R.recv('app', 'profile.loaded', function () {
                    // all we care about is the avatar menu
                    dirty();
                }));

                subscriptions2.push(R.recv('app', 'title', function (title) {
                    setTitle(title);
                }));
                subscriptions2.push(R.recv('navbar', 'clearButtons', function () {
                    clearButtons();
                }));
                subscriptions2.push(R.recv('navbar', 'addButton', function (data) {
                    addButton(data);
                }));
                subscriptions2.push(R.recv('navbar', 'enableButton', function (data) {
                    var button = buttonMap[data.id];
                    if (button) {
                        button.disabled = false;
                    }
                    dirty();
                }));
                /*
                subscriptions.push(R.sub('refresh', function () {
                    if (isDirty) {
                        console.log('yo, dirty, trying to reattach....');
                        console.log($container);
                        reattach()
                            .catch(function (err) {
                                console.log('ERROR');
                                console.log(err);
                            })
                            .done();
                    }
                }));
                */

                subscriptions2.push(R.recv('app', 'heartbeat', function (data) {
                    if (isDirty) {
                        reattach()
                            .catch(function (err) {
                                console.log('ERROR');
                                console.log(err);
                            })
                            .done();
                    }
                }));
            }
            function unsubscribeAll() {
                subscriptions.forEach(function (sub) {
                    R.unsub(sub);
                });
                subscriptions2.forEach(function (sub) {
                    R.drop(sub);
                });
            }
            function stop() {
                return Q.Promise(function (resolve) {
                    unsubscribeAll();
                    resolve();
                });
            }

            /*
             * These are the registered menu items. Any menu item must be registered
             * here.
             * Menu items may also be added using the defMenuItem method.
             * A menu item might be defined by a panel or widget when it is first loaded. In this case,
             */
            var menuItems = {
                divider: {
                    type: 'divider'
                }
            };
            function addMenuItem(id, menuDef) {
                menuItems[id] = menuDef;
            }

            var menu = [];
            function clearMenu() {
                menu = [];
            }

            /*
            function deleteMenuItem(id) {
                delete menu[id];
            }
            function insertMenuItem(id, beforeItem) {
            }
            */
            function setMenu(ids) {
                clearMenu();
                menu = ids.map(function (id) {
                    return id;
                });
            }

            //
            var title = '';
            function setTitle(newTitle) {
                title = newTitle;
                dirty();
            }

            // EVENTS
            // TODO; Move to separate module.
            var events = [];
            function addEvent(type, handler, id, data) {
                if (!id) {
                    id = html.genId();
                }
                events.push({
                    type: type,
                    selector: '#' + id,
                    handler: handler
                });
                dirty();
                return id;
            }
            function matches (element, selector) {
                var matches = ['matches', 'webkitMatchesSelector', 'msMatchesSelector', 'mozMatchesSelector', 'oMatchesSelector'],
                    matcher = _.find(matches, function (m) {return (m in element);});
                if (matcher) {
                    return element[matcher](selector);
                } else {
                    throw new Error('No mathches method found!');
                }
            }
            function attachEvents() {
                events.forEach(function (event) {
                    $container.on(event.type, event.selector, event.data, event.handler);
                    /*var fun = function (e) {
                        console.log('trying...');
                        console.log(e.target);
                        console.log(event.selector);
                        console.log(matches(e.target, event.selector));
                        if (matches(e.target, event.selector)) {
                            event.handler();
                        }
                    };
                    event.actualHandler = fun;
                    $container.get(0).addEventListener(event.type, fun);
                    */
                });
            }
            function detachEvents() {
                events.forEach(function (event) {
                    if (event.listener) {
                        $container.off(event.type, event.selector);
                        // $container.get(0).removeEventListener(event.type, event.actualHandler);
                    }
                });
            }

            function handleSignout(e) {
                Session.logout()
                    .then(function () {
                        R.send('app', 'loggedout');
                        R.send('app', 'navigate', 'welcome');
                    })
                    .catch(function (err) {
                        console.log('ERROR');
                        console.log(err);
                        alert('Error signing out (check console for details)');
                    })
                    .done();
            }

            // RENDERERS
            function renderMenuItem(item) {
                var li = html.tag('li'),
                    a = html.tag('a'),
                    div = html.tag('div'),
                    span = html.tag('span');
                var icon = null;
                if (item.icon) {
                    icon = div({class: 'navbar-icon'}, [
                        span({class: 'fa fa-' + item.icon})
                    ]);
                }
                var type = item.type || 'button';
                switch (type) {
                    case 'button':
                        if (item.uri) {
                            return li({}, a({href: item.uri}, [
                                icon,
                                item.label
                            ]));
                        } else if (item.path) {
                            return li({}, a({href: '#'+item.path}, [
                                icon,
                                item.label
                            ]));
                        }
                    case 'divider':
                        return li({role: 'presentation', class: 'divider'});
                }
            }

            var menus = {};
            function addMenu(id, items) {
                menus[id] = items;
            }
            function addToMenu(id, item) {
                menus[id].push(item);
                dirty();
            }

            function renderMenu() {
                var ul = html.tag('ul');
                if (R.isLoggedIn()) {
                    setMenu(menus['authenticated']);
                } else {
                    setMenu(menus['unauthenticated']);
                }
                return ul({class: 'dropdown-menu', role: 'menu', 'aria-labeledby': 'kb-nav-menu'}, menu.map(function (id) {
                    var item = menuItems[id];
                    if (!item) {
                        console.log('item ' + id + ' not defined');
                    } else {
                        return renderMenuItem(item);
                    }
                }));
            }
            function renderAvatar() {
                var img = html.tag('img', {close: false});
                var profile = R.getItem('userprofile');
                if (profile) {
                    return img({src: profile.getAvatarURL(), style: 'width: 40px;', class: 'login-button-avatar', 'data-element': 'avatar'});
                }
                return img({src: '/modules/navbar/images/nouserpic.png', style: 'width: 40px;', class: 'login-button-avatar', 'data-element': 'avatar'});
            }
            function renderLogin() {
                var button = html.tag('button'),
                    div = html.tag('div'),
                    a = html.tag('a'),
                    span = html.tag('span'),
                    ul = html.tag('ul'),
                    li = html.tag('li'),
                    br = html.tag('br', {close: false}),
                    i = html.tag('i');

                if (R.isLoggedIn()) {
                    /* TODO: fix dependencies like this -- realname is not available until, and unless, the
                      profile is loaded, which happens asynchronously.
                    */
                    var profile = R.getItem('userprofile');
                    var realname = profile ? profile.getProp('user.realname') : '?';
                    return div({class: 'dropdown', style: 'display:inline-block'}, [
                        button({type: 'button', class: 'btn btn-default dropdown-toggle', 'data-toggle': 'dropdown', 'aria-expanded': 'false'}, [
                            renderAvatar(),
                            span({class: 'caret', style: 'margin-left: 5px;'})
                        ]),
                        ul({class: 'dropdown-menu', role: 'menu'}, [
                            li({}, [
                                a({href: R.getConfig('ui.paths.spa_root') + 'people/' + R.getUsername(), 'data-menu-item': 'userlabel'}, [
                                    div({style: 'display:inline-block; width: 34px; vertical-align: top;'}, [
                                        span({class: 'fa fa-user', style: 'font-size: 150%; margin-right: 10px;'})
                                    ]),
                                    div({style: 'display: inline-block', 'data-element': 'user-label'}, [
                                        realname,
                                        br(),
                                        i({}, R.getUsername())
                                    ])
                                ])
                            ]),
                            li({class: 'divider'}),
                            li({}, [
                                a({href: '#', 'data-menu-item': 'logout', id: addEvent('click', handleSignout)}, [
                                    div({style: 'display: inline-block; width: 34px;'}, [
                                        span({class: 'fa fa-sign-out', style: 'font-size: 150%; margin-right: 10px;'})
                                    ]),
                                    'Sign Out'
                                ])
                            ])
                        ])
                    ]);
                }
                return a({type: 'button', class: 'btn btn-primary navbar-btn kb-nav-btn', 'data-button': 'signin', href: '#login'}, [
                    div({class: 'fa fa-sign-in  fa-inverse', style: 'margin-right: 5px;'}),
                    div({class: 'kb-nav-btn-txt'}, ['Sign In'])
                ]);
            }

            function render() {
                var div = html.tag('div'),
                    button = html.tag('button'),
                    span = html.tag('span'),
                    a = html.tag('a'),
                    img = html.tag('img', {close: false});
                var content = div({class: 'container-fluid'}, [
                    div({class: 'navbar-header navbar-menu'}, [
                        div({style: 'display: inline-block;', 'data-element': 'menu'}, [
                            button({id: 'kb-nav-menu',
                                class: 'btn btn-default navbar-btn kb-nav-btn',
                                'data-toggle': 'dropdown',
                                'aria-haspopup': 'true'}, [
                                span({class: 'fa fa-navicon'})
                            ]),
                            renderMenu()
                        ]),
                        a({href: 'http://kbase.us'}, [
                            img({id: 'logo', src: 'modules/navbar/images/kbase_logo.png', width: '46'})
                        ])
                    ]),
                    div({class: 'navbar-text navbar-title'}, [
                        span({class: 'title', 'data-element': 'title'}, [
                            title
                        ])
                    ]),
                    div({class: 'navbar-right'}, [
                        span({class: 'navbar-buttons', 'data-element': 'buttons'}, [
                            renderButtons()
                        ]),
                        span({id: 'signin-button', 'data-element': 'signin-button'}, [
                            renderLogin()
                        ])
                    ])
                ]);
                return content;
            }

            /* BUTTONS */
            var buttons = [];
            var buttonMap = {};
            function clearButtons() {
                if (!$container) {
                    return false
                }
                // $container.find('.navbar-buttons').empty();
                buttons = [];
                buttonMap = {};
                return true;
            }

            function addButton(cfg) {
                if (cfg.place === 'end') {
                    buttons.push(cfg);
                } else {
                    buttons.unshift(cfg);
                }
                buttonMap[cfg.name] = cfg;
                dirty();
                return true;
            }

            function renderButton(cfg) {
                var iconStyle = '';
                var label = '';

                var div = html.tag('div'),
                    a = html.tag('a'),
                    button = html.tag('button');

                if (cfg.label) {
                    label = div({class: 'kb-nav-btn-txt'}, cfg.label);
                } else {
                    iconStyle += 'font-size: 150%;';
                }

                var btn;
                var id = html.genId();
                var attribs = {
                    'data-button': cfg.name,
                    id: id,
                    class: 'btn btn-' + (cfg.style || 'default') + ' navbar-btn kb-nav-btn',
                    disabled: cfg.disabled ? true : false
                };
                var icon = div({
                    class: 'fa fa-' + cfg.icon,
                    style: iconStyle
                });
                if (cfg.url) {
                    // a link style button
                    attribs.role = 'button';
                    attribs.href = cfg.url;
                    if (cfg.target) {
                        attribs.target = cfg.target;
                    } else if (cfg.external) {
                        attribs.target = '_blank';
                    }
                    btn = a(attribs, [icon, label]);
                } else {
                    btn = button(attribs, [icon, label]);
                    addEvent('click', function (e) {
                        console.log('yes, here!');
                        //e.preventDefault();
                        console.log('yes, here2!');
                        cfg.callback();
                        return false;
                    }, id);
                }
                return btn;
            }

            function renderButtons() {
                return buttons.map(function (buttonDef) {
                    return renderButton(buttonDef);
                });
            }

            function findButton(name) {
                return $container.find('.navbar-buttons [data-button="' + name + '"]');
            }

            // All set up, set flags.
            dirty();

            /*
             * And this, dear friends, is the Navbar api.
             */
            return {
                // Standard panel/widget stuff
                setup: setup,
                teardown: teardown,
                attach: attach,
                detach: detach,
                start: start,
                stop: stop,
                // probably should remove after play time is over...
                render: render,
                // navbar api
                setTitle: setTitle,
                // addMenuItem: addMenuItem,
                clearButtons: clearButtons,
                addButton: addButton,

                addMenu: addMenu,
                addMenuItem: addMenuItem,

                addToMenu: addToMenu,

                    //addAppMenuItem: addAppMenuItem,
                    //removeAppMenuItem: removeAppMenuItem,
                    //addPanelMenuItem: addPanelMenuItem,
                    //removePanelMenuItem: removePanelMenuItem,
                    //clearMenu:
                    // On the other hand, panels and widgets don't need to muck with the menu,
                    // they can use buttons.
                    //clearButtons: clearButtons,
                    //addButton: addButton,
                    //addDropdown: addDropdown

            };
        };
        return {
            create: factory
        };
    });
<commit_msg>Updated signout option to redirect to login page.<commit_after>/*global
 define
 */
/*jslint
 browser: true,
 white: true
 */
define([
    'jquery',
    'kb.runtime',
    'kb.html',
    'q',
    'kb.session'],
    function ($, R, html, Q, Session) {
        'use strict';
        // ACTUALLY: a widget
        /*
         * Use the factory pattern.
         * This lets us create objects which don't use "this" and which use
         * natural closures for modularization rather than object construction
         * by way of Object.create()
         *
         */
        var factory = function () {
            var self = this;
            function setup() {
                return self;
            }
            function teardown() {
                // TODO: remove routes
                return false;
            }

            var isDirty = undefined;
            function dirty() {
                isDirty = true;
            }
            function clean() {
                isDirty = false;
            }

            var $mount = null;
            var $container = null;
            function attach(node) {
                return Q.Promise(function (resolve) {
                    if ($mount) {
                        throw new Error('Already attached');
                    }
                    $mount = $(node);
                    $container = $('

');
                    $mount.html($container);
                    var content = render();
                    $container.html(content);
                    attachEvents();
                    clean();
                    resolve();
                });
            }
            function reattach() {
                return Q.Promise(function (resolve) {
                    detach()
                        .then(function () {
                            return stop();
                        })
                        .then(function () {
                            $container = $('

');
                            $mount.empty().append($container);
                            var content = render();
                            $container.html(content);
                            attachEvents();
                            clean();
                        })
                        .then(function () {
                            return start();
                        })
                        .done();
                });
            }
            function detach() {
                return Q.Promise(function (resolve) {
                    detachEvents();
                    // $mount.empty();
                    $container.remove();
                    $container = null;
                    resolve();
                });
            }

            var subscriptions = [];
            var subscriptions2 = [];
            function start() {
                return Q.Promise(function (resolve) {
                    subscribeAll();
                    resolve();
                });
                /*

                 R.whenItem('userprofile')
                 .then(function (profile) {
                 attach($container).done();
                 })
                 .done();
                 */
            }
            function subscribeAll() {
                unsubscribeAll();
                subscriptions2.push(R.recv('app', 'loggedout', function () {
                    // all we care about is the avatar menu
                    // this will be automatically re-rendered if we set the dirty
                    // flag.
                    dirty();
                }));
                subscriptions2.push(R.recv('app', 'loggedin', function () {
                    // all we care about is the avatar menu
                    dirty();
                }));
                subscriptions2.push(R.recv('app', 'profile.loaded', function () {
                    // all we care about is the avatar menu
                    dirty();
                }));

                subscriptions2.push(R.recv('app', 'title', function (title) {
                    setTitle(title);
                }));
                subscriptions2.push(R.recv('navbar', 'clearButtons', function () {
                    clearButtons();
                }));
                subscriptions2.push(R.recv('navbar', 'addButton', function (data) {
                    addButton(data);
                }));
                subscriptions2.push(R.recv('navbar', 'enableButton', function (data) {
                    var button = buttonMap[data.id];
                    if (button) {
                        button.disabled = false;
                    }
                    dirty();
                }));
                /*
                subscriptions.push(R.sub('refresh', function () {
                    if (isDirty) {
                        console.log('yo, dirty, trying to reattach....');
                        console.log($container);
                        reattach()
                            .catch(function (err) {
                                console.log('ERROR');
                                console.log(err);
                            })
                            .done();
                    }
                }));
                */

                subscriptions2.push(R.recv('app', 'heartbeat', function (data) {
                    if (isDirty) {
                        reattach()
                            .catch(function (err) {
                                console.log('ERROR');
                                console.log(err);
                            })
                            .done();
                    }
                }));
            }
            function unsubscribeAll() {
                subscriptions.forEach(function (sub) {
                    R.unsub(sub);
                });
                subscriptions2.forEach(function (sub) {
                    R.drop(sub);
                });
            }
            function stop() {
                return Q.Promise(function (resolve) {
                    unsubscribeAll();
                    resolve();
                });
            }

            /*
             * These are the registered menu items. Any menu item must be registered
             * here.
             * Menu items may also be added using the defMenuItem method.
             * A menu item might be defined by a panel or widget when it is first loaded. In this case,
             */
            var menuItems = {
                divider: {
                    type: 'divider'
                }
            };
            function addMenuItem(id, menuDef) {
                menuItems[id] = menuDef;
            }

            var menu = [];
            function clearMenu() {
                menu = [];
            }

            /*
            function deleteMenuItem(id) {
                delete menu[id];
            }
            function insertMenuItem(id, beforeItem) {
            }
            */
            function setMenu(ids) {
                clearMenu();
                menu = ids.map(function (id) {
                    return id;
                });
            }

            //
            var title = '';
            function setTitle(newTitle) {
                title = newTitle;
                dirty();
            }

            // EVENTS
            // TODO; Move to separate module.
            var events = [];
            function addEvent(type, handler, id, data) {
                if (!id) {
                    id = html.genId();
                }
                events.push({
                    type: type,
                    selector: '#' + id,
                    handler: handler
                });
                dirty();
                return id;
            }
            function matches (element, selector) {
                var matches = ['matches', 'webkitMatchesSelector', 'msMatchesSelector', 'mozMatchesSelector', 'oMatchesSelector'],
                    matcher = _.find(matches, function (m) {return (m in element);});
                if (matcher) {
                    return element[matcher](selector);
                } else {
                    throw new Error('No mathches method found!');
                }
            }
            function attachEvents() {
                events.forEach(function (event) {
                    $container.on(event.type, event.selector, event.data, event.handler);
                    /*var fun = function (e) {
                        console.log('trying...');
                        console.log(e.target);
                        console.log(event.selector);
                        console.log(matches(e.target, event.selector));
                        if (matches(e.target, event.selector)) {
                            event.handler();
                        }
                    };
                    event.actualHandler = fun;
                    $container.get(0).addEventListener(event.type, fun);
                    */
                });
            }
            function detachEvents() {
                events.forEach(function (event) {
                    if (event.listener) {
                        $container.off(event.type, event.selector);
                        // $container.get(0).removeEventListener(event.type, event.actualHandler);
                    }
                });
            }

            function handleSignout(e) {
                Session.logout()
                    .then(function () {
                        R.send('app', 'loggedout');
                        R.send('app', 'navigate', 'login');
                    })
                    .catch(function (err) {
                        console.log('ERROR');
                        console.log(err);
                        alert('Error signing out (check console for details)');
                    })
                    .done();
            }

            // RENDERERS
            function renderMenuItem(item) {
                var li = html.tag('li'),
                    a = html.tag('a'),
                    div = html.tag('div'),
                    span = html.tag('span');
                var icon = null;
                if (item.icon) {
                    icon = div({class: 'navbar-icon'}, [
                        span({class: 'fa fa-' + item.icon})
                    ]);
                }
                var type = item.type || 'button';
                switch (type) {
                    case 'button':
                        if (item.uri) {
                            return li({}, a({href: item.uri}, [
                                icon,
                                item.label
                            ]));
                        } else if (item.path) {
                            return li({}, a({href: '#'+item.path}, [
                                icon,
                                item.label
                            ]));
                        }
                    case 'divider':
                        return li({role: 'presentation', class: 'divider'});
                }
            }

            var menus = {};
            function addMenu(id, items) {
                menus[id] = items;
            }
            function addToMenu(id, item) {
                menus[id].push(item);
                dirty();
            }

            function renderMenu() {
                var ul = html.tag('ul');
                if (R.isLoggedIn()) {
                    setMenu(menus['authenticated']);
                } else {
                    setMenu(menus['unauthenticated']);
                }
                return ul({class: 'dropdown-menu', role: 'menu', 'aria-labeledby': 'kb-nav-menu'}, menu.map(function (id) {
                    var item = menuItems[id];
                    if (!item) {
                        console.log('item ' + id + ' not defined');
                    } else {
                        return renderMenuItem(item);
                    }
                }));
            }
            function renderAvatar() {
                var img = html.tag('img', {close: false});
                var profile = R.getItem('userprofile');
                if (profile) {
                    return img({src: profile.getAvatarURL(), style: 'width: 40px;', class: 'login-button-avatar', 'data-element': 'avatar'});
                }
                return img({src: '/modules/navbar/images/nouserpic.png', style: 'width: 40px;', class: 'login-button-avatar', 'data-element': 'avatar'});
            }
            function renderLogin() {
                var button = html.tag('button'),
                    div = html.tag('div'),
                    a = html.tag('a'),
                    span = html.tag('span'),
                    ul = html.tag('ul'),
                    li = html.tag('li'),
                    br = html.tag('br', {close: false}),
                    i = html.tag('i');

                if (R.isLoggedIn()) {
                    /* TODO: fix dependencies like this -- realname is not available until, and unless, the
                      profile is loaded, which happens asynchronously.
                    */
                    var profile = R.getItem('userprofile');
                    var realname = profile ? profile.getProp('user.realname') : '?';
                    return div({class: 'dropdown', style: 'display:inline-block'}, [
                        button({type: 'button', class: 'btn btn-default dropdown-toggle', 'data-toggle': 'dropdown', 'aria-expanded': 'false'}, [
                            renderAvatar(),
                            span({class: 'caret', style: 'margin-left: 5px;'})
                        ]),
                        ul({class: 'dropdown-menu', role: 'menu'}, [
                            li({}, [
                                a({href: R.getConfig('ui.paths.spa_root') + 'people/' + R.getUsername(), 'data-menu-item': 'userlabel'}, [
                                    div({style: 'display:inline-block; width: 34px; vertical-align: top;'}, [
                                        span({class: 'fa fa-user', style: 'font-size: 150%; margin-right: 10px;'})
                                    ]),
                                    div({style: 'display: inline-block', 'data-element': 'user-label'}, [
                                        realname,
                                        br(),
                                        i({}, R.getUsername())
                                    ])
                                ])
                            ]),
                            li({class: 'divider'}),
                            li({}, [
                                a({href: '#', 'data-menu-item': 'logout', id: addEvent('click', handleSignout)}, [
                                    div({style: 'display: inline-block; width: 34px;'}, [
                                        span({class: 'fa fa-sign-out', style: 'font-size: 150%; margin-right: 10px;'})
                                    ]),
                                    'Sign Out'
                                ])
                            ])
                        ])
                    ]);
                }
                return a({type: 'button', class: 'btn btn-primary navbar-btn kb-nav-btn', 'data-button': 'signin', href: '#login'}, [
                    div({class: 'fa fa-sign-in  fa-inverse', style: 'margin-right: 5px;'}),
                    div({class: 'kb-nav-btn-txt'}, ['Sign In'])
                ]);
            }

            function render() {
                var div = html.tag('div'),
                    button = html.tag('button'),
                    span = html.tag('span'),
                    a = html.tag('a'),
                    img = html.tag('img', {close: false});
                var content = div({class: 'container-fluid'}, [
                    div({class: 'navbar-header navbar-menu'}, [
                        div({style: 'display: inline-block;', 'data-element': 'menu'}, [
                            button({id: 'kb-nav-menu',
                                class: 'btn btn-default navbar-btn kb-nav-btn',
                                'data-toggle': 'dropdown',
                                'aria-haspopup': 'true'}, [
                                span({class: 'fa fa-navicon'})
                            ]),
                            renderMenu()
                        ]),
                        a({href: 'http://kbase.us'}, [
                            img({id: 'logo', src: 'modules/navbar/images/kbase_logo.png', width: '46'})
                        ])
                    ]),
                    div({class: 'navbar-text navbar-title'}, [
                        span({class: 'title', 'data-element': 'title'}, [
                            title
                        ])
                    ]),
                    div({class: 'navbar-right'}, [
                        span({class: 'navbar-buttons', 'data-element': 'buttons'}, [
                            renderButtons()
                        ]),
                        span({id: 'signin-button', 'data-element': 'signin-button'}, [
                            renderLogin()
                        ])
                    ])
                ]);
                return content;
            }

            /* BUTTONS */
            var buttons = [];
            var buttonMap = {};
            function clearButtons() {
                if (!$container) {
                    return false
                }
                // $container.find('.navbar-buttons').empty();
                buttons = [];
                buttonMap = {};
                return true;
            }

            function addButton(cfg) {
                if (cfg.place === 'end') {
                    buttons.push(cfg);
                } else {
                    buttons.unshift(cfg);
                }
                buttonMap[cfg.name] = cfg;
                dirty();
                return true;
            }

            function renderButton(cfg) {
                var iconStyle = '';
                var label = '';

                var div = html.tag('div'),
                    a = html.tag('a'),
                    button = html.tag('button');

                if (cfg.label) {
                    label = div({class: 'kb-nav-btn-txt'}, cfg.label);
                } else {
                    iconStyle += 'font-size: 150%;';
                }

                var btn;
                var id = html.genId();
                var attribs = {
                    'data-button': cfg.name,
                    id: id,
                    class: 'btn btn-' + (cfg.style || 'default') + ' navbar-btn kb-nav-btn',
                    disabled: cfg.disabled ? true : false
                };
                var icon = div({
                    class: 'fa fa-' + cfg.icon,
                    style: iconStyle
                });
                if (cfg.url) {
                    // a link style button
                    attribs.role = 'button';
                    attribs.href = cfg.url;
                    if (cfg.target) {
                        attribs.target = cfg.target;
                    } else if (cfg.external) {
                        attribs.target = '_blank';
                    }
                    btn = a(attribs, [icon, label]);
                } else {
                    btn = button(attribs, [icon, label]);
                    addEvent('click', function (e) {
                        console.log('yes, here!');
                        //e.preventDefault();
                        console.log('yes, here2!');
                        cfg.callback();
                        return false;
                    }, id);
                }
                return btn;
            }

            function renderButtons() {
                return buttons.map(function (buttonDef) {
                    return renderButton(buttonDef);
                });
            }

            function findButton(name) {
                return $container.find('.navbar-buttons [data-button="' + name + '"]');
            }

            // All set up, set flags.
            dirty();

            /*
             * And this, dear friends, is the Navbar api.
             */
            return {
                // Standard panel/widget stuff
                setup: setup,
                teardown: teardown,
                attach: attach,
                detach: detach,
                start: start,
                stop: stop,
                // probably should remove after play time is over...
                render: render,
                // navbar api
                setTitle: setTitle,
                // addMenuItem: addMenuItem,
                clearButtons: clearButtons,
                addButton: addButton,

                addMenu: addMenu,
                addMenuItem: addMenuItem,

                addToMenu: addToMenu,

                    //addAppMenuItem: addAppMenuItem,
                    //removeAppMenuItem: removeAppMenuItem,
                    //addPanelMenuItem: addPanelMenuItem,
                    //removePanelMenuItem: removePanelMenuItem,
                    //clearMenu:
                    // On the other hand, panels and widgets don't need to muck with the menu,
                    // they can use buttons.
                    //clearButtons: clearButtons,
                    //addButton: addButton,
                    //addDropdown: addDropdown

            };
        };
        return {
            create: factory
        };
    });
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { ListView } from 'react-native';

import CategoryListItem from '../containers/CategoryListItem';

export default class CategoryListView extends Component {
  constructor(props) {
    super(props);

    props.loadCategories();

    const ds = new ListView.DataSource({
      rowHasChanged: (r1, r2) => r1.id !== r2.id,
    });
    this.dataSource = ds.cloneWithRows([]);
  }

  componentWillReceiveProps(nextProps) {
    if(nextProps.categories.length != this.props.categories.length ||
       nextProps.categories.map(cat => cat.id) !== this.props.categories.map(cat => cat.id)) {
      this.dataSource.cloneWithRows(nextProps.categories);
    }
  }

  render() {
    return (
      <ListView
        dataSource={this.dataSource}
        renderRow={(row) => <CategoryListItem id={row.id} name={row.name} />}
      />
    );
  }
}
<commit_msg>Refactor CategoryListView<commit_after>import React, { Component } from 'react';
import { ListView } from 'react-native';

import CategoryListItem from '../containers/CategoryListItem';

export default class CategoryListView extends Component {
  constructor(props) {
    super(props);

    props.loadCategories();

    const ds = new ListView.DataSource({
      rowHasChanged: (r1, r2) => r1.id !== r2.id,
    });
    this.dataSource = ds.cloneWithRows([]);
  }

  shouldComponentUpdate(nextProps) {
    return nextProps.categories.length !== this.props.categories.length || nextProps.categories.map(cat => cat.id) !== this.props.categories.map(cat => cat.id));
  }

  componentWillUpdate(nextProps) {
    this.dataSource.cloneWithRows(nextProps.categories);
  }

  render() {
    return (
      <ListView
        dataSource={this.dataSource}
        renderRow={(row) => <CategoryListItem id={row.id} name={row.name} />}
      />
    );
  }
}
<|endoftext|>


<commit_before>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { ipcRenderer, remote } from 'electron';
import classNames from 'classnames';
import {
  Button,
  Menu,
  MenuItem,
  MenuDivider,
  Popover,
  Position
} from '@blueprintjs/core';

import {
  LOAD_CHARTS,
  LOAD_SETTINGS,
  SEND_TOGGLE_COMPACT,
  SEND_TOGGLE_WELCOME,
  SHOW_ISSUE_REPORTING_MODAL,
  CHECK_FOR_UPDATES,
} from 'channels';

import { Themes } from 'enums';

export default class CustomMenu extends PureComponent {
  static propTypes = {
    theme: PropTypes.string.isRequired,
    resetSession: PropTypes.func.isRequired,
    className: PropTypes.string
  };

  win = remote.getCurrentWindow();

  goToCharts = () => {
    this.win.webContents.send(LOAD_CHARTS);
  };

  goToSettings = () => {
    this.win.webContents.send(LOAD_SETTINGS);
  };

  resetSession = () => {
    const { resetSession } = this.props;
    resetSession();
  };

  toggleFullscreen = () => {
    this.win.setFullScreen(!this.win.isFullScreen());
  };

  toggleCompact = () => {
    if (this.win.isFullScreen()) this.toggleFullscreen();
    this.win.webContents.send(SEND_TOGGLE_COMPACT);
  };

  welcome = () => {
    this.win.webContents.send(SEND_TOGGLE_WELCOME);
  };

  report = () => {
    this.win.webContents.send(SHOW_ISSUE_REPORTING_MODAL);
  };

  quit = () => {
    this.win.close();
  };

  update = () => {
    ipcRenderer.send(CHECK_FOR_UPDATES);
  };

  minimize = () => {
    this.win.minimize();
  };

  render() {
    const { theme, className } = this.props;

    const portalContainer = classNames(
      'menu',
      {
        'pt-dark': theme === Themes.DARK
      }
    );

    const menuContainer = classNames(
      'non-draggable',
      'no-select',
      className
    );

    const menuStyle = classNames(
      'pt-minimal',
      'btn-no-hover',
      {
        'btn-white': className.includes('btn-white'),
        'btn-black': className.includes('btn-black')
      }
    );

    const menu = (
      <Menu className="non-draggable">
        <MenuItem
          onClick={this.goToCharts}
          iconName="timeline-line-chart"
          text="Charts"
        />
        <MenuDivider />
        <MenuItem
          onClick={this.resetSession}
          iconName="refresh"
          text="New Session"
        />
        <MenuDivider />
        <MenuItem
          onClick={this.toggleFullscreen}
          iconName="maximize"
          text="Fullscreen"
        />
        <MenuItem
          onClick={this.toggleCompact}
          iconName="minimize"
          text="Compact Mode"
        />
        <MenuDivider />
        <MenuItem
          onClick={this.welcome}
          iconName="chat"
          text="Welcome"
        />
        <MenuItem
          onClick={this.report}
          iconName="error"
          text="Report Issue"
        />
        <MenuDivider />
        <MenuItem
          onClick={this.update}
          iconName="automatic-updates"
          text="Check for updates"
        />
        <MenuItem
          onClick={this.goToSettings}
          iconName="cog"
          text="Settings"
        />
      </Menu>
    );

    return (
      <Popover
        content={menu}
        position={Position.BOTTOM_LEFT}
        popoverClassName="pt-minimal"
        portalClassName={portalContainer}
        className={menuContainer}
      >
        <Button iconName="menu" className={menuStyle} />
      </Popover>
    );
  }
}
<commit_msg>feat: Remove option to set fullscreen<commit_after>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { ipcRenderer, remote } from 'electron';
import classNames from 'classnames';
import {
  Button,
  Menu,
  MenuItem,
  MenuDivider,
  Popover,
  Position
} from '@blueprintjs/core';

import {
  LOAD_CHARTS,
  LOAD_SETTINGS,
  SEND_TOGGLE_COMPACT,
  SEND_TOGGLE_WELCOME,
  SHOW_ISSUE_REPORTING_MODAL,
  CHECK_FOR_UPDATES,
} from 'channels';

import { Themes } from 'enums';

export default class CustomMenu extends PureComponent {
  static propTypes = {
    theme: PropTypes.string.isRequired,
    resetSession: PropTypes.func.isRequired,
    className: PropTypes.string
  };

  win = remote.getCurrentWindow();

  goToCharts = () => {
    this.win.webContents.send(LOAD_CHARTS);
  };

  goToSettings = () => {
    this.win.webContents.send(LOAD_SETTINGS);
  };

  resetSession = () => {
    const { resetSession } = this.props;
    resetSession();
  };

  toggleFullscreen = () => {
    this.win.setFullScreen(!this.win.isFullScreen());
  };

  toggleCompact = () => {
    if (this.win.isFullScreen()) this.toggleFullscreen();
    this.win.webContents.send(SEND_TOGGLE_COMPACT);
  };

  welcome = () => {
    this.win.webContents.send(SEND_TOGGLE_WELCOME);
  };

  report = () => {
    this.win.webContents.send(SHOW_ISSUE_REPORTING_MODAL);
  };

  quit = () => {
    this.win.close();
  };

  update = () => {
    ipcRenderer.send(CHECK_FOR_UPDATES);
  };

  minimize = () => {
    this.win.minimize();
  };

  render() {
    const { theme, className } = this.props;

    const portalContainer = classNames(
      'menu',
      {
        'pt-dark': theme === Themes.DARK
      }
    );

    const menuContainer = classNames(
      'non-draggable',
      'no-select',
      className
    );

    const menuStyle = classNames(
      'pt-minimal',
      'btn-no-hover',
      {
        'btn-white': className.includes('btn-white'),
        'btn-black': className.includes('btn-black')
      }
    );

    const menu = (
      <Menu className="non-draggable">
        <MenuItem
          onClick={this.goToCharts}
          iconName="timeline-line-chart"
          text="Charts"
        />
        <MenuDivider />
        <MenuItem
          onClick={this.resetSession}
          iconName="refresh"
          text="New Session"
        />
        <MenuDivider />
        <MenuItem
          onClick={this.toggleCompact}
          iconName="minimize"
          text="Compact Mode"
        />
        <MenuDivider />
        <MenuItem
          onClick={this.welcome}
          iconName="chat"
          text="Welcome"
        />
        <MenuItem
          onClick={this.report}
          iconName="error"
          text="Report Issue"
        />
        <MenuDivider />
        <MenuItem
          onClick={this.update}
          iconName="automatic-updates"
          text="Check for updates"
        />
        <MenuItem
          onClick={this.goToSettings}
          iconName="cog"
          text="Settings"
        />
      </Menu>
    );

    return (
      <Popover
        content={menu}
        position={Position.BOTTOM_LEFT}
        popoverClassName="pt-minimal"
        portalClassName={portalContainer}
        className={menuContainer}
      >
        <Button iconName="menu" className={menuStyle} />
      </Popover>
    );
  }
}
<|endoftext|>


<commit_before>import React, {Component} from 'react'
import Arrow from 'material-ui/svg-icons/navigation/expand-more';
import Play from 'material-ui/svg-icons/av/play-circle-outline';
import Profile from 'material-ui/svg-icons/social/person-outline';
import Message from 'material-ui/svg-icons/communication/message';
import Paper from 'material-ui/Paper';
import Food from 'material-ui/svg-icons/maps/restaurant';
import Health from 'material-ui/svg-icons/maps/local-hospital';
import HorizontalNonLinearStepper from './Stepper';
import Rule from './Divider';
import Chips from './Chips';

const logoUrl = require('../../assets/img/logo.png');
const plateUrl = require('../../assets/img/plate_nobg.png');
const screensUrl = require('../../assets/img/screenshots.png');
const badgesUrl = require('../../assets/img/badges.png');

const style = {
  height: 100,
  width: 100,
  margin: 20,
  textAlign: 'center',
  display: 'inline-block',
};

class WelcomePage extends Component {

  componentDidMount() {
      window.addEventListener('scroll', this.handleScroll);
  }

  componentWillUnmount() {
      window.removeEventListener('scroll', this.handleScroll);
  }

  handleScroll(event) {
      let arrow = document.getElementById("arrow");
      var opacity = 1;  // initial opacity
      var timer = setInterval(function () {
          if (opacity <= 0.1) {
              clearInterval(timer);
              arrow.style.display = 'none';
          }

          arrow.style.opacity = opacity;
          arrow.style.filter = 'alpha(opacity=' + opacity * 100 + ")";
          opacity -= opacity * 0.1;
      }, 25);
  }

  render () {
    const iconStyles = {
      width: 90,
      height: 70
    };

    const foo =
hisdfgsdfg
;

    return (

Kiwwi*

PLAN WELL.

EAT WELL.

BE WELL.

Repeat.

Getting Started <Play style={{width: '60px', height: '60px'}}/>

Step 1. Tell us about you <Profile style={{width: '110px', height: '95px', color: 'white'}}/>

                    <HorizontalNonLinearStepper/>

Step 2. Tell us about your food <Food style={{width: '110px', height: '95px', color: 'white'}}/>

            <Chips/>

Step 3. Select a health plan <Health style={{width: '110px', height: '95px', color: 'white'}}/>

            <Rule className='wow animated fadeInRight'/>

Contact Us <Message style={{width: '60px', height: '60px'}}/>

    )
  }
}

export default WelcomePage;<commit_msg>Remove noise<commit_after>import React, {Component} from 'react'
import Arrow from 'material-ui/svg-icons/navigation/expand-more';
import Play from 'material-ui/svg-icons/av/play-circle-outline';
import Profile from 'material-ui/svg-icons/social/person-outline';
import Message from 'material-ui/svg-icons/communication/message';
import Paper from 'material-ui/Paper';
import Food from 'material-ui/svg-icons/maps/restaurant';
import Health from 'material-ui/svg-icons/maps/local-hospital';
import HorizontalNonLinearStepper from './Stepper';
import Rule from './Divider';
import Chips from './Chips';
import Drawer from 'material-ui/Drawer';
import MenuItem from 'material-ui/MenuItem'

const logoUrl = require('../../assets/img/logo.png');
const plateUrl = require('../../assets/img/plate_nobg.png');
const screensUrl = require('../../assets/img/screenshots.png');
const badgesUrl = require('../../assets/img/badges.png');

const style = {
  height: 100,
  width: 100,
  margin: 20,
  textAlign: 'center',
  display: 'inline-block',
};

class WelcomePage extends Component {

  componentDidMount() {
      window.addEventListener('scroll', this.handleScroll);
  }

  componentWillUnmount() {
      window.removeEventListener('scroll', this.handleScroll);
  }

  handleScroll(event) {
      let arrow = document.getElementById("arrow");
      var opacity = 1;  // initial opacity
      var timer = setInterval(function () {
          if (opacity <= 0.1) {
              clearInterval(timer);
              arrow.style.display = 'none';
          }

          arrow.style.opacity = opacity;
          arrow.style.filter = 'alpha(opacity=' + opacity * 100 + ")";
          opacity -= opacity * 0.1;
      }, 25);
  }

  render () {
    const iconStyles = {
      width: 90,
      height: 70
    };

    return (

Kiwwi*

PLAN WELL.

EAT WELL.

BE WELL.

Repeat.

Getting Started <Play style={{width: '60px', height: '60px'}}/>

Step 1. Tell us about you <Profile style={{width: '110px', height: '95px', color: 'white'}}/>

                    <HorizontalNonLinearStepper/>

Step 2. Tell us about your food <Food style={{width: '110px', height: '95px', color: 'white'}}/>

            <Chips/>

Step 3. Select a health plan <Health style={{width: '110px', height: '95px', color: 'white'}}/>

            <Rule className='wow animated fadeInRight'/>

Contact Us <Message style={{width: '60px', height: '60px'}}/>

    )
  }
}

export default WelcomePage;<|endoftext|>


<commit_before>class AuthController {
    constructor(data) {
        this._data = data;
    }

    postLogin(req, res, next, passport) {
        return passport.authenticate('local', (err, user, info) => {
            const model = {};
            model.username = req.body.username;
            if (err) {
                model.err = err.message;
                return res.render('login', { model: model });
            }

            return req.login(user, () => {
                res.cookie('username', user.username);
                return res.redirect('/');
            });
        })(req, res, next);
    }

    postRegister(req, res) {
        return this._data.users.create(req.body)
            .then((user) => {
                req.logIn(user, (err) => {
                    if (err) {
                        res.redirect('/login');
                    }

                    res.redirect('/profile');
                });
            })
            .catch((err) => {
                res.render('register', {
                    model: req.body,
                    errors: err,
                });
            });
    }

    logOut(req, res) {
        req.logout();
        res.clearCookie('username');
        return res.redirect('/home');
    }

    getLogin(req, res) {
        return res.render('login');
    }

    getRegister(req, res) {
       return res.render('register');
    }
}

module.exports = AuthController;
<commit_msg>Fixed bug logic add to cart after register<commit_after>class AuthController {
    constructor(data) {
        this._data = data;
    }

    postLogin(req, res, next, passport) {
        return passport.authenticate('local', (err, user, info) => {
            const model = {};
            model.username = req.body.username;
            if (err) {
                model.err = err.message;
                return res.render('login', { model: model });
            }

            return req.login(user, () => {
                res.cookie('username', user.username);
                return res.redirect('/');
            });
        })(req, res, next);
    }

    postRegister(req, res) {
        return this._data.users.create(req.body)
            .then((user) => {
                req.logIn(user, (err) => {
                    if (err) {
                        res.redirect('/login');
                    }

                    res.cookie('username', user.username);
                    res.redirect('/profile');
                });
            })
            .catch((err) => {
                res.render('register', {
                    model: req.body,
                    errors: err,
                });
            });
    }

    logOut(req, res) {
        req.logout();
        res.clearCookie('username');
        return res.redirect('/home');
    }

    getLogin(req, res) {
        return res.render('login');
    }

    getRegister(req, res) {
       return res.render('register');
    }
}

module.exports = AuthController;
<|endoftext|>


<commit_before>/**
 * Simple color entry widget
 *
 * @copyright 2005 silverorange Inc.
 */

/**
 * Creates a SwatSimpleColorEntry object
 *
 * @param string id
 * @param Array colors
 */
function SwatSimpleColorEntry(id, colors)
{
	this.id = id;
	this.colors = colors;
	this.is_open = false;
	this.is_drawn = false;

	this.palette_div = document.getElementById(this.id + '_palette');
	this.swatch_span = document.getElementById(this.id + '_swatch');
	this.input_tag = document.getElementById(this.id);

	// try to make a square palette
	this.columns = Math.ceil(Math.sqrt(this.colors.length));

	this.current_color = null;

	for (i = 0; i < this.colors.length; i++) {
		if (this.input_tag.value == this.colors[i]) {
			this.setColor(i);
			break;
		}
	}
}

/**
 * Closes this color palette
 */
SwatSimpleColorEntry.prototype.close = function()
{
	this.palette_div.style.display = 'none';
	SwatZIndexManager.lowerElement(this.palette_div);

	this.is_open = false;
}

/**
 * Opens this color palette
 */
SwatSimpleColorEntry.prototype.open = function()
{
	this.draw();

	this.palette_div.style.display = 'block';
	SwatZIndexManager.raiseElement(this.palette_div);

	this.is_open = true;
}

/**
 * Draws this color palette
 */
SwatSimpleColorEntry.prototype.draw = function()
{
	if (!this.is_drawn) {
		var output =
			'

';

		if (this.colors.length % this.columns == 0)
			var num_cells = this.colors.length
		else
			var num_cells = this.colors.length +
				(this.columns - (this.colors.length % this.columns));

		for (i = 0; i < num_cells; i++) {
			if (i % this.columns == 0)
				output = output + '
';

			if (i < this.colors.length) {

				if (i == this.current_color) {
					output = output +
						'';
				} else {
					output = output +
						'';
				}

				output = output +
					'' +
					' ' +
					'' +
					'	';

			} else {
				output = output +
					'' +
					' ' +
					'	';
			}

			if ((i + 1) % this.columns == 0)
				output = output + '
';
		}

		output = output + '

';

		this.palette_div.innerHTML = output;
		this.is_drawn = true;
	}
}

SwatSimpleColorEntry.prototype.toggle = function()
{
	if (this.is_open)
		this.close();
	else
		this.open();
}

/**
 * Sets the value of the color entry input tag to the selected color and
 * highlights the selected color
 *
 * @param number color_index the index of the selected color.
 */
SwatSimpleColorEntry.prototype.setColor = function(color_index)
{
	if (this.is_drawn) {
		if (this.current_color !== null) {
			var old_palette_entry =
				document.getElementById(this.id +
					'_palette_' + this.current_color);

			old_palette_entry.className = '';
		}
	}

	this.input_tag.value = this.colors[color_index];
	this.swatch_span.style.background = '#' + this.colors[color_index];
	this.current_color = color_index;

	if (this.is_drawn) {
		var palette_entry =
			document.getElementById(this.id + '_palette_' + color_index);

		palette_entry.className = 'swat-simple-color-palette-selected';
	}

	this.close();
}
<commit_msg>Update SimpleColorEntry JavaScript to match Swat changes.<commit_after>/**
 * Simple color entry widget
 *
 * @copyright 2005 silverorange Inc.
 */

/**
 * Creates a SwatSimpleColorEntry object
 *
 * @param string id
 * @param Array colors
 */
function SwatSimpleColorEntry(id, colors)
{
	this.id = id;
	this.colors = colors;
	this.is_open = false;
	this.is_drawn = false;

	this.palette_div = document.getElementById(this.id + '_palette');
	this.swatch_span = document.getElementById(this.id + '_swatch');
	this.input_tag = document.getElementById(this.id + '_value');

	// try to make a square palette
	this.columns = Math.ceil(Math.sqrt(this.colors.length));

	this.current_color = null;

	for (i = 0; i < this.colors.length; i++) {
		if (this.input_tag.value == this.colors[i]) {
			this.setColor(i);
			break;
		}
	}
}

/**
 * Closes this color palette
 */
SwatSimpleColorEntry.prototype.close = function()
{
	this.palette_div.style.display = 'none';
	SwatZIndexManager.lowerElement(this.palette_div);

	this.is_open = false;
}

/**
 * Opens this color palette
 */
SwatSimpleColorEntry.prototype.open = function()
{
	this.draw();

	this.palette_div.style.display = 'block';
	SwatZIndexManager.raiseElement(this.palette_div);

	this.is_open = true;
}

/**
 * Draws this color palette
 */
SwatSimpleColorEntry.prototype.draw = function()
{
	if (!this.is_drawn) {
		var output =
			'

';

		if (this.colors.length % this.columns == 0)
			var num_cells = this.colors.length
		else
			var num_cells = this.colors.length +
				(this.columns - (this.colors.length % this.columns));

		for (i = 0; i < num_cells; i++) {
			if (i % this.columns == 0)
				output = output + '
';

			if (i < this.colors.length) {

				if (i == this.current_color) {
					output = output +
						'';
				} else {
					output = output +
						'';
				}

				output = output +
					'' +
					' ' +
					'' +
					'	';

			} else {
				output = output +
					'' +
					' ' +
					'	';
			}

			if ((i + 1) % this.columns == 0)
				output = output + '
';
		}

		output = output + '

';

		this.palette_div.innerHTML = output;
		this.is_drawn = true;
	}
}

SwatSimpleColorEntry.prototype.toggle = function()
{
	if (this.is_open)
		this.close();
	else
		this.open();
}

/**
 * Sets the value of the color entry input tag to the selected color and
 * highlights the selected color
 *
 * @param number color_index the index of the selected color.
 */
SwatSimpleColorEntry.prototype.setColor = function(color_index)
{
	if (this.is_drawn) {
		if (this.current_color !== null) {
			var old_palette_entry =
				document.getElementById(this.id +
					'_palette_' + this.current_color);

			old_palette_entry.className = '';
		}
	}

	this.input_tag.value = this.colors[color_index];
	this.swatch_span.style.background = '#' + this.colors[color_index];
	this.current_color = color_index;

	if (this.is_drawn) {
		var palette_entry =
			document.getElementById(this.id + '_palette_' + color_index);

		palette_entry.className = 'swat-simple-color-palette-selected';
	}

	this.close();
}
<|endoftext|>


<commit_before>'use strict';

const userMiddleware = require('../middlewares/user');
const errorMiddleware = require('../middlewares/error');
const authorizationMiddleware = require('../middlewares/authorization');
const connectionParamsMiddleware = require('../middlewares/connection-params');
const timeoutLimitsMiddleware = require('../middlewares/timeout-limits');
const { initializeProfilerMiddleware } = require('../middlewares/profiler');
const rateLimitsMiddleware = require('../middlewares/rate-limit');
const { RATE_LIMIT_ENDPOINTS_GROUPS } = rateLimitsMiddleware;

const zlib = require('zlib');
const PSQL = require('cartodb-psql');
const copyTo = require('pg-copy-streams').to;
const copyFrom = require('pg-copy-streams').from;

function CopyController(metadataBackend, userDatabaseService, userLimitsService) {
    this.metadataBackend = metadataBackend;
    this.userDatabaseService = userDatabaseService;
    this.userLimitsService = userLimitsService;
}

CopyController.prototype.route = function (app) {
    const { base_url } = global.settings;

    const copyFromMiddlewares = endpointGroup => {
        return [
            initializeProfilerMiddleware('copyfrom'),
            userMiddleware(),
            rateLimitsMiddleware(this.userLimitsService, endpointGroup),
            authorizationMiddleware(this.metadataBackend),
            connectionParamsMiddleware(this.userDatabaseService),
            timeoutLimitsMiddleware(this.metadataBackend),
            this.handleCopyFrom.bind(this),
            this.responseCopyFrom.bind(this),
            errorMiddleware()
        ];
    };

    const copyToMiddlewares = endpointGroup => {
        return [
            initializeProfilerMiddleware('copyto'),
            userMiddleware(),
            rateLimitsMiddleware(this.userLimitsService, endpointGroup),
            authorizationMiddleware(this.metadataBackend),
            connectionParamsMiddleware(this.userDatabaseService),
            timeoutLimitsMiddleware(this.metadataBackend),
            this.handleCopyTo.bind(this),
            this.responseCopyTo.bind(this),
            errorMiddleware()
        ];
    };

    app.post(`${base_url}/sql/copyfrom`, copyFromMiddlewares(RATE_LIMIT_ENDPOINTS_GROUPS.COPY_FROM));
    app.get(`${base_url}/sql/copyto`, copyToMiddlewares(RATE_LIMIT_ENDPOINTS_GROUPS.COPY_TO));
};

CopyController.prototype.handleCopyTo = function (req, res, next) {
    const { sql } = req.query;

    if (!sql) {
        throw new Error("Parameter 'sql' is missing");
    }

    // Only accept SQL that starts with 'COPY'
    if (!sql.toUpperCase().startsWith("COPY ")) {
        throw new Error("SQL must start with COPY");
    }

    try {
        // Open pgsql COPY pipe and stream out to HTTP response
        const pg = new PSQL(res.locals.userDbParams);
        pg.connect(function (err, client) {
            if (err) {
                return next(err);
            }

            let copyToStream = copyTo(sql);
            const pgstream = client.query(copyToStream);

            res.on('error', next);
            pgstream.on('error', next);
            pgstream.on('end', next);

            pgstream.pipe(res);
        });
    } catch (err) {
        next(err);
    }

};

CopyController.prototype.responseCopyTo = function (req, res) {
    let { filename } = req.query;

    if (!filename) {
        filename = 'carto-sql-copyto.dmp';
    }

    res.setHeader("Content-Disposition", `attachment; filename=${encodeURIComponent(filename)}`);
    res.setHeader("Content-Type", "application/octet-stream");
    res.send();
};

CopyController.prototype.handleCopyFrom = function (req, res, next) {
    const { sql } = req.query;

    if (!sql) {
        return next(new Error("Parameter 'sql' is missing, must be in URL or first field in POST"));
    }

    // Only accept SQL that starts with 'COPY'
    if (!sql.toUpperCase().startsWith("COPY ")) {
        return next(new Error("SQL must start with COPY"));
    }

    try {
        const start_time = Date.now();

        // Connect and run the COPY
        const pg = new PSQL(res.locals.userDbParams);
        pg.connect(function (err, client) {
            if (err) {
                return next(err);
            }

            let copyFromStream = copyFrom(sql);
            const pgstream = client.query(copyFromStream);
            pgstream.on('error', next);
            pgstream.on('end', function () {
                const end_time = Date.now();
                res.body = {
                    time: (end_time - start_time) / 1000,
                    total_rows: copyFromStream.rowCount
                };

                return next();
            });

            if (req.get('content-encoding') === 'gzip') {
                req.pipe(zlib.createGunzip()).pipe(pgstream);
            } else {
                req.pipe(pgstream);
            }
        });

    } catch (err) {
        next(err);
    }

};

CopyController.prototype.responseCopyFrom = function (req, res, next) {
    if (!res.body || !res.body.total_rows) {
        return next(new Error("No rows copied"));
    }

    res.send(res.body);
};

module.exports = CopyController;
<commit_msg>moving copyto headers to correct position<commit_after>'use strict';

const userMiddleware = require('../middlewares/user');
const errorMiddleware = require('../middlewares/error');
const authorizationMiddleware = require('../middlewares/authorization');
const connectionParamsMiddleware = require('../middlewares/connection-params');
const timeoutLimitsMiddleware = require('../middlewares/timeout-limits');
const { initializeProfilerMiddleware } = require('../middlewares/profiler');
const rateLimitsMiddleware = require('../middlewares/rate-limit');
const { RATE_LIMIT_ENDPOINTS_GROUPS } = rateLimitsMiddleware;

const zlib = require('zlib');
const PSQL = require('cartodb-psql');
const copyTo = require('pg-copy-streams').to;
const copyFrom = require('pg-copy-streams').from;

function CopyController(metadataBackend, userDatabaseService, userLimitsService) {
    this.metadataBackend = metadataBackend;
    this.userDatabaseService = userDatabaseService;
    this.userLimitsService = userLimitsService;
}

CopyController.prototype.route = function (app) {
    const { base_url } = global.settings;

    const copyFromMiddlewares = endpointGroup => {
        return [
            initializeProfilerMiddleware('copyfrom'),
            userMiddleware(),
            rateLimitsMiddleware(this.userLimitsService, endpointGroup),
            authorizationMiddleware(this.metadataBackend),
            connectionParamsMiddleware(this.userDatabaseService),
            timeoutLimitsMiddleware(this.metadataBackend),
            this.handleCopyFrom.bind(this),
            this.responseCopyFrom.bind(this),
            errorMiddleware()
        ];
    };

    const copyToMiddlewares = endpointGroup => {
        return [
            initializeProfilerMiddleware('copyto'),
            userMiddleware(),
            rateLimitsMiddleware(this.userLimitsService, endpointGroup),
            authorizationMiddleware(this.metadataBackend),
            connectionParamsMiddleware(this.userDatabaseService),
            timeoutLimitsMiddleware(this.metadataBackend),
            this.handleCopyTo.bind(this),
            errorMiddleware()
        ];
    };

    app.post(`${base_url}/sql/copyfrom`, copyFromMiddlewares(RATE_LIMIT_ENDPOINTS_GROUPS.COPY_FROM));
    app.get(`${base_url}/sql/copyto`, copyToMiddlewares(RATE_LIMIT_ENDPOINTS_GROUPS.COPY_TO));
};

CopyController.prototype.handleCopyTo = function (req, res, next) {
    const { sql, filename = 'carto-sql-copyto.dmp' } = req.query;

    console.log('request headers', req.headers)

    if (!sql) {
        throw new Error("Parameter 'sql' is missing");
    }

    // Only accept SQL that starts with 'COPY'
    if (!sql.toUpperCase().startsWith("COPY ")) {
        throw new Error("SQL must start with COPY");
    }

    try {
        // Open pgsql COPY pipe and stream out to HTTP response
        const pg = new PSQL(res.locals.userDbParams);
        pg.connect(function (err, client) {
            if (err) {
                return next(err);
            }

            let copyToStream = copyTo(sql);
            const pgstream = client.query(copyToStream);

            res.on('error', next);
            pgstream.on('error', next);
            pgstream.on('end', next);

            res.setHeader("Content-Disposition", `attachment; filename=${encodeURIComponent(filename)}`);
            res.setHeader("Content-Type", "application/octet-stream");

            pgstream.pipe(res);
        });
    } catch (err) {
        next(err);
    }

};

CopyController.prototype.handleCopyFrom = function (req, res, next) {
    const { sql } = req.query;

    if (!sql) {
        return next(new Error("Parameter 'sql' is missing, must be in URL or first field in POST"));
    }

    // Only accept SQL that starts with 'COPY'
    if (!sql.toUpperCase().startsWith("COPY ")) {
        return next(new Error("SQL must start with COPY"));
    }

    try {
        const start_time = Date.now();

        // Connect and run the COPY
        const pg = new PSQL(res.locals.userDbParams);
        pg.connect(function (err, client) {
            if (err) {
                return next(err);
            }

            let copyFromStream = copyFrom(sql);
            const pgstream = client.query(copyFromStream);
            pgstream.on('error', next);
            pgstream.on('end', function () {
                const end_time = Date.now();
                res.body = {
                    time: (end_time - start_time) / 1000,
                    total_rows: copyFromStream.rowCount
                };

                return next();
            });

            if (req.get('content-encoding') === 'gzip') {
                req.pipe(zlib.createGunzip()).pipe(pgstream);
            } else {
                req.pipe(pgstream);
            }
        });

    } catch (err) {
        next(err);
    }

};

CopyController.prototype.responseCopyFrom = function (req, res, next) {
    if (!res.body || !res.body.total_rows) {
        return next(new Error("No rows copied"));
    }

    res.send(res.body);
};

module.exports = CopyController;
<|endoftext|>


<commit_before>(function () {
  angular.module('attributes', [])

  .directive('ngRightClick', function($parse) {

    return function(scope, element, attrs) {
      var fn = $parse(attrs.ngRightClick);

      element.bind('contextmenu', function(event) {

        scope.$apply(function() {
          event.preventDefault();
          fn(scope, {$event:event});
        });
      });
    };
  })

  .directive('ngScroll', function ($parse) {

    return function (scope, element, attrs) {
      var fn = $parse(attrs.ngScroll);

      element.bind('scroll', function (event) {

        scope.$apply(function() {
          event.preventDefault();
          fn(scope, {$event:event});
        });
      });
    };
  })

  .directive('ngInputChange', function ($parse) {

    return {
      restrict: 'A',
      require: '?ngModel',

      link: function(scope, element, attrs, ngModel) {

        element.on('change', function (e) {

          if (ngModel) {
            ngModel.$setViewValue(e.srcElement.value);
          }
        });
      }
    };

    // return function (scope, element, attrs) {
    //   var fn = $parse(attrs.ngInputChange);
    //
    //   element.bind('change', function (event) {
    //
    //     scope.$apply(function() {
    //       event.preventDefault();
    //       fn(scope, {$event:event});
    //     });
    //   });
    // };
  });

})();
<commit_msg>removed unecessary comments<commit_after>(function () {
  angular.module('attributes', [])

  .directive('ngRightClick', function($parse) {

    return function(scope, element, attrs) {
      var fn = $parse(attrs.ngRightClick);

      element.bind('contextmenu', function(event) {

        scope.$apply(function() {
          event.preventDefault();
          fn(scope, {$event:event});
        });
      });
    };
  })

  .directive('ngScroll', function ($parse) {

    return function (scope, element, attrs) {
      var fn = $parse(attrs.ngScroll);

      element.bind('scroll', function (event) {

        scope.$apply(function() {
          event.preventDefault();
          fn(scope, {$event:event});
        });
      });
    };
  })

  .directive('ngInputChange', function ($parse) {

    return {
      restrict: 'A',
      require: '?ngModel',

      link: function(scope, element, attrs, ngModel) {

        element.on('change', function (e) {

          if (ngModel) {
            ngModel.$setViewValue(e.srcElement.value);
          }
        });
      }
    };
  });

})();
<|endoftext|>


<commit_before>'use strict';
var async = require('async');
var log = require('../../../service/log');
const that = this;

exports.addPopulate = function(query, populates) {
    for (var i = 0; i < populates.length; i++) {
        query = query.populate(populates[i].toLowerCase());
    }
    return query;
};

exports.checkMethod = function(status, meta_data) {
    let flag = false;
    if (
        (typeof meta_data.unable !== 'undefined' && meta_data.unable) ||
        typeof meta_data.unable === 'undefined'
    ) {
        flag = true;
    }

    return flag;
};

exports.getPage = function(page, limit) {
    return limit * page - limit;
};

exports.configureMiddleware = function(req, res, next, middlewares) {
    var operations = [];
    if (middlewares.length > 0) {
        for (var i = 0; i < middlewares.length; i++) {
            operations.push(middlewares[i].bind(null, req, res));
        }

        async.series(operations, function(err) {
            if (err) {
                log.error('There was a problem running the middleware' + err);
                return next(err);
            }
            next();
        });

    } else {
        next();
    }
};

exports.setMiddlewares = function(model) {
    var middlewares = {
        'list': [],
        'create': [],
        'delete': [],
        'detail': [],
        'update': []
    };

    var keys = Object.keys(middlewares);
    for (var x = 0; x < keys.length; x++) {
        if (
            typeof model[keys[x]] !== 'undefined' &&
            typeof model[keys[x]].service !== 'undefined'
        ) {
            for (var i = 0; i < model[keys[x]].service.length; i++) {
                const service = model[keys[x]].service[i].name;
                const method = model[keys[x]].service[i].method;
                middlewares[keys[x]].push(require('../../../service/' + service)[method]);
            }
        }
    }
    return middlewares;
};

exports.applySearch = function(req) {
    const search = JSON.parse(req.query.search);
    const keys = Object.keys(search);
    for (var x = 0; x < keys.length; x++) {
        const type = req.model.structure[keys[x]].type.toLowerCase();
        if (type === 'string' && typeof search[keys[x]] === 'string') {
            req.filter[keys[x]] = new RegExp(search[keys[x]], 'i');
        }
    }
};

exports.applyQueryFilter = function(req, keys) {
    for (var i = 0; i < keys.length; i++) {
        if (
            keys[i] !== 'page' &&
            keys[i] !== 'limit' &&
            keys[i] !== 'search' &&
            typeof req.model.structure[keys[i]] !== 'undefined'
        ) {
            req.filter[keys[i]] = req.query[keys[i]];
        }
    }
};

exports.addSelected = function(model) {
    const keys = Object.keys(model);
    for (var i = 0; i < keys.length; i++) {
        if (typeof model[keys[i]].select !== 'undefined') {
            const selects = Object.keys(model[keys[i]].select);
            for (var x = 0; x < selects.length; x++) {
                model[keys[i]].select[selects[x]] = model[keys[i]].select[selects[x]] == false ?
                0 : 1;
            }
        }
    }
    return;
};

exports.applyFilter = function(req, method) {
    req.filter = {};
    const keys = Object.keys(req.query);

    if (keys.length > 0) {
        that.applyQueryFilter(req, keys);
    }

    if (req.query.search && req.model[method].search) {
        that.applySearch(req);
    }

    return;
};
<commit_msg>delete unnecessary context<commit_after>'use strict';
var async = require('async');
var log = require('../../../service/log');

exports.addPopulate = function(query, populates) {
    for (var i = 0; i < populates.length; i++) {
        query = query.populate(populates[i].toLowerCase());
    }
    return query;
};

exports.checkMethod = function(status, meta_data) {
    let flag = false;
    if (
        (typeof meta_data.unable !== 'undefined' && meta_data.unable) ||
        typeof meta_data.unable === 'undefined'
    ) {
        flag = true;
    }

    return flag;
};

exports.getPage = function(page, limit) {
    return limit * page - limit;
};

exports.configureMiddleware = function(req, res, next, middlewares) {
    var operations = [];
    if (middlewares.length > 0) {
        for (var i = 0; i < middlewares.length; i++) {
            operations.push(middlewares[i].bind(null, req, res));
        }

        async.series(operations, function(err) {
            if (err) {
                log.error('There was a problem running the middleware' + err);
                return next(err);
            }
            next();
        });

    } else {
        next();
    }
};

exports.setMiddlewares = function(model) {
    var middlewares = {
        'list': [],
        'create': [],
        'delete': [],
        'detail': [],
        'update': []
    };

    var keys = Object.keys(middlewares);
    for (var x = 0; x < keys.length; x++) {
        if (
            typeof model[keys[x]] !== 'undefined' &&
            typeof model[keys[x]].service !== 'undefined'
        ) {
            for (var i = 0; i < model[keys[x]].service.length; i++) {
                const service = model[keys[x]].service[i].name;
                const method = model[keys[x]].service[i].method;
                middlewares[keys[x]].push(require('../../../service/' + service)[method]);
            }
        }
    }
    return middlewares;
};

exports.addSelected = function(model) {
    const keys = Object.keys(model);
    for (var i = 0; i < keys.length; i++) {
        if (typeof model[keys[i]].select !== 'undefined') {
            const selects = Object.keys(model[keys[i]].select);
            for (var x = 0; x < selects.length; x++) {
                model[keys[i]].select[selects[x]] = model[keys[i]].select[selects[x]] == false ?
                0 : 1;
            }
        }
    }
    return;
};

exports.applyFilter = function(req, method) {
    req.filter = {};
    const keys = Object.keys(req.query);

    if (keys.length > 0) {
        applyQueryFilter(req, keys);
    }

    if (req.query.search && req.model[method].search) {
        applySearch(req);
    }

    return;
};

function applySearch(req) {
    const search = JSON.parse(req.query.search);
    const keys = Object.keys(search);
    for (var x = 0; x < keys.length; x++) {
        const type = req.model.structure[keys[x]].type.toLowerCase();
        if (type === 'string' && typeof search[keys[x]] === 'string') {
            req.filter[keys[x]] = new RegExp(search[keys[x]], 'i');
        }
    }
}

function applyQueryFilter(req, keys) {
    for (var i = 0; i < keys.length; i++) {
        if (
            keys[i] !== 'page' &&
            keys[i] !== 'limit' &&
            keys[i] !== 'search' &&
            typeof req.model.structure[keys[i]] !== 'undefined'
        ) {
            req.filter[keys[i]] = req.query[keys[i]];
        }
    }
}
<|endoftext|>


<commit_before>/**
 * Copyright 2014 Ian Davies
 *
 * 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.
 */
define([], function() {

	// TODO: Implement a more robust persistence API.
	// Perhaps use something like https://github.com/grevory/angular-local-storage

	return ['$window', function PersistenceConstructor($window) {

		this.save = function save(key, value) {
			$window.localStorage[key] = value;
		}

		this.load = function load(key) {
			return $window.localStorage[key];
		}

		this.session = {
			save: function sessionSave(key, value) {
				$window.sessionStorage[key] = value;
			},

			load: function sessionLoad(key, value) {
				return $window.sessionStorage[key];
			},
		};

	}];

});<commit_msg>Cope when local storage is disabled.<commit_after>/**
 * Copyright 2014 Ian Davies
 *
 * 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.
 */
define([], function() {

	// TODO: Implement a more robust persistence API.
	// Perhaps use something like https://github.com/grevory/angular-local-storage

	return ['$window', function PersistenceConstructor($window) {

		this.save = function save(key, value) {
			try {
				$window.localStorage[key] = value;
			} catch (e) {
				console.error("Failed to save to local storage. This might be a browser restriction.", e);
			}
		}

		this.load = function load(key) {
			try {
				return $window.localStorage[key];
			} catch (e) {
				console.error("Failed to read from local storage. This might be a browser restriction.", e);
				return null;
			}
		}

		this.session = {
			save: function sessionSave(key, value) {
				try {
					$window.sessionStorage[key] = value;
				} catch (e) {
					console.error("Failed to save to session storage. This might be a browser restriction.", e);
				}
			},

			load: function sessionLoad(key, value) {
				try {
					return $window.sessionStorage[key];
				} catch (e) {
					console.error("Failed to read from session storage. This might be a browser restriction.", e);
					return null;
				}
			},
		};

	}];

});<|endoftext|>


<commit_before>define(function (require) {
    var defineComponent = require('flight/lib/component');
    var templates = require('js/templates'),
        template = templates['course'];
    var _ = require('lodash/lodash');

    return defineComponent(course);

    function course() {
        this.defaultAttrs({
            app: '#app',
            courseName: '.course_name'
        });
        this.renderCourse = function () {
            console.log(this.attr.course);
            var groups = this.groupCheckpoints(this.attr.course.checkpoints);

            var html = template.render({groups: groups});
            $('#app').html(html).fadeIn();
            //this.select('app').append(html).fadeIn();
        };

        this.groupCheckpoints = function (checkpoints) {
            var groupCheckpoints = [];
            var groupNames = _.uniq(_.pluck(checkpoints, 'type'));

            _.forEach(groupNames, function (groupName) {
                groupCheckpoints.push({groupName: groupName, checkpoints: _.where(checkpoints, {type: groupName})})
            });
            return groupCheckpoints;
        };

        this.after('initialize', function () {
            this.renderCourse();
        });
    }
});
<commit_msg>format codes<commit_after>define(function (require) {
    var defineComponent = require('flight/lib/component');
    var templates = require('js/templates'),
        template = templates['course'];
    var _ = require('lodash/lodash');

    return defineComponent(course);

    function course() {
        this.defaultAttrs({
            app: '#app',
            courseName: '.course_name'
        });
        this.renderCourse = function () {
            var groups = this.groupCheckpoints(this.attr.course.checkpoints);

            var html = template.render({groups: groups});
            $('#app').html(html).fadeIn();
            this.on('.checkpoint-item', 'click', this.handleChecked);
            //this.select('app').append(html).fadeIn();
        };

        this.handleChecked = function (event) {
            var id = event.target.id;
            var data = event.target.checked;
            $.ajax('/api/users/course/checkpoints/' + id, {
                method: 'patch',
                data: {checked: data}
            }).fail(function () {
                console.log('checkpoint 更新失败');
            }).done(function (data) {
                console.log(data);
                console.log('checkpoint 更新成功');
            });

        };

        this.groupCheckpoints = function (checkpoints) {
            var groupCheckpoints = [];
            var groupNames = _.uniq(_.pluck(checkpoints, 'type'));

            _.forEach(groupNames, function (groupName) {
                groupCheckpoints.push({groupName: groupName, checkpoints: _.where(checkpoints, {type: groupName})})
            });
            return groupCheckpoints;
        };

        this.after('initialize', function () {
            this.renderCourse();
        });
    }
});
<|endoftext|>


<commit_before>import chrono from 'components/chrono';

/**
 * Parse day periods according to CLDR.
 * @see http://www.unicode.org/cldr/charts/29/verify/dates/en.html
 */
const dayPeriodsParser = new chrono.Parser();
dayPeriodsParser.pattern =
  () => new RegExp('midnight|morning|in the morning|noon|' +
    'afternoon|in the afternoon|evening|in the evening|night|at night', 'i');
dayPeriodsParser.extract = (text, ref, match) => {
  let hour;
  let meridiem;

  switch (match[0].toLowerCase()) {
    case 'midnight':
      hour = 0;
      meridiem = 0;
      break;
    case 'morning':
    case 'in the morning':
      hour = 9;
      meridiem = 0;
      break;
    case 'noon':
      hour = 12;
      meridiem = 1;
      break;
    case 'afternoon':
    case 'in the afternoon':
      hour = 15;
      meridiem = 1;
      break;
    case 'evening':
    case 'in the evening':
      hour = 19;
      meridiem = 1;
      break;
    case 'night':
    case 'at night':
      hour = 10;
      meridiem = 1;
      break;
  }

  return new chrono.ParsedResult({
    ref,
    text: match[0],
    index: match.index,
    start: {
      hour,
      meridiem,
    },
  });
};

/**
 * When the meridiem is not specified, set the time to after the current time.
 * `at 5 today` (current time is 3pm) => `5pm`.
 */
const forwardHoursRefiner = new chrono.Refiner();
forwardHoursRefiner.refine = (text, results, opt = {}) => {
  if (opt.forwardHoursOnly !== true) {
    return results;
  }

  // If the date is today and there is no AM/PM (meridiem) specified,
  // let all the time be after the current time.
  results.forEach((result) => {
    changeDate(result.start, result.ref);
    if (result.end) {
      changeDate(result.end, result.ref);
    }
  });

  return results;

  function changeDate(component, ref) {
    if (!component.isCertain('meridiem')
      && component.get('year') === ref.getFullYear()
      && component.get('month') === ref.getMonth() + 1
      && component.get('day') === ref.getDate()
      && component.get('hour') < ref.getHours()) {
      component.assign('meridiem', 1);
      component.assign('hour', component.get('hour') + 12);
    }
  }
};

const customChrono = new chrono.Chrono(chrono.options.casualOption());
customChrono.parsers.push(dayPeriodsParser);
customChrono.refiners.push(forwardHoursRefiner);

export default {
  parse: (phrase) => customChrono.parse(phrase, new Date(), {
    forwardDatesOnly: true,
    forwardHoursOnly: true,
  }),
};
<commit_msg>Use moment.js in the chrono refiner. (#92)<commit_after>import chrono from 'components/chrono';

/**
 * Parse day periods according to CLDR.
 * @see http://www.unicode.org/cldr/charts/29/verify/dates/en.html
 */
const dayPeriodsParser = new chrono.Parser();
dayPeriodsParser.pattern =
  () => new RegExp('midnight|morning|in the morning|noon|' +
    'afternoon|in the afternoon|evening|in the evening|night|at night', 'i');
dayPeriodsParser.extract = (text, ref, match) => {
  let hour;
  let meridiem;

  switch (match[0].toLowerCase()) {
    case 'midnight':
      hour = 0;
      meridiem = 0;
      break;
    case 'morning':
    case 'in the morning':
      hour = 9;
      meridiem = 0;
      break;
    case 'noon':
      hour = 12;
      meridiem = 1;
      break;
    case 'afternoon':
    case 'in the afternoon':
      hour = 15;
      meridiem = 1;
      break;
    case 'evening':
    case 'in the evening':
      hour = 19;
      meridiem = 1;
      break;
    case 'night':
    case 'at night':
      hour = 10;
      meridiem = 1;
      break;
  }

  return new chrono.ParsedResult({
    ref,
    text: match[0],
    index: match.index,
    start: {
      hour,
      meridiem,
    },
  });
};

/**
 * When the meridiem is not specified, set the time to after the current time.
 * `at 5 today` (current time is 3pm) => `5pm`.
 */
const forwardHoursRefiner = new chrono.Refiner();
forwardHoursRefiner.refine = (text, results, opt = {}) => {
  if (opt.forwardHoursOnly !== true) {
    return results;
  }

  // If the date is today and there is no AM/PM (meridiem) specified,
  // let all the time be after the current time.
  results.forEach((result) => {
    changeDate(result.start, result.ref);
    if (result.end) {
      changeDate(result.end, result.ref);
    }
  });

  return results;

  function changeDate(component, ref) {
    if (!component.isCertain('meridiem')
      && component.moment(ref).isSame(component, 'day')
      && component.get('hour') <= ref.getHours()) {
      component.assign('meridiem', 1);
      component.assign('hour', component.get('hour') + 12);
    }
  }
};

const customChrono = new chrono.Chrono(chrono.options.casualOption());
customChrono.parsers.push(dayPeriodsParser);
customChrono.refiners.push(forwardHoursRefiner);

export default {
  parse: (phrase) => customChrono.parse(phrase, new Date(), {
    forwardDatesOnly: true,
    forwardHoursOnly: true,
  }),
};
<|endoftext|>