<commit_before>/*
 * MelonJS Game Engine
 * Copyright (C) 2011 - 2013, Olivier BIOT
 * http://www.melonjs.org
 *
 */
(function () {
    /**
     * a generic 2D Vector Object
     * @class
     * @extends Object
     * @memberOf me
     * @constructor
     * @param {Number} [x=0] x value of the vector
     * @param {Number} [y=0] y value of the vector
     */
    me.Vector2d = Object.extend(
    /** @scope me.Vector2d.prototype */
    {
        /** @ignore */
        init : function (x, y) {
            return this.set(x || 0, y || 0);
        },

        /**
         * set the Vector x and y properties to the given values

         * @name set
         * @memberOf me.Vector2d
         * @function
         * @param {Number} x
         * @param {Number} y
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        set : function (x, y) {
            if (x !== +x || y !== +y) {
                throw new me.Vector2d.Error(
                    "invalid x,y parameters (not a number)"
                );
            }

            /**
             * x value of the vector
             * @public
             * @type Number
             * @name x
             * @memberOf me.Vector2d
             */
            this.x = x;

            /**
             * y value of the vector
             * @public
             * @type Number
             * @name y
             * @memberOf me.Vector2d
             */
            this.y = y;

            return this;
        },

        /**
         * set the Vector x and y properties to 0
         * @name setZero
         * @memberOf me.Vector2d
         * @function
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        setZero : function () {
            return this.set(0, 0);
        },

        /**
         * set the Vector x and y properties using the passed vector
         * @name setV
         * @memberOf me.Vector2d
         * @function
         * @param {me.Vector2d} v
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        setV : function (v) {
            this.x = v.x;
            this.y = v.y;
            return this;
        },

        /**
         * Add the passed vector to this vector
         * @name add
         * @memberOf me.Vector2d
         * @function
         * @param {me.Vector2d} v
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        add : function (v) {
            this.x += v.x;
            this.y += v.y;
            return this;
        },

        /**
         * Substract the passed vector to this vector
         * @name sub
         * @memberOf me.Vector2d
         * @function
         * @param {me.Vector2d} v
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        sub : function (v) {
            this.x -= v.x;
            this.y -= v.y;
            return this;
        },

        /**
         * Multiply this vector values by the given scalar
         * @name scale
         * @memberOf me.Vector2d
         * @function
         * @param {Number} x
         * @param {Number} [y=x]
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        scale : function (x, y) {
            this.x *= x;
            this.y *= typeof (y) !== "undefined" ? y : x;
            return this;
        },

        /**
         * Multiply this vector values by the passed vector
         * @name scaleV
         * @memberOf me.Vector2d
         * @function
         * @param {me.Vector2d} v
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        scaleV : function (v) {
            this.x *= v.x;
            this.y *= v.y;
            return this;
        },

        /**
         * Divide this vector values by the passed value
         * @name div
         * @memberOf me.Vector2d
         * @function
         * @param {Number} value
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        div : function (n) {
            this.x /= n;
            this.y /= n;
            return this;
        },

        /**
         * Update this vector values to absolute values
         * @name abs
         * @memberOf me.Vector2d
         * @function
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        abs : function () {
            if (this.x < 0) {
                this.x = -this.x;
            }
            if (this.y < 0) {
                this.y = -this.y;
            }
            return this;
        },

        /**
         * Clamp the vector value within the specified value range
         * @name clamp
         * @memberOf me.Vector2d
         * @function
         * @param {Number} low
         * @param {Number} high
         * @return {me.Vector2d} new me.Vector2d
         */
        clamp : function (low, high) {
            return new me.Vector2d(this.x.clamp(low, high), this.y.clamp(low, high));
        },

        /**
         * Clamp this vector value within the specified value range
         * @name clampSelf
         * @memberOf me.Vector2d
         * @function
         * @param {Number} low
         * @param {Number} high
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        clampSelf : function (low, high) {
            this.x = this.x.clamp(low, high);
            this.y = this.y.clamp(low, high);
            return this;
        },

        /**
         * Update this vector with the minimum value between this and the passed vector
         * @name minV
         * @memberOf me.Vector2d
         * @function
         * @param {me.Vector2d} v
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        minV : function (v) {
            this.x = this.x < v.x ? this.x : v.x;
            this.y = this.y < v.y ? this.y : v.y;
            return this;
        },

        /**
         * Update this vector with the maximum value between this and the passed vector
         * @name maxV
         * @memberOf me.Vector2d
         * @function
         * @param {me.Vector2d} v
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        maxV : function (v) {
            this.x = this.x > v.x ? this.x : v.x;
            this.y = this.y > v.y ? this.y : v.y;
            return this;
        },

        /**
         * Floor the vector values
         * @name floor
         * @memberOf me.Vector2d
         * @function
         * @return {me.Vector2d} new me.Vector2d
         */
        floor : function () {
            return new me.Vector2d(~~this.x, ~~this.y);
        },

        /**
         * Floor this vector values
         * @name floorSelf
         * @memberOf me.Vector2d
         * @function
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        floorSelf : function () {
            this.x = ~~this.x;
            this.y = ~~this.y;
            return this;
        },

        /**
         * Ceil the vector values
         * @name ceil
         * @memberOf me.Vector2d
         * @function
         * @return {me.Vector2d} new me.Vector2d
         */
        ceil : function () {
            return new me.Vector2d(Math.ceil(this.x), Math.ceil(this.y));
        },

        /**
         * Ceil this vector values
         * @name ceilSelf
         * @memberOf me.Vector2d
         * @function
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        ceilSelf : function () {
            this.x = Math.ceil(this.x);
            this.y = Math.ceil(this.y);
            return this;
        },

        /**
         * Negate the vector values
         * @name negate
         * @memberOf me.Vector2d
         * @function
         * @return {me.Vector2d} new me.Vector2d
         */
        negate : function () {
            return new me.Vector2d(-this.x, -this.y);
        },

        /**
         * Negate this vector values
         * @name negateSelf
         * @memberOf me.Vector2d
         * @function
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        negateSelf : function () {
            this.x = -this.x;
            this.y = -this.y;
            return this;
        },

        /**
         * Copy the x,y values of the passed vector to this one
         * @name copy
         * @memberOf me.Vector2d
         * @function
         * @param {me.Vector2d} v
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        copy : function (v) {
            this.x = v.x;
            this.y = v.y;
            return this;
        },

        /**
         * return true if the two vectors are the same
         * @name equals
         * @memberOf me.Vector2d
         * @function
         * @param {me.Vector2d} v
         * @return {Boolean}
         */
        equals : function (v) {
            return ((this.x === v.x) && (this.y === v.y));
        },

        /**
         * return the length (magnitude) of this vector
         * @name length
         * @memberOf me.Vector2d
         * @function
         * @return {Number}
         */
        length : function () {
            return Math.sqrt(this.x * this.x + this.y * this.y);
        },

        /**
         * normalize this vector (scale the vector so that its magnitude is 1)
         * @name normalize
         * @memberOf me.Vector2d
         * @function
         * @return {Number}
         */
        normalize : function () {
            var len = this.length();
            // some limit test
            if (len < Number.MIN_VALUE) {
                return 0.0;
            }
            var invL = 1.0 / len;
            this.x *= invL;
            this.y *= invL;
            return len;
        },

        /**
         * return the dot product of this vector and the passed one
         * @name dotProduct
         * @memberOf me.Vector2d
         * @function
         * @param {me.Vector2d} v
         * @return {Number}
         */
        dotProduct : function (/**me.Vector2d*/ v) {
            return this.x * v.x + this.y * v.y;
        },

        /**
         * return the distance between this vector and the passed one
         * @name distance
         * @memberOf me.Vector2d
         * @function
         * @param {me.Vector2d} v
         * @return {Number}
         */
        distance : function (v) {
            return Math.sqrt((this.x - v.x) * (this.x - v.x) + (this.y - v.y) * (this.y - v.y));
        },

        /**
         * return the angle between this vector and the passed one
         * @name angle
         * @memberOf me.Vector2d
         * @function
         * @param {me.Vector2d} v
         * @return {Number} angle in radians
         */
        angle : function (v) {
            return Math.atan2((v.y - this.y), (v.x - this.x));
        },

        /**
         * return a clone copy of this vector
         * @name clone
         * @memberOf me.Vector2d
         * @function
         * @return {me.Vector2d} new me.Vector2d
         */
        clone : function () {
            return new me.Vector2d(this.x, this.y);
        },

        /**
         * convert the object to a string representation
         * @name toString
         * @memberOf me.Vector2d
         * @function
         * @return {String}
         */
        toString : function () {
            return "x:" + this.x + ",y:" + this.y;
        }
    });

    /**
     * Base class for Vector2d exception handling.
     * @name Error
     * @memberOf me.Vector2d
     * @constructor
     * @param {String} msg Error message.
     */
    me.Vector2d.Error = me.Error.extend({
        init : function (msg) {
            this._super(me.Error, "init", [ msg ]);
            this.name = "me.Vector2d.Error";
        }
    });
})();
<commit_msg>extended the set of functions for `me.Vector2d`<commit_after>/*
 * MelonJS Game Engine
 * Copyright (C) 2011 - 2013, Olivier BIOT
 * http://www.melonjs.org
 *
 */
(function () {
    /**
     * a generic 2D Vector Object
     * @class
     * @extends Object
     * @memberOf me
     * @constructor
     * @param {Number} [x=0] x value of the vector
     * @param {Number} [y=0] y value of the vector
     */
    me.Vector2d = Object.extend(
    /** @scope me.Vector2d.prototype */
    {
        /** @ignore */
        init : function (x, y) {
            return this.set(x || 0, y || 0);
        },

        /**
         * set the Vector x and y properties to the given values

         * @name set
         * @memberOf me.Vector2d
         * @function
         * @param {Number} x
         * @param {Number} y
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        set : function (x, y) {
            if (x !== +x || y !== +y) {
                throw new me.Vector2d.Error(
                    "invalid x,y parameters (not a number)"
                );
            }

            /**
             * x value of the vector
             * @public
             * @type Number
             * @name x
             * @memberOf me.Vector2d
             */
            this.x = x;

            /**
             * y value of the vector
             * @public
             * @type Number
             * @name y
             * @memberOf me.Vector2d
             */
            this.y = y;

            return this;
        },

        /**
         * set the Vector x and y properties to 0
         * @name setZero
         * @memberOf me.Vector2d
         * @function
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        setZero : function () {
            return this.set(0, 0);
        },

        /**
         * set the Vector x and y properties using the passed vector
         * @name setV
         * @memberOf me.Vector2d
         * @function
         * @param {me.Vector2d} v
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        setV : function (v) {
            this.x = v.x;
            this.y = v.y;
            return this;
        },

        /**
         * Add the passed vector to this vector
         * @name add
         * @memberOf me.Vector2d
         * @function
         * @param {me.Vector2d} v
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        add : function (v) {
            this.x += v.x;
            this.y += v.y;
            return this;
        },

        /**
         * Substract the passed vector to this vector
         * @name sub
         * @memberOf me.Vector2d
         * @function
         * @param {me.Vector2d} v
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        sub : function (v) {
            this.x -= v.x;
            this.y -= v.y;
            return this;
        },

        /**
         * Multiply this vector values by the given scalar
         * @name scale
         * @memberOf me.Vector2d
         * @function
         * @param {Number} x
         * @param {Number} [y=x]
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        scale : function (x, y) {
            this.x *= x;
            this.y *= typeof (y) !== "undefined" ? y : x;
            return this;
        },

        /**
         * Multiply this vector values by the passed vector
         * @name scaleV
         * @memberOf me.Vector2d
         * @function
         * @param {me.Vector2d} v
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        scaleV : function (v) {
            this.x *= v.x;
            this.y *= v.y;
            return this;
        },

        /**
         * Divide this vector values by the passed value
         * @name div
         * @memberOf me.Vector2d
         * @function
         * @param {Number} value
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        div : function (n) {
            this.x /= n;
            this.y /= n;
            return this;
        },

        /**
         * Update this vector values to absolute values
         * @name abs
         * @memberOf me.Vector2d
         * @function
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        abs : function () {
            if (this.x < 0) {
                this.x = -this.x;
            }
            if (this.y < 0) {
                this.y = -this.y;
            }
            return this;
        },

        /**
         * Clamp the vector value within the specified value range
         * @name clamp
         * @memberOf me.Vector2d
         * @function
         * @param {Number} low
         * @param {Number} high
         * @return {me.Vector2d} new me.Vector2d
         */
        clamp : function (low, high) {
            return new me.Vector2d(this.x.clamp(low, high), this.y.clamp(low, high));
        },

        /**
         * Clamp this vector value within the specified value range
         * @name clampSelf
         * @memberOf me.Vector2d
         * @function
         * @param {Number} low
         * @param {Number} high
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        clampSelf : function (low, high) {
            this.x = this.x.clamp(low, high);
            this.y = this.y.clamp(low, high);
            return this;
        },

        /**
         * Update this vector with the minimum value between this and the passed vector
         * @name minV
         * @memberOf me.Vector2d
         * @function
         * @param {me.Vector2d} v
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        minV : function (v) {
            this.x = this.x < v.x ? this.x : v.x;
            this.y = this.y < v.y ? this.y : v.y;
            return this;
        },

        /**
         * Update this vector with the maximum value between this and the passed vector
         * @name maxV
         * @memberOf me.Vector2d
         * @function
         * @param {me.Vector2d} v
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        maxV : function (v) {
            this.x = this.x > v.x ? this.x : v.x;
            this.y = this.y > v.y ? this.y : v.y;
            return this;
        },

        /**
         * Floor the vector values
         * @name floor
         * @memberOf me.Vector2d
         * @function
         * @return {me.Vector2d} new me.Vector2d
         */
        floor : function () {
            return new me.Vector2d(~~this.x, ~~this.y);
        },

        /**
         * Floor this vector values
         * @name floorSelf
         * @memberOf me.Vector2d
         * @function
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        floorSelf : function () {
            this.x = ~~this.x;
            this.y = ~~this.y;
            return this;
        },

        /**
         * Ceil the vector values
         * @name ceil
         * @memberOf me.Vector2d
         * @function
         * @return {me.Vector2d} new me.Vector2d
         */
        ceil : function () {
            return new me.Vector2d(Math.ceil(this.x), Math.ceil(this.y));
        },

        /**
         * Ceil this vector values
         * @name ceilSelf
         * @memberOf me.Vector2d
         * @function
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        ceilSelf : function () {
            this.x = Math.ceil(this.x);
            this.y = Math.ceil(this.y);
            return this;
        },

        /**
         * Negate the vector values
         * @name negate
         * @memberOf me.Vector2d
         * @function
         * @return {me.Vector2d} new me.Vector2d
         */
        negate : function () {
            return new me.Vector2d(-this.x, -this.y);
        },

        /**
         * Negate this vector values
         * @name negateSelf
         * @memberOf me.Vector2d
         * @function
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        negateSelf : function () {
            this.x = -this.x;
            this.y = -this.y;
            return this;
        },

        /**
         * Copy the x,y values of the passed vector to this one
         * @name copy
         * @memberOf me.Vector2d
         * @function
         * @param {me.Vector2d} v
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        copy : function (v) {
            this.x = v.x;
            this.y = v.y;
            return this;
        },

        /**
         * return true if the two vectors are the same
         * @name equals
         * @memberOf me.Vector2d
         * @function
         * @param {me.Vector2d} v
         * @return {Boolean}
         */
        equals : function (v) {
            return ((this.x === v.x) && (this.y === v.y));
        },

        /**
         * normalize this vector (scale the vector so that its magnitude is 1)
         * @name normalize
         * @memberOf me.Vector2d
         * @function
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        normalize : function () {
            var d = this.length();
            if (d > 0) {
                this.x = this.x / d;
                this.y = this.y / d;
            }
            return this;
        },

        /**
         * change this vector to be perpendicular to what it was before.

         * (Effectively rotates it 90 degrees in a clockwise direction)
         * @name perp
         * @memberOf me.Vector2d
         * @function
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        perp : function () {
            var x = this.x;
            this.x = this.y;
            this.y = -x;
            return this;
        },

        /**
         * Rotate this vector (counter-clockwise) by the specified angle (in radians).
         * @name rotate
         * @memberOf me.Vector2d
         * @function
         * @param {number} angle The angle to rotate (in radians)
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        rotate : function (angle) {
            var x = this.x;
            var y = this.y;
            this.x = x * Math.cos(angle) - y * Math.sin(angle);
            this.y = x * Math.sin(angle) + y * Math.cos(angle);
            return this;
        },

         /**
         * Reverse this vector.
         * @name reverse
         * @memberOf me.Vector2d
         * @function
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        reverse : function () {
            this.x = -this.x;
            this.y = -this.y;
            return this;
        },

        /**
         * return the dot product of this vector and the passed one
         * @name dotProduct
         * @memberOf me.Vector2d
         * @function
         * @param {me.Vector2d} v
         * @return {Number} The dot product.
         */
        dotProduct : function (v) {
            return this.x * v.x + this.y * v.y;
        },

       /**
         * return the square length of this vector
         * @name length2
         * @memberOf me.Vector2d
         * @function
         * @return {Number} The length^2 of this vector.
         */
        length2 : function () {
            return this.dotProduct(this);
        },

        /**
         * return the length (magnitude) of this vector
         * @name length
         * @memberOf me.Vector2d
         * @function
         * @return {Number} the length of this vector
         */
        length : function () {
            return Math.sqrt(this.length2());
        },

        /**
         * return the distance between this vector and the passed one
         * @name distance
         * @memberOf me.Vector2d
         * @function
         * @param {me.Vector2d} v
         * @return {Number}
         */
        distance : function (v) {
            return Math.sqrt((this.x - v.x) * (this.x - v.x) + (this.y - v.y) * (this.y - v.y));
        },

        /**
         * return the angle between this vector and the passed one
         * @name angle
         * @memberOf me.Vector2d
         * @function
         * @param {me.Vector2d} v
         * @return {Number} angle in radians
         */
        angle : function (v) {
            return Math.atan2((v.y - this.y), (v.x - this.x));
        },

        /**
         * project this vector on to another vector.
         * @name project
         * @memberOf me.Vector2d
         * @function
         * @param {me.Vector2d} v The vector to project onto.
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        project : function (v) {
            var amt = this.dotProduct(v) / v.length2();
            this.x = amt * v.x;
            this.y = amt * v.y;
            return this;
        },

        /**
         * Project this vector onto a vector of unit length.

         * This is slightly more efficient than `project` when dealing with unit vectors.
         * @name projectN
         * @memberOf me.Vector2d
         * @function
         * @param {me.Vector2d} v The unit vector to project onto.
         * @return {me.Vector2d} Reference to this object for method chaining
         */
        projectN : function (v) {
            var amt = this.dotProduct(v);
            this.x = amt * v.x;
            this.y = amt * v.y;
            return this;
        },

        /**
         * Reflect this vector on an arbitrary axis.
         * @name reflect
         * @memberOf me.Vector2d
         * @function
         * @param {me.Vector2d} axis The vector representing the axis.
         * @return {me.Vector2d} Reference to this object for method chaining.
         */
        reflect : function (axis) {
            var x = this.x;
            var y = this.y;
            this.project(axis).scale(2);
            this.x -= x;
            this.y -= y;
            return this;
        },

        /**
         * Reflect this vector on an arbitrary axis (represented by a unit vector)

         * This is slightly more efficient than `reflect` when dealing with unit vectors.
         * @name reflectN
         * @memberOf me.Vector2d
         * @function
         * @param {me.Vector2d} axis The vector representing the axis.
         * @return {me.Vector2d} Reference to this object for method chaining.
         */
        reflectN : function (axis) {
            var x = this.x;
            var y = this.y;
            this.projectN(axis).scale(2);
            this.x -= x;
            this.y -= y;
            return this;
        },

        /**
         * return a clone copy of this vector
         * @name clone
         * @memberOf me.Vector2d
         * @function
         * @return {me.Vector2d} new me.Vector2d
         */
        clone : function () {
            return new me.Vector2d(this.x, this.y);
        },

        /**
         * convert the object to a string representation
         * @name toString
         * @memberOf me.Vector2d
         * @function
         * @return {String}
         */
        toString : function () {
            return "x:" + this.x + ",y:" + this.y;
        }
    });

    /**
     * Base class for Vector2d exception handling.
     * @name Error
     * @memberOf me.Vector2d
     * @constructor
     * @param {String} msg Error message.
     */
    me.Vector2d.Error = me.Error.extend({
        init : function (msg) {
            this._super(me.Error, "init", [ msg ]);
            this.name = "me.Vector2d.Error";
        }
    });
})();
<|endoftext|>


<commit_before>import { is } from '../utils'

export default {
  props: {
    src: {
      type: String,
      required: true
    },
    placeholder: {
      type: String
    },
    blur: {
      type: Number
    },
    noRatio: {
      type: Boolean
    }
  },

  data () {
    return {
      isRendered: false,
      options: {},
      defaultBlur: 20,
      image: null,
      placeholderImage: null,
      aspectRatio: 0.5625,
      isPollingKilled: false,
      cached: false
    }
  },

  watch: {
    src (value) {
      // this.image = null
      // this.placeholderImage = null
      // this.isRendered = false
      // this.isPollingKilled = false
      // this.cached = false

      this.handleImageLoading()
    }
  },

  computed: {
    shouldPlaceholderRender () {
      return !!this.placeholderImage
    },

    shouldImageRender () {
      return this.isRendered
    },

    wrapperStyle () {
      if (this.noRatio) {
        return {}
      }

      return {
        paddingBottom: `${this.aspectRatio * 100}%`
      }
    },

    blurStyle () {
      let blur = this.defaultBlur

      if (is(this.blur)) {
        return this.getBlurStyle(this.blur)
      }

      if (is(this.options.blur)) {
        return this.getBlurStyle(this.options.blur)
      }

      return this.getBlurStyle(blur)
    }
  },

  mounted () {
    this.handleImageLoading()
  },

  methods: {
    getBlurStyle (amount) {
      if (amount === 0) {
        return
      }

      return {
        filter: `blur(${amount}px)`
      }
    },

    defineAspectRatio (img) {
      const delay = this.options.timeout || 2500
      const pollInterval = this.options.pollInterval || 80

      const poll = setInterval(() => {
        if (!img.naturalWidth) {
          return
        }

        clearInterval(poll)

        const { naturalHeight, naturalWidth } = img

        this.aspectRatio = naturalHeight / naturalWidth
      }, pollInterval)

      setTimeout(() => {
        if (img.naturalWidth) {
          return
        }

        clearInterval(poll)
        this.isPollingKilled = true
      }, delay)
    },

    loadImage () {
      const image = new Image()
      const delay = this.options.delay || 0

      // reset the image holder
      this.image = null
      this.isRendered = false

      this.defineAspectRatio(image)

      image.onload = () => {
        if (this.image) {
          return
        }

        if (this.isPollingKilled) {
          this.defineAspectRatio(image)
        }

        // assign the image
        this.image = image.src

        // the drawImage it's a synchronous method, so when it's done
        // the nextTick will notify the view that we're ready
        // to fadeIn the main image
        const ctx = this.$refs.canvas.getContext('2d')
        ctx.drawImage(this.$refs.main, 0, 0)

        // next tick to know when the image is rendered
        this.$nextTick(() => {
          // timeout for a custom delay
          setTimeout(() => {
            this.isRendered = true
          }, delay)
        })

        // dispatches an event on image load
        this.$emit('onLoad', image.src)
      }

      image.src = this.src
    },

    loadPlaceholder () {
      if (!this.placeholder && !this.options.placeholder) {
        return
      }

      const image = new Image()
      let src = this.placeholder

      if (this.options.placeholder && !this.placeholder) {
        src = this.options.placeholder
      }

      image.onload = () => {
        this.placeholderImage = src

        // Dispatches an event on placeholder image load
        this.$emit('onLoadPlaceholder', src)
      }

      image.src = src
    },

    handleImageLoading () {
      this.loadPlaceholder()
      this.loadImage()
    }
  }
}
<commit_msg>style(image): remove comments<commit_after>import { is } from '../utils'

export default {
  props: {
    src: {
      type: String,
      required: true
    },
    placeholder: {
      type: String
    },
    blur: {
      type: Number
    },
    noRatio: {
      type: Boolean
    }
  },

  data () {
    return {
      isRendered: false,
      options: {},
      defaultBlur: 20,
      image: null,
      placeholderImage: null,
      aspectRatio: 0.5625,
      isPollingKilled: false,
      cached: false
    }
  },

  watch: {
    src (value) {
      this.handleImageLoading()
    }
  },

  computed: {
    shouldPlaceholderRender () {
      return !!this.placeholderImage
    },

    shouldImageRender () {
      return this.isRendered
    },

    wrapperStyle () {
      if (this.noRatio) {
        return {}
      }

      return {
        paddingBottom: `${this.aspectRatio * 100}%`
      }
    },

    blurStyle () {
      let blur = this.defaultBlur

      if (is(this.blur)) {
        return this.getBlurStyle(this.blur)
      }

      if (is(this.options.blur)) {
        return this.getBlurStyle(this.options.blur)
      }

      return this.getBlurStyle(blur)
    }
  },

  mounted () {
    this.handleImageLoading()
  },

  methods: {
    getBlurStyle (amount) {
      if (amount === 0) {
        return
      }

      return {
        filter: `blur(${amount}px)`
      }
    },

    defineAspectRatio (img) {
      const delay = this.options.timeout || 2500
      const pollInterval = this.options.pollInterval || 80

      const poll = setInterval(() => {
        if (!img.naturalWidth) {
          return
        }

        clearInterval(poll)

        const { naturalHeight, naturalWidth } = img

        this.aspectRatio = naturalHeight / naturalWidth
      }, pollInterval)

      setTimeout(() => {
        if (img.naturalWidth) {
          return
        }

        clearInterval(poll)
        this.isPollingKilled = true
      }, delay)
    },

    loadImage () {
      const image = new Image()
      const delay = this.options.delay || 0

      // reset the image holder
      this.image = null
      this.isRendered = false

      this.defineAspectRatio(image)

      image.onload = () => {
        if (this.image) {
          return
        }

        if (this.isPollingKilled) {
          this.defineAspectRatio(image)
        }

        // assign the image
        this.image = image.src

        // the drawImage it's a synchronous method, so when it's done
        // the nextTick will notify the view that we're ready
        // to fadeIn the main image
        const ctx = this.$refs.canvas.getContext('2d')
        ctx.drawImage(this.$refs.main, 0, 0)

        // next tick to know when the image is rendered
        this.$nextTick(() => {
          // timeout for a custom delay
          setTimeout(() => {
            this.isRendered = true
          }, delay)
        })

        // dispatches an event on image load
        this.$emit('onLoad', image.src)
      }

      image.src = this.src
    },

    loadPlaceholder () {
      if (!this.placeholder && !this.options.placeholder) {
        return
      }

      const image = new Image()
      let src = this.placeholder

      if (this.options.placeholder && !this.placeholder) {
        src = this.options.placeholder
      }

      image.onload = () => {
        this.placeholderImage = src

        // Dispatches an event on placeholder image load
        this.$emit('onLoadPlaceholder', src)
      }

      image.src = src
    },

    handleImageLoading () {
      this.loadPlaceholder()
      this.loadImage()
    }
  }
}
<|endoftext|>


<commit_before>/**
 * migrate.js
 */

import {
  getStorage, removeStorage, updateCommand,
} from "./browser.js";

/* constants */
import {EDITOR_EXEC, OPTIONS_OPEN} from "./constant.js";
const KEY_ACCESS = "accessKey";
const KEY_EDITOR = "editorShortCut";
const KEY_OPTIONS = "optionsShortCut";

/**
 * migrate old storage
 * @returns {Promise.<Array>} - results of each handler
 */
export const migrateStorage = async () => {
  const store = await getStorage([
    EDITOR_EXEC,
    KEY_ACCESS,
    KEY_EDITOR,
    KEY_OPTIONS,
    OPTIONS_OPEN,
  ]);
  const func = [];
  if (store[EDITOR_EXEC]) {
    const {value} = store[EDITOR_EXEC];
    await updateCommand(EDITOR_EXEC, value);
    func.push(removeStorage(EDITOR_EXEC));
  }
  if (store[OPTIONS_OPEN]) {
    const {value} = store[OPTIONS_OPEN];
    await updateCommand(OPTIONS_OPEN, value);
    func.push(removeStorage(OPTIONS_OPEN));
  }
  if (store[KEY_ACCESS]) {
    func.push(removeStorage(KEY_ACCESS));
  }
  if (store[KEY_EDITOR]) {
    func.push(removeStorage(KEY_EDITOR));
  }
  if (store[KEY_OPTIONS]) {
    func.push(removeStorage(KEY_OPTIONS));
  }
  return Promise.all(func);
};
<commit_msg>Update migrate.js<commit_after>/**
 * migrate.js
 */

import {
  getAllStorage, removeStorage, updateCommand,
} from "./browser.js";

/* constants */
import {EDITOR_EXEC, OPTIONS_OPEN} from "./constant.js";
const ENABLE_PB = "enablePB";
const KEY_ACCESS = "accessKey";
const KEY_EDITOR = "editorShortCut";
const KEY_OPTIONS = "optionsShortCut";

/**
 * migrate old storage
 * @returns {Promise.<Array>} - results of each handler
 */
export const migrateStorage = async () => {
  const store = await getAllStorage();
  const func = [];
  if (store[EDITOR_EXEC]) {
    const {value} = store[EDITOR_EXEC];
    await updateCommand(EDITOR_EXEC, value);
    func.push(removeStorage(EDITOR_EXEC));
  }
  if (store[OPTIONS_OPEN]) {
    const {value} = store[OPTIONS_OPEN];
    await updateCommand(OPTIONS_OPEN, value);
    func.push(removeStorage(OPTIONS_OPEN));
  }
  if (store[ENABLE_PB]) {
    func.push(removeStorage(ENABLE_PB));
  }
  if (store[KEY_ACCESS]) {
    func.push(removeStorage(KEY_ACCESS));
  }
  if (store[KEY_EDITOR]) {
    func.push(removeStorage(KEY_EDITOR));
  }
  if (store[KEY_OPTIONS]) {
    func.push(removeStorage(KEY_OPTIONS));
  }
  return Promise.all(func);
};
<|endoftext|>


<commit_before>
// TODO: consider having slightly different structure for chart components vs charts
//       **probably a bad idea... but worth a thought.  Now have 'layers' for easy tweaking of components
mc.models.axes = function axes(model) {

  model = model || {}

  //============================================================
  // Public Variables with Default Settings
  //------------------------------------------------------------

  model.renderBottom    = true
  model.renderTop       = false
  model.renderLeft      = true
  model.renderRight     = false

  //scales must be passed into axes component, top/bottom defaults to xScale, left/right defaults to yScale
  //model.bottom
  //model.top
  //model.left
  //model.right

  // Components
  model.bottomAxis      = d3.svg.axis()
  model.topAxis         = d3.svg.axis()
  model.leftAxis        = d3.svg.axis()
  model.rightAxis       = d3.svg.axis()

  // Accessors
  model.bottomLabel_    = d => d.xLabel || ''
  model.topLabel_       = d => d.xLabel || ''
  model.leftLabel_      = d => d.yLabel || ''
  model.rightLabel_     = d => d.yLabel || ''

  model.bottomTickSize_ = height => [-height, 1]
  model.topTickSize_    = height => [-height, 1]
  model.leftTickSize_   = width => [-width, 1]
  model.rightTickSize_  = width => [-width, 1]

  model.bottomTicks_    = width => [Math.round(width/80)]
  model.topTicks_       = width => [Math.round(width/80)]
  model.leftTicks_      = height => [Math.round(height/40)]
  model.rightTicks_     = height => [Math.round(height/40)]

  //TODO: make Label alignment an option

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

  chart.calc = function(instance, data) {
    //Currently no calculations in axes

    return chart;
  };

  chart.build = function(instance, data) {

    //TODO: FIGURE OUT WHAT SHOULD BE ON INSTANCE

    //TODO: Consider using a layer for each axis

    //TODO: assume all charts using axes model have inherited chartBase

    var container = d3.select(this);

    // Elements
    //TODO: axes wrap, etc. are likelt separate from parent chart's wrap/g so either don't store on 'instance' or use unique name //TODO: investigate, might be able to actuallly use paren;t wrap/g
    var wrap, wrapEnter, g, gEnter;

    // Assume scales are setup by parent model

    //------------------------------------------------------------
    // Setup Chart Layers

    //TODO: consider using only wrap/wrapEnter, no g/gEnter
    wrap      = container.selectAll('g.mc-axes').data([data]);
    wrapEnter = wrap.enter().append('g').attr('class', 'mc-axes');
    gEnter    = wrapEnter.append('g');
    g         = wrap.select('g');

    gEnter.append('g').attr('class', 'mc-axis mc-bottomAxis');
    gEnter.append('g').attr('class', 'mc-axis mc-topAxis');
    gEnter.append('g').attr('class', 'mc-axis mc-leftAxis');
    gEnter.append('g').attr('class', 'mc-axis mc-rightAxis');

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

    //------------------------------------------------------------
    // Bottom Axis

    if (model.renderBottom) {
      model.bottomAxis
        .scale(model.bottom || instance.x)
        .orient('bottom')
        ;
      model.bottomAxis
        .tickSize.apply(model.bottomAxis, model.bottomTickSize_(instance.height))
        ;
      model.bottomAxis
        .ticks.apply(model.bottomAxis, model.bottomTicks_(instance.width))
        ;
      gEnter.select('.mc-bottomAxis').append('g')
          .attr('class', 'x axis')  //TODO: mc- namespace these classes?
        .append('text')
          .attr('class', 'label')  //TODO: mc- namespace these classes?
          .attr('dx', -6)
          .attr('dy', -6)
          .style('text-anchor', 'end')
          ;
      g.select('.mc-bottomAxis .label')
          .attr('x', instance.width)
          .text(model.bottomLabel_);
          ;
      g.select('.mc-bottomAxis .x.axis')
          .attr('transform', 'translate(0,' + instance.height + ')')
          .call(model.bottomAxis)
          ;
    }

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

    //------------------------------------------------------------
    // Top Axis

    if (model.renderTop) {
      model.topAxis
        .scale(model.top || instance.x)
        .orient('top')
        ;
      model.topAxis
        .tickSize.apply(model.topAxis, model.topTickSize_(instance.height))
        ;
      model.topAxis
        .ticks.apply(model.topAxis, model.topTicks_(instance.width))
        ;
      gEnter.select('.mc-topAxis').append('g')
          .attr('class', 'x axis')
        .append('text')
          .attr('class', 'label')
          .attr('dy', '1em')
          .attr('dx', '-2em')
          .style('text-anchor', 'end')
          ;
      g.select('.mc-topAxis .label')
          .attr('x', instance.width)
          .text(model.topLabel_);
          ;
      g.select('.mc-topAxis .x.axis')
          //.attr('transform', 'translate(0,0)')
          .call(model.topAxis)
          ;
    }

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

    //------------------------------------------------------------
    // Left Axis

    if (model.renderLeft) {
      model.leftAxis
        .scale(model.left || instance.y)
        .orient('left')
        ;
      model.leftAxis
        .tickSize.apply(model.leftAxis, model.leftTickSize_(instance.width))
        ;
      model.leftAxis
        .ticks.apply(model.leftAxis, model.leftTicks_(instance.height))
        ;
      gEnter.select('.mc-leftAxis').append('g')
          .attr('class', 'y axis')
        .append('text')
          .attr('class', 'label')
          .attr('transform', 'rotate(90)')
          .attr('dx', 6)
          .attr('dy', -6)
          .style('text-anchor', 'start')
          ;
      g.select('.mc-leftAxis .label')
          .text(model.leftLabel_)
          ;
      g.select('.mc-leftAxis .y.axis')
          .call(model.leftAxis)
          ;
    }

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

    //------------------------------------------------------------
    // Right Axis

    if (model.renderRight) {
      model.rightAxis
        .scale(model.right || instance.y)
        .orient('right')
        ;
      model.rightAxis
        .tickSize.apply(model.rightAxis, model.rightTickSize_(instance.width))
        ;
      model.rightAxis
        .ticks.apply(model.rightAxis, model.rightTicks_(instance.height))
        ;
      gEnter.select('.mc-rightAxis').append('g')
          .attr('class', 'y axis')
        .append('text')
          .attr('class', 'label')
          .attr('transform', 'rotate(-90)')
          .attr('dy', -6)
          .attr('dx', -6)
          .style('text-anchor', 'end')
          ;
      g.select('.mc-rightAxis .label')
          .text(model.rightLabel_)
          ;
      g.select('.mc-rightAxis .y.axis')
          .attr('transform', 'translate(' + instance.width + ',0)')
          .call(model.rightAxis)
          ;
    }

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

    return chart;
  };

  function chart(selection, instance) {
    selection.each(function(data) {
      instance = instance || {};

      chart.calc.call(this, instance, data);
      chart.build.call(this, instance, data);
    });

    return chart;
  }

  //============================================================
  // Expose Public API
  //------------------------------------------------------------

  // TODO: figure out best way to expose these so we can use mc.rebind instead of manually rebinding every key
  // TODO: consider using defineProperty and making non enumerable
  chart.bottomAxis = model.bottomAxis;
  chart.topAxis    = model.topAxis;
  chart.leftAxis   = model.leftAxis;
  chart.rightAxis  = model.rightAxis;

  chart.bottomScale = _ => {
    if (!arguments.length) return model.bottom;
    model.bottom = _;
    return chart;
  };

  chart.topScale = _ => {
    if (!arguments.length) return model.top;
    model.top = _;
    return chart;
  };

  chart.leftScale = _ => {
    if (!arguments.length) return model.left;
    model.left = _;
    return chart;
  };

  chart.rightScale = _ => {
    if (!arguments.length) return model.right;
    model.right = _;
    return chart;
  };

  //TODO: might want to rename these for when they are rebinded to complete charts (ie. barChart.renderRight vs. barChart.renderRightAxis)
  chart.renderBottom = _ => {
    if (!arguments.length) return model.renderBottom;
    model.renderBottom = _;
    return chart;
  };

  chart.renderTop = _ => {
    if (!arguments.length) return model.renderTop;
    model.renderTop = _;
    return chart;
  };

  chart.renderLeft = _ => {
    if (!arguments.length) return model.renderLeft;
    model.renderLeft = _;
    return chart;
  };

  chart.renderRight = _ => {
    if (!arguments.length) return model.renderRight;
    model.renderRight = _;
    return chart;
  };

  chart.bottomLabel = _ => {
    if (!arguments.length) return model.bottomLabel_;
    model.bottomLabel_ = d3.functor(_);
    return chart;
  };

  chart.topLabel = _ => {
    if (!arguments.length) return model.topLabel_;
    model.topLabel_ = d3.functor(_);
    return chart;
  };

  chart.leftLabel = _ => {
    if (!arguments.length) return model.leftLabel_;
    model.leftLabel_ = d3.functor(_);
    return chart;
  };

  chart.rightLabel = _ => {
    if (!arguments.length) return model.rightLabel_;
    model.rightLabel_ = d3.functor(_);
    return chart;
  };

  chart.bottomTickSize = _ => {
    if (!arguments.length) return model.bottomTickSize_;
    model.bottomTickSize_ = d3.functor(_);
    return chart;
  };

  chart.topTickSize = _ => {
    if (!arguments.length) return model.topTickSize_;
    model.topTickSize_ = d3.functor(_);
    return chart;
  };

  chart.leftTickSize = _ => {
    if (!arguments.length) return model.leftTickSize_;
    model.leftTickSize_ = d3.functor(_);
    return chart;
  };

  chart.rightTickSize = _ => {
    if (!arguments.length) return model.rightTickSize_;
    model.rightTickSize_ = d3.functor(_);
    return chart;
  };

  chart.bottomTicks = _ => {
    if (!arguments.length) return model.bottomTicks_;
    model.bottomTicks_ = d3.functor(_);
    return chart;
  };

  chart.topTicks = _ => {
    if (!arguments.length) return model.topTicks_;
    model.topTicks_ = d3.functor(_);
    return chart;
  };

  chart.leftTicks = _ => {
    if (!arguments.length) return model.leftTicks_;
    model.leftTicks_ = d3.functor(_);
    return chart;
  };

  chart.rightTicks = _ => {
    if (!arguments.length) return model.rightTicks_;
    model.rightTicks_ = d3.functor(_);
    return chart;
  };

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

  return chart;
};
<commit_msg>undo arrow functions converted that could now be... arguments.length is parents.. no good for getter/setters<commit_after>
// TODO: consider having slightly different structure for chart components vs charts
//       **probably a bad idea... but worth a thought.  Now have 'layers' for easy tweaking of components
mc.models.axes = function axes(model) {

  model = model || {}

  //============================================================
  // Public Variables with Default Settings
  //------------------------------------------------------------

  model.renderBottom    = true
  model.renderTop       = false
  model.renderLeft      = true
  model.renderRight     = false

  //scales must be passed into axes component, top/bottom defaults to xScale, left/right defaults to yScale
  //model.bottom
  //model.top
  //model.left
  //model.right

  // Components
  model.bottomAxis      = d3.svg.axis()
  model.topAxis         = d3.svg.axis()
  model.leftAxis        = d3.svg.axis()
  model.rightAxis       = d3.svg.axis()

  // Accessors
  model.bottomLabel_    = d => d.xLabel || ''
  model.topLabel_       = d => d.xLabel || ''
  model.leftLabel_      = d => d.yLabel || ''
  model.rightLabel_     = d => d.yLabel || ''

  model.bottomTickSize_ = height => [-height, 1]
  model.topTickSize_    = height => [-height, 1]
  model.leftTickSize_   = width => [-width, 1]
  model.rightTickSize_  = width => [-width, 1]

  model.bottomTicks_    = width => [Math.round(width/80)]
  model.topTicks_       = width => [Math.round(width/80)]
  model.leftTicks_      = height => [Math.round(height/40)]
  model.rightTicks_     = height => [Math.round(height/40)]

  //TODO: make Label alignment an option

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

  chart.calc = function(instance, data) {
    //Currently no calculations in axes

    return chart;
  };

  chart.build = function(instance, data) {

    //TODO: FIGURE OUT WHAT SHOULD BE ON INSTANCE

    //TODO: Consider using a layer for each axis

    //TODO: assume all charts using axes model have inherited chartBase

    var container = d3.select(this);

    // Elements
    //TODO: axes wrap, etc. are likelt separate from parent chart's wrap/g so either don't store on 'instance' or use unique name //TODO: investigate, might be able to actuallly use paren;t wrap/g
    var wrap, wrapEnter, g, gEnter;

    // Assume scales are setup by parent model

    //------------------------------------------------------------
    // Setup Chart Layers

    //TODO: consider using only wrap/wrapEnter, no g/gEnter
    wrap      = container.selectAll('g.mc-axes').data([data]);
    wrapEnter = wrap.enter().append('g').attr('class', 'mc-axes');
    gEnter    = wrapEnter.append('g');
    g         = wrap.select('g');

    gEnter.append('g').attr('class', 'mc-axis mc-bottomAxis');
    gEnter.append('g').attr('class', 'mc-axis mc-topAxis');
    gEnter.append('g').attr('class', 'mc-axis mc-leftAxis');
    gEnter.append('g').attr('class', 'mc-axis mc-rightAxis');

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

    //------------------------------------------------------------
    // Bottom Axis

    if (model.renderBottom) {
      model.bottomAxis
        .scale(model.bottom || instance.x)
        .orient('bottom')
        ;
      model.bottomAxis
        .tickSize.apply(model.bottomAxis, model.bottomTickSize_(instance.height))
        ;
      model.bottomAxis
        .ticks.apply(model.bottomAxis, model.bottomTicks_(instance.width))
        ;
      gEnter.select('.mc-bottomAxis').append('g')
          .attr('class', 'x axis')  //TODO: mc- namespace these classes?
        .append('text')
          .attr('class', 'label')  //TODO: mc- namespace these classes?
          .attr('dx', -6)
          .attr('dy', -6)
          .style('text-anchor', 'end')
          ;
      g.select('.mc-bottomAxis .label')
          .attr('x', instance.width)
          .text(model.bottomLabel_);
          ;
      g.select('.mc-bottomAxis .x.axis')
          .attr('transform', 'translate(0,' + instance.height + ')')
          .call(model.bottomAxis)
          ;
    }

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

    //------------------------------------------------------------
    // Top Axis

    if (model.renderTop) {
      model.topAxis
        .scale(model.top || instance.x)
        .orient('top')
        ;
      model.topAxis
        .tickSize.apply(model.topAxis, model.topTickSize_(instance.height))
        ;
      model.topAxis
        .ticks.apply(model.topAxis, model.topTicks_(instance.width))
        ;
      gEnter.select('.mc-topAxis').append('g')
          .attr('class', 'x axis')
        .append('text')
          .attr('class', 'label')
          .attr('dy', '1em')
          .attr('dx', '-2em')
          .style('text-anchor', 'end')
          ;
      g.select('.mc-topAxis .label')
          .attr('x', instance.width)
          .text(model.topLabel_);
          ;
      g.select('.mc-topAxis .x.axis')
          //.attr('transform', 'translate(0,0)')
          .call(model.topAxis)
          ;
    }

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

    //------------------------------------------------------------
    // Left Axis

    if (model.renderLeft) {
      model.leftAxis
        .scale(model.left || instance.y)
        .orient('left')
        ;
      model.leftAxis
        .tickSize.apply(model.leftAxis, model.leftTickSize_(instance.width))
        ;
      model.leftAxis
        .ticks.apply(model.leftAxis, model.leftTicks_(instance.height))
        ;
      gEnter.select('.mc-leftAxis').append('g')
          .attr('class', 'y axis')
        .append('text')
          .attr('class', 'label')
          .attr('transform', 'rotate(90)')
          .attr('dx', 6)
          .attr('dy', -6)
          .style('text-anchor', 'start')
          ;
      g.select('.mc-leftAxis .label')
          .text(model.leftLabel_)
          ;
      g.select('.mc-leftAxis .y.axis')
          .call(model.leftAxis)
          ;
    }

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

    //------------------------------------------------------------
    // Right Axis

    if (model.renderRight) {
      model.rightAxis
        .scale(model.right || instance.y)
        .orient('right')
        ;
      model.rightAxis
        .tickSize.apply(model.rightAxis, model.rightTickSize_(instance.width))
        ;
      model.rightAxis
        .ticks.apply(model.rightAxis, model.rightTicks_(instance.height))
        ;
      gEnter.select('.mc-rightAxis').append('g')
          .attr('class', 'y axis')
        .append('text')
          .attr('class', 'label')
          .attr('transform', 'rotate(-90)')
          .attr('dy', -6)
          .attr('dx', -6)
          .style('text-anchor', 'end')
          ;
      g.select('.mc-rightAxis .label')
          .text(model.rightLabel_)
          ;
      g.select('.mc-rightAxis .y.axis')
          .attr('transform', 'translate(' + instance.width + ',0)')
          .call(model.rightAxis)
          ;
    }

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

    return chart;
  };

  function chart(selection, instance) {
    selection.each(function(data) {
      instance = instance || {};

      chart.calc.call(this, instance, data);
      chart.build.call(this, instance, data);
    });

    return chart;
  }

  //============================================================
  // Expose Public API
  //------------------------------------------------------------

  // TODO: figure out best way to expose these so we can use mc.rebind instead of manually rebinding every key
  // TODO: consider using defineProperty and making non enumerable
  chart.bottomAxis = model.bottomAxis;
  chart.topAxis    = model.topAxis;
  chart.leftAxis   = model.leftAxis;
  chart.rightAxis  = model.rightAxis;

  chart.bottomScale = function(_) {
    if (!arguments.length) return model.bottom;
    model.bottom = _;
    return chart;
  };

  chart.topScale = function(_) {
    if (!arguments.length) return model.top;
    model.top = _;
    return chart;
  };

  chart.leftScale = function(_) {
    if (!arguments.length) return model.left;
    model.left = _;
    return chart;
  };

  chart.rightScale = function(_) {
    if (!arguments.length) return model.right;
    model.right = _;
    return chart;
  };

  //TODO: might want to rename these for when they are rebinded to complete charts (ie. barChart.renderRight vs. barChart.renderRightAxis)
  chart.renderBottom = function(_) {
    if (!arguments.length) return model.renderBottom;
    model.renderBottom = _;
    return chart;
  };

  chart.renderTop = function(_) {
    if (!arguments.length) return model.renderTop;
    model.renderTop = _;
    return chart;
  };

  chart.renderLeft = function(_) {
    if (!arguments.length) return model.renderLeft;
    model.renderLeft = _;
    return chart;
  };

  chart.renderRight = function(_) {
    if (!arguments.length) return model.renderRight;
    model.renderRight = _;
    return chart;
  };

  chart.bottomLabel = function(_) {
    if (!arguments.length) return model.bottomLabel_;
    model.bottomLabel_ = d3.functor(_);
    return chart;
  };

  chart.topLabel = function(_) {
    if (!arguments.length) return model.topLabel_;
    model.topLabel_ = d3.functor(_);
    return chart;
  };

  chart.leftLabel = function(_) {
    if (!arguments.length) return model.leftLabel_;
    model.leftLabel_ = d3.functor(_);
    return chart;
  };

  chart.rightLabel = function(_) {
    if (!arguments.length) return model.rightLabel_;
    model.rightLabel_ = d3.functor(_);
    return chart;
  };

  chart.bottomTickSize = function(_) {
    if (!arguments.length) return model.bottomTickSize_;
    model.bottomTickSize_ = d3.functor(_);
    return chart;
  };

  chart.topTickSize = function(_) {
    if (!arguments.length) return model.topTickSize_;
    model.topTickSize_ = d3.functor(_);
    return chart;
  };

  chart.leftTickSize = function(_) {
    if (!arguments.length) return model.leftTickSize_;
    model.leftTickSize_ = d3.functor(_);
    return chart;
  };

  chart.rightTickSize = function(_) {
    if (!arguments.length) return model.rightTickSize_;
    model.rightTickSize_ = d3.functor(_);
    return chart;
  };

  chart.bottomTicks = function(_) {
    if (!arguments.length) return model.bottomTicks_;
    model.bottomTicks_ = d3.functor(_);
    return chart;
  };

  chart.topTicks = function(_) {
    if (!arguments.length) return model.topTicks_;
    model.topTicks_ = d3.functor(_);
    return chart;
  };

  chart.leftTicks = function(_) {
    if (!arguments.length) return model.leftTicks_;
    model.leftTicks_ = d3.functor(_);
    return chart;
  };

  chart.rightTicks = function(_) {
    if (!arguments.length) return model.rightTicks_;
    model.rightTicks_ = d3.functor(_);
    return chart;
  };

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

  return chart;
};
<|endoftext|>


<commit_before>/* eslint func-names: 0 */
/* eslint no-invalid-this: 0 */

const mongoose = require('mongoose');

mongoose.Promise = global.Promise;

const logger = require('../utils/logger');

const messageSchema = new mongoose.Schema({
    'contents': {
        'required': true,
        'type': String
    },
    'createdAt': {
        'default': Date.now,
        'type': Date
    },
    'createdBy': {
        'ref': 'profile',
        'type': mongoose.Schema.Types.ObjectId
    },
    'editedBy': {
        'ref': 'profile',
        'type': mongoose.Schema.Types.ObjectId
    },
    'updatedAt': {
        'default': Date.now,
        'type': Date
    }
});

const postSchema = new mongoose.Schema({
    'contents': String,
    'createdAt': {
        'default': Date.now,
        'type': Date
    },
    'createdBy': {
        'ref': 'profile',
        'type': mongoose.Schema.Types.ObjectId
    },
    'editedBy': {
        'ref': 'profile',
        'type': mongoose.Schema.Types.ObjectId
    },
    'messageCount': {
        'default': 0,
        'type': Number
    },
    'messages': [messageSchema],
    'pinned': {
        'default': false,
        'type': Boolean
    },
    'slug': String,
    'title': {
        'required': true,
        'type': String
    },
    'updatedAt': {
        'default': Date.now,
        'type': Date
    },
    'views': {
        'default': 0,
        'type': Number
    }
});

postSchema.statics.createPost = function (data, profileId) {

    return new Promise((resolve, reject) => {

        const post = new this({
            'contents': data.contents,
            'createdBy': profileId,
            'slug': data.title.toLowerCase()
                .replace(/[^a-z]+/g, '-')
                .replace(/^\-|\-$/g, ''),
            'title': data.title
        });

        post.save((err, results) => {

            if (err || !results) {

                logger.err('Error creating new post.', err, data);

                reject({
                    'message': 'Internal Server Error',
                    'status': 500
                });

            } else {

                resolve(this.showPostById(results._id));

            }

        });

    });

};

postSchema.statics.updatePostById = function (postId, data, profileId) {

    return new Promise((resolve, reject) => {

        this.findOne({
            '_id': postId,
            'createdBy': profileId
        })
            .exec((execError, post) => {

                if (execError || !post) {

                    logger.err('Error updating existing post.', execError, data);

                    reject({
                        'message': 'Internal Server Error',
                        'status': 500
                    });

                } else {

                    if (typeof data.title !== 'undefined') {

                        post.title = data.title;

                    }

                    if (typeof data.contents !== 'undefined') {

                        post.contents = data.contents;

                    }

                    post.editedBy = profileId;

                    post.save((saveError, results) => {

                        if (saveError || !results) {

                            logger.err('Error updating existing post.', saveError, data);

                            reject({
                                'message': 'Internal Server Error',
                                'status': 500
                            });

                        } else {

                            resolve(this.showPostById(postId));

                        }

                    });

                }

            });

    });

};

postSchema.statics.addMessageToPostById = function (postId, data, profileId) {

    return new Promise((resolve, reject) => {

        this.findOneAndUpdate(
            {
                '_id': postId
            },
            {
                '$push': {
                    'messages': {
                        'contents': data.contents,
                        'createdBy': profileId
                    }
                },
                '$set': {
                    'updatedAt': Date.now()
                }
            },
            {
                'new': true
            },
            (updateError, results) => {

                if (updateError || !results) {

                    logger.err('Error updating existing message.', updateError, data);

                    reject({
                        'message': 'Internal Server Error',
                        'status': 500
                    });

                } else {

                    resolve(this.showMessageById(postId, results.messages.slice(-1)[0]._id));

                }

            }
        );

    });

};

postSchema.statics.updateMessageToPostById = function (postId, messageId, data, profileId) {

    return new Promise((resolve, reject) => {

        this.findOneAndUpdate(
            {
                '_id': postId,
                'messages': {
                    '$elemMatch': {
                        '_id': messageId,
                        'createdBy': profileId
                    }
                }
            },
            {
                '$set': {
                    'messages.$.contents': data.contents,
                    'messages.$.editedBy': profileId,
                    'messages.$.updatedAt': Date.now(),
                    'updatedAt': Date.now()
                }
            },
            {
                'new': true
            },
            (updateError, results) => {

                if (updateError || !results) {

                    logger.err('Error updating existing message.', updateError, data);

                    reject({
                        'message': 'Internal Server Error',
                        'status': 500
                    });

                } else {

                    resolve(this.showMessageById(postId, messageId));

                }

            }
        );

    });

};

postSchema.statics.deletePostById = function (postId, profileId) {

    return new Promise((resolve, reject) => {

        this.findOneAndRemove(
            {
                '_id': postId,
                'createdBy': profileId
            },
            (removeError, post) => {

                if (removeError || !post) {

                    logger.err('Error deleting existing post.', removeError);

                    reject({
                        'message': 'Internal Server Error',
                        'status': 500
                    });

                } else {

                    resolve([]);

                }

            }
        );

    });

};

postSchema.statics.deleteMessageFromPostById = function (postId, messageId, profileId) {

    return new Promise((resolve, reject) => {

        this.findOneAndUpdate(
            {
                '_id': postId,
                'messages': {
                    '$elemMatch': {
                        '_id': messageId,
                        'createdBy': profileId
                    }
                }
            },
            {
                '$pull': {
                    'messages': {
                        '_id': messageId,
                        'createdBy': profileId
                    }
                },
                '$set': {
                    'updatedAt': Date.now()
                }
            },
            {
                'new': true,
                'upsert': true
            },
            (updateError, results) => {

                if (updateError || !results) {

                    logger.err('Error deleting existing message.', updateError);

                    reject({
                        'message': 'Internal Server Error',
                        'status': 500
                    });

                } else {

                    resolve({});

                }

            }
        );

    });

};

postSchema.statics.showPostById = function (postId) {

    return new Promise((resolve, reject) => {

        this.findByIdAndUpdate(postId, {
            '$inc': {
                'views': 1
            }
        })
            .populate('createdBy')
            .populate('editedBy')
            .populate('messages.createdBy')
            .populate('messages.editedBy')
            .exec((updateError, results) => {

                if (updateError || !results) {

                    logger.err(`Post id ${postId} not found.`);

                    reject({
                        'message': 'Post not found.',
                        'status': 404
                    });

                } else {

                    resolve(results);

                }

            });

    });

};

postSchema.statics.showMessageById = function (postId, messageId) {

    return new Promise((resolve, reject) => {

        this.find({
            'messages._id': messageId
        }, {
            'messages.$': true
        })
            .populate('messages.createdBy')
            .populate('messages.editedBy')
            .exec((findError, results) => {

                if (findError || !results || !results[0] || !results[0].messages) {

                    logger.err(`Message id ${messageId} not found.`);

                    reject({
                        'message': 'Message not found.',
                        'status': 404
                    });

                } else {

                    resolve(results[0].messages[0]);

                }

            });

    });

};

postSchema.statics.listPosts = function () {

    return new Promise((resolve, reject) => {

        this.find()
            .populate('createdBy')
            .populate('editedBy')
            .sort({
                'pinned': -1,
                'updatedAt': -1
            })
            .select('createdAt updatedAt views title slug contents messageCount createdBy editedBy')
            .exec((findError, results) => {

                if (findError || !results) {

                    logger.err('Error retrieving post list.', findError);

                    reject({
                        'message': 'Internal Server Error',
                        'status': 500
                    });

                } else {

                    resolve(results);

                }

            });

    });

};

postSchema.statics.listMessagesByPostId = function (postId) {

    return new Promise((resolve, reject) => {

        this.findByIdAndUpdate(postId, {
            '$inc': {
                'views': 1
            }
        })
            .populate('createdBy')
            .populate('editedBy')
            .populate('messages.createdBy')
            .populate('messages.editedBy')
            .exec((updateError, results) => {

                if (updateError || !results) {

                    logger.err(`Post id ${postId} not found.`);

                    reject({
                        'message': 'Post not found.',
                        'status': 404
                    });

                } else {

                    resolve(results.messages);

                }

            });

    });

};

postSchema.statics.searchPosts = function (query) {

    return new Promise((resolve, reject) => {

        if (query) {

            let modifiedQuery = query;

            modifiedQuery = modifiedQuery.trim().toLowerCase();
            modifiedQuery = modifiedQuery.replace(/[^0-9a-z]+/, '|').replace(/^\||\|$/, '');

            if (modifiedQuery) {

                this.find({
                    'title': {
                        '$regex': new RegExp(query, 'i')
                    }
                })
                    .populate('createdBy')
                    .populate('editedBy')
                    .sort({
                        'updatedAt': -1
                    })
                    .select('createdAt updatedAt views title slug contents messageCount createdBy editedBy')
                    .exec((findError, results) => {

                        if (findError || !results) {

                            logger.err('Error retrieving search results.', findError, query);

                            reject({
                                'message': 'Internal Server Error',
                                'status': 500
                            });

                        } else {

                            resolve(results);

                        }

                    });

            } else {

                resolve([]);

            }

        } else {

            resolve([]);

        }

    });

};

messageSchema.virtual('id').get(function () {

    return this._id.toHexString();

});

messageSchema.set('toJSON', {
    'virtuals': true
});

postSchema.post('findOneAndUpdate', (doc, next) => {

    if (doc && doc.messageCount !== doc.messages.length) {

        doc.messageCount = doc.messages.length;

        doc.save(next);

    }

    next();

});

postSchema.virtual('id').get(function () {

    return this._id.toHexString();

});

postSchema.set('toJSON', {
    'virtuals': true
});

module.exports = mongoose.model('post', postSchema);
<commit_msg>Fixed syntax issue.<commit_after>/* eslint func-names: 0 */
/* eslint no-invalid-this: 0 */

const mongoose = require('mongoose');

mongoose.Promise = global.Promise;

const logger = require('../utils/logger');

const messageSchema = new mongoose.Schema({
    'contents': {
        'required': true,
        'type': String
    },
    'createdAt': {
        'default': Date.now,
        'type': Date
    },
    'createdBy': {
        'ref': 'profile',
        'type': mongoose.Schema.Types.ObjectId
    },
    'editedBy': {
        'ref': 'profile',
        'type': mongoose.Schema.Types.ObjectId
    },
    'updatedAt': {
        'default': Date.now,
        'type': Date
    }
});

const postSchema = new mongoose.Schema({
    'contents': String,
    'createdAt': {
        'default': Date.now,
        'type': Date
    },
    'createdBy': {
        'ref': 'profile',
        'type': mongoose.Schema.Types.ObjectId
    },
    'editedBy': {
        'ref': 'profile',
        'type': mongoose.Schema.Types.ObjectId
    },
    'messageCount': {
        'default': 0,
        'type': Number
    },
    'messages': [messageSchema],
    'pinned': {
        'default': false,
        'type': Boolean
    },
    'slug': String,
    'title': {
        'required': true,
        'type': String
    },
    'updatedAt': {
        'default': Date.now,
        'type': Date
    },
    'views': {
        'default': 0,
        'type': Number
    }
});

postSchema.statics.createPost = function (data, profileId) {

    return new Promise((resolve, reject) => {

        const post = new this({
            'contents': data.contents,
            'createdBy': profileId,
            'slug': data.title.toLowerCase()
                .replace(/[^a-z]+/g, '-')
                .replace(/^-|-$/g, ''),
            'title': data.title
        });

        post.save((err, results) => {

            if (err || !results) {

                logger.err('Error creating new post.', err, data);

                reject({
                    'message': 'Internal Server Error',
                    'status': 500
                });

            } else {

                resolve(this.showPostById(results._id));

            }

        });

    });

};

postSchema.statics.updatePostById = function (postId, data, profileId) {

    return new Promise((resolve, reject) => {

        this.findOne({
            '_id': postId,
            'createdBy': profileId
        })
            .exec((execError, post) => {

                if (execError || !post) {

                    logger.err('Error updating existing post.', execError, data);

                    reject({
                        'message': 'Internal Server Error',
                        'status': 500
                    });

                } else {

                    if (typeof data.title !== 'undefined') {

                        post.title = data.title;

                    }

                    if (typeof data.contents !== 'undefined') {

                        post.contents = data.contents;

                    }

                    post.editedBy = profileId;

                    post.save((saveError, results) => {

                        if (saveError || !results) {

                            logger.err('Error updating existing post.', saveError, data);

                            reject({
                                'message': 'Internal Server Error',
                                'status': 500
                            });

                        } else {

                            resolve(this.showPostById(postId));

                        }

                    });

                }

            });

    });

};

postSchema.statics.addMessageToPostById = function (postId, data, profileId) {

    return new Promise((resolve, reject) => {

        this.findOneAndUpdate(
            {
                '_id': postId
            },
            {
                '$push': {
                    'messages': {
                        'contents': data.contents,
                        'createdBy': profileId
                    }
                },
                '$set': {
                    'updatedAt': Date.now()
                }
            },
            {
                'new': true
            },
            (updateError, results) => {

                if (updateError || !results) {

                    logger.err('Error updating existing message.', updateError, data);

                    reject({
                        'message': 'Internal Server Error',
                        'status': 500
                    });

                } else {

                    resolve(this.showMessageById(postId, results.messages.slice(-1)[0]._id));

                }

            }
        );

    });

};

postSchema.statics.updateMessageToPostById = function (postId, messageId, data, profileId) {

    return new Promise((resolve, reject) => {

        this.findOneAndUpdate(
            {
                '_id': postId,
                'messages': {
                    '$elemMatch': {
                        '_id': messageId,
                        'createdBy': profileId
                    }
                }
            },
            {
                '$set': {
                    'messages.$.contents': data.contents,
                    'messages.$.editedBy': profileId,
                    'messages.$.updatedAt': Date.now(),
                    'updatedAt': Date.now()
                }
            },
            {
                'new': true
            },
            (updateError, results) => {

                if (updateError || !results) {

                    logger.err('Error updating existing message.', updateError, data);

                    reject({
                        'message': 'Internal Server Error',
                        'status': 500
                    });

                } else {

                    resolve(this.showMessageById(postId, messageId));

                }

            }
        );

    });

};

postSchema.statics.deletePostById = function (postId, profileId) {

    return new Promise((resolve, reject) => {

        this.findOneAndRemove(
            {
                '_id': postId,
                'createdBy': profileId
            },
            (removeError, post) => {

                if (removeError || !post) {

                    logger.err('Error deleting existing post.', removeError);

                    reject({
                        'message': 'Internal Server Error',
                        'status': 500
                    });

                } else {

                    resolve([]);

                }

            }
        );

    });

};

postSchema.statics.deleteMessageFromPostById = function (postId, messageId, profileId) {

    return new Promise((resolve, reject) => {

        this.findOneAndUpdate(
            {
                '_id': postId,
                'messages': {
                    '$elemMatch': {
                        '_id': messageId,
                        'createdBy': profileId
                    }
                }
            },
            {
                '$pull': {
                    'messages': {
                        '_id': messageId,
                        'createdBy': profileId
                    }
                },
                '$set': {
                    'updatedAt': Date.now()
                }
            },
            {
                'new': true,
                'upsert': true
            },
            (updateError, results) => {

                if (updateError || !results) {

                    logger.err('Error deleting existing message.', updateError);

                    reject({
                        'message': 'Internal Server Error',
                        'status': 500
                    });

                } else {

                    resolve({});

                }

            }
        );

    });

};

postSchema.statics.showPostById = function (postId) {

    return new Promise((resolve, reject) => {

        this.findByIdAndUpdate(postId, {
            '$inc': {
                'views': 1
            }
        })
            .populate('createdBy')
            .populate('editedBy')
            .populate('messages.createdBy')
            .populate('messages.editedBy')
            .exec((updateError, results) => {

                if (updateError || !results) {

                    logger.err(`Post id ${postId} not found.`);

                    reject({
                        'message': 'Post not found.',
                        'status': 404
                    });

                } else {

                    resolve(results);

                }

            });

    });

};

postSchema.statics.showMessageById = function (postId, messageId) {

    return new Promise((resolve, reject) => {

        this.find({
            'messages._id': messageId
        }, {
            'messages.$': true
        })
            .populate('messages.createdBy')
            .populate('messages.editedBy')
            .exec((findError, results) => {

                if (findError || !results || !results[0] || !results[0].messages) {

                    logger.err(`Message id ${messageId} not found.`);

                    reject({
                        'message': 'Message not found.',
                        'status': 404
                    });

                } else {

                    resolve(results[0].messages[0]);

                }

            });

    });

};

postSchema.statics.listPosts = function () {

    return new Promise((resolve, reject) => {

        this.find()
            .populate('createdBy')
            .populate('editedBy')
            .sort({
                'pinned': -1,
                'updatedAt': -1
            })
            .select('createdAt updatedAt views title slug contents messageCount createdBy editedBy')
            .exec((findError, results) => {

                if (findError || !results) {

                    logger.err('Error retrieving post list.', findError);

                    reject({
                        'message': 'Internal Server Error',
                        'status': 500
                    });

                } else {

                    resolve(results);

                }

            });

    });

};

postSchema.statics.listMessagesByPostId = function (postId) {

    return new Promise((resolve, reject) => {

        this.findByIdAndUpdate(postId, {
            '$inc': {
                'views': 1
            }
        })
            .populate('createdBy')
            .populate('editedBy')
            .populate('messages.createdBy')
            .populate('messages.editedBy')
            .exec((updateError, results) => {

                if (updateError || !results) {

                    logger.err(`Post id ${postId} not found.`);

                    reject({
                        'message': 'Post not found.',
                        'status': 404
                    });

                } else {

                    resolve(results.messages);

                }

            });

    });

};

postSchema.statics.searchPosts = function (query) {

    return new Promise((resolve, reject) => {

        if (query) {

            let modifiedQuery = query;

            modifiedQuery = modifiedQuery.trim().toLowerCase();
            modifiedQuery = modifiedQuery.replace(/[^0-9a-z]+/, '|').replace(/^\||\|$/, '');

            if (modifiedQuery) {

                this.find({
                    'title': {
                        '$regex': new RegExp(query, 'i')
                    }
                })
                    .populate('createdBy')
                    .populate('editedBy')
                    .sort({
                        'updatedAt': -1
                    })
                    .select('createdAt updatedAt views title slug contents messageCount createdBy editedBy')
                    .exec((findError, results) => {

                        if (findError || !results) {

                            logger.err('Error retrieving search results.', findError, query);

                            reject({
                                'message': 'Internal Server Error',
                                'status': 500
                            });

                        } else {

                            resolve(results);

                        }

                    });

            } else {

                resolve([]);

            }

        } else {

            resolve([]);

        }

    });

};

messageSchema.virtual('id').get(function () {

    return this._id.toHexString();

});

messageSchema.set('toJSON', {
    'virtuals': true
});

postSchema.post('findOneAndUpdate', (doc, next) => {

    if (doc && doc.messageCount !== doc.messages.length) {

        doc.messageCount = doc.messages.length;

        doc.save(next);

    }

    next();

});

postSchema.virtual('id').get(function () {

    return this._id.toHexString();

});

postSchema.set('toJSON', {
    'virtuals': true
});

module.exports = mongoose.model('post', postSchema);
<|endoftext|>


<commit_before>
export default {

    findOne: async (db, id) => {
        if (!id) {
            return false;
        }

        let userArray;
        try {
            userArray = await db.all('SELECT rowid as id, username from user where rowid = ' + id); // oops, not very secure
        } catch (ex) {
            return false;
        }

        if (userArray !== undefined && userArray !== null && userArray[0] !== undefined) {
            if (userArray.length > 1) {
                return userArray;
            }
            return userArray[0];
        }
        return false;
    },

    findOneWithUsername: async (db, username) => {
        if (!username) {
            return false;
        }

        let userArray;
        try {
            userArray = await db.all("SELECT rowid AS id, username, password FROM user WHERE username = '" + username + "' LIMIT 1");
        } catch(err) {
            return false;
        }

        if (userArray !== undefined && userArray !== null && userArray[0] !== undefined) {
            return userArray[0];
        }
        return false;
    },

    findIdWithUsername: async (db, username) => {
        if (!username) {
            return false;
        }

        let userArray;
        try {
            userArray = await db.all('SELECT rowid as id FROM user WHERE rowid = ' + id + ' LIMIT 1');
        } catch(err) {
            return false;
        }

        if (userArray !== undefined && userArray !== null && userArray[0] !== undefined) {
            return userArray[0];
        }

        return false;
    },

    findAll: async (db) => {
        return await db.all('SELECT rowid AS id, username FROM user');
    },

    create: async (db, username, password) => {
        if (!username || !password) {
            return false;
        }

        try {
            return await db.all("INSERT INTO user (username, password) VALUES ('" + username + "', '" + password + "')");  // oops, not very secure
        } catch (ex) {
            return false;
        }
        return false;
    },

    update: async (db, password, id) => {
        if (!password || !id) {
            return false;
        }

        try {
            return await db.all("UPDATE user SET PASSWORD = '" + password + "' WHERE rowid = " + id); // oops, not very secure
        } catch (ex) {
            return false;
        }
    },

    findUserItems: async (db, userId) => {
        if (!userId) {
            return false;
        }
        try {
            return await db.all("SELECT DISTINCT name FROM item WHERE creator = " + userId);
        } catch(ex) {
            return false;
        }
    }

}
<commit_msg>Oops, exposing plain text password..<commit_after>
export default {

    findOne: async (db, id) => {
        if (!id) {
            return false;
        }

        let userArray;
        try {
            userArray = await db.all('SELECT rowid as id, username, password from user where rowid = ' + id); // oops, not very secure
        } catch (ex) {
            return false;
        }

        if (userArray !== undefined && userArray !== null && userArray[0] !== undefined) {
            if (userArray.length > 1) {
                return userArray;
            }
            return userArray[0];
        }
        return false;
    },

    findOneWithUsername: async (db, username) => {
        if (!username) {
            return false;
        }

        let userArray;
        try {
            userArray = await db.all("SELECT rowid AS id, username, password FROM user WHERE username = '" + username + "' LIMIT 1");
        } catch(err) {
            return false;
        }

        if (userArray !== undefined && userArray !== null && userArray[0] !== undefined) {
            return userArray[0];
        }
        return false;
    },

    findIdWithUsername: async (db, username) => {
        if (!username) {
            return false;
        }

        let userArray;
        try {
            userArray = await db.all('SELECT rowid as id FROM user WHERE rowid = ' + id + ' LIMIT 1');
        } catch(err) {
            return false;
        }

        if (userArray !== undefined && userArray !== null && userArray[0] !== undefined) {
            return userArray[0];
        }

        return false;
    },

    findAll: async (db) => {
        return await db.all('SELECT rowid AS id, username FROM user');
    },

    create: async (db, username, password) => {
        if (!username || !password) {
            return false;
        }

        try {
            return await db.all("INSERT INTO user (username, password) VALUES ('" + username + "', '" + password + "')");  // oops, not very secure
        } catch (ex) {
            return false;
        }
        return false;
    },

    update: async (db, password, id) => {
        if (!password || !id) {
            return false;
        }

        try {
            return await db.all("UPDATE user SET PASSWORD = '" + password + "' WHERE rowid = " + id); // oops, not very secure
        } catch (ex) {
            return false;
        }
    },

    findUserItems: async (db, userId) => {
        if (!userId) {
            return false;
        }
        try {
            return await db.all("SELECT DISTINCT name FROM item WHERE creator = " + userId);
        } catch(ex) {
            return false;
        }
    }

}
<|endoftext|>