<commit_before>var gameModal = gameModal || {};

gameModal = function (game) {

    var _this = this;

    game.modals = {};

    /**
     * [hideModal description]
     * @param  {[type]} type [description]
     * @return {[type]}      [description]
     */
    this.hideModal = function(type) {
        window.console.log(type);
        game.modals[type].visible = false;
    };

    return {

        createModal: function (options) {

            var type = options.type || ''; // must be unique
            var includeBackground = options.includeBackground; // maybe not optional
            var backgroundColor = options.backgroundColor || "0x000000";
            var backgroundOpacity = options.backgroundOpacity || 0.7;
            var modalCloseOnInput = options.modalCloseOnInput || false;
            var vCenter = options.vCenter || true;
            var hCenter = options.hCenter || true;
            var itemsArr = options.itemsArr || [];
            /*var vPadding = options.vPadding || 20;*/

            /////////////////////////////////////////////////////////////////////

            var modal;
            var modalGroup = game.add.group();

            if (includeBackground === true) {
                modal = game.add.graphics(game.width, game.height);
                modal.beginFill(backgroundColor, backgroundOpacity);
                modal.x = 0;
                modal.y = 0;

                modal.drawRect(0, 0, game.width, game.height);

                if(modalCloseOnInput === true) {

                    var innerModal = game.add.sprite(0, 0);
                    innerModal.inputEnabled = true;
                    innerModal.width = game.width;
                    innerModal.height = game.height;
                    innerModal.type = type;
                    innerModal.input.priorityID = 0;
                    innerModal.events.onInputDown.add(function(e, pointer){
                        window.console.log(e, pointer);
                        this.hideModal(e.type);
                    }, _this, 2);

                    modalGroup.add(innerModal);
                }
                else {
                    //modal.inputEnabled = true;
                    /*var innerModal = game.add.sprite(0, 0);
                    innerModal.inputEnabled = true;
                    innerModal.width = game.width;
                    innerModal.height = game.height;
                    innerModal.type = type;
                    innerModal.input.priorityID = 2;
                    innerModal.events.onInputDown.add(function(e){
                        //
                    }, _this);
                    modalGroup.add(innerModal);*/
                }
            }

            // add the bg
            if(includeBackground) {
                modalGroup.add(modal);
            }

            var modalLabel;
            for (var i = 0; i < itemsArr.length; i += 1) {
                var item = itemsArr[i];
                var itemType = item.type || 'text';
                var itemColor = item.color || 0x000000;
                var itemFontfamily = item.fontFamily || 'Arial';
                var itemFontSize = item.fontSize || 32;
                var itemStroke = item.stroke || '0x000000';
                var itemStrokeThickness = item.strokeThickness || 0;
                var itemAlign = item.align || 'center';
                var offsetX = item.offsetX || 0;
                var offsetY = item.offsetY || 0;
                var contentScale = item.contentScale || 1;
                var content = item.content || "";
                var centerX = game.width / 2;
                var centerY = game.height / 2;
                var callback = item.callback || false;

                modalLabel = null;

                if (itemType === "text" || itemType === "bitmapText") {

                    if (itemType === "text") {
                        modalLabel = game.add.text(0, 0, content, {
                            font: itemFontSize + 'px ' + itemFontfamily,
                            fill: "#" + String(itemColor).replace("0x",""),
                            stroke: "#" + String(itemStroke).replace("0x",""),
                            strokeThickness: itemStrokeThickness,
                            align: itemAlign
                        });
                        modalLabel.contentType = 'text';
                        modalLabel.update();
                        modalLabel.x = ((game.width / 2) - (modalLabel.width / 2)) + offsetX;
                        modalLabel.y = ((game.height / 2) - (modalLabel.height / 2)) + offsetY;
                    } else {
                        modalLabel = game.add.bitmapText(0, 0, itemFontfamily, String(content), itemFontSize);
                        modalLabel.contentType = 'bitmapText';
                        modalLabel.updateText();
                        modalLabel.x = (centerX - (modalLabel.width / 2)) + offsetX;
                        modalLabel.y = (centerY - (modalLabel.height / 2)) + offsetY;
                    }

                } else if (itemType === "image") {
                    //content = item.imageKey || "";
                    modalLabel = game.add.image(0, 0, content);
                    modalLabel.scale.setTo(contentScale, contentScale);
                    modalLabel.contentType = 'image';
                    modalLabel.x = (centerX - ((modalLabel.width) / 2)) + offsetX;
                    modalLabel.y = (centerY - ((modalLabel.height) / 2)) + offsetY;
                }

                modalLabel.offsetX = offsetX;
                modalLabel.offsetY = offsetY;

                if (callback !== false) {
                    modalLabel.inputEnabled = true;
                    modalLabel.pixelPerfectClick = true;
                    modalLabel.priorityID = 10;
                    modalLabel.events.onInputDown.add(callback, modalLabel);
                }

                if(type !== "bitmapText"){
                    modalLabel.bringToTop();
                    modalGroup.add(modalLabel);
                    modalLabel.bringToTop();
                    modalGroup.bringToTop(modalLabel);
                }
                else {
                    modalGroup.add(modalLabel);
                    modalGroup.bringToTop(modalLabel);
                }
            }

            modalGroup.visible = false;
            game.modals[type] = modalGroup;

        },
        updateModalValue: function(value, type, index, id) {
            var item;
            if(index !== undefined && index !== null) {
                item = game.modals[type].getChildAt(index);
            }
            else if(id !== undefined && id !== null) {

            }

            if(item.contentType === "text") {
                item.text = value;
                item.update();
                item.x = ((game.width / 2) - (item.width / 2)) + item.offsetX;
                item.y = ((game.height / 2) - (item.height / 2)) + item.offsetY;
            }
            else if(item.contentType === "bitmapText") {
                item.text = value;
                item.updateText();
                item.x = ((game.width / 2) - (item.width / 2)) + item.offsetX;
                item.y = ((game.height / 2) - (item.height / 2)) + item.offsetY;
            }
            else if(item.contentType === "image") {
                item.loadTexture(value);
            }

        },
        getModalItem: function(type, index) {
            return game.modals[type].getChildAt(index);
        },
        showModal: function (type) {
            game.world.bringToTop(game.modals[type]);
            game.modals[type].visible = true;
            // you can add animation here
        },
        hideModal: function (type) {
            game.modals[type].visible = false;
            // you can add animation here
        },
        destroyModal: function (type) {
            game.modals[type].destroy();
            delete game.modals[type];
        }
    };
};

/**
 * [createModal description]
 * @param  {[type]} type [description]
 * @return {[type]}      [description]
 */
function createModal(type, fn) {

    var modalGroup = game.add.group();
    modalGroup.inputEnabled = true;

    var modal = game.add.graphics(game.width, game.height);
    modal.beginFill("0xffffff", 0.7);
    modal.x = 0;
    modal.y = 0;
    modal.inputEnabled = true;
    modal.drawRect(0, 0, game.width, game.height);

    //var modalPanel = game.add.image((game.width / 2 - (550 / 2)), (game.height / 2 - (400 / 2)), "modal");

    if (type === "game-over") {

        var gameLabel = game.add.image(game.width / 2 - ((358 * 0.6) / 2), (game.height / 2) - 250, 'gameover');
        gameLabel.scale.setTo(0.6, 0.6);
        var gameLabel1 = game.add.image(game.width / 2 - ((533 * 0.6) / 2), game.height / 2, 'tryagain');
        gameLabel1.scale.setTo(0.6, 0.6);
        var yesLabel = game.add.image(game.width / 2 - 200, game.height / 2 + 150, 'yes');
        var noLabel = game.add.image(game.width / 2 + 80, game.height / 2 + 150, 'no');

        yesLabel.scale.setTo(0.8, 0.8);
        noLabel.scale.setTo(0.8, 0.8);

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

        yesLabel.inputEnabled = true;
        yesLabel.events.onInputDown.add(function () {
            game.state.start('Game');
        }, this);

        noLabel.inputEnabled = true;
        noLabel.events.onInputDown.add(function () {
            game.state.start('MainMenu');
        }, this);

        modalGroup.add(modal);
        modalGroup.add(gameLabel);
        modalGroup.add(gameLabel1);
        modalGroup.add(yesLabel);
        modalGroup.add(noLabel);

    } else if (type === "level") {

        var modalText = game.add.bitmapText(0, 0, 'font', "Starting \nNext Level", 52);

        modalText.inputEnabled = true;
        modalText.updateText();
        modalText.x = game.width / 2 - (modalText.width / 2);
        modalText.y = game.height / 2 - (modalText.height / 2) - 200;

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

        var countDownText = game.add.bitmapText(0, 0, 'font', "3", 38);

        //countDownText.inputEnabled = true;
        countDownText.updateText();
        countDownText.x = game.width / 2 - (countDownText.width / 2);
        countDownText.y = game.height / 2 - (countDownText.height / 2) - 100;

        reg.countDownText = countDownText;

        modal.destroy();
        //modalGroup.add(modal);
        modalGroup.add(modalText);
        modalGroup.add(countDownText);

    } else if (type === "info") {

        // -----------
        var modalText = game.add.bitmapText(0, 0, 'font', "Click/TAP the signs \nin the correct order", 32);

        modalText.inputEnabled = true;
        modalText.updateText();
        modalText.x = game.width / 2 - (modalText.width / 2);
        modalText.y = game.height / 2 - (modalText.height / 2);

        var closeX = game.add.bitmapText(0, 0, 'font', 'Got it!', 40);
        closeX.inputEnabled = true;
        closeX.updateText();
        closeX.x = game.width / 2 - (closeX.width / 2);
        closeX.y = game.height - 300;

        closeX.events.onInputDown.add(function () {
            fn();
            hideModal('info');
        }, game);

        modalGroup.add(modal);
        modalGroup.add(closeX);
        //modalGroup.add(modalPanel);
        //modalGroup.add(modalHeader);
        //modalGroup.add(gameLabel2);
        modalGroup.add(modalText);
    }

    modalGroup.visible = false;

    reg.modal[type] = modalGroup;

    if (type === "info") {
        showModal(type);
    }
}<commit_msg>typo fix<commit_after>var gameModal = gameModal || {};

gameModal = function (game) {

    var _this = this;

    game.modals = {};

    /**
     * [hideModal description]
     * @param  {[type]} type [description]
     * @return {[type]}      [description]
     */
    this.hideModal = function(type) {
        window.console.log(type);
        game.modals[type].visible = false;
    };

    return {

        createModal: function (options) {

            var type = options.type || ''; // must be unique
            var includeBackground = options.includeBackground; // maybe not optional
            var backgroundColor = options.backgroundColor || "0x000000";
            var backgroundOpacity = options.backgroundOpacity || 0.7;
            var modalCloseOnInput = options.modalCloseOnInput || false;
            var vCenter = options.vCenter || true;
            var hCenter = options.hCenter || true;
            var itemsArr = options.itemsArr || [];
            /*var vPadding = options.vPadding || 20;*/

            /////////////////////////////////////////////////////////////////////

            var modal;
            var modalGroup = game.add.group();

            if (includeBackground === true) {
                modal = game.add.graphics(game.width, game.height);
                modal.beginFill(backgroundColor, backgroundOpacity);
                modal.x = 0;
                modal.y = 0;

                modal.drawRect(0, 0, game.width, game.height);

                if(modalCloseOnInput === true) {

                    var innerModal = game.add.sprite(0, 0);
                    innerModal.inputEnabled = true;
                    innerModal.width = game.width;
                    innerModal.height = game.height;
                    innerModal.type = type;
                    innerModal.input.priorityID = 0;
                    innerModal.events.onInputDown.add(function(e, pointer){
                        window.console.log(e, pointer);
                        this.hideModal(e.type);
                    }, _this, 2);

                    modalGroup.add(innerModal);
                }
                else {
                    //modal.inputEnabled = true;
                    /*var innerModal = game.add.sprite(0, 0);
                    innerModal.inputEnabled = true;
                    innerModal.width = game.width;
                    innerModal.height = game.height;
                    innerModal.type = type;
                    innerModal.input.priorityID = 2;
                    innerModal.events.onInputDown.add(function(e){
                        //
                    }, _this);
                    modalGroup.add(innerModal);*/
                }
            }

            // add the bg
            if(includeBackground) {
                modalGroup.add(modal);
            }

            var modalLabel;
            for (var i = 0; i < itemsArr.length; i += 1) {
                var item = itemsArr[i];
                var itemType = item.type || 'text';
                var itemColor = item.color || 0x000000;
                var itemFontfamily = item.fontFamily || 'Arial';
                var itemFontSize = item.fontSize || 32;
                var itemStroke = item.stroke || '0x000000';
                var itemStrokeThickness = item.strokeThickness || 0;
                var itemAlign = item.align || 'center';
                var offsetX = item.offsetX || 0;
                var offsetY = item.offsetY || 0;
                var contentScale = item.contentScale || 1;
                var content = item.content || "";
                var centerX = game.width / 2;
                var centerY = game.height / 2;
                var callback = item.callback || false;

                modalLabel = null;

                if (itemType === "text" || itemType === "bitmapText") {

                    if (itemType === "text") {
                        modalLabel = game.add.text(0, 0, content, {
                            font: itemFontSize + 'px ' + itemFontfamily,
                            fill: "#" + String(itemColor).replace("0x",""),
                            stroke: "#" + String(itemStroke).replace("0x",""),
                            strokeThickness: itemStrokeThickness,
                            align: itemAlign
                        });
                        modalLabel.contentType = 'text';
                        modalLabel.update();
                        modalLabel.x = ((game.width / 2) - (modalLabel.width / 2)) + offsetX;
                        modalLabel.y = ((game.height / 2) - (modalLabel.height / 2)) + offsetY;
                    } else {
                        modalLabel = game.add.bitmapText(0, 0, itemFontfamily, String(content), itemFontSize);
                        modalLabel.contentType = 'bitmapText';
                        modalLabel.updateText();
                        modalLabel.x = (centerX - (modalLabel.width / 2)) + offsetX;
                        modalLabel.y = (centerY - (modalLabel.height / 2)) + offsetY;
                    }

                } else if (itemType === "image") {
                    //content = item.imageKey || "";
                    modalLabel = game.add.image(0, 0, content);
                    modalLabel.scale.setTo(contentScale, contentScale);
                    modalLabel.contentType = 'image';
                    modalLabel.x = (centerX - ((modalLabel.width) / 2)) + offsetX;
                    modalLabel.y = (centerY - ((modalLabel.height) / 2)) + offsetY;
                }

                modalLabel.offsetX = offsetX;
                modalLabel.offsetY = offsetY;

                if (callback !== false) {
                    modalLabel.inputEnabled = true;
                    modalLabel.pixelPerfectClick = true;
                    modalLabel.priorityID = 10;
                    modalLabel.events.onInputDown.add(callback, modalLabel);
                }

                if(itemType !== "bitmapText"){
                    modalLabel.bringToTop();
                    modalGroup.add(modalLabel);
                    modalLabel.bringToTop();
                    modalGroup.bringToTop(modalLabel);
                }
                else {
                    modalGroup.add(modalLabel);
                    modalGroup.bringToTop(modalLabel);
                }
            }

            modalGroup.visible = false;
            game.modals[type] = modalGroup;

        },
        updateModalValue: function(value, type, index, id) {
            var item;
            if(index !== undefined && index !== null) {
                item = game.modals[type].getChildAt(index);
            }
            else if(id !== undefined && id !== null) {

            }

            if(item.contentType === "text") {
                item.text = value;
                item.update();
                item.x = ((game.width / 2) - (item.width / 2)) + item.offsetX;
                item.y = ((game.height / 2) - (item.height / 2)) + item.offsetY;
            }
            else if(item.contentType === "bitmapText") {
                item.text = value;
                item.updateText();
                item.x = ((game.width / 2) - (item.width / 2)) + item.offsetX;
                item.y = ((game.height / 2) - (item.height / 2)) + item.offsetY;
            }
            else if(item.contentType === "image") {
                item.loadTexture(value);
            }

        },
        getModalItem: function(type, index) {
            return game.modals[type].getChildAt(index);
        },
        showModal: function (type) {
            game.world.bringToTop(game.modals[type]);
            game.modals[type].visible = true;
            // you can add animation here
        },
        hideModal: function (type) {
            game.modals[type].visible = false;
            // you can add animation here
        },
        destroyModal: function (type) {
            game.modals[type].destroy();
            delete game.modals[type];
        }
    };
};

/**
 * [createModal description]
 * @param  {[type]} type [description]
 * @return {[type]}      [description]
 */
function createModal(type, fn) {

    var modalGroup = game.add.group();
    modalGroup.inputEnabled = true;

    var modal = game.add.graphics(game.width, game.height);
    modal.beginFill("0xffffff", 0.7);
    modal.x = 0;
    modal.y = 0;
    modal.inputEnabled = true;
    modal.drawRect(0, 0, game.width, game.height);

    //var modalPanel = game.add.image((game.width / 2 - (550 / 2)), (game.height / 2 - (400 / 2)), "modal");

    if (type === "game-over") {

        var gameLabel = game.add.image(game.width / 2 - ((358 * 0.6) / 2), (game.height / 2) - 250, 'gameover');
        gameLabel.scale.setTo(0.6, 0.6);
        var gameLabel1 = game.add.image(game.width / 2 - ((533 * 0.6) / 2), game.height / 2, 'tryagain');
        gameLabel1.scale.setTo(0.6, 0.6);
        var yesLabel = game.add.image(game.width / 2 - 200, game.height / 2 + 150, 'yes');
        var noLabel = game.add.image(game.width / 2 + 80, game.height / 2 + 150, 'no');

        yesLabel.scale.setTo(0.8, 0.8);
        noLabel.scale.setTo(0.8, 0.8);

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

        yesLabel.inputEnabled = true;
        yesLabel.events.onInputDown.add(function () {
            game.state.start('Game');
        }, this);

        noLabel.inputEnabled = true;
        noLabel.events.onInputDown.add(function () {
            game.state.start('MainMenu');
        }, this);

        modalGroup.add(modal);
        modalGroup.add(gameLabel);
        modalGroup.add(gameLabel1);
        modalGroup.add(yesLabel);
        modalGroup.add(noLabel);

    } else if (type === "level") {

        var modalText = game.add.bitmapText(0, 0, 'font', "Starting \nNext Level", 52);

        modalText.inputEnabled = true;
        modalText.updateText();
        modalText.x = game.width / 2 - (modalText.width / 2);
        modalText.y = game.height / 2 - (modalText.height / 2) - 200;

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

        var countDownText = game.add.bitmapText(0, 0, 'font', "3", 38);

        //countDownText.inputEnabled = true;
        countDownText.updateText();
        countDownText.x = game.width / 2 - (countDownText.width / 2);
        countDownText.y = game.height / 2 - (countDownText.height / 2) - 100;

        reg.countDownText = countDownText;

        modal.destroy();
        //modalGroup.add(modal);
        modalGroup.add(modalText);
        modalGroup.add(countDownText);

    } else if (type === "info") {

        // -----------
        var modalText = game.add.bitmapText(0, 0, 'font', "Click/TAP the signs \nin the correct order", 32);

        modalText.inputEnabled = true;
        modalText.updateText();
        modalText.x = game.width / 2 - (modalText.width / 2);
        modalText.y = game.height / 2 - (modalText.height / 2);

        var closeX = game.add.bitmapText(0, 0, 'font', 'Got it!', 40);
        closeX.inputEnabled = true;
        closeX.updateText();
        closeX.x = game.width / 2 - (closeX.width / 2);
        closeX.y = game.height - 300;

        closeX.events.onInputDown.add(function () {
            fn();
            hideModal('info');
        }, game);

        modalGroup.add(modal);
        modalGroup.add(closeX);
        //modalGroup.add(modalPanel);
        //modalGroup.add(modalHeader);
        //modalGroup.add(gameLabel2);
        modalGroup.add(modalText);
    }

    modalGroup.visible = false;

    reg.modal[type] = modalGroup;

    if (type === "info") {
        showModal(type);
    }
}<|endoftext|>


<commit_before>import Move from './Move.js';

import AbilityEvent from '../../../events/AbilityEvent.js';

export default class UseAbilityMove extends Move {
    constructor(actorTile, index, x, y) { // TODO: Consider passing target tile
        super(actorTile);
        if(!Number.isInteger(+index) || !Number.isInteger(+x) || !Number.isInteger(+y)) {
            throw new Error('Parameters must be integers: ' + arguments);
        }
        this._index = +index;
        this._x = +x;
        this._y = +y;
    }

    getIndex() {
        return this._index;
    }

    getX() {
        return this._x;
    }

    getY() {
        return this._y;
    }

    getReasonIllegal(dungeon, creature) {
        const ability = creature.getAbilities()[this.getIndex()];
        const tile = dungeon.getTile(this.getX(), this.getY());
        return ability.getReasonIllegal(dungeon, creature, tile);
    }

    getCostMultiplier() {
        return 1;
    }

    execute(dungeon, creature) {
        const x = this.getX();
        const y = this.getY();
        const tile = dungeon.getTile(x, y);
        const reason = this.getReasonIllegal(dungeon, creature, tile);
        if(reason) {
            throw new Error(reason);
        }
        const index = this._index;
        const ability = creature.getAbilities()[index];
        if(ability.isTargetted()) {
            ability.use(dungeon, creature, tile);
            dungeon.fireEvent(new AbilityEvent(dungeon, creature, ability, tile));
        } else {
            ability.use(dungeon, creature);
            dungeon.fireEvent(new AbilityEvent(dungeon, creature, ability));
        }
    }

    isSeenBy(dungeon, observer) {
        return observer.canSee(dungeon, dungeon.getTile(this.getActorX(), this.getActorY()));
    }
}
<commit_msg>Documentation<commit_after>import Move from './Move.js';

import AbilityEvent from '../../../events/AbilityEvent.js';

/**
 * The move a Creature makes when they use an ability
 */
export default class UseAbilityMove extends Move {
    constructor(actorTile, index, x, y) { // TODO: Consider passing target tile
        super(actorTile);
        if(!Number.isInteger(+index) || !Number.isInteger(+x) || !Number.isInteger(+y)) {
            throw new Error('Parameters must be integers: ' + arguments);
        }
        this._index = +index;
        this._x = +x;
        this._y = +y;
    }

    /**
     * Gets the index of the ability to be used
     * @returns {number} - A non-negative integer. The position of the ability in the Creature's list
     */
    getIndex() {
        return this._index;
    }

    /**
     * Gets the x value of the ability target position, if any
     * @returns {number | null}
     */
    getX() {
        return this._x;
    }

    /**
     * Gets the y value of the ability target position, if any
     * @returns {number | null}
     */
    getY() {
        return this._y;
    }

    /**
     * @override
     */
    getReasonIllegal(dungeon, creature) {
        const ability = creature.getAbilities()[this.getIndex()];
        const tile = dungeon.getTile(this.getX(), this.getY());
        return ability.getReasonIllegal(dungeon, creature, tile);
    }

    /**
     * @override
     */
    getCostMultiplier() {
        return 1;
    }

    /**
     * @override
     */
    execute(dungeon, creature) {
        const x = this.getX();
        const y = this.getY();
        const tile = dungeon.getTile(x, y);
        const reason = this.getReasonIllegal(dungeon, creature, tile);
        if(reason) {
            throw new Error(reason);
        }
        const index = this._index;
        const ability = creature.getAbilities()[index];
        if(ability.isTargetted()) {
            ability.use(dungeon, creature, tile);
            dungeon.fireEvent(new AbilityEvent(dungeon, creature, ability, tile));
        } else {
            ability.use(dungeon, creature);
            dungeon.fireEvent(new AbilityEvent(dungeon, creature, ability));
        }
    }

    /**
     * @override
     */
    isSeenBy(dungeon, observer) {
        return observer.canSee(dungeon, dungeon.getTile(this.getActorX(), this.getActorY()));
    }
}
<|endoftext|>


<commit_before>'use strict';

describe('Directive: functionList', function() {

  // load the directive's module
  beforeEach(module('voyager'));

  var scope, $compile;

  beforeEach(inject(function ($rootScope, _$compile_) {
    scope = $rootScope.$new();
    $compile = _$compile_;

    scope = $rootScope.$new();
    scope.schema = {
      properties: {
        aggregate: {
          supportedEnums: {
            quantitative: ['a', 'b'],
            undefined: []
          }
        },
        timeUnit: {
          supportedEnums: {
            temporal: ['f1','f2']
          }
        },
        bin: {
          supportedTypes: {
            quantitative: true
          }
        }
      }
    };
    scope.pills = {
      x: { type: 'quantitative', name: 'x'},
      y: null,
      color: { type: 'temporal', name: 'c'},
      update: function() {}
    };
    scope.encType = 'x';
    scope.encType2 = 'y';
    scope.encType3 = 'color';
  }));

  it('should have correct number of radio', function() {
    // FIXME
  });

});
<commit_msg>encType => channel (local var)<commit_after>'use strict';

describe('Directive: functionList', function() {

  // load the directive's module
  beforeEach(module('voyager'));

  var scope, $compile;

  beforeEach(inject(function ($rootScope, _$compile_) {
    scope = $rootScope.$new();
    $compile = _$compile_;

    scope = $rootScope.$new();
    scope.schema = {
      properties: {
        aggregate: {
          supportedEnums: {
            quantitative: ['a', 'b'],
            undefined: []
          }
        },
        timeUnit: {
          supportedEnums: {
            temporal: ['f1','f2']
          }
        },
        bin: {
          supportedTypes: {
            quantitative: true
          }
        }
      }
    };
    scope.pills = {
      x: { type: 'quantitative', name: 'x'},
      y: null,
      color: { type: 'temporal', name: 'c'},
      update: function() {}
    };
    scope.channel = 'x';
    scope.channel2 = 'y';
    scope.channel3 = 'color';
  }));

  it('should have correct number of radio', function() {
    // FIXME
  });

});
<|endoftext|>


<commit_before>// The database abstraction layer

'use strict';

var Promise = require('bluebird');
var downloadGTFS = require('./download');
var _ = require('underscore');

function GTFSdb(knex) {

  this._knex = knex;
};

GTFSdb.prototype.download = function download(config, callback) {
  var knex = this._knex;
  return new Promise(function(fulfill, reject) {
    downloadGTFS(knex, config, function(error){
      if (error) reject(error)
      else fulfill();
    });
  });
}

GTFSdb.prototype.getAllAgencies = function getAgencies() {
  return this._knex.select().table('agency_entry')
  .join('agency', 'agency_entry.id', '=', 'agency.agency_entry_id')
  .map(formatAgency);
}

GTFSdb.prototype.getAgencies = function getAgencies(agencyKey) {
  return this._knex.select().from('agency')
  .where('agency_entry_id', getAgencyId(this._knex, agencyKey))
  .map(function (row) {
    // Attach the agency key.
    row.agency_key = agencyKey;
    return row;
  })
  .map(formatAgency);
}

GTFSdb.prototype.getStops = function getStops(agencyKey) {
  return this._knex.select().from('stop')
  .where('agency_entry_id', getAgencyId(this._knex, agencyKey));
}

GTFSdb.prototype.getStop = function getStop(agencyKey, stopId) {
  return this._knex.select().from('stop')
  .where({
    stop_id: stopId,
    agency_entry_id: getAgencyId(this._knex, agencyKey)
  });
}

GTFSdb.prototype.getRoutes = function getRoutes(agencyKey) {
  return this._knex.select().from('route')
  .where('agency_entry_id', getAgencyId(this._knex, agencyKey));
}

GTFSdb.prototype.getRoute = function getRoute(agencyKey, routeId) {
  return this._knex.select().from('route')
  .where({
    route_id: routeId,
    agency_entry_id: getAgencyId(this._knex, agencyKey)
  });
}

GTFSdb.prototype.getRouteTrips = function getRouteTrips(agencyKey, routeId) {
  var knex = this._knex;
  return knex.select(
    'id',
    'trip_id',
    'route_id',
    'service_id',
    'trip_headsign',
    'trip_short_name',
    'direction_id',
    'block_id',
    'shape_id',
    'wheelchair_accessible',
    'bikes_allowed'
  ).from('trip').where({
    agency_entry_id: getAgencyId(knex, agencyKey),
    route_id: knex.select('id').from('route').where({
      route_id: routeId,
      agency_entry_id: getAgencyId(this._knex, agencyKey)
    })
  }).then(function (trips) {

    return Promise.props({
      trips: trips,
      shapes: getShapeSequences(knex, trips),
      stops: getStops(knex, trips)
    });
  }).then(function (data) {

    return Promise.props({
      trips: Promise.map(data.trips, function (trip) {
        trip.stop_times = data.stops[trip.id];
        trip.id = undefined;
        // FIXME: Get the stop_id, NOT the database ID
        return trip;
      }),
      shapes: data.shapes
    })
  });
}

// Helpers

function getAgencyId(knex, agencyKey) {
  return knex.select('id').from('agency_entry')
  .where({ agency_key: agencyKey });
}

function formatAgency(agency) {
  agency.id = undefined;
  agency.agency_entry_id = undefined;
  return formatRow(agency);
}

function formatRow(row) {
  row.created_at = undefined;
  row.updated_at = undefined;
  return row;
}

function getShapeSequences(knex, trips) {
  return knex.select(
    'shape_id',
    'shape_pt_lat',
    'shape_pt_lon',
    'shape_pt_sequence',
    'shape_dist_traveled'
  ).from('shape_sequence').whereIn('shape_id', trips.map(function (x) { return x.shape_id; }))
  .then(combineShapes)
}

function getStops(knex, trips) {
  return knex.select(
    'stop_time.trip_id',
    'stop_time.arrival_time',
    'stop_time.departure_time',
    'stop_time.stop_sequence',
    'stop_time.stop_headsign',
    'stop_time.pickup_type',
    'stop_time.drop_off_type',
    'stop_time.shape_dist_traveled',
    'stop_time.timepoint',
    'stop.stop_id'
  ).from('stop_time').whereIn('stop_time.trip_id', trips.map(function (x) { return x.id; }))
  .leftJoin('stop', 'stop.id', 'stop_time.stop_id')
  .then(combineStops);
}

function combineShapes(shapeSequences) {

  var dict = shapeSequences.reduce(function (acc, row) {
    var d = acc[row.shape_id];
    if (!d) {
      d = [];
      acc[row.shape_id] = d;
    }
    // Insert sorted.
    var insertPos = d.length;
    for (var i = 0; i < d.length; i++) {
      if (d[i].shape_pt_sequence > row.shape_pt_sequence) {
        insertPos = i;
        break;
      }
    }
    d.splice(i, 0, row);
    return acc;
  }, {});

  // Remove redundant information.
  for (var key in dict) {
    var shapes = dict[key];
    dict[key] = shapes.map(function (s) {
      return {
        lat: s.shape_pt_lat,
        lon: s.shape_pt_lon,
        shape_dist_traveled: (s.shape_dist_traveled != null ? s.shape_dist_traveled : undefined)
      };
    });
  }
  return dict;
}

function combineStops(routeStops) {
  var dict = routeStops.reduce(function (acc, row) {
    var d = acc[row.trip_id];
    if (!d) {
      d = [];
      acc[row.trip_id] = d;
    }
    // Insert sorted.
    var insertPos = d.length;
    for (var i = 0; i < d.length; i++) {
      if (d[i].stop_sequence > row.stop_sequence) {
        insertPos = i;
        break;
      }
    }
    d.splice(i, 0, row);
    return acc;
  }, {});

  return dict;
}

module.exports = function createGTFSdb(knex) {
  var gtfsdb = new GTFSdb(knex);
  return gtfsdb;
};
<commit_msg>Change the columns that are returned from within the API<commit_after>// The database abstraction layer

'use strict';

var Promise = require('bluebird');
var downloadGTFS = require('./download');
var _ = require('underscore');

function GTFSdb(knex) {

  this._knex = knex;
};

GTFSdb.prototype.download = function download(config, callback) {
  var knex = this._knex;
  return new Promise(function(fulfill, reject) {
    downloadGTFS(knex, config, function(error){
      if (error) reject(error)
      else fulfill();
    });
  });
}

GTFSdb.prototype.getAllAgencies = function getAgencies() {
  return this._knex.select(agencyCols).table('agency_entry')
  .join('agency', 'agency_entry.id', '=', 'agency.agency_entry_id')
  .map(formatAgency);
}

GTFSdb.prototype.getAgencies = function getAgencies(agencyKey) {
  return this._knex.select(agencyCols).from('agency')
  .where('agency_entry_id', getAgencyId(this._knex, agencyKey))
  .map(function (row) {
    // Attach the agency key.
    row.agency_key = agencyKey;
    return row;
  });
}

GTFSdb.prototype.getStops = function getStops(agencyKey) {
  return this._knex.select(stopCols).from('stop')
  .where('agency_entry_id', getAgencyId(this._knex, agencyKey));
}

GTFSdb.prototype.getStop = function getStop(agencyKey, stopId) {
  return this._knex.select(stopCols).from('stop')
  .where({
    stop_id: stopId,
    agency_entry_id: getAgencyId(this._knex, agencyKey)
  });
}

GTFSdb.prototype.getRoutes = function getRoutes(agencyKey) {
  return this._knex.select(routeCols).from('route')
  .where('route.agency_entry_id', getAgencyId(this._knex, agencyKey))
  .leftJoin('agency', 'agency.id', 'route.agency_id');
}

GTFSdb.prototype.getRoute = function getRoute(agencyKey, routeId) {
  return this._knex.select(routeCols).from('route')
  .where({
    'route.route_id': routeId,
    'route.agency_entry_id': getAgencyId(this._knex, agencyKey)
  })
  .leftJoin('agency', 'agency.id', 'route.agency_id');
}

GTFSdb.prototype.getRouteTrips = function getRouteTrips(agencyKey, routeId) {
  var knex = this._knex;
  return knex.select(tripCols).from('trip').where({
    'trip.agency_entry_id': getAgencyId(knex, agencyKey),
    'trip.route_id': knex.select('id').from('route').where({
      'route.route_id': routeId,
      'route.agency_entry_id': getAgencyId(this._knex, agencyKey)
    })
  }).then(function (trips) {

    return Promise.props({
      trips: trips,
      shapes: getShapeSequences(knex, trips),
      stops: getStops(knex, trips)
    });
  }).then(function (data) {

    return Promise.props({
      trips: Promise.map(data.trips, function (trip) {
        trip.stop_times = data.stops[trip.id];
        trip.id = undefined;
        // FIXME: Get the stop_id, NOT the database ID
        return trip;
      }),
      shapes: data.shapes
    })
  });
}

// Default columns

var agencyCols = [
  'agency.id',
  'agency.agency_id',
  'agency.agency_name',
  'agency.agency_url',
  'agency.agency_timezone',
  'agency.agency_lang',
  'agency.agency_phone',
  'agency.agency_fare_url',
  'agency.last_update'
];

var stopCols = [
  'stop.stop_id',
  'stop.stop_code',
  'stop.stop_name',
  'stop.stop_desc',
  'stop.stop_lat',
  'stop.stop_lon',
  'stop.zone_id',
  'stop.stop_url',
  'stop.location_type',
  'stop.parent_station',
  'stop.stop_timezone',
  'stop.wheelchair_boarding',
  'stop.platform_code'
];

var routeCols = [
  'route.id',
  'route.route_id',
  'route.route_short_name',
  'route.route_long_name',
  'route.route_desc',
  'route.route_type',
  'route.route_url',
  'route.route_color',
  'route.route_text_color',
  'agency.agency_id'
];

var tripCols = [
  'trip.id',
  'trip.trip_id',
  'trip.route_id',
  'trip.service_id',
  'trip.trip_headsign',
  'trip.trip_short_name',
  'trip.direction_id',
  'trip.block_id',
  'trip.shape_id',
  'trip.wheelchair_accessible',
  'trip.bikes_allowed'
];

// Helpers

function getAgencyId(knex, agencyKey) {
  return knex.select('id').from('agency_entry')
  .where({ agency_key: agencyKey });
}

function formatAgency(agency) {
  agency.id = undefined;
  agency.agency_entry_id = undefined;
  return formatRow(agency);
}

function formatRow(row) {
  row.created_at = undefined;
  row.updated_at = undefined;
  return row;
}

function getShapeSequences(knex, trips) {
  return knex.select(
    'shape_sequence.shape_id',
    'shape_sequence.shape_pt_lat',
    'shape_sequence.shape_pt_lon',
    'shape_sequence.shape_pt_sequence',
    'shape_sequence.shape_dist_traveled'
  ).from('shape_sequence').whereIn('shape_id', trips.map(function (x) { return x.shape_id; }))
  .then(combineShapes)
}

function getStops(knex, trips) {
  return knex.select(
    'stop_time.trip_id',
    'stop_time.arrival_time',
    'stop_time.departure_time',
    'stop_time.stop_sequence',
    'stop_time.stop_headsign',
    'stop_time.pickup_type',
    'stop_time.drop_off_type',
    'stop_time.shape_dist_traveled',
    'stop_time.timepoint',
    'stop.stop_id'
  ).from('stop_time').whereIn('stop_time.trip_id', trips.map(function (x) { return x.id; }))
  .leftJoin('stop', 'stop.id', 'stop_time.stop_id')
  .then(combineStops);
}

function combineShapes(shapeSequences) {

  var dict = shapeSequences.reduce(function (acc, row) {
    var d = acc[row.shape_id];
    if (!d) {
      d = [];
      acc[row.shape_id] = d;
    }
    // Insert sorted.
    var insertPos = d.length;
    for (var i = 0; i < d.length; i++) {
      if (d[i].shape_pt_sequence > row.shape_pt_sequence) {
        insertPos = i;
        break;
      }
    }
    d.splice(i, 0, row);
    return acc;
  }, {});

  // Remove redundant information.
  for (var key in dict) {
    var shapes = dict[key];
    dict[key] = shapes.map(function (s) {
      return {
        lat: s.shape_pt_lat,
        lon: s.shape_pt_lon,
        shape_dist_traveled: (s.shape_dist_traveled != null ? s.shape_dist_traveled : undefined)
      };
    });
  }
  return dict;
}

function combineStops(routeStops) {
  var dict = routeStops.reduce(function (acc, row) {
    var d = acc[row.trip_id];
    if (!d) {
      d = [];
      acc[row.trip_id] = d;
    }
    // Insert sorted.
    var insertPos = d.length;
    for (var i = 0; i < d.length; i++) {
      if (d[i].stop_sequence > row.stop_sequence) {
        insertPos = i;
        break;
      }
    }
    d.splice(i, 0, row);
    return acc;
  }, {});

  return dict;
}

module.exports = function createGTFSdb(knex) {
  var gtfsdb = new GTFSdb(knex);
  return gtfsdb;
};
<|endoftext|>


<commit_before>const { Minimatch } = require('minimatch')
const sm = require('sitemap')
const isHTTPS = require('is-https')
const { uniq } = require('lodash')
const path = require('path')
const fs = require('fs-extra')
const AsyncCache = require('async-cache')
const pify = require('pify')
const { hostname } = require('os')

// Defaults
const defaults = {
  path: '/sitemap.xml',
  hostname: null,
  generate: false,
  exclude: [],
  routes: [],
  cacheTime: 1000 * 60 * 15
}

module.exports = function nuxtSitemap (moduleOptions) {
  const options = Object.assign({}, defaults, this.options.sitemap, moduleOptions)

  // Static Routes
  const staticRoutesPromise = new Promise((resolve, reject) => {
    this.extendRoutes(routes => {
      // Map to path
      routes = routes.map(r => r.path)

      // Apply excludes
      options.exclude.forEach(pattern => {
        const minimatch = new Minimatch(pattern)
        minimatch.negate = true
        routes = routes.filter(route => minimatch.match(route))
      })
      resolve(routes)
    })
  })

  // Create a cache for routes
  const cache = new AsyncCache({
    maxAge: options.cacheTime,
    load (_, callback) {
      Promise.all([staticRoutesPromise, promisifyRoute(options.routes)])
        .then(sources => Array.prototype.concat.apply([], sources))
        .then(routes => uniq(routes))
        .then(routes => {
          callback(null, routes)
        })
        .catch(err => {
          callback(err)
        })
    }
  })
  cache.get = pify(cache.get)

  // sitemap.xml is written to static dir on generate mode
  const xmlGeneratePath = path.resolve(this.options.srcDir, 'static' + options.path)

  if (options.generate) {
    // Generate static sitemap.xml
    cache.get('routes')
      .then(routes => createSitemap(options, routes))
      .then(sitemap => sitemap.toXML())
      .then(xml => fs.writeFile(xmlGeneratePath, xml))
  }

  // Ensure no generated file exists
  fs.removeSync(xmlGeneratePath)

  // Add server middleware
  this.addServerMiddleware({
    path: options.path,
    handler (req, res, next) {
      cache.get('routes')
        .then(routes => createSitemap(options, routes, req))
        .then(sitemap => sitemap.toXML())
        .then(xml => {
          res.setHeader('Content-Type', 'application/xml')
          res.end(xml)
        }).catch(err => {
          next(err)
        })
    }
  })
}

// Initialize a fresh sitemap instance
function createSitemap (options, routes, req) {
  const sitemapConfig = {}

  // Set sitemap hostname
  sitemapConfig.hostname = options.hostname ||
    (req && `${isHTTPS(req) ? 'https' : 'http'}://${req.headers.host}`) || `http://${hostname()}`

  // Set urls and ensure they are unique
  sitemapConfig.urls = uniq(routes)

  // Set cacheTime
  sitemapConfig.cacheTime = options.cacheTime || 0

  // Create promisified instance and return
  const sitemap = sm.createSitemap(sitemapConfig)
  sitemap.toXML = pify(sitemap.toXML)

  return sitemap
}

// Borrowed from nuxt/common/utils
function promisifyRoute (fn) {
  // If routes is an array
  if (Array.isArray(fn)) {
    return Promise.resolve(fn)
  }
  // If routes is a function expecting a callback
  if (fn.length === 1) {
    return new Promise((resolve, reject) => {
      fn(function (err, routeParams) {
        if (err) {
          reject(err)
        }
        resolve(routeParams)
      })
    })
  }
  let promise = fn()
  if (!promise || (!(promise instanceof Promise) && (typeof promise.then !== 'function'))) {
    promise = Promise.resolve(promise)
  }
  return promise
}
<commit_msg>fix(sitemap): use path.join for static file path<commit_after>const { Minimatch } = require('minimatch')
const sm = require('sitemap')
const isHTTPS = require('is-https')
const { uniq } = require('lodash')
const path = require('path')
const fs = require('fs-extra')
const AsyncCache = require('async-cache')
const pify = require('pify')
const { hostname } = require('os')

// Defaults
const defaults = {
  path: '/sitemap.xml',
  hostname: null,
  generate: false,
  exclude: [],
  routes: [],
  cacheTime: 1000 * 60 * 15
}

module.exports = function nuxtSitemap (moduleOptions) {
  const options = Object.assign({}, defaults, this.options.sitemap, moduleOptions)

  // Static Routes
  const staticRoutesPromise = new Promise((resolve, reject) => {
    this.extendRoutes(routes => {
      // Map to path
      routes = routes.map(r => r.path)

      // Apply excludes
      options.exclude.forEach(pattern => {
        const minimatch = new Minimatch(pattern)
        minimatch.negate = true
        routes = routes.filter(route => minimatch.match(route))
      })
      resolve(routes)
    })
  })

  // Create a cache for routes
  const cache = new AsyncCache({
    maxAge: options.cacheTime,
    load (_, callback) {
      Promise.all([staticRoutesPromise, promisifyRoute(options.routes)])
        .then(sources => Array.prototype.concat.apply([], sources))
        .then(routes => uniq(routes))
        .then(routes => {
          callback(null, routes)
        })
        .catch(err => {
          callback(err)
        })
    }
  })
  cache.get = pify(cache.get)

  // sitemap.xml is written to static dir on generate mode
  const xmlGeneratePath = path.resolve(this.options.srcDir, path.join('static', options.path))

  if (options.generate) {
    // Generate static sitemap.xml
    cache.get('routes')
      .then(routes => createSitemap(options, routes))
      .then(sitemap => sitemap.toXML())
      .then(xml => fs.writeFile(xmlGeneratePath, xml))
  }

  // Ensure no generated file exists
  fs.removeSync(xmlGeneratePath)

  // Add server middleware
  this.addServerMiddleware({
    path: options.path,
    handler (req, res, next) {
      cache.get('routes')
        .then(routes => createSitemap(options, routes, req))
        .then(sitemap => sitemap.toXML())
        .then(xml => {
          res.setHeader('Content-Type', 'application/xml')
          res.end(xml)
        }).catch(err => {
          next(err)
        })
    }
  })
}

// Initialize a fresh sitemap instance
function createSitemap (options, routes, req) {
  const sitemapConfig = {}

  // Set sitemap hostname
  sitemapConfig.hostname = options.hostname ||
    (req && `${isHTTPS(req) ? 'https' : 'http'}://${req.headers.host}`) || `http://${hostname()}`

  // Set urls and ensure they are unique
  sitemapConfig.urls = uniq(routes)

  // Set cacheTime
  sitemapConfig.cacheTime = options.cacheTime || 0

  // Create promisified instance and return
  const sitemap = sm.createSitemap(sitemapConfig)
  sitemap.toXML = pify(sitemap.toXML)

  return sitemap
}

// Borrowed from nuxt/common/utils
function promisifyRoute (fn) {
  // If routes is an array
  if (Array.isArray(fn)) {
    return Promise.resolve(fn)
  }
  // If routes is a function expecting a callback
  if (fn.length === 1) {
    return new Promise((resolve, reject) => {
      fn(function (err, routeParams) {
        if (err) {
          reject(err)
        }
        resolve(routeParams)
      })
    })
  }
  let promise = fn()
  if (!promise || (!(promise instanceof Promise) && (typeof promise.then !== 'function'))) {
    promise = Promise.resolve(promise)
  }
  return promise
}
<|endoftext|>


<commit_before>/*
  backgrid
  http://github.com/wyuenho/backgrid

  Copyright (c) 2013 Jimmy Yuen Ho Wong and contributors
  Licensed under the MIT @license.
*/

/**
   A Footer is a generic class that only defines a default tag `tfoot` and
   number of required parameters in the initializer.

   @abstract
   @class Backgrid.Footer
   @extends Backbone.View
 */
var Footer = Backgrid.Footer = Backbone.View.extend({

  /** @property */
  tagName: "tfoot",

  /**
     Initializer.

     @param {Object} options
     @param {*} options.parent The parent view class of this footer.
     @param {Backbone.Collection.<Backgrid.Column>|Array.<Backgrid.Column>|Array.<Object>} options.columns
     Column metadata.
     @param {Backbone.Collection} options.collection

     @throws {TypeError} If options.columns or options.collection is undefined.
  */
  initialize: function (options) {
    Backgrid.requireOptions(options, ["columns", "collection"]);
    this.parent = options.parent;
    this.columns = options.columns;
    if (!(this.columns instanceof Backbone.Collection)) {
      this.columns = new Backgrid.Columns(this.columns);
    }
  }

});
<commit_msg>Remove extraneous parent reference from Footer<commit_after>/*
  backgrid
  http://github.com/wyuenho/backgrid

  Copyright (c) 2013 Jimmy Yuen Ho Wong and contributors
  Licensed under the MIT @license.
*/

/**
   A Footer is a generic class that only defines a default tag `tfoot` and
   number of required parameters in the initializer.

   @abstract
   @class Backgrid.Footer
   @extends Backbone.View
 */
var Footer = Backgrid.Footer = Backbone.View.extend({

  /** @property */
  tagName: "tfoot",

  /**
     Initializer.

     @param {Object} options
     @param {*} options.parent The parent view class of this footer.
     @param {Backbone.Collection.<Backgrid.Column>|Array.<Backgrid.Column>|Array.<Object>} options.columns
     Column metadata.
     @param {Backbone.Collection} options.collection

     @throws {TypeError} If options.columns or options.collection is undefined.
  */
  initialize: function (options) {
    Backgrid.requireOptions(options, ["columns", "collection"]);
    this.columns = options.columns;
    if (!(this.columns instanceof Backbone.Collection)) {
      this.columns = new Backgrid.Columns(this.columns);
    }
  }

});
<|endoftext|>


<commit_before>// ==========================================================================
//                          DG.CasePlotView
//
//  Author:   William Finzer
//
//  Copyright (c) 2014 by The Concord Consortium, 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.
// ==========================================================================

sc_require('components/graph/plots/plot_view');

/** @class DG.CasePlotView - A plot of dots placed according to numeric values

 @extends DG.PlotView
 */
DG.CasePlotView = DG.PlotView.extend(
  /** @scope DG.CasePlotView.prototype */
  {
    dataRangeDidChange: function( iSource, iQuestion, iKey, iChanges ) {
      var this_ = this,
          tPlotElementLength = this._plottedElements.length,
          tCases = this.getPath( 'model.cases'),
          tRC = this.createRenderContext();

      // iChanges can be a single index or an array of indices
      var tChanges = (SC.typeOf( iChanges ) === SC.T_NUMBER ? [ iChanges ] : iChanges);
      tChanges = tChanges || [];
      tChanges.forEach( function( iIndex ) {
        if( iIndex >= tPlotElementLength )
          this_.callCreateCircle( tCases[ iIndex], iIndex, this_._createAnimationOn );
        this_.setCircleCoordinate( tRC, tCases[ iIndex], iIndex );
      } );
      sc_super();
    },

    /**
     * Set the coordinates and other attributes of the case circle (a Rafael element in this._plottedElements).
     * @param iRC {} case-invariant Render Context
     * @param iCase {DG.Case} the case data
     * @param iIndex {number} index of case in collection
     * @param iAnimate {Boolean} (optional) want changes to be animated into place?
     * @param iCallback {Function} Will be called when animation finished
     * @returns {cx {Number},cy {Number}} final coordinates or null if not defined (hidden plot element)
     */
    setCircleCoordinate: function setCircleCoordinate( iRC, iCase, iIndex, iAnimate, iCallback ) {
      DG.assert( iRC && iRC.xAxisView );
      DG.assert( iCase );
      DG.assert( DG.MathUtilities.isInIntegerRange( iIndex, 0, this._plottedElements.length ));

      function dataToCoordinateWithMargin( iAxisView, iData, iMargin ) {
        // position icons in view, with margin to prevent circle edge from being clipped.
        // compare to DG.AxisView.dataToCoordinate().
        var tPixelMin = iAxisView.get('pixelMin'),
            tPixelMax = iAxisView.get('pixelMax');
        if( tPixelMin < tPixelMax )
          return tPixelMin + iMargin + iData * (tPixelMax - tPixelMin - 2*iMargin);
        else
          return tPixelMin - iMargin + iData * (tPixelMax - tPixelMin + 2*iMargin);
      }

      var tCircle = this._plottedElements[ iIndex],
          tRadius = this._pointRadius,
          tWorldCoords = this.get( 'model' ).getWorldCoords( iIndex ),
          tCoordX = dataToCoordinateWithMargin( iRC.xAxisView, tWorldCoords.x, tRadius ),
          tCoordY = dataToCoordinateWithMargin( iRC.yAxisView, tWorldCoords.y, tRadius ),
          tIsMissingCase = SC.none(tCoordX) || SC.none(tCoordY);

      // show or hide if needed, then update if shown.
      if( this.showHidePlottedElement( tCircle, tIsMissingCase)) {
        this.updatePlottedElement( tCircle, tCoordX, tCoordY, tRadius, iRC.calcCaseColorString( iCase ),
          iAnimate, iCallback);
        return { cx: tCoordX, cy: tCoordY, r: tRadius };
      }
      return null;
    },

    createCircle: function ( iDatum, iIndex, iAnimate ) {
      var this_ = this;

      function changeCaseValues( iIndex, iWorldValues) {
        this_.get('model').setWorldCoords( iIndex, iWorldValues);
      }

      var tIsDragging = false,
          kOpaque = 1,
          tInitialTransform = null,
          tCircle = this.get('paper').circle( -100, -100, this._pointRadius )
            .attr( { cursor: "pointer" } )
            .addClass( DG.PlotUtilities.kColoredDotClassName )
            .hover( function ( event ) {  // over
              // Note that Firefox can come through here repeatedly so we have to check for existence
              if( !tIsDragging && SC.none( tInitialTransform)) {
                tInitialTransform = this.transform();
                this.animate( { opacity: kOpaque, transform: DG.PlotUtilities.kDataHoverTransform }, DG.PlotUtilities.kDataTipShowTime );
              }
            },
            function( event ) { // out
              if( !tIsDragging ) {
                this.stop();
                this.animate( {transform: tInitialTransform }, DG.PlotUtilities.kHighlightHideTime );
                tInitialTransform = null;
              }
            } )
            .mousedown( function( iEvent) {
              this_.get( 'model' ).selectCaseByIndex( iIndex, iEvent.shiftKey);
            } )
          .drag(function (dx, dy) { // continue
                // TODO: drag all selected cases, not just this case.
                var tWorldX = this_.get('xAxisView').coordinateToData( this.ox + dx),
                    tWorldY = this_.get('yAxisView').coordinateToData( this.oy + dy),
                    tPoint = { x: tWorldX, y: tWorldY },
                    tRC = this_.createRenderContext(),
                    tCurrTransform = this.transform();
                if( isFinite( tPoint.x) && isFinite( tPoint.y)) {
                  // Put the element into the initial transformed state so that changing case values
                  // will not be affected by the scaling in the current transform.
                  this.transform( tInitialTransform);
                  changeCaseValues( this.index, tPoint);
                  this.transform( tCurrTransform);
                }
                this_.setCircleCoordinate( tRC, this_.getPath('model.cases')[ this.index], this.index);
              },
              function (x, y) { // begin
                tIsDragging = true;
                this.ox = this.attr("cx");
                this.oy = this.attr("cy");
                this.animate({opacity: kOpaque }, DG.PlotUtilities.kDataTipShowTime, "bounce");
                this.toFront();
              },
              function() {  // end
                this.animate( {transform: tInitialTransform }, DG.PlotUtilities.kHighlightHideTime);
                tIsDragging = false;
              })
          ;
      //if( iIndex % 100 === 0 ) DG.logTimer( iIndex===0, "CreateCircle index="+iIndex );
      tCircle.index = iIndex;
      tCircle.node.setAttribute( 'shape-rendering', 'geometric-precision' );
      if( iAnimate)
        DG.PlotUtilities.doCreateCircleAnimation( tCircle);
      return tCircle;
    },

    /**
     We may clear and draw everything from scratch if required.
     */
    drawData: function() {
      if( this.getPath( 'model.isAnimating' ) )
        return; // Points are animating to new position

      if( !SC.none( this.get( 'transferredPointCoordinates' ) ) ) {
        this.animateFromTransferredPoints();
        return;
      }

      var this_ = this,
          tCases = this.getPath( 'model.cases' ),
          tRC = this.createRenderContext(),
          tIndex;

      if( this._mustCreatePlottedElements ) {
        this._plottedElements.forEach( function( iElement ) {
          iElement.remove();
        } );
        this._plottedElements.length = 0;

        this._pointRadius = this.calcPointRadius(); // make sure created circles are of right size
        tCases.forEach( this.callCreateCircle, this );
        this._mustCreatePlottedElements = false;
      }

      tCases.forEach( function( iCase, iIndex ) {
        this_.setCircleCoordinate( tRC, iCase, iIndex );
      } );

      // Get rid of any extra circles
      for( tIndex = tCases.length; tIndex < this._plottedElements.length; tIndex++ ) {
        this._plottedElements[ tIndex].remove();
      }
      this._plottedElements.length = tCases.length;
    },

    /**
     Generate the svg needed to display the plot
     */
    doDraw: function doDraw() {
      sc_super();

      this.drawData();

      this.updateSelection();

    },

    /**
     * The array object my model uses to store world coords has been swapped out. We want to animate to new positions.
     */
    worldValuesChanged: function() {
      this.prepareForConfigurationChange();
      this.set('transferredPointCoordinates', this.get('cachedPointCoordinates'));
      this._isRenderingValid = false;
      this.displayDidChange();
    }.observes( '.model.worldValues')

  } );

<commit_msg>Add explosion of dots animation in initial creation of plot.<commit_after>// ==========================================================================
//                          DG.CasePlotView
//
//  Author:   William Finzer
//
//  Copyright (c) 2014 by The Concord Consortium, 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.
// ==========================================================================

sc_require('components/graph/plots/plot_view');

/** @class DG.CasePlotView - A plot of dots placed according to numeric values

 @extends DG.PlotView
 */
DG.CasePlotView = DG.PlotView.extend(
  /** @scope DG.CasePlotView.prototype */
  {
    dataRangeDidChange: function( iSource, iQuestion, iKey, iChanges ) {
      var this_ = this,
          tPlotElementLength = this._plottedElements.length,
          tCases = this.getPath( 'model.cases'),
          tRC = this.createRenderContext();

      // iChanges can be a single index or an array of indices
      var tChanges = (SC.typeOf( iChanges ) === SC.T_NUMBER ? [ iChanges ] : iChanges);
      tChanges = tChanges || [];
      tChanges.forEach( function( iIndex ) {
        if( iIndex >= tPlotElementLength )
          this_.callCreateCircle( tCases[ iIndex], iIndex, this_._createAnimationOn );
        this_.setCircleCoordinate( tRC, tCases[ iIndex], iIndex );
      } );
      sc_super();
    },

    /**
     * Set the coordinates and other attributes of the case circle (a Rafael element in this._plottedElements).
     * @param iRC {} case-invariant Render Context
     * @param iCase {DG.Case} the case data
     * @param iIndex {number} index of case in collection
     * @param iAnimate {Boolean} (optional) want changes to be animated into place?
     * @param iCallback {Function} Will be called when animation finished
     * @returns {cx {Number},cy {Number}} final coordinates or null if not defined (hidden plot element)
     */
    setCircleCoordinate: function setCircleCoordinate( iRC, iCase, iIndex, iAnimate, iCallback ) {
      DG.assert( iRC && iRC.xAxisView );
      DG.assert( iCase );
      DG.assert( DG.MathUtilities.isInIntegerRange( iIndex, 0, this._plottedElements.length ));

      function dataToCoordinateWithMargin( iAxisView, iData, iMargin ) {
        // position icons in view, with margin to prevent circle edge from being clipped.
        // compare to DG.AxisView.dataToCoordinate().
        var tPixelMin = iAxisView.get('pixelMin'),
            tPixelMax = iAxisView.get('pixelMax');
        if( tPixelMin < tPixelMax )
          return tPixelMin + iMargin + iData * (tPixelMax - tPixelMin - 2*iMargin);
        else
          return tPixelMin - iMargin + iData * (tPixelMax - tPixelMin + 2*iMargin);
      }

      var tCircle = this._plottedElements[ iIndex],
          tRadius = this._pointRadius,
          tWorldCoords = this.get( 'model' ).getWorldCoords( iIndex ),
          tCoordX = dataToCoordinateWithMargin( iRC.xAxisView, tWorldCoords.x, tRadius ),
          tCoordY = dataToCoordinateWithMargin( iRC.yAxisView, tWorldCoords.y, tRadius ),
          tIsMissingCase = SC.none(tCoordX) || SC.none(tCoordY);

      // show or hide if needed, then update if shown.
      if( this.showHidePlottedElement( tCircle, tIsMissingCase)) {
        this.updatePlottedElement( tCircle, tCoordX, tCoordY, tRadius, iRC.calcCaseColorString( iCase ),
          iAnimate, iCallback);
        return { cx: tCoordX, cy: tCoordY, r: tRadius };
      }
      return null;
    },

    createCircle: function ( iDatum, iIndex, iAnimate ) {
      var this_ = this;

      function changeCaseValues( iIndex, iWorldValues) {
        this_.get('model').setWorldCoords( iIndex, iWorldValues);
      }

      var tIsDragging = false,
          kOpaque = 1,
          tInitialTransform = null,
          tPaper = this.get('paper'),
          tCircle = tPaper.circle( tPaper.width / 2, tPaper.height / 2, this._pointRadius )
            .attr( { cursor: "pointer" } )
            .addClass( DG.PlotUtilities.kColoredDotClassName )
            .hover( function ( event ) {  // over
              // Note that Firefox can come through here repeatedly so we have to check for existence
              if( !tIsDragging && SC.none( tInitialTransform)) {
                tInitialTransform = this.transform();
                this.animate( { opacity: kOpaque, transform: DG.PlotUtilities.kDataHoverTransform }, DG.PlotUtilities.kDataTipShowTime );
              }
            },
            function( event ) { // out
              if( !tIsDragging ) {
                this.stop();
                this.animate( {transform: tInitialTransform }, DG.PlotUtilities.kHighlightHideTime );
                tInitialTransform = null;
              }
            } )
            .mousedown( function( iEvent) {
              this_.get( 'model' ).selectCaseByIndex( iIndex, iEvent.shiftKey);
            } )
          .drag(function (dx, dy) { // continue
                // TODO: drag all selected cases, not just this case.
                var tWorldX = this_.get('xAxisView').coordinateToData( this.ox + dx),
                    tWorldY = this_.get('yAxisView').coordinateToData( this.oy + dy),
                    tPoint = { x: tWorldX, y: tWorldY },
                    tRC = this_.createRenderContext(),
                    tCurrTransform = this.transform();
                if( isFinite( tPoint.x) && isFinite( tPoint.y)) {
                  // Put the element into the initial transformed state so that changing case values
                  // will not be affected by the scaling in the current transform.
                  this.transform( tInitialTransform);
                  changeCaseValues( this.index, tPoint);
                  this.transform( tCurrTransform);
                }
                this_.setCircleCoordinate( tRC, this_.getPath('model.cases')[ this.index], this.index);
              },
              function (x, y) { // begin
                tIsDragging = true;
                this.ox = this.attr("cx");
                this.oy = this.attr("cy");
                this.animate({opacity: kOpaque }, DG.PlotUtilities.kDataTipShowTime, "bounce");
                this.toFront();
              },
              function() {  // end
                this.animate( {transform: tInitialTransform }, DG.PlotUtilities.kHighlightHideTime);
                tIsDragging = false;
              })
          ;
      //if( iIndex % 100 === 0 ) DG.logTimer( iIndex===0, "CreateCircle index="+iIndex );
      tCircle.index = iIndex;
      tCircle.node.setAttribute( 'shape-rendering', 'geometric-precision' );
      return tCircle;
    },

    /**
     We may clear and draw everything from scratch if required.
     */
    drawData: function() {
      if( this.getPath( 'model.isAnimating' ) )
        return; // Points are animating to new position

      if( !SC.none( this.get( 'transferredPointCoordinates' ) ) ) {
        this.animateFromTransferredPoints();
        return;
      }

      var this_ = this,
          tCases = this.getPath( 'model.cases' ),
          tRC = this.createRenderContext(),
          tIndex;

      if( this._mustCreatePlottedElements ) {
        this._plottedElements.forEach( function( iElement ) {
          iElement.remove();
        } );
        this._plottedElements.length = 0;

        this._pointRadius = this.calcPointRadius(); // make sure created circles are of right size
        tCases.forEach( this.callCreateCircle, this );
        this._mustCreatePlottedElements = false;
        this.worldValuesChanged();  // Initial animation from center of plot to random points
      }

      tCases.forEach( function( iCase, iIndex ) {
        this_.setCircleCoordinate( tRC, iCase, iIndex );
      } );

      // Get rid of any extra circles
      for( tIndex = tCases.length; tIndex < this._plottedElements.length; tIndex++ ) {
        this._plottedElements[ tIndex].remove();
      }
      this._plottedElements.length = tCases.length;
    },

    /**
     Generate the svg needed to display the plot
     */
    doDraw: function doDraw() {
      sc_super();

      this.drawData();

      this.updateSelection();

    },

    /**
     * The array object my model uses to store world coords has been swapped out. We want to animate to new positions.
     */
    worldValuesChanged: function() {
      this.prepareForConfigurationChange();
      this.set('transferredPointCoordinates', this.get('cachedPointCoordinates'));
      this._isRenderingValid = false;
      this.displayDidChange();
    }.observes( '.model.worldValues')

  } );

<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import uuid from 'uuid';
import _ from 'lodash';
// eslint-disable-next-line import/no-extraneous-dependencies
import moment from 'moment';
import {
  Callout,
  ConfirmationModal,
} from '@folio/stripes/components';
import {
  FormattedMessage,
  intlShape,
  injectIntl
} from 'react-intl';
import SafeHTMLMessage from '@folio/react-intl-safe-html';
import ChargeForm from './ChargeForm';
import ItemLookup from './ItemLookup';
import ActionModal from '../Actions/ActionModal';
import { getFullName } from '../../util';
import { loadServicePoints } from '../accountFunctions';

class ChargeFeeFine extends React.Component {
  static propTypes = {
    resources: PropTypes.shape({
      feefines: PropTypes.shape({
        records: PropTypes.arrayOf(PropTypes.object),
      }),
      owners: PropTypes.shape({
        records: PropTypes.arrayOf(PropTypes.object),
      }),
      activeRecord: PropTypes.object,
    }).isRequired,
    mutator: PropTypes.shape({
      accounts: PropTypes.shape({
        POST: PropTypes.func.isRequired,
        PUT: PropTypes.func.isRequired,
      }),
      feefineactions: PropTypes.shape({
        POST: PropTypes.func.isRequired,
      }),
      activeRecord: PropTypes.shape({
        update: PropTypes.func,
      }),
      account: PropTypes.shape({
        GET: PropTypes.func,
      }),
    }).isRequired,
    stripes: PropTypes.object.isRequired,

    okapi: PropTypes.object,
    selectedLoan: PropTypes.object,
    user: PropTypes.object,
    intl: intlShape.isRequired,
    history: PropTypes.object,
    location: PropTypes.object,
    match: PropTypes.object,
  };

  constructor(props) {
    super(props);
    this.state = {
      ownerId: '0',
      lookup: false,
      pay: false,
      showConfirmDialog: false,
    };
    this.onClickCharge = this.onClickCharge.bind(this);
    this.onClickSelectItem = this.onClickSelectItem.bind(this);
    this.onChangeOwner = this.onChangeOwner.bind(this);
    this.onFindShared = this.onFindShared.bind(this);
    this.item = {};
    this.onCloseModal = this.onCloseModal.bind(this);
    this.onChangeItem = this.onChangeItem.bind(this);
    this.onClosePayModal = this.onClosePayModal.bind(this);
    this.onClickPay = this.onClickPay.bind(this);
    this.type = {};
    this.callout = null;
  }

  shouldComponentUpdate(nextProps) {
    const items = _.get(this.props.resources, ['items', 'records'], []);
    const nextItems = _.get(nextProps.resources, ['items', 'records'], []);
    const barcode = _.get(this.props.resources, ['activeRecord', 'barcode']);
    if (nextItems.length === 1 && barcode !== null) {
      if (nextItems[0].barcode === barcode) this.item = nextItems[0];
    }

    if (items !== nextItems) {
      this.setState({
        lookup: true,
      });
    }

    return true;
  }

  componentWillUnmount() {
    this.item = {};
    this.props.mutator.activeRecord.update({ barcode: null });
  }

  onClickCharge(type) {
    const owners = _.get(this.props.resources, ['owners', 'records'], []);
    const feefines = _.get(this.props.resources, ['feefines', 'records'], []);
    const selectedLoan = this.props.selectedLoan || {};

    const { intl: { formatMessage } } = this.props;
    const item = (selectedLoan.id) ? selectedLoan.item : this.item;

    type.paymentStatus = {
      name: 'Outstanding',
    };
    type.status = {
      name: 'Open',
    };
    type.remaining = type.amount;
    type.feeFineType = (feefines.find(f => f.id === type.feeFineId) || {}).feeFineType || '';
    type.feeFineOwner = (owners.find(o => o.id === type.ownerId) || {}).owner || '';
    type.title = item.title;
    type.barcode = item.barcode;
    type.callNumber = item.callNumber;
    type.location = (selectedLoan.id) ? (item.location || {}).name : (item.effectiveLocation || {}).name;
    type.materialType = (item.materialType || {}).name;
    type.materialTypeId = (selectedLoan.id) ? '0' : (item.materialType || {}).id || '0';

    if (selectedLoan.dueDate) type.dueDate = selectedLoan.dueDate;
    if (selectedLoan.returnDate) type.returnedDate = selectedLoan.returnDate;
    type.id = uuid();
    type.loanId = selectedLoan.id || '0';
    type.userId = this.props.user.id;
    type.itemId = this.item.id || '0';
    let commentInfo = '';
    const tagStaff = formatMessage({ id: 'ui-users.accounts.actions.tag.staff' });
    const tagPatron = formatMessage({ id: 'ui-users.accounts.actions.tag.patron' });
    if (type.comments) {
      commentInfo = `${tagStaff} : ${type.comments}`;
    }
    if (type.patronInfo && type.notify) {
      commentInfo = `${commentInfo} \n ${tagPatron} : ${type.patronInfo}`;
    }

    delete type.comments;
    delete type.notify;
    delete type.patronInfo;

    return this.props.mutator.accounts.POST(type)
      .then(() => this.newAction({}, type.id, type.feeFineType, type.amount, commentInfo, type.remaining, 0, type.feeFineOwner));
  }

  newAction = (action, id, typeAction, amount, comment, balance, transaction, createdAt) => {
    const path = `accounts/${this.type.id}`;

    return this.props.mutator.account.GET({ path }).then(record => {
      const dateAction = _.get(record, ['metadata', 'updatedDate'], moment().format());

      const newAction = {
        typeAction,
        source: `${this.props.okapi.currentUser.lastName}, ${this.props.okapi.currentUser.firstName}`,
        createdAt,
        accountId: id,
        dateAction,
        userId: this.props.user.id,
        amountAction: parseFloat(amount || 0).toFixed(2),
        balance: parseFloat(balance || 0).toFixed(2),
        transactionInformation: transaction || '-',
        comments: comment,
      };
      this.props.mutator.feefineactions.POST(Object.assign(action, newAction));
    });
  }

  onClickPay(type) {
    this.type = type;
    this.type.remaining = type.amount;
    this.setState({
      pay: true,
    });
    return new Promise((resolve, reject) => {
      this.payResolve = resolve;
      this.payReject = reject;
    });
  }

  onClosePayModal() {
    this.setState({
      pay: false,
    });
  }

  onClickSelectItem(barcode) {
    if (barcode !== '') {
      this.props.mutator.activeRecord.update({ barcode });
      if ((this.props.resources.activeRecord || {}).barcode === barcode) {
        this.setState({
          lookup: true,
        });
      }
    }
  }

  onChangeOwner(e) {
    const ownerId = e.target.value;
    if (_.get(this.props.resources, ['activeRecord', 'shared']) === undefined) {
      const owners = _.get(this.props.resources, ['owners', 'records'], []);
      const shared = (owners.find(o => o.owner === 'Shared') || {}).id || '0';
      this.props.mutator.activeRecord.update({ shared });
    }
    this.props.mutator.activeRecord.update({ ownerId });
    this.setState({
      ownerId,
    });
  }

  onChangeItem(item) {
    this.item = item;
  }

  onFindShared(id) {
    this.props.mutator.activeRecord.update({ shared: id });
  }

  onCloseModal() {
    this.setState({
      lookup: false,
    });
  }

  showCalloutMessage(a) {
    const message =

        <FormattedMessage id="ui-users.charge.messageThe" />
        {a.feeFineType}
        <FormattedMessage id="ui-users.charge.messageOf" />
        {`${parseFloat(a.amount).toFixed(2)}`}
        <FormattedMessage id="ui-users.charge.messageSuccessfully" />
        {(a.paymentStatus.name).toLowerCase()}
        <FormattedMessage id="ui-users.charge.messageFor" />
        {`${getFullName(this.props.user)}`}
      ;
    this.callout.sendCallout({ message });
  }

  showConfirmDialog = (values) => {
    this.setState({
      showConfirmDialog: true,
      values
    });

    return new Promise((resolve, reject) => {
      this.actionResolve = resolve;
      this.actionReject = reject;
    });
  }

  hideConfirmDialog = () => {
    this.setState({
      showConfirmDialog: false,
      values: {}
    });
  }

  onConfirm = () => {
    const { values } = this.state;
    const { intl: { formatMessage } } = this.props;
    const tagStaff = formatMessage({ id: 'ui-users.accounts.actions.tag.staff' });
    const tagPatron = formatMessage({ id: 'ui-users.accounts.actions.tag.patron' });
    let comment = '';
    if (values.comment) {
      comment = `${tagStaff} : ${values.comment}`;
    }
    if (values.patronInfo && values.notify) {
      comment = `${comment} \n ${tagPatron} : ${values.patronInfo}`;
    }
    this.onClickCharge(this.type).then(() => {
      this.type.remaining = parseFloat(this.type.amount - values.amount).toFixed(2);
      let paymentStatus = _.capitalize(formatMessage({ id: 'ui-users.accounts.actions.warning.paymentAction' }));
      if (this.type.remaining === '0.00') {
        paymentStatus = `${paymentStatus} ${formatMessage({ id: 'ui-users.accounts.status.fully' })}`;
        this.type.status.name = 'Closed';
      } else {
        paymentStatus = `${paymentStatus} ${formatMessage({ id: 'ui-users.accounts.status.partially' })}`;
      }
      this.type.paymentStatus.name = paymentStatus;
      this.props.mutator.activeRecord.update({ id: this.type.id });
      return this.props.mutator.accounts.PUT(this.type);
    })
      .then(() => this.newAction({ paymentMethod: values.method }, this.type.id,
        this.type.paymentStatus.name, values.amount,
        comment, this.type.remaining,
        values.transaction, this.type.feeFineOwner))
      .then(() => {
        this.hideConfirmDialog();
        this.onClosePayModal();
        this.showCalloutMessage(this.type);
        this.payResolve();
      })
      .then(() => { this.props.history.goBack(); });
  }

  renderConfirmMessage = () => {
    const { intl: { formatMessage } } = this.props;
    const values = this.state.values || {};
    const type = this.type || {};
    const amount = parseFloat(values.amount || 0).toFixed(2);
    let paymentStatus = formatMessage({ id: 'ui-users.accounts.actions.warning.paymentAction' });
    paymentStatus = `${(parseFloat(values.amount) !== parseFloat(type.amount)
      ? formatMessage({ id: 'ui-users.accounts.status.partially' })
      : formatMessage({ id: 'ui-users.accounts.status.fully' }))} ${paymentStatus}`;
    return (
      <SafeHTMLMessage
        id="ui-users.accounts.confirmation.message"
        values={{ count: 1, amount, action: paymentStatus }}
      />
    );
  }

  onSubmitCharge = (data) => {
    const {
      history
    } = this.props;
    if (data.pay) {
      delete data.pay;
      this.type.remaining = data.amount;
      this.onClickPay(data);
    } else {
      delete data.pay;
      this.onClickCharge(data)
        .then(() => { history.goBack(); });
    }
  }

  render() {
    const {
      resources,
      user,
      stripes,
      location,
      history,
      intl,
      match: {
        params: { loanid },
      },
    } = this.props;
    this.item = _.get(resources, ['items', 'records', [0]], {});
    const allfeefines = _.get(resources, ['allfeefines', 'records'], []);
    const owners = _.get(resources, ['owners', 'records'], []);
    const list = [];
    const shared = owners.find(o => o.owner === 'Shared');
    allfeefines.forEach(f => {
      if (!list.find(o => (o || {}).id === f.ownerId)) {
        const owner = owners.find(o => (o || {}).id === f.ownerId);
        if (owner !== undefined) { list.push(owner); }
      }
    });
    const feefines = (this.state.ownerId !== '0') ? (resources.feefines || {}).records || [] : [];
    const payments = _.get(resources, ['payments', 'records'], []).filter(p => p.ownerId === this.state.ownerId);
    const accounts = _.get(resources, ['accounts', 'records'], []);
    const settings = _.get(this.props.resources, ['commentRequired', 'records', 0], {});
    const barcode = _.get(this.props.resources, 'activeRecord.barcode');

    const defaultServicePointId = _.get(resources, ['curUserServicePoint', 'records', 0, 'defaultServicePointId'], '-');
    const servicePointsIds = _.get(resources, ['curUserServicePoint', 'records', 0, 'servicePointsIds'], []);

    let selected = parseFloat(0);
    accounts.forEach(a => {
      selected += parseFloat(a.remaining);
    });
    parseFloat(selected).toFixed(2);
    let item;

    if (this.item && (loanid || barcode)) {
      item = {
        id: this.item.id || '',
        instance: this.item.title || '',
        barcode: this.item.barcode || '',
        itemStatus: (this.item.status || {}).name || '',
        callNumber: this.item.callNumber || '',
        location: (this.item.effectiveLocation || {}).name || '',
        type: (this.item.materialType || {}).name || '',
      };
    }

    const isPending = {
      owners: _.get(resources, ['owners', 'isPending'], false),
      feefines: _.get(resources, ['feefines', 'isPending'], false),
      servicePoints: _.get(resources, ['curUserServicePoint', 'isPending'], true)
    };

    const items = _.get(resources, ['items', 'records'], []);
    const ownerId = loadServicePoints({ owners: (shared ? owners : list), defaultServicePointId, servicePointsIds });
    const initialValues = { amount: this.type.amount, notify: true, ownerId };

    return (

        <ChargeForm
          onClickPay={this.onClickPay}
          defaultServicePointId={defaultServicePointId}
          servicePointsIds={servicePointsIds}
          onSubmit={this.onSubmitCharge}
          user={user}
          ownerList={(shared) ? owners : list}
          owners={owners}
          isPending={isPending}
          ownerId={this.state.ownerId}
          feefines={feefines}
          item={item}
          onFindShared={this.onFindShared}
          onChangeOwner={this.onChangeOwner}
          onClickSelectItem={this.onClickSelectItem}
          stripes={stripes}
          location={location}
          history={history}
          {...this.props}
        />
        <ItemLookup
          resources={resources}
          items={items}
          open={(this.state.lookup && items.length > 1)}
          onChangeItem={this.onChangeItem}
          onClose={this.onCloseModal}
        />
        <ActionModal
          intl={intl}
          action="payment"
          form="payment-modals"
          label="nameMethod"
          initialValues={initialValues}
          open={this.state.pay}
          commentRequired={settings.paid}
          onClose={this.onClosePayModal}
          accounts={[this.type]}
          balance={this.type.amount}
          data={payments}
          stripes={stripes}
          onSubmit={(values) => { this.showConfirmDialog(values); }}
          owners={owners}
          feefines={feefines}
        />
        <Callout ref={(ref) => { this.callout = ref; }} />
        <ConfirmationModal
          open={this.state.showConfirmDialog}
          heading={<FormattedMessage id="ui-users.accounts.confirmation.head" values={{ action: 'payment' }} />}
          message={this.renderConfirmMessage()}
          onConfirm={this.onConfirm}
          onCancel={this.hideConfirmDialog}
          cancelLabel={<FormattedMessage id="ui-users.accounts.cancellation.field.back" />}
          confirmLabel={<FormattedMessage id="ui-users.accounts.cancellation.field.confirm" />}
        />

    );
  }
}

export default injectIntl(ChargeFeeFine);
<commit_msg>UIU-1246: Remove changes from another branch<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import uuid from 'uuid';
import _ from 'lodash';
// eslint-disable-next-line import/no-extraneous-dependencies
import moment from 'moment';
import {
  Callout,
  ConfirmationModal,
} from '@folio/stripes/components';
import {
  FormattedMessage,
  intlShape,
  injectIntl
} from 'react-intl';
import SafeHTMLMessage from '@folio/react-intl-safe-html';
import ChargeForm from './ChargeForm';
import ItemLookup from './ItemLookup';
import ActionModal from '../Actions/ActionModal';
import { getFullName } from '../../util';
import { loadServicePoints } from '../accountFunctions';

class ChargeFeeFine extends React.Component {
  static propTypes = {
    resources: PropTypes.shape({
      feefines: PropTypes.shape({
        records: PropTypes.arrayOf(PropTypes.object),
      }),
      owners: PropTypes.shape({
        records: PropTypes.arrayOf(PropTypes.object),
      }),
      activeRecord: PropTypes.object,
    }).isRequired,
    mutator: PropTypes.shape({
      accounts: PropTypes.shape({
        POST: PropTypes.func.isRequired,
        PUT: PropTypes.func.isRequired,
      }),
      feefineactions: PropTypes.shape({
        POST: PropTypes.func.isRequired,
      }),
      activeRecord: PropTypes.shape({
        update: PropTypes.func,
      }),
      account: PropTypes.shape({
        GET: PropTypes.func,
      }),
    }).isRequired,
    stripes: PropTypes.object.isRequired,

    okapi: PropTypes.object,
    selectedLoan: PropTypes.object,
    user: PropTypes.object,
    intl: intlShape.isRequired,
    history: PropTypes.object,
    location: PropTypes.object,
    match: PropTypes.object,
  };

  constructor(props) {
    super(props);
    this.state = {
      ownerId: '0',
      lookup: false,
      pay: false,
      showConfirmDialog: false,
    };
    this.onClickCharge = this.onClickCharge.bind(this);
    this.onClickSelectItem = this.onClickSelectItem.bind(this);
    this.onChangeOwner = this.onChangeOwner.bind(this);
    this.onFindShared = this.onFindShared.bind(this);
    this.item = {};
    this.onCloseModal = this.onCloseModal.bind(this);
    this.onChangeItem = this.onChangeItem.bind(this);
    this.onClosePayModal = this.onClosePayModal.bind(this);
    this.onClickPay = this.onClickPay.bind(this);
    this.type = {};
    this.callout = null;
  }

  shouldComponentUpdate(nextProps) {
    const items = _.get(this.props.resources, ['items', 'records'], []);
    const nextItems = _.get(nextProps.resources, ['items', 'records'], []);
    const barcode = _.get(this.props.resources, ['activeRecord', 'barcode']);
    if (nextItems.length === 1 && barcode !== null) {
      if (nextItems[0].barcode === barcode) this.item = nextItems[0];
    }

    if (items !== nextItems) {
      this.setState({
        lookup: true,
      });
    }

    return true;
  }

  componentWillUnmount() {
    this.item = {};
    this.props.mutator.activeRecord.update({ barcode: null });
  }

  onClickCharge(type) {
    const owners = _.get(this.props.resources, ['owners', 'records'], []);
    const feefines = _.get(this.props.resources, ['feefines', 'records'], []);
    const selectedLoan = this.props.selectedLoan || {};

    const { intl: { formatMessage } } = this.props;
    const item = (selectedLoan.id) ? selectedLoan.item : this.item;

    type.paymentStatus = {
      name: 'Outstanding',
    };
    type.status = {
      name: 'Open',
    };
    type.remaining = type.amount;
    type.feeFineType = (feefines.find(f => f.id === type.feeFineId) || {}).feeFineType || '';
    type.feeFineOwner = (owners.find(o => o.id === type.ownerId) || {}).owner || '';
    type.title = item.title;
    type.barcode = item.barcode;
    type.callNumber = item.callNumber;
    type.location = (selectedLoan.id) ? (item.location || {}).name : (item.effectiveLocation || {}).name;
    type.materialType = (item.materialType || {}).name;
    type.materialTypeId = (selectedLoan.id) ? '0' : (item.materialType || {}).id || '0';

    if (selectedLoan.dueDate) type.dueDate = selectedLoan.dueDate;
    if (selectedLoan.returnDate) type.returnedDate = selectedLoan.returnDate;
    type.id = uuid();
    type.loanId = selectedLoan.id || '0';
    type.userId = this.props.user.id;
    type.itemId = this.item.id || '0';
    let commentInfo = '';
    const tagStaff = formatMessage({ id: 'ui-users.accounts.actions.tag.staff' });
    const tagPatron = formatMessage({ id: 'ui-users.accounts.actions.tag.patron' });
    if (type.comments) {
      commentInfo = `${tagStaff} : ${type.comments}`;
    }
    if (type.patronInfo && type.notify) {
      commentInfo = `${commentInfo} \n ${tagPatron} : ${type.patronInfo}`;
    }
    delete type.comments;
    delete type.notify;
    delete type.patronInfo;
    return this.props.mutator.accounts.POST(type)
      .then(() => this.newAction({}, type.id, type.feeFineType, type.amount, commentInfo, type.remaining, 0, type.feeFineOwner));
  }

  newAction = (action, id, typeAction, amount, comment, balance, transaction, createdAt) => {
    const path = `accounts/${this.type.id}`;
    return this.props.mutator.account.GET({ path }).then(record => {
      const dateAction = _.get(record, ['metadata', 'updatedDate'], moment().format());

      const newAction = {
        typeAction,
        source: `${this.props.okapi.currentUser.lastName}, ${this.props.okapi.currentUser.firstName}`,
        createdAt,
        accountId: id,
        dateAction,
        userId: this.props.user.id,
        amountAction: parseFloat(amount || 0).toFixed(2),
        balance: parseFloat(balance || 0).toFixed(2),
        transactionInformation: transaction || '-',
        comments: comment,
      };
      this.props.mutator.feefineactions.POST(Object.assign(action, newAction));
    });
  }

  onClickPay(type) {
    this.type = type;
    this.type.remaining = type.amount;
    this.setState({
      pay: true,
    });
    return new Promise((resolve, reject) => {
      this.payResolve = resolve;
      this.payReject = reject;
    });
  }

  onClosePayModal() {
    this.setState({
      pay: false,
    });
  }

  onClickSelectItem(barcode) {
    if (barcode !== '') {
      this.props.mutator.activeRecord.update({ barcode });
      if ((this.props.resources.activeRecord || {}).barcode === barcode) {
        this.setState({
          lookup: true,
        });
      }
    }
  }

  onChangeOwner(e) {
    const ownerId = e.target.value;
    if (_.get(this.props.resources, ['activeRecord', 'shared']) === undefined) {
      const owners = _.get(this.props.resources, ['owners', 'records'], []);
      const shared = (owners.find(o => o.owner === 'Shared') || {}).id || '0';
      this.props.mutator.activeRecord.update({ shared });
    }
    this.props.mutator.activeRecord.update({ ownerId });
    this.setState({
      ownerId,
    });
  }

  onChangeItem(item) {
    this.item = item;
  }

  onFindShared(id) {
    this.props.mutator.activeRecord.update({ shared: id });
  }

  onCloseModal() {
    this.setState({
      lookup: false,
    });
  }

  showCalloutMessage(a) {
    const message =

        <FormattedMessage id="ui-users.charge.messageThe" />
        {a.feeFineType}
        <FormattedMessage id="ui-users.charge.messageOf" />
        {`${parseFloat(a.amount).toFixed(2)}`}
        <FormattedMessage id="ui-users.charge.messageSuccessfully" />
        {(a.paymentStatus.name).toLowerCase()}
        <FormattedMessage id="ui-users.charge.messageFor" />
        {`${getFullName(this.props.user)}`}
      ;
    this.callout.sendCallout({ message });
  }

  showConfirmDialog = (values) => {
    this.setState({
      showConfirmDialog: true,
      values
    });

    return new Promise((resolve, reject) => {
      this.actionResolve = resolve;
      this.actionReject = reject;
    });
  }

  hideConfirmDialog = () => {
    this.setState({
      showConfirmDialog: false,
      values: {}
    });
  }

  onConfirm = () => {
    const { values } = this.state;
    const { intl: { formatMessage } } = this.props;
    const tagStaff = formatMessage({ id: 'ui-users.accounts.actions.tag.staff' });
    const tagPatron = formatMessage({ id: 'ui-users.accounts.actions.tag.patron' });
    let comment = '';
    if (values.comment) {
      comment = `${tagStaff} : ${values.comment}`;
    }
    if (values.patronInfo && values.notify) {
      comment = `${comment} \n ${tagPatron} : ${values.patronInfo}`;
    }
    this.onClickCharge(this.type).then(() => {
      this.type.remaining = parseFloat(this.type.amount - values.amount).toFixed(2);
      let paymentStatus = _.capitalize(formatMessage({ id: 'ui-users.accounts.actions.warning.paymentAction' }));
      if (this.type.remaining === '0.00') {
        paymentStatus = `${paymentStatus} ${formatMessage({ id: 'ui-users.accounts.status.fully' })}`;
        this.type.status.name = 'Closed';
      } else {
        paymentStatus = `${paymentStatus} ${formatMessage({ id: 'ui-users.accounts.status.partially' })}`;
      }
      this.type.paymentStatus.name = paymentStatus;
      this.props.mutator.activeRecord.update({ id: this.type.id });
      return this.props.mutator.accounts.PUT(this.type);
    })
      .then(() => this.newAction({ paymentMethod: values.method }, this.type.id,
        this.type.paymentStatus.name, values.amount,
        comment, this.type.remaining,
        values.transaction, this.type.feeFineOwner))
      .then(() => {
        this.hideConfirmDialog();
        this.onClosePayModal();
        this.showCalloutMessage(this.type);
        this.payResolve();
      })
      .then(() => { this.props.history.goBack(); });
  }

  renderConfirmMessage = () => {
    const { intl: { formatMessage } } = this.props;
    const values = this.state.values || {};
    const type = this.type || {};
    const amount = parseFloat(values.amount || 0).toFixed(2);
    let paymentStatus = formatMessage({ id: 'ui-users.accounts.actions.warning.paymentAction' });
    paymentStatus = `${(parseFloat(values.amount) !== parseFloat(type.amount)
      ? formatMessage({ id: 'ui-users.accounts.status.partially' })
      : formatMessage({ id: 'ui-users.accounts.status.fully' }))} ${paymentStatus}`;
    return (
      <SafeHTMLMessage
        id="ui-users.accounts.confirmation.message"
        values={{ count: 1, amount, action: paymentStatus }}
      />
    );
  }

  onSubmitCharge = (data) => {
    const {
      history
    } = this.props;
    if (data.pay) {
      delete data.pay;
      this.type.remaining = data.amount;
      this.onClickPay(data);
    } else {
      delete data.pay;
      this.onClickCharge(data)
        .then(() => { history.goBack(); });
    }
  }

  render() {
    const {
      resources,
      user,
      stripes,
      location,
      history,
      intl,
      match: {
        params: { loanid },
      },
    } = this.props;
    this.item = _.get(resources, ['items', 'records', [0]], {});
    const allfeefines = _.get(resources, ['allfeefines', 'records'], []);
    const owners = _.get(resources, ['owners', 'records'], []);
    const list = [];
    const shared = owners.find(o => o.owner === 'Shared');
    allfeefines.forEach(f => {
      if (!list.find(o => (o || {}).id === f.ownerId)) {
        const owner = owners.find(o => (o || {}).id === f.ownerId);
        if (owner !== undefined) { list.push(owner); }
      }
    });
    const feefines = (this.state.ownerId !== '0') ? (resources.feefines || {}).records || [] : [];
    const payments = _.get(resources, ['payments', 'records'], []).filter(p => p.ownerId === this.state.ownerId);
    const accounts = _.get(resources, ['accounts', 'records'], []);
    const settings = _.get(this.props.resources, ['commentRequired', 'records', 0], {});
    const barcode = _.get(this.props.resources, 'activeRecord.barcode');

    const defaultServicePointId = _.get(resources, ['curUserServicePoint', 'records', 0, 'defaultServicePointId'], '-');
    const servicePointsIds = _.get(resources, ['curUserServicePoint', 'records', 0, 'servicePointsIds'], []);

    let selected = parseFloat(0);
    accounts.forEach(a => {
      selected += parseFloat(a.remaining);
    });
    parseFloat(selected).toFixed(2);
    let item;

    if (this.item && (loanid || barcode)) {
      item = {
        id: this.item.id || '',
        instance: this.item.title || '',
        barcode: this.item.barcode || '',
        itemStatus: (this.item.status || {}).name || '',
        callNumber: this.item.callNumber || '',
        location: (this.item.effectiveLocation || {}).name || '',
        type: (this.item.materialType || {}).name || '',
      };
    }

    const isPending = {
      owners: _.get(resources, ['owners', 'isPending'], false),
      feefines: _.get(resources, ['feefines', 'isPending'], false),
      servicePoints: _.get(resources, ['curUserServicePoint', 'isPending'], true)
    };

    const items = _.get(resources, ['items', 'records'], []);
    const ownerId = loadServicePoints({ owners: (shared ? owners : list), defaultServicePointId, servicePointsIds });
    const initialValues = { amount: this.type.amount, notify: true, ownerId };

    return (

        <ChargeForm
          onClickPay={this.onClickPay}
          defaultServicePointId={defaultServicePointId}
          servicePointsIds={servicePointsIds}
          onSubmit={this.onSubmitCharge}
          user={user}
          ownerList={(shared) ? owners : list}
          owners={owners}
          isPending={isPending}
          ownerId={this.state.ownerId}
          feefines={feefines}
          item={item}
          onFindShared={this.onFindShared}
          onChangeOwner={this.onChangeOwner}
          onClickSelectItem={this.onClickSelectItem}
          stripes={stripes}
          location={location}
          history={history}
          {...this.props}
        />
        <ItemLookup
          resources={resources}
          items={items}
          open={(this.state.lookup && items.length > 1)}
          onChangeItem={this.onChangeItem}
          onClose={this.onCloseModal}
        />
        <ActionModal
          intl={intl}
          action="payment"
          form="payment-modals"
          label="nameMethod"
          initialValues={initialValues}
          open={this.state.pay}
          commentRequired={settings.paid}
          onClose={this.onClosePayModal}
          accounts={[this.type]}
          balance={this.type.amount}
          data={payments}
          stripes={stripes}
          onSubmit={(values) => { this.showConfirmDialog(values); }}
          owners={owners}
          feefines={feefines}
        />
        <Callout ref={(ref) => { this.callout = ref; }} />
        <ConfirmationModal
          open={this.state.showConfirmDialog}
          heading={<FormattedMessage id="ui-users.accounts.confirmation.head" values={{ action: 'payment' }} />}
          message={this.renderConfirmMessage()}
          onConfirm={this.onConfirm}
          onCancel={this.hideConfirmDialog}
          cancelLabel={<FormattedMessage id="ui-users.accounts.cancellation.field.back" />}
          confirmLabel={<FormattedMessage id="ui-users.accounts.cancellation.field.confirm" />}
        />

    );
  }
}

export default injectIntl(ChargeFeeFine);
<|endoftext|>