<commit_before>/* This file is part of Indico.
 * Copyright (C) 2002 - 2016 European Organization for Nuclear Research (CERN).
 *
 * Indico is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 3 of the
 * License, or (at your option) any later version.
 *
 * Indico is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Indico; if not, see <http://www.gnu.org/licenses/>.
 */

(function(global) {
    'use strict';

    global.setupPersonLinkWidget = function setupPersonLinkWidget(options) {
        options = $.extend(true, {
            fieldId: null,
            eventId: null,
            authorTypes: null,
            showEmptyCoauthors: true,
            sort: true,
            allow: {
                authors: false,
                submitters: false,
                emptyEmail: false,
                externalUsers: true,
                speakers: true
            },
            defaults: {
                authorType: 0,
                isSpeaker: false,
                isSubmitter: false
            },
            require: {
                primaryAuthor: false,
                secondaryAuthor: false,
                submitter: false,
                speaker: false
            }
        }, options);

        var $field = $('#' + options.fieldId);
        var $fieldDisplay = $('#people-list-' + options.fieldId);
        var $authorList = $fieldDisplay.find('#author-list-' + options.fieldId);
        var $noAuthorPlaceholder = $fieldDisplay.find('#no-author-placeholder-' + options.fieldId);
        var $coauthorList = $fieldDisplay.find('#coauthor-list-' + options.fieldId);
        var $coauthorListTitle = $fieldDisplay.find('#coauthor-list-title-' + options.fieldId);
        var $noCoauthorPlaceholder = $fieldDisplay.find('#no-coauthor-placeholder-' + options.fieldId);
        var $otherList = $fieldDisplay.find('#other-list-' + options.fieldId);
        var $otherListTitle = $fieldDisplay.find('#other-list-title-' + options.fieldId);
        var $noOtherPlaceholder = $fieldDisplay.find('#no-other-placeholder-' + options.fieldId);
        var $buttonAddExisting = $('#add-existing-' + options.fieldId);
        var $buttonAddNew = $('#add-new-' + options.fieldId);
        var $buttonAlphaOrder = $fieldDisplay.find('.alpha-order-switch');
        var $form = $field.closest('form');
        var customOrder = !$buttonAlphaOrder.hasClass('active');

        function updatePersonOrder() {
            var people = _.map($fieldDisplay.find('.person-row'), function(e) {
                return $(e).data('person');
            });
            people.forEach(function(person, i) {
                person.displayOrder = customOrder ? (i + 1) : 0;
                $field.principalfield('set', person.id, {displayOrder: person.displayOrder});
            });
        }

        function setupList(entryType, $list, sortedPeople) {
            var isSortable = options.sort === true;

            $list.empty();

            if (isSortable) {
                $list.sortable({
                    axis: 'y',
                    containment: 'parent',
                    cursor: 'move',
                    distance: 10,
                    handle: '.sort-handle',
                    items: '> .person-row',
                    tolerance: 'pointer',
                    forceHelperSize: true,
                    forcePlaceholderSize: true,
                    helper: function(e, item) {
                        var originals = item.children();
                        var helper = item.clone();
                        helper.children().each(function(i) {
                            $(this).width(originals.eq(i).width());
                        });
                        return helper;
                    },
                    update: updatePersonOrder
                });
            }

            sortedPeople.forEach(function(person) {
                renderPerson(person, $list, entryType, isSortable && customOrder);
            });
        }

        function renderPeople(people) {
            $coauthorList.empty();
            $otherList.empty();

            var sortedPeople = _.sortBy(people, function(person) {
                return [person.displayOrder, person.name];
            });

            // Set default values
            people.forEach(function(person) {
                setPersonDefaults(person);
            });

            if (options.authorTypes) {
                var sortedAuthors = _.filter(sortedPeople, function(person) {
                    return person.authorType === options.authorTypes.primary;
                });
                var sortedCoAuthors = _.filter(sortedPeople, function(person) {
                    return person.authorType === options.authorTypes.secondary;
                });
                var sortedOthers = _.filter(sortedPeople, function(person) {
                    return (!options.authorTypes || person.authorType === options.authorTypes.none ||
                            (!options.allow.authors && person.isSpeaker));
                });
                setupList(options.authorTypes.primary, $authorList, sortedAuthors);
                setupList(options.authorTypes.secondary, $coauthorList, sortedCoAuthors);
                setupList(options.authorTypes.none, $otherList, sortedOthers);
            } else {
                setupList(null, $otherList, sortedPeople);
            }

            $noAuthorPlaceholder.toggle($authorList.is(':empty'));
            if (!options.showEmptyCoauthors) {
                $coauthorListTitle.toggle($coauthorList.is(':not(:empty)'));
            } else {
                $noCoauthorPlaceholder.toggle($coauthorList.is(':empty'));
            }
            $otherListTitle.toggle($otherList.is(':not(:empty)'));
            $noOtherPlaceholder.toggle($otherList.is(':empty'));
        }

        function renderPerson(person, $list, entryType, isSortable) {
            var $speakerLabel = $('').addClass('i-label small speaker').text($T.gettext("Speaker"));
            var $personRow = $('
').addClass('person-row').data('person', person);
            var $personName = $('
').addClass('name').text(person.name);
            var $personRoles = $('').addClass('person-roles');
            var $personButtons = $('').addClass('person-buttons');
            var $buttonRemove = $('').addClass('i-button-icon danger icon-close')
                                        .attr('title', $T.gettext("Remove person"));
            var $buttonEdit = $('').addClass('i-button-icon icon-edit')
                                      .attr('title', $T.gettext("Edit information"));
            var $buttonConfig = $('').addClass('i-button-icon icon-settings')
                                        .attr('title', $T.gettext("Configure roles"));

            $personRow.append($personName).append($personRoles).append($personButtons);
            $personButtons.append($buttonRemove).append($buttonEdit);

            if (isSortable) {
                $personRow.prepend('');
            }

            if (options.allow.submitters) {
                var $submitterLabel = $('').addClass('i-label small submitter')
                                                 .text($T.gettext("Submitter"));
                $personRoles.append($submitterLabel.toggleClass('selected', person.isSubmitter));
            }

            if (options.allow.authors && options.allow.speakers) {
                $personRoles.prepend($speakerLabel.toggleClass('selected', person.isSpeaker));
            }

            if (entryType !== null && entryType === options.authorTypes.none) {
                if (options.allow.authors && options.allow.speakers) {
                    $speakerLabel.addClass('other');
                }
            }

            $list.append($personRow);

            if (options.allow.submitters || options.allow.authors) {
                $personButtons.append($buttonConfig);
                setupPersonConfig(person, $buttonConfig, $personRow, $personRoles);
            }
            $buttonEdit.on('click', function() {
                $field.principalfield('edit', person.id);
            });
            $buttonRemove.on('click', function() {
                $field.principalfield('removeOne', person.id);
            });
        }

        function setPersonDefaults(person) {
            if (person.authorType === undefined) {
                person.authorType = options.defaults.authorType;
            }
            if (person.isSpeaker === undefined) {
                person.isSpeaker = options.defaults.isSpeaker;
            }
            if (person.isSubmitter === undefined) {
                person.isSubmitter = options.defaults.isSubmitter;
            }
        }

        function setupPersonConfig(person, $element, $personRow, $personRoles) {
            var $buttons = $('
');
            var $buttonsSeparator = $('
').addClass('titled-rule').text($T.gettext("or"));
            var $submitterLabel = $personRoles.find('.submitter');
            var $speakerLabel = $personRoles.find('.speaker');

            function actionButton(moveText, $targetList, targetData) {
                var $button = $('
').addClass('action-row').text(moveText);
                return $button.on('click', function() {
                    $element.qbubble('hide');
                    if ($targetList) {
                        $personRow.appendTo($targetList);
                        updatePersonOrder();
                    }
                    $field.principalfield('set', person.id, targetData);
                });
            }

            if (options.allow.authors) {
                if (person.authorType !== options.authorTypes.primary) {
                    $buttons.append(actionButton($T.gettext("Move to authors"), $authorList, {authorType: 1}));
                }

                if (person.authorType !== options.authorTypes.secondary) {
                    $buttons.append(actionButton($T.gettext("Move to co-authors"), $coauthorList, {authorType: 2}));
                }

                if (options.allow.speakers) {
                    if (person.authorType !== options.authorTypes.none) {
                        $buttons.append(actionButton($T.gettext("Move to others"), $otherList,
                                                     {authorType: 0, isSpeaker: true}));
                        var text = person.isSpeaker ? $T.gettext("Not a speaker anymore")
                                                    : $T.gettext("Make a speaker");

                        $buttons.append($buttonsSeparator);
                        $buttons.append(actionButton(text, null, {isSpeaker: !person.isSpeaker}));

                        $speakerLabel.on('click', function() {
                            $field.principalfield('set', person.id, {isSpeaker: !person.isSpeaker});
                        });
                    } else {
                        $speakerLabel.qtip({
                            content: {
                                text: $T.gettext("People in the 'Others' section must be speakers.")
                            },
                            show: {
                                event: 'click',
                                solo: true
                            },
                            hide: {
                                event: 'unfocus click'
                            }
                        });
                    }
                }
            }

            if (options.allow.submitters) {
                var $submitterButton = $('
').addClass('action-row');
                $submitterButton.text(person.isSubmitter ? $T.gettext("Revoke submission rights") :
                                                           $T.gettext("Grant submission rights"));
                $submitterButton.on('click', function() {
                    $element.qbubble('hide');
                    $field.principalfield('set', person.id, {isSubmitter: !person.isSubmitter});
                });
                $buttons.append($submitterButton);
                $submitterLabel.on('click', function() {
                    $field.principalfield('set', person.id, {isSubmitter: !person.isSubmitter});
                });
            }

            $element.qbubble({
                style: {
                    classes: 'person-link-qbubble'
                },
                content: {
                    text: $buttons
                },
                position: {
                    my: 'left middle',
                    at: 'right middle',
                    adjust: {x: 15}
                },
                events: {
                    show: function() {
                        $element.addClass('active');
                        $element.closest('.person-row').addClass('active');
                    },
                    hide: function() {
                        $element.removeClass('active');
                        $element.closest('.person-row').removeClass('active');
                    }
                }
            });
        }

        $field.principalfield({
            eventId: options.eventId,
            allowExternalUsers: options.allow.externalUsers,
            allowEmptyEmail: options.allow.emptyEmail,
            multiChoice: true,
            overwriteChoice: false,
            render: function(people) {
                renderPeople(people);
            },
            onAdd: function(people) {
                people.forEach(function(person) {
                    if (person.authorType === undefined) {
                        var maxOrder = _.max(people, _.iteratee('displayOrder')).displayOrder;
                        setPersonDefaults(person);
                        person.displayOrder = customOrder ? (maxOrder + 1) : 0;
                    }
                });
            }
        });

        $buttonAddExisting.on('click', function() {
            $field.principalfield('choose');
        });

        $buttonAddNew.on('click', function() {
            $field.principalfield('enter');
        });

        function getSortingMessage()  {
            if (customOrder) {
                return $T.gettext('Custom sorting has been applied. Click to restore alphabetical order.');
            } else {
                return $T.gettext('Alphabetical sorting is ON. Click to turn it off.');
            }
        }

        $buttonAlphaOrder.qtip({content: getSortingMessage});
        $buttonAlphaOrder.on('click', function() {
            var $list = $fieldDisplay.find('.person-list');
            customOrder = !customOrder;
            $buttonAlphaOrder.toggleClass('active', !customOrder);
            if (customOrder) {
                updatePersonOrder();
            } else {
                $list.find('.person-row').each(function() {
                    $(this).data('person').displayOrder = 0;
                });
            }
            $field.principalfield('refresh');
        });

        $form.on('submit', function(evt) {
            var e = $.Event('ajaxDialog:validateBeforeSubmit');
            $(this).trigger(e);
            if (e.isDefaultPrevented()) {
                evt.preventDefault();
            }
        });

        $field.closest('form').on('ajaxDialog:validateBeforeSubmit', function(evt) {
            var $this = $(this);
            var req = options.require;

            if (req.primaryAuthor || req.secondaryAuthor || req.submitter || req.speaker || !options.allow.speakers) {
                var $formField = $field.closest('.form-field');
                var $formGroup = $field.closest('.form-group');
                var hiddenData = JSON.parse($field.val());
                var hasError = false;

                if (req.speaker && _.indexOf(_.pluck(hiddenData, 'isSpeaker'), true) === -1) {
                    hasError = true;
                    $formField.data('error', $T.gettext('You must add at least one speaker'));
                } else if (req.submitter && _.indexOf(_.pluck(hiddenData, 'isSubmitter'), true) === -1) {
                    hasError = true;
                    $formField.data('error', $T.gettext('You must add at least one submitter'));
                } else if (req.secondaryAuthor && _.indexOf(_.pluck(hiddenData, 'authorType'), 2) === -1) {
                    hasError = true;
                    $formField.data('error', $T.gettext('You must add at least one co-author'));
                } else if (req.primaryAuthor && _.indexOf(_.pluck(hiddenData, 'authorType'), 1) === -1) {
                    hasError = true;
                    $formField.data('error', $T.gettext('You must add at least one author'));
                } else if (!options.allow.speakers && _.indexOf(_.pluck(hiddenData, 'authorType'), 0) !== -1) {
                    hasError = true;
                    $formField.data('error', $T.gettext('You cannot have users in the Other section, please make ' +
                                                        'them authors or co-authors'));
                }

                if (hasError) {
                    evt.preventDefault();
                    $formGroup.addClass('has-error');
                    showFormErrors($this.parent());
                } else {
                    $formGroup.removeClass('has-error');
                    $formField.removeData('error');
                }
            }
        });
    };
})(window);
<commit_msg>Fix edit/delete of manually entered person<commit_after>/* This file is part of Indico.
 * Copyright (C) 2002 - 2016 European Organization for Nuclear Research (CERN).
 *
 * Indico is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 3 of the
 * License, or (at your option) any later version.
 *
 * Indico is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Indico; if not, see <http://www.gnu.org/licenses/>.
 */

(function(global) {
    'use strict';

    global.setupPersonLinkWidget = function setupPersonLinkWidget(options) {
        options = $.extend(true, {
            fieldId: null,
            eventId: null,
            authorTypes: null,
            showEmptyCoauthors: true,
            sort: true,
            allow: {
                authors: false,
                submitters: false,
                emptyEmail: false,
                externalUsers: true,
                speakers: true
            },
            defaults: {
                authorType: 0,
                isSpeaker: false,
                isSubmitter: false
            },
            require: {
                primaryAuthor: false,
                secondaryAuthor: false,
                submitter: false,
                speaker: false
            }
        }, options);

        var $field = $('#' + options.fieldId);
        var $fieldDisplay = $('#people-list-' + options.fieldId);
        var $authorList = $fieldDisplay.find('#author-list-' + options.fieldId);
        var $noAuthorPlaceholder = $fieldDisplay.find('#no-author-placeholder-' + options.fieldId);
        var $coauthorList = $fieldDisplay.find('#coauthor-list-' + options.fieldId);
        var $coauthorListTitle = $fieldDisplay.find('#coauthor-list-title-' + options.fieldId);
        var $noCoauthorPlaceholder = $fieldDisplay.find('#no-coauthor-placeholder-' + options.fieldId);
        var $otherList = $fieldDisplay.find('#other-list-' + options.fieldId);
        var $otherListTitle = $fieldDisplay.find('#other-list-title-' + options.fieldId);
        var $noOtherPlaceholder = $fieldDisplay.find('#no-other-placeholder-' + options.fieldId);
        var $buttonAddExisting = $('#add-existing-' + options.fieldId);
        var $buttonAddNew = $('#add-new-' + options.fieldId);
        var $buttonAlphaOrder = $fieldDisplay.find('.alpha-order-switch');
        var $form = $field.closest('form');
        var customOrder = !$buttonAlphaOrder.hasClass('active');
        var maxNewPersonID = 0;

        function setNewPersonID(person) {
            person.id = 'new-' + maxNewPersonID;
            maxNewPersonID++;
        }

        function updatePersonOrder() {
            var people = _.map($fieldDisplay.find('.person-row'), function(e) {
                return $(e).data('person');
            });
            people.forEach(function(person, i) {
                person.displayOrder = customOrder ? (i + 1) : 0;
                $field.principalfield('set', person.id, {displayOrder: person.displayOrder});
            });
        }

        function setupList(entryType, $list, sortedPeople) {
            var isSortable = options.sort === true;

            $list.empty();

            if (isSortable) {
                $list.sortable({
                    axis: 'y',
                    containment: 'parent',
                    cursor: 'move',
                    distance: 10,
                    handle: '.sort-handle',
                    items: '> .person-row',
                    tolerance: 'pointer',
                    forceHelperSize: true,
                    forcePlaceholderSize: true,
                    helper: function(e, item) {
                        var originals = item.children();
                        var helper = item.clone();
                        helper.children().each(function(i) {
                            $(this).width(originals.eq(i).width());
                        });
                        return helper;
                    },
                    update: updatePersonOrder
                });
            }

            sortedPeople.forEach(function(person) {
                renderPerson(person, $list, entryType, isSortable && customOrder);
            });
        }

        function renderPeople(people) {
            $coauthorList.empty();
            $otherList.empty();

            var sortedPeople = _.sortBy(people, function(person) {
                return [person.displayOrder, person.name];
            });

            // Set default values
            people.forEach(function(person) {
                setPersonDefaults(person);
            });

            if (options.authorTypes) {
                var sortedAuthors = _.filter(sortedPeople, function(person) {
                    return person.authorType === options.authorTypes.primary;
                });
                var sortedCoAuthors = _.filter(sortedPeople, function(person) {
                    return person.authorType === options.authorTypes.secondary;
                });
                var sortedOthers = _.filter(sortedPeople, function(person) {
                    return (!options.authorTypes || person.authorType === options.authorTypes.none ||
                            (!options.allow.authors && person.isSpeaker));
                });
                setupList(options.authorTypes.primary, $authorList, sortedAuthors);
                setupList(options.authorTypes.secondary, $coauthorList, sortedCoAuthors);
                setupList(options.authorTypes.none, $otherList, sortedOthers);
            } else {
                setupList(null, $otherList, sortedPeople);
            }

            $noAuthorPlaceholder.toggle($authorList.is(':empty'));
            if (!options.showEmptyCoauthors) {
                $coauthorListTitle.toggle($coauthorList.is(':not(:empty)'));
            } else {
                $noCoauthorPlaceholder.toggle($coauthorList.is(':empty'));
            }
            $otherListTitle.toggle($otherList.is(':not(:empty)'));
            $noOtherPlaceholder.toggle($otherList.is(':empty'));
        }

        function renderPerson(person, $list, entryType, isSortable) {
            var $speakerLabel = $('').addClass('i-label small speaker').text($T.gettext("Speaker"));
            var $personRow = $('
').addClass('person-row').data('person', person);
            var $personName = $('
').addClass('name').text(person.name);
            var $personRoles = $('').addClass('person-roles');
            var $personButtons = $('').addClass('person-buttons');
            var $buttonRemove = $('').addClass('i-button-icon danger icon-close')
                                        .attr('title', $T.gettext("Remove person"));
            var $buttonEdit = $('').addClass('i-button-icon icon-edit')
                                      .attr('title', $T.gettext("Edit information"));
            var $buttonConfig = $('').addClass('i-button-icon icon-settings')
                                        .attr('title', $T.gettext("Configure roles"));

            $personRow.append($personName).append($personRoles).append($personButtons);
            $personButtons.append($buttonRemove).append($buttonEdit);

            if (isSortable) {
                $personRow.prepend('');
            }

            if (options.allow.submitters) {
                var $submitterLabel = $('').addClass('i-label small submitter')
                                                 .text($T.gettext("Submitter"));
                $personRoles.append($submitterLabel.toggleClass('selected', person.isSubmitter));
            }

            if (options.allow.authors && options.allow.speakers) {
                $personRoles.prepend($speakerLabel.toggleClass('selected', person.isSpeaker));
            }

            if (entryType !== null && entryType === options.authorTypes.none) {
                if (options.allow.authors && options.allow.speakers) {
                    $speakerLabel.addClass('other');
                }
            }

            $list.append($personRow);

            if (options.allow.submitters || options.allow.authors) {
                $personButtons.append($buttonConfig);
                setupPersonConfig(person, $buttonConfig, $personRow, $personRoles);
            }
            $buttonEdit.on('click', function() {
                $field.principalfield('edit', person.id);
            });
            $buttonRemove.on('click', function() {
                $field.principalfield('removeOne', person.id);
            });
        }

        function setPersonDefaults(person) {
            if (person.authorType === undefined) {
                person.authorType = options.defaults.authorType;
            }
            if (person.isSpeaker === undefined) {
                person.isSpeaker = options.defaults.isSpeaker;
            }
            if (person.isSubmitter === undefined) {
                person.isSubmitter = options.defaults.isSubmitter;
            }
            if (person.id === undefined) {
                setNewPersonID(person);
            }
        }

        function setupPersonConfig(person, $element, $personRow, $personRoles) {
            var $buttons = $('
');
            var $buttonsSeparator = $('
').addClass('titled-rule').text($T.gettext("or"));
            var $submitterLabel = $personRoles.find('.submitter');
            var $speakerLabel = $personRoles.find('.speaker');

            function actionButton(moveText, $targetList, targetData) {
                var $button = $('
').addClass('action-row').text(moveText);
                return $button.on('click', function() {
                    $element.qbubble('hide');
                    if ($targetList) {
                        $personRow.appendTo($targetList);
                        updatePersonOrder();
                    }
                    $field.principalfield('set', person.id, targetData);
                });
            }

            if (options.allow.authors) {
                if (person.authorType !== options.authorTypes.primary) {
                    $buttons.append(actionButton($T.gettext("Move to authors"), $authorList, {authorType: 1}));
                }

                if (person.authorType !== options.authorTypes.secondary) {
                    $buttons.append(actionButton($T.gettext("Move to co-authors"), $coauthorList, {authorType: 2}));
                }

                if (options.allow.speakers) {
                    if (person.authorType !== options.authorTypes.none) {
                        $buttons.append(actionButton($T.gettext("Move to others"), $otherList,
                                                     {authorType: 0, isSpeaker: true}));
                        var text = person.isSpeaker ? $T.gettext("Not a speaker anymore")
                                                    : $T.gettext("Make a speaker");

                        $buttons.append($buttonsSeparator);
                        $buttons.append(actionButton(text, null, {isSpeaker: !person.isSpeaker}));

                        $speakerLabel.on('click', function() {
                            $field.principalfield('set', person.id, {isSpeaker: !person.isSpeaker});
                        });
                    } else {
                        $speakerLabel.qtip({
                            content: {
                                text: $T.gettext("People in the 'Others' section must be speakers.")
                            },
                            show: {
                                event: 'click',
                                solo: true
                            },
                            hide: {
                                event: 'unfocus click'
                            }
                        });
                    }
                }
            }

            if (options.allow.submitters) {
                var $submitterButton = $('
').addClass('action-row');
                $submitterButton.text(person.isSubmitter ? $T.gettext("Revoke submission rights") :
                                                           $T.gettext("Grant submission rights"));
                $submitterButton.on('click', function() {
                    $element.qbubble('hide');
                    $field.principalfield('set', person.id, {isSubmitter: !person.isSubmitter});
                });
                $buttons.append($submitterButton);
                $submitterLabel.on('click', function() {
                    $field.principalfield('set', person.id, {isSubmitter: !person.isSubmitter});
                });
            }

            $element.qbubble({
                style: {
                    classes: 'person-link-qbubble'
                },
                content: {
                    text: $buttons
                },
                position: {
                    my: 'left middle',
                    at: 'right middle',
                    adjust: {x: 15}
                },
                events: {
                    show: function() {
                        $element.addClass('active');
                        $element.closest('.person-row').addClass('active');
                    },
                    hide: function() {
                        $element.removeClass('active');
                        $element.closest('.person-row').removeClass('active');
                    }
                }
            });
        }

        $field.principalfield({
            eventId: options.eventId,
            allowExternalUsers: options.allow.externalUsers,
            allowEmptyEmail: options.allow.emptyEmail,
            multiChoice: true,
            overwriteChoice: false,
            render: function(people) {
                renderPeople(people);
            },
            onAdd: function(people) {
                people.forEach(function(person) {
                    if (person.authorType === undefined) {
                        var maxOrder = _.max(people, _.iteratee('displayOrder')).displayOrder;
                        setPersonDefaults(person);
                        person.displayOrder = customOrder ? (maxOrder + 1) : 0;
                    }
                });
            }
        });

        $buttonAddExisting.on('click', function() {
            $field.principalfield('choose');
        });

        $buttonAddNew.on('click', function() {
            $field.principalfield('enter');
        });

        function getSortingMessage()  {
            if (customOrder) {
                return $T.gettext('Custom sorting has been applied. Click to restore alphabetical order.');
            } else {
                return $T.gettext('Alphabetical sorting is ON. Click to turn it off.');
            }
        }

        $buttonAlphaOrder.qtip({content: getSortingMessage});
        $buttonAlphaOrder.on('click', function() {
            var $list = $fieldDisplay.find('.person-list');
            customOrder = !customOrder;
            $buttonAlphaOrder.toggleClass('active', !customOrder);
            if (customOrder) {
                updatePersonOrder();
            } else {
                $list.find('.person-row').each(function() {
                    $(this).data('person').displayOrder = 0;
                });
            }
            $field.principalfield('refresh');
        });

        $form.on('submit', function(evt) {
            var e = $.Event('ajaxDialog:validateBeforeSubmit');
            $(this).trigger(e);
            if (e.isDefaultPrevented()) {
                evt.preventDefault();
            }
        });

        $field.closest('form').on('ajaxDialog:validateBeforeSubmit', function(evt) {
            var $this = $(this);
            var req = options.require;

            if (req.primaryAuthor || req.secondaryAuthor || req.submitter || req.speaker || !options.allow.speakers) {
                var $formField = $field.closest('.form-field');
                var $formGroup = $field.closest('.form-group');
                var hiddenData = JSON.parse($field.val());
                var hasError = false;

                if (req.speaker && _.indexOf(_.pluck(hiddenData, 'isSpeaker'), true) === -1) {
                    hasError = true;
                    $formField.data('error', $T.gettext('You must add at least one speaker'));
                } else if (req.submitter && _.indexOf(_.pluck(hiddenData, 'isSubmitter'), true) === -1) {
                    hasError = true;
                    $formField.data('error', $T.gettext('You must add at least one submitter'));
                } else if (req.secondaryAuthor && _.indexOf(_.pluck(hiddenData, 'authorType'), 2) === -1) {
                    hasError = true;
                    $formField.data('error', $T.gettext('You must add at least one co-author'));
                } else if (req.primaryAuthor && _.indexOf(_.pluck(hiddenData, 'authorType'), 1) === -1) {
                    hasError = true;
                    $formField.data('error', $T.gettext('You must add at least one author'));
                } else if (!options.allow.speakers && _.indexOf(_.pluck(hiddenData, 'authorType'), 0) !== -1) {
                    hasError = true;
                    $formField.data('error', $T.gettext('You cannot have users in the Other section, please make ' +
                                                        'them authors or co-authors'));
                }

                if (hasError) {
                    evt.preventDefault();
                    $formGroup.addClass('has-error');
                    showFormErrors($this.parent());
                } else {
                    $formGroup.removeClass('has-error');
                    $formField.removeData('error');
                }
            }
        });
    };
})(window);
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { Redirect } from 'react-router-dom';
import Section from 'shared/components/section/section';
import FormButton from 'shared/components/form/formButton/formButton';
import { patchBackend } from 'shared/utils/apiHelper';
import Identifier from './formComponents/identifier';
import Interests from './formComponents/interests';
import WorkInfo from './formComponents/workInfo';
import SchoolInfo from './formComponents/schoolInfo';
import MilitaryInfo from './formComponents/militaryInfo';
import styles from './informationForm.css';

class SignupInformation extends Component {

  constructor(props) {
    super(props);
    this.onIdentifierStatusChange = this.onIdentifierStatusChange.bind(this);
    this.onCheckBoxChange = this.onCheckBoxChange.bind(this);
    this.state = {
      error: false,
      isValid: true,
      success: false,
      identifier: 'false',
      interests: new Set(),
      step: 0
    };
  }

  // On-Change handler dynamically creates state named after the
  // ID of the changing event, with a value captured by the event itself.
  // Ex. If a form select with ID 'hello' selects value 'greeted'
  // Then state will be updated with key of 'hello' and value of 'greeted'
  onIdentifierStatusChange = (e, value) => {
    this.setState({ [e.target.id]: value });
  }

  // Adds values from checkboxes to a set, eliminating possible repeat values
  onCheckBoxChange = (value) => {
    this.setState({ interests: this.state.interests.add(value) });
  }

  // Reduces 'step' value by 1, going back one page in the form
  // Unless you are at the first page
  previousPage = () => {
    if (this.state.step < 1) {
      return;
    }
    this.setState({ step: this.state.step -= 1 });
  }

  // Patches whatever values that have been captured so far to the DB
  // Then adds 1 to step to progress to the next page.
  saveAndContinue = () => {
    patchBackend('users', {
      user: {
        education_level: this.state.schoolLevel,
        scholarship_info: this.state.scholarships,
        employment_status: this.state.workInfo,
        company_name: this.state.company,
        company_role: this.state.role,
        volunteer: this.state.identifier,
        branch_of_service: this.state.branch,
        // Necessary to convert Set to Array for storage in DB
        interests: Array.from(this.state.interests)
      },
    });
    this.setState({ step: this.state.step += 1 });
  }
  // Showstep renders each consecutive 'page' (component) based on user input
  // The form splits based on identifier, which determines whether or not
  // You are military or civillian. If miltitary, it's false. If civillian, true
  // 'Step' state is combined with 'identifier' to determine which component to
  // Serve to the user. The default case, or STEP ONE is the Identifier form.
  showStep = () => {
    const step = this.state.step + this.state.identifier;
    switch (step) {
      // Military STEP 2
      case '1false':
        return (
          <MilitaryInfo
            update={this.onIdentifierStatusChange}
            percent={'20'}
          />
        );
      // Civillian STEP 2
      case '1true':
        return (
          <WorkInfo
            role={this.state.role}
            company={this.state.company}
            update={this.onIdentifierStatusChange}
            percent={'33'}
          />
        );
      // Civillian STEP 3
      case '2true':
        return (
          <Interests
            update={this.onCheckBoxChange}
            percent={'66'}
          />
        );
      // Civillian COMPLETE
      case '3true':
        return (
          <Redirect to="/profile" />
        );
      // Military STEP 3
      case '2false':
        return (
          <WorkInfo
            role={this.state.role}
            company={this.state.company}
            update={this.onIdentifierStatusChange}
            percent={'40'}
          />
        );
      // Military STEP 4
      case '3false':
        return (
          <SchoolInfo
            update={this.onIdentifierStatusChange}
            percent={'60'}
          />
        );
      // Military STEP 5
      case '4false':
        return (
          <Interests
            update={this.onCheckBoxChange}
            percent={'80'}
          />
        );
      // Military COMPLETE
      case '5false':
        return (
          <Redirect to="/profile" />
        );
      // STEP ONE
      default:
        return <Identifier update={this.onIdentifierStatusChange} />;
    }
  }

  render() {
    const showStep = this.showStep();
    return (

At Op-Code, we are dedicated to helping our community thrive. In order to do so, we need to collect some information to better serve you. Please take a minute to complete these steps and help us on our mission to code the future. We will never sell or distribute your information.

        {showStep}

          <FormButton text="Go Back" onClick={this.previousPage} theme="blue" />
          <FormButton text="Save and Continue" onClick={this.saveAndContinue} theme="red" />

    );
  }
}

export default SignupInformation;
<commit_msg>Add error handling for save and continue function<commit_after>import React, { Component } from 'react';
import { Redirect } from 'react-router-dom';
import Section from 'shared/components/section/section';
import FormButton from 'shared/components/form/formButton/formButton';
import { patchBackend } from 'shared/utils/apiHelper';
import Identifier from './formComponents/identifier';
import Interests from './formComponents/interests';
import WorkInfo from './formComponents/workInfo';
import SchoolInfo from './formComponents/schoolInfo';
import MilitaryInfo from './formComponents/militaryInfo';
import styles from './informationForm.css';

class SignupInformation extends Component {

  constructor(props) {
    super(props);
    this.onIdentifierStatusChange = this.onIdentifierStatusChange.bind(this);
    this.onCheckBoxChange = this.onCheckBoxChange.bind(this);
    this.state = {
      error: false,
      isValid: true,
      success: false,
      identifier: 'false',
      interests: new Set(),
      step: 0
    };
  }

  // On-Change handler dynamically creates state named after the
  // ID of the changing event, with a value captured by the event itself.
  // Ex. If a form select with ID 'hello' selects value 'greeted'
  // Then state will be updated with key of 'hello' and value of 'greeted'
  onIdentifierStatusChange = (e, value) => {
    this.setState({ [e.target.id]: value });
  }

  // Adds values from checkboxes to a set, eliminating possible repeat values
  onCheckBoxChange = (value) => {
    this.setState({ interests: this.state.interests.add(value) });
  }

  // Reduces 'step' value by 1, going back one page in the form
  // Unless you are at the first page
  previousPage = () => {
    if (this.state.step < 1) {
      return;
    }
    this.setState({ step: this.state.step -= 1 });
  }

  // Patches whatever values that have been captured so far to the DB
  // Then adds 1 to step to progress to the next page.
  saveAndContinue = () => {
    patchBackend('users', {
      user: {
        education_level: this.state.schoolLevel,
        scholarship_info: this.state.scholarships,
        employment_status: this.state.workInfo,
        company_name: this.state.company,
        company_role: this.state.role,
        volunteer: this.state.identifier,
        branch_of_service: this.state.branch,
        // Necessary to convert Set to Array for storage in DB
        interests: Array.from(this.state.interests)
      },
    })
    .then(() => {
      this.setState({ step: this.state.step += 1 });
    }).catch(() => {
      this.setState({ error: true });
    });
  }
  // Showstep renders each consecutive 'page' (component) based on user input
  // The form splits based on identifier, which determines whether or not
  // You are military or civillian. If miltitary, it's false. If civillian, true
  // 'Step' state is combined with 'identifier' to determine which component to
  // Serve to the user. The default case, or STEP ONE is the Identifier form.
  showStep = () => {
    const step = this.state.step + this.state.identifier;
    switch (step) {
      // Military STEP 2
      case '1false':
        return (
          <MilitaryInfo
            update={this.onIdentifierStatusChange}
            percent={'20'}
          />
        );
      // Civillian STEP 2
      case '1true':
        return (
          <WorkInfo
            role={this.state.role}
            company={this.state.company}
            update={this.onIdentifierStatusChange}
            percent={'33'}
          />
        );
      // Civillian STEP 3
      case '2true':
        return (
          <Interests
            update={this.onCheckBoxChange}
            percent={'66'}
          />
        );
      // Civillian COMPLETE
      case '3true':
        return (
          <Redirect to="/profile" />
        );
      // Military STEP 3
      case '2false':
        return (
          <WorkInfo
            role={this.state.role}
            company={this.state.company}
            update={this.onIdentifierStatusChange}
            percent={'40'}
          />
        );
      // Military STEP 4
      case '3false':
        return (
          <SchoolInfo
            update={this.onIdentifierStatusChange}
            percent={'60'}
          />
        );
      // Military STEP 5
      case '4false':
        return (
          <Interests
            update={this.onCheckBoxChange}
            percent={'80'}
          />
        );
      // Military COMPLETE
      case '5false':
        return (
          <Redirect to="/profile" />
        );
      // STEP ONE
      default:
        return <Identifier update={this.onIdentifierStatusChange} />;
    }
  }

  render() {
    const showStep = this.showStep();
    return (

At Op-Code, we are dedicated to helping our community thrive. In order to do so, we need to collect some information to better serve you. Please take a minute to complete these steps and help us on our mission to code the future. We will never sell or distribute your information.

        {showStep}

          <FormButton text="Go Back" onClick={this.previousPage} theme="blue" />
          <FormButton text="Save and Continue" onClick={this.saveAndContinue} theme="red" />
          {this.state.error ?
There was an error saving your information, please try again.

 : null }

    );
  }
}

export default SignupInformation;
<|endoftext|>


<commit_before>var tower_Operate = {
    run: function(tower, attackDuration, towerNum) {
        //My bit that computes "how much damage could my towers do to creep x?" counted inactive towers
        //Count defender damage from current ones as well
        //Remember to factor in boosted ranged parts
        //Check after picking target, and check with range of 1 for nearby healers, totalling healing parts
        var thisRoom = tower.room;

        if (!Memory.towerNeedEnergy[thisRoom.name]) {
            Memory.towerNeedEnergy[thisRoom.name] = [];
        }
        if (!Memory.towerPickedTarget[thisRoom.name] || Game.time % 5 == 0) {
            /*if (Memory.towerPickedTarget[thisRoom.name]) {
                let thisHostile = Game.getObjectById(Memory.towerPickedTarget[thisRoom.name]);
                if (thisHostile && thisHostile.hits > (thisHostile.hitsMax - 500)) {
                    Memory.towerPickedTarget[thisRoom.name] = '';
                }
            } else {
                Memory.towerPickedTarget[thisRoom.name] = '';
            }*/

            Memory.towerPickedTarget[thisRoom.name] = '';
        }

        var checkDelay;
        if (thisRoom.storage) {
            if (thisRoom.storage.store[RESOURCE_ENERGY] >= 425000) {
                checkDelay = 10;
            } else if (thisRoom.storage.store[RESOURCE_ENERGY] >= 225000) {
                checkDelay = 20;
            } else if (thisRoom.storage.store[RESOURCE_ENERGY] < 100000) {
                checkDelay = 50;
            } else if (thisRoom.storage.store[RESOURCE_ENERGY] < 225000) {
                checkDelay = 35;
            }
        } else {
            checkDelay = 250;
        }

        let UnderAttackPos = Memory.roomsUnderAttack.indexOf(thisRoom.name);
        if (UnderAttackPos >= 0 && tower.energy > 0) {
            //Memory.roomCreeps[thisRoom.name];
            //Only if no salvager flag
            let didHeal = false
            let salvagerPos = Memory.roomsPrepSalvager.indexOf(thisRoom.name);
            let hostileCount = 1;

            let defenders = _.filter(Memory.roomCreeps[thisRoom.name], (creep) => creep.memory.priority == 'defender');

            let closestHostile = Game.getObjectById(Memory.towerPickedTarget[thisRoom.name]);
            if (!closestHostile) {
                //Find new target to shoot at.
                let allHostiles = tower.room.find(FIND_HOSTILE_CREEPS, {
                    filter: (eCreep) => (!Memory.whiteList.includes(eCreep.owner.username))
                });
                let allTowers = tower.room.find(FIND_STRUCTURES, {
                    filter: (structure) => (structure.structureType == STRUCTURE_TOWER)
                });
                hostileCount = allHostiles.length;

                let damageRecord = 0;
                let targetToShoot = undefined;

                for (let thisHostile in allHostiles) {
                    //Shoot at whatever target you can do the most damage to
                    //Calculate flat tower damage
                    let flatDamage = 0;
                    for (let thisTower in allTowers) {
                        let thisRange = allTowers[thisTower].pos.getRangeTo(allHostiles[thisHostile]);
                        if (thisRange <= 5) {
                            flatDamage += TOWER_POWER_ATTACK;
                        } else if (thisRange >= 20) {
                            flatDamage += TOWER_POWER_ATTACK - (TOWER_FALLOFF * TOWER_POWER_ATTACK);
                        } else {
                            //Midrange calculation
                            flatDamage += Math.round(TOWER_POWER_ATTACK - (((thisRange - 5) * (TOWER_FALLOFF / 15)) * TOWER_POWER_ATTACK))
                        }
                    }

                    //Add in potential defender damage
                    for (let thisDefender in defenders) {
                        defenders[thisDefender].body.forEach(function(thisPart) {
                            if (thisPart.type == RANGED_ATTACK && thisPart.boost) {
                                flatDamage += RANGED_ATTACK_POWER * BOOSTS['ranged_attack'][thisPart.boost]['rangedAttack']
                            } else if (thisPart.type == RANGED_ATTACK) {
                                flatDamage += RANGED_ATTACK_POWER
                            }
                        });
                    }

                    //Subtract target's TOUGH & HEAL damage soak
                    let damageReduction = 0;
                    let boostedTough = undefined;

                    allHostiles[thisHostile].body.forEach(function(thisPart) {
                        if (thisPart.type == TOUGH && thisPart.boost) {
                            boostedTough = thisPart.boost;
                        } else if (thisPart.type == HEAL && thisPart.boost) {
                            damageReduction += HEAL_POWER * BOOSTS['heal'][thisPart.boost]['heal']
                        } else if (thisPart.type == HEAL) {
                            damageReduction += HEAL_POWER
                        }
                    });
                    //Look for healer creeps within 3 spaces of target creep for further subtractions
                    let nearbyFriendos = allHostiles[thisHostile].pos.findInRange(FIND_HOSTILE_CREEPS, 3, {
                        filter: (eCreep) => (!Memory.whiteList.includes(eCreep.owner.username))
                    });
                    for (let thisFriendo in nearbyFriendos) {
                        let friendRange = allHostiles[thisHostile].pos.getRangeTo(nearbyFriendos[thisFriendo]);
                        nearbyFriendos[thisFriendo].body.forEach(function(thisPart) {
                            if (thisPart.type == HEAL && thisPart.boost) {
                                if (friendRange == 1) {
                                    damageReduction += HEAL_POWER * BOOSTS['heal'][thisPart.boost]['heal']
                                } else {
                                    damageReduction += RANGED_HEAL_POWER * BOOSTS['heal'][thisPart.boost]['rangedHeal']
                                }
                            } else if (thisPart.type == HEAL) {
                                if (friendRange == 1) {
                                    damageReduction += HEAL_POWER
                                } else {
                                    damageReduction += RANGED_HEAL_POWER
                                }
                            }
                        });
                    }

                    //Factor in damage reduction from Tough parts
                    if (boostedTough) {
                        flatDamage = flatDamage * BOOSTS['tough'][boostedTough]['damage']
                    }

                    //Display the calculated damage total under the target
                    let dColor = 'green';
                    if ((flatDamage - damageReduction) <= 0) {
                        dColor = 'red';
                    }
                    new RoomVisual(thisRoom.name).text((flatDamage - damageReduction).toString(), allHostiles[thisHostile].pos.x, allHostiles[thisHostile].pos.y, {color: dColor, font: 0.8});

                    //Determine if this beats the best
                    if ((flatDamage - damageReduction) > damageRecord) {
                        damageRecord = (flatDamage - damageReduction);
                        targetToShoot = allHostiles[thisHostile];
                    }
                }

                //if targetToShoot is defined, a valid target you can damage was found.
                if (targetToShoot) {
                    closestHostile = targetToShoot;
                }
            }

            //Heal only if the target isn't taking damage
            if (Memory.roomCreeps[thisRoom.name] && (!closestHostile || closestHostile.hits > (closestHostile.hitsMax - 500))) {
                if (Game.flags[thisRoom.name + "RoomOperator"]) {
                    powerCreep = tower.pos.findClosestByRange(FIND_MY_POWER_CREEPS);
                    if (powerCreep && powerCreep.hits < powerCreep.hitsMax) {
                        tower.heal(powerCreep);
                        didHeal = true;
                    }
                }
                let allCreeps = Memory.roomCreeps[thisRoom.name];
                if (allCreeps.length && !didHeal) {
                    allCreeps.sort(healCompare);
                    if (allCreeps[0].hits < allCreeps[0].hitsMax - 199) {
                        tower.heal(allCreeps[0]);
                        didHeal = true;
                    }
                }
            }

            if (!didHeal) {
                if (salvagerPos >= 0) {
                    //Verify that it's still not worth the time
                    //RETUNE - this could possibly spawn defenders if a big enough invader wave attacks
                    if (!closestHostile || determineCreepThreat(closestHostile, hostileCount.length)) {
                        //BAD TIMES
                        Memory.roomsPrepSalvager.splice(salvagerPos, 1);
                        salvagerPos = -1;
                    }
                }

                if (closestHostile) {
                    if (closestHostile.owner.username != "Invader" && closestHostile.hitsMax > 200) {
                        Game.notify('ROOM DEFENCE : ' + closestHostile.owner.username + ' is tresspassing in ' + thisRoom.name);
                        Memory.LastNotification = Game.time.toString() + ' : ' + closestHostile.owner.username + ' is tresspassing in ' + thisRoom.name
                    }
                    Memory.towerPickedTarget[thisRoom.name] = closestHostile.id;

                    if (tower.room.controller.level < 7) {
                        tower.attack(closestHostile);
                        if (range <= 5 && closestHostile.owner.username != 'Invader') {
                            //Too close for comfort
                            tower.room.controller.activateSafeMode();
                        }
                    } else {
                        tower.attack(closestHostile);
                    }
                }
            }
        } else if ((tower.energy > (tower.energyCapacity * 0.5)) && (Game.time % checkDelay == 0)) {
            var criticalRoads = tower.room.find(FIND_STRUCTURES, {
                filter: (structure) => (structure.structureType == STRUCTURE_ROAD && structure.hits < (structure.hitsMax / 2))
            });
            if (criticalRoads.length) {
                criticalRoads.sort(repairCompare);
                tower.repair(criticalRoads[0]);
            } else if (Memory.repairTarget[tower.room.name]) {
                let decayingRampart = Game.getObjectById(Memory.repairTarget[tower.room.name]);
                if (decayingRampart && decayingRampart.hits != decayingRampart.hitsMax) {
                    tower.repair(decayingRampart);
                } else {
                    //Bad target, let main handle reassignment
                    Memory.repairTarget[tower.room.name] = undefined;
                }
            }
        }

        if (tower.energy <= tower.energyCapacity - 150 && Memory.towerNeedEnergy[thisRoom.name].indexOf(tower.id) == -1) {
            Memory.towerNeedEnergy[thisRoom.name].push(tower.id);
        } else if (tower.energy > tower.energyCapacity - 150 && Memory.towerNeedEnergy[thisRoom.name].indexOf(tower.id) > -1) {
            var thisTowerIndex = Memory.towerNeedEnergy[thisRoom.name].indexOf(tower.id)
            Memory.towerNeedEnergy[thisRoom.name].splice(thisTowerIndex, 1);
        }
        //Enable to see tower coverage
        //thisRoom.visual.rect(thisTower.pos.x - 15, thisTower.pos.y - 15, 30, 30, {fill: '#ff0019', opacity: 0.2});
        //wew
    }
};

function repairCompare(a, b) {
    if (a.hits < b.hits)
        return -1;
    if (a.hits > b.hits)
        return 1;
    return 0;
}

function healCompare(a, b) {
    let aDiff = a.hitsMax - a.hits;
    let bDiff = b.hitsMax - b.hits;
    if (aDiff < bDiff)
        return 1;
    if (aDiff > bDiff)
        return -1;
    return 0;
}

function determineCreepThreat(eCreep, totalHostiles) {
    if ((eCreep.owner.username == 'Invader' || eCreep.name.indexOf('Drainer') >= 0) || (eCreep.hitsMax <= 1000 && totalHostiles <= 1)) {
        return false;
    } else {
        //Determine if this creep is boosted.
        eCreep.body.forEach(function(thisPart) {
            if (thisPart.boost) {
                return true;
            }
        });
        //unboosted threat, not a problem.
        return false;
    }
}

module.exports = tower_Operate;<commit_msg>Fix low level tower logic<commit_after>var tower_Operate = {
    run: function(tower, attackDuration, towerNum) {
        //My bit that computes "how much damage could my towers do to creep x?" counted inactive towers
        //Count defender damage from current ones as well
        //Remember to factor in boosted ranged parts
        //Check after picking target, and check with range of 1 for nearby healers, totalling healing parts
        var thisRoom = tower.room;

        if (!Memory.towerNeedEnergy[thisRoom.name]) {
            Memory.towerNeedEnergy[thisRoom.name] = [];
        }
        if (!Memory.towerPickedTarget[thisRoom.name] || Game.time % 5 == 0) {
            /*if (Memory.towerPickedTarget[thisRoom.name]) {
                let thisHostile = Game.getObjectById(Memory.towerPickedTarget[thisRoom.name]);
                if (thisHostile && thisHostile.hits > (thisHostile.hitsMax - 500)) {
                    Memory.towerPickedTarget[thisRoom.name] = '';
                }
            } else {
                Memory.towerPickedTarget[thisRoom.name] = '';
            }*/

            Memory.towerPickedTarget[thisRoom.name] = '';
        }

        var checkDelay;
        if (thisRoom.storage) {
            if (thisRoom.storage.store[RESOURCE_ENERGY] >= 425000) {
                checkDelay = 10;
            } else if (thisRoom.storage.store[RESOURCE_ENERGY] >= 225000) {
                checkDelay = 20;
            } else if (thisRoom.storage.store[RESOURCE_ENERGY] < 100000) {
                checkDelay = 50;
            } else if (thisRoom.storage.store[RESOURCE_ENERGY] < 225000) {
                checkDelay = 35;
            }
        } else {
            checkDelay = 250;
        }

        let UnderAttackPos = Memory.roomsUnderAttack.indexOf(thisRoom.name);
        if (UnderAttackPos >= 0 && tower.energy > 0) {
            //Memory.roomCreeps[thisRoom.name];
            //Only if no salvager flag
            let didHeal = false
            let salvagerPos = Memory.roomsPrepSalvager.indexOf(thisRoom.name);
            let hostileCount = 1;

            let defenders = _.filter(Memory.roomCreeps[thisRoom.name], (creep) => creep.memory.priority == 'defender');

            let closestHostile = Game.getObjectById(Memory.towerPickedTarget[thisRoom.name]);
            if (!closestHostile) {
                //Find new target to shoot at.
                let allHostiles = tower.room.find(FIND_HOSTILE_CREEPS, {
                    filter: (eCreep) => (!Memory.whiteList.includes(eCreep.owner.username))
                });
                let allTowers = tower.room.find(FIND_STRUCTURES, {
                    filter: (structure) => (structure.structureType == STRUCTURE_TOWER)
                });
                hostileCount = allHostiles.length;

                let damageRecord = 0;
                let targetToShoot = undefined;

                for (let thisHostile in allHostiles) {
                    //Shoot at whatever target you can do the most damage to
                    //Calculate flat tower damage
                    let flatDamage = 0;
                    for (let thisTower in allTowers) {
                        let thisRange = allTowers[thisTower].pos.getRangeTo(allHostiles[thisHostile]);
                        if (thisRange <= 5) {
                            flatDamage += TOWER_POWER_ATTACK;
                        } else if (thisRange >= 20) {
                            flatDamage += TOWER_POWER_ATTACK - (TOWER_FALLOFF * TOWER_POWER_ATTACK);
                        } else {
                            //Midrange calculation
                            flatDamage += Math.round(TOWER_POWER_ATTACK - (((thisRange - 5) * (TOWER_FALLOFF / 15)) * TOWER_POWER_ATTACK))
                        }
                    }

                    //Add in potential defender damage
                    for (let thisDefender in defenders) {
                        defenders[thisDefender].body.forEach(function(thisPart) {
                            if (thisPart.type == RANGED_ATTACK && thisPart.boost) {
                                flatDamage += RANGED_ATTACK_POWER * BOOSTS['ranged_attack'][thisPart.boost]['rangedAttack']
                            } else if (thisPart.type == RANGED_ATTACK) {
                                flatDamage += RANGED_ATTACK_POWER
                            }
                        });
                    }

                    //Subtract target's TOUGH & HEAL damage soak
                    let damageReduction = 0;
                    let boostedTough = undefined;

                    allHostiles[thisHostile].body.forEach(function(thisPart) {
                        if (thisPart.type == TOUGH && thisPart.boost) {
                            boostedTough = thisPart.boost;
                        } else if (thisPart.type == HEAL && thisPart.boost) {
                            damageReduction += HEAL_POWER * BOOSTS['heal'][thisPart.boost]['heal']
                        } else if (thisPart.type == HEAL) {
                            damageReduction += HEAL_POWER
                        }
                    });
                    //Look for healer creeps within 3 spaces of target creep for further subtractions
                    let nearbyFriendos = allHostiles[thisHostile].pos.findInRange(FIND_HOSTILE_CREEPS, 3, {
                        filter: (eCreep) => (!Memory.whiteList.includes(eCreep.owner.username))
                    });
                    for (let thisFriendo in nearbyFriendos) {
                        let friendRange = allHostiles[thisHostile].pos.getRangeTo(nearbyFriendos[thisFriendo]);
                        nearbyFriendos[thisFriendo].body.forEach(function(thisPart) {
                            if (thisPart.type == HEAL && thisPart.boost) {
                                if (friendRange == 1) {
                                    damageReduction += HEAL_POWER * BOOSTS['heal'][thisPart.boost]['heal']
                                } else {
                                    damageReduction += RANGED_HEAL_POWER * BOOSTS['heal'][thisPart.boost]['rangedHeal']
                                }
                            } else if (thisPart.type == HEAL) {
                                if (friendRange == 1) {
                                    damageReduction += HEAL_POWER
                                } else {
                                    damageReduction += RANGED_HEAL_POWER
                                }
                            }
                        });
                    }

                    //Factor in damage reduction from Tough parts
                    if (boostedTough) {
                        flatDamage = flatDamage * BOOSTS['tough'][boostedTough]['damage']
                    }

                    //Display the calculated damage total under the target
                    let dColor = 'green';
                    if ((flatDamage - damageReduction) <= 0) {
                        dColor = 'red';
                    }
                    new RoomVisual(thisRoom.name).text((flatDamage - damageReduction).toString(), allHostiles[thisHostile].pos.x, allHostiles[thisHostile].pos.y, {color: dColor, font: 0.8});

                    //Determine if this beats the best
                    if ((flatDamage - damageReduction) > damageRecord) {
                        damageRecord = (flatDamage - damageReduction);
                        targetToShoot = allHostiles[thisHostile];
                    }
                }

                //if targetToShoot is defined, a valid target you can damage was found.
                if (targetToShoot) {
                    closestHostile = targetToShoot;
                }
            }

            //Heal only if the target isn't taking damage
            if (Memory.roomCreeps[thisRoom.name] && (!closestHostile || closestHostile.hits > (closestHostile.hitsMax - 500))) {
                if (Game.flags[thisRoom.name + "RoomOperator"]) {
                    powerCreep = tower.pos.findClosestByRange(FIND_MY_POWER_CREEPS);
                    if (powerCreep && powerCreep.hits < powerCreep.hitsMax) {
                        tower.heal(powerCreep);
                        didHeal = true;
                    }
                }
                let allCreeps = Memory.roomCreeps[thisRoom.name];
                if (allCreeps.length && !didHeal) {
                    allCreeps.sort(healCompare);
                    if (allCreeps[0].hits < allCreeps[0].hitsMax - 199) {
                        tower.heal(allCreeps[0]);
                        didHeal = true;
                    }
                }
            }

            if (!didHeal) {
                if (salvagerPos >= 0) {
                    //Verify that it's still not worth the time
                    //RETUNE - this could possibly spawn defenders if a big enough invader wave attacks
                    if (!closestHostile || determineCreepThreat(closestHostile, hostileCount.length)) {
                        //BAD TIMES
                        Memory.roomsPrepSalvager.splice(salvagerPos, 1);
                        salvagerPos = -1;
                    }
                }

                if (closestHostile) {
                    if (closestHostile.owner.username != "Invader" && closestHostile.hitsMax > 200) {
                        Game.notify('ROOM DEFENCE : ' + closestHostile.owner.username + ' is tresspassing in ' + thisRoom.name);
                        Memory.LastNotification = Game.time.toString() + ' : ' + closestHostile.owner.username + ' is tresspassing in ' + thisRoom.name
                    }
                    Memory.towerPickedTarget[thisRoom.name] = closestHostile.id;

                    if (tower.room.controller.level < 7) {
                        if (tower.pos.getRangeTo(closestHostile) <= 5 && closestHostile.owner.username != 'Invader') {
                            //Too close for comfort
                            tower.room.controller.activateSafeMode();
                        }
                    }
                    tower.attack(closestHostile);
                }
            }
        } else if ((tower.energy > (tower.energyCapacity * 0.5)) && (Game.time % checkDelay == 0)) {
            var criticalRoads = tower.room.find(FIND_STRUCTURES, {
                filter: (structure) => (structure.structureType == STRUCTURE_ROAD && structure.hits < (structure.hitsMax / 2))
            });
            if (criticalRoads.length) {
                criticalRoads.sort(repairCompare);
                tower.repair(criticalRoads[0]);
            } else if (Memory.repairTarget[tower.room.name]) {
                let decayingRampart = Game.getObjectById(Memory.repairTarget[tower.room.name]);
                if (decayingRampart && decayingRampart.hits != decayingRampart.hitsMax) {
                    tower.repair(decayingRampart);
                } else {
                    //Bad target, let main handle reassignment
                    Memory.repairTarget[tower.room.name] = undefined;
                }
            }
        }

        if (tower.energy <= tower.energyCapacity - 150 && Memory.towerNeedEnergy[thisRoom.name].indexOf(tower.id) == -1) {
            Memory.towerNeedEnergy[thisRoom.name].push(tower.id);
        } else if (tower.energy > tower.energyCapacity - 150 && Memory.towerNeedEnergy[thisRoom.name].indexOf(tower.id) > -1) {
            var thisTowerIndex = Memory.towerNeedEnergy[thisRoom.name].indexOf(tower.id)
            Memory.towerNeedEnergy[thisRoom.name].splice(thisTowerIndex, 1);
        }
        //Enable to see tower coverage
        //thisRoom.visual.rect(thisTower.pos.x - 15, thisTower.pos.y - 15, 30, 30, {fill: '#ff0019', opacity: 0.2});
        //wew
    }
};

function repairCompare(a, b) {
    if (a.hits < b.hits)
        return -1;
    if (a.hits > b.hits)
        return 1;
    return 0;
}

function healCompare(a, b) {
    let aDiff = a.hitsMax - a.hits;
    let bDiff = b.hitsMax - b.hits;
    if (aDiff < bDiff)
        return 1;
    if (aDiff > bDiff)
        return -1;
    return 0;
}

function determineCreepThreat(eCreep, totalHostiles) {
    if ((eCreep.owner.username == 'Invader' || eCreep.name.indexOf('Drainer') >= 0) || (eCreep.hitsMax <= 1000 && totalHostiles <= 1)) {
        return false;
    } else {
        //Determine if this creep is boosted.
        eCreep.body.forEach(function(thisPart) {
            if (thisPart.boost) {
                return true;
            }
        });
        //unboosted threat, not a problem.
        return false;
    }
}

module.exports = tower_Operate;<|endoftext|>


<commit_before>//<script src="https://rawgit.com/mshoote/BTJSC/master/Markup/AutoTestingMRK4.js"></script>
(function(console){
    console.save = function(data, filename){

        if(!data) {
            console.error('Console.save: No data')
            return;
        }

        if(!filename) filename = 'pagingTime.txt'

        if(typeof data === "object"){
            data = JSON.stringify(data, undefined, 4)
        }

        var blob = new Blob([data], {type: 'text/json'}),
            e    = document.createEvent('MouseEvents'),
            a    = document.createElement('a')

        a.download = filename
        a.href = window.URL.createObjectURL(blob)
        a.dataset.downloadurl =  ['text/json', a.download, a.href].join(':')
        e.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null)
        a.dispatchEvent(e)
    }
})(console)
window.onload = function() {
	window.setTimeout(function(){
  // Check for browser support
    if(!(window.performance && window.performance.timing)) {
    return;
  }
  console.log(console.save([
  performance.timing.loadEventEnd - performance.timing.fetchStart,
  performance.timing.fetchStart - performance.timing.navigationStart,
  performance.timing.redirectEnd - performance.timing.redirectStart,
  performance.timing.domainLookupStart - performance.timing.fetchStart,
  performance.timing.domainLookupEnd - performance.timing.domainLookupStart,
  performance.timing.connectEnd - performance.timing.connectStart,
  performance.timing.responseEnd - performance.timing.requestStart,
  performance.timing.unloadEventEnd - performance.timing.unloadEventStart,
  performance.timing.domContentLoadedEventEnd - performance.timing.domContentLoadedEventStart,
  performance.timing.domComplete - performance.timing.domInteractive,
  performance.timing.loadEventEnd - performance.timing.responseEnd,
  performance.timing.domInteractive - performance.timing.responseEnd,
  performance.timing.loadEventEnd - performance.timing.loadEventStart,
  performance.timing.domComplete - performance.timing.domLoading,
  performance.timing.domContentLoadedEventStart - performance.timing.domLoading,
  null
  ]));
  }, 0);
};
setTimeout(function(){window.location=window.location;},60000);
<commit_msg>Update AutoTestingMRK4.js<commit_after>//<script src="https://rawgit.com/mshoote/BTJSC/master/Markup/AutoTestingMRK4.js"></script>
(function(console){
    console.save = function(data, filename){

        if(!data) {
            console.error('Console.save: No data')
            return;
        }

        if(!filename) filename = 'pagingTime.txt'

        if(typeof data === "object"){
            data = JSON.stringify(data, undefined, 4)
        }

        var blob = new Blob([data], {type: 'text/json'}),
            e    = document.createEvent('MouseEvents'),
            a    = document.createElement('a')

        a.download = filename
        a.href = window.URL.createObjectURL(blob)
        a.dataset.downloadurl =  ['text/json', a.download, a.href].join(':')
        e.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null)
        a.dispatchEvent(e)
    }
})(console)
window.onload = function() {
	window.setTimeout(function(){
  // Check for browser support
    if(!(window.performance && window.performance.timing)) {
    return;
  }
  console.log(console.save([
  performance.timing.loadEventEnd - performance.timing.fetchStart,
  performance.timing.fetchStart - performance.timing.navigationStart,
  performance.timing.redirectEnd - performance.timing.redirectStart,
  performance.timing.domainLookupStart - performance.timing.fetchStart,
  performance.timing.domainLookupEnd - performance.timing.domainLookupStart,
  performance.timing.connectEnd - performance.timing.connectStart,
  performance.timing.responseEnd - performance.timing.requestStart,
  performance.timing.unloadEventEnd - performance.timing.unloadEventStart,
  performance.timing.domContentLoadedEventEnd - performance.timing.domContentLoadedEventStart,
  performance.timing.domComplete - performance.timing.domInteractive,
  performance.timing.loadEventEnd - performance.timing.responseEnd,
  performance.timing.domInteractive - performance.timing.responseEnd,
  performance.timing.loadEventEnd - performance.timing.loadEventStart,
  performance.timing.domComplete - performance.timing.domLoading,
  performance.timing.domContentLoadedEventStart - performance.timing.domLoading,
  null
  ]));
  }, 0);
};
setTimeout(function(){window.location=window.location;},60000);
//setTimeout(function(){window.location=window.location;},30000);
//setTimeout(function(){window.location=window.location;},10000);
<|endoftext|>


<commit_before>import {
  observe,
  defineReactive,
} from './observe'
import {
  watch as watche,
  makeComputed,
} from './watcher'
import {
  def,
  defi,
  noop,
  isFunction,
  every,
} from './utils'
import {
  WATCHERS_PROPERTY_NAME,
  DATA_PROPTERTY_NAME,
} from './constants'

// Only could be react, compute or watch
ob.default = react
ob.deep = ob.lazy = ob.sync = false

Object.setPrototypeOf(ob, {react, compute, watch})

/**
 * ob
 *
 * @public
 * @param {Object} target
 * @param {*} [expression]
 * @param {*} [fun]
 * @param {*} [options]
 * @return {Function} ob
 */

export default function ob (target, expression, fun, options) {
  if (!target.hasOwnProperty(WATCHERS_PROPERTY_NAME)) {
    init(target)
  }
  return ob.default(target, expression, fun, options)
}

/**
 * React options
 *
 * @public
 * @param {Object} options
 * @param {Object} [target]
 * @return {Function} ob
 */

function react (options, target) {
  if (target) {
    if (!target.hasOwnProperty(WATCHERS_PROPERTY_NAME)) {
      init(target)
    }
  } else {
    target = Object.create(null)
  }
  options.methods && carryMethods(target, options.methods)
  options.data && reactProperties(target, options.data)
  options.computed && computeProperties(target, options.computed)
  options.watchers && watchProperties(target, options.watchers)
  return target
}

/**
 * Compute property
 *
 * @public
 * @param {Object} target
 * @param {String} name
 * @param {Function|Object} getterOrAccessor
 *        - Function getter
 *        - Object accessor
 *          - Function [get]  - getter
 *          - Function [set]  - setter
 * @param {Boolean} [cache]
 */

function compute (target, name, getterOrAccessor, cache) {
  if (!target.hasOwnProperty(WATCHERS_PROPERTY_NAME)) {
    init(target)
  }
  let getter, setter
  if (isFunction(getterOrAccessor)) {
    getter = makeComputed(target, getterOrAccessor)
    setter = noop
  } else {
    getter = getterOrAccessor.get
            ? cache !== false
              ? makeComputed(target, getterOrAccessor.get)
              : getterOrAccessor.get.bind(this)
            : noop
    setter = getterOrAccessor.set ? getterOrAccessor.set.bind(this) : noop
  }
  defi(target, name, getter, setter)
}

/**
 * Watch property
 *
 * @public
 * @param {Object} target
 * @param {String|Function} expressionOrFunction
 * @param {Function} callback
 * @param {Object} [options]
 *                 - {Boolean} deep
 *                 - {Boolean} sync
 *                 - {Boolean} lazy
 * @return {Watcher}
 */

function watch (target, expressionOrFunction, callback, options = ob) {
  if (!target.hasOwnProperty(WATCHERS_PROPERTY_NAME)) {
    init(target)
  }
  return watche(target, expressionOrFunction, callback, options)
}

/**
 * @private
 * @param {Object} target
 */

function init (target) {
  def(target, WATCHERS_PROPERTY_NAME, [], false)
  def(target, DATA_PROPTERTY_NAME, Object.create(null), false)
  observe(target[DATA_PROPTERTY_NAME])
  reactSelfProperties(target)
}

/**
 * @private
 * @param {Object} target
 * @param {Object} methods
 */

function carryMethods (target, methods) {
  every(methods, (name, method) => {
    target[name] = method.bind(target)
  })
}

/**
 * @private
 * @param {Object} target
 * @param {String} key
 * @param {*} value
 */
function reactProperty (target, key, value) {
  target[DATA_PROPTERTY_NAME][key] = value
  defineReactive(target[DATA_PROPTERTY_NAME], key, value)
  proxy(target, key)
}

/**
 * @private
 * @param {Object} target
 * @param {Object} properties
 */

function reactProperties (target, properties) {
  every(properties, (key, value) => reactProperty(target, key, value))
}

/**
 * @private
 * @param {Object} target
 */

function reactSelfProperties (target) {
  every(target, (key, value) => {
    !isFunction(value) && reactProperty(target, key, value)
  })
}

/**
 * @private
 * @param {Object} target
 * @param {Object} properties
 */

function computeProperties (target, properties) {
  every(properties, (key, value) => compute(target, key, value))
}

/**
 * @private
 * @param {Object} target
 * @param {Object} properties
 */

function watchProperties (target, properties) {
  every(properties, (expression, functionOrOption) => {
    if (isFunction(functionOrOption)) {
      watch(target, expression, functionOrOption)
    } else {
      watch(target, expression, functionOrOption.watcher, functionOrOption)
    }
  })
}

/**
 * @private
 * @param {Object} target
 * @param {String} key
 */

function proxy (target, key) {
  function getter () {
    return target[DATA_PROPTERTY_NAME][key]
  }
  function setter (value) {
    target[DATA_PROPTERTY_NAME][key] = value
  }
  defi(target, key, getter, setter)
}
<commit_msg>Init new target created in method react<commit_after>import {
  observe,
  defineReactive,
} from './observe'
import {
  watch as watche,
  makeComputed,
} from './watcher'
import {
  def,
  defi,
  noop,
  isFunction,
  every,
} from './utils'
import {
  WATCHERS_PROPERTY_NAME,
  DATA_PROPTERTY_NAME,
} from './constants'

// Only could be react, compute or watch
ob.default = react
ob.deep = ob.lazy = ob.sync = false

Object.setPrototypeOf(ob, {react, compute, watch})

/**
 * ob
 *
 * @public
 * @param {Object} target
 * @param {*} [expression]
 * @param {*} [fun]
 * @param {*} [options]
 * @return {Function} ob
 */

export default function ob (target, expression, fun, options) {
  if (!target.hasOwnProperty(WATCHERS_PROPERTY_NAME)) {
    init(target)
  }
  return ob.default(target, expression, fun, options)
}

/**
 * React options
 *
 * @public
 * @param {Object} options
 * @param {Object} [target]
 * @return {Function} ob
 */

function react (options, target) {
  if (target) {
    if (!target.hasOwnProperty(WATCHERS_PROPERTY_NAME)) {
      init(target)
    }
  } else {
    target = {}
    init(target)
  }
  options.methods && carryMethods(target, options.methods)
  options.data && reactProperties(target, options.data)
  options.computed && computeProperties(target, options.computed)
  options.watchers && watchProperties(target, options.watchers)
  return target
}

/**
 * Compute property
 *
 * @public
 * @param {Object} target
 * @param {String} name
 * @param {Function|Object} getterOrAccessor
 *        - Function getter
 *        - Object accessor
 *          - Function [get]  - getter
 *          - Function [set]  - setter
 * @param {Boolean} [cache]
 */

function compute (target, name, getterOrAccessor, cache) {
  if (!target.hasOwnProperty(WATCHERS_PROPERTY_NAME)) {
    init(target)
  }
  let getter, setter
  if (isFunction(getterOrAccessor)) {
    getter = makeComputed(target, getterOrAccessor)
    setter = noop
  } else {
    getter = getterOrAccessor.get
            ? cache !== false
              ? makeComputed(target, getterOrAccessor.get)
              : getterOrAccessor.get.bind(this)
            : noop
    setter = getterOrAccessor.set ? getterOrAccessor.set.bind(this) : noop
  }
  defi(target, name, getter, setter)
}

/**
 * Watch property
 *
 * @public
 * @param {Object} target
 * @param {String|Function} expressionOrFunction
 * @param {Function} callback
 * @param {Object} [options]
 *                 - {Boolean} deep
 *                 - {Boolean} sync
 *                 - {Boolean} lazy
 * @return {Watcher}
 */

function watch (target, expressionOrFunction, callback, options = ob) {
  if (!target.hasOwnProperty(WATCHERS_PROPERTY_NAME)) {
    init(target)
  }
  return watche(target, expressionOrFunction, callback, options)
}

/**
 * @private
 * @param {Object} target
 */

function init (target) {
  def(target, WATCHERS_PROPERTY_NAME, [], false)
  def(target, DATA_PROPTERTY_NAME, Object.create(null), false)
  observe(target[DATA_PROPTERTY_NAME])
  reactSelfProperties(target)
}

/**
 * @private
 * @param {Object} target
 * @param {Object} methods
 */

function carryMethods (target, methods) {
  every(methods, (name, method) => {
    target[name] = method.bind(target)
  })
}

/**
 * @private
 * @param {Object} target
 * @param {String} key
 * @param {*} value
 */
function reactProperty (target, key, value) {
  target[DATA_PROPTERTY_NAME][key] = value
  defineReactive(target[DATA_PROPTERTY_NAME], key, value)
  proxy(target, key)
}

/**
 * @private
 * @param {Object} target
 * @param {Object} properties
 */

function reactProperties (target, properties) {
  every(properties, (key, value) => reactProperty(target, key, value))
}

/**
 * @private
 * @param {Object} target
 */

function reactSelfProperties (target) {
  every(target, (key, value) => {
    !isFunction(value) && reactProperty(target, key, value)
  })
}

/**
 * @private
 * @param {Object} target
 * @param {Object} properties
 */

function computeProperties (target, properties) {
  every(properties, (key, value) => compute(target, key, value))
}

/**
 * @private
 * @param {Object} target
 * @param {Object} properties
 */

function watchProperties (target, properties) {
  every(properties, (expression, functionOrOption) => {
    if (isFunction(functionOrOption)) {
      watch(target, expression, functionOrOption)
    } else {
      watch(target, expression, functionOrOption.watcher, functionOrOption)
    }
  })
}

/**
 * @private
 * @param {Object} target
 * @param {String} key
 */

function proxy (target, key) {
  function getter () {
    return target[DATA_PROPTERTY_NAME][key]
  }
  function setter (value) {
    target[DATA_PROPTERTY_NAME][key] = value
  }
  defi(target, key, getter, setter)
}
<|endoftext|>


<commit_before>angular.module('notesApp.noteStore', [])
.factory('NoteStore', function(){

  //the notes array
  var notesText = [];

  return{
    list: function(){
      return notesText;
    },
    //function to get text from the notesText array
    //takes the note Id as a parameter
    get: function(noteId){
      for(var i = 0; i < notesText.length; i++){
        if(notesText[i].id == noteId){
          return notesText[i];
        }
      }
      return undefined;
    },
    //function to add a Note
    //takes the note object
    add: function(note){
      notesText.push(note);
    },
    //function to make changes in the notesText array
    //takes the note object
    update: function(note){
      for(var i = 0; i < notesText.length; i++){
        if(notesText[i].id == note.id){
          notesText[i] = note;
        }
      }
    }
  };

});<commit_msg>use localStorage api to store data<commit_after>angular.module('notesApp.noteStore', [])
.factory('NoteStore', function(){

  //the notes array
  var notesText = angular.fromJson(window.localStorage['notesText'] || '[]');

  //HTML 5 api 'localStorage'
  //works with desktop and mobile
  function save(){
  	window.localStorage['notesText'] = angular.toJson(notesText);
  }

  return{
    list: function(){
      return notesText;
    },
    //function to get text from the notesText array
    //takes the note Id as a parameter
    get: function(noteId){
      for(var i = 0; i < notesText.length; i++){
        if(notesText[i].id == noteId){
          return notesText[i];
        }
      }
      return undefined;
    },
    //function to add a Note
    //takes the note object
    add: function(note){
      notesText.push(note);
      save();
    },
    //function to make changes in the notesText array
    //takes the note object
    update: function(note){
      for(var i = 0; i < notesText.length; i++){
        if(notesText[i].id == note.id){
          notesText[i] = note;
        }
      }
      save();
    }
  };

});<|endoftext|>


<commit_before>define(
  'tinymce.themes.mobile.ui.ToolbarWidgets',

  [
    'tinymce.themes.mobile.ui.Buttons'
  ],

  function (Buttons) {
    var button = function (ios, clazz, makeItems) {
      return Buttons.forToolbar(clazz, function () {
        var items = makeItems();
        ios.setContextToolbar([
          {
            label: 'font-color',
            items: items
          }
        ]);
      }, { }, { });
    };

    return {
      button: button
    };
  }
);
<commit_msg>TM-6: aria labels<commit_after>define(
  'tinymce.themes.mobile.ui.ToolbarWidgets',

  [
    'tinymce.themes.mobile.ui.Buttons'
  ],

  function (Buttons) {
    var button = function (ios, clazz, makeItems) {
      return Buttons.forToolbar(clazz, function () {
        var items = makeItems();
        ios.setContextToolbar([
          {
            // FIX: I18n
            label: clazz + ' group',
            items: items
          }
        ]);
      }, { }, { });
    };

    return {
      button: button
    };
  }
);
<|endoftext|>