<commit_before>YUI.add('aui-form-validator-tests', function(Y) {

    //--------------------------------------------------------------------------
    // AUI Form Validator Unit Tests
    //--------------------------------------------------------------------------

    var suite = new Y.Test.Suite('aui-form-validator'),
        formValidator;

    var isImageURL = function(val) {
        var regex = /(https?:\/\/.*\.(?:png|jpg|jpeg|gif))/i;
        return regex.test(val);
    };

    Y.FormValidator.addCustomRules(
        {
            'imageURL': {
                condition: isImageURL,
                errorMessage: 'Please enter a valid URL that points to an image (jpg, jpeg, png, or gif).'
            }
        }
    );

    formValidator = new Y.FormValidator({
        boundingBox: '#myForm',
        fieldStrings: {
            email: {
                required: 'Type your email in this field.'
            },
            name: {
                required: 'Please provide your name.'
            }
        },
        rules: {
            age: {
                required: true
            },
            email: {
                email: true,
                required: true
            },
            emailConfirmation: {
                email: true,
                equalTo: '#email',
                required: true
            },
            gender: {
                required: true
            },
            'image-url': {
                imageURL: true,
                required: true
            },
            name: {
                rangeLength: [2, 50],
                required: true
            },
            picture: {
                acceptFiles: 'jpg, gif, png',
                required: true
            },
            read: {
                required: true
            },
            url: {
                required: true,
                url: true
            }
        },
        showAllMessages: true
    });

    //--------------------------------------------------------------------------
    // Test Case for invalid fields
    //--------------------------------------------------------------------------

    suite.add(new Y.Test.Case({

        name: 'AUI Form Submit Form Tests',

        /*
         * Check if on submit all fields are marked as invalid
         * Tests: AUI-965
         */
        'test submit form': function() {
            var elementWithoutError,
                forms;

            forms = Y.all('form');
            forms.each(function (form) {
                form.simulate('submit');
            });

            elementWithoutError = Y.one('.form-group:not(.has-error)');

            Y.Assert.isNull(elementWithoutError, 'There shouldn\'t be any element without class error');
        },

        /*
         * Check if validator nodes render after the input and lable's textNode
         * Tests: AUI-965
         */
        'test error message displayed after label': function() {
            var instance = this;

            instance._assertValidatorNextLabel('input[value=male]');

            instance._assertValidatorNextLabel('input[name=read]');
        },

        /*
         * Check if validator correctly validates <select> html fields
         * Tests: AUI-1204
         */
        'test submit empty select': function() {
            var form = Y.Node.create('<form><select name="gender"></select></form>'),
                select = form.one('select'),
                validOption,
                validator;

            Y.Node.create('<option value=""></option>').appendTo(select);
            validOption = Y.Node.create('<option value=\"male\">Male</option>').appendTo(select);

            validator = new Y.FormValidator({
                boundingBox: form,
                rules: {
                    gender: {
                        required: true
                    }
                }
            });

            form.simulate('submit');

            Y.Assert.isTrue(validator.hasErrors(), 'Validator should have errors');

            validOption.attr('selected', 'selected');

            form.simulate('submit');

            Y.Assert.isFalse(validator.hasErrors(), 'Validator should have no errors');
        },

        /*
         * Check if validator correctly validates fields with custom rules
         * @tests AUI-1654
         */
        'test custom rules': function() {
            var form = Y.Node.create('<form><input name="gt50" id="gt50" type="text"></form>'),
                input = form.one('input'),
                validator,
                gt50Executed = false;

            var gt50 = function(val) {
                gt50Executed = true;

                return (val >= 50);
            };

            Y.FormValidator.addCustomRules(
                {
                    'greaterThan50': {
                        condition: gt50,
                        errorMessage: 'The digit should be >=50'
                    }
                }
            );

            validator = new Y.FormValidator({
                boundingBox: form,
                rules: {
                    gt50: {
                        greaterThan50: true
                    }
                }
            });

            form.simulate('submit');

            Y.Assert.isFalse(gt50Executed, 'gt50Executed should be false');

            Y.Assert.isFalse(validator.hasErrors(), 'Validator should have no errors');

            input.attr('value', '42');

            form.simulate('submit');

            Y.Assert.isTrue(gt50Executed, 'gt50Executed should be true');

            Y.Assert.isTrue(validator.hasErrors(), 'Validator should have errors');

            input.attr('value', '100');

            form.simulate('submit');

            Y.Assert.isFalse(validator.hasErrors(), 'Validator should have no errors');
        },

        /*
         * Check if validator correctly validates fields with custom rules that
         * are required (using required property)
         * @tests AUI-2027
         */
        'test required (using required property) custom rules': function() {
            var form = Y.Node.create('<form><input name="inputName" type="text"></form>'),
                input = form.one('input'),
                validator,
                custonFnExecuted;

            var conditionFn = function() {
                custonFnExecuted = true;

                return true;
            };

            Y.FormValidator.addCustomRules(
                {
                    'myCustomRule': {
                        condition: conditionFn,
                        errorMessage: 'error message'
                    }
                }
            );

            validator = new Y.FormValidator({
                boundingBox: form,
                rules: {
                    inputName: {
                        myCustomRule: true,
                        required: true
                    }
                }
            });

            form.simulate('submit');

            Y.Assert.isTrue(custonFnExecuted, 'custonFnExecuted should be true');

            Y.Assert.isTrue(validator.hasErrors(), 'Validator should have errors');

            input.attr('value', 'anything');

            form.simulate('submit');

            Y.Assert.isFalse(validator.hasErrors(), 'Validator should have no errors');
        },

        /*
         * Check if validator correctly validates fields with custom rules that
         * are required (using custon property)
         * @tests AUI-2027
         */
        'test required (using custon property) custom rules': function() {
            var form = Y.Node.create('<form><input name="inputName" type="text"></form>'),
                input = form.one('input'),
                validator,
                custonFnExecuted;

            var conditionFn = function(val) {
                custonFnExecuted = true;

                return !!val;
            };

            Y.FormValidator.addCustomRules(
                {
                    'myCustomRule': {
                        condition: conditionFn,
                        errorMessage: 'error message'
                    }
                }
            );

            validator = new Y.FormValidator({
                boundingBox: form,
                rules: {
                    inputName: {
                        myCustomRule: true,
                        custom: true
                    }
                }
            });

            form.simulate('submit');

            Y.Assert.isTrue(custonFnExecuted, 'custonFnExecuted should be true');

            Y.Assert.isTrue(validator.hasErrors(), 'Validator should have errors');

            input.attr('value', 'anything');

            form.simulate('submit');

            Y.Assert.isFalse(validator.hasErrors(), 'Validator should have no errors');
        },

        /*
         * Check if validator correctly validates fields with custom rules that
         * are required (using requireValidation property)
         * @tests AUI-2027
         */
        'test required (using requireValidation property) custom rules': function() {
            var form = Y.Node.create('<form><input name="inputName" type="text"></form>'),
                input = form.one('input'),
                validator,
                custonFnExecuted;

            var conditionFn = function(val) {
                custonFnExecuted = true;

                return !!val;
            };

            Y.FormValidator.addCustomRules(
                {
                    'myCustomRule': {
                        condition: conditionFn,
                        errorMessage: 'error message'
                    }
                }
            );

            validator = new Y.FormValidator({
                boundingBox: form,
                rules: {
                    inputName: {
                        myCustomRule: true,
                        requireValidation: true
                    }
                }
            });

            form.simulate('submit');

            Y.Assert.isTrue(custonFnExecuted, 'custonFnExecuted should be true');

            Y.Assert.isTrue(validator.hasErrors(), 'Validator should have errors');

            input.attr('value', 'anything');

            form.simulate('submit');

            Y.Assert.isFalse(validator.hasErrors(), 'Validator should have no errors');
        },

        /*
         * Check if validator correctly passes rule value to custom rules
         * @tests AUI-2027
         */
        'test passing rule values to custom rules': function() {
            var form = Y.Node.create('<form><input name="gt50" id="gt50" type="text"></form>'),
                validator;

            var conditionFn = function(val, node, ruleValue) {
                return ruleValue === 'my rule value';
            };

            Y.FormValidator.addCustomRules(
                {
                    'myCustomRule': {
                        condition: conditionFn,
                        errorMessage: 'error message'
                    }
                }
            );

            validator = new Y.FormValidator({
                boundingBox: form,
                rules: {
                    gt50: {
                        myCustomRule: 'my rule value',
                        requireValidation: true
                    }
                }
            });

            form.simulate('submit');

            Y.Assert.isFalse(validator.hasErrors(), 'Validator should have no errors');
        },

        /*
         * Check if validator correctly validates non-required fields
         * via required: false
         * @tests AUI-2027
         */
        'test non-required fields using required: false': function() {
            var form = Y.Node.create('<form><input name="inputName" type="text"></form>'),
                input = form.one('input'),
                validator;

            validator = new Y.FormValidator({
                boundingBox: form,
                rules: {
                    inputName: {
                        required: false
                    }
                }
            });

            form.simulate('submit');

            Y.Assert.isFalse(validator.hasErrors(), 'Validator should have no errors');

            input.attr('value', 'anything');

            form.simulate('submit');

            Y.Assert.isFalse(validator.hasErrors(), 'Validator should have no errors');
        },

        /*
         * Check if validator correctly validates hasValue rule
         * @tests AUI-2027
         */
        'test hasValue rule': function() {
            var form = Y.Node.create('<form><input name="inputName" type="text"></form>'),
                input = form.one('input'),
                validator;

            validator = new Y.FormValidator({
                boundingBox: form,
                rules: {
                    inputName: {
                        hasValue: true,
                        requireValidation: true
                    }
                }
            });

            form.simulate('submit');

            Y.Assert.isTrue(validator.hasErrors(), 'Validator should have errors');

            input.attr('value', 'anything');

            form.simulate('submit');

            Y.Assert.isFalse(validator.hasErrors(), 'Validator should have no errors');
        },

        /*
         * Check if validator correctly validates required fields when using a
         * function as a rule value
         *
         * @tests AUI-2027
         */
        'test required (via required property) fields using rule value as a function': function() {
            var form = Y.Node.create('<form><input name="inputName" type="text"></form>'),
                input = form.one('input'),
                validator;

            validator = new Y.FormValidator({
                boundingBox: form,
                rules: {
                    inputName: {
                        required: function() {
                            return true;
                        }
                    }
                }
            });

            form.simulate('submit');

            Y.Assert.isTrue(validator.hasErrors(), 'Validator should have errors');

            input.attr('value', 'anything');

            form.simulate('submit');

            Y.Assert.isFalse(validator.hasErrors(), 'Validator should have no errors');
        },

        /*
         * Check if validator correctly validates required fields when using a
         * function as a rule value
         *
         * @tests AUI-2027
         */
        'test required (via requireValidation property) fields using rule value as a function ': function() {
            var form = Y.Node.create('<form><input name="inputName" type="text"></form>'),
                input = form.one('input'),
                validator;

            validator = new Y.FormValidator({
                boundingBox: form,
                rules: {
                    inputName: {
                        requireValidation: function() {
                            return true;
                        },
                        hasValue: true
                    }
                }
            });

            form.simulate('submit');

            Y.Assert.isTrue(validator.hasErrors(), 'Validator should have errors');

            input.attr('value', 'anything');

            form.simulate('submit');

            Y.Assert.isFalse(validator.hasErrors(), 'Validator should have no errors');
        },

        _assertValidatorNextLabel: function(input) {
            var inputNode,
                textNode;

            inputNode = Y.one(input);

            textNode = inputNode.get('nextSibling');

            Y.Assert.isTrue(textNode.get('nodeType') === 3, 'Next to the input should be a text node');

            if (Y.FormValidator.isCheckable(inputNode)) {
                textNode = inputNode.ancestor('.form-group').get('lastChild').previous();
            }

            Y.Assert.isTrue(
                textNode.next().hasClass('form-validator-stack'),
                'Next to the input should be form validator');
        }
    }));

    Y.Test.Runner.add(suite);

}, '', {
    requires: ['test', 'aui-form-validator', 'node-event-simulate']
});
<commit_msg>AUI-2027 Source formatting<commit_after>YUI.add('aui-form-validator-tests', function(Y) {

    //--------------------------------------------------------------------------
    // AUI Form Validator Unit Tests
    //--------------------------------------------------------------------------

    var suite = new Y.Test.Suite('aui-form-validator'),
        formValidator;

    var isImageURL = function(val) {
        var regex = /(https?:\/\/.*\.(?:png|jpg|jpeg|gif))/i;
        return regex.test(val);
    };

    Y.FormValidator.addCustomRules(
        {
            'imageURL': {
                condition: isImageURL,
                errorMessage: 'Please enter a valid URL that points to an image (jpg, jpeg, png, or gif).'
            }
        }
    );

    formValidator = new Y.FormValidator({
        boundingBox: '#myForm',
        fieldStrings: {
            email: {
                required: 'Type your email in this field.'
            },
            name: {
                required: 'Please provide your name.'
            }
        },
        rules: {
            age: {
                required: true
            },
            email: {
                email: true,
                required: true
            },
            emailConfirmation: {
                email: true,
                equalTo: '#email',
                required: true
            },
            gender: {
                required: true
            },
            'image-url': {
                imageURL: true,
                required: true
            },
            name: {
                rangeLength: [2, 50],
                required: true
            },
            picture: {
                acceptFiles: 'jpg, gif, png',
                required: true
            },
            read: {
                required: true
            },
            url: {
                required: true,
                url: true
            }
        },
        showAllMessages: true
    });

    //--------------------------------------------------------------------------
    // Test Case for invalid fields
    //--------------------------------------------------------------------------

    suite.add(new Y.Test.Case({

        name: 'AUI Form Submit Form Tests',

        /*
         * Check if on submit all fields are marked as invalid
         * Tests: AUI-965
         */
        'test submit form': function() {
            var elementWithoutError,
                forms;

            forms = Y.all('form');
            forms.each(function (form) {
                form.simulate('submit');
            });

            elementWithoutError = Y.one('.form-group:not(.has-error)');

            Y.Assert.isNull(elementWithoutError, 'There shouldn\'t be any element without class error');
        },

        /*
         * Check if validator nodes render after the input and lable's textNode
         * Tests: AUI-965
         */
        'test error message displayed after label': function() {
            var instance = this;

            instance._assertValidatorNextLabel('input[value=male]');

            instance._assertValidatorNextLabel('input[name=read]');
        },

        /*
         * Check if validator correctly validates <select> html fields
         * Tests: AUI-1204
         */
        'test submit empty select': function() {
            var form = Y.Node.create('<form><select name="gender"></select></form>'),
                select = form.one('select'),
                validOption,
                validator;

            Y.Node.create('<option value=""></option>').appendTo(select);
            validOption = Y.Node.create('<option value=\"male\">Male</option>').appendTo(select);

            validator = new Y.FormValidator({
                boundingBox: form,
                rules: {
                    gender: {
                        required: true
                    }
                }
            });

            form.simulate('submit');

            Y.Assert.isTrue(validator.hasErrors(), 'Validator should have errors');

            validOption.attr('selected', 'selected');

            form.simulate('submit');

            Y.Assert.isFalse(validator.hasErrors(), 'Validator should have no errors');
        },

        /*
         * Check if validator correctly validates fields with custom rules
         * @tests AUI-1654
         */
        'test custom rules': function() {
            var form = Y.Node.create('<form><input name="gt50" id="gt50" type="text"></form>'),
                input = form.one('input'),
                validator,
                gt50Executed = false;

            var gt50 = function(val) {
                gt50Executed = true;

                return (val >= 50);
            };

            Y.FormValidator.addCustomRules(
                {
                    'greaterThan50': {
                        condition: gt50,
                        errorMessage: 'The digit should be >=50'
                    }
                }
            );

            validator = new Y.FormValidator({
                boundingBox: form,
                rules: {
                    gt50: {
                        greaterThan50: true
                    }
                }
            });

            form.simulate('submit');

            Y.Assert.isFalse(gt50Executed, 'gt50Executed should be false');

            Y.Assert.isFalse(validator.hasErrors(), 'Validator should have no errors');

            input.attr('value', '42');

            form.simulate('submit');

            Y.Assert.isTrue(gt50Executed, 'gt50Executed should be true');

            Y.Assert.isTrue(validator.hasErrors(), 'Validator should have errors');

            input.attr('value', '100');

            form.simulate('submit');

            Y.Assert.isFalse(validator.hasErrors(), 'Validator should have no errors');
        },

        /*
         * Check if validator correctly validates fields with custom rules that
         * are required (using required property)
         * @tests AUI-2027
         */
        'test required (using required property) custom rules': function() {
            var form = Y.Node.create('<form><input name="inputName" type="text"></form>'),
                input = form.one('input'),
                validator,
                customFnExecuted;

            var conditionFn = function() {
                customFnExecuted = true;

                return true;
            };

            Y.FormValidator.addCustomRules(
                {
                    'myCustomRule': {
                        condition: conditionFn,
                        errorMessage: 'error message'
                    }
                }
            );

            validator = new Y.FormValidator({
                boundingBox: form,
                rules: {
                    inputName: {
                        myCustomRule: true,
                        required: true
                    }
                }
            });

            form.simulate('submit');

            Y.Assert.isTrue(customFnExecuted, 'customFnExecuted should be true');

            Y.Assert.isTrue(validator.hasErrors(), 'Validator should have errors');

            input.attr('value', 'anything');

            form.simulate('submit');

            Y.Assert.isFalse(validator.hasErrors(), 'Validator should have no errors');
        },

        /*
         * Check if validator correctly validates fields with custom rules that
         * are required (using custom property)
         * @tests AUI-2027
         */
        'test required (using custom property) custom rules': function() {
            var form = Y.Node.create('<form><input name="inputName" type="text"></form>'),
                input = form.one('input'),
                validator,
                customFnExecuted;

            var conditionFn = function(val) {
                customFnExecuted = true;

                return !!val;
            };

            Y.FormValidator.addCustomRules(
                {
                    'myCustomRule': {
                        condition: conditionFn,
                        errorMessage: 'error message'
                    }
                }
            );

            validator = new Y.FormValidator({
                boundingBox: form,
                rules: {
                    inputName: {
                        myCustomRule: true,
                        custom: true
                    }
                }
            });

            form.simulate('submit');

            Y.Assert.isTrue(customFnExecuted, 'customFnExecuted should be true');

            Y.Assert.isTrue(validator.hasErrors(), 'Validator should have errors');

            input.attr('value', 'anything');

            form.simulate('submit');

            Y.Assert.isFalse(validator.hasErrors(), 'Validator should have no errors');
        },

        /*
         * Check if validator correctly validates fields with custom rules that
         * are required (using requireValidation property)
         * @tests AUI-2027
         */
        'test required (using requireValidation property) custom rules': function() {
            var form = Y.Node.create('<form><input name="inputName" type="text"></form>'),
                input = form.one('input'),
                validator,
                customFnExecuted;

            var conditionFn = function(val) {
                customFnExecuted = true;

                return !!val;
            };

            Y.FormValidator.addCustomRules(
                {
                    'myCustomRule': {
                        condition: conditionFn,
                        errorMessage: 'error message'
                    }
                }
            );

            validator = new Y.FormValidator({
                boundingBox: form,
                rules: {
                    inputName: {
                        myCustomRule: true,
                        requireValidation: true
                    }
                }
            });

            form.simulate('submit');

            Y.Assert.isTrue(customFnExecuted, 'customFnExecuted should be true');

            Y.Assert.isTrue(validator.hasErrors(), 'Validator should have errors');

            input.attr('value', 'anything');

            form.simulate('submit');

            Y.Assert.isFalse(validator.hasErrors(), 'Validator should have no errors');
        },

        /*
         * Check if validator correctly passes rule value to custom rules
         * @tests AUI-2027
         */
        'test passing rule values to custom rules': function() {
            var form = Y.Node.create('<form><input name="gt50" id="gt50" type="text"></form>'),
                validator;

            var conditionFn = function(val, node, ruleValue) {
                return ruleValue === 'my rule value';
            };

            Y.FormValidator.addCustomRules(
                {
                    'myCustomRule': {
                        condition: conditionFn,
                        errorMessage: 'error message'
                    }
                }
            );

            validator = new Y.FormValidator({
                boundingBox: form,
                rules: {
                    gt50: {
                        myCustomRule: 'my rule value',
                        requireValidation: true
                    }
                }
            });

            form.simulate('submit');

            Y.Assert.isFalse(validator.hasErrors(), 'Validator should have no errors');
        },

        /*
         * Check if validator correctly validates non-required fields
         * via required: false
         * @tests AUI-2027
         */
        'test non-required fields using required: false': function() {
            var form = Y.Node.create('<form><input name="inputName" type="text"></form>'),
                input = form.one('input'),
                validator;

            validator = new Y.FormValidator({
                boundingBox: form,
                rules: {
                    inputName: {
                        required: false
                    }
                }
            });

            form.simulate('submit');

            Y.Assert.isFalse(validator.hasErrors(), 'Validator should have no errors');

            input.attr('value', 'anything');

            form.simulate('submit');

            Y.Assert.isFalse(validator.hasErrors(), 'Validator should have no errors');
        },

        /*
         * Check if validator correctly validates hasValue rule
         * @tests AUI-2027
         */
        'test hasValue rule': function() {
            var form = Y.Node.create('<form><input name="inputName" type="text"></form>'),
                input = form.one('input'),
                validator;

            validator = new Y.FormValidator({
                boundingBox: form,
                rules: {
                    inputName: {
                        hasValue: true,
                        requireValidation: true
                    }
                }
            });

            form.simulate('submit');

            Y.Assert.isTrue(validator.hasErrors(), 'Validator should have errors');

            input.attr('value', 'anything');

            form.simulate('submit');

            Y.Assert.isFalse(validator.hasErrors(), 'Validator should have no errors');
        },

        /*
         * Check if validator correctly validates required fields when using a
         * function as a rule value
         *
         * @tests AUI-2027
         */
        'test required (via required property) fields using rule value as a function': function() {
            var form = Y.Node.create('<form><input name="inputName" type="text"></form>'),
                input = form.one('input'),
                validator;

            validator = new Y.FormValidator({
                boundingBox: form,
                rules: {
                    inputName: {
                        required: function() {
                            return true;
                        }
                    }
                }
            });

            form.simulate('submit');

            Y.Assert.isTrue(validator.hasErrors(), 'Validator should have errors');

            input.attr('value', 'anything');

            form.simulate('submit');

            Y.Assert.isFalse(validator.hasErrors(), 'Validator should have no errors');
        },

        /*
         * Check if validator correctly validates required fields when using a
         * function as a rule value
         *
         * @tests AUI-2027
         */
        'test required (via requireValidation property) fields using rule value as a function ': function() {
            var form = Y.Node.create('<form><input name="inputName" type="text"></form>'),
                input = form.one('input'),
                validator;

            validator = new Y.FormValidator({
                boundingBox: form,
                rules: {
                    inputName: {
                        requireValidation: function() {
                            return true;
                        },
                        hasValue: true
                    }
                }
            });

            form.simulate('submit');

            Y.Assert.isTrue(validator.hasErrors(), 'Validator should have errors');

            input.attr('value', 'anything');

            form.simulate('submit');

            Y.Assert.isFalse(validator.hasErrors(), 'Validator should have no errors');
        },

        _assertValidatorNextLabel: function(input) {
            var inputNode,
                textNode;

            inputNode = Y.one(input);

            textNode = inputNode.get('nextSibling');

            Y.Assert.isTrue(textNode.get('nodeType') === 3, 'Next to the input should be a text node');

            if (Y.FormValidator.isCheckable(inputNode)) {
                textNode = inputNode.ancestor('.form-group').get('lastChild').previous();
            }

            Y.Assert.isTrue(
                textNode.next().hasClass('form-validator-stack'),
                'Next to the input should be form validator');
        }
    }));

    Y.Test.Runner.add(suite);

}, '', {
    requires: ['test', 'aui-form-validator', 'node-event-simulate']
});
<|endoftext|>


<commit_before>var menubar = require('menubar')
var ipc = require("electron").ipcMain
var globalShortcut = require('global-shortcut')
var mb = menubar({ dir: __dirname + '/app', width: 400, height: 175, icon: __dirname + '/app/Icon-Template.png', preloadWindow: true, 'window-position': 'topRight' })
var Menu = require('menu')

mb.app.on('will-quit', function () {
  globalShortcut.unregisterAll()
})

mb.app.on('activate', function () {
  mb.showWindow()
})

// when receive the abort message, close the app
ipc.on('abort', function () {
  mb.hideWindow()
})

var template = [
  {
    label: 'Mojibar',
    submenu: [
      {
        label: 'Undo',
        accelerator: 'Command+Z',
        selector: 'undo:'
      },
      {
        label: 'Redo',
        accelerator: 'Shift+Command+Z',
        selector: 'redo:'
      },
      {
        label: 'Cut',
        accelerator: 'Command+X',
        selector: 'cut:'
      },
      {
        label: 'Copy',
        accelerator: 'Command+C',
        selector: 'copy:'
      },
      {
        label: 'Paste',
        accelerator: 'Command+V',
        selector: 'paste:'
      },
      {
        label: 'Select All',
        accelerator: 'Command+A',
        selector: 'selectAll:'
      },
      {
        label: 'Quit App',
        accelerator: 'Command+Q',
        selector: 'terminate:'
      },
      {
        label: 'Toggle DevTools',
        accelerator: 'Alt+Command+I',
        click: function () { mb.window.toggleDevTools() }
      }
    ]
  }
]

mb.on('ready', function ready () {
  // Build default menu for text editing and devtools. (gone since electron 0.25.2)
  var menu = Menu.buildFromTemplate(template)
  Menu.setApplicationMenu(menu)
  console.log(process.versions.electron)

  // Register a 'ctrl+shift+space' shortcut listener.
  var ret = globalShortcut.register('ctrl+shift+space', function () {
    mb.window.isVisible() ? mb.hideWindow() : mb.showWindow()
  })

  if (!ret) {
    console.log('registration failed')
  }
})
<commit_msg>Remove version logging<commit_after>var menubar = require('menubar')
var ipc = require("electron").ipcMain
var globalShortcut = require('global-shortcut')
var mb = menubar({ dir: __dirname + '/app', width: 400, height: 175, icon: __dirname + '/app/Icon-Template.png', preloadWindow: true, 'window-position': 'topRight' })
var Menu = require('menu')

mb.app.on('will-quit', function () {
  globalShortcut.unregisterAll()
})

mb.app.on('activate', function () {
  mb.showWindow()
})

// when receive the abort message, close the app
ipc.on('abort', function () {
  mb.hideWindow()
})

var template = [
  {
    label: 'Mojibar',
    submenu: [
      {
        label: 'Undo',
        accelerator: 'Command+Z',
        selector: 'undo:'
      },
      {
        label: 'Redo',
        accelerator: 'Shift+Command+Z',
        selector: 'redo:'
      },
      {
        label: 'Cut',
        accelerator: 'Command+X',
        selector: 'cut:'
      },
      {
        label: 'Copy',
        accelerator: 'Command+C',
        selector: 'copy:'
      },
      {
        label: 'Paste',
        accelerator: 'Command+V',
        selector: 'paste:'
      },
      {
        label: 'Select All',
        accelerator: 'Command+A',
        selector: 'selectAll:'
      },
      {
        label: 'Quit App',
        accelerator: 'Command+Q',
        selector: 'terminate:'
      },
      {
        label: 'Toggle DevTools',
        accelerator: 'Alt+Command+I',
        click: function () { mb.window.toggleDevTools() }
      }
    ]
  }
]

mb.on('ready', function ready () {
  // Build default menu for text editing and devtools. (gone since electron 0.25.2)
  var menu = Menu.buildFromTemplate(template)
  Menu.setApplicationMenu(menu)

  // Register a 'ctrl+shift+space' shortcut listener.
  var ret = globalShortcut.register('ctrl+shift+space', function () {
    mb.window.isVisible() ? mb.hideWindow() : mb.showWindow()
  })

  if (!ret) {
    console.log('registration failed')
  }
})
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2014 Google Inc. All Rights Reserved.
 *
 * 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.
 */

CLASS({
  package: 'foam.dao',
  name: 'SeqNoDAO',
  label: 'foam.dao.SeqNoDAO',

  extendsModel: 'foam.dao.ProxyDAO',

  documentation: function() {/*
   Set a specified properties value with an auto-increment
   sequence number on DAO.put() if the properties value
   is set to the properties default value.
  */},
  properties: [
    {
      name: 'property',
      type: 'Property',
      required: true,
      hidden: true,
      defaultValueFn: function() {
        return this.delegate.model ? this.delegate.model.ID : undefined;
      },
      transient: true
    },
    {
      model_: 'IntProperty',
      name: 'sequenceValue',
      defaultValue: 1
    }
  ],

  methods: {
    init: function() {
      this.SUPER();

      var future = afuture();
      this.WHEN_READY = future.get;

      // Scan all DAO values to find the largest
      this.delegate.select(MAX(this.property))(function(max) {
        if ( max.max ) this.sequenceValue = max.max + 1;
        future.set(true);
      }.bind(this));
    },
    put: function(obj, sink) {
      this.WHEN_READY(function() {
        var val = this.property.f(obj);

        if ( val == this.property.defaultValue ) {
          obj[this.property.name] = this.sequenceValue++;
        }

        this.delegate.put(obj, sink);
      }.bind(this));
    }
  }
});
<commit_msg>Fix to SeqNoDAO if property has no defaultValue.<commit_after>/**
 * @license
 * Copyright 2014 Google Inc. All Rights Reserved.
 *
 * 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.
 */

CLASS({
  package: 'foam.dao',
  name: 'SeqNoDAO',
  label: 'foam.dao.SeqNoDAO',

  extendsModel: 'foam.dao.ProxyDAO',

  documentation: function() {/*
   Set a specified properties value with an auto-increment
   sequence number on DAO.put() if the properties value
   is set to the properties default value.
  */},
  properties: [
    {
      name: 'property',
      type: 'Property',
      required: true,
      hidden: true,
      defaultValueFn: function() {
        return this.delegate.model ? this.delegate.model.ID : undefined;
      },
      transient: true
    },
    {
      model_: 'IntProperty',
      name: 'sequenceValue',
      defaultValue: 1
    }
  ],

  methods: {
    init: function() {
      this.SUPER();

      var future = afuture();
      this.WHEN_READY = future.get;

      // Scan all DAO values to find the largest
      this.delegate.select(MAX(this.property))(function(max) {
        if ( max.max ) this.sequenceValue = max.max + 1;
        future.set(true);
      }.bind(this));
    },
    put: function(obj, sink) {
      this.WHEN_READY(function() {
        var val = this.property.f(obj);

        if ( ! val || val == this.property.defaultValue ) {
          obj[this.property.name] = this.sequenceValue++;
        }

        this.delegate.put(obj, sink);
      }.bind(this));
    }
  }
});
<|endoftext|>


<commit_before>(() => {

    'use strict';

    angular
        .module('app')
        .controller('ConfirmUsersController', ConfirmUsersController);
    ConfirmUsersController.$inject = ['growl', '$log', '$route', 'ConfirmUsersService'];

    //This controller allows administrator get, edit, approve or decline unapproved users
    //TODO: make use to getUsers(id) admin.platoonId instead of static id
    //TODO: confirm list of available fields for request to approve user
    //TODO: complete function to get list of Ranks from server
    //TODO: disable some ui elements before them content fully loaded
    //TODO: delete JSON.parse();
    //TODO: try to use angular modal instead of bootstrap ones
    //TODO: use new api to approve and decline users
    //TODO: use api to update user data
    function ConfirmUsersController(growl, $log, $route, ConfirmUsersService) {
        //Set variables
        const vm = this;
        const editUserModal = '#EditUser';            //name of modal window to edit user
        const confirmDeleteModal = '#ConfirmDelete';  //same, but to confirm decline user
        vm.usersList = [];
        vm.currentUser = {};
        vm.editUser = editUser;
        vm.changeGroup = changeGroup;
        vm.changePlatoon = changePlatoon;
        vm.getSections = getSections;
        vm.approveUser = approveUser;
        vm.declineUser = declineUser;
        vm.showConfirmDecline = showConfirmDecline;

        activate();

        ////

        function activate() {
            $log.debug('Init ConfirmUsersController ...');
            //Get list of unapproved users with same 'platoonId' as admin's
            getUsers(1);
            //init "FooTable" plugin in all tables with 'footable' class
            $(document).ready(function () {
                $('.footable').footable();
            });
            $log.debug('Init complete.');
        }

        //Function to set in 'vm' user list with specified platoonId
        function getUsers(grId) {
            ConfirmUsersService.getUsers({platoonId: grId}).$promise.then((res) => {
                if (res.success) {
                    let result;
                    result = JSON.parse(res.data.message);
                    result.forEach((item) => {
                        item.birthDate = new Date(item.birthDate);  //use 'new Data()' instead of raw int
                    });
                    vm.usersList = result;
                    $log.debug('Load users list:', vm.usersList);
                }
            });
        }

        //Function to edit currentUser
        function editUser(id) {
            vm.currentUser = vm.usersList.find((item) => item.id == id) || {};
            getCities(vm.currentUser.countryId);
            getGroups(vm.currentUser.cityId);
            getPlatoons(vm.currentUser.groupId);
            getSections(vm.currentUser.platoonId);
            getRanks();
            $(editUserModal).modal();       //load modal window in view (maybe incorrect)
            $log.debug('Edit user:', vm.currentUser);
        }

        //Function to approve currentUser
        function approveUser() {
            $(editUserModal).modal('hide'); //immediately hide modal window to prevent double confirm
            // let valuesToSend = {
            //     "firstName": vm.currentUser.firstName,
            //     "lastName": vm.currentUser.lastName,
            //     "gender": vm.currentUser.gender,
            //     "phoneNumber": vm.currentUser.phoneNumber,
            //     "birthDate": vm.currentUser.birthDate.getTime(),
            //     "cityId": vm.currentUser.cityId,
            //     "groupId": vm.currentUser.groupId,
            //     "platoonId": vm.currentUser.platoonId,
            //     "sectionId": vm.currentUser.sectionId,
            //     "rankId": vm.currentUser.rankId
            // };
            ConfirmUsersService.approveUser([vm.currentUser.id],
                (res) => {
                    if (res.success) {
                        growl.success('Користувач ' + vm.currentUser.firstName + ' ' +
                            vm.currentUser.lastName + ' підтверджений');
                        $route.reload();
                    } else {
                        growl.error('Помилка:' + res.data.message);
                    }
                });
            // ConfirmUsersService.updateUser({userId: vm.currentUser.id}, valuesToSend,
            //     (res) => {
            //         if (res.success) {
            //             growl.success('Користувач ' + vm.currentUser.firstName + ' ' +
            //                 vm.currentUser.lastName + ' підтверджений');
            //             $route.reload();
            //         } else {
            //             growl.error('Помилка:' + res.data.message);
            //         }
            //     });
        }

        //Function to decline currentUser
        function declineUser() {
            $(confirmDeleteModal).modal('hide');    //prevent double decline
            $(editUserModal).modal('hide');         //also to prevent double decline
            ConfirmUsersService.declineUser([vm.currentUser.id],
                (res) => {
                    if (res.success) {
                        growl.info('Користувач ' + vm.currentUser.firstName + ' ' +
                            vm.currentUser.lastName + ' видалений');
                        $route.reload();
                    } else {
                        growl.error('Помилка:' + res.data.message);
                    }
                });
        }

        //This additional function needed just to create another modal with 'confirm decline user'
        function showConfirmDecline() {
            $(confirmDeleteModal).modal();
        }

        //function to set in 'vm' list of Cities by countryId
        function getCities(countryId) {
            if (countryId == null) return;
            ConfirmUsersService.city({countryId: countryId}).$promise.then((res) => {
                if (res.success) {
                    vm.cities = res.data;
                }
            });
        }

        //function to set in 'vm' list of Groups by cityId
        function getGroups(cityId) {
            if (cityId == null) return;
            ConfirmUsersService.group({cityId: cityId}).$promise.then((res) => {
                if (res.success) {
                    vm.groups = res.data;
                }
            });
        }

        //function to set in 'vm' list of Platoons by groupId
        function getPlatoons(groupId) {
            if (groupId == null) return;
            ConfirmUsersService.platoon({groupId: groupId}).$promise.then((res) => {
                if (res.success) {
                    vm.platoons = res.data;
                }
            });
        }

        //function to set in 'vm' list of Sections by platoonId
        function getSections(platoonId) {
            if (platoonId == null) return;
            ConfirmUsersService.section({platoonId: platoonId}).$promise.then((res) => {
                if (res.success) {
                    vm.sections = res.data;
                }
            });
        }

        //Special function for view to correct change group
        function changeGroup(cityId) {
            getGroups(cityId);
            vm.platoons = null;
            vm.sections = null;
        }

        //Same, but to correct change platoon
        function changePlatoon(groupId) {
            getPlatoons(groupId);
            vm.sections = null;
        }

        //function to set in 'vm' list of Ranks
        function getRanks() {
            vm.ranks = [
                {id: 2, name: 'Помічник'},
                {id: 3, name: 'Старший помічник'},
                {id: 1, name: 'Молодший помічник'}];
        }
    }
})();<commit_msg>Add reading platoonId from $rootScope<commit_after>(() => {

    'use strict';

    angular
        .module('app')
        .controller('ConfirmUsersController', ConfirmUsersController);
    ConfirmUsersController.$inject = ['$rootScope', 'growl', '$log', '$route', 'ConfirmUsersService'];

    //This controller allows administrator get, edit, approve or decline unapproved users
    //TODO: make use to getUsers(id) admin.platoonId instead of static id
    //TODO: confirm list of available fields for request to approve user
    //TODO: complete function to get list of Ranks from server
    //TODO: test how good disable some ui elements before them content fully loaded
    //TODO: delete JSON.parse();
    //TODO: try to use angular modal instead of bootstrap ones
    //TODO: test api to approve and decline users
    //TODO: use api to update user data
    function ConfirmUsersController($rootScope, growl, $log, $route, ConfirmUsersService) {
        //Set variables
        const vm = this;
        const editUserModal = '#EditUser';            //name of modal window to edit user
        const confirmDeleteModal = '#ConfirmDelete';  //same, but to confirm decline user
        vm.usersList = [];
        vm.currentUser = {};
        vm.editUser = editUser;
        vm.changeGroup = changeGroup;
        vm.changePlatoon = changePlatoon;
        vm.getSections = getSections;
        vm.approveUser = approveUser;
        vm.declineUser = declineUser;
        vm.showConfirmDecline = showConfirmDecline;

        activate();

        ////

        function activate() {
            $log.debug('Init ConfirmUsersController ...');
            //Get list of unapproved users with same 'platoonId' as admin's
            getUsers($rootScope.currentUser.platoon);
            //init "FooTable" plugin in all tables with 'footable' class
            $(document).ready(function () {
                $('.footable').footable();
            });
            $log.debug('Init complete.');
        }

        //Function to set in 'vm' user list with specified platoonId
        function getUsers(grId) {
            ConfirmUsersService.getUsers({platoonId: grId}).$promise.then((res) => {
                if (res.success) {
                    let result;
                    result = JSON.parse(res.data.message);
                    result.forEach((item) => {
                        item.birthDate = new Date(item.birthDate);  //use 'new Data()' instead of raw int
                    });
                    vm.usersList = result;
                    $log.debug('Load users list:', vm.usersList);
                }
            });
        }

        //Function to edit currentUser
        function editUser(id) {
            vm.currentUser = vm.usersList.find((item) => item.id == id) || {};
            getCities(vm.currentUser.countryId);
            getGroups(vm.currentUser.cityId);
            getPlatoons(vm.currentUser.groupId);
            getSections(vm.currentUser.platoonId);
            getRanks();
            $(editUserModal).modal();       //load modal window in view (maybe incorrect)
            $log.debug('Edit user:', vm.currentUser);
        }

        //Function to approve currentUser
        function approveUser() {
            $(editUserModal).modal('hide'); //immediately hide modal window to prevent double confirm
            // let valuesToSend = {
            //     "firstName": vm.currentUser.firstName,
            //     "lastName": vm.currentUser.lastName,
            //     "gender": vm.currentUser.gender,
            //     "phoneNumber": vm.currentUser.phoneNumber,
            //     "birthDate": vm.currentUser.birthDate.getTime(),
            //     "cityId": vm.currentUser.cityId,
            //     "groupId": vm.currentUser.groupId,
            //     "platoonId": vm.currentUser.platoonId,
            //     "sectionId": vm.currentUser.sectionId,
            //     "rankId": vm.currentUser.rankId
            // };
            ConfirmUsersService.approveUser([vm.currentUser.id],
                (res) => {
                    if (res.success) {
                        growl.success('Користувач ' + vm.currentUser.firstName + ' ' +
                            vm.currentUser.lastName + ' підтверджений');
                        $route.reload();
                    } else {
                        growl.error('Помилка:' + res.data.message);
                    }
                });
            // ConfirmUsersService.updateUser({userId: vm.currentUser.id}, valuesToSend,
            //     (res) => {
            //         if (res.success) {
            //             growl.success('Користувач ' + vm.currentUser.firstName + ' ' +
            //                 vm.currentUser.lastName + ' підтверджений');
            //             $route.reload();
            //         } else {
            //             growl.error('Помилка:' + res.data.message);
            //         }
            //     });
        }

        //Function to decline currentUser
        function declineUser() {
            $(confirmDeleteModal).modal('hide');    //prevent double decline
            $(editUserModal).modal('hide');         //also to prevent double decline
            ConfirmUsersService.declineUser([vm.currentUser.id],
                (res) => {
                    if (res.success) {
                        growl.info('Користувач ' + vm.currentUser.firstName + ' ' +
                            vm.currentUser.lastName + ' видалений');
                        $route.reload();
                    } else {
                        growl.error('Помилка:' + res.data.message);
                    }
                });
        }

        //This additional function needed just to create another modal with 'confirm decline user'
        function showConfirmDecline() {
            $(confirmDeleteModal).modal();
        }

        //function to set in 'vm' list of Cities by countryId
        function getCities(countryId) {
            if (countryId == null) return;
            ConfirmUsersService.city({countryId: countryId}).$promise.then((res) => {
                if (res.success) {
                    vm.cities = res.data;
                }
            });
        }

        //function to set in 'vm' list of Groups by cityId
        function getGroups(cityId) {
            if (cityId == null) return;
            ConfirmUsersService.group({cityId: cityId}).$promise.then((res) => {
                if (res.success) {
                    vm.groups = res.data;
                }
            });
        }

        //function to set in 'vm' list of Platoons by groupId
        function getPlatoons(groupId) {
            if (groupId == null) return;
            ConfirmUsersService.platoon({groupId: groupId}).$promise.then((res) => {
                if (res.success) {
                    vm.platoons = res.data;
                }
            });
        }

        //function to set in 'vm' list of Sections by platoonId
        function getSections(platoonId) {
            if (platoonId == null) return;
            ConfirmUsersService.section({platoonId: platoonId}).$promise.then((res) => {
                if (res.success) {
                    vm.sections = res.data;
                }
            });
        }

        //Special function for view to correct change group
        function changeGroup(cityId) {
            getGroups(cityId);
            vm.platoons = null;
            vm.sections = null;
        }

        //Same, but to correct change platoon
        function changePlatoon(groupId) {
            getPlatoons(groupId);
            vm.sections = null;
        }

        //function to set in 'vm' list of Ranks
        function getRanks() {
            vm.ranks = [
                {id: 2, name: 'Помічник'},
                {id: 3, name: 'Старший помічник'},
                {id: 1, name: 'Молодший помічник'}];
        }
    }
})();<|endoftext|>


<commit_before>const projData = [{"project":"Is death the great equalizer?","url":"https://apps.bostonglobe.com/metro/investigations/spotlight/2020/09/last-words/part1-dying-poor/index.html","org":"The Boston Globe","img":"https://apps.bostonglobe.com/metro/investigations/spotlight/2020/09/last-words/assets/images/day1-share.jpg"},
{"project":"The virus’s tale","url":"https://apps.bostonglobe.com/metro/graphics/2020/05/coronavirus-tale/","org":"The Boston Globe","img":"coronavirus-tale-og.jpg"},
{"project":"Coronavirus deaths in Mass. are likely far higher than what’s been reported. Here’s why","url":"https://www.bostonglobe.com/2020/04/22/nation/official-toll-massachusetts-coronavirus-deaths-likely-undercounted-review-shows/","org":"The Boston Globe","img":"https://bostonglobe-prod.cdn.arcpublishing.com/resizer/6vUM1pxTNJi5-uV8OpZrqlUckYI=/1440x0/arc-anglerfish-arc2-prod-bostonglobe.s3.amazonaws.com/public/TFUVTTODH6XSVP6AVDGY5X5AMU.jpg"},
{"project":"How overwhelmed could New England hospitals become? Explore maps of different scenarios","url":"https://www.bostonglobe.com/2020/03/26/nation/how-overwhelmed-could-new-england-hospitals-become-explore-maps-different-scenarios/","org":"The Boston Globe","img":"https://bostonglobe-prod.cdn.arcpublishing.com/resizer/It_ElsukaYmpbH312-Anx_cHbhg=/1440x0/arc-anglerfish-arc2-prod-bostonglobe.s3.amazonaws.com/public/CBSAPTBWBBHLRHUHNFINSKFRFY.jpg"},
{"project":"Seeing Red: A Spotlight report on traffic and congestion in metro Boston ","url":"https://apps.bostonglobe.com/metro/investigations/spotlight/2019/11/19/seeing-red/","org":"The Boston Globe","img":"https://apps.bostonglobe.com/metro/investigations/spotlight/2019/11/19/seeing-red/assets/images/optimized/ryantrafficrush3spotlight_1280.jpg"},
{"project":"At the edge of a warming world","url":"https://apps.bostonglobe.com/metro/2019/09/26/cape-cod-climate-change/story/","org":"The Boston Globe","img":"https://apps.bostonglobe.com/metro/2019/09/26/cape-cod-climate-change/assets/images/landing_1280.jpg"},
{"project":"For Red Line commutes, a roll of the dice and branch determine timing","url":"https://www.bostonglobe.com/metro/2019/08/06/roll-dice-red-line/oVvMxKrNk4sdruBzdRUzFM/story.html","org":"The Boston Globe","img":"https://bostonglobe-prod.cdn.arcpublishing.com/resizer/K8hASOuwACEUyQt1O7xETrc4PHo=/1440x0/arc-anglerfish-arc2-prod-bostonglobe.s3.amazonaws.com/public/QDLA3TVPXEI6TJPIHE2PSPSJ2I.jpg"},
{"project":"The Valedictorians Project: What became of Boston's brightest?","url":"https://apps.bostonglobe.com/magazine/graphics/2019/01/17/valedictorians/","org":"The Boston Globe","img":"landingcover_1200.jpg"},
{"project":"Who’s running for president in 2020?","url":"https://apps.bostonglobe.com/news/politics/graphics/2019/03/president-2020-candidates/","org":"The Boston Globe","img":"og-2020.jpg"},
{"project":"What the Mueller report says about Trump and more","url":"https://apps.bostonglobe.com/news/politics/graphics/2019/03/mueller-report/","org":"The Boston Globe","img":"report_topper.jpg"},
{"project":"Here’s how the Patriots Super Bowl roster evolved around Tom Brady","url":"https://apps.bostonglobe.com/sports/graphics/2019/02/03/superbowl-2019-patriots-roster-brady/","org":"The Boston Globe","img":"og.jpg"},
{"project":"Inside the secret courts of Massachusetts","url":"https://apps.bostonglobe.com/metro/investigations/spotlight/secret-courts-in-massachusetts/","org":"The Boston Globe","img":"secret_og_1200.jpg"},
{"project":"Gladiator: The story of Aaron Hernandez and Football Inc.","url":"https://apps.bostonglobe.com/spotlight/gladiator/","org":"The Boston Globe","img":"gladiator_og.jpg"},
{"project":"Elections 2018","url":"https://www3.bostonglobe.com/elections/2018/?arc404=true","org":"The Boston Globe","img":"https://apps.bostonglobe.com/elections/2018/assets/images/election_us_og.jpg"},
{"project":"What happened when Boston Public Schools tried for equity with an algorithm","url":"https://apps.bostonglobe.com/ideas/graphics/2018/09/equity-machine/","org":"The Boston Globe","img":"https://apps.bostonglobe.com/ideas/graphics/2018/09/equity-machine/assets/og.jpg"},
{"project":"Journalists are not the enemy","url":"https://apps.bostonglobe.com/opinion/graphics/2018/08/freepress/","org":"The Boston Globe","img":"https://apps.bostonglobe.com/opinion/graphics/2018/08/freepress/assets/freepress_og.jpg"},
{"project":"TSA is tracking regular travelers like terrorists in secret surveillance","url":"https://apps.bostonglobe.com/news/nation/graphics/2018/07/tsa-quiet-skies/","org":"The Boston Globe","img":"https://apps.bostonglobe.com/news/nation/graphics/2018/07/tsa-quiet-skies/assets/img/airport_delay_1200.jpg"},
{"project":"Traffic, crowding, cancellations: This MBTA route shows all the T’s bus problems","url":"https://apps.bostonglobe.com/metro/graphics/2018/08/111-bus/","org":"The Boston Globe","img":"https://apps.bostonglobe.com/metro/graphics/2018/08/111-bus/assets/img/bus_og_1200.jpg"},
{"project":"The case for ending Google’s Internet domination","url":"https://apps.bostonglobe.com/opinion/graphics/2018/06/break-google/","org":"The Boston Globe","img":"break.gif"},
{"project":"Doctors and sex abuse: How well does your state protect patients?","url":"https://doctors.ajc.com/states/","org":"Atlanta Journal-Constitution","img":"http://s3.amazonaws.com/ajc-doctors-images/Doc-stethoscope-intro_social.jpg"},
{"project":"Families, not job seekers, gain the most from legal immigration","url":"https://www.ajc.com/news/gen-politics/families-not-job-seekers-gain-the-most-from-legal-immigration/mMeYq4d9MuXy4d5TwCvOPJ/","org":"Atlanta Journal-Constitution","img":"https://www.ajc.com/rf/image_lowres/Pub/p8/MyAJC/2017/08/07/Images/green-cards_by-categ-460-460.png"},
{"project":"Which are Georgia's winning industries?","url":"https://www.ajc.com/business/which-are-georgia-winning-and-losing-job-industries-since-2000/8eIZ0Q6X1NfMjk3KEYSsZJ/","org":"Atlanta Journal-Constitution","img":"https://s3.amazonaws.com/ajc-staging-sites/georgia-industries/img/trade-all.jpg"},
{"project":"How Georgia’s Sixth Congressional District voted","url":"https://www.ajc.com/news/gen-politics/how-each-neighborhood-voted-the-6th-district-runoff/72ZamHK2RQLoVsvFhcfWjM/","org":"Atlanta Journal-Constitution","img":"map-precinct.jpg"},
{"project":"After Virginia, Georgia has the most Confederate symbols in the country","url":"https://www.ajc.com/news/state--regional-govt--politics/after-virginia-georgia-has-the-most-confederate-symbols-the-country/vZPnQ2kGSd9xgURzS5kJiJ/","org":"Atlanta Journal-Constitution","img":"https://www.ajc.com/rf/image_lowres/Pub/p8/AJC/2017/08/18/Images/newsEngin.19603242_030616_IN_stone1.jpg"},
{"project":"The Ultimate Atlanta School Guide","url":"https://schools.ajc.com/#/schools","org":"Atlanta Journal-Constitution","img":"https://schools.ajc.com/images/school.jpg"}];

const projects = d3.select('#code-projects')
  .selectAll('.portfolio-item')
  .data(projData)
  .join('div')
  .attr('class', 'portfolio-item');

const links = projects
  .append('a')
  .attr('href', d => d.url);

const divs = links
  .append('div')
  .attr('class', 'portfolio-item__img');

divs.append('img')
  .attr('src', d => d.img.indexOf('http') > -1 ? d.img :
    d.project.indexOf('Sixth Congressional') > -1
    ? 'assets/map-precinct.jpg' :
    `${d.url}assets/images/${d.img}`);

divs.append('h3')
  .attr('class', 'portfolio-item__title')
  .text(d => d.project);

divs.append('p')
  .attr('class', 'portfolio-item__org')
  .append('span')
  .text(d => d.org);<commit_msg>Adding WBUR byline<commit_after>const projData = [{"project":"Utility Regulators Ignored Conflict Of Interest Concerns For National Grid Audit","url":"https://www.wbur.org/investigations/2020/11/12/conflict-of-interest-investigation-national-grid-utility-regulators-massachusetts","org":"WBUR","img":"https://d279m997dpfwgl.cloudfront.net/wp/2020/11/1109_national-grid01-1000x667.jpg"},
{"project":"Is death the great equalizer?","url":"https://apps.bostonglobe.com/metro/investigations/spotlight/2020/09/last-words/part1-dying-poor/index.html","org":"The Boston Globe","img":"https://apps.bostonglobe.com/metro/investigations/spotlight/2020/09/last-words/assets/images/day1-share.jpg"},
{"project":"The virus’s tale","url":"https://apps.bostonglobe.com/metro/graphics/2020/05/coronavirus-tale/","org":"The Boston Globe","img":"coronavirus-tale-og.jpg"},
{"project":"Coronavirus deaths in Mass. are likely far higher than what’s been reported. Here’s why","url":"https://www.bostonglobe.com/2020/04/22/nation/official-toll-massachusetts-coronavirus-deaths-likely-undercounted-review-shows/","org":"The Boston Globe","img":"https://bostonglobe-prod.cdn.arcpublishing.com/resizer/6vUM1pxTNJi5-uV8OpZrqlUckYI=/1440x0/arc-anglerfish-arc2-prod-bostonglobe.s3.amazonaws.com/public/TFUVTTODH6XSVP6AVDGY5X5AMU.jpg"},
{"project":"How overwhelmed could New England hospitals become? Explore maps of different scenarios","url":"https://www.bostonglobe.com/2020/03/26/nation/how-overwhelmed-could-new-england-hospitals-become-explore-maps-different-scenarios/","org":"The Boston Globe","img":"https://bostonglobe-prod.cdn.arcpublishing.com/resizer/It_ElsukaYmpbH312-Anx_cHbhg=/1440x0/arc-anglerfish-arc2-prod-bostonglobe.s3.amazonaws.com/public/CBSAPTBWBBHLRHUHNFINSKFRFY.jpg"},
{"project":"Seeing Red: A Spotlight report on traffic and congestion in metro Boston ","url":"https://apps.bostonglobe.com/metro/investigations/spotlight/2019/11/19/seeing-red/","org":"The Boston Globe","img":"https://apps.bostonglobe.com/metro/investigations/spotlight/2019/11/19/seeing-red/assets/images/optimized/ryantrafficrush3spotlight_1280.jpg"},
{"project":"At the edge of a warming world","url":"https://apps.bostonglobe.com/metro/2019/09/26/cape-cod-climate-change/story/","org":"The Boston Globe","img":"https://apps.bostonglobe.com/metro/2019/09/26/cape-cod-climate-change/assets/images/landing_1280.jpg"},
{"project":"For Red Line commutes, a roll of the dice and branch determine timing","url":"https://www.bostonglobe.com/metro/2019/08/06/roll-dice-red-line/oVvMxKrNk4sdruBzdRUzFM/story.html","org":"The Boston Globe","img":"https://bostonglobe-prod.cdn.arcpublishing.com/resizer/K8hASOuwACEUyQt1O7xETrc4PHo=/1440x0/arc-anglerfish-arc2-prod-bostonglobe.s3.amazonaws.com/public/QDLA3TVPXEI6TJPIHE2PSPSJ2I.jpg"},
{"project":"The Valedictorians Project: What became of Boston's brightest?","url":"https://apps.bostonglobe.com/magazine/graphics/2019/01/17/valedictorians/","org":"The Boston Globe","img":"landingcover_1200.jpg"},
{"project":"Who’s running for president in 2020?","url":"https://apps.bostonglobe.com/news/politics/graphics/2019/03/president-2020-candidates/","org":"The Boston Globe","img":"og-2020.jpg"},
{"project":"What the Mueller report says about Trump and more","url":"https://apps.bostonglobe.com/news/politics/graphics/2019/03/mueller-report/","org":"The Boston Globe","img":"report_topper.jpg"},
{"project":"Here’s how the Patriots Super Bowl roster evolved around Tom Brady","url":"https://apps.bostonglobe.com/sports/graphics/2019/02/03/superbowl-2019-patriots-roster-brady/","org":"The Boston Globe","img":"og.jpg"},
{"project":"Inside the secret courts of Massachusetts","url":"https://apps.bostonglobe.com/metro/investigations/spotlight/secret-courts-in-massachusetts/","org":"The Boston Globe","img":"secret_og_1200.jpg"},
{"project":"Gladiator: The story of Aaron Hernandez and Football Inc.","url":"https://apps.bostonglobe.com/spotlight/gladiator/","org":"The Boston Globe","img":"gladiator_og.jpg"},
{"project":"Elections 2018","url":"https://www3.bostonglobe.com/elections/2018/?arc404=true","org":"The Boston Globe","img":"https://apps.bostonglobe.com/elections/2018/assets/images/election_us_og.jpg"},
{"project":"What happened when Boston Public Schools tried for equity with an algorithm","url":"https://apps.bostonglobe.com/ideas/graphics/2018/09/equity-machine/","org":"The Boston Globe","img":"https://apps.bostonglobe.com/ideas/graphics/2018/09/equity-machine/assets/og.jpg"},
{"project":"Journalists are not the enemy","url":"https://apps.bostonglobe.com/opinion/graphics/2018/08/freepress/","org":"The Boston Globe","img":"https://apps.bostonglobe.com/opinion/graphics/2018/08/freepress/assets/freepress_og.jpg"},
{"project":"TSA is tracking regular travelers like terrorists in secret surveillance","url":"https://apps.bostonglobe.com/news/nation/graphics/2018/07/tsa-quiet-skies/","org":"The Boston Globe","img":"https://apps.bostonglobe.com/news/nation/graphics/2018/07/tsa-quiet-skies/assets/img/airport_delay_1200.jpg"},
{"project":"Traffic, crowding, cancellations: This MBTA route shows all the T’s bus problems","url":"https://apps.bostonglobe.com/metro/graphics/2018/08/111-bus/","org":"The Boston Globe","img":"https://apps.bostonglobe.com/metro/graphics/2018/08/111-bus/assets/img/bus_og_1200.jpg"},
{"project":"The case for ending Google’s Internet domination","url":"https://apps.bostonglobe.com/opinion/graphics/2018/06/break-google/","org":"The Boston Globe","img":"break.gif"},
{"project":"Doctors and sex abuse: How well does your state protect patients?","url":"https://doctors.ajc.com/states/","org":"Atlanta Journal-Constitution","img":"http://s3.amazonaws.com/ajc-doctors-images/Doc-stethoscope-intro_social.jpg"},
{"project":"Families, not job seekers, gain the most from legal immigration","url":"https://www.ajc.com/news/gen-politics/families-not-job-seekers-gain-the-most-from-legal-immigration/mMeYq4d9MuXy4d5TwCvOPJ/","org":"Atlanta Journal-Constitution","img":"https://www.ajc.com/rf/image_lowres/Pub/p8/MyAJC/2017/08/07/Images/green-cards_by-categ-460-460.png"},
{"project":"Which are Georgia's winning industries?","url":"https://www.ajc.com/business/which-are-georgia-winning-and-losing-job-industries-since-2000/8eIZ0Q6X1NfMjk3KEYSsZJ/","org":"Atlanta Journal-Constitution","img":"https://s3.amazonaws.com/ajc-staging-sites/georgia-industries/img/trade-all.jpg"},
{"project":"How Georgia’s Sixth Congressional District voted","url":"https://www.ajc.com/news/gen-politics/how-each-neighborhood-voted-the-6th-district-runoff/72ZamHK2RQLoVsvFhcfWjM/","org":"Atlanta Journal-Constitution","img":"map-precinct.jpg"},
{"project":"After Virginia, Georgia has the most Confederate symbols in the country","url":"https://www.ajc.com/news/state--regional-govt--politics/after-virginia-georgia-has-the-most-confederate-symbols-the-country/vZPnQ2kGSd9xgURzS5kJiJ/","org":"Atlanta Journal-Constitution","img":"https://www.ajc.com/rf/image_lowres/Pub/p8/AJC/2017/08/18/Images/newsEngin.19603242_030616_IN_stone1.jpg"},
{"project":"The Ultimate Atlanta School Guide","url":"https://schools.ajc.com/#/schools","org":"Atlanta Journal-Constitution","img":"https://schools.ajc.com/images/school.jpg"}];

const projects = d3.select('#code-projects')
  .selectAll('.portfolio-item')
  .data(projData)
  .join('div')
  .attr('class', 'portfolio-item');

const links = projects
  .append('a')
  .attr('href', d => d.url);

const divs = links
  .append('div')
  .attr('class', 'portfolio-item__img');

divs.append('img')
  .attr('src', d => d.img.indexOf('http') > -1 ? d.img :
    d.project.indexOf('Sixth Congressional') > -1
    ? 'assets/map-precinct.jpg' :
    `${d.url}assets/images/${d.img}`);

divs.append('h3')
  .attr('class', 'portfolio-item__title')
  .text(d => d.project);

divs.append('p')
  .attr('class', 'portfolio-item__org')
  .append('span')
  .text(d => d.org);<|endoftext|>


<commit_before>if (require('electron-squirrel-startup')) return;
const $ = jQuery = require('jquery')
const http       = require('http')
, CLogger  = require('node-clogger')
const path = require('path')
const nightlife  = require('nightlife-rabbit')
    , autobahn = require('autobahn')
const child_process = require("child_process")
const electron = require('electron')
const app = electron.app
const BrowserWindow = electron.BrowserWindow

let backendProcess = undefined

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow

function createWindow () {
  mainWindow = new BrowserWindow({width: 1200, height: 900})
  mainWindow.loadURL("file://" + __dirname + "/src/index.html")

  mainWindow.on('closed', function () {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null
    app.quit();
  })
}

app.on('before-quit', function(){

  if (backendProcess){
    try {
      if (process.platform == "darwin") {
        backendProcess.kill();
      }
      else if (process.platform == "win32") {
        child_process.exec('taskkill /T /F /IM otone_client.exe');
      }
    }
    catch(e){
      console.log(e);
    }
  }
});

function startWampRouter() {
    var router = nightlife.createRouter({
        httpServer: http.createServer(),
        port: 8080,
        path: '/ws',
        autoCreateRealms: true,
        logger: new CLogger({name: 'nightlife-router'})
    });
}

function startBackend() {
  if (process.platform == "darwin") {
    backendProcess = child_process.exec(app.getAppPath() + "/backend-dist/mac/otone_client " + app.getAppPath());
  } else if (process.platform == "win32") {
    if (process.platform == "win32") {
      child_process.exec('taskkill /T /F /IM otone_client.exe',function(error, stdout, stderr){
        backendProcess = child_process.execFile(app.getAppPath() + "\\backend-dist\\win\\otone_client.exe", [app.getAppPath()]);
      });
    }
  }
}

app.on('ready', createWindow)
app.on('ready', startWampRouter)
app.on('ready', startBackend)

app.on('window-all-closed', function () {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', function () {
  if (mainWindow === null) {
    createWindow()
  }
})
<commit_msg>moved back to .spawn() when calling .exe on Windows (execFile was used for a test and is uneeded)<commit_after>if (require('electron-squirrel-startup')) return;
const $ = jQuery = require('jquery')
const http       = require('http')
, CLogger  = require('node-clogger')
const path = require('path')
const nightlife  = require('nightlife-rabbit')
    , autobahn = require('autobahn')
const child_process = require("child_process")
const electron = require('electron')
const app = electron.app
const BrowserWindow = electron.BrowserWindow

let backendProcess = undefined

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow

function createWindow () {
  mainWindow = new BrowserWindow({width: 1200, height: 900})
  mainWindow.loadURL("file://" + __dirname + "/src/index.html")

  mainWindow.on('closed', function () {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null
    app.quit();
  })
}

app.on('before-quit', function(){

  if (backendProcess){
    try {
      if (process.platform == "darwin") {
        backendProcess.kill();
      }
      else if (process.platform == "win32") {
        child_process.exec('taskkill /T /F /IM otone_client.exe');
      }
    }
    catch(e){
      console.log(e);
    }
  }
});

function startWampRouter() {
    var router = nightlife.createRouter({
        httpServer: http.createServer(),
        port: 8080,
        path: '/ws',
        autoCreateRealms: true,
        logger: new CLogger({name: 'nightlife-router'})
    });
}

function startBackend() {
  if (process.platform == "darwin") {
    backendProcess = child_process.exec(app.getAppPath() + "/backend-dist/mac/otone_client " + app.getAppPath());
  } else if (process.platform == "win32") {
    if (process.platform == "win32") {
      child_process.exec('taskkill /T /F /IM otone_client.exe',function(error, stdout, stderr){
        backendProcess = child_process.spawn(app.getAppPath() + "\\backend-dist\\win\\otone_client.exe", [app.getAppPath()]);
      });
    }
  }
}

app.on('ready', createWindow)
app.on('ready', startWampRouter)
app.on('ready', startBackend)

app.on('window-all-closed', function () {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', function () {
  if (mainWindow === null) {
    createWindow()
  }
})
<|endoftext|>


<commit_before>// Create the module and name it app
var app = angular.module('DockerWebUI', ['ngCookies','ngRoute']);

/*
 *This config command configures all $http requests to be send with 'X-Requested-With' header
 * which is required by docker-registry flask server
 */
app.config(function($httpProvider){
	delete $httpProvider.defaults.headers.common['X-Requested-With'];
});

// configure our routes.
/*
 *Using routes we create a single page application(SPA), with index.html as the base template and then loading
 *various views using ng-view, and anchor tags.
 */
app.config(function($routeProvider) {
	$routeProvider

		// route for the home page
		.when('/', {
			templateUrl : 'pages/home.html',
			controller  : 'MainController'
		})

		// route for the showNamespaces page
		.when('/showNamespaces', {
			templateUrl : 'pages/showNamespaces.html',
			controller  : 'NamespacesController'
		})

		// route for the showNamespacesRepos page
		.when('/showNamespacesRepos', {
			templateUrl : 'pages/showNamespacesRepos.html',
			controller  : 'NamespacesReposController'
		})

		// route for the showRepositories page
		.when('/showRepositories', {
			templateUrl : 'pages/showRepositories.html',
			controller  : 'RepositoriesController'
		})

		// route for the showImages page
		.when('/showImages', {
			templateUrl : 'pages/showImages.html',
			controller  : 'ImagesController'
		});
});

/*This service is used to define the object which stores the current Docker-registry IP address and defines the getter and setter
  methods for accessing  and modifyingthe IP address.
*/
app.service('IPService', function () {
	var IP = '192.168.1.1';
	return {
		getIP: function () {
			return IP;
		},
		setIP: function(value) {
			IP = value;
		}
	};
});

// create the Main controller (for index.html) and inject Angular's $scope
app.controller('MainController', ['$scope','IPService','$route','$window','$cookies',function($scope,IPService,$route,$window,$cookies) {
	// create a message to display in our view
	$scope.inputIP='';
	//$cookies.IP='localhost';
	//$scope.cookieIP=$cookies.IP;
	//console.log('The cookiestore ip is' + $scope.cookieIP);
	$scope.setIP=function(inputIP)
	{
		IPService.setIP(inputIP);
		$cookies.IP=inputIP;
		//$cookieStore.put(‘IP’, inputIP);
		console.log('the IP has been changed to '+IPService.getIP());
		$window.location.href = "#showNamespaces";
		$route.reload();
	}
}]);

//Show Namespaces controller, all JS code for showNamespaces page is here
app.controller('NamespacesController', function($rootScope,$scope,$http,IPService,$route,$cookies) {

	$scope.message = 'shownamespaces page';
	//$scope.IP=IPService.getIP();
	$scope.IP=$cookies.IP;
	//$scope.IP=$cookieStore.get(‘ip’);
	console.log('the ip is ' + $scope.IP);
	$scope.num_results=0;
	$scope.dictionary={};
	$scope.namespacesList=[];
	results=[];
	//namespaces=[];
	//images=[];

	$http({method: 'GET', url: 'http://'+$scope.IP+'/v1/search'}).success(function(data)
	{
		$scope.num_results=data.num_results;
		results=data.results;
		angular.forEach(results,function(result)
		{
			$scope.dictionary[result.name.split('/')[0]]=[];
		});
		angular.forEach(results,function(result)
		{
			//namespaces.push(result.name.split('/')[0]);
			//images.push(result.name.split('/')[1]);
			$scope.dictionary[result.name.split('/')[0]].push(result.name.split('/')[1]);
		});
		angular.forEach($scope.dictionary,function(key,value)
		{
			temp={};
			temp['name']=value;
			$scope.namespacesList.push(temp);
		});
	}).error(function(data){alert('Unable to reuest.')});

});

//Show NamespacesRepos controller, all JS code for showNamespaces page is here
app.controller('NamespacesReposController', function($rootScope,$scope,$http,IPService,$route,$cookies,$location) {

	$scope.queryAll=$location.search()['queryAll'];
	if($scope.queryAll === undefined || $scope.queryAll === "")
	{
		$scope.IP=$cookies.IP;
		console.log('the ip is ' + $scope.IP);
		$scope.num_results=0;
		$scope.namespacesReposList=[];
		$http({method: 'GET', url: 'http://'+$scope.IP+'/v1/search'}).success(function(data)
		{
			$scope.num_results=data.num_results;
			$scope.namespacesReposList=data.results;
		}).error(function(data){alert('Unable to request.')});
	}
	else
	{
		$scope.IP=$cookies.IP;
		console.log('the ip is ' + $scope.IP);
		$scope.num_results=0;
		$scope.namespacesReposList=[];
		$http({method: 'GET', url: 'http://'+$scope.IP+'/v1/search'}).success(function(data)
		{
			$scope.num_results=data.num_results;
			angular.forEach(data.results,function(result)
			{
				$scope.queryAll = angular.lowercase($scope.queryAll);
				if( result.name.indexOf($scope.queryAll) >= 0 )
					$scope.namespacesReposList.push(result);
			});
		}).error(function(data){alert('Unable to request.')});

	}
});

//Show repositories controller, all JS code for showRepositories page is here
app.controller('RepositoriesController', function($scope,$http,$location,IPService,$window,$cookies,$route) {
	//$scope.IP=IPService.getIP();
	$scope.IP=$cookies.IP;
	$scope.namespace=$location.search()['namespace'];
	$scope.num_results=0;
	$scope.repositoriesList=[];
	$scope.go = function (path) {
	$location.path(path);
	};
	$http({method: 'GET', url: 'http://'+$scope.IP+'/v1/search'}).success(function(data)
	{
		$scope.num_results=data.num_results;
		results=data.results;
		angular.forEach(results,function(result)
		{
			if(result.name.split('/')[0]===$scope.namespace)
			{
				temp={};
				temp['name']=result.name.split('/')[1];
				$scope.repositoriesList.push(temp);
			}
		});
	}).error(function(data){alert('Unable to request.')});
	deleteRepoURL='http://'+$scope.IP+'/v1/repositories/'+$scope.namespace;
	$scope.deleteRepo = function (repo)
	{

			$http.delete(deleteRepoURL+'/'+repo +'/').success(function (data)
			{
				console.log('Deleted Repo : '+repo);
				$window.location.href = "#showRepositories?namespace="+$scope.namespace;
				$route.reload();
			}).error(function(data){});;
	};
});

//Show images controller, all JS code for showImages page is here
app.controller('ImagesController', function($scope,$http,$location,IPService,$window,$cookies,$route) {
	//$scope.IP=IPService.getIP();
	$scope.IP=$cookies.IP;
	//$scope.newTag='';
	$scope.namespace=$location.search()['namespace'];
	$scope.repository=$location.search()['repository'];
	$scope.tagsList=[];
	URL='http://'+$scope.IP+'/v1/repositories/'+$scope.namespace+'/'+$scope.repository+'/tags';
	$scope.deleteTag = function (tag)
	{

			$http.delete(URL+'/'+tag).success(function (data)
			{
				console.log('Deleted tag : '+tag);
				$window.location.href = "#showImages?namespace="+$scope.namespace+"&repository="+$scope.repository;
				$route.reload();
			}).error(function(data){alert('Unable to delete.')});;
	};
	deleteRepoURL='http://'+$scope.IP+'/v1/repositories/'+$scope.namespace+'/'+ $scope.repository;
	$scope.deleteRepo = function ()
	{

			$http.delete(deleteRepoURL+'/').success(function (data)
			{
				console.log('Deleted Repo : '+$scope.repository);
				$window.location.href = "#showRepositories?namespace="+$scope.namespace;
				$route.reload();
			}).error(function(data){});;
	};

	/*This function gets 2 parameters the old tag before editand the new tag after edit.
	 * This function will delete the old tag after getting the image id attached to it, use this image ID
	 * to put the new tag in the repository, thus having the same effect as editing a tag.
	 */
	$scope.changeTag = function (oldTag,newTag)
	{
		$scope.oldTagURL=URL+'/'+oldTag;
		$scope.newTagURL=URL+'/'+newTag;
		$scope.imageID='';
		imageId='\"hello\"';
		console.log('image id fetch url is '+ $scope.oldTagURL);
		console.log('tag putting url is ' + $scope.newTagURL);
		console.log('new tag is '+ newTag);
		if(newTag !== undefined)
		{

			$http({method: 'GET', url: $scope.oldTagURL }).success(function(data)
			{
				console.log('Data fetched : '+data);
				imageId='\"'+data.replace(/"/g,'')+'\"';
				$http.delete($scope.oldTagURL).success(function (data)
				{
					$http({method: 'PUT', url: $scope.newTagURL, data: imageId , headers: {"Content-Type": "application/json","Accept": "application/json"}}).success(function(data)
					{
						$window.location.href = "#showImages?namespace="+$scope.namespace+"&repository="+$scope.repository;
						$route.reload();
					}).error(function(data){
					console.log('Unable to set tag for imageID');
					});

				}).error(function(data){alert('Unable to delete.')});

			}).error(function(data){console.log('Unable to get image ID for tag')});

		}
		else
		{
			console.log('New tag is empty. Not doing anything');
		}

	}

	$http({method: 'GET', url: URL }).success(function(data)
	{
		$scope.results=data;
		numTags=0;
		angular.forEach($scope.results,function(key,value)
		{
			numTags++;
			temp={};
			temp['name']=value;
			temp['id']=numTags;
			$scope.tagsList.push(temp);
		});
	}).error(function(data){alert('Unable to request.')});
});

<commit_msg>fixed : issue#41<commit_after>// Create the module and name it app
var app = angular.module('DockerWebUI', ['ngCookies','ngRoute']);

/*
 *This config command configures all $http requests to be send with 'X-Requested-With' header
 * which is required by docker-registry flask server
 */
app.config(function($httpProvider){
	delete $httpProvider.defaults.headers.common['X-Requested-With'];
});

// configure our routes.
/*
 *Using routes we create a single page application(SPA), with index.html as the base template and then loading
 *various views using ng-view, and anchor tags.
 */
app.config(function($routeProvider) {
	$routeProvider

		// route for the home page
		.when('/', {
			templateUrl : 'pages/home.html',
			controller  : 'MainController'
		})

		// route for the showNamespaces page
		.when('/showNamespaces', {
			templateUrl : 'pages/showNamespaces.html',
			controller  : 'NamespacesController'
		})

		// route for the showNamespacesRepos page
		.when('/showNamespacesRepos', {
			templateUrl : 'pages/showNamespacesRepos.html',
			controller  : 'NamespacesReposController'
		})

		// route for the showRepositories page
		.when('/showRepositories', {
			templateUrl : 'pages/showRepositories.html',
			controller  : 'RepositoriesController'
		})

		// route for the showImages page
		.when('/showImages', {
			templateUrl : 'pages/showImages.html',
			controller  : 'ImagesController'
		});
});

/*This service is used to define the object which stores the current Docker-registry IP address and defines the getter and setter
  methods for accessing  and modifyingthe IP address.
*/
app.service('IPService', function () {
	var IP = '192.168.1.1';
	return {
		getIP: function () {
			return IP;
		},
		setIP: function(value) {
			IP = value;
		}
	};
});

// create the Main controller (for index.html) and inject Angular's $scope
app.controller('MainController', ['$scope','IPService','$route','$window','$cookies',function($scope,IPService,$route,$window,$cookies) {
	// create a message to display in our view
	$scope.inputIP='';
	//$cookies.IP='localhost';
	//$scope.cookieIP=$cookies.IP;
	//console.log('The cookiestore ip is' + $scope.cookieIP);
	$scope.setIP=function(inputIP)
	{
		IPService.setIP(inputIP);
		$cookies.IP=inputIP;
		//$cookieStore.put(‘IP’, inputIP);
		console.log('the IP has been changed to '+IPService.getIP());
		$window.location.href = "#showNamespaces";
		$route.reload();
	}
}]);

//Show Namespaces controller, all JS code for showNamespaces page is here
app.controller('NamespacesController', function($rootScope,$scope,$http,IPService,$route,$cookies) {

	$scope.message = 'shownamespaces page';
	//$scope.IP=IPService.getIP();
	$scope.IP=$cookies.IP;
	//$scope.IP=$cookieStore.get(‘ip’);
	console.log('the ip is ' + $scope.IP);
	$scope.num_results=0;
	$scope.dictionary={};
	$scope.namespacesList=[];
	results=[];
	//namespaces=[];
	//images=[];

	$http({method: 'GET', url: 'http://'+$scope.IP+'/v1/search'}).success(function(data)
	{
		$scope.num_results=data.num_results;
		results=data.results;
		angular.forEach(results,function(result)
		{
			$scope.dictionary[result.name.split('/')[0]]=[];
		});
		angular.forEach(results,function(result)
		{
			//namespaces.push(result.name.split('/')[0]);
			//images.push(result.name.split('/')[1]);
			$scope.dictionary[result.name.split('/')[0]].push(result.name.split('/')[1]);
		});
		angular.forEach($scope.dictionary,function(key,value)
		{
			temp={};
			temp['name']=value;
			$scope.namespacesList.push(temp);
		});
	}).error(function(data){alert('Unable to reuest.')});

});

//Show NamespacesRepos controller, all JS code for showNamespaces page is here
app.controller('NamespacesReposController', function($rootScope,$scope,$http,IPService,$route,$cookies,$location) {

	$scope.queryAll=$location.search()['queryAll'];
	if($scope.queryAll === undefined || $scope.queryAll === "")
	{
		$scope.IP=$cookies.IP;
		console.log('the ip is ' + $scope.IP);
		$scope.num_results=0;
		$scope.namespacesReposList=[];
		$http({method: 'GET', url: 'http://'+$scope.IP+'/v1/search'}).success(function(data)
		{
			$scope.num_results=data.num_results;
			$scope.namespacesReposList=data.results;
		}).error(function(data){alert('Unable to request.')});
	}
	else
	{
		$scope.IP=$cookies.IP;
		console.log('the ip is ' + $scope.IP);
		$scope.num_results=0;
		$scope.namespacesReposList=[];
		$http({method: 'GET', url: 'http://'+$scope.IP+'/v1/search'}).success(function(data)
		{
			$scope.num_results=data.num_results;
			angular.forEach(data.results,function(result)
			{
				$scope.queryAll = angular.lowercase($scope.queryAll);
				if( result.name.indexOf($scope.queryAll) >= 0 )
					$scope.namespacesReposList.push(result);
			});
		}).error(function(data){alert('Unable to request.')});

	}
});

//Show repositories controller, all JS code for showRepositories page is here
app.controller('RepositoriesController', function($scope,$http,$location,IPService,$window,$cookies,$route) {
	//$scope.IP=IPService.getIP();
	$scope.IP=$cookies.IP;
	$scope.namespace=$location.search()['namespace'];
	$scope.num_results=0;
	$scope.repositoriesList=[];
	$scope.go = function (path) {
	$location.path(path);
	};
	$http({method: 'GET', url: 'http://'+$scope.IP+'/v1/search'}).success(function(data)
	{
		$scope.num_results=data.num_results;
		results=data.results;
		angular.forEach(results,function(result)
		{
			if(result.name.split('/')[0]===$scope.namespace)
			{
				temp={};
				temp['name']=result.name.split('/')[1];
				$scope.repositoriesList.push(temp);
			}
		});
	}).error(function(data){alert('Unable to request.')});
	deleteRepoURL='http://'+$scope.IP+'/v1/repositories/'+$scope.namespace;
	$scope.deleteRepo = function (repo)
	{

			$http.delete(deleteRepoURL+'/'+repo +'/').success(function (data)
			{
				console.log('Deleted Repo : '+repo);
				$window.location.href = "#showRepositories?namespace="+$scope.namespace;
				$route.reload();
			}).error(function(data){});;
	};
});

//Show images controller, all JS code for showImages page is here
app.controller('ImagesController', function($scope,$http,$location,IPService,$window,$cookies,$route) {
	//$scope.IP=IPService.getIP();
	$scope.IP=$cookies.IP;
	//$scope.newTag='';
	$scope.namespace=$location.search()['namespace'];
	$scope.repository=$location.search()['repository'];
	$scope.tagsList=[];
	URL='http://'+$scope.IP+'/v1/repositories/'+$scope.namespace+'/'+$scope.repository+'/tags';
	$scope.deleteTag = function (tag)
	{

			$http.delete(URL+'/'+tag).success(function (data)
			{
				console.log('Deleted tag : '+tag);
				$window.location.href = "#showImages?namespace="+$scope.namespace+"&repository="+$scope.repository;
				$route.reload();
			}).error(function(data){alert('Unable to delete.')});;
	};
	deleteRepoURL='http://'+$scope.IP+'/v1/repositories/'+$scope.namespace+'/'+ $scope.repository;
	$scope.deleteRepo = function ()
	{

			$http.delete(deleteRepoURL+'/').success(function (data)
			{
				console.log('Deleted Repo : '+$scope.repository);
				$window.location.href = "#showRepositories?namespace="+$scope.namespace;
				$route.reload();
			}).error(function(data){});;
	};

	/*This function gets 2 parameters the old tag before editand the new tag after edit.
	 * This function will delete the old tag after getting the image id attached to it, use this image ID
	 * to put the new tag in the repository, thus having the same effect as editing a tag.
	 */
	$scope.changeTag = function (oldTag,newTag)
	{
		$scope.oldTagURL=URL+'/'+oldTag;
		$scope.newTagURL=URL+'/'+newTag;
		$scope.imageID='';
		imageId='\"hello\"';
		console.log('image id fetch url is '+ $scope.oldTagURL);
		console.log('tag putting url is ' + $scope.newTagURL);
		console.log('new tag is '+ newTag);
		if(newTag !== undefined)
		{

			$http({method: 'GET', url: $scope.oldTagURL }).success(function(data)
			{
				console.log('Data fetched : '+data);
				imageId='\"'+data.replace(/"/g,'')+'\"';
				if(oldTag !== newTag)
				{
					$http({method: 'PUT', url: $scope.newTagURL, data: imageId , headers: {"Content-Type": "application/json","Accept": "application/json"}}).success(function(data)
					{
						$http.delete($scope.oldTagURL).success(function (data)
						{
							$window.location.href = "#showImages?namespace="+$scope.namespace+"&repository="+$scope.repository;
							$route.reload();
						}).error(function(data){alert('Unable to delete.')});
					}).error(function(data){
					console.log('Unable to set tag for imageID');
					});
				}
				else
				{
					console.log('OldTag same as newTag ,no action taken');
				}

			}).error(function(data){console.log('Unable to get image ID for tag')});

		}
		else
		{
			console.log('New tag is empty. Not doing anything');
		}

	}

	$http({method: 'GET', url: URL }).success(function(data)
	{
		$scope.results=data;
		numTags=0;
		angular.forEach($scope.results,function(key,value)
		{
			numTags++;
			temp={};
			temp['name']=value;
			temp['id']=numTags;
			$scope.tagsList.push(temp);
		});
	}).error(function(data){alert('Unable to request.')});
});

<|endoftext|>


<commit_before>"use strict"; // strict mode syntax
var grid = null;
// initial table properties, after getting the data from the file.
var loadSlickTable = function(fileData){
	var c1 = document.getElementById('slickTable');
	var data = [];
	var columns = [];
	var w = 66 //default width
	//now we push the values of the columns into the grid
	for(var i = 0; i < fileData[0].length; i++){
		columns.push({
			id: i,
			name: '',
			field: i,
			width: w,
			editor: Slick.Editors.Text,
			minWidth: 60, //sets range for width of columns
			maxWidth: 80
		});
	}

  // set options for the table
  var options = {
	editable: true, //allows the table to be edited
    enableCellNavigation: true, //tabbable
    enableColumnReorder: false,
	autoHeight: true, //these three just make the
	forceFitColumns: true, //table look nice/fit
	fullWidthRows: true,
	rowHeight: 28
  };

  $(function () {
	// adding in the data to the grid
    for (var i = 0; i < fileData.length; i++) {
			var d = (data[i] = {});
			d["id"] = i;
			for(var j = 0; j < columns.length; j++){
				if(i > 0){
					d[j] = parseInt(fileData[i][j]);
				}
				else {
					d[j] = fileData[i][j];
				}
			}
	}
    grid = new Slick.Grid(c1, data, columns, options);
  });
  return grid;
}

var linkSlickTable = function(chart, player, overlay, summary){
	grid.onCellChange.subscribe(function (e, args) {
		//args = Object {row: (row #) , cell: (column #), item: Object, grid: SlickGrid}
		var row = args.row;
		var col = args.cell;
		var newVal = grid.getData()[row][col];

		// if a label
		if (row == 0){
			chart.scale.xLabels[col] = newVal;
		}
		// not a label - check to see if it's a number.
		// If not, do nothing
		else if ((!isNaN(newVal)) && (newVal != "")){
			newVal = parseInt(newVal);
			//Update audio with new value
			player.changeLine(row-1,col,newVal);
			// change value in chart
			if(type==="line")
			chart.datasets[row-1].points[col].value = newVal;
			else if(type ==="bar")
			chart.datasets[row-1].bars[col].value = newVal;
		}
		//update chart and overlay
		chart.update();
		summary.update();
        	//overlay.updateSize(chart);
	});
}
<commit_msg>Graph and table now work with decimals<commit_after>"use strict"; // strict mode syntax
var grid = null;
// initial table properties, after getting the data from the file.
var loadSlickTable = function(fileData){
	var c1 = document.getElementById('slickTable');
	var data = [];
	var columns = [];
	var w = 66 //default width
	//now we push the values of the columns into the grid
	for(var i = 0; i < fileData[0].length; i++){
		columns.push({
			id: i,
			name: '',
			field: i,
			width: w,
			editor: Slick.Editors.Text,
			minWidth: 60, //sets range for width of columns
			maxWidth: 80
		});
	}

  // set options for the table
  var options = {
	editable: true, //allows the table to be edited
    enableCellNavigation: true, //tabbable
    enableColumnReorder: false,
	autoHeight: true, //these three just make the
	forceFitColumns: true, //table look nice/fit
	fullWidthRows: true,
	rowHeight: 28
  };

  $(function () {
	// adding in the data to the grid
    for (var i = 0; i < fileData.length; i++) {
			var d = (data[i] = {});
			d["id"] = i;
			for(var j = 0; j < columns.length; j++){
				if(i > 0){
					d[j] = parseFloat(fileData[i][j]);
				}
				else {
					d[j] = fileData[i][j];
				}
			}
	}
    grid = new Slick.Grid(c1, data, columns, options);
  });
  return grid;
}

var linkSlickTable = function(chart, player, overlay, summary){
	grid.onCellChange.subscribe(function (e, args) {
		//args = Object {row: (row #) , cell: (column #), item: Object, grid: SlickGrid}
		var row = args.row;
		var col = args.cell;
		var newVal = grid.getData()[row][col];

		// if a label
		if (row == 0){
			chart.scale.xLabels[col] = newVal;
		}
		// not a label - check to see if it's a number.
		// If not, do nothing
		else if ((!isNaN(newVal)) && (newVal != "")){
			newVal = parseFloat(newVal);
			//Update audio with new value
			player.changeLine(row-1,col,newVal);
			// change value in chart
			if(type==="line")
			chart.datasets[row-1].points[col].value = newVal;
			else if(type ==="bar")
			chart.datasets[row-1].bars[col].value = newVal;
		}
		//update chart and overlay
		chart.update();
		summary.update();
        	//overlay.updateSize(chart);
	});
}
<|endoftext|>