<commit_before>/*
 * Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

define(function (require, exports, module) {
    "use strict";

    var Fluxxor = require("fluxxor"),
        Immutable = require("immutable"),
        _ = require("lodash");

    var events = require("../events"),
        collection = require("js/util/collection"),
        log = require("js/util/log");

    var DialogStore = Fluxxor.createStore({
        /**
         * List of the modal dialog IDs
         *
         * @const
         * @type {Array}
         */
        _modalDialogIDs: Immutable.Set([
            "first-launch-dialog",
            "keyboard-shortcut-dialog",
            "exports-panel-dialog"
        ]),

        /**
         * The set of open Dialog IDs
         *
         * @private
         * @type {Immutable.Set.<string>}
         */
        _openDialogs: Immutable.Set(),

        /**
         * Information/state for all registered dialogs
         *
         * The value of the map represents the state of the given dialog.
         * It is a map with the following optional keys:
         *     policy: Immutable.Map.<string, boolean>,
         *     documentID: number,
         *     selectionType: string

         * @private
         * @type {Immutable.Map.<string, Immutable.Map<string, object>>}
         */
        _registeredDialogs: Immutable.Map(),

        initialize: function () {
            this.bindActions(
                events.RESET, this._handleReset,
                events.dialog.OPEN_DIALOG, this._handleOpen,
                events.dialog.CLOSE_DIALOG, this._handleClose,
                events.dialog.CLOSE_ALL_DIALOGS, this._handleCloseAll,
                events.document.SELECT_LAYERS_BY_ID, this._handleSelectionChange,
                events.document.SELECT_LAYERS_BY_INDEX, this._handleSelectionChange,
                events.document.history.optimistic.GROUP_SELECTED, this._handleSelectionChange,
                events.document.CLOSE_DOCUMENT, this._handleDocumentChange,
                events.document.SELECT_DOCUMENT, this._handleDocumentChange
            );
        },

        /**
         * Reset or initialize store state.
         *
         * @private
         */
        _handleReset: function () {
            this._openDialogs = Immutable.Set();
            this._registeredDialogs = Immutable.Map();
        },

        getState: function () {
            return {
                openDialogs: this._openDialogs,
                appIsModal: this._openDialogs.some(function (id) {
                    return this._modalDialogIDs.has(id);
                }, this),
                appIsInputModal: this._openDialogs.contains("search-bar-dialog")
            };
        },

        /**
         * Fetch the current document ID, or null if there is no current document.
         *
         * @private
         * @return {?number}
         */
        _getCurrentDocumentID: function () {
            var applicationStore = this.flux.store("application");

            return applicationStore.getCurrentDocumentID();
        },

        /**
         * Fetch the type of the current layer selection, or none if there is no
         * consistent type.
         *
         * @private
         * @return {?string}
         */
        _getCurrentSelectionType: function () {
            var applicationStore = this.flux.store("application"),
                currentDocument = applicationStore.getCurrentDocument();

            if (!currentDocument) {
                return null;
            }

            var kinds = collection.pluck(currentDocument.layers.selected, "kind");

            return collection.uniformValue(kinds);
        },

        /**
         * Returns true if the given dialog ID is one of the modal dialogs
         * @param {string} id Dialog ID
         * @return {boolean}
         */
        isModalDialog: function (id) {
            return this._modalDialogIDs.has(id);
        },

        /**
         * Merges state if this event has already been registered
         *
         * @param {string} id Dialog ID
         * @param {object} dismissalPolicy
         */
        registerDialog: function (id, dismissalPolicy) {
            if (this._registeredDialogs.has(id)) {
                throw new Error("Failed to register dialog: " + id + " already exists.");
            }

            var state = Immutable.Map({
                policy: Immutable.Map(dismissalPolicy)
            });

            this._registeredDialogs = this._registeredDialogs.set(id, state);
        },

        /**
         * Deregisters a dialog and
         * emits a change event if this dialog was open
         *
         * @private
         * @param {string} id
         */
        deregisterDialog: function (id) {
            if (!this._registeredDialogs.has(id)) {
                // This a warning instead of an error because the store's state
                // may be reset as a result of a controller reset, which would
                // explain the missing dialog. Hence, this is most likely benign.
                log.warn("Failed to deregister dialog: " + id + " does not exist.");
            }

            this._registeredDialogs = this._registeredDialogs.delete(id);
            if (this._openDialogs.has(id)) {
                this._openDialogs = this._openDialogs.delete(id);
                this.emit("change");
            }
        },

        /**
         * Handle an open-dialog event.
         * If this dialog has not been pre-registered, it must contain a dismissal policy in the payload
         * Otherwise, the optional dismissal policy will overwrite the previous
         *
         * @private
         * @param {{id: string, dismissalPolicy: object=}} payload
         */
        _handleOpen: function (payload) {
            var id = payload.id,
                newState = Immutable.Map({
                    policy: Immutable.Map(payload.dismissalPolicy || {})
                });

            // register on the fly, but warn if a dismissal policy was not provided
            if (!this._registeredDialogs.has(id)) {
                if (_.isEmpty(payload.dismissalPolicy)) {
                    log.warn("Opening an un-registered dialog without providing a dismissalPolicy");
                }
            } else {
                // merge the new policy, if it was provided
                newState = this._registeredDialogs.get(id).merge(newState);
            }

            if (newState.getIn(["policy", "documentChange"])) {
                newState = newState.set("documentID", this._getCurrentDocumentID());
            }

            if (newState.getIn(["policy", "selectionTypeChange"])) {
                newState = newState.set("selectionType", this._getCurrentSelectionType());
            }

            // update the registry
            this._registeredDialogs = this._registeredDialogs.set(id, newState);

            // Close dialogs with the "openDialog" dismissal policy
            // and add this new one
            this._openDialogs = this._openDialogs
                .filterNot(function (dialogID) {
                    return this._registeredDialogs.getIn([dialogID, "policy", "dialogOpen"], false);
                }, this)
                .add(id);

            this.emit("change");
        },

        /**
         * Handle a close-dialog event.
         *
         * @private
         * @param {{id: number}} payload
         */
        _handleClose: function (payload) {
            this._openDialogs = this._openDialogs.delete(payload.id);
            this.emit("change");
        },

        /**
         * Handle a close-all-dialogs event.
         *
         * @private
         */
        _handleCloseAll: function () {
            this._openDialogs = this._openDialogs.clear();
            this.emit("change");
        },

        /**
         * Close all dialogs with a documentChange dismissal policy.
         *
         * @private
         */
        _handleDocumentChange: function () {
            this.waitFor(["document", "application"], function () {
                this._openDialogs = this._openDialogs.filterNot(function (dialogID) {
                    var state = this._registeredDialogs.get(dialogID);
                    return state.get("policy").get("documentChange") &&
                        state.get("documentID") !== this._getCurrentDocumentID();
                }, this);

                this.emit("change");
            });
        },

        /**
         * Close all dialogs with a selectionTypeChange dismissal policy.
         *
         * @private
         */
        _handleSelectionChange: function () {
            this.waitFor(["document"], function () {
                this._openDialogs = this._openDialogs.filterNot(function (dialogID) {
                    var state = this._registeredDialogs.get(dialogID);
                    return state.get("policy").get("selectionTypeChange") &&
                        state.get("selectionType") !== this._getCurrentSelectionType();
                }, this);

                this.emit("change");
            });
        }
    });

    module.exports = DialogStore;
});
<commit_msg>Properly merge dismissal policy during dialog open of previously registered dialog<commit_after>/*
 * Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

define(function (require, exports, module) {
    "use strict";

    var Fluxxor = require("fluxxor"),
        Immutable = require("immutable"),
        _ = require("lodash");

    var events = require("../events"),
        collection = require("js/util/collection"),
        log = require("js/util/log");

    var DialogStore = Fluxxor.createStore({
        /**
         * List of the modal dialog IDs
         *
         * @const
         * @type {Array}
         */
        _modalDialogIDs: Immutable.Set([
            "first-launch-dialog",
            "keyboard-shortcut-dialog",
            "exports-panel-dialog"
        ]),

        /**
         * The set of open Dialog IDs
         *
         * @private
         * @type {Immutable.Set.<string>}
         */
        _openDialogs: Immutable.Set(),

        /**
         * Information/state for all registered dialogs
         *
         * The value of the map represents the state of the given dialog.
         * It is a map with the following optional keys:
         *     policy: Immutable.Map.<string, boolean>,
         *     documentID: number,
         *     selectionType: string

         * @private
         * @type {Immutable.Map.<string, Immutable.Map<string, object>>}
         */
        _registeredDialogs: Immutable.Map(),

        initialize: function () {
            this.bindActions(
                events.RESET, this._handleReset,
                events.dialog.OPEN_DIALOG, this._handleOpen,
                events.dialog.CLOSE_DIALOG, this._handleClose,
                events.dialog.CLOSE_ALL_DIALOGS, this._handleCloseAll,
                events.document.SELECT_LAYERS_BY_ID, this._handleSelectionChange,
                events.document.SELECT_LAYERS_BY_INDEX, this._handleSelectionChange,
                events.document.history.optimistic.GROUP_SELECTED, this._handleSelectionChange,
                events.document.CLOSE_DOCUMENT, this._handleDocumentChange,
                events.document.SELECT_DOCUMENT, this._handleDocumentChange
            );
        },

        /**
         * Reset or initialize store state.
         *
         * @private
         */
        _handleReset: function () {
            this._openDialogs = Immutable.Set();
            this._registeredDialogs = Immutable.Map();
        },

        getState: function () {
            return {
                openDialogs: this._openDialogs,
                appIsModal: this._openDialogs.some(function (id) {
                    return this._modalDialogIDs.has(id);
                }, this),
                appIsInputModal: this._openDialogs.contains("search-bar-dialog")
            };
        },

        /**
         * Fetch the current document ID, or null if there is no current document.
         *
         * @private
         * @return {?number}
         */
        _getCurrentDocumentID: function () {
            var applicationStore = this.flux.store("application");

            return applicationStore.getCurrentDocumentID();
        },

        /**
         * Fetch the type of the current layer selection, or none if there is no
         * consistent type.
         *
         * @private
         * @return {?string}
         */
        _getCurrentSelectionType: function () {
            var applicationStore = this.flux.store("application"),
                currentDocument = applicationStore.getCurrentDocument();

            if (!currentDocument) {
                return null;
            }

            var kinds = collection.pluck(currentDocument.layers.selected, "kind");

            return collection.uniformValue(kinds);
        },

        /**
         * Returns true if the given dialog ID is one of the modal dialogs
         * @param {string} id Dialog ID
         * @return {boolean}
         */
        isModalDialog: function (id) {
            return this._modalDialogIDs.has(id);
        },

        /**
         * Merges state if this event has already been registered
         *
         * @param {string} id Dialog ID
         * @param {object} dismissalPolicy
         */
        registerDialog: function (id, dismissalPolicy) {
            if (this._registeredDialogs.has(id)) {
                throw new Error("Failed to register dialog: " + id + " already exists.");
            }

            var state = Immutable.Map({
                policy: Immutable.Map(dismissalPolicy)
            });

            this._registeredDialogs = this._registeredDialogs.set(id, state);
        },

        /**
         * Deregisters a dialog and
         * emits a change event if this dialog was open
         *
         * @private
         * @param {string} id
         */
        deregisterDialog: function (id) {
            if (!this._registeredDialogs.has(id)) {
                // This a warning instead of an error because the store's state
                // may be reset as a result of a controller reset, which would
                // explain the missing dialog. Hence, this is most likely benign.
                log.warn("Failed to deregister dialog: " + id + " does not exist.");
            }

            this._registeredDialogs = this._registeredDialogs.delete(id);
            if (this._openDialogs.has(id)) {
                this._openDialogs = this._openDialogs.delete(id);
                this.emit("change");
            }
        },

        /**
         * Handle an open-dialog event.
         * If this dialog has not been pre-registered, it must contain a dismissal policy in the payload
         * Otherwise, the optional dismissal policy will overwrite the previous
         *
         * @private
         * @param {{id: string, dismissalPolicy: object=}} payload
         */
        _handleOpen: function (payload) {
            var id = payload.id,
                newState = Immutable.Map({
                    policy: Immutable.Map(payload.dismissalPolicy || {})
                });

            // register on the fly, but warn if a dismissal policy was not provided
            if (!this._registeredDialogs.has(id)) {
                if (_.isEmpty(payload.dismissalPolicy)) {
                    log.warn("Opening an un-registered dialog without providing a dismissalPolicy");
                }
            } else {
                // merge the new policy, if it was provided
                newState = this._registeredDialogs.get(id).mergeDeep(newState);
            }

            if (newState.getIn(["policy", "documentChange"])) {
                newState = newState.set("documentID", this._getCurrentDocumentID());
            }

            if (newState.getIn(["policy", "selectionTypeChange"])) {
                newState = newState.set("selectionType", this._getCurrentSelectionType());
            }

            // update the registry
            this._registeredDialogs = this._registeredDialogs.set(id, newState);

            // Close dialogs with the "openDialog" dismissal policy
            // and add this new one
            this._openDialogs = this._openDialogs
                .filterNot(function (dialogID) {
                    return this._registeredDialogs.getIn([dialogID, "policy", "dialogOpen"], false);
                }, this)
                .add(id);

            this.emit("change");
        },

        /**
         * Handle a close-dialog event.
         *
         * @private
         * @param {{id: number}} payload
         */
        _handleClose: function (payload) {
            this._openDialogs = this._openDialogs.delete(payload.id);
            this.emit("change");
        },

        /**
         * Handle a close-all-dialogs event.
         *
         * @private
         */
        _handleCloseAll: function () {
            this._openDialogs = this._openDialogs.clear();
            this.emit("change");
        },

        /**
         * Close all dialogs with a documentChange dismissal policy.
         *
         * @private
         */
        _handleDocumentChange: function () {
            this.waitFor(["document", "application"], function () {
                this._openDialogs = this._openDialogs.filterNot(function (dialogID) {
                    var state = this._registeredDialogs.get(dialogID);
                    return state.get("policy").get("documentChange") &&
                        state.get("documentID") !== this._getCurrentDocumentID();
                }, this);

                this.emit("change");
            });
        },

        /**
         * Close all dialogs with a selectionTypeChange dismissal policy.
         *
         * @private
         */
        _handleSelectionChange: function () {
            this.waitFor(["document"], function () {
                this._openDialogs = this._openDialogs.filterNot(function (dialogID) {
                    var state = this._registeredDialogs.get(dialogID);
                    return state.get("policy").get("selectionTypeChange") &&
                        state.get("selectionType") !== this._getCurrentSelectionType();
                }, this);

                this.emit("change");
            });
        }
    });

    module.exports = DialogStore;
});
<|endoftext|>


<commit_before>import $ from 'jquery';

var dirs = {
    x: ['width', 'left', 'right'],
    y: ['height', 'top', 'bottom']
};

export function position(element, target, attach, targetAttach, offset, targetOffset, flip, boundary) {

    element = $(element);
    target = $(target);
    boundary = boundary && $(boundary);
    attach = getPos(attach);
    targetAttach = getPos(targetAttach);

    var dim = getDimensions(element),
        targetDim = getDimensions(target),
        position = targetDim;

    moveTo(position, attach, dim, -1);
    moveTo(position, targetAttach, targetDim, 1);

    offset = getOffsets(offset, dim.width, dim.height);
    targetOffset = getOffsets(targetOffset, targetDim.width, targetDim.height);

    offset['x'] += targetOffset['x'];
    offset['y'] += targetOffset['y'];

    position.left += offset['x'];
    position.top += offset['y'];

    boundary = getDimensions(boundary || window);

    var flipped = {element: attach, target: targetAttach};

    if (flip) {
        $.each(dirs, (dir, [prop, align, alignFlip]) => {

            if (!(flip === true || flip.indexOf(dir) !== -1)) {
                return;
            }

            var elemOffset = attach[dir] === align ? -dim[prop] : attach[dir] === alignFlip ? dim[prop] : 0,
                targetOffset = targetAttach[dir] === align ? targetDim[prop] : targetAttach[dir] === alignFlip ? -targetDim[prop] : 0;

            if (position[align] < boundary[align] || position[align] + dim[prop] > boundary[alignFlip]) {

                var newVal = position[align] + elemOffset + targetOffset - offset[dir] * 2;

                if (newVal >= boundary[align] && newVal + dim[prop] <= boundary[alignFlip]) {
                    position[align] = newVal;

                    ['element', 'target'].forEach((el) => {
                        flipped[el][dir] = !elemOffset
                            ? flipped[el][dir]
                            : flipped[el][dir] === dirs[dir][1]
                                ? dirs[dir][2]
                                : dirs[dir][1];
                    });
                }
            }

        });
    }

    element.offset({left: position.left, top: position.top});

    return flipped;
}

export function getDimensions(elem) {

    elem = $(elem);

    var width = elem.outerWidth(),
        height = elem.outerHeight(),
        offset = elem[0].getClientRects ? elem.offset() : null,
        left = offset ? Math.round(offset.left) : elem.scrollLeft(),
        top = offset ? Math.round(offset.top) : elem.scrollTop();

    return {width, height, left, top, right: left + width, bottom: top + height};
}

function moveTo(position, attach, dim, factor) {
    $.each(dirs, function (dir, [prop, align, alignFlip]) {
        if (attach[dir] === alignFlip) {
            position[align] += dim[prop] * factor;
        } else if (attach[dir] === 'center') {
            position[align] += dim[prop] * factor / 2;
        }
    });
}

function getPos(pos) {

    var x = /left|center|right/, y = /top|center|bottom/;

    pos = (pos || '').split(' ');

    if (pos.length === 1) {
        pos = x.test(pos[0])
            ? pos.concat(['center'])
            : y.test(pos[0])
                ? ['center'].concat(pos)
                : ['center', 'center'];
    }

    return {
        x: x.test(pos[0]) ? pos[0] : 'center',
        y: y.test(pos[1]) ? pos[1] : 'center'
    };
}

function getOffsets(offsets, width, height) {

    offsets = (offsets || '').split(' ');

    return {
        x: offsets[0] ? parseFloat(offsets[0]) * (offsets[0][offsets[0].length - 1] === '%' ? width / 100 : 1) : 0,
        y: offsets[1] ? parseFloat(offsets[1]) * (offsets[1][offsets[1].length - 1] === '%' ? height / 100 : 1) : 0
    };
}

export function flipPosition(pos) {
    switch (pos) {
        case 'left':
            return 'right';
        case 'right':
            return 'left';
        case 'top':
            return 'bottom';
        case 'bottom':
            return 'top';
        default:
            return pos;
    }
}
<commit_msg>fix getDimensions<commit_after>import $ from 'jquery';

var dirs = {
    x: ['width', 'left', 'right'],
    y: ['height', 'top', 'bottom']
};

export function position(element, target, attach, targetAttach, offset, targetOffset, flip, boundary) {

    element = $(element);
    target = $(target);
    boundary = boundary && $(boundary);
    attach = getPos(attach);
    targetAttach = getPos(targetAttach);

    var dim = getDimensions(element),
        targetDim = getDimensions(target),
        position = targetDim;

    moveTo(position, attach, dim, -1);
    moveTo(position, targetAttach, targetDim, 1);

    offset = getOffsets(offset, dim.width, dim.height);
    targetOffset = getOffsets(targetOffset, targetDim.width, targetDim.height);

    offset['x'] += targetOffset['x'];
    offset['y'] += targetOffset['y'];

    position.left += offset['x'];
    position.top += offset['y'];

    boundary = getDimensions(boundary || window);

    var flipped = {element: attach, target: targetAttach};

    if (flip) {
        $.each(dirs, (dir, [prop, align, alignFlip]) => {

            if (!(flip === true || flip.indexOf(dir) !== -1)) {
                return;
            }

            var elemOffset = attach[dir] === align ? -dim[prop] : attach[dir] === alignFlip ? dim[prop] : 0,
                targetOffset = targetAttach[dir] === align ? targetDim[prop] : targetAttach[dir] === alignFlip ? -targetDim[prop] : 0;

            if (position[align] < boundary[align] || position[align] + dim[prop] > boundary[alignFlip]) {

                var newVal = position[align] + elemOffset + targetOffset - offset[dir] * 2;

                if (newVal >= boundary[align] && newVal + dim[prop] <= boundary[alignFlip]) {
                    position[align] = newVal;

                    ['element', 'target'].forEach((el) => {
                        flipped[el][dir] = !elemOffset
                            ? flipped[el][dir]
                            : flipped[el][dir] === dirs[dir][1]
                                ? dirs[dir][2]
                                : dirs[dir][1];
                    });
                }
            }

        });
    }

    element.offset({left: position.left, top: position.top});

    return flipped;
}

export function getDimensions(elem) {

    elem = $(elem);

    var width = Math.round(elem.outerWidth()),
        height = Math.round(elem.outerHeight()),
        offset = elem[0].getClientRects ? elem.offset() : null,
        left = offset ? Math.round(offset.left) : elem.scrollLeft(),
        top = offset ? Math.round(offset.top) : elem.scrollTop();

    return {width, height, left, top, right: left + width, bottom: top + height};
}

function moveTo(position, attach, dim, factor) {
    $.each(dirs, function (dir, [prop, align, alignFlip]) {
        if (attach[dir] === alignFlip) {
            position[align] += dim[prop] * factor;
        } else if (attach[dir] === 'center') {
            position[align] += dim[prop] * factor / 2;
        }
    });
}

function getPos(pos) {

    var x = /left|center|right/, y = /top|center|bottom/;

    pos = (pos || '').split(' ');

    if (pos.length === 1) {
        pos = x.test(pos[0])
            ? pos.concat(['center'])
            : y.test(pos[0])
                ? ['center'].concat(pos)
                : ['center', 'center'];
    }

    return {
        x: x.test(pos[0]) ? pos[0] : 'center',
        y: y.test(pos[1]) ? pos[1] : 'center'
    };
}

function getOffsets(offsets, width, height) {

    offsets = (offsets || '').split(' ');

    return {
        x: offsets[0] ? parseFloat(offsets[0]) * (offsets[0][offsets[0].length - 1] === '%' ? width / 100 : 1) : 0,
        y: offsets[1] ? parseFloat(offsets[1]) * (offsets[1][offsets[1].length - 1] === '%' ? height / 100 : 1) : 0
    };
}

export function flipPosition(pos) {
    switch (pos) {
        case 'left':
            return 'right';
        case 'right':
            return 'left';
        case 'top':
            return 'bottom';
        case 'bottom':
            return 'top';
        default:
            return pos;
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2012, David Haglund
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//     * Redistributions of source code must retain the above
//       copyright notice, this list of conditions and the following
//       disclaimer.
//
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials
//       provided with the distribution.
//
//     * Neither the name of the copyright holder nor the names of its
//       contributors may be used to endorse or promote products
//       derived from this software without specific prior written
//       permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.

// I have borrowed a few lines from the code specified below:
// https://github.com/mbostock/d3/blob/master/examples/contour/contour.html
// with the license:
// https://github.com/mbostock/d3/blob/master/LICENSE

/*globals d3 */
(function () {
    'use strict';
    var svg, svgBits, bitData, data, dw, dh, width, height, html,
        boxSizeHeight = 50,
        defaultWidth = 50,
        send_window = [{
            width: 50,
            color: "green2"
        }, {
            width: 100,
            color: "green2"
        }, {
            width: 33,
            color: "orange2",
            arrow: "VT(R)"
        }, {
            width: 53,
            color: "red2"
        }, {
            width: 110,
            color: "green2"
        }, {
            width: 220,
            color: "red2"
        }, {
            width: 40,
            color: "red2"
        }, {
            width: 60,
            color: "green2"
        }, {
            color: "white"
        }, {
            color: "white",
            id: "..."
        }, {
            color: "white",
            id: 514,
            arrow: "VT(MR)"
        }],
        colorMap = {
            red: "#d7191c",
            orange: "#feae61",
            yellow: "#ffffbf",
            lightgreen: "a6d96a",
            green: "#1a9641",
            // white: "#fff",
            orange2: "#FF7F00",
            red2: "#E41A1C",
            blue: "#377EB8",
            green2: "#4DAF4A",
            pink: "#984EA3",
            white: "#377EB8"
        };

    function translateX(d, i) {
        return "translate(" + (d.offset) + ",0)";
    }

    function translateArrowX(d) {
        return d.offset + d.width / 2;
    }

    function addOffsetAndId(bits) {
        return bits.reduce(function (acc, val) {
            if (!val.hasOwnProperty("width")) {
                val.width = defaultWidth;
            }
            val.offset = acc.width;
            if (!val.hasOwnProperty("id")) {
                val.id = acc.count;
            }
            acc.list.push(val);
            acc.width += val.width;
            acc.count += 1;
            return acc;
        }, {list: [], width: 0, count: 0});
    }

    data = addOffsetAndId(send_window);
    dh = data.length;
    width = data.width;
    height = boxSizeHeight + 150;

    svg = d3.select("#window").append("svg")
        .attr("title", "a packet")
        .attr("version", 1.1)
        .attr("xmlns", "http://www.w3.org/2000/svg")
        .attr("width", width)
        .attr("height", height);

    // define arrow-head, generate it with data?
    d3.select("#window").select("svg")
        .append("defs")
        .append("marker")
        .attr("id", "ArrowFillLeft")
        .attr("viewBox", "0 0 10 10")
        .attr("refX", 5)
        .attr("refY", 5)
        .attr("markerUnits", "strokeWidth")
        .attr("markerwidth", 18)
        .attr("markerHeight", 6)
        .attr("orient", "auto")
        .append("path")
        .attr("d", "M 10 0 L 0 5 L 10 10 z");

    // Arrows!
    svg.selectAll("line")
        .data(data.list.filter(function (d) {
            return d.hasOwnProperty("arrow");
        }))
        .enter()
        .append("line")
        .attr("x1", translateArrowX)
        .attr("x2", translateArrowX)
        .attr("y1", 55.5)
        .attr("y2", 100)
        .attr("fill", "none")
        .attr("stroke", "#000")
        .attr("stroke-width", 3)
        .attr("marker-start", "url(#ArrowFillLeft)");

    bitData = svg.selectAll("g.bit")
        .data(data.list)
        .enter()
        .append("g")
        .attr("transform", translateX);

    bitData.append("rect")
        .attr("width", function (d) { return d.width; })
        .attr("height", boxSizeHeight)
        .style("border", "solid 1px #000")
        .style("stroke", "#000")
        .style("stroke-width", "2px")
        .style("fill", function (d) {
            return colorMap[d.color] || colorMap.orange;
        });

    bitData.append("text")
        .style("font-size", "0.8em")
        .style("fill", "#000")
        .attr("text-anchor", "middle")
        .attr("dy", boxSizeHeight / 2 * 1.2)
        .attr("dx", function (d) { return d.width / 2; })
        .text(function (d) {
            return d.id;
        });
}());
<commit_msg>Added labels to the arrows<commit_after>// Copyright (c) 2012, David Haglund
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//     * Redistributions of source code must retain the above
//       copyright notice, this list of conditions and the following
//       disclaimer.
//
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials
//       provided with the distribution.
//
//     * Neither the name of the copyright holder nor the names of its
//       contributors may be used to endorse or promote products
//       derived from this software without specific prior written
//       permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.

// I have borrowed a few lines from the code specified below:
// https://github.com/mbostock/d3/blob/master/examples/contour/contour.html
// with the license:
// https://github.com/mbostock/d3/blob/master/LICENSE

/*globals d3 */
(function () {
    'use strict';
    var svg, svgBits, boxData, data, dw, dh, width, height, html, arrow,
        boxSizeHeight = 50,
        defaultWidth = 50,
        send_window = [{
            color: "ack"
        }, {
            width: 100,
            color: "ack"
        }, {
            width: 33,
            color: "pending",
            arrow: "VT(R)"
        }, {
            color: "nack"
        }, {
            width: 110,
            color: "ack"
        }, {
            width: 100,
            color: "nack"
        }, {
            width: 40,
            color: "nack"
        }, {
            width: 60,
            color: "ack"
        }, {
            color: "unused"
        }, {
            color: "unused",
            id: "..."
        }, {
            color: "unused",
            id: 514,
            arrow: "VT(MR)"
        }],
        colorMap = {
            red: "#d7191c",
            orange: "#feae61",
            yellow: "#ffffbf",
            lightgreen: "a6d96a",
            green: "#1a9641",
            blue: "#377EB8",
            pink: "#984EA3",

            ack: "#4DAF4A",
            pending: "#FF7F00",
            nack: "#E41A1C",
            unused: "#377EB8"
        };

    function translateX(d) {
        return "translate(" + (d.offset) + ",0)";
    }

    function arrowX(d) {
        return d.offset + d.width / 2;
    }

    function translateArrow(d) {
        return "translate(" + (Math.floor(arrowX(d)) + 0.5) + "," + 55.5 + ")";
    }

    function addOffsetAndId(bits) {
        return bits.reduce(function (acc, val) {
            if (!val.hasOwnProperty("width")) {
                val.width = defaultWidth;
            }
            val.offset = acc.width;
            if (!val.hasOwnProperty("id")) {
                val.id = acc.count;
            }
            acc.list.push(val);
            acc.width += val.width;
            acc.count += 1;
            return acc;
        }, {list: [], width: 0, count: 0});
    }

    data = addOffsetAndId(send_window);
    dh = data.length;
    width = data.width + 100;
    height = boxSizeHeight + 150;

    svg = d3.select("#window").append("svg")
        .attr("title", "a packet")
        .attr("version", 1.1)
        .attr("xmlns", "http://www.w3.org/2000/svg")
        .attr("width", width)
        .attr("height", height)
        .append("g")
        .attr("transform", "translate(5,5)");

    // Group the rect and the text
    boxData = svg.selectAll("g.boxes")
        .data(data.list)
        .enter()
        .append("g")
        .attr("class", "boxes")
        .attr("transform", translateX);

    boxData.append("rect")
        .attr("width", function (d) { return d.width; })
        .attr("height", boxSizeHeight)
        .style("border", "solid 1px #000")
        .style("stroke", "#000")
        .style("stroke-width", "2px")
        .style("fill", function (d) {
            return colorMap[d.color] || colorMap.orange;
        });

    boxData.append("text")
        .style("font-size", "0.8em")
        .style("fill", "#000")
        .attr("text-anchor", "middle")
        .attr("dy", boxSizeHeight / 2 * 1.25)
        .attr("dx", function (d) { return d.width / 2; })
        .text(function (d) {
            return d.id;
        });

    // Define the arrow head
    svg.append("defs")
        .append("marker")
        .attr("id", "ArrowFillLeft")
        .attr("viewBox", "0 0 10 10")
        .attr("refX", 5)
        .attr("refY", 5)
        .attr("markerUnits", "strokeWidth")
        .attr("markerwidth", 18)
        .attr("markerHeight", 6)
        .attr("orient", "auto")
        .append("path")
        .attr("d", "M 10 0 L 0 5 L 10 10 z");

    // Group arrows and arrow labels
    arrow = svg.selectAll("g.arrows")
        .data(data.list.filter(function (d) {
            return d.hasOwnProperty("arrow");
        }))
        .enter()
        .append("g")
        .attr("class", "arrows")
        .attr("transform", translateArrow);

    arrow.append("line")
        .attr("y2", 45.5)
        .attr("fill", "none")
        .attr("stroke", "#000")
        .attr("stroke-width", 3)
        .attr("marker-start", "url(#ArrowFillLeft)");

    arrow.append("text")
        .style("font-size", "0.8em")
        .style("fill", "#000")
        .attr("text-anchor", "middle")
        .attr("dy", 60)
        .attr("dx", 0)
        .text(function (d) {
            return d.arrow;
        });
}());
<|endoftext|>


<commit_before>import { offset } from './dimensions';
import { clamp, includes, ucfirst } from './lang';
import { offsetViewport, scrollParents } from './viewport';

const dirs = [
    ['width', 'x', 'left', 'right'],
    ['height', 'y', 'top', 'bottom'],
];

export function positionAt(element, target, options) {
    options = {
        attach: {
            element: ['left', 'top'],
            target: ['left', 'top'],
            ...options.attach,
        },
        offset: [0, 0],
        ...options,
    };

    const dim = options.flip
        ? attachToWithFlip(element, target, options)
        : attachTo(element, target, options);

    offset(element, dim);
}

function attachTo(element, target, options) {
    let { attach, offset: offsetBy } = {
        attach: {
            element: ['left', 'top'],
            target: ['left', 'top'],
            ...options.attach,
        },
        offset: [0, 0],
        ...options,
    };

    const position = offset(element);
    const targetOffset = offset(target);
    for (const [i, [prop, dir, start, end]] of Object.entries(dirs)) {
        position[start] = position[dir] =
            targetOffset[start] +
            moveBy(attach.target[i], end, targetOffset[prop]) -
            moveBy(attach.element[i], end, position[prop]) +
            +offsetBy[i];
        position[end] = position[start] + position[prop];
    }
    return position;
}

function attachToWithFlip(element, target, options) {
    const position = attachTo(element, target, options);
    const targetDim = offset(target);

    let {
        flip,
        attach: { element: elAttach, target: targetAttach },
        offset: elOffset,
        boundary,
        viewport,
        viewportPadding,
    } = options;

    let viewports = scrollParents(element);
    if (boundary === target) {
        viewports = viewports.filter((viewport) => viewport !== boundary);
    }
    const [scrollElement] = viewports;
    viewports.push(viewport);

    const offsetPosition = { ...position };
    for (const [i, [prop, dir, start, end]] of Object.entries(dirs)) {
        if (flip !== true && !includes(flip, dir)) {
            continue;
        }

        const willFlip =
            !intersectLine(position, targetDim, i) && intersectLine(position, targetDim, 1 - i);

        viewport = getIntersectionArea(...viewports.filter(Boolean).map(offsetViewport));

        if (viewportPadding) {
            viewport[start] += viewportPadding;
            viewport[end] -= viewportPadding;
        }

        if (boundary && !willFlip && position[prop] <= offset(boundary)[prop]) {
            viewport = getIntersectionArea(viewport, offset(boundary));
        }

        const isInStartBoundary = position[start] >= viewport[start];
        const isInEndBoundary = position[end] <= viewport[end];

        if (isInStartBoundary && isInEndBoundary) {
            continue;
        }

        let offsetBy;

        // Flip
        if (willFlip) {
            if (
                (elAttach[i] === end && isInStartBoundary) ||
                (elAttach[i] === start && isInEndBoundary)
            ) {
                continue;
            }

            offsetBy =
                (elAttach[i] === start
                    ? -position[prop]
                    : elAttach[i] === end
                    ? position[prop]
                    : 0) +
                (targetAttach[i] === start
                    ? targetDim[prop]
                    : targetAttach[i] === end
                    ? -targetDim[prop]
                    : 0) -
                elOffset[i] * 2;

            if (
                !isInScrollArea(
                    {
                        ...position,
                        [start]: position[start] + offsetBy,
                        [end]: position[end] + offsetBy,
                    },
                    scrollElement,
                    i
                )
            ) {
                if (isInScrollArea(position, scrollElement, i)) {
                    continue;
                }

                if (options.recursion) {
                    return false;
                }

                const newPos = attachToWithFlip(element, target, {
                    ...options,
                    attach: {
                        element: elAttach.map(flipDir).reverse(),
                        target: targetAttach.map(flipDir).reverse(),
                    },
                    offset: elOffset.reverse(),
                    flip: flip === true ? flip : [...flip, dirs[1 - i][1]],
                    recursion: true,
                });

                if (newPos && isInScrollArea(newPos, scrollElement, 1 - i)) {
                    return newPos;
                }
            }

            // Move
        } else {
            offsetBy =
                clamp(
                    clamp(position[start], viewport[start], viewport[end] - position[prop]),
                    targetDim[start] - position[prop] + elOffset[i],
                    targetDim[end] - elOffset[i]
                ) - position[start];
        }

        offsetPosition[start] = position[dir] = position[start] + offsetBy;
        offsetPosition[end] += offsetBy;
    }

    return offsetPosition;
}

function moveBy(start, end, dim) {
    return start === 'center' ? dim / 2 : start === end ? dim : 0;
}

function getIntersectionArea(...rects) {
    let area = {};
    for (const rect of rects) {
        for (const [, , start, end] of dirs) {
            area[start] = Math.max(area[start] || 0, rect[start]);
            area[end] = Math.min(...[area[end], rect[end]].filter(Boolean));
        }
    }
    return area;
}

function isInScrollArea(position, scrollElement, dir) {
    const viewport = offsetViewport(scrollElement);
    const [prop, , start, end] = dirs[dir];
    viewport[start] -= scrollElement[`scroll${ucfirst(start)}`];
    viewport[end] = viewport[start] + scrollElement[`scroll${ucfirst(prop)}`];

    return position[start] >= viewport[start] && position[end] <= viewport[end];
}

function intersectLine(dimA, dimB, dir) {
    const [, , start, end] = dirs[dir];
    return dimA[end] > dimB[start] && dimB[end] > dimA[start];
}

function flipDir(prop) {
    for (let i = 0; i < dirs.length; i++) {
        const index = dirs[i].indexOf(prop);
        if (~index) {
            return dirs[1 - i][(index % 2) + 2];
        }
    }
}
<commit_msg>refactor: cleanup<commit_after>import { offset } from './dimensions';
import { clamp, includes, ucfirst } from './lang';
import { offsetViewport, scrollParents } from './viewport';

const dirs = [
    ['width', 'x', 'left', 'right'],
    ['height', 'y', 'top', 'bottom'],
];

export function positionAt(element, target, options) {
    options = {
        attach: {
            element: ['left', 'top'],
            target: ['left', 'top'],
            ...options.attach,
        },
        offset: [0, 0],
        ...options,
    };

    const dim = options.flip
        ? attachToWithFlip(element, target, options)
        : attachTo(element, target, options);

    offset(element, dim);
}

function attachTo(element, target, options) {
    let { attach, offset: offsetBy } = {
        attach: {
            element: ['left', 'top'],
            target: ['left', 'top'],
            ...options.attach,
        },
        offset: [0, 0],
        ...options,
    };

    const position = offset(element);
    const targetOffset = offset(target);
    for (const [i, [prop, dir, start, end]] of Object.entries(dirs)) {
        position[start] = position[dir] =
            targetOffset[start] +
            moveBy(attach.target[i], end, targetOffset[prop]) -
            moveBy(attach.element[i], end, position[prop]) +
            +offsetBy[i];
        position[end] = position[start] + position[prop];
    }
    return position;
}

function moveBy(start, end, dim) {
    return start === 'center' ? dim / 2 : start === end ? dim : 0;
}

function attachToWithFlip(element, target, options) {
    const position = attachTo(element, target, options);
    const targetDim = offset(target);

    let {
        flip,
        attach: { element: elAttach, target: targetAttach },
        offset: elOffset,
        boundary,
        viewport,
        viewportPadding,
    } = options;

    let viewports = scrollParents(element);
    if (boundary === target) {
        viewports = viewports.filter((viewport) => viewport !== boundary);
    }
    const [scrollElement] = viewports;
    viewports.push(viewport);

    const offsetPosition = { ...position };
    for (const [i, [prop, dir, start, end]] of Object.entries(dirs)) {
        if (flip !== true && !includes(flip, dir)) {
            continue;
        }

        const willFlip =
            !intersectLine(position, targetDim, i) && intersectLine(position, targetDim, 1 - i);

        viewport = getIntersectionArea(...viewports.filter(Boolean).map(offsetViewport));

        if (viewportPadding) {
            viewport[start] += viewportPadding;
            viewport[end] -= viewportPadding;
        }

        if (boundary && !willFlip && position[prop] <= offset(boundary)[prop]) {
            viewport = getIntersectionArea(viewport, offset(boundary));
        }

        const isInStartBoundary = position[start] >= viewport[start];
        const isInEndBoundary = position[end] <= viewport[end];

        if (isInStartBoundary && isInEndBoundary) {
            continue;
        }

        let offsetBy;

        // Flip
        if (willFlip) {
            if (
                (elAttach[i] === end && isInStartBoundary) ||
                (elAttach[i] === start && isInEndBoundary)
            ) {
                continue;
            }

            offsetBy =
                (elAttach[i] === start
                    ? -position[prop]
                    : elAttach[i] === end
                    ? position[prop]
                    : 0) +
                (targetAttach[i] === start
                    ? targetDim[prop]
                    : targetAttach[i] === end
                    ? -targetDim[prop]
                    : 0) -
                elOffset[i] * 2;

            if (
                !isInScrollArea(
                    {
                        ...position,
                        [start]: position[start] + offsetBy,
                        [end]: position[end] + offsetBy,
                    },
                    scrollElement,
                    i
                )
            ) {
                if (isInScrollArea(position, scrollElement, i)) {
                    continue;
                }

                if (options.recursion) {
                    return false;
                }

                const newPos = attachToWithFlip(element, target, {
                    ...options,
                    attach: {
                        element: elAttach.map(flipDir).reverse(),
                        target: targetAttach.map(flipDir).reverse(),
                    },
                    offset: elOffset.reverse(),
                    flip: flip === true ? flip : [...flip, dirs[1 - i][1]],
                    recursion: true,
                });

                if (newPos && isInScrollArea(newPos, scrollElement, 1 - i)) {
                    return newPos;
                }
            }

            // Move
        } else {
            offsetBy =
                clamp(
                    clamp(position[start], viewport[start], viewport[end] - position[prop]),
                    targetDim[start] - position[prop] + elOffset[i],
                    targetDim[end] - elOffset[i]
                ) - position[start];
        }

        offsetPosition[start] = position[dir] = position[start] + offsetBy;
        offsetPosition[end] += offsetBy;
    }

    return offsetPosition;
}

function getIntersectionArea(...rects) {
    let area = {};
    for (const rect of rects) {
        for (const [, , start, end] of dirs) {
            area[start] = Math.max(area[start] || 0, rect[start]);
            area[end] = Math.min(...[area[end], rect[end]].filter(Boolean));
        }
    }
    return area;
}

function isInScrollArea(position, scrollElement, dir) {
    const viewport = offsetViewport(scrollElement, false);
    const [prop, , start, end] = dirs[dir];
    viewport[start] -= scrollElement[`scroll${ucfirst(start)}`];
    viewport[end] = viewport[start] + scrollElement[`scroll${ucfirst(prop)}`];

    return position[start] >= viewport[start] && position[end] <= viewport[end];
}

function intersectLine(dimA, dimB, dir) {
    const [, , start, end] = dirs[dir];
    return dimA[end] > dimB[start] && dimB[end] > dimA[start];
}

function flipDir(prop) {
    for (let i = 0; i < dirs.length; i++) {
        const index = dirs[i].indexOf(prop);
        if (~index) {
            return dirs[1 - i][(index % 2) + 2];
        }
    }
}
<|endoftext|>


<commit_before>import { Component } from 'substance'

const DISABLED = { disabled: true }

/**
 * A component that renders a group of tools.
 *
 * @param {string} props.name
 * @param {string} props.style
 * @param {string} props.theme
 * @param {boolean} props.hideDisabled
 * @param {array} props.items array of item specifications
 * @param {object} props.commandStates command states by name
 */
export default class ToolGroup extends Component {
  constructor (...args) {
    super(...args)

    this._deriveState(this.props)
  }

  willReceiveProps (newProps) {
    this._deriveState(newProps)
  }

  getTheme () {
    // HACK: falling back to 'light' in a hard-coded way
    return this.props.theme || 'light'
  }

  _deriveState (props) {
    if (this._isTopLevel) {
      this._derivedState = this._deriveGroupState(props, props.commandStates)
    } else {
      this._derivedState = props.itemState
    }
  }

  render ($$) {
    const { name, hideDisabled } = this.props
    let el = $$('div')
      .addClass(this._getClassNames())
      .addClass('sm-' + name)

    let hasEnabledItem = this._derivedState.hasEnabledItem
    if (hasEnabledItem || !hideDisabled) {
      el.append(this._renderLabel($$))
      el.append(this._renderItems($$))
    }

    return el
  }

  _renderLabel ($$) {
    // EXPERIMENTAL: showing a ToolGroup label an
    const { style, label } = this.props
    if (style === 'descriptive' && label) {
      const SeparatorClass = this.getComponent('tool-separator')
      return $$(SeparatorClass, { label })
    }
  }

  _renderItems ($$) {
    const { style, hideDisabled, commandStates } = this.props
    const theme = this.getTheme()
    const { itemStates } = this._derivedState
    let els = []
    for (let itemState of itemStates) {
      let item = itemState.item
      let type = item.type
      switch (type) {
        case 'command': {
          const commandName = item.name
          let commandState = itemState.commandState
          if (itemState.enabled || !hideDisabled) {
            let ToolClass = this._getToolClass(item)
            els.push(
              $$(ToolClass, {
                item,
                commandState,
                style,
                theme
              }).ref(commandName)
            )
          }
          break
        }
        case 'separator': {
          let ToolSeparator = this.getComponent('tool-separator')
          els.push(
            $$(ToolSeparator, item)
          )
          break
        }
        default: {
          let ToolClass = this._getToolClass(item)
          els.push(
            $$(ToolClass, Object.assign({}, item, {
              commandStates,
              itemState,
              theme
            })).ref(item.name)
          )
        }
      }
    }
    return els
  }

  get _isTopLevel () { return false }

  // ATTENTION: this is only called for top-level tool groups (Menu, Prompt, ) which are ToolDrop
  _deriveGroupState (group, commandStates) {
    let itemStates = group.items.map(item => this._deriveItemState(item, commandStates))
    let hasEnabledItem = itemStates.some(item => item.enabled || item.hasEnabledItem)
    return {
      item: group,
      itemStates,
      hasEnabledItem
    }
  }

  _deriveItemState (item, commandStates) {
    switch (item.type) {
      case 'command': {
        let commandState = commandStates[item.name] || DISABLED
        return {
          item,
          commandState,
          enabled: !commandState.disabled
        }
      }
      case 'group':
      case 'dropdown':
      case 'prompt':
      case 'switcher': {
        return this._deriveGroupState(item, commandStates)
      }
      case 'separator': {
        return { item }
      }
      default:
        throw new Error('Unsupported item type')
    }
  }

  _getClassNames () {
    return 'sc-tool-group'
  }

  _getToolClass (item) {
    // use an ToolClass from toolSpec if configured inline in ToolGroup spec
    let ToolClass
    if (item.ToolClass) {
      ToolClass = item.ToolClass
    } else {
      switch (item.type) {
        case 'command': {
          // try to use a tool registered by the same name as the command
          ToolClass = this.getComponent(item.name, 'no-throw')
          if (!ToolClass) {
            // using the default tool otherwise
            ToolClass = this.getComponent('tool')
          }
          break
        }
        case 'dropdown': {
          ToolClass = this.getComponent('tool-dropdown')
          break
        }
        case 'group': {
          ToolClass = this.getComponent('tool-group')
          break
        }
        case 'prompt': {
          ToolClass = this.getComponent('tool-prompt')
          break
        }
        case 'separator': {
          ToolClass = this.getComponent('tool-separator')
          break
        }
        case 'switcher': {
          ToolClass = this.getComponent('tool-switcher')
          break
        }
        default: {
          console.error('Unsupported item type inside ToolGroup:', item.type)
        }
      }
    }

    return ToolClass
  }
}
<commit_msg>Hide disabled nested tool groups.<commit_after>import { Component } from 'substance'

const DISABLED = { disabled: true }

/**
 * A component that renders a group of tools.
 *
 * @param {string} props.name
 * @param {string} props.style
 * @param {string} props.theme
 * @param {boolean} props.hideDisabled
 * @param {array} props.items array of item specifications
 * @param {object} props.commandStates command states by name
 */
export default class ToolGroup extends Component {
  constructor (...args) {
    super(...args)

    this._deriveState(this.props)
  }

  willReceiveProps (newProps) {
    this._deriveState(newProps)
  }

  getTheme () {
    // HACK: falling back to 'light' in a hard-coded way
    return this.props.theme || 'light'
  }

  _deriveState (props) {
    if (this._isTopLevel) {
      this._derivedState = this._deriveGroupState(props, props.commandStates)
    } else {
      this._derivedState = props.itemState
    }
  }

  render ($$) {
    const { name, hideDisabled } = this.props
    let el = $$('div')
      .addClass(this._getClassNames())
      .addClass('sm-' + name)

    let hasEnabledItem = this._derivedState.hasEnabledItem
    if (hasEnabledItem || !hideDisabled) {
      el.append(this._renderLabel($$))
      el.append(this._renderItems($$))
    }

    return el
  }

  _renderLabel ($$) {
    // EXPERIMENTAL: showing a ToolGroup label an
    const { style, label } = this.props
    if (style === 'descriptive' && label) {
      const SeparatorClass = this.getComponent('tool-separator')
      return $$(SeparatorClass, { label })
    }
  }

  _renderItems ($$) {
    const { style, hideDisabled, commandStates } = this.props
    const theme = this.getTheme()
    const { itemStates } = this._derivedState
    let els = []
    for (let itemState of itemStates) {
      let item = itemState.item
      let type = item.type
      switch (type) {
        case 'command': {
          const commandName = item.name
          let commandState = itemState.commandState
          if (itemState.enabled || !hideDisabled) {
            let ToolClass = this._getToolClass(item)
            els.push(
              $$(ToolClass, {
                item,
                commandState,
                style,
                theme
              }).ref(commandName)
            )
          }
          break
        }
        case 'separator': {
          let ToolSeparator = this.getComponent('tool-separator')
          els.push(
            $$(ToolSeparator, item)
          )
          break
        }
        default: {
          if (!hideDisabled || itemState.enabled || itemState.hasEnabledItem) {
            let ToolClass = this._getToolClass(item)
            els.push(
              // ATTENTION: we are passing down options present on the current
              // group, but they can be overridden via spec
              // TODO: add all con
              $$(ToolClass, Object.assign({ hideDisabled }, item, {
                commandStates,
                itemState,
                theme
              })).ref(item.name)
            )
          }
        }
      }
    }
    return els
  }

  get _isTopLevel () { return false }

  // ATTENTION: this is only called for top-level tool groups (Menu, Prompt, ) which are ToolDrop
  _deriveGroupState (group, commandStates) {
    let itemStates = group.items.map(item => this._deriveItemState(item, commandStates))
    let hasEnabledItem = itemStates.some(item => item.enabled || item.hasEnabledItem)
    return {
      item: group,
      itemStates,
      hasEnabledItem
    }
  }

  _deriveItemState (item, commandStates) {
    switch (item.type) {
      case 'command': {
        let commandState = commandStates[item.name] || DISABLED
        return {
          item,
          commandState,
          enabled: !commandState.disabled
        }
      }
      case 'group':
      case 'dropdown':
      case 'prompt':
      case 'switcher': {
        return this._deriveGroupState(item, commandStates)
      }
      case 'separator': {
        return { item }
      }
      default:
        throw new Error('Unsupported item type')
    }
  }

  _getClassNames () {
    return 'sc-tool-group'
  }

  _getToolClass (item) {
    // use an ToolClass from toolSpec if configured inline in ToolGroup spec
    let ToolClass
    if (item.ToolClass) {
      ToolClass = item.ToolClass
    } else {
      switch (item.type) {
        case 'command': {
          // try to use a tool registered by the same name as the command
          ToolClass = this.getComponent(item.name, 'no-throw')
          if (!ToolClass) {
            // using the default tool otherwise
            ToolClass = this.getComponent('tool')
          }
          break
        }
        case 'dropdown': {
          ToolClass = this.getComponent('tool-dropdown')
          break
        }
        case 'group': {
          ToolClass = this.getComponent('tool-group')
          break
        }
        case 'prompt': {
          ToolClass = this.getComponent('tool-prompt')
          break
        }
        case 'separator': {
          ToolClass = this.getComponent('tool-separator')
          break
        }
        case 'switcher': {
          ToolClass = this.getComponent('tool-switcher')
          break
        }
        default: {
          console.error('Unsupported item type inside ToolGroup:', item.type)
        }
      }
    }

    return ToolClass
  }
}
<|endoftext|>


<commit_before>$(function() {
    window.onload = function() {
    console.log("%c  ~~~  Bob v0.2 - Developed by d4rkd0s  ~~~  ", "color: #FFFFFF; font-size: 12px; background: #3F1338;");
    var game = new Phaser.Game(1156, 650, Phaser.AUTO, '', { preload: preload, create: create, update: update });
    function preload() {
        //setting up starting vars
        score = 0;
        console.log("%c   score: 0   ", "color: #FFFFFF; font-size: 12px; background: #FD8223;");
        horseHealth = 3;
        console.log("%c   horseHealth: 3   ", "color: #FFFFFF; font-size: 12px; background: #FD8223;");

        speed = 250;
        //game.load.image('bob', 'assets/images/bob.png');
        game.load.spritesheet('bob', 'assets/images/bob.png', 54, 80);
        console.log("%c   loaded: spritesheet   ", "color: #FFFFFF; font-size: 10px; background: #5CA6FF;");
        game.load.image('apple', 'assets/images/apple_red.png');
        game.load.image('background', 'assets/images/background.png');
        console.log("%c   loaded: background   ", "color: #FFFFFF; font-size: 10px; background: #5CA6FF;");
        //game.load.image('healthbar', 'assets/images/healthbar.png');
        //console.log("%c   loaded: healthbar   ", "color: #FFFFFF; font-size: 10px; background: #5CA6FF;");
        game.load.image('ocean', 'assets/images/ocean.png');
        console.log("%c   loaded: horse   ", "color: #FFFFFF; font-size: 10px; background: #5CA6FF;");
        game.load.image('horse', 'assets/images/horse.png');
        console.log("%c   set border: ocean   ", "color: #FFFFFF; font-size: 10px; background: #5CA6FF;");
        cursors = game.input.keyboard.createCursorKeys();
        console.log("%c   user input: enabled   ", "color: #FFFFFF; font-size: 10px; background: #5CA6FF;");
        game.load.audio('applesound', 'assets/sounds/apple.wav');
        game.load.audio('bobsound', 'assets/sounds/bob.wav')
        //walking case switch
        function coroutine(f) {
           var o = f(); // instantiate the coroutine
           o.next(); // execute until the first yield
           return function(x) {
                o.next(x);
            }
        }
        var clock = coroutine(function*(_) {
            while (true) {
                yield _;
                foot = 0;
                yield _;
                foot = 1;
            }
        });

        //walk step speed in ms
        setInterval(clock, 100);
        //notify user (console)
        console.log("%c   walking: enabled   ", "color: #FFFFFF; font-size: 10px; background: #5CA6FF;");
    }//preload

    function create() {

        //  A simple background for our game
        game.add.sprite(0, 0, 'background');
        console.log("%c   spawned: background   ", "color: #FFFFFF; font-size: 10px; background: #FCD22F;");
        //Game Objects
        player = game.add.sprite(775, game.world.height - 150, 'bob');
        console.log("%c   spawned: player   ", "color: #FFFFFF; font-size: 10px; background: #FCD22F;");
        apple = game.add.sprite(100, 200, 'apple');

        //var healthbar = game.add.sprite(0,0,'healthbar');
        //healthbar.cropEnabled = true;
        //healthbar.crop.width = (character.health / character.maxHealth) * healthbar.width

        //text = "Score: " . score;
        //style = { font: "32px Arial", fill: "#3D4185", align: "center" };
        //game.add.text(game.world.centerX-300, 0, text, style);
        //sound
        applesound = game.add.audio('applesound');
        applesound.allowMultiple = true;

        bobsound = game.add.audio('bobsound');
        bobsound.allowMultiple = true;

        ocean = game.add.sprite(0, game.world.height - 484, 'ocean');
        console.log("%c   spawned: border(ocean)   ", "color: #FFFFFF; font-size: 10px; background: #FCD22F;");

        //add horse
        horse = game.add.sprite(450, game.world.height - 300, 'horse');

        //ocean
        game.physics.enable(ocean, Phaser.Physics.ARCADE);
        console.log("%c   physics: enabled(ocean)   ", "color: #FFFFFF; font-size: 10px; background: #83CB53;");
        ocean.body.immovable = true;
        console.log("%c   locked: border(ocean)   ", "color: #FFFFFF; font-size: 10px; background: #A40E38;");

        //start physics
        game.physics.startSystem(Phaser.Physics.ARCADE);
        console.log("%c   physics: enabled(player)   ", "color: #FFFFFF; font-size: 10px; background: #83CB53;");
        game.physics.arcade.enable(player);
        game.physics.arcade.enableBody(player);
        console.log("%c   physics: bounds(player)   ", "color: #FFFFFF; font-size: 10px; background: #83CB53;");
        game.physics.arcade.enable(horse);
        game.physics.arcade.enableBody(horse);
        game.physics.arcade.enable(apple);
        game.physics.arcade.enableBody(apple);
        player.body.collideWorldBounds = true;
        horse.body.collideWorldBounds = true;
        apple.body.collideWorldBounds = true;
        console.log("%c   collideWorldBounds: enabled   ", "color: #FFFFFF; font-size: 10px; background: #83CB53;");
    }//create()

    function update() {

        //ocean collision
        game.physics.arcade.collide(player, ocean);
        game.physics.arcade.collide(player, horse);
        game.physics.arcade.collide(ocean, apple);
        game.physics.arcade.collide(horse, ocean);
        //horse.body.accelerateToObject(horse, player, 600, 250, 250);

        //  Reset the players velocity (movement)
        player.body.velocity.x = 0;
        player.body.velocity.y = 0;

        if ( horseHealth >= 3 ){
            horse.velocity = game.physics.arcade.accelerateToObject(horse, apple, 50, 50, 50);
        }
        if ( horseHealth == 2 ){
            horse.velocity = game.physics.arcade.accelerateToObject(horse, apple, 100, 100, 100);
        }
        if ( horseHealth == 1 ){
            horse.velocity = game.physics.arcade.accelerateToObject(horse, apple, 200, 200, 200);
        }

        if ( apple.alive == true){
            if ( game.physics.arcade.overlap(apple, player) == true ){
                score = score + 1;
                bobsound.play();
                $( "#score" ).text("Score: " + score);
                apple.kill();
                console.log("Score: " + score);
            }
            if ( game.physics.arcade.collide(apple, horse) == true ){
                horseHealth = horseHealth - 1;
                if ( horseHealth == 1 ){
                    $( "#horseHealth" ).text(horseHealth + " apple until your horse dies!");
                }
                else{
                    $( "#horseHealth" ).text(horseHealth + " apples until your horse dies!");
                }
                applesound.play();
                apple.kill();
                if ( horseHealth == 0 ){
                    $( "#score" ).text("Final Score: " + score);
                    $( "#horseHealth" ).text("Your horse has died!");
                    game.physics.destroy();
                }
                console.log("horseHealth: " + horseHealth);
            }
        }//apple alive
        else{
            randX = Math.floor(Math.random()*(800-50+1)+50);
            randY = Math.floor(Math.random()*(550-180+1)+180);
            if ( game.physics.arcade.overlap(apple, horse) == true ){
                console.log("Apple spawned on horse, regenerating randX and randY");
                randX = Math.floor(Math.random()*(800-50+1)+50);
                randY = Math.floor(Math.random()*(550-180+1)+180);
                apple.kill();
            }
            else{
                console.log("Apple is clear of horse, spawned apple.");
                apple = game.add.sprite(randX, randY, 'apple');
                game.physics.arcade.enable(apple);
                game.physics.arcade.enableBody(apple);
                apple.body.collideWorldBounds = true;
                game.physics.arcade.collide(player, apple);
                game.physics.arcade.collide(ocean, apple);
            }

        }//dead apple

        if (cursors.left.isDown)
        {
            if (cursors.up.isDown)
            {
                //  Move to the left+up
                player.body.velocity.x = -speed;
                player.body.velocity.y = -speed;
                if ( foot == 0 ){
                    player.frame = 4;
                }
                if ( foot == 1 ){
                   player.frame = 5;
                }
            }
            else if (cursors.down.isDown)
            {
                //  Move to the left+down
                player.body.velocity.x = -speed;
                player.body.velocity.y = speed;
                if ( foot == 0 ){
                    player.frame = 4;
                }
                if ( foot == 1 ){
                   player.frame = 5;
                }
            }
            else
            {
                //  Move to the left
                player.body.velocity.x = -speed*2;
                if ( foot == 0 ){
                    player.frame = 4;
                }
                if ( foot == 1 ){
                   player.frame = 5;
                }
            }

        }

        else if (cursors.right.isDown)
        {
            if (cursors.up.isDown)
            {
                //  Move to the right+up
                player.body.velocity.x = speed;
                player.body.velocity.y = -speed;
                if ( foot == 0 ){
                    player.frame = 6;
                }
                if ( foot == 1 ){
                   player.frame = 7;
                }
            }
            else if (cursors.down.isDown)
            {
                //  Move to the right+down
                player.body.velocity.x = speed;
                player.body.velocity.y = speed;
                if ( foot == 0 ){
                    player.frame = 6;
                }
                if ( foot == 1 ){
                   player.frame = 7;
                }
            }
            else
            {
                //  Move to the right
                player.body.velocity.x = speed*2;
                if ( foot == 0 ){
                    player.frame = 6;
                }
                if ( foot == 1 ){
                   player.frame = 7;
                }
            }

        }
        else if (cursors.up.isDown)
        {
            //  Move to the up
            player.body.velocity.y = -speed;
            if ( foot == 0 ){
               player.frame = 2;
            }
            if ( foot == 1 ){
               player.frame = 3;
            }
        }
        else if (cursors.down.isDown)
        {
            //  Move to the down
            player.body.velocity.y = speed;
            if ( foot == 0 ){
               player.frame = 0;
            }
            if ( foot == 1 ){
               player.frame = 1;
            }

        }

        } //update

};
});<commit_msg>Faster as you score!<commit_after>$(function() {
    window.onload = function() {
    console.log("%c  ~~~  Bob v0.2 - Developed by d4rkd0s  ~~~  ", "color: #FFFFFF; font-size: 12px; background: #3F1338;");
    var game = new Phaser.Game(1156, 650, Phaser.AUTO, '', { preload: preload, create: create, update: update });
    function preload() {
        //setting up starting vars
        score = 0;
        console.log("%c   score: 0   ", "color: #FFFFFF; font-size: 12px; background: #FD8223;");
        horseHealth = 3;
        console.log("%c   horseHealth: 3   ", "color: #FFFFFF; font-size: 12px; background: #FD8223;");

        speed = 250;
        //game.load.image('bob', 'assets/images/bob.png');
        game.load.spritesheet('bob', 'assets/images/bob.png', 54, 80);
        console.log("%c   loaded: spritesheet   ", "color: #FFFFFF; font-size: 10px; background: #5CA6FF;");
        game.load.image('apple', 'assets/images/apple_red.png');
        game.load.image('background', 'assets/images/background.png');
        console.log("%c   loaded: background   ", "color: #FFFFFF; font-size: 10px; background: #5CA6FF;");
        //game.load.image('healthbar', 'assets/images/healthbar.png');
        //console.log("%c   loaded: healthbar   ", "color: #FFFFFF; font-size: 10px; background: #5CA6FF;");
        game.load.image('ocean', 'assets/images/ocean.png');
        console.log("%c   loaded: horse   ", "color: #FFFFFF; font-size: 10px; background: #5CA6FF;");
        game.load.image('horse', 'assets/images/horse.png');
        console.log("%c   set border: ocean   ", "color: #FFFFFF; font-size: 10px; background: #5CA6FF;");
        cursors = game.input.keyboard.createCursorKeys();
        console.log("%c   user input: enabled   ", "color: #FFFFFF; font-size: 10px; background: #5CA6FF;");
        game.load.audio('applesound', 'assets/sounds/apple.wav');
        game.load.audio('bobsound', 'assets/sounds/bob.wav')
        //walking case switch
        function coroutine(f) {
           var o = f(); // instantiate the coroutine
           o.next(); // execute until the first yield
           return function(x) {
                o.next(x);
            }
        }
        var clock = coroutine(function*(_) {
            while (true) {
                yield _;
                foot = 0;
                yield _;
                foot = 1;
            }
        });

        //walk step speed in ms
        setInterval(clock, 100);
        //notify user (console)
        console.log("%c   walking: enabled   ", "color: #FFFFFF; font-size: 10px; background: #5CA6FF;");
    }//preload

    function create() {

        //  A simple background for our game
        game.add.sprite(0, 0, 'background');
        console.log("%c   spawned: background   ", "color: #FFFFFF; font-size: 10px; background: #FCD22F;");
        //Game Objects
        player = game.add.sprite(775, game.world.height - 150, 'bob');
        console.log("%c   spawned: player   ", "color: #FFFFFF; font-size: 10px; background: #FCD22F;");
        apple = game.add.sprite(100, 200, 'apple');

        //var healthbar = game.add.sprite(0,0,'healthbar');
        //healthbar.cropEnabled = true;
        //healthbar.crop.width = (character.health / character.maxHealth) * healthbar.width

        //text = "Score: " . score;
        //style = { font: "32px Arial", fill: "#3D4185", align: "center" };
        //game.add.text(game.world.centerX-300, 0, text, style);
        //sound
        applesound = game.add.audio('applesound');
        applesound.allowMultiple = true;

        bobsound = game.add.audio('bobsound');
        bobsound.allowMultiple = true;

        ocean = game.add.sprite(0, game.world.height - 484, 'ocean');
        console.log("%c   spawned: border(ocean)   ", "color: #FFFFFF; font-size: 10px; background: #FCD22F;");

        //add horse
        horse = game.add.sprite(450, game.world.height - 300, 'horse');

        //ocean
        game.physics.enable(ocean, Phaser.Physics.ARCADE);
        console.log("%c   physics: enabled(ocean)   ", "color: #FFFFFF; font-size: 10px; background: #83CB53;");
        ocean.body.immovable = true;
        console.log("%c   locked: border(ocean)   ", "color: #FFFFFF; font-size: 10px; background: #A40E38;");

        //start physics
        game.physics.startSystem(Phaser.Physics.ARCADE);
        console.log("%c   physics: enabled(player)   ", "color: #FFFFFF; font-size: 10px; background: #83CB53;");
        game.physics.arcade.enable(player);
        game.physics.arcade.enableBody(player);
        console.log("%c   physics: bounds(player)   ", "color: #FFFFFF; font-size: 10px; background: #83CB53;");
        game.physics.arcade.enable(horse);
        game.physics.arcade.enableBody(horse);
        game.physics.arcade.enable(apple);
        game.physics.arcade.enableBody(apple);
        player.body.collideWorldBounds = true;
        horse.body.collideWorldBounds = true;
        apple.body.collideWorldBounds = true;
        console.log("%c   collideWorldBounds: enabled   ", "color: #FFFFFF; font-size: 10px; background: #83CB53;");
    }//create()

    function update() {

        //ocean collision
        game.physics.arcade.collide(player, ocean);
        game.physics.arcade.collide(player, horse);
        game.physics.arcade.collide(ocean, apple);
        game.physics.arcade.collide(horse, ocean);
        //horse.body.accelerateToObject(horse, player, 600, 250, 250);

        //  Reset the players velocity (movement)
        player.body.velocity.x = 0;
        player.body.velocity.y = 0;

        //move mr.horse
        horse.velocity = game.physics.arcade.accelerateToObject(horse, apple, 50+(score*10), 50+(score*10), 50+(score*10));

        if ( apple.alive == true){
            if ( game.physics.arcade.overlap(apple, player) == true ){
                score = score + 1;
                bobsound.play();
                $( "#score" ).text("Score: " + score);
                apple.kill();
                console.log("Score: " + score);
            }
            if ( game.physics.arcade.collide(apple, horse) == true ){
                horseHealth = horseHealth - 1;
                if ( horseHealth == 1 ){
                    $( "#horseHealth" ).text(horseHealth + " apple until your horse dies!");
                }
                else{
                    $( "#horseHealth" ).text(horseHealth + " apples until your horse dies!");
                }
                applesound.play();
                apple.kill();
                if ( horseHealth == 0 ){
                    $( "#score" ).text("Final Score: " + score);
                    $( "#horseHealth" ).text("Your horse has died!");
                    game.physics.destroy();
                }
                console.log("horseHealth: " + horseHealth);
            }
        }//apple alive
        else{
            randX = Math.floor(Math.random()*(800-50+1)+50);
            randY = Math.floor(Math.random()*(550-180+1)+180);
            if ( game.physics.arcade.overlap(apple, horse) == true ){
                console.log("Apple spawned on horse, regenerating randX and randY");
                randX = Math.floor(Math.random()*(800-50+1)+50);
                randY = Math.floor(Math.random()*(550-180+1)+180);
                apple.kill();
            }
            else{
                console.log("Apple is clear of horse, spawned apple.");
                apple = game.add.sprite(randX, randY, 'apple');
                game.physics.arcade.enable(apple);
                game.physics.arcade.enableBody(apple);
                apple.body.collideWorldBounds = true;
                game.physics.arcade.collide(player, apple);
                game.physics.arcade.collide(ocean, apple);
            }

        }//dead apple

        if (cursors.left.isDown)
        {
            if (cursors.up.isDown)
            {
                //  Move to the left+up
                player.body.velocity.x = -speed;
                player.body.velocity.y = -speed;
                if ( foot == 0 ){
                    player.frame = 4;
                }
                if ( foot == 1 ){
                   player.frame = 5;
                }
            }
            else if (cursors.down.isDown)
            {
                //  Move to the left+down
                player.body.velocity.x = -speed;
                player.body.velocity.y = speed;
                if ( foot == 0 ){
                    player.frame = 4;
                }
                if ( foot == 1 ){
                   player.frame = 5;
                }
            }
            else
            {
                //  Move to the left
                player.body.velocity.x = -speed*2;
                if ( foot == 0 ){
                    player.frame = 4;
                }
                if ( foot == 1 ){
                   player.frame = 5;
                }
            }

        }

        else if (cursors.right.isDown)
        {
            if (cursors.up.isDown)
            {
                //  Move to the right+up
                player.body.velocity.x = speed;
                player.body.velocity.y = -speed;
                if ( foot == 0 ){
                    player.frame = 6;
                }
                if ( foot == 1 ){
                   player.frame = 7;
                }
            }
            else if (cursors.down.isDown)
            {
                //  Move to the right+down
                player.body.velocity.x = speed;
                player.body.velocity.y = speed;
                if ( foot == 0 ){
                    player.frame = 6;
                }
                if ( foot == 1 ){
                   player.frame = 7;
                }
            }
            else
            {
                //  Move to the right
                player.body.velocity.x = speed*2;
                if ( foot == 0 ){
                    player.frame = 6;
                }
                if ( foot == 1 ){
                   player.frame = 7;
                }
            }

        }
        else if (cursors.up.isDown)
        {
            //  Move to the up
            player.body.velocity.y = -speed;
            if ( foot == 0 ){
               player.frame = 2;
            }
            if ( foot == 1 ){
               player.frame = 3;
            }
        }
        else if (cursors.down.isDown)
        {
            //  Move to the down
            player.body.velocity.y = speed;
            if ( foot == 0 ){
               player.frame = 0;
            }
            if ( foot == 1 ){
               player.frame = 1;
            }

        }

        } //update

};
});<|endoftext|>