<commit_before>'use strict';

describe('hide-show', function() {

    var markUp =
            '
' +
                '
Text content to be hidden text content to be hidden text content to be hidden text content to be hidden
' +
            '
',
        testElement;

    var markUp2 =
            '
' +
                '
Contact details
' +
                '
' +
                    '
Telephone 01234 567 890
' +
                    '
Email test@test.com
' +
                '
' +
            '
',
        testElement2;

    beforeEach(function() {
        testElement = $(markUp);
    });

    it('depends on jQuery', function() {
        expect($).toBeDefined();
    });

    it('should be protected against multiple instantiations', function() {
        var plugin = testElement.hideShow();
        expect(plugin === testElement.hideShow()).toBe(true);
    });

    describe('- plugin init', function() {

        beforeEach(function() {
            testElement.hideShow();
        });

        it('should be available with the showHide identifier', function() {
            expect($('

').hideShow).toBeDefined();
        });

        it('should add a class and ID to the content to be hidden', function() {
            expect(testElement.hasClass('js-hide-show_content')).toBe(true);
            expect(testElement.attr('id')).toContain('content');
        });

        it('should set the state to visible by default', function() {
            expect(testElement.hasClass('js-hide-show_content--expanded')).toBe(true);
            expect(testElement.attr('aria-hidden')).toBe('false');
            expect(testElement.css('display')).toBe('block');

            expect(testElement.siblings('.js-hide-show_btn').attr('aria-expanded')).toBe('true');
        });

        it('should insert the trigger element before the content by default', function() {
            expect(testElement.prev('.js-hide-show_btn').length).toBe(1);
        });

        describe('- createTriggerElement function', function() {

            it('should create the trigger element', function() {
                var testElementId = testElement.attr('id');

                expect(testElement.siblings('.js-hide-show_btn').attr('aria-controls')).toBe(testElementId);
                expect(testElement.siblings('.js-hide-show_btn').hasClass('js-hide-show_btn')).toBe(true);
                expect(testElement.siblings('.js-hide-show_btn').text()).toBe('Hide Content');
            });
        });
    });

    describe('- toggle function', function() {

        beforeEach(function() {
            testElement.hideShow();
            spyOn(jQuery.fn, 'slideUp');
            spyOn(jQuery.fn, 'slideDown');
        });

        it('should toggle the content open when closed', function() {
            var button = testElement.siblings('.js-hide-show_btn');

            button.click();
            expect(jQuery.fn.slideUp).toHaveBeenCalled();
        });

        it('should toggle the content closed when open', function() {
            var button = testElement.siblings('.js-hide-show_btn');

            testElement.data('plugin_hideShow').close();

            button.click();
            expect(jQuery.fn.slideDown).toHaveBeenCalled();
        });
    });

    describe('- open method', function() {

        beforeEach(function() {
            testElement.hideShow();
            spyOn(jQuery.fn, 'slideDown');
        });

        it('should open the content when the trigger element is clicked', function() {
            var button = testElement.siblings('.js-hide-show_btn');

            testElement.data('plugin_hideShow').close();
            button.click();

            expect(testElement.hasClass('js-hide-show_content--expanded')).toBe(true);
            expect(testElement.attr('aria-hidden')).toBe('false');
            expect(jQuery.fn.slideDown).toHaveBeenCalled();
        });

        it('should update the trigger element when it is clicked', function() {
            var button = testElement.siblings('.js-hide-show_btn');

            testElement.data('plugin_hideShow').close();
            button.click();

            expect(button.hasClass('js-hide-show_btn--expanded')).toBe(true);
            expect(button.attr('aria-expanded')).toBe('true');
            expect(button.text()).toBe('Hide Content');
        });
    });

    describe('- close method', function() {

        beforeEach(function() {
            testElement.hideShow();
            spyOn(jQuery.fn, 'slideUp');
        });

        it('should close the content when the trigger element is clicked', function() {
            var button = testElement.siblings('.js-hide-show_btn');

            button.click();

            expect(testElement.hasClass('js-hide-show_content--collapsed')).toBe(true);
            expect(testElement.attr('aria-hidden')).toBe('true');
            expect(jQuery.fn.slideUp).toHaveBeenCalled();
        });

        it('should update the trigger element when it is clicked', function() {
            var button = testElement.siblings('.js-hide-show_btn');

            button.click();

            expect(button.hasClass('js-hide-show_btn--collapsed')).toBe(true);
            expect(button.attr('aria-expanded')).toBe('false');
            expect(button.text()).toBe('Show Content');
        });
    });

    describe('- rebuild method', function() {

        it('should reinitiate the plugin', function() {
            var plugin = testElement.hideShow();

            plugin.data('plugin_hideShow').destroy();
            plugin.data('plugin_hideShow').rebuild();

            expect(plugin === testElement.hideShow()).toBe(true);
        });
    });

    describe('- destroy method', function() {

        beforeEach(function() {
            testElement2 = $(markUp2);

            testElement.hideShow();

            testElement.data('plugin_hideShow').destroy();
        });

        it('should reset the content element back to its original state', function() {
            expect(testElement.attr('aria-hidden')).toBe(undefined);
            expect(testElement.attr('id')).toBe(undefined);
            expect(testElement.attr('style')).toBe(undefined);
            expect(testElement.hasClass('js-hide-show_content')).toBe(false);
            expect(testElement.hasClass('js-hide-show_content--collapsed')).toBe(false);
            expect(testElement.hasClass('js-hide-show_content--expanded')).toBe(false);
        });

        it('should remove the trigger element', function() {
            expect(testElement.siblings('.js-hide-show_btn').length).toBe(0);
        });

        it('should reset the trigger element back to its original state', function() {
            var trigger = $('#trigger', testElement2);

            testElement2.find('div').hideShow({
                triggerElementTarget: trigger
            });

            testElement2.find('div').data('plugin_hideShow').destroy();

            var testElementId = testElement2.find('div').attr('id');

            expect(trigger.attr('aria-controls')).toBe(undefined);
            expect(trigger.attr('aria-expanded')).toBe(undefined);
            expect(trigger.attr('role')).toBe(undefined);
            expect(trigger.attr('tabindex')).toBe(undefined);
            expect(trigger.hasClass('js-hide-show_btn')).toBe(false);
            expect(trigger.hasClass('js-hide-show_btn--expanded')).toBe(false);
            expect(trigger.hasClass('js-hide-show_btn--collapsed')).toBe(false);
        });
    });

    describe('- plugin options', function() {

        beforeEach(function() {
            testElement2 = $(markUp2);
        });

        it('should add a tabindex of -1 to the element if the trigger does not immediately precede it', function() {
            testElement2.find('div').hideShow({
                insertMethod: 'append',
                insertTriggerLocation: testElement2
            });

            expect(testElement2.find('div').attr('tabindex')).toBe('-1');
        });

        it('should hide the content if the state is set to "hidden"', function() {
            testElement.hideShow({
                state: 'hidden'
            });

            expect(testElement.hasClass('js-hide-show_content--collapsed')).toBe(true);
            expect(testElement.attr('aria-hidden')).toBe('true');
            expect(testElement.css('display')).toBe('none');

            expect(testElement.siblings('.js-hide-show_btn').attr('aria-expanded')).toBe('false');
            expect(testElement.siblings('.js-hide-show_btn').text()).toBe('Show Content');
        });

        it('should insert the trigger element after the content if the insertMethod is set to "after"', function() {
            testElement2.find('div').hideShow({
                insertMethod: 'after',
                insertTriggerLocation: testElement2
            });

            expect(testElement2.next('.js-hide-show_btn').length).toBe(1);
        });

        it('should insert the trigger element after the content if the insertMethod is set to "append"', function() {
            testElement2.find('div').hideShow({
                insertMethod: 'append',
                insertTriggerLocation: testElement2
            });

            expect(testElement2.find('div').next('.js-hide-show_btn').length).toBe(1);
        });

        it('should insert the trigger element after the content if the insertMethod is set to "prepend"', function() {
            testElement2.find('div').hideShow({
                insertMethod: 'prepend',
                insertTriggerLocation: testElement2
            });

            expect(testElement2.find('h3').prev('.js-hide-show_btn').length).toBe(1);
        });

        it('should default to inserting the trigger element before the content if the insertMethod is not "after", "append" or "prepend"', function() {
            testElement2.find('div').hideShow({
                insertMethod: '',
                insertTriggerLocation: testElement2.find('div')
            });

            expect(testElement2.find('div').prev('.js-hide-show_btn').length).toBe(1);
        });

        it('should use an existing element if the triggerElementTarget option is given', function() {
            var trigger = $('#trigger', testElement2);

            testElement2.find('div').hideShow({
                triggerElementTarget: trigger
            });

            var testElementId = testElement2.find('div').attr('id');

            expect(trigger.attr('aria-controls')).toBe(testElementId);
            expect(trigger.hasClass('js-hide-show_btn')).toBe(true);
            expect(trigger.attr('role')).toBe('button');
            expect(trigger.attr('tabindex')).toBe('0');
        });

        it('should customise the "hideText" used for the button', function() {
            testElement.hideShow({
                hideText: 'Collapse details'
            });

            expect(testElement.siblings('.js-hide-show_btn').text()).toBe('Collapse details');
        });

        it('should customise the "showText" used for the button', function() {
            testElement.hideShow({
                showText: 'Expand details',
                state: 'hidden'
            });

            expect(testElement.siblings('.js-hide-show_btn').text()).toBe('Expand details');
        });

        it('should customise the class on the button', function() {
            testElement.hideShow({
                buttonClass: 'trigger-button'
            });
            expect(testElement.siblings('.trigger-button').length).toBe(1);
        });

        it('should customise the collapsed class on the button', function() {
            testElement.hideShow({
                buttonExpandedClass: 'collapsed'
            });
            expect(testElement.siblings('.js-hide-show_btn').hasClass('collapsed')).toBe(true);
        });

        it('should customise the expanded class on the button', function() {
            testElement.hideShow({
                buttonExpandedClass: 'expanded'
            });
            expect(testElement.siblings('.js-hide-show_btn').hasClass('expanded')).toBe(true);
        });

        it('should customise the class on the container', function() {
            testElement.hideShow({
                containerClass: 'container'
            });
            expect(testElement.hasClass('container')).toBe(true);
        });

        it('should customise the collapsed class on the container', function() {
            testElement.hideShow({
                containerCollapsedClass: 'collapsed',
                state: 'hidden'
            });
            expect(testElement.hasClass('collapsed')).toBe(true);
        });

        it('should customise the expanded class on the container', function() {
            testElement.hideShow({
                containerExpandedClass: 'expanded'
            });
            expect(testElement.hasClass('expanded')).toBe(true);
        });

        it('should trigger "callbackBeforeClose" when the close public method is called', function() {
            var mocks,
                el,
                beforeClose = false;

            mocks = {
                callbackBeforeClose: function(testElement) {
                    beforeClose = true;
                }
            },
            el = testElement.hideShow({
                callbackBeforeClose: mocks.callbackBeforeClose
            });

            el.data('plugin_hideShow').close();

            expect(beforeClose).toBe(true);
        });

        it('should trigger "callbackBeforeOpen" when the open public method is called', function() {
            var mocks,
                el,
                beforeOpen = false;

            mocks = {
                callbackBeforeOpen: function(testElement) {
                    beforeOpen = true;
                }
            },
            el = testElement.hideShow({
                callbackBeforeOpen: mocks.callbackBeforeOpen
            });

            el.data('plugin_hideShow').open();

            expect(beforeOpen).toBe(true);
        });

        it('should trigger "callbackCreate" once the plugin has been created', function() {
            var mocks,
                el,
                created = false;

            mocks = {
                callbackCreate: function(testElement) {
                    created = true;
                }
            },
            el = testElement.hideShow({
                callbackCreate: mocks.callbackCreate
            });

            expect(created).toBe(true);
        });

        it('should trigger "callbackDestroy" once the plugin has been destroyed', function() {
            var mocks,
                el,
                destroyed = false;

            mocks = {
                callbackDestroy: function(testElement) {
                    destroyed = true;
                }
            },
            el = testElement.hideShow({
                callbackDestroy: mocks.callbackDestroy
            });

            el.data('plugin_hideShow').destroy();

            expect(destroyed).toBe(true);
        });

        it('should trigger "callbackClosed" when the close public method is called', function() {
            var mocks,
                el,
                closed = false;

            mocks = {
                callbackClosed: function(testElement) {
                    closed = true;
                }
            },
            el = testElement.hideShow({
                callbackClosed: mocks.callbackClosed
            });

            el.data('plugin_hideShow').close();

            expect(closed).toBe(true);
        });

        it('should trigger "callbackOpened" when the open public method is called', function() {
            var mocks,
                el,
                opened = false;

            mocks = {
                callbackOpened: function(testElement) {
                    opened = true;
                }
            },
            el = testElement.hideShow({
                callbackOpened: mocks.callbackOpened
            });

            el.data('plugin_hideShow').open();

            expect(opened).toBe(true);
        });
    });
});<commit_msg>alphabetically sorted the option tests<commit_after>'use strict';

describe('hide-show', function() {

    var markUp =
            '
' +
                '
Text content to be hidden text content to be hidden text content to be hidden text content to be hidden
' +
            '
',
        testElement;

    var markUp2 =
            '
' +
                '
Contact details
' +
                '
' +
                    '
Telephone 01234 567 890
' +
                    '
Email test@test.com
' +
                '
' +
            '
',
        testElement2;

    beforeEach(function() {
        testElement = $(markUp);
    });

    it('depends on jQuery', function() {
        expect($).toBeDefined();
    });

    it('should be protected against multiple instantiations', function() {
        var plugin = testElement.hideShow();
        expect(plugin === testElement.hideShow()).toBe(true);
    });

    describe('- plugin init', function() {

        beforeEach(function() {
            testElement.hideShow();
        });

        it('should be available with the showHide identifier', function() {
            expect($('

').hideShow).toBeDefined();
        });

        it('should add a class and ID to the content to be hidden', function() {
            expect(testElement.hasClass('js-hide-show_content')).toBe(true);
            expect(testElement.attr('id')).toContain('content');
        });

        it('should set the state to visible by default', function() {
            expect(testElement.hasClass('js-hide-show_content--expanded')).toBe(true);
            expect(testElement.attr('aria-hidden')).toBe('false');
            expect(testElement.css('display')).toBe('block');

            expect(testElement.siblings('.js-hide-show_btn').attr('aria-expanded')).toBe('true');
        });

        it('should insert the trigger element before the content by default', function() {
            expect(testElement.prev('.js-hide-show_btn').length).toBe(1);
        });

        describe('- createTriggerElement function', function() {

            it('should create the trigger element', function() {
                var testElementId = testElement.attr('id');

                expect(testElement.siblings('.js-hide-show_btn').attr('aria-controls')).toBe(testElementId);
                expect(testElement.siblings('.js-hide-show_btn').hasClass('js-hide-show_btn')).toBe(true);
                expect(testElement.siblings('.js-hide-show_btn').text()).toBe('Hide Content');
            });
        });
    });

    describe('- toggle function', function() {

        beforeEach(function() {
            testElement.hideShow();
            spyOn(jQuery.fn, 'slideUp');
            spyOn(jQuery.fn, 'slideDown');
        });

        it('should toggle the content open when closed', function() {
            var button = testElement.siblings('.js-hide-show_btn');

            button.click();
            expect(jQuery.fn.slideUp).toHaveBeenCalled();
        });

        it('should toggle the content closed when open', function() {
            var button = testElement.siblings('.js-hide-show_btn');

            testElement.data('plugin_hideShow').close();

            button.click();
            expect(jQuery.fn.slideDown).toHaveBeenCalled();
        });
    });

    describe('- open method', function() {

        beforeEach(function() {
            testElement.hideShow();
            spyOn(jQuery.fn, 'slideDown');
        });

        it('should open the content when the trigger element is clicked', function() {
            var button = testElement.siblings('.js-hide-show_btn');

            testElement.data('plugin_hideShow').close();
            button.click();

            expect(testElement.hasClass('js-hide-show_content--expanded')).toBe(true);
            expect(testElement.attr('aria-hidden')).toBe('false');
            expect(jQuery.fn.slideDown).toHaveBeenCalled();
        });

        it('should update the trigger element when it is clicked', function() {
            var button = testElement.siblings('.js-hide-show_btn');

            testElement.data('plugin_hideShow').close();
            button.click();

            expect(button.hasClass('js-hide-show_btn--expanded')).toBe(true);
            expect(button.attr('aria-expanded')).toBe('true');
            expect(button.text()).toBe('Hide Content');
        });
    });

    describe('- close method', function() {

        beforeEach(function() {
            testElement.hideShow();
            spyOn(jQuery.fn, 'slideUp');
        });

        it('should close the content when the trigger element is clicked', function() {
            var button = testElement.siblings('.js-hide-show_btn');

            button.click();

            expect(testElement.hasClass('js-hide-show_content--collapsed')).toBe(true);
            expect(testElement.attr('aria-hidden')).toBe('true');
            expect(jQuery.fn.slideUp).toHaveBeenCalled();
        });

        it('should update the trigger element when it is clicked', function() {
            var button = testElement.siblings('.js-hide-show_btn');

            button.click();

            expect(button.hasClass('js-hide-show_btn--collapsed')).toBe(true);
            expect(button.attr('aria-expanded')).toBe('false');
            expect(button.text()).toBe('Show Content');
        });
    });

    describe('- rebuild method', function() {

        it('should reinitiate the plugin', function() {
            var plugin = testElement.hideShow();

            plugin.data('plugin_hideShow').destroy();
            plugin.data('plugin_hideShow').rebuild();

            expect(plugin === testElement.hideShow()).toBe(true);
        });
    });

    describe('- destroy method', function() {

        beforeEach(function() {
            testElement2 = $(markUp2);

            testElement.hideShow();

            testElement.data('plugin_hideShow').destroy();
        });

        it('should reset the content element back to its original state', function() {
            expect(testElement.attr('aria-hidden')).toBe(undefined);
            expect(testElement.attr('id')).toBe(undefined);
            expect(testElement.attr('style')).toBe(undefined);
            expect(testElement.hasClass('js-hide-show_content')).toBe(false);
            expect(testElement.hasClass('js-hide-show_content--collapsed')).toBe(false);
            expect(testElement.hasClass('js-hide-show_content--expanded')).toBe(false);
        });

        it('should remove the trigger element', function() {
            expect(testElement.siblings('.js-hide-show_btn').length).toBe(0);
        });

        it('should reset the trigger element back to its original state', function() {
            var trigger = $('#trigger', testElement2);

            testElement2.find('div').hideShow({
                triggerElementTarget: trigger
            });

            testElement2.find('div').data('plugin_hideShow').destroy();

            var testElementId = testElement2.find('div').attr('id');

            expect(trigger.attr('aria-controls')).toBe(undefined);
            expect(trigger.attr('aria-expanded')).toBe(undefined);
            expect(trigger.attr('role')).toBe(undefined);
            expect(trigger.attr('tabindex')).toBe(undefined);
            expect(trigger.hasClass('js-hide-show_btn')).toBe(false);
            expect(trigger.hasClass('js-hide-show_btn--expanded')).toBe(false);
            expect(trigger.hasClass('js-hide-show_btn--collapsed')).toBe(false);
        });
    });

    describe('- plugin options', function() {

        beforeEach(function() {
            testElement2 = $(markUp2);
        });

        it('should add a tabindex of -1 to the element if the trigger does not immediately precede it', function() {
            testElement2.find('div').hideShow({
                insertMethod: 'append',
                insertTriggerLocation: testElement2
            });

            expect(testElement2.find('div').attr('tabindex')).toBe('-1');
        });

        it('should hide the content if the state is set to "hidden"', function() {
            testElement.hideShow({
                state: 'hidden'
            });

            expect(testElement.hasClass('js-hide-show_content--collapsed')).toBe(true);
            expect(testElement.attr('aria-hidden')).toBe('true');
            expect(testElement.css('display')).toBe('none');

            expect(testElement.siblings('.js-hide-show_btn').attr('aria-expanded')).toBe('false');
            expect(testElement.siblings('.js-hide-show_btn').text()).toBe('Show Content');
        });

        it('should insert the trigger element after the content if the insertMethod is set to "after"', function() {
            testElement2.find('div').hideShow({
                insertMethod: 'after',
                insertTriggerLocation: testElement2
            });

            expect(testElement2.next('.js-hide-show_btn').length).toBe(1);
        });

        it('should insert the trigger element after the content if the insertMethod is set to "append"', function() {
            testElement2.find('div').hideShow({
                insertMethod: 'append',
                insertTriggerLocation: testElement2
            });

            expect(testElement2.find('div').next('.js-hide-show_btn').length).toBe(1);
        });

        it('should insert the trigger element after the content if the insertMethod is set to "prepend"', function() {
            testElement2.find('div').hideShow({
                insertMethod: 'prepend',
                insertTriggerLocation: testElement2
            });

            expect(testElement2.find('h3').prev('.js-hide-show_btn').length).toBe(1);
        });

        it('should default to inserting the trigger element before the content if the insertMethod is not "after", "append" or "prepend"', function() {
            testElement2.find('div').hideShow({
                insertMethod: '',
                insertTriggerLocation: testElement2.find('div')
            });

            expect(testElement2.find('div').prev('.js-hide-show_btn').length).toBe(1);
        });

        it('should use an existing element if the triggerElementTarget option is given', function() {
            var trigger = $('#trigger', testElement2);

            testElement2.find('div').hideShow({
                triggerElementTarget: trigger
            });

            var testElementId = testElement2.find('div').attr('id');

            expect(trigger.attr('aria-controls')).toBe(testElementId);
            expect(trigger.hasClass('js-hide-show_btn')).toBe(true);
            expect(trigger.attr('role')).toBe('button');
            expect(trigger.attr('tabindex')).toBe('0');
        });

        it('should customise the "hideText" used for the button', function() {
            testElement.hideShow({
                hideText: 'Collapse details'
            });

            expect(testElement.siblings('.js-hide-show_btn').text()).toBe('Collapse details');
        });

        it('should customise the "showText" used for the button', function() {
            testElement.hideShow({
                showText: 'Expand details',
                state: 'hidden'
            });

            expect(testElement.siblings('.js-hide-show_btn').text()).toBe('Expand details');
        });

        it('should customise the class on the button', function() {
            testElement.hideShow({
                buttonClass: 'trigger-button'
            });
            expect(testElement.siblings('.trigger-button').length).toBe(1);
        });

        it('should customise the collapsed class on the button', function() {
            testElement.hideShow({
                buttonExpandedClass: 'collapsed'
            });
            expect(testElement.siblings('.js-hide-show_btn').hasClass('collapsed')).toBe(true);
        });

        it('should customise the expanded class on the button', function() {
            testElement.hideShow({
                buttonExpandedClass: 'expanded'
            });
            expect(testElement.siblings('.js-hide-show_btn').hasClass('expanded')).toBe(true);
        });

        it('should customise the class on the container', function() {
            testElement.hideShow({
                containerClass: 'container'
            });
            expect(testElement.hasClass('container')).toBe(true);
        });

        it('should customise the collapsed class on the container', function() {
            testElement.hideShow({
                containerCollapsedClass: 'collapsed',
                state: 'hidden'
            });
            expect(testElement.hasClass('collapsed')).toBe(true);
        });

        it('should customise the expanded class on the container', function() {
            testElement.hideShow({
                containerExpandedClass: 'expanded'
            });
            expect(testElement.hasClass('expanded')).toBe(true);
        });

        it('should trigger "callbackBeforeClose" when the close public method is called', function() {
            var mocks,
                el,
                beforeClose = false;

            mocks = {
                callbackBeforeClose: function(testElement) {
                    beforeClose = true;
                }
            },
            el = testElement.hideShow({
                callbackBeforeClose: mocks.callbackBeforeClose
            });

            el.data('plugin_hideShow').close();

            expect(beforeClose).toBe(true);
        });

        it('should trigger "callbackBeforeOpen" when the open public method is called', function() {
            var mocks,
                el,
                beforeOpen = false;

            mocks = {
                callbackBeforeOpen: function(testElement) {
                    beforeOpen = true;
                }
            },
            el = testElement.hideShow({
                callbackBeforeOpen: mocks.callbackBeforeOpen
            });

            el.data('plugin_hideShow').open();

            expect(beforeOpen).toBe(true);
        });

        it('should trigger "callbackClosed" when the close public method is called', function() {
            var mocks,
                el,
                closed = false;

            mocks = {
                callbackClosed: function(testElement) {
                    closed = true;
                }
            },
            el = testElement.hideShow({
                callbackClosed: mocks.callbackClosed
            });

            el.data('plugin_hideShow').close();

            expect(closed).toBe(true);
        });

        it('should trigger "callbackCreate" once the plugin has been created', function() {
            var mocks,
                el,
                created = false;

            mocks = {
                callbackCreate: function(testElement) {
                    created = true;
                }
            },
            el = testElement.hideShow({
                callbackCreate: mocks.callbackCreate
            });

            expect(created).toBe(true);
        });

        it('should trigger "callbackDestroy" once the plugin has been destroyed', function() {
            var mocks,
                el,
                destroyed = false;

            mocks = {
                callbackDestroy: function(testElement) {
                    destroyed = true;
                }
            },
            el = testElement.hideShow({
                callbackDestroy: mocks.callbackDestroy
            });

            el.data('plugin_hideShow').destroy();

            expect(destroyed).toBe(true);
        });

        it('should trigger "callbackOpened" when the open public method is called', function() {
            var mocks,
                el,
                opened = false;

            mocks = {
                callbackOpened: function(testElement) {
                    opened = true;
                }
            },
            el = testElement.hideShow({
                callbackOpened: mocks.callbackOpened
            });

            el.data('plugin_hideShow').open();

            expect(opened).toBe(true);
        });
    });
});<|endoftext|>


<commit_before>(function() {
    'use strict';

    /**
     * usage: <textarea ng-model="content" redactor></textarea>
     *
     *    additional options:
     *      redactor: hash (pass in a redactor options hash)
     *
     */

    var redactorOptions = {};

    angular.module('angular-redactor', [])
        .constant('redactorOptions', redactorOptions)
        .directive('redactor', ['$timeout', function($timeout) {
            return {
                restrict: 'A',
                require: 'ngModel',
                link: function(scope, element, attrs, ngModel) {

                    // Expose scope var with loaded state of Redactor
                    scope.redactorLoaded = false;

                    var updateModel = function updateModel(value) {
                            // $timeout to avoid $digest collision
                            $timeout(function() {
                                scope.$apply(function() {
                                    ngModel.$setViewValue(value);
                                });
                            });
                        },
                        options = {
                            changeCallback: updateModel
                        },
                        additionalOptions = attrs.redactor ?
                            scope.$eval(attrs.redactor) : {},
                        editor,
                        $_element = angular.element(element);

                    angular.extend(options, redactorOptions, additionalOptions);

                    // prevent collision with the constant values on ChangeCallback
                    if(!angular.isUndefined(redactorOptions.changeCallback)) {
                        options.changeCallback = function() {
                            updateModel.call(this);
                            redactorOptions.changeCallback.call(this);
                        }
                    }

                    // put in timeout to avoid $digest collision.  call render() to
                    // set the initial value.
                    $timeout(function() {
                        editor = $_element.redactor(options);
                        ngModel.$render();
                    });

                    ngModel.$render = function() {
                        if(angular.isDefined(editor)) {
                            $timeout(function() {
                                $_element.redactor('insert.set', ngModel.$viewValue || '');
                                scope.redactorLoaded = true;
                            });
                        }
                    };
                }
            };
        }]);
})();

<commit_msg>Update angular-redactor.js<commit_after>(function() {
    'use strict';

    /**
     * usage: <textarea ng-model="content" redactor></textarea>
     *
     *    additional options:
     *      redactor: hash (pass in a redactor options hash)
     *
     */

    var redactorOptions = {};

    angular.module('angular-redactor', [])
        .constant('redactorOptions', redactorOptions)
        .directive('redactor', ['$timeout', function($timeout) {
            return {
                restrict: 'A',
                require: 'ngModel',
                link: function(scope, element, attrs, ngModel) {

                    // Expose scope var with loaded state of Redactor
                    scope.redactorLoaded = false;

                    var updateModel = function updateModel(value) {
                            // $timeout to avoid $digest collision
                            $timeout(function() {
                                scope.$apply(function() {
                                    ngModel.$setViewValue(value);
                                });
                            });
                        },
                        options = {
                            changeCallback: updateModel
                        },
                        additionalOptions = attrs.redactor ?
                            scope.$eval(attrs.redactor) : {},
                        editor,
                        $_element = angular.element(element);

                    angular.extend(options, redactorOptions, additionalOptions);

                    // prevent collision with the constant values on ChangeCallback
                    var changeCallback = additionalOptions.changeCallback || redactorOptions.changeCallback;
                    if (changeCallback) {
                        options.changeCallback = function(value) {
                            updateModel.call(this, value);
                            changeCallback.call(this, value);
                        }
                    }

                    // put in timeout to avoid $digest collision.  call render() to
                    // set the initial value.
                    $timeout(function() {
                        editor = $_element.redactor(options);
                        ngModel.$render();
                    });

                    ngModel.$render = function() {
                        if(angular.isDefined(editor)) {
                            $timeout(function() {
                                $_element.redactor('insert.set', ngModel.$viewValue || '');
                                scope.redactorLoaded = true;
                            });
                        }
                    };
                }
            };
        }]);
})();

<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Redirect } from 'react-router-dom';
import { VOTING_NOT_STARTED, VOTING_IN_PROGRESS, VOTING_FINISHED } from 'common/actionTypes/issues';
import {
  adminCloseIssue,
  adminDeleteIssue,
  enableVoting,
  disableVoting,
} from 'features/adminButtons/actionCreators';
import { getIssueText, activeIssueExists, getIssue, getIssueKey } from 'features/issue/selectors';
import Button from '../../Button';
import Card from '../../Card';
import Dialog from '../../Dialog';
import ButtonIconText from '../../ButtonIconText';
import Pin from '../Pin';
import css from './Issue.css';

class Issue extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      redirectToEditIssue: false,
      showDeleteIssueDialog: false,
      showCloseIssueDialog: false,
      showDisableVotingDialog: false,
    };
  }

  onClickDeleteIssue() {
    this.setState({ showDeleteIssueDialog: true });
  }

  deleteIssue() {
    this.setState({ showDeleteIssueDialog: false });
    this.props.deleteIssue();
  }

  onClickCloseIssue() {
    this.setState({ showCloseIssueDialog: true });
  }

  closeIssue() {
    this.setState({ showCloseIssueDialog: false });
    this.props.closeIssue();
  }

  votingBtnOnClick() {
    if (this.props.issueStatus === VOTING_NOT_STARTED) {
      this.props.enableVoting();
    } else if(this.props.issueStatus === VOTING_IN_PROGRESS) {
      this.setState({showDisableVotingDialog: true});
    }
  }

  disableVoting(){
    this.setState({showDisableVotingDialog: false});
    this.props.disableVoting();
  }

  closeDeleteDialog() {
    this.setState({ showDeleteIssueDialog: false });
  }

  closeCloseDialog() {
    this.setState({ showCloseIssueDialog: false });
  }

  closeDisableVotingDialog() {
    this.setState({ showDisableVotingDialog: false });
  }

  render() {
    const {
      issueIsActive, issueStatus, issueText, pin, registrationOpen,
    } = this.props;
    const { showDeleteIssueDialog, showCloseIssueDialog, showDisableVotingDialog } = this.state;
    const votingInProgress = issueStatus === VOTING_IN_PROGRESS;
    let enableDisableVotingBtnText;
    if (issueStatus === VOTING_NOT_STARTED) enableDisableVotingBtnText = 'Start votering';
    else if (issueStatus === VOTING_IN_PROGRESS) enableDisableVotingBtnText = 'Avslutt votering';
    else enableDisableVotingBtnText = 'Votering er ferdig';
    return (
      <Card classes={css.issue}>
        {this.state.redirectToEditIssue && <Redirect to="/admin/question" />}
        <Dialog
          title="Bekreft sletting av sak"
          subtitle={`Bekreft sletting av "${issueText}"`}
          visible={showDeleteIssueDialog}
          onClose={() => this.closeDeleteDialog()}
        >
          <Button background onClick={() => this.deleteIssue()}>Bekreft</Button>
          <Button
            background
            onClick={() => this.closeDeleteDialog()}
          >Avbryt</Button>
        </Dialog>
        <Dialog
          title="Bekreft avslutting av sak"
          subtitle={`Bekreft avslutting av "${issueText}"`}
          visible={showCloseIssueDialog}
          onClose={() => this.closeCloseDialog()}
        >
          <Button background onClick={() => this.closeIssue()}>Bekreft</Button>
          <Button
            background
            onClick={() => this.closeCloseDialog()}
          >Avbryt</Button>
        </Dialog>
        <Dialog
          title="Bekreft avslutting av votering"
          subtitle={`Bekreft avslutting av votering for "${issueText}"`}
          visible={showDisableVotingDialog}
          onClose={() => this.closeDisableVotingDialog()}
        >
          <Button background onClick={() => this.disableVoting()}>Bekreft</Button>
          <Button
            background
            onClick={() => this.closeDisableVotingDialog()}
          >Avbryt</Button>
        </Dialog>

            <Pin code={registrationOpen ? pin : 'Registreringen er ikke åpen.'} />

Aktiv sak

          {issueIsActive &&

            <ButtonIconText
              text={enableDisableVotingBtnText}
              iconClass={votingInProgress || issueStatus === VOTING_FINISHED
                ? css.lock : css.unlock}
              onClick={() => this.votingBtnOnClick()}
              disabled={this.props.issueStatus === VOTING_FINISHED}
            />
            <ButtonIconText
              text="Rediger"
              iconClass={css.edit}
              onClick={() => { this.setState({ redirectToEditIssue: true }); }}
            />
            <ButtonIconText text="Avslutt" iconClass={css.end} onClick={() => this.onClickCloseIssue()} />
            <ButtonIconText
              text="Slett"
              iconClass={css.delete}
              onClick={() => this.onClickDeleteIssue()}
            />

          }

{issueText}

      </Card>
    );
  }
}

Issue.defaultProps = {
  pin: 0,
  issueStatus: VOTING_NOT_STARTED,
  registrationOpen: false,
};

Issue.propTypes = {
  closeIssue: PropTypes.func.isRequired,
  deleteIssue: PropTypes.func.isRequired,
  disableVoting: PropTypes.func.isRequired,
  enableVoting: PropTypes.func.isRequired,
  issueIsActive: PropTypes.bool.isRequired,
  issueStatus: PropTypes.string,
  issueText: PropTypes.string.isRequired,
  pin: PropTypes.number,
  registrationOpen: PropTypes.bool,
};

const mapStateToProps = state => ({
  issueIsActive: activeIssueExists(state),
  issueStatus: getIssueKey(state, 'status'),
  issueText: getIssueText(state),
  issue: getIssue(state),
  pin: state.meeting.pin,
  registrationOpen: state.meeting.registrationOpen,
});

// Following this example since we need id from state
// https://github.com/reactjs/react-redux/issues/237#issuecomment-168817739
const mergeProps = (stateProps, dispatchProps, ownProps) => {
  const { dispatch } = dispatchProps;
  return {
    ...ownProps,
    ...stateProps,
    closeIssue: () => {
      dispatch(adminCloseIssue({ issue: stateProps.issue.id }));
    },
    deleteIssue: () => {
      dispatch(adminDeleteIssue({ issue: stateProps.issue.id }));
    },
    disableVoting: () => {
      dispatch(disableVoting({ issue: stateProps.issue.id }));
    },
    enableVoting: () => {
      dispatch(enableVoting({ issue: stateProps.issue.id }));
    },
  };
};

export default Issue;
export const IssueContainer = connect(
  mapStateToProps,
  null,
  mergeProps,
)(Issue);
<commit_msg>Linting<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Redirect } from 'react-router-dom';
import { VOTING_NOT_STARTED, VOTING_IN_PROGRESS, VOTING_FINISHED } from 'common/actionTypes/issues';
import {
  adminCloseIssue,
  adminDeleteIssue,
  enableVoting,
  disableVoting,
} from 'features/adminButtons/actionCreators';
import { getIssueText, activeIssueExists, getIssue, getIssueKey } from 'features/issue/selectors';
import Button from '../../Button';
import Card from '../../Card';
import Dialog from '../../Dialog';
import ButtonIconText from '../../ButtonIconText';
import Pin from '../Pin';
import css from './Issue.css';

class Issue extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      redirectToEditIssue: false,
      showDeleteIssueDialog: false,
      showCloseIssueDialog: false,
      showDisableVotingDialog: false,
    };
  }

  onClickDeleteIssue() {
    this.setState({ showDeleteIssueDialog: true });
  }

  onClickCloseIssue() {
    this.setState({ showCloseIssueDialog: true });
  }

  deleteIssue() {
    this.setState({ showDeleteIssueDialog: false });
    this.props.deleteIssue();
  }

  closeIssue() {
    this.setState({ showCloseIssueDialog: false });
    this.props.closeIssue();
  }

  votingBtnOnClick() {
    if (this.props.issueStatus === VOTING_NOT_STARTED) {
      this.props.enableVoting();
    } else if (this.props.issueStatus === VOTING_IN_PROGRESS) {
      this.setState({ showDisableVotingDialog: true });
    }
  }

  disableVoting() {
    this.setState({ showDisableVotingDialog: false });
    this.props.disableVoting();
  }

  closeDeleteDialog() {
    this.setState({ showDeleteIssueDialog: false });
  }

  closeCloseDialog() {
    this.setState({ showCloseIssueDialog: false });
  }

  closeDisableVotingDialog() {
    this.setState({ showDisableVotingDialog: false });
  }

  render() {
    const {
      issueIsActive, issueStatus, issueText, pin, registrationOpen,
    } = this.props;
    const { showDeleteIssueDialog, showCloseIssueDialog, showDisableVotingDialog } = this.state;
    const votingInProgress = issueStatus === VOTING_IN_PROGRESS;
    let enableDisableVotingBtnText;
    if (issueStatus === VOTING_NOT_STARTED) enableDisableVotingBtnText = 'Start votering';
    else if (issueStatus === VOTING_IN_PROGRESS) enableDisableVotingBtnText = 'Avslutt votering';
    else enableDisableVotingBtnText = 'Votering er ferdig';
    return (
      <Card classes={css.issue}>
        {this.state.redirectToEditIssue && <Redirect to="/admin/question" />}
        <Dialog
          title="Bekreft sletting av sak"
          subtitle={`Bekreft sletting av "${issueText}"`}
          visible={showDeleteIssueDialog}
          onClose={() => this.closeDeleteDialog()}
        >
          <Button background onClick={() => this.deleteIssue()}>Bekreft</Button>
          <Button
            background
            onClick={() => this.closeDeleteDialog()}
          >Avbryt</Button>
        </Dialog>
        <Dialog
          title="Bekreft avslutting av sak"
          subtitle={`Bekreft avslutting av "${issueText}"`}
          visible={showCloseIssueDialog}
          onClose={() => this.closeCloseDialog()}
        >
          <Button background onClick={() => this.closeIssue()}>Bekreft</Button>
          <Button
            background
            onClick={() => this.closeCloseDialog()}
          >Avbryt</Button>
        </Dialog>
        <Dialog
          title="Bekreft avslutting av votering"
          subtitle={`Bekreft avslutting av votering for "${issueText}"`}
          visible={showDisableVotingDialog}
          onClose={() => this.closeDisableVotingDialog()}
        >
          <Button background onClick={() => this.disableVoting()}>Bekreft</Button>
          <Button
            background
            onClick={() => this.closeDisableVotingDialog()}
          >Avbryt</Button>
        </Dialog>

            <Pin code={registrationOpen ? pin : 'Registreringen er ikke åpen.'} />

Aktiv sak

          {issueIsActive &&

            <ButtonIconText
              text={enableDisableVotingBtnText}
              iconClass={votingInProgress || issueStatus === VOTING_FINISHED
                ? css.lock : css.unlock}
              onClick={() => this.votingBtnOnClick()}
              disabled={this.props.issueStatus === VOTING_FINISHED}
            />
            <ButtonIconText
              text="Rediger"
              iconClass={css.edit}
              onClick={() => { this.setState({ redirectToEditIssue: true }); }}
            />
            <ButtonIconText
              text="Avslutt" iconClass={css.end}
              onClick={() => this.onClickCloseIssue()}
            />
            <ButtonIconText
              text="Slett"
              iconClass={css.delete}
              onClick={() => this.onClickDeleteIssue()}
            />

          }

{issueText}

      </Card>
    );
  }
}

Issue.defaultProps = {
  pin: 0,
  issueStatus: VOTING_NOT_STARTED,
  registrationOpen: false,
};

Issue.propTypes = {
  closeIssue: PropTypes.func.isRequired,
  deleteIssue: PropTypes.func.isRequired,
  disableVoting: PropTypes.func.isRequired,
  enableVoting: PropTypes.func.isRequired,
  issueIsActive: PropTypes.bool.isRequired,
  issueStatus: PropTypes.string,
  issueText: PropTypes.string.isRequired,
  pin: PropTypes.number,
  registrationOpen: PropTypes.bool,
};

const mapStateToProps = state => ({
  issueIsActive: activeIssueExists(state),
  issueStatus: getIssueKey(state, 'status'),
  issueText: getIssueText(state),
  issue: getIssue(state),
  pin: state.meeting.pin,
  registrationOpen: state.meeting.registrationOpen,
});

// Following this example since we need id from state
// https://github.com/reactjs/react-redux/issues/237#issuecomment-168817739
const mergeProps = (stateProps, dispatchProps, ownProps) => {
  const { dispatch } = dispatchProps;
  return {
    ...ownProps,
    ...stateProps,
    closeIssue: () => {
      dispatch(adminCloseIssue({ issue: stateProps.issue.id }));
    },
    deleteIssue: () => {
      dispatch(adminDeleteIssue({ issue: stateProps.issue.id }));
    },
    disableVoting: () => {
      dispatch(disableVoting({ issue: stateProps.issue.id }));
    },
    enableVoting: () => {
      dispatch(enableVoting({ issue: stateProps.issue.id }));
    },
  };
};

export default Issue;
export const IssueContainer = connect(
  mapStateToProps,
  null,
  mergeProps,
)(Issue);
<|endoftext|>


<commit_before>var roles = require('../models/tables').roles;
var utils = require('../lib/utils');
var config = require('../config');
var dbUtils = require('../lib/dbUtils');
var middleware = require('../middleware');

var passport = require('passport');
var permission = require('permission');

exports.init = init;

/**
 * Adds routes for handling user sent messages
 * @param router
 */
function init(router) {

    // All of our messaging routes are accessible only by users with the
    // role of fosterParent or caseWorker, and only after successful permissions will the user object
    // be available to the views.
    router.use(permission(Object.keys(roles).map(function(key){return roles[key]})));
    // All views get a res.locals.user object set
    router.use(setUser);

    router.get('/sendMessage', function(req, res, next) {
        if(req.isAuthenticated()) {
            res.render('forms/sendmessage');
        }
    });
    /**
     * Take user details, and if all entered in properly save user to the database.
     * If something goes wrong we redirect back to the forms to try again, but with a message to the user too.
     */
    router.post('/message', function(req, res, next) {
        console.log('recieved message');
        if(req.user && req.isAuthenticated()) {
            /**
             * Form must contain following components:
             * subject      IN message.subject
             * message text IN message.text
             * recipient    IN message.recipientID
             */
            var message = {};
            message['fromID']       = req.user.userID;
            message['subject']      = req.body.subject;
            message['message']      = req.body.text;
            message['hasRead']      = false;

            var recipientField = req.body.recipientID;
            console.log(recipientField);
            var isRecipientNumeric = isNaN(recipientField);
            console.log(isRecipientNumeric);
            console.log('recieved message');

            if(!(isRecipientNumeric)) {
                // If we are given the numerical ID of recipient, send directly
                message['recipientID']  = parseInt(recipientField);
                processMessage(message, req, res);
            } else {
                console.log('message given by email');
                // If not, lookup by email
                if(recipientField) {
                    dbUtils.retrieveUser({'email':recipientField}).then(function(user) {
                        console.log('user corresponding to email is:');
                        console.log(user);
                        var recipientID = user.userID;
                        message['recipientID'] = recipientID;

                        processMessage(message, req, res);
                    });
                } else {
                    // No unique identifier
                    message['recipientID'] = null;
                    processMessage(message, req, res);
                }
            }

        }
        else {
            res.render('501', {status: 501, url: req.url});
        }
    });

     /**
      * Gets userIDs+addresses for all users relevant to the user making the request.
      *
      */
     router.post('/getRelevantAddresses', function(req, res) {
        var userID = req.user.userID;
        var userRole = req.user.userDetails.role;
        var allUsersInCommunication = [userID];

        if(userRole == 'fosterParent') {
            dbUtils.getFosterParentCases(userID).then(function(cases) {
                for (index in cases){
                    var specificCase = cases[index];
                    allUsersInCommunication.push(cases.caseWorker);
                }
                res.send(allUsersInCommunication);
            });
        }
        else {
            dbUtils.getCaseWorkerCases(userID).then(function(cases) {
                for (index in cases) {
                    var specificCase = cases[index];
                    allUsersInCommunication.push(cases.fosterParent);
                }
                res.send(allUsersInCommunication);
            });
        }
    });
}

function processMessage(message, req, res) {
    //Makes sure all fields exist
    var allFieldsExist = false;
    if(message['subject']       != null &&
       message['message']       != null &&
       message['recipientID']   != null) {
       allFieldsExist=true;
    } else {
        if(!allFieldsExist) {
            req.flash('error', 'Required fields not filled');
        }
        req.flash('success', 'Message sent!');
        res.redirect('/inbox');
        return;
    }

    dbUtils.checkExist('users', {'userID': message['recipientID']}, function(err, recipientExists) {

        if(err) {
            res.render('501', {status: 501, url: req.url});
            return;
        }
        if(recipientExists && allFieldsExist) {
            dbUtils.addMessage(message).then(function() {
                res.redirect('/sendMessage');
            });
        } else {
            req.flash('error', 'Please enter a valid recipient');
            res.redirect('/sendMessage');
        }
            });
}

/**
 * Small middleware for setting the user object to be visible in our handlebars layouts
 * Its side effect is a `res.locals.user` variable being set.
 */
function setUser(req, res, next) {
    if (req.user) {
        res.locals.user = req.user;
    }
    next();
};
<commit_msg>added catch statements<commit_after>var roles = require('../models/tables').roles;
var utils = require('../lib/utils');
var config = require('../config');
var dbUtils = require('../lib/dbUtils');
var middleware = require('../middleware');

var passport = require('passport');
var permission = require('permission');

exports.init = init;

/**
 * Adds routes for handling user sent messages
 * @param router
 */
function init(router) {

    // All of our messaging routes are accessible only by users with the
    // role of fosterParent or caseWorker, and only after successful permissions will the user object
    // be available to the views.
    router.use(permission(Object.keys(roles).map(function(key){return roles[key]})));
    // All views get a res.locals.user object set
    router.use(setUser);

    router.get('/sendMessage', function(req, res, next) {
        if(req.isAuthenticated()) {
            res.render('forms/sendmessage');
        }
    });
    /**
     * Take user details, and if all entered in properly save user to the database.
     * If something goes wrong we redirect back to the forms to try again, but with a message to the user too.
     */
    router.post('/message', function(req, res, next) {
        console.log('recieved message');
        if(req.user && req.isAuthenticated()) {
            /**
             * Form must contain following components:
             * subject      IN message.subject
             * message text IN message.text
             * recipient    IN message.recipientID
             */
            var message = {};
            message['fromID']       = req.user.userID;
            message['subject']      = req.body.subject;
            message['message']      = req.body.text;
            message['hasRead']      = false;

            var recipientField = req.body.recipientID;
            console.log(recipientField);
            var isRecipientNumeric = isNaN(recipientField);
            console.log(isRecipientNumeric);
            console.log('recieved message');

            if(!(isRecipientNumeric)) {
                // If we are given the numerical ID of recipient, send directly
                message['recipientID']  = parseInt(recipientField);
                processMessage(message, req, res);
            } else {
                console.log('message given by email');
                // If not, lookup by email
                if(recipientField) {
                    dbUtils.retrieveUser({'email':recipientField}).then(function(user) {
                        console.log('user corresponding to email is:');
                        console.log(user);
                        var recipientID = user.userID;
                        message['recipientID'] = recipientID;

                        processMessage(message, req, res);
                    }).catch(function(err) {
                        message['recipientID'] = null;
                        processMessage(message, req, res);
                    });
                } else {
                    // No unique identifier
                    message['recipientID'] = null;
                    processMessage(message, req, res);
                }
            }

        }
        else {
            res.render('501', {status: 501, url: req.url});
        }
    });

     /**
      * Gets userIDs+addresses for all users relevant to the user making the request.
      *
      */
     router.post('/getRelevantAddresses', function(req, res) {
        var userID = req.user.userID;
        var userRole = req.user.userDetails.role;
        var allUsersInCommunication = [userID];

        if(userRole == 'fosterParent') {
            dbUtils.getFosterParentCases(userID).then(function(cases) {
                for (index in cases){
                    var specificCase = cases[index];
                    allUsersInCommunication.push(cases.caseWorker);
                }
                res.send(allUsersInCommunication);
            });
        }
        else {
            dbUtils.getCaseWorkerCases(userID).then(function(cases) {
                for (index in cases) {
                    var specificCase = cases[index];
                    allUsersInCommunication.push(cases.fosterParent);
                }
                res.send(allUsersInCommunication);
            });
        }
    });
}

function processMessage(message, req, res) {
    //Makes sure all fields exist
    var allFieldsExist = false;
    if(message['subject']       != null &&
       message['message']       != null &&
       message['recipientID']   != null) {
       allFieldsExist=true;
    } else {
        if(message['recipientID'] == null) {
            req.flash('error', 'Invalid recipient!');
        }
        if(!allFieldsExist) {
            req.flash('error', 'Required fields not filled');
        }
        req.flash('success', 'Message sent!');
        res.redirect('/inbox');
        return;
    }

    dbUtils.checkExist('users', {'userID': message['recipientID']}, function(err, recipientExists) {

        if(err) {
            res.render('501', {status: 501, url: req.url});
            return;
        }
        if(recipientExists && allFieldsExist) {
            dbUtils.addMessage(message).then(function() {
                res.redirect('/sendMessage');
            });
        } else {
            req.flash('error', 'Please enter a valid recipient');
            res.redirect('/sendMessage');
        }
            });
}

/**
 * Small middleware for setting the user object to be visible in our handlebars layouts
 * Its side effect is a `res.locals.user` variable being set.
 */
function setUser(req, res, next) {
    if (req.user) {
        res.locals.user = req.user;
    }
    next();
};
<|endoftext|>


<commit_before>// stuff to do as soon as document is loadded
$(function(){
    $('.ui-slider').hide()
});

// make API request immediately
$.ajax({
    url : '/moves/summary/daily',
    xhrFields : {
        withCredentials : true
    }
}).done(function(data){

    $(document).ready( function(){ // ensure document ready

        var desiredWeeklyIncreaseRate = 1.1

        var walkToday = data.walk.distance.slice(-1)[0]
        // suggest walking distance based on average distance centered around a week ago
        var suggestedWalkToday = data.walk.distance.slice(-11,-4).reduce(function(a,b){ return a + b })/7*desiredWeeklyIncreaseRate // ignores that curve will be exponential, but resulting overshoot is minimal
        var suggestedWalkTomorrow = data.walk.distance.slice(-10,-3).reduce(function(a,b){ return a + b })/7*desiredWeeklyIncreaseRate // ignores that curve will be exponential, but resulting overshoot is minimal

        $('.walked-today').text(roundForDisplay(walkToday) + ' mi')
        $('.walk-more-today').text(roundForDisplay(Math.max(suggestedWalkToday - walkToday, 0)) + ' mi')
        $('.walk-tomorrow').text(roundForDisplay(suggestedWalkTomorrow) + ' mi')

        var walkGraphData = _.pairs(_.object(data.dates, data.walk.distance))

        var suggestedWalkGraphData = [walkGraphData.slice(-2)[0], [data.dates.slice(-1)[0], suggestedWalkToday], [data.futureDates[0], suggestedWalkTomorrow]]

        var fullGraphDateRange = data.dates.concat(data.futureDates.slice(0,1))

        var defaultGraphRangeIndices = [-28, -1] // show the last four weeks by default

        var walkGraph = $.jqplot('walk-graph',  [walkGraphData, suggestedWalkGraphData],
            {
                title: 'Daily walking distance',
                axes: {
                    xaxis: {
                        renderer         : $.jqplot.DateAxisRenderer,
                        tickOptions : {
                            formatString : '%d-%b-%Y'
                        },
                        min              : fullGraphDateRange.slice(defaultGraphRangeIndices[0])[0],
                        max              : fullGraphDateRange.slice(defaultGraphRangeIndices[1])[0],
                    },
                    yaxis : {
                        min : 0,
                        max : Math.ceil(Math.max.apply(null, data.walk.distance))
                    }
                },
                series : [{
                    lineWidth       : 3,
                    showMarker      : false,
                    shadow          : false,
                    rendererOptions : {
                        smooth : true
                    }
                },{
                    lineWidth       : 3,
                    linePattern     : [.01, 1.1],
                    showMarker      : false,
                    shadow          : false,
                    rendererOptions : {
                        smooth : true
                    }
                }],
                highlighter: {
                    show                : true,
                    sizeAdjust          : 7.5,
                    tooltipAxes         : 'y',
                    useAxesFormatters   : false,
                    tooltipFormatString : '%.1f'
               }
            })

        $('#date-range-slider').slider({
            range: true,
            min: 0,
            max: fullGraphDateRange.length,
            values: [fullGraphDateRange.length+defaultGraphRangeIndices[0], fullGraphDateRange.length+defaultGraphRangeIndices[1]],
            slide: function( event, ui ) {
                walkGraph.replot({
                    axes: {
                        xaxis : {
                            min : fullGraphDateRange[ui.values[0]],
                            max : fullGraphDateRange[ui.values[1]]
                        }
                    }
                });
            }
        });

        $('.ui-slider').show()
    })

})

function roundForDisplay(num){
    return Math.round(num*10)/10
}
<commit_msg>Begin refactor which will allow for #2 & #16<commit_after>// stuff to do as soon as document is loadded
$(function(){
    $('.ui-slider').hide()
});

// make API request immediately
$.ajax({
    url : '/moves/summary/daily',
    xhrFields : {
        withCredentials : true
    }
}).done(function(data){

    $(document).ready( function(){ // ensure document ready

        var desiredWeeklyIncreaseRate = 1.1

        var walkToday = data.walk.distance.slice(-1)[0]

        // suggest walking distance based on average distance centered around a week ago
        var walkAndSuggestedWalk = data.walk.distance.slice(-28,-1) // seed suggested walk with data from the past month except for today

        // add suggested walking for today with a minimum of how much have already walked
        walkAndSuggestedWalk.push(Math.max(walkToday, walkAndSuggestedWalk.slice(-10,-3).reduce(function(a,b){ return a + b })/7*desiredWeeklyIncreaseRate))

        for (var i = 0; i < 14; i++){ // calculate suggested walking for next 14 days
            walkAndSuggestedWalk.push(walkAndSuggestedWalk.slice(-10,-3).reduce(function(a,b){ return a + b })/7*desiredWeeklyIncreaseRate)
        }

        suggestedWalk = walkAndSuggestedWalk.slice(27) // starting from today

        $('.walked-today').text(roundForDisplay(walkToday) + ' mi')
        $('.walk-more-today').text(roundForDisplay(Math.max(suggestedWalk[0] - walkToday, 0)) + ' mi')
        $('.walk-tomorrow').text(roundForDisplay(suggestedWalk[1]) + ' mi')

        var walkGraphData = _.pairs(_.object(data.dates, data.walk.distance))

        var suggestedWalkGraphData = [[data.dates.slice(-1)[0], suggestedWalk[0]], [data.futureDates[0], suggestedWalk[1]], [data.futureDates[1], suggestedWalk[2]]]

        var fullGraphDateRange = data.dates.concat(data.futureDates.slice(0,2))

        var defaultGraphRangeIndices = [-28, -1] // show the last four weeks by default

        var walkGraph = $.jqplot('walk-graph',  [walkGraphData, suggestedWalkGraphData],
            {
                title: 'Daily walking distance',
                axes: {
                    xaxis: {
                        renderer         : $.jqplot.DateAxisRenderer,
                        tickOptions : {
                            formatString : '%d-%b-%Y'
                        },
                        min              : fullGraphDateRange.slice(defaultGraphRangeIndices[0])[0],
                        max              : fullGraphDateRange.slice(defaultGraphRangeIndices[1])[0],
                    },
                    yaxis : {
                        min : 0,
                        max : Math.ceil(Math.max.apply(null, data.walk.distance))
                    }
                },
                series : [{
                    lineWidth       : 3,
                    showMarker      : false,
                    shadow          : false,
                    rendererOptions : {
                        smooth : true
                    }
                },{
                    lineWidth       : 3,
                    linePattern     : 'dotted',
                    showMarker      : true,
                    shadow          : false,
                    rendererOptions : {
                        smooth : true
                    }
                }],
                highlighter: {
                    show                : true,
                    sizeAdjust          : 7.5,
                    tooltipAxes         : 'y',
                    useAxesFormatters   : false,
                    tooltipFormatString : '%.1f'
               }
            })

        $('#date-range-slider').slider({
            range: true,
            min: 0,
            max: fullGraphDateRange.length,
            values: [fullGraphDateRange.length+defaultGraphRangeIndices[0], fullGraphDateRange.length+defaultGraphRangeIndices[1]],
            slide: function( event, ui ) {
                walkGraph.replot({
                    axes: {
                        xaxis : {
                            min : fullGraphDateRange[ui.values[0]],
                            max : fullGraphDateRange[ui.values[1]]
                        }
                    }
                });
            }
        });

        $('.ui-slider').show()
    })

})

function roundForDisplay(num){
    return Math.round(num*10)/10
}
<|endoftext|>


<commit_before>'use strict';

var React = require('react');
var ReactDOM = require('react-dom');
var ReactD3 = require('react-d3-components');

var logs;
var result;
var timer;
var LineChart = ReactD3.LineChart;

class Charts extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      isShown: false,
      Meminfo: {
        values: [{
          x: 0,
          y: 0
        }]
      },
      ThreadCount: {
        values: [{
          x: 0,
          y: 0
        }]
      },
      cpu: {
        values: [{
          x: 0,
          y: 0
        }]
      },
      wifiData: {
        values: [{
          x: 0,
          y: 0
        }]
      },
      mobileData: {
        values: [{
          x: 0,
          y: 0
        }]
      }
    };
  }

  componentDidMount() {
    this.getData();
    if (this.state.isShown) {
      this.setDataState();
    }
  }

  extract(logs) {
    var map = {};
    var pattern = /\<\#\s*chart\s*\|([\s\S]+?)\#\>/g;
    var arr;
    while ((arr = pattern.exec(logs)) !== null) {
      var log = arr[1];
      var result = JSON.parse(log);
      result.forEach(obj => {
        var item = obj.item;
        if (!(item in map)) {
          map[item] = [];
        }
        map[item].push(obj.data);
      });
    }
    return map;
  }

  extractTimer(logs) {
    var timer;
    var pattern = /\<\#\s*timer\s*\|([\s\S]+?)\#\>/g;
    var arr = pattern.exec(logs);
    if (arr) {
      var log = arr[1].trim();
      timer = log.split(' ')[0];
    } else {
      timer = 5;
    }
    return +timer;
  }

  getData() {
    logs = $('#logs').text();
    result = this.extract(logs);
    if (Object.keys(result).length) {
      this.state.isShown = true;
    }
    timer = this.extractTimer(logs);
  }

  getMemData() {
    var valuesTemp = [];
    var meminfo = result['Meminfo'];
    for (var i = 0, j = meminfo.length; i < j; i++) {
      valuesTemp.push({
        x: i * timer,
        y: +meminfo[i]
      });
    }
    return {
      label: 'Meminfo',
      values: valuesTemp
    };
  }

  getThreadData() {
    var valuesTemp = [];
    var threadCount = result['ThreadCount'];
    for (var i = 0, j = threadCount.length; i < j; i++) {
      valuesTemp.push({
        x: i * timer,
        y: +threadCount[i]
      });
    }
    return {
      label: 'ThreadCount',
      values: valuesTemp
    };
  }

  getCpuData() {
    var valuesTemp = [];
    var cpu = result['cpu'];
    for (var i = 0, j = cpu.length; i < j; i++) {
      valuesTemp.push({
        x: i * timer,
        y: +cpu[i]
      });
    }
    return {
      label: 'cpu',
      values: valuesTemp
    };
  }

  getTrafficWifiData() {
    var valuesTempRcv = [];
    var valuesTempSnd = [];
    var traffic = result['Traffic'];
    for (var i = 0, j = traffic.length; i < j; i++) {
      valuesTempRcv.push({
        x: i * timer,
        y: (traffic[i].wifi.rcv - traffic[0].wifi.rcv) / 1024
      });
      valuesTempSnd.push({
        x: i * timer,
        y: (traffic[i].wifi.snd - traffic[0].wifi.snd) / 1024
      });
    }
    return [
      {
        label: 'TrafficWifiRcv(KB)',
        values: valuesTempRcv
      },
      {
        label: 'TrafficWifiSnd(KB)',
        values: valuesTempSnd
      }
    ];
  }

  getTrafficMobileData() {
    var valuesTempRcv = [];
    var valuesTempSnd = [];
    var traffic = result['Traffic'];
    for (var i = 0, j = traffic.length; i < j; i++) {
      valuesTempRcv.push({
        x: i * timer,
        y: (traffic[i].mobile.rcv - traffic[0].mobile.rcv) / 1024
      });
      valuesTempSnd.push({
        x: i * timer,
        y: (traffic[i].mobile.snd - traffic[0].mobile.snd) / 1024
      });
    }
    return [
      {
        label: 'TrafficMobileRcv',
        values: valuesTempRcv
      },
      {
        label: 'TrafficMobileSnd',
        values: valuesTempSnd
      }
    ];
  }

  setDataState() {
    var Meminfo = this.getMemData();
    var ThreadCount = this.getThreadData();
    var cpu = this.getCpuData();
    var wifiData = this.getTrafficWifiData();
    var mobileData = this.getTrafficMobileData();

    this.setState({
      Meminfo: Meminfo,
      ThreadCount: ThreadCount,
      cpu: cpu,
      wifiData: wifiData,
      mobileData: mobileData
    });
  }

  getLineChartProps(flag) {
    this.getData();
    return {
      width: 720,
      height: 300,
      margin: {
        top: 10, bottom: 50, left: 100, right: 10
      },
      xAxis: {
        label: 'time'
      },
      yAxis: {
        label: flag
      }
    };
  }

  render() {
    return (

        <LineChart
          data={this.state.Meminfo}
          {...this.getLineChartProps('Meminfo')}
        />

        <LineChart
          data={this.state.cpu}
          {...this.getLineChartProps('CPU')}
        />

        <LineChart
          data={this.state.ThreadCount}
         {...this.getLineChartProps('ThreadCount')}
        />

        <LineChart
          data={this.state.mobileData}
         {...this.getLineChartProps('MobileTraffic')}
        />

        <LineChart
          data={this.state.wifiData}
          {...this.getLineChartProps('WifiTraffic')}
        />

    );
  }
}

ReactDOM.render(<Charts />, document.getElementById('charts'));

(function() {
  $('#retry').on('click', function() {
    var taskId = $(this).data('id');
    $.ajax({
      url: '/api/task/update?_csrf=' + $('#csrf_token').val(),
      async: false,
      method: 'post',
      data: {
        taskId: taskId,
        data: {
          status: 0
        }
      },
      success: function(d) {
        if (!d.success) {
          alert(d.errMsg);
        }
        location.reload();
      }
    });
    return false;
  });
  var bash = $('.bash');

  function download(filename, text) {
    var pom = document.createElement('a');
    pom.setAttribute('href', 'data:text/html;charset=utf-8,' + encodeURIComponent(text));
    pom.setAttribute('download', filename);

    if (document.createEvent) {
      var event = document.createEvent('MouseEvents');
      event.initEvent('click', true, true);
      pom.dispatchEvent(event);
    } else {
      pom.click();
    }
  }

  $('.log-export').on('click', function() {
    var text = bash.html();
    var taskTitle = $('.col-md-9 .alert h4')[0].firstChild.nodeValue;
    var taskDate = $('.col-md-9 .clearfix .pull-right')[0].firstChild.nodeValue;
    var result = $('.col-md-3 .build-widget:first-child h4')[0].firstChild.nodeValue;
    var filename = 'reliable-' + taskTitle + '-' + taskDate + '-' + result;
    download(filename, text);
  });

  $(function() {
    $('img').lazyload();
  });

  var modalImage = null;
  $('.bash img').click(function() {
    modalImage = $(this);
    $('#image-modal').modal();
  });

  function isUsingWidth(image) {
    var win = $(window);
    var img = $(image);

    if (win.width() / win.height() < img.width() / img.height()) {
      return true;
    } else {
      return false;
    }
  }

  $('#image-modal').on('show.bs.modal', function() {
    var src = modalImage.attr('data-original');
    var win = $(window);
    var html = '';

    if (isUsingWidth(modalImage)) {
      html += '';
    } else {
      html += '';
    }

    $(this).find('.image').html(html);
  });

  $('#image-modal').on('click.bs.modal', function(event) {
    if (!$(event.target).is('#image-modal img')) {
      $('#image-modal').modal('hide');
    }
  });

  if ($('.build-head').hasClass('alert-info')) {
    // for chrome/safari
    // reference: http://stackoverflow.com/questions/15691569/javascript-issue-with-scrollto-in-chrome
    setTimeout(function() {
      window.scrollTo(0, 99999);
    }, 200);

    setTimeout(function() {
      location.reload();
    }, 10000);
  }

  // sidebar sticky
  $('#affix-sidebar').affix({ offset: { top: 106 } });

})();
<commit_msg>fix cpu chart<commit_after>'use strict';

var React = require('react');
var ReactDOM = require('react-dom');
var ReactD3 = require('react-d3-components');

var logs;
var result;
var timer;
var LineChart = ReactD3.LineChart;

class Charts extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      isShown: false,
      Meminfo: {
        values: [{
          x: 0,
          y: 0
        }]
      },
      ThreadCount: {
        values: [{
          x: 0,
          y: 0
        }]
      },
      cpu: {
        values: [{
          x: 0,
          y: 0
        }]
      },
      wifiData: {
        values: [{
          x: 0,
          y: 0
        }]
      },
      mobileData: {
        values: [{
          x: 0,
          y: 0
        }]
      }
    };
  }

  componentDidMount() {
    this.getData();
    if (this.state.isShown) {
      this.setDataState();
    }
  }

  extract(logs) {
    var map = {};
    var pattern = /\<\#\s*chart\s*\|([\s\S]+?)\#\>/g;
    var arr;
    while ((arr = pattern.exec(logs)) !== null) {
      var log = arr[1];
      var result = JSON.parse(log);
      result.forEach(obj => {
        //console.log(obj)
        var item = obj.item;
        if (!(item in map)) {
          map[item] = [];
        }
        map[item].push(obj.data);
      });
    }
    return map;
  }

  extractTimer(logs) {
    var timer;
    var pattern = /\<\#\s*timer\s*\|([\s\S]+?)\#\>/g;
    var arr = pattern.exec(logs);
    if (arr) {
      var log = arr[1].trim();
      timer = log.split(' ')[0];
    } else {
      timer = 5;
    }
    return +timer;
  }

  getData() {
    logs = $('#logs').text();
    result = this.extract(logs);
    if (Object.keys(result).length) {
      this.state.isShown = true;
    }
    timer = this.extractTimer(logs);
  }

  getMemData() {
    var valuesTemp = [];
    var meminfo = result['Meminfo'];
    for (var i = 0, j = meminfo.length; i < j; i++) {
      valuesTemp.push({
        x: i * timer,
        y: +meminfo[i]
      });
    }
    return {
      label: 'Meminfo',
      values: valuesTemp
    };
  }

  getThreadData() {
    var valuesTemp = [];
    var threadCount = result['ThreadCount'];
    for (var i = 0, j = threadCount.length; i < j; i++) {
      //console.log(typeof threadCount[i])
      //console.log(typeof +threadCount[i])
      valuesTemp.push({
        x: i * timer,
        y: +threadCount[i]
      });
    }
    return {
      label: 'ThreadCount',
      values: valuesTemp
    };
  }

  getCpuData() {
    var valuesTemp = [];
    var cpu = result['cpu'];
    for (var i = 0, j = cpu.length; i < j; i++) {
      valuesTemp.push({
        x: i * timer,
        y: parseInt(cpu[i], 10)
      });
    }
    return {
      label: 'cpu',
      values: valuesTemp
    };
  }

  getTrafficWifiData() {
    var valuesTempRcv = [];
    var valuesTempSnd = [];
    var traffic = result['Traffic'];
    for (var i = 0, j = traffic.length; i < j; i++) {
      valuesTempRcv.push({
        x: i * timer,
        y: (traffic[i].wifi.rcv - traffic[0].wifi.rcv) / 1024
      });
      valuesTempSnd.push({
        x: i * timer,
        y: (traffic[i].wifi.snd - traffic[0].wifi.snd) / 1024
      });
    }
    return [
      {
        label: 'TrafficWifiRcv(KB)',
        values: valuesTempRcv
      },
      {
        label: 'TrafficWifiSnd(KB)',
        values: valuesTempSnd
      }
    ];
  }

  getTrafficMobileData() {
    var valuesTempRcv = [];
    var valuesTempSnd = [];
    var traffic = result['Traffic'];
    for (var i = 0, j = traffic.length; i < j; i++) {
      valuesTempRcv.push({
        x: i * timer,
        y: (traffic[i].mobile.rcv - traffic[0].mobile.rcv) / 1024
      });
      valuesTempSnd.push({
        x: i * timer,
        y: (traffic[i].mobile.snd - traffic[0].mobile.snd) / 1024
      });
    }
    return [{
      label: 'TrafficMobileRcv',
      values: valuesTempRcv
    }, {
      label: 'TrafficMobileSnd',
      values: valuesTempSnd
    }];
  }

  setDataState() {
    var Meminfo = this.getMemData();
    var ThreadCount = this.getThreadData();
    var cpu = this.getCpuData();
    var wifiData = this.getTrafficWifiData();
    var mobileData = this.getTrafficMobileData();

    this.setState({
      Meminfo: Meminfo,
      ThreadCount: ThreadCount,
      cpu: cpu,
      wifiData: wifiData,
      mobileData: mobileData
    });
  }

  getLineChartProps(flag) {
    this.getData();
    return {
      width: 720,
      height: 300,
      margin: {
        top: 10, bottom: 50, left: 100, right: 10
      },
      xAxis: {
        label: 'time'
      },
      yAxis: {
        label: flag
      }
    };
  }

  render() {
    return (

        <LineChart
          data={this.state.Meminfo}
          {...this.getLineChartProps('Meminfo')}
        />

        <LineChart
          data={this.state.cpu}
          {...this.getLineChartProps('CPU')}
        />

        <LineChart
          data={this.state.ThreadCount}
         {...this.getLineChartProps('ThreadCount')}
        />

        <LineChart
          data={this.state.mobileData}
         {...this.getLineChartProps('MobileTraffic')}
        />

        <LineChart
          data={this.state.wifiData}
          {...this.getLineChartProps('WifiTraffic')}
        />

    );
  }
}

ReactDOM.render(<Charts />, document.getElementById('charts'));

(function() {
  $('#retry').on('click', function() {
    var taskId = $(this).data('id');
    $.ajax({
      url: '/api/task/update?_csrf=' + $('#csrf_token').val(),
      async: false,
      method: 'post',
      data: {
        taskId: taskId,
        data: {
          status: 0
        }
      },
      success: function(d) {
        if (!d.success) {
          alert(d.errMsg);
        }
        location.reload();
      }
    });
    return false;
  });
  var bash = $('.bash');

  function download(filename, text) {
    var pom = document.createElement('a');
    pom.setAttribute('href', 'data:text/html;charset=utf-8,' + encodeURIComponent(text));
    pom.setAttribute('download', filename);

    if (document.createEvent) {
      var event = document.createEvent('MouseEvents');
      event.initEvent('click', true, true);
      pom.dispatchEvent(event);
    } else {
      pom.click();
    }
  }

  $('.log-export').on('click', function() {
    var text = bash.html();
    var taskTitle = $('.col-md-9 .alert h4')[0].firstChild.nodeValue;
    var taskDate = $('.col-md-9 .clearfix .pull-right')[0].firstChild.nodeValue;
    var result = $('.col-md-3 .build-widget:first-child h4')[0].firstChild.nodeValue;
    var filename = 'reliable-' + taskTitle + '-' + taskDate + '-' + result;
    download(filename, text);
  });

  $(function() {
    $('img').lazyload();
  });

  var modalImage = null;
  $('.bash img').click(function() {
    modalImage = $(this);
    $('#image-modal').modal();
  });

  function isUsingWidth(image) {
    var win = $(window);
    var img = $(image);

    if (win.width() / win.height() < img.width() / img.height()) {
      return true;
    } else {
      return false;
    }
  }

  $('#image-modal').on('show.bs.modal', function() {
    var src = modalImage.attr('data-original');
    var win = $(window);
    var html = '';

    if (isUsingWidth(modalImage)) {
      html += '';
    } else {
      html += '';
    }

    $(this).find('.image').html(html);
  });

  $('#image-modal').on('click.bs.modal', function(event) {
    if (!$(event.target).is('#image-modal img')) {
      $('#image-modal').modal('hide');
    }
  });

  if ($('.build-head').hasClass('alert-info')) {
    // for chrome/safari
    // reference: http://stackoverflow.com/questions/15691569/javascript-issue-with-scrollto-in-chrome
    setTimeout(function() {
      window.scrollTo(0, 99999);
    }, 200);

    setTimeout(function() {
      location.reload();
    }, 10000);
  }

  // sidebar sticky
  $('#affix-sidebar').affix({
    offset: {
      top: 106
    }
  });

})();
<|endoftext|>


<commit_before>/*******************************************************************************
 * Copyright [2017] [Quirino Brizi (quirino.brizi@gmail.com)]
 *
 * 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.
 ******************************************************************************/

'use strict'

const logger = require('../infrastructure/Logger');

/**
 * Manage services for containers realization.
 */
module.exports = class EnvironmentService {

    constructor(eventEmitter, anomalyService, environmentRepository) {
        this.eventEmitter = eventEmitter;
        this.anomalyService = anomalyService;
        this.environmentRepository = environmentRepository;

        this.containers = {};
    }

    deregisterContainer(container) {
        logger.info("* * remove [%s] [%s] from realization", container.getName(), container.getContainerId());
        delete this.containers[container.getContainerId()];
    }

    alreadyObserves(container) {
        return container.getContainerId() in this.containers;
    }

    close() {

    }

    removeOrphans(containers) {
        var self = this;

        function comparer(otherArray) {
            return function (current) {
                return otherArray.filter(function (other) {
                    return other.getContainerId() == current;
                }).length == 0;
            }
        }
        var orphans = Object.keys(self.containers).filter(comparer(containers));

        for (var i = 0; i < orphans.length; i++) {
            var orphan = orphans[i];
            delete self.containers[orphan];
        }
    }

    /**
     * Evaluate the received realization
     * @method evaluateRealization
     * @param  {Realization}            realization the received realization
     */
    async evaluateRealization(realization) {
        if (!this.containers[realization.getContainerId()] ||
            (Date.now() - this.containers[realization.getContainerId()].lastEvaluate) > 500) {

            let environment = await this.environmentRepository.get();
            let containers = await environment.inspectRealizationsForAnomalies(realization, this.anomalyService);
            this.eventEmitter.emit('containers.updated', containers);
            this.containers[realization.getContainerId()] = {
                lastEvaluate: Date.now()
            };
        }
    }

    queryInfo() {
        return this.environmentRepository.queryInfo();
    }
};
<commit_msg>container inspection to 1000ms<commit_after>/*******************************************************************************
 * Copyright [2017] [Quirino Brizi (quirino.brizi@gmail.com)]
 *
 * 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.
 ******************************************************************************/

'use strict'

const logger = require('../infrastructure/Logger');

/**
 * Manage services for containers realization.
 */
module.exports = class EnvironmentService {

    constructor(eventEmitter, anomalyService, environmentRepository) {
        this.eventEmitter = eventEmitter;
        this.anomalyService = anomalyService;
        this.environmentRepository = environmentRepository;

        this.containers = {};
    }

    deregisterContainer(container) {
        logger.info("* * remove [%s] [%s] from realization", container.getName(), container.getContainerId());
        delete this.containers[container.getContainerId()];
    }

    alreadyObserves(container) {
        return container.getContainerId() in this.containers;
    }

    close() {

    }

    removeOrphans(containers) {
        var self = this;

        function comparer(otherArray) {
            return function (current) {
                return otherArray.filter(function (other) {
                    return other.getContainerId() == current;
                }).length == 0;
            }
        }
        var orphans = Object.keys(self.containers).filter(comparer(containers));

        for (var i = 0; i < orphans.length; i++) {
            var orphan = orphans[i];
            delete self.containers[orphan];
        }
    }

    /**
     * Evaluate the received realization
     * @method evaluateRealization
     * @param  {Realization}            realization the received realization
     */
    async evaluateRealization(realization) {
        if (!this.containers[realization.getContainerId()] ||
            (Date.now() - this.containers[realization.getContainerId()].lastEvaluate) > 1000) {

            let environment = await this.environmentRepository.get();
            let containers = await environment.inspectRealizationsForAnomalies(realization, this.anomalyService);
            this.eventEmitter.emit('containers.updated', containers);
            this.containers[realization.getContainerId()] = {
                lastEvaluate: Date.now()
            };
        }
    }

    queryInfo() {
        return this.environmentRepository.queryInfo();
    }
};
<|endoftext|>