<commit_before>var EventEmitter = require('../utils/EventEmitter'),
    Rectangle = require('../geom/Rectangle'),
    PhysicsTarget = require('../physics/PhysicsTarget'),
    inherit = require('../utils/inherit'),
    Texture = require('./Texture'),
    math = require('../math/math'),
    utils = require('../utils/utils'),
    PIXI = require('../vendor/pixi');

/**
 * The base Sprite class. This class is the base for all images on the screen. This class extends PIXI's Sprite.
 *
 * @class Sprite
 * @extends [PIXI.Sprite](http://www.goodboydigital.com/pixijs/docs/classes/Sprite.html)
 * @uses EventEmitter
 * @uses PhysicsTarget
 * @constructor
 * @param textures {Texture|Array<Texture>|Object} The texture for the sprite to display, an array of texture to animation through, or an animation object.
 *      The later looks like: `{ animationName: { frames: [frame1, frame2], speed: 0.5, loop: false } }` where each frame is a Texture object
 * @param [speed] {Number} The speed of the animations (can be overriden on a specific animations)
 * @param [start] {String} The animation to start with, defaults to the first found key otherwise
 * @example
 *      var spr = new gf.Sprite(texture);
 */
var Sprite = function(anims, speed, start) {
    EventEmitter.call(this);
    PhysicsTarget.call(this);

    if(!anims) {
        anims = Texture.__default;
    }

    //parse tx into correct format
    if(anims instanceof Texture) {
        anims = { _default: { frames: [anims] } };
        start = '_default';
    }
    else if(anims instanceof Array) {
        anims = { _default: { frames: anims } };
        start = '_default';
    } else {
        //massage animations into full format
        for(var a in anims) {
            if(start === undefined)
                start = a;

            var anim = anims[a];

            if(anim instanceof Array)
                anims[a] = { name: a, frames: anim };
            else if(anim instanceof Texture)
                anims[a] = { name: a, frames: [anim] };
            else
                anims[a].name = a;
        }
    }

    PIXI.Sprite.call(this, anims[start].frames[0]);

    /**
     * The name of the sprite
     *
     * @property name
     * @type String
     * @default ''
     */
    this.name = '';

    /**
     * The lifetime of the sprite. Once it reaches 0 (after being set)
     * the sprite's visible property is set to false, so that it will
     * no longer be rendered. NOT YET IMPLEMENTED
     *
     * @property lifetime
     * @type Number
     * @default Infinity
     * @private
     */
    this.lifespan = Infinity;

    /**
     * The animation speed for this sprite
     *
     * @property speed
     * @type Number
     * @default 1
     */
    this.speed = speed || 1;

    /**
     * Whether or not to loop the animations. This can be overriden
     * on a per-animation level
     *
     * @property loop
     * @type Boolean
     * @default false
     */
    this.loop = false;

    /**
     * The registerd animations for this AnimatedSprite
     *
     * @property animations
     * @type Object
     * @readOnly
     */
    this.animations = anims;

    /**
     * The currently playing animation
     *
     * @property currentAnimation
     * @type String
     * @readOnly
     */
    this.currentAnimation = start;

    /**
     * The current frame being shown
     *
     * @property currentFrame
     * @type Number
     * @readOnly
     */
    this.currentFrame = 0;

    /**
     * Whether or not the animation is currently playing
     *
     * @property playing
     * @type Boolean
     * @readOnly
     */
    this.playing = false;

    this.hitArea = this.hitArea || new Rectangle(0, 0, this.width, this.height);

    //show first frame
    this.goto(0, this.currentAnimation);

    /**
     * Fired when a new frame of the running animation is shown
     *
     * @event frame
     * @param animation {String} The animation name that is playing
     * @param frameId {Number} The frame that is being shown
     */

    /**
     * Fired when the running animation completes
     *
     * @event complete
     * @param animation {String} The animation that has completed
     */
};

inherit(Sprite, PIXI.Sprite, {
    enableInteractivity: function(game) {
        game.input.pointers.watchSprite(this);
        return this;
    },
    /**
     * Sets the sprite to visible = true
     *
     * @method show
     * @return {Sprite} Returns itself.
     * @chainable
     */
    show: function() {
        this.visible = true;
        return this;
    },
    /**
     * Sets the sprite to visible = false
     *
     * @method hide
     * @return {Sprite} Returns itself.
     * @chainable
     */
    hide: function() {
        this.visible = false;
        return this;
    },
    /**
     * Creates a new Sprite instance with the same values as this one
     *
     * @method clone
     * @return {Sprite} Returns the new sprite
     */
    clone: function() {
        //make a copy of our animations object
        var anims = utils.extend(true, {}, this.animations),
            spr = new Sprite(anims, this.speed, this.currentAnimation);

        spr.name = this.name;
        spr.loop = this.loop;
        spr.currentFrame = this.currentFrame;
        spr.playing = this.playing;
        spr.hitArea = this.hitArea.clone();

        spr.body = this.body.clone();

        spr.blendMode = this.blendMode;

        spr.anchor.x = this.anchor.x;
        spr.anchor.y = this.anchor.y;

        spr.position.x = this.position.x;
        spr.position.y = this.position.y;

        spr.scale.x = this.scale.x;
        spr.scale.y = this.scale.y;

        spr.pivot.x = this.pivot.x;
        spr.pivot.y = this.pivot.y;

        spr.rotation = this.rotation;
        spr.alpha = this.alpha;
        spr.visible = this.visible;
        spr.buttonMode = this.buttonMode;
        spr.renderable = this.renderable;

        //Don't copy some pixi stuff

        //spr.children = this.children;
        //spr.parent = this.parent;
        //spr.stage = this.stage;
        //spr.worldAlpha = this.worldAlpha;
        //spr._interactive = this._interactive;
        //spr.worldTransform = this.worldTransform;
        //spr.localTransform = this.localTransform;
        //spr.color = this.color;
        //spr.dynamic = this.dynamic;

        return spr;
    },
    /**
     * Adds a new animation to this animated sprite
     *
     * @method addAnimation
     * @param name {String} The string name of the animation
     * @param frames {Array<Texture>} The array of texture frames
     * @param [speed] {Number} The animation speed
     * @param [loop] {Boolean} Loop the animation or not
     * @return {Sprite} Returns itself.
     * @chainable
     */
    addAnimation: function(name, frames, speed, loop) {
        if(typeof name === 'object') {
            this.animations[name.name] = name;
        } else {
            this.animations[name] = {
                name: name,
                frames: frames,
                speed: speed,
                loop: loop
            };
        }

        return this;
    },
    /**
     * Goes to a frame and starts playing the animation from there. You can optionally
     * pass the name of a new aniamtion to start playing.
     *
     * @method goto
     * @param frame {Number} The index of the frame to start on
     * @param [name] {String} The string name of the animation to go to
     * @return {Sprite} Returns itself.
     * @chainable
     */
    goto: function(frame, anim) {
        if(typeof frame === 'string') {
            anim = frame;
            frame = 0;
        }

        this.currentFrame = frame || 0;
        this.lastRound = math.round(frame || 0);

        if(anim) {
            this.currentAnimation = anim;
        }

        this.setTexture(this.animations[this.currentAnimation].frames[this.currentFrame]);
        this.emit('frame', this.currentAnimation, this.lastRound);

        return this;
    },
    /**
     * Starts playing the currently active animation
     *
     * @method play
     * @return {Sprite} Returns itself.
     * @chainable
     */
    play: function() {
        this.playing = true;
        return this;
    },
    /**
     * Stops playing the currently active animation
     *
     * @method stop
     * @return {Sprite} Returns itself.
     * @chainable
     */
    stop: function() {
        this.playing = false;
        return this;
    },
    /**
     * Removes this sprite from the stage and the physics system
     *
     * @method destroy
     */
    destroy: function() {
        this.stop();
        this.disablePhysics();

        if(this.parent)
            this.parent.removeChild(this);

        this.name = null;
        this.lifetime = null;
        this.speed = null;
        this.loop = null;
        this.animations = null;
        this.currentAnimation = null;
        this.currentFrame = null;
        this.playing = null;
        this.hitArea = null;
    },
    /**
     * Called by PIXI to update our textures and do the actual animation
     *
     * @method updateTransform
     * @private
     */
    updateTransform: function() {
        PIXI.Sprite.prototype.updateTransform.call(this);

        if(!this.playing) return;

        var anim = this.animations[this.currentAnimation],
            round,
            loop = anim.loop !== undefined ? anim.loop : this.loop;

        this.currentFrame += anim.speed || this.speed;
        round = math.round(this.currentFrame);

        if(round < anim.frames.length) {
            if(round !== this.lastRound) {
                this.lastRound = round;
                this.setTexture(anim.frames[round]);
                this.emit('frame', this.currentAnimation, round);
            }
        }
        else {
            if(loop) {
                this.goto(0);
            } else {
                this.stop();
                this.emit('complete', this.currentAnimation);
            }
        }
    }
});

module.exports = Sprite;

//Add event echos
/*
['click', 'mousedown', 'mouseup', 'mouseupoutside', 'mouseover', 'mouseout', 'mousemove', 'tap', 'touchstart', 'touchend', 'touchendoutside'].forEach(function(evtname) {
    Sprite.prototype[evtname] = module.exports = function(e) {
        this.emit(evtname, e);
    };
});
*/

/*
 * MOUSE Callbacks
 */

/**
 * A callback that is used when the users clicks on the sprite with their mouse
 *
 * @event click
 * @param interactionData {InteractionData}
 */

/**
 * A callback that is used when the user clicks the mouse down over the sprite
 *
 * @event mousedown
 * @param interactionData {InteractionData}
 */

/**
 * A callback that is used when the user releases the mouse that was over the sprite
 * for this callback to be fired the mouse must have been pressed down over the sprite
 *
 * @event mouseup
 * @param interactionData {InteractionData}
 */

/**
 * A callback that is used when the user releases the mouse that was over the sprite but is no longer over the sprite
 * for this callback to be fired, The touch must have started over the sprite
 *
 * @event mouseupoutside
 * @param interactionData {InteractionData}
 */

/**
 * A callback that is used when the users mouse rolls over the sprite
 *
 * @event mouseover
 * @param interactionData {InteractionData}
 */

/**
 * A callback that is used when the users mouse leaves the sprite
 *
 * @event mouseout
 * @param interactionData {InteractionData}
 */

/**
 * A callback that is used when the user moves the mouse while over the sprite
 *
 * @event mousemove
 * @param interactionData {InteractionData}
 */

/*
 * TOUCH Callbacks
 */

/**
 * A callback that is used when the users taps on the sprite with their finger
 * basically a touch version of click
 *
 * @event tap
 * @param interactionData {InteractionData}
 */

/**
 * A callback that is used when the user touch's over the sprite
 *
 * @event touchstart
 * @param interactionData {InteractionData}
 */

/**
 * A callback that is used when the user releases a touch over the sprite
 *
 * @event touchend
 * @param interactionData {InteractionData}
 */

/**
 * A callback that is used when the user releases the touch that was over the sprite
 * for this callback to be fired, The touch must have started over the sprite
 *
 * @event touchendoutside
 * @param interactionData {InteractionData}
 */
<commit_msg>make sprite animations based on time not frames<commit_after>var EventEmitter = require('../utils/EventEmitter'),
    Rectangle = require('../geom/Rectangle'),
    PhysicsTarget = require('../physics/PhysicsTarget'),
    Clock = require('../utils/Clock'),
    inherit = require('../utils/inherit'),
    Texture = require('./Texture'),
    math = require('../math/math'),
    utils = require('../utils/utils'),
    PIXI = require('../vendor/pixi');

/**
 * The base Sprite class. This class is the base for all images on the screen. This class extends PIXI's Sprite.
 *
 * @class Sprite
 * @extends [PIXI.Sprite](http://www.goodboydigital.com/pixijs/docs/classes/Sprite.html)
 * @uses EventEmitter
 * @uses PhysicsTarget
 * @constructor
 * @param textures {Texture|Array<Texture>|Object} The texture for the sprite to display, an array of texture to animation through, or an animation object.
 *      The later looks like: `{ animationName: { frames: [frame1, frame2], frameTime: 0.5, loop: false } }` where each frame is a Texture object
 * @param [frameTime] {Number} The frame time of the animations (can be overriden on a specific animations)
 * @param [start] {String} The animation to start with, defaults to the first found key otherwise
 * @example
 *      var spr = new gf.Sprite(texture);
 */
var Sprite = function(anims, frameTime, start) {
    EventEmitter.call(this);
    PhysicsTarget.call(this);

    if(!anims) {
        anims = Texture.__default;
    }

    //parse tx into correct format
    if(anims instanceof Texture) {
        anims = { _default: { frames: [anims] } };
        start = '_default';
    }
    else if(anims instanceof Array) {
        anims = { _default: { frames: anims } };
        start = '_default';
    } else {
        //massage animations into full format
        for(var a in anims) {
            if(start === undefined)
                start = a;

            var anim = anims[a];

            if(anim instanceof Array)
                anims[a] = { name: a, frames: anim };
            else if(anim instanceof Texture)
                anims[a] = { name: a, frames: [anim] };
            else
                anims[a].name = a;
        }
    }

    PIXI.Sprite.call(this, anims[start].frames[0]);

    /**
     * The name of the sprite
     *
     * @property name
     * @type String
     * @default ''
     */
    this.name = '';

    /**
     * The lifetime of the sprite. Once it reaches 0 (after being set)
     * the sprite's visible property is set to false, so that it will
     * no longer be rendered. NOT YET IMPLEMENTED
     *
     * @property lifetime
     * @type Number
     * @default Infinity
     * @private
     */
    this.lifespan = Infinity;

    /**
     * The animation frameTime for this sprite
     *
     * @property frameTime
     * @type Number
     * @default 1
     */
    this.frameTime = frameTime || 250;

    /**
     * Whether or not to loop the animations. This can be overriden
     * on a per-animation level
     *
     * @property loop
     * @type Boolean
     * @default false
     */
    this.loop = false;

    /**
     * The registerd animations for this AnimatedSprite
     *
     * @property animations
     * @type Object
     * @readOnly
     */
    this.animations = anims;

    /**
     * The currently playing animation
     *
     * @property currentAnimation
     * @type String
     * @readOnly
     */
    this.currentAnimation = start;

    /**
     * The current frame being shown
     *
     * @property currentFrame
     * @type Number
     * @readOnly
     */
    this.currentFrame = 0;

    /**
     * Whether or not the animation is currently playing
     *
     * @property playing
     * @type Boolean
     * @readOnly
     */
    this.playing = false;

    this.hitArea = this.hitArea || new Rectangle(0, 0, this.width, this.height);

    //show first frame
    this.goto(0, this.currentAnimation);

    /**
     * Fired when a new frame of the running animation is shown
     *
     * @event frame
     * @param animation {String} The animation name that is playing
     * @param frameId {Number} The frame that is being shown
     */

    /**
     * Fired when the running animation completes
     *
     * @event complete
     * @param animation {String} The animation that has completed
     */

    this._clock = new Clock();
    this._clock.start();
    this._frameTime = 0;
};

inherit(Sprite, PIXI.Sprite, {
    enableInteractivity: function(game) {
        game.input.pointers.watchSprite(this);
        return this;
    },
    /**
     * Sets the sprite to visible = true
     *
     * @method show
     * @return {Sprite} Returns itself.
     * @chainable
     */
    show: function() {
        this.visible = true;
        return this;
    },
    /**
     * Sets the sprite to visible = false
     *
     * @method hide
     * @return {Sprite} Returns itself.
     * @chainable
     */
    hide: function() {
        this.visible = false;
        return this;
    },
    /**
     * Creates a new Sprite instance with the same values as this one
     *
     * @method clone
     * @return {Sprite} Returns the new sprite
     */
    clone: function() {
        //make a copy of our animations object
        var anims = utils.extend(true, {}, this.animations),
            spr = new Sprite(anims, this.frameTime, this.currentAnimation);

        spr.name = this.name;
        spr.loop = this.loop;
        spr.currentFrame = this.currentFrame;
        spr.playing = this.playing;
        spr.hitArea = this.hitArea.clone();

        spr.body = this.body.clone();

        spr.blendMode = this.blendMode;

        spr.anchor.x = this.anchor.x;
        spr.anchor.y = this.anchor.y;

        spr.position.x = this.position.x;
        spr.position.y = this.position.y;

        spr.scale.x = this.scale.x;
        spr.scale.y = this.scale.y;

        spr.pivot.x = this.pivot.x;
        spr.pivot.y = this.pivot.y;

        spr.rotation = this.rotation;
        spr.alpha = this.alpha;
        spr.visible = this.visible;
        spr.buttonMode = this.buttonMode;
        spr.renderable = this.renderable;

        //Don't copy some pixi stuff

        //spr.children = this.children;
        //spr.parent = this.parent;
        //spr.stage = this.stage;
        //spr.worldAlpha = this.worldAlpha;
        //spr._interactive = this._interactive;
        //spr.worldTransform = this.worldTransform;
        //spr.localTransform = this.localTransform;
        //spr.color = this.color;
        //spr.dynamic = this.dynamic;

        return spr;
    },
    /**
     * Adds a new animation to this animated sprite
     *
     * @method addAnimation
     * @param name {String} The string name of the animation
     * @param frames {Array<Texture>} The array of texture frames
     * @param [frameTime] {Number} The animation frame time
     * @param [loop] {Boolean} Loop the animation or not
     * @return {Sprite} Returns itself.
     * @chainable
     */
    addAnimation: function(name, frames, frameTime, loop) {
        if(typeof name === 'object') {
            this.animations[name.name] = name;
        } else {
            this.animations[name] = {
                name: name,
                frames: frames,
                frameTime: frameTime,
                loop: loop
            };
        }

        return this;
    },
    /**
     * Goes to a frame and starts playing the animation from there. You can optionally
     * pass the name of a new aniamtion to start playing.
     *
     * @method goto
     * @param frame {Number} The index of the frame to start on
     * @param [name] {String} The string name of the animation to go to
     * @return {Sprite} Returns itself.
     * @chainable
     */
    goto: function(frame, anim) {
        if(typeof frame === 'string') {
            anim = frame;
            frame = 0;
        }

        this.currentFrame = frame || 0;

        if(anim) {
            this.currentAnimation = anim;
        }

        this.setTexture(this.animations[this.currentAnimation].frames[this.currentFrame]);
        this.emit('frame', this.currentAnimation, this.currentFrame);

        return this;
    },
    /**
     * Starts playing the currently active animation
     *
     * @method play
     * @return {Sprite} Returns itself.
     * @chainable
     */
    play: function() {
        this.playing = true;
        return this;
    },
    /**
     * Stops playing the currently active animation
     *
     * @method stop
     * @return {Sprite} Returns itself.
     * @chainable
     */
    stop: function() {
        this.playing = false;
        return this;
    },
    /**
     * Removes this sprite from the stage and the physics system
     *
     * @method destroy
     */
    destroy: function() {
        this.stop();
        this.disablePhysics();

        if(this.parent)
            this.parent.removeChild(this);

        this.name = null;
        this.lifetime = null;
        this.frameTime = null;
        this.loop = null;
        this.animations = null;
        this.currentAnimation = null;
        this.currentFrame = null;
        this.playing = null;
        this.hitArea = null;
    },
    /**
     * Called by PIXI to update our textures and do the actual animation
     *
     * @method updateTransform
     * @private
     */
    updateTransform: function() {
        PIXI.Sprite.prototype.updateTransform.call(this);

        //get delta
        var dt = this._clock.getDelta();

        //if not playing, quit
        if(!this.playing) return;

        //get anim and test time
        var anim = this.animations[this.currentAnimation];

        this._frameTime += dt * 1000;

        if(this._frameTime < (anim.frameTime || 500)) return;

        //update animation to next frame
        var loop = anim.loop !== undefined ? anim.loop : this.loop,
            frame = ++this.currentFrame;

        this._frameTime = 0;

        if(frame < anim.frames.length) {
            this.setTexture(anim.frames[frame]);
            this.emit('frame', this.currentAnimation, frame);
        }
        else {
            if(loop) {
                this.goto(0);
            } else {
                this.stop();
                this.emit('complete', this.currentAnimation);
            }
        }
    }
});

module.exports = Sprite;

//Add event echos
/*
['click', 'mousedown', 'mouseup', 'mouseupoutside', 'mouseover', 'mouseout', 'mousemove', 'tap', 'touchstart', 'touchend', 'touchendoutside'].forEach(function(evtname) {
    Sprite.prototype[evtname] = module.exports = function(e) {
        this.emit(evtname, e);
    };
});
*/

/*
 * MOUSE Callbacks
 */

/**
 * A callback that is used when the users clicks on the sprite with their mouse
 *
 * @event click
 * @param interactionData {InteractionData}
 */

/**
 * A callback that is used when the user clicks the mouse down over the sprite
 *
 * @event mousedown
 * @param interactionData {InteractionData}
 */

/**
 * A callback that is used when the user releases the mouse that was over the sprite
 * for this callback to be fired the mouse must have been pressed down over the sprite
 *
 * @event mouseup
 * @param interactionData {InteractionData}
 */

/**
 * A callback that is used when the user releases the mouse that was over the sprite but is no longer over the sprite
 * for this callback to be fired, The touch must have started over the sprite
 *
 * @event mouseupoutside
 * @param interactionData {InteractionData}
 */

/**
 * A callback that is used when the users mouse rolls over the sprite
 *
 * @event mouseover
 * @param interactionData {InteractionData}
 */

/**
 * A callback that is used when the users mouse leaves the sprite
 *
 * @event mouseout
 * @param interactionData {InteractionData}
 */

/**
 * A callback that is used when the user moves the mouse while over the sprite
 *
 * @event mousemove
 * @param interactionData {InteractionData}
 */

/*
 * TOUCH Callbacks
 */

/**
 * A callback that is used when the users taps on the sprite with their finger
 * basically a touch version of click
 *
 * @event tap
 * @param interactionData {InteractionData}
 */

/**
 * A callback that is used when the user touch's over the sprite
 *
 * @event touchstart
 * @param interactionData {InteractionData}
 */

/**
 * A callback that is used when the user releases a touch over the sprite
 *
 * @event touchend
 * @param interactionData {InteractionData}
 */

/**
 * A callback that is used when the user releases the touch that was over the sprite
 * for this callback to be fired, The touch must have started over the sprite
 *
 * @event touchendoutside
 * @param interactionData {InteractionData}
 */
<|endoftext|>


<commit_before>export default {
  name: 'XAxis',
  props: [
    {
      name: 'hide',
      type: 'Boolean',
      defaultVal: 'false',
      isOptional: false,
      desc: {
        'en-US': 'If set true, the axis do not display in the chart.',
        'zh-CN': '是否隐藏 x 轴。',
      },
    }, {
      name: 'dataKey',
      type: 'String | Number',
      defaultVal: 'null',
      isOptional: true,
      desc: {
        'en-US': 'The key of data displayed in the axis.',
        'zh-CN': '指定展示的数据维度。',
      },
    }, {
      name: 'xAxisId',
      type: 'String | Number',
      defaultVal: '0',
      isOptional: false,
      desc: {
        'en-US': 'The unique id of x-axis.',
        'zh-CN': 'x 轴的唯一 id。',
      },
    }, {
      name: 'width',
      type: 'Number',
      defaultVal: '0',
      isOptional: false,
      desc: {
        'en-US': 'The width of axis which is usually calculated internally.',
        'zh-CN': 'x 轴的宽度，一般在图表内部计算。',
      },
    }, {
      name: 'height',
      type: 'Number',
      defaultVal: '30',
      isOptional: false,
      desc: {
        'en-US': 'The height of axis, which can be setted by user.',
        'zh-CN': 'x 轴的高度，这个可以根据需要进行配置。',
      },
    }, {
      name: 'orientation',
      type: '\'bottom\' , \'top\'',
      defaultVal: '\'bottom\'',
      isOptional: false,
      desc: {
        'en-US': 'The orientation of axis',
        'zh-CN': 'x 轴的位置。',
      },
    }, {
      name: 'type',
      type: '\'number\' | \'category\'',
      defaultVal: '\'category\'',
      isOptional: false,
      desc: {
        'en-US': 'The type of axis.',
        'zh-CN': 'x 轴的类型：数值轴、类目轴。',
      },
    }, {
      name: 'allowDecimals',
      type: 'Boolean',
      defaultVal: 'true',
      isOptional: false,
      desc: {
        'en-US': 'Allow the ticks of XAxis to be decimals or not.',
        'zh-CN': '是否允许小数类型的刻度。',
      },
    }, {
      name: 'allowDataOverflow',
      type: 'Boolean',
      defaultVal: 'false',
      isOptional: false,
      desc: {
        'en-US': 'When domain of the axis is specified and the type of the axis is \'number\', if allowDataOverflow is set to be false, the domain will be adjusted when the minimum value of data is smaller than domain[0] or the maximum value of data is greater than domain[1] so that the axis displays all data values. If set to true, graphic elements (line, area, bars) will be clipped to conform to the specified domain.',
        'zh-CN': '当轴是数值轴时，指定轴的定义域（domain）的时候，如果 allowDataOverflow 的值为 false，我们会根据数据的最大值和最小值来调整 domain，确保所有的数据能够展示。如果 allowDataOverflow 的值为 true，不会调整 domain ，而是将相应的图形元素会直接裁剪掉。',
      },
    }, {
      name: 'allowDuplicatedCategory',
      type: 'Boolean',
      defaultVal: 'true',
      isOptional: false,
      desc: {
        'en-US': 'Allow the axis has duplicated categorys or not when the type of axis is "category".',
        'zh-CN': '是否允许类目轴有重复的类目。',
      },
    }, {
      name: 'tickCount',
      type: 'Number',
      defaultVal: '5',
      isOptional: false,
      desc: {
        'en-US': 'The count of axis ticks. Not used if \'type\' is \'category\'.',
        'zh-CN': '刻度数。如果\'type\'是\'category\'，则不使用。',
      },
    }, {
      name: 'domain',
      type: 'Array',
      defaultVal: '[0, \'auto\']',
      isOptional: true,
      desc: {
        'en-US': 'Specify the domain of axis when the axis is a number axis. The length of domain should be 2, and we will validate the values in domain. And each element in the array can be a number, \'auto\', \'dataMin\', \'dataMax\', a string like \'dataMin - 20\', \'dataMax + 100\', or a function that accepts a single argument and returns a number. If any element of domain is set to be \'auto\', comprehensible scale ticks will be calculated, and the final domain of axis is generated by the ticks.',
        'zh-CN': '当 x 轴是数值轴时，通过这个配置可以指定 x 轴刻度函数的定义域。这个配置是一个二元数组，数组中的元素可以是一个数值，"auto", "dataMin", "dataMax" 或者类似于"dataMin - 100", "dataMax + 200"这样的字符串。如果任意元素的取值为"auto"，我们会生成可读性高的刻度，并且保证设置的刻度数。',
      },
      format: [
        '<XAxis type="number" domain={[\'dataMin\', \'dataMax\']} />',
        '<XAxis type="number" domain={[0, \'dataMax\']} />',
        '<XAxis type="number" domain={[\'auto\', \'auto\']} />',
        '<XAxis type="number" domain={[0, \'dataMax + 1000\']} />',
        '<XAxis type="number" domain={[\'dataMin - 100\', \'dataMax + 100\']} />',
        '<XAxis type="number" domain={[dataMin => (0 - Math.abs(dataMin)), dataMax => (dataMax * 2)]} />',
      ],
      examples: [{
        name: 'Numeric XAxis with specified domain',
        url: '/examples/VerticalLineChartWithSpecifiedDomain',
      }],
    }, {
      name: 'interval',
      type: '"preserveStart" | "preserveEnd" | "preserveStartEnd" | Number',
      defaultVal: '\'preserveEnd\'',
      isOptional: false,
      desc: {
        'en-US': 'If set 0, all the ticks will be shown. If set preserveStart", "preserveEnd" or "preserveStartEnd", the ticks which is to be shown or hidden will be calculated automatically.',
        'zh-CN': '当值为0时，所有的刻度都会展示。如果值为1，则会间隔1个刻度来展示相应的刻度。当值为 "preserveStart" 时，根据刻度的宽度自动计算间隔，在有足够的空间的情况下，会从头部的刻度开始计算。当值为 "preserveEnd" 时，会从尾部的刻度开始计算是否展示。当值为"preserveStartEnd"，会从头部、尾部的刻度开始计算向中间计算是否展示。',
      },
    }, {
      name: 'padding',
      type: 'Object',
      defaultVal: '{ left: 0, right: 0 }',
      isOptional: false,
      desc: {
        'en-US': 'Specify the padding of x-axis.',
        'zh-CN': '指定内边距。',
      },
      format: [
        '<XAxis padding={{ left: 10 }} />',
        '<XAxis padding={{ right: 20 }} />',
        '<XAxis padding={{ left: 20, right: 20 }} />',
      ],
      examples: [{
        name: 'XAxis with non-zero padding',
        url: '/examples/LineChartWithXAxisPading',
      }],
    }, {
      name: 'minTickGap',
      type: 'Number',
      defaultVal: '5',
      isOptional: false,
      desc: {
        'en-US': 'The minimum gap between two adjacent labels.',
        'zh-CN': '两个刻度之前最小间隔宽度。',
      },
    }, {
      name: 'axisLine',
      type: 'Boolean | Object',
      defaultVal: 'true',
      isOptional: false,
      desc: {
        'en-US': 'If set false, no axis line will be drawn. If set a object, the option is the configuration of axis line.',
        'zh-CN': '轴线配置。当值为 false 时，不绘制轴线。当值为对象类型时，会把这个对象解析成轴线的属性配置。',
      },
    }, {
      name: 'tickLine',
      type: 'Boolean | Object',
      defaultVal: 'true',
      isOptional: false,
      desc: {
        'en-US': 'If set false, no axis tick lines will be drawn. If set a object, the option is the configuration of tick lines.',
        'zh-CN': '刻度线配置。当值为 false 时，不绘制刻度线。当值为对象类型时，会把这个对象解析成刻度线的属性配置。',
      },
    }, {
      name: 'tickSize',
      type: 'Number',
      defaultVal: '6',
      isOptional: false,
      desc: {
        'en-US': 'The length of tick line.',
        'zh-CN': '刻度线的长度。',
      },
    }, {
      name: 'tickFormatter',
      type: 'Function',
      defaultVal: 'null',
      isOptional: true,
      desc: {
        'en-US': 'The formatter function of tick.',
        'zh-CN': '刻度的格式化函数。',
      },
    }, {
      name: 'ticks',
      type: 'Array',
      defaultVal: 'null',
      isOptional: true,
      desc: {
        'en-US': 'Set the values of axis ticks manually.',
        'zh-CN': '指定需要展示的刻度。',
      },
    }, {
      name: 'tick',
      type: 'Boolean | Object | ReactElement',
      defaultVal: 'null',
      isOptional: true,
      desc: {
        'en-US': 'If set false, no ticks will be drawn. If set a object, the option is the configuration of ticks. If set a React element, the option is the custom react element of drawing ticks.',
        'zh-CN': '刻度配置。当值为 false 时，不绘制刻度。当值为对象类型时，会把这个对象解析成刻度的属性配置。当值为 React element，会克隆这个元素来渲染刻度。',
      },
      format: [
        '<XAxis tick={false} />',
        '<XAxis tick={{stroke: \'red\', strokeWidth: 2}} />',
        '<XAxis tick={<CustomizedTick />} />',
      ],
      examples: [{
        name: 'A line chart with customized x-axis tick',
        url: '/examples/CustomizedLabelLineChart',
      }],
    }, {
      name: 'mirror',
      type: 'Boolean',
      defaultVal: 'false',
      isOptional: false,
      desc: {
        'en-US': 'If set true, flips ticks around the axis line, displaying the labels inside the chart instead of outside.',
        'zh-CN': '如果值为 true , 将刻度展示在轴的内侧，而不是外侧。',
      },
    }, {
      name: 'reversed',
      type: 'Boolean',
      defaultVal: 'false',
      isOptional: false,
      desc: {
        'en-US': 'Reverse the ticks or not.',
        'zh-CN': '是否反转刻度的顺序',
      },
    }, {
      name: 'label',
      type: 'String | Number | ReactElement | Object',
      defaultVal: 'null',
      isOptional: true,
      desc: {
        'en-US': 'If set a string or a number, default label will be drawn, and the option is content. If set a React element, the option is the custom react element of drawing label. If an object, the option is the props of a new Label instance.',
        'zh-CN': '当值为简单类型的数值或者字符串时，这个值会被渲染成文字标签。当值为 React element，会克隆这个元素来渲染文字标签。如果一个对象，该选项是一个新的Label实例的道具。',
      },
      format: [
        '<XAxis label="Height" />',
        '<XAxis label={<CustomizedLabel />} />',
        '<XAxis label={{ value: "XAxis Label" }} />',
      ],
      examples: [
        {
          name: 'A composed chart with axis labels',
          url: '/examples/ComposedChartWithAxisLabels',
        },
      ],
    }, {
      name: 'scale',
      type: `'auto' | 'linear' | 'pow' | 'sqrt' | 'log' | 'identity' | 'time' |
        'band' | 'point' | 'ordinal' | 'quantile' | 'quantize' | 'utcTime' | 'sequential' |
        'threshold' | Function`,
      defaultVal: 'auto',
      isOptional: false,
      desc: {
        'en-US': `If set to 'auto', the scale function is decided by the type of chart, and the props type.
When set to 'time', make sure to also set type to 'number' and to innclude a domain.`,
        'zh-CN': '当值为 "auto" 时，会根据图表类型来生成 scale 函数，也可以传入自定义的函数作为 scale 函数。',
      },
      format: [
        '<XAxis scale="log" />',
        `
import { scaleLog } from 'd3-scale';
const scale = scaleLog().base(Math.E);

...
  <XAxis scale={scale} />
...
`,
      ],
    }, {
      name: 'unit',
      type: 'String | Number',
      defaultVal: 'null',
      isOptional: true,
      desc: {
        'en-US': 'The unit of data displayed in the axis. This option will be used to represent an index unit in a scatter chart.',
        'zh-CN': 'x 轴展示数据的单位。这个单位会展示在 Tooltip 的数值后面。',
      },
    }, {
      name: 'name',
      type: 'String | Number',
      defaultVal: 'null',
      isOptional: true,
      desc: {
        'en-US': 'The name of data displayed in the axis. This option will be used to represent an index in a scatter chart.',
        'zh-CN': 'x 轴展示数据的名称。这个单位会展示在 Tooltip 内容中。',
      },
    }, {
      name: 'onClick',
      type: 'Function',
      isOptional: true,
      desc: {
        'en-US': 'The customized event handler of click on the ticks of this axis',
        'zh-CN': '刻度 click 事件的回调函数。',
      },
    }, {
      name: 'onMouseDown',
      type: 'Function',
      isOptional: true,
      desc: {
        'en-US': 'The customized event handler of mousedown on the the ticks of this axis',
        'zh-CN': '刻度 mousedown 事件的回调函数。',
      },
    }, {
      name: 'onMouseUp',
      type: 'Function',
      isOptional: true,
      desc: {
        'en-US': 'The customized event handler of mouseup on the ticks of this axis',
        'zh-CN': '刻度 mouseup 事件的回调函数。',
      },
    }, {
      name: 'onMouseMove',
      type: 'Function',
      isOptional: true,
      desc: {
        'en-US': 'The customized event handler of mousemove on the ticks of this axis',
        'zh-CN': '刻度 mousemove 事件的回调函数。',
      },
    }, {
      name: 'onMouseOver',
      type: 'Function',
      isOptional: true,
      desc: {
        'en-US': 'The customized event handler of mouseover on the ticks of this axis',
        'zh-CN': '刻度 mouseover 事件的回调函数。',
      },
    }, {
      name: 'onMouseOut',
      type: 'Function',
      isOptional: true,
      desc: {
        'en-US': 'The customized event handler of mouseout on the ticks of this axis',
        'zh-CN': '刻度 mouseout 事件的回调函数。',
      },
    }, {
      name: 'onMouseEnter',
      type: 'Function',
      isOptional: true,
      desc: {
        'en-US': 'The customized event handler of moustenter on the ticks of this axis',
        'zh-CN': '刻度 moustenter 事件的回调函数。',
      },
    }, {
      name: 'onMouseLeave',
      type: 'Function',
      isOptional: true,
      desc: {
        'en-US': 'The customized event handler of mouseleave on the ticks of this axis',
        'zh-CN': '刻度 mouseleave 事件的回调函数。',
      },
    }, {
      name: 'tickMargin',
      type: 'Number',
      isOptional: true,
      desc: {
        'en-US': 'The margin between tick line and tick.',
        'zh-CN': '刻度线和刻度之间的间隔。',
      },
    },
  ],
  parentComponents: [
    'AreaChart', 'BarChart', 'LineChart', 'ComposedChart',
    'ScatterChart',
  ],
  childrenComponents: [
    'Label',
  ],
};
<commit_msg>fix: fix another typo<commit_after>export default {
  name: 'XAxis',
  props: [
    {
      name: 'hide',
      type: 'Boolean',
      defaultVal: 'false',
      isOptional: false,
      desc: {
        'en-US': 'If set true, the axis do not display in the chart.',
        'zh-CN': '是否隐藏 x 轴。',
      },
    }, {
      name: 'dataKey',
      type: 'String | Number',
      defaultVal: 'null',
      isOptional: true,
      desc: {
        'en-US': 'The key of data displayed in the axis.',
        'zh-CN': '指定展示的数据维度。',
      },
    }, {
      name: 'xAxisId',
      type: 'String | Number',
      defaultVal: '0',
      isOptional: false,
      desc: {
        'en-US': 'The unique id of x-axis.',
        'zh-CN': 'x 轴的唯一 id。',
      },
    }, {
      name: 'width',
      type: 'Number',
      defaultVal: '0',
      isOptional: false,
      desc: {
        'en-US': 'The width of axis which is usually calculated internally.',
        'zh-CN': 'x 轴的宽度，一般在图表内部计算。',
      },
    }, {
      name: 'height',
      type: 'Number',
      defaultVal: '30',
      isOptional: false,
      desc: {
        'en-US': 'The height of axis, which can be setted by user.',
        'zh-CN': 'x 轴的高度，这个可以根据需要进行配置。',
      },
    }, {
      name: 'orientation',
      type: '\'bottom\' , \'top\'',
      defaultVal: '\'bottom\'',
      isOptional: false,
      desc: {
        'en-US': 'The orientation of axis',
        'zh-CN': 'x 轴的位置。',
      },
    }, {
      name: 'type',
      type: '\'number\' | \'category\'',
      defaultVal: '\'category\'',
      isOptional: false,
      desc: {
        'en-US': 'The type of axis.',
        'zh-CN': 'x 轴的类型：数值轴、类目轴。',
      },
    }, {
      name: 'allowDecimals',
      type: 'Boolean',
      defaultVal: 'true',
      isOptional: false,
      desc: {
        'en-US': 'Allow the ticks of XAxis to be decimals or not.',
        'zh-CN': '是否允许小数类型的刻度。',
      },
    }, {
      name: 'allowDataOverflow',
      type: 'Boolean',
      defaultVal: 'false',
      isOptional: false,
      desc: {
        'en-US': 'When domain of the axis is specified and the type of the axis is \'number\', if allowDataOverflow is set to be false, the domain will be adjusted when the minimum value of data is smaller than domain[0] or the maximum value of data is greater than domain[1] so that the axis displays all data values. If set to true, graphic elements (line, area, bars) will be clipped to conform to the specified domain.',
        'zh-CN': '当轴是数值轴时，指定轴的定义域（domain）的时候，如果 allowDataOverflow 的值为 false，我们会根据数据的最大值和最小值来调整 domain，确保所有的数据能够展示。如果 allowDataOverflow 的值为 true，不会调整 domain ，而是将相应的图形元素会直接裁剪掉。',
      },
    }, {
      name: 'allowDuplicatedCategory',
      type: 'Boolean',
      defaultVal: 'true',
      isOptional: false,
      desc: {
        'en-US': 'Allow the axis has duplicated categorys or not when the type of axis is "category".',
        'zh-CN': '是否允许类目轴有重复的类目。',
      },
    }, {
      name: 'tickCount',
      type: 'Number',
      defaultVal: '5',
      isOptional: false,
      desc: {
        'en-US': 'The count of axis ticks. Not used if \'type\' is \'category\'.',
        'zh-CN': '刻度数。如果\'type\'是\'category\'，则不使用。',
      },
    }, {
      name: 'domain',
      type: 'Array',
      defaultVal: '[0, \'auto\']',
      isOptional: true,
      desc: {
        'en-US': 'Specify the domain of axis when the axis is a number axis. The length of domain should be 2, and we will validate the values in domain. And each element in the array can be a number, \'auto\', \'dataMin\', \'dataMax\', a string like \'dataMin - 20\', \'dataMax + 100\', or a function that accepts a single argument and returns a number. If any element of domain is set to be \'auto\', comprehensible scale ticks will be calculated, and the final domain of axis is generated by the ticks.',
        'zh-CN': '当 x 轴是数值轴时，通过这个配置可以指定 x 轴刻度函数的定义域。这个配置是一个二元数组，数组中的元素可以是一个数值，"auto", "dataMin", "dataMax" 或者类似于"dataMin - 100", "dataMax + 200"这样的字符串。如果任意元素的取值为"auto"，我们会生成可读性高的刻度，并且保证设置的刻度数。',
      },
      format: [
        '<XAxis type="number" domain={[\'dataMin\', \'dataMax\']} />',
        '<XAxis type="number" domain={[0, \'dataMax\']} />',
        '<XAxis type="number" domain={[\'auto\', \'auto\']} />',
        '<XAxis type="number" domain={[0, \'dataMax + 1000\']} />',
        '<XAxis type="number" domain={[\'dataMin - 100\', \'dataMax + 100\']} />',
        '<XAxis type="number" domain={[dataMin => (0 - Math.abs(dataMin)), dataMax => (dataMax * 2)]} />',
      ],
      examples: [{
        name: 'Numeric XAxis with specified domain',
        url: '/examples/VerticalLineChartWithSpecifiedDomain',
      }],
    }, {
      name: 'interval',
      type: '"preserveStart" | "preserveEnd" | "preserveStartEnd" | Number',
      defaultVal: '\'preserveEnd\'',
      isOptional: false,
      desc: {
        'en-US': 'If set 0, all the ticks will be shown. If set preserveStart", "preserveEnd" or "preserveStartEnd", the ticks which is to be shown or hidden will be calculated automatically.',
        'zh-CN': '当值为0时，所有的刻度都会展示。如果值为1，则会间隔1个刻度来展示相应的刻度。当值为 "preserveStart" 时，根据刻度的宽度自动计算间隔，在有足够的空间的情况下，会从头部的刻度开始计算。当值为 "preserveEnd" 时，会从尾部的刻度开始计算是否展示。当值为"preserveStartEnd"，会从头部、尾部的刻度开始计算向中间计算是否展示。',
      },
    }, {
      name: 'padding',
      type: 'Object',
      defaultVal: '{ left: 0, right: 0 }',
      isOptional: false,
      desc: {
        'en-US': 'Specify the padding of x-axis.',
        'zh-CN': '指定内边距。',
      },
      format: [
        '<XAxis padding={{ left: 10 }} />',
        '<XAxis padding={{ right: 20 }} />',
        '<XAxis padding={{ left: 20, right: 20 }} />',
      ],
      examples: [{
        name: 'XAxis with non-zero padding',
        url: '/examples/LineChartWithXAxisPading',
      }],
    }, {
      name: 'minTickGap',
      type: 'Number',
      defaultVal: '5',
      isOptional: false,
      desc: {
        'en-US': 'The minimum gap between two adjacent labels.',
        'zh-CN': '两个刻度之前最小间隔宽度。',
      },
    }, {
      name: 'axisLine',
      type: 'Boolean | Object',
      defaultVal: 'true',
      isOptional: false,
      desc: {
        'en-US': 'If set false, no axis line will be drawn. If set a object, the option is the configuration of axis line.',
        'zh-CN': '轴线配置。当值为 false 时，不绘制轴线。当值为对象类型时，会把这个对象解析成轴线的属性配置。',
      },
    }, {
      name: 'tickLine',
      type: 'Boolean | Object',
      defaultVal: 'true',
      isOptional: false,
      desc: {
        'en-US': 'If set false, no axis tick lines will be drawn. If set a object, the option is the configuration of tick lines.',
        'zh-CN': '刻度线配置。当值为 false 时，不绘制刻度线。当值为对象类型时，会把这个对象解析成刻度线的属性配置。',
      },
    }, {
      name: 'tickSize',
      type: 'Number',
      defaultVal: '6',
      isOptional: false,
      desc: {
        'en-US': 'The length of tick line.',
        'zh-CN': '刻度线的长度。',
      },
    }, {
      name: 'tickFormatter',
      type: 'Function',
      defaultVal: 'null',
      isOptional: true,
      desc: {
        'en-US': 'The formatter function of tick.',
        'zh-CN': '刻度的格式化函数。',
      },
    }, {
      name: 'ticks',
      type: 'Array',
      defaultVal: 'null',
      isOptional: true,
      desc: {
        'en-US': 'Set the values of axis ticks manually.',
        'zh-CN': '指定需要展示的刻度。',
      },
    }, {
      name: 'tick',
      type: 'Boolean | Object | ReactElement',
      defaultVal: 'null',
      isOptional: true,
      desc: {
        'en-US': 'If set false, no ticks will be drawn. If set a object, the option is the configuration of ticks. If set a React element, the option is the custom react element of drawing ticks.',
        'zh-CN': '刻度配置。当值为 false 时，不绘制刻度。当值为对象类型时，会把这个对象解析成刻度的属性配置。当值为 React element，会克隆这个元素来渲染刻度。',
      },
      format: [
        '<XAxis tick={false} />',
        '<XAxis tick={{stroke: \'red\', strokeWidth: 2}} />',
        '<XAxis tick={<CustomizedTick />} />',
      ],
      examples: [{
        name: 'A line chart with customized x-axis tick',
        url: '/examples/CustomizedLabelLineChart',
      }],
    }, {
      name: 'mirror',
      type: 'Boolean',
      defaultVal: 'false',
      isOptional: false,
      desc: {
        'en-US': 'If set true, flips ticks around the axis line, displaying the labels inside the chart instead of outside.',
        'zh-CN': '如果值为 true , 将刻度展示在轴的内侧，而不是外侧。',
      },
    }, {
      name: 'reversed',
      type: 'Boolean',
      defaultVal: 'false',
      isOptional: false,
      desc: {
        'en-US': 'Reverse the ticks or not.',
        'zh-CN': '是否反转刻度的顺序',
      },
    }, {
      name: 'label',
      type: 'String | Number | ReactElement | Object',
      defaultVal: 'null',
      isOptional: true,
      desc: {
        'en-US': 'If set a string or a number, default label will be drawn, and the option is content. If set a React element, the option is the custom react element of drawing label. If an object, the option is the props of a new Label instance.',
        'zh-CN': '当值为简单类型的数值或者字符串时，这个值会被渲染成文字标签。当值为 React element，会克隆这个元素来渲染文字标签。如果一个对象，该选项是一个新的Label实例的道具。',
      },
      format: [
        '<XAxis label="Height" />',
        '<XAxis label={<CustomizedLabel />} />',
        '<XAxis label={{ value: "XAxis Label" }} />',
      ],
      examples: [
        {
          name: 'A composed chart with axis labels',
          url: '/examples/ComposedChartWithAxisLabels',
        },
      ],
    }, {
      name: 'scale',
      type: `'auto' | 'linear' | 'pow' | 'sqrt' | 'log' | 'identity' | 'time' |
        'band' | 'point' | 'ordinal' | 'quantile' | 'quantize' | 'utcTime' | 'sequential' |
        'threshold' | Function`,
      defaultVal: 'auto',
      isOptional: false,
      desc: {
        'en-US': `If set to 'auto', the scale function is decided by the type of chart, and the props type.
When set to 'time', make sure to also set type to 'number' and to include a domain.`,
        'zh-CN': '当值为 "auto" 时，会根据图表类型来生成 scale 函数，也可以传入自定义的函数作为 scale 函数。',
      },
      format: [
        '<XAxis scale="log" />',
        `
import { scaleLog } from 'd3-scale';
const scale = scaleLog().base(Math.E);

...
  <XAxis scale={scale} />
...
`,
      ],
    }, {
      name: 'unit',
      type: 'String | Number',
      defaultVal: 'null',
      isOptional: true,
      desc: {
        'en-US': 'The unit of data displayed in the axis. This option will be used to represent an index unit in a scatter chart.',
        'zh-CN': 'x 轴展示数据的单位。这个单位会展示在 Tooltip 的数值后面。',
      },
    }, {
      name: 'name',
      type: 'String | Number',
      defaultVal: 'null',
      isOptional: true,
      desc: {
        'en-US': 'The name of data displayed in the axis. This option will be used to represent an index in a scatter chart.',
        'zh-CN': 'x 轴展示数据的名称。这个单位会展示在 Tooltip 内容中。',
      },
    }, {
      name: 'onClick',
      type: 'Function',
      isOptional: true,
      desc: {
        'en-US': 'The customized event handler of click on the ticks of this axis',
        'zh-CN': '刻度 click 事件的回调函数。',
      },
    }, {
      name: 'onMouseDown',
      type: 'Function',
      isOptional: true,
      desc: {
        'en-US': 'The customized event handler of mousedown on the the ticks of this axis',
        'zh-CN': '刻度 mousedown 事件的回调函数。',
      },
    }, {
      name: 'onMouseUp',
      type: 'Function',
      isOptional: true,
      desc: {
        'en-US': 'The customized event handler of mouseup on the ticks of this axis',
        'zh-CN': '刻度 mouseup 事件的回调函数。',
      },
    }, {
      name: 'onMouseMove',
      type: 'Function',
      isOptional: true,
      desc: {
        'en-US': 'The customized event handler of mousemove on the ticks of this axis',
        'zh-CN': '刻度 mousemove 事件的回调函数。',
      },
    }, {
      name: 'onMouseOver',
      type: 'Function',
      isOptional: true,
      desc: {
        'en-US': 'The customized event handler of mouseover on the ticks of this axis',
        'zh-CN': '刻度 mouseover 事件的回调函数。',
      },
    }, {
      name: 'onMouseOut',
      type: 'Function',
      isOptional: true,
      desc: {
        'en-US': 'The customized event handler of mouseout on the ticks of this axis',
        'zh-CN': '刻度 mouseout 事件的回调函数。',
      },
    }, {
      name: 'onMouseEnter',
      type: 'Function',
      isOptional: true,
      desc: {
        'en-US': 'The customized event handler of moustenter on the ticks of this axis',
        'zh-CN': '刻度 moustenter 事件的回调函数。',
      },
    }, {
      name: 'onMouseLeave',
      type: 'Function',
      isOptional: true,
      desc: {
        'en-US': 'The customized event handler of mouseleave on the ticks of this axis',
        'zh-CN': '刻度 mouseleave 事件的回调函数。',
      },
    }, {
      name: 'tickMargin',
      type: 'Number',
      isOptional: true,
      desc: {
        'en-US': 'The margin between tick line and tick.',
        'zh-CN': '刻度线和刻度之间的间隔。',
      },
    },
  ],
  parentComponents: [
    'AreaChart', 'BarChart', 'LineChart', 'ComposedChart',
    'ScatterChart',
  ],
  childrenComponents: [
    'Label',
  ],
};
<|endoftext|>


<commit_before>// Copyright (c) 2018 Austin George
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the The GNU Affero General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// You should have received a copy of the GNU Affero General Public
// License along with this library; if not, write to the Free Software
// Foundation, 51 Franklin Street, Suite 500 Boston, MA 02110-1335 USA

function Toolbar() {
    var $j = jQuery.noConflict();
    var stopIconColorWhenPlaying = '#ea174c';
    var language = localStorage.languagePreference;

    this.renderLogoIcon = function (onclick) {
        var logoIcon = document.getElementById('mb-logo');
        logoIcon.onmouseenter = function () {
            document.body.style.cursor = "pointer";
        };
        logoIcon.onmouseleave = function () {
            document.body.style.cursor = "default";
        };
        logoIcon.onclick = function () {
            onclick();
        };
    };

    this.renderPlayIcon = function (onclick) {
        var playIcon = document.getElementById('play');
        var stopIcon = document.getElementById('stop');
        playIcon.onclick = function () {
            onclick();
            stopIcon.style.color = stopIconColorWhenPlaying;
        };

    };
    this.renderStopIcon = function (onclick) {
        var stopIcon = document.getElementById('stop');
        stopIcon.onclick = function () {
            onclick();
            stopIcon.style.color = 'white';
        };
    };
    this.renderNewProjectIcon = function (onclick) {
        var newProjectIcon = document.getElementById('new-project');
        newProjectIcon.onclick = function () {
            onclick();
        };
    };
    this.renderLoadIcon = function (onclick) {
        var loadIcon = document.getElementById('load');
        loadIcon.onclick = function () {
            onclick();
        };
    };
    this.renderSaveIcons = function (html_onclick, svg_onclick, png_onclick, wave_onclick, ly_onclick, abc_onclick, blockartworksvg_onclick) {
        var saveButton = document.getElementById('saveButton');
        var saveButtonAdvanced = document.getElementById('saveButtonAdvanced');
        if (beginnerMode) {
            saveButtonAdvanced.style.display = 'block';
            saveButtonAdvanced.style.display = 'none';
            saveButton.onclick = function () {
                html_onclick();
            }
        } else {
            saveButton.style.display = 'none';
            saveButtonAdvanced.style.display = 'block';
            saveButtonAdvanced.onclick = function () {

                var saveHTML = document.getElementById('save-html');
                saveHTML.onclick = function () {
                    html_onclick();
                };

                var saveSVG = document.getElementById('save-svg');
                saveSVG.onclick = function () {
                    svg_onclick();
                };

                var savePNG = document.getElementById('save-png');
                savePNG.onclick = function () {
                    png_onclick();
                };

                var saveWAV = document.getElementById('save-wav');
                saveWAV.onclick = function () {
                    wave_onclick();
                };

                var saveLY = document.getElementById('save-ly');
                saveLY.onclick = function () {
                    ly_onclick();
                };

                var saveABC = document.getElementById('save-abc');
                saveABC.onclick = function () {
                    abc_onclick();
                };

                var saveArtworkSVG = document.getElementById('save-blockartwork-svg');
                saveArtworkSVG.onclick = function () {
                    blockartworksvg_onclick();
                };
            }
        }
    };
    this.renderPlanetIcon = function (planet, onclick) {
        var planetIcon = document.getElementById('planetIcon');
        var planetIconDisabled = document.getElementById('planetIconDisabled');

        if (planet) {
            planetIcon.onclick = function () {
                document.getElementById('toolbars').style.display = "none";
                onclick();
            };
        } else {
            planetIcon.style.display = 'none';
            planetIconDisabled.style.display = 'block';
        }
    };

    this.renderMenuIcon = function (onclick) {
        var menuIcon = document.getElementById('menu');
        var auxToolbar = document.getElementById('aux-toolbar');
        menuIcon.onclick = function () {
            if (auxToolbar.style.display == '' || auxToolbar.style.display == 'none') {
                onclick(false);
                auxToolbar.style.display = 'block';
                menuIcon.innerHTML = 'more_vert';
                document.getElementById('toggleAuxBtn').className = 'blue darken-1';
            } else {
                onclick(true);
                auxToolbar.style.display = 'none';
                menuIcon.innerHTML = 'menu';
                document.getElementById('toggleAuxBtn').className -= 'blue darken-1';
            }
        };
    };

    this.renderHelpIcon = function (onclick) {
        var helpIcon = document.getElementById('helpIcon');
        helpIcon.onclick = function () {
            onclick();
        };
    };
    this.renderModeSelectIcon = function (onclick) {
        var begIcon = document.getElementById('beginnerMode');
        var advIcon = document.getElementById('advancedMode');
        if (begIcon.style.display === 'none') {
            advIcon.onclick = function () {
                onclick();
            };
        } else {
            begIcon.onclick = function () {
                onclick();
            }
        }
    };

    this.renderRunSlowlyIcon = function (onclick) {
        var runSlowlyIcon = document.getElementById('runSlowlyIcon');
        if (beginnerMode && language === 'ja') {
            runSlowlyIcon.style.display = 'none';

        }
        runSlowlyIcon.onclick = function () {
            onclick();
            document.getElementById('stop').style.color = stopIconColorWhenPlaying;

        };
    };
    this.renderRunStepIcon = function (onclick) {
        var runStepByStepIcon = document.getElementById('runStepByStepIcon');
        if (beginnerMode && language === 'ja') {
            runStepByStepIcon.style.display = 'none';
        }
        runStepByStepIcon.onclick = function () {
            onclick();
            document.getElementById('stop').style.color = stopIconColorWhenPlaying;
        };
    };
    this.renderAdvancedIcons = function (analytics_onclick, openPlugin_onclick, delPlugin_onclick) {
        var displayStatsIcon = document.getElementById('displayStatsIcon');
        var loadPluginIcon = document.getElementById('loadPluginIcon');
        var delPluginIcon = document.getElementById('delPluginIcon');
        var enableHorizScrollIcon = document.getElementById('enableHorizScrollIcon');

        if (!beginnerMode) {
            displayStatsIcon.onclick = function () {
                analytics_onclick();
            };

            loadPluginIcon.onclick = function () {
                openPlugin_onclick();
            };

            delPluginIcon.onclick = function () {
                delPlugin_onclick();
            };
        } else {
            displayStatsIcon.style.display = "none";
            loadPluginIcon.style.display = "none";
            delPluginIcon.style.display = "none";
            enableHorizScrollIcon.style.display = "none";
        }
    };
    // var scrollEnabled = false;
    // this.renderEnableHorizScrollIcon = function (setScroller, _setupBlocksContainerEvents) {
    //     var enableHorizScrollIcon = document.getElementById('enableHorizScrollIcon');
    //     enableHorizScrollIcon.onclick = function () {
    //         setScroller();
    //         _setupBlocksContainerEvents();
    //     }

    // }

    this.renderMergeIcon = function (onclick) {
        var mergeWithCurrentIcon = document.getElementById('mergeWithCurrentIcon');
        mergeWithCurrentIcon.onclick = function () {
            onclick();
        };
    };
    this.renderRestoreIcon = function (onclick) {
        var restoreIcon = document.getElementById('restoreIcon');
        restoreIcon.onclick = function () {
            onclick();
        };
    };
    this.renderLanguageSelectIcon = function (enUS_onclick, enUK_onclick, es_onclick, ja_onclick, kana_onclick, zhCN_onclick, th_onclick, ayc_onclick, gug_onclick, hi_onclick, ibo_onclick, ar_onclick) {
        var languageSelectIcon = document.getElementById('languageSelectIcon');
        languageSelectIcon.onclick=function(){
            var enUS=document.getElementById('en-US');
            enUS.onclick=function(){
                enUS_onclick();
            };

            var enUK=document.getElementById('en-UK');
            enUK.onclick=function(){
                enUK_onclick();
            };

            var es=document.getElementById('es');
            es.onclick=function(){
                es_onclick();
            };

            var ja=document.getElementById('ja');
            ja.onclick=function(){
                ja_onclick();
            };

            var kana=document.getElementById('kana');
            kana.onclick=function(){
                kana_onclick();
            };

            var zhCN=document.getElementById('zhCN');
            chCN.onclick=function(){
                zhCN_onclick();
            };

            var th=document.getElementById('th');
            th.onclick=function(){
                th_onclick();
            };

            var ayc=document.getElementById('ayc');
            ayc.onclick=function(){
                ayc_onclick();
            };

            var gug=document.getElementById('gug');
            gug.onclick=function(){
                gug_onclick();
            };

            var hi=document.getElementById('hi');
            hi.onclick=function(){
                hi_onclick();
            };

            var ibo=document.getElementById('ibo');
            ibo.onclick=function(){
                ibo_onclick();
            };

            var ar=document.getElementById('ar');
            ar.onclick=function(){
                ar_onclick();
            };

            var he=document.getElementById('he');
            he.onclick=function(){
                he_onclick();
            };
        }
    };

    var strings = [
        ["mb-logo", _("About Music Blocks")],
        ["play", _("Play")],
        ["stop", _("Stop")],
        ["newFile", _("New project")],
        ["load", _("Load project from file")],
        ["saveButton", _("Save project")],
        ["saveButtonAdvanced", _("Save project")],
        ["planetIcon", _("Find and share projects")],
        ["planetIconDisabled", _("Offline. Sharing is unavailable")],
        ["toggleAuxBtn", _("Auxilary menu")],
        ["helpIcon", _("Help")],
        ["runSlowlyIcon", _("Run slowly")],
        ["runStepByStepIcon", _("Run step by step")],
        ["displayStatsIcon", _("Display statistics")],
        ["loadPluginIcon", _("Load plugin")],
        ["delPluginIcon", _("Delete plugin")],
        ["enableHorizScrollIcon", _("Enable horizontal scrolling")],
        ["disableHorizScrollIcon", _("Disable horizontal scrolling")],
        ["mergeWithCurrentIcon", _("Merge with current project")],
        ["restoreIcon", _("Restore")],
        ["languageSelectIcon", _("Select language")],
        ["save-html", _("Save as HTML"), 'innerHTML'],
        ["save-svg", _("Save as svg"), 'innerHTML'],
        ["save-png", _("Save as png"), 'innerHTML'],
        ["save-wav", _("Save as wav"), 'innerHTML'],
        ["save-ly", _("Save sheet music"), 'innerHTML'],
        ["save-abc", _("Save as abc"), 'innerHTML'],
        ["save-blockartwork-svg", _("Save block artwork"), 'innerHTML'],
        ["new-project", _("Confirm"), 'innerHTML'],
        ["beginnerMode", _("Switch to beginner mode")],
        ["advancedMode", _("Switch to advanced mode")],

    ];

    // Workaround for FF
    var strings_ = [
        _("About Music Blocks"),
        _("Play"),
        _("Stop"),
        _("New project"),
        _("Load project from file"),
        _("Save project"),
        _("Save project"),
        _("Find and share projects"),
        _("Offline. Sharing is unavailable"),
        _("Auxilary menu"),
        _("Help"),
        _("Run slowly"),
        _("Run step by step"),
        _("Display statistics"),
        _("Load plugin"),
        _("Delete plugin"),
        _("Enable horizontal scrolling"),
        _("Disable horizontal scrolling"),
        _("Merge with current project"),
        _("Restore"),
        _("Select language"),
        _("Save as HTML"),
        _("Save as svg"),
        _("Save as png"),
        _("Save as wav"),
        _("Save sheet music"),
        _("Save as abc"),
        _("Save block artwork"),
        _("Confirm"),
        _("Switch to beginner mode"),
        _("Switch to advanced mode")
    ];

    this.init = function (mode) {
        var beginnerMode = document.getElementById('beginnerMode');
        var advancedMode = document.getElementById('advancedMode');

        if (mode || mode === 'null') {
            advancedMode.style.display = "block";
            beginnerMode.style.display = "none";
        } else {
            advancedMode.style.display = "none";
            beginnerMode.style.display = "display";
        }

        for (var i = 0; i < strings.length; i++) {
            var obj = strings[i];
            var trans = strings_[i];
            var elem = document.getElementById(obj[0]);
            // console.log(obj[0] + " trans: " + trans);
            if (strings[i].length == 3) {
                elem.innerHTML = obj[1];
            } else {
                elem.setAttribute("data-tooltip", trans);
            }
        }
        $j('.tooltipped').tooltip({
            html: true,
            delay: 100
        });

        $j('.materialize-iso, .dropdown-trigger').dropdown({
            constrainWidth: false,
            hover: false, // Activate on hover
            belowOrigin: true, // Displays dropdown below the button
        });
    };
}
<commit_msg>Update toolbar.js<commit_after>// Copyright (c) 2018 Austin George
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the The GNU Affero General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// You should have received a copy of the GNU Affero General Public
// License along with this library; if not, write to the Free Software
// Foundation, 51 Franklin Street, Suite 500 Boston, MA 02110-1335 USA

function Toolbar() {
    var $j = jQuery.noConflict();
    var stopIconColorWhenPlaying = '#ea174c';
    var language = localStorage.languagePreference;

    this.renderLogoIcon = function (onclick) {
        var logoIcon = document.getElementById('mb-logo');
        logoIcon.onmouseenter = function () {
            document.body.style.cursor = "pointer";
        };
        logoIcon.onmouseleave = function () {
            document.body.style.cursor = "default";
        };
        logoIcon.onclick = function () {
            onclick();
        };
    };

    this.renderPlayIcon = function (onclick) {
        var playIcon = document.getElementById('play');
        var stopIcon = document.getElementById('stop');
        playIcon.onclick = function () {
            onclick();
            stopIcon.style.color = stopIconColorWhenPlaying;
        };

    };
    this.renderStopIcon = function (onclick) {
        var stopIcon = document.getElementById('stop');
        stopIcon.onclick = function () {
            onclick();
            stopIcon.style.color = 'white';
        };
    };
    this.renderNewProjectIcon = function (onclick) {
        var newProjectIcon = document.getElementById('new-project');
        newProjectIcon.onclick = function () {
            onclick();
        };
    };
    this.renderLoadIcon = function (onclick) {
        var loadIcon = document.getElementById('load');
        loadIcon.onclick = function () {
            onclick();
        };
    };
    this.renderSaveIcons = function (html_onclick, svg_onclick, png_onclick, wave_onclick, ly_onclick, abc_onclick, blockartworksvg_onclick) {
        var saveButton = document.getElementById('saveButton');
        var saveButtonAdvanced = document.getElementById('saveButtonAdvanced');
        if (beginnerMode) {
            saveButtonAdvanced.style.display = 'block';
            saveButtonAdvanced.style.display = 'none';
            saveButton.onclick = function () {
                html_onclick();
            }
        } else {
            saveButton.style.display = 'none';
            saveButtonAdvanced.style.display = 'block';
            saveButtonAdvanced.onclick = function () {

                var saveHTML = document.getElementById('save-html');
                saveHTML.onclick = function () {
                    html_onclick();
                };

                var saveSVG = document.getElementById('save-svg');
                saveSVG.onclick = function () {
                    svg_onclick();
                };

                var savePNG = document.getElementById('save-png');
                savePNG.onclick = function () {
                    png_onclick();
                };

                var saveWAV = document.getElementById('save-wav');
                saveWAV.onclick = function () {
                    wave_onclick();
                };

                var saveLY = document.getElementById('save-ly');
                saveLY.onclick = function () {
                    ly_onclick();
                };

                var saveABC = document.getElementById('save-abc');
                saveABC.onclick = function () {
                    abc_onclick();
                };

                var saveArtworkSVG = document.getElementById('save-blockartwork-svg');
                saveArtworkSVG.onclick = function () {
                    blockartworksvg_onclick();
                };
            }
        }
    };
    this.renderPlanetIcon = function (planet, onclick) {
        var planetIcon = document.getElementById('planetIcon');
        var planetIconDisabled = document.getElementById('planetIconDisabled');

        if (planet) {
            planetIcon.onclick = function () {
                document.getElementById('toolbars').style.display = "none";
                onclick();
            };
        } else {
            planetIcon.style.display = 'none';
            planetIconDisabled.style.display = 'block';
        }
    };

    this.renderMenuIcon = function (onclick) {
        var menuIcon = document.getElementById('menu');
        var auxToolbar = document.getElementById('aux-toolbar');
        menuIcon.onclick = function () {
            if (auxToolbar.style.display == '' || auxToolbar.style.display == 'none') {
                onclick(false);
                auxToolbar.style.display = 'block';
                menuIcon.innerHTML = 'more_vert';
                document.getElementById('toggleAuxBtn').className = 'blue darken-1';
                // $('.tooltipped').tooltip();
            } else {
                onclick(true);
                auxToolbar.style.display = 'none';
                menuIcon.innerHTML = 'menu';
                document.getElementById('toggleAuxBtn').className -= 'blue darken-1';
            }
        };
    };

    this.renderHelpIcon = function (onclick) {
        var helpIcon = document.getElementById('helpIcon');
        helpIcon.onclick = function () {
            onclick();
        };
    };
    this.renderModeSelectIcon = function (onclick) {
        var modeText = document.getElementById('modeText');
        modeText.onclick = function () {
            onclick();
        };
    };

    this.renderRunSlowlyIcon = function (onclick) {
        var runSlowlyIcon = document.getElementById('runSlowlyIcon');
        if (beginnerMode && language === 'ja') {
            runSlowlyIcon.style.display = 'none';

        }
        runSlowlyIcon.onclick = function () {
            onclick();
            document.getElementById('stop').style.color = stopIconColorWhenPlaying;

        };
    };
    this.renderRunStepIcon = function (onclick) {
        var runStepByStepIcon = document.getElementById('runStepByStepIcon');
        if (beginnerMode && language === 'ja') {
            runStepByStepIcon.style.display = 'none';
        }
        runStepByStepIcon.onclick = function () {
            onclick();
            document.getElementById('stop').style.color = stopIconColorWhenPlaying;
        };
    };
    this.renderAdvancedIcons = function (analytics_onclick, openPlugin_onclick, delPlugin_onclick) {
        var displayStatsIcon = document.getElementById('displayStatsIcon');
        var loadPluginIcon = document.getElementById('loadPluginIcon');
        var delPluginIcon = document.getElementById('delPluginIcon');
        var enableHorizScrollIcon = document.getElementById('enableHorizScrollIcon');

        if (!beginnerMode) {
            displayStatsIcon.onclick = function () {
                analytics_onclick();
            };

            loadPluginIcon.onclick = function () {
                openPlugin_onclick();
            };

            delPluginIcon.onclick = function () {
                delPlugin_onclick();
            };
        } else {
            displayStatsIcon.style.display = "none";
            loadPluginIcon.style.display = "none";
            delPluginIcon.style.display = "none";
            enableHorizScrollIcon.style.display = "none";
        }
    };
    // var scrollEnabled = false;
    // this.renderEnableHorizScrollIcon = function (setScroller, _setupBlocksContainerEvents) {
    //     var enableHorizScrollIcon = document.getElementById('enableHorizScrollIcon');
    //     enableHorizScrollIcon.onclick = function () {
    //         setScroller();
    //         _setupBlocksContainerEvents();
    //     }

    // }

    this.renderMergeIcon = function (onclick) {
        var mergeWithCurrentIcon = document.getElementById('mergeWithCurrentIcon');
        mergeWithCurrentIcon.onclick = function () {
            onclick();
        };
    };
    this.renderRestoreIcon = function (onclick) {
        var restoreIcon = document.getElementById('restoreIcon');
        restoreIcon.onclick = function () {
            onclick();
        };
    };
    this.renderLanguageSelectIcon = function (languageBox) {
        var languageSelectIcon = document.getElementById('languageSelectIcon');
        languageSelectIcon.onclick=function(){
            var enUS=document.getElementById('enUS');
            enUS.onclick=function(){
                languageBox.enUS_onclick();
            };

            var enUK=document.getElementById('enUK');
            enUK.onclick=function(){
                languageBox.enUK_onclick();
            };

            var es=document.getElementById('es');
            es.onclick=function(){
                languageBox.es_onclick();
            };

            var ja=document.getElementById('ja');
            ja.onclick=function(){
                languageBox.ja_onclick();
            };

            var kana=document.getElementById('kana');
            kana.onclick=function(){
                languageBox.kana_onclick();
            };

            var zhCN=document.getElementById('zhCN');
            zhCN.onclick=function(){
                languageBox.zhCN_onclick();
            };

            var th=document.getElementById('th');
            th.onclick=function(){
                languageBox.th_onclick();
            };

            var ayc=document.getElementById('ayc');
            ayc.onclick=function(){
                languageBox.ayc_onclick();
            };

            var gug=document.getElementById('gug');
            gug.onclick=function(){
                languageBox.gug_onclick();
            };

            var hi=document.getElementById('hi');
            hi.onclick=function(){
                languageBox.hi_onclick();
            };

            var ibo=document.getElementById('ibo');
            ibo.onclick=function(){
                languageBox.ibo_onclick();
            };

            var ar=document.getElementById('ar');
            ar.onclick=function(){
                languageBox.ar_onclick();
            };

            var he=document.getElementById('he');
            he.onclick=function(){
                languageBox.he_onclick();
            };
        }
    };

    var strings = [
        ["mb-logo", _("About Music Blocks")],
        ["play", _("Play")],
        ["stop", _("Stop")],
        ["newFile", _("New project")],
        ["load", _("Load project from file")],
        ["saveButton", _("Save project")],
        ["saveButtonAdvanced", _("Save project")],
        ["planetIcon", _("Find and share projects")],
        ["planetIconDisabled", _("Offline. Sharing is unavailable")],
        ["toggleAuxBtn", _("Auxilary menu")],
        ["helpIcon", _("Help")],
        ["runSlowlyIcon", _("Run slowly")],
        ["runStepByStepIcon", _("Run step by step")],
        ["displayStatsIcon", _("Display statistics")],
        ["loadPluginIcon", _("Load plugin")],
        ["delPluginIcon", _("Delete plugin")],
        ["enableHorizScrollIcon", _("Enable horizontal scrolling")],
        ["disableHorizScrollIcon", _("Disable horizontal scrolling")],
        ["mergeWithCurrentIcon", _("Merge with current project")],
        ["restoreIcon", _("Restore")],
        ["modeText", _("Switch to beginner mode")],
        ["languageSelectIcon", _("Select language")],
        ["save-html", _("Save as HTML"), 'innerHTML'],
        ["save-svg", _("Save as svg"), 'innerHTML'],
        ["save-png", _("Save as png"), 'innerHTML'],
        ["save-wav", _("Save as wav"), 'innerHTML'],
        ["save-ly", _("Save sheet music"), 'innerHTML'],
        ["save-abc", _("Save as abc"), 'innerHTML'],
        ["save-blockartwork-svg", _("Save block artwork"), 'innerHTML'],
        ["new-project", _("Confirm"), 'innerHTML'],
        ["enUS", _("English (United States)"), 'innerHTML'],
        ["enUK", _("English (United Kingdom)"), 'innerHTML'],
        ["ja", _("日本語"), 'innerHTML'],
        ["es", _("español"), 'innerHTML'],
        ["kana", _("にほんご"), 'innerHTML'],
        ["zhCN", _("中文"), 'innerHTML'],
        ["th", _("ภาษาไทย"), 'innerHTML'],
        ["ayc", _("aymara"), 'innerHTML'],
        ["gug", _("guarani"), 'innerHTML'],
        ["hi", _("हिंदी"), 'innerHTML'],
        ["ibo", _("igbo"), 'innerHTML'],
        ["ar", _("عربى"), 'innerHTML'],
        ["he", _("עִברִית"), 'innerHTML'],
    ];

    // Workaround for FF
    var strings_ = [
        _("About Music Blocks"),
        _("Play"),
        _("Stop"),
        _("New project"),
        _("Load project from file"),
        _("Save project"),
        _("Save project"),
        _("Find and share projects"),
        _("Offline. Sharing is unavailable"),
        _("Auxilary menu"),
        _("Help"),
        _("Run slowly"),
        _("Run step by step"),
        _("Display statistics"),
        _("Load plugin"),
        _("Delete plugin"),
        _("Enable horizontal scrolling"),
        _("Disable horizontal scrolling"),
        _("Merge with current project"),
        _("Restore"),
        _("Switch to beginner mode"),
        _("Select language"),
        _("Save as HTML"),
        _("Save as svg"),
        _("Save as png"),
        _("Save as wav"),
        _("Save sheet music"),
        _("Save as abc"),
        _("Save block artwork"),
        _("Confirm"),
        _("Select language"),
        ];

    this.init = function () {
        for (var i = 0; i < strings.length; i++) {
            var obj = strings[i];
            var trans = strings_[i];
            var elem = document.getElementById(obj[0]);
            // console.log(obj[0] + " trans: " + trans);
            if (strings[i].length === 3) {
                elem.innerHTML = obj[1];
            } else {
                elem.setAttribute("data-tooltip", trans);
            }
        }
        $j('.tooltipped').tooltip({
            html: true
        });

    };
}
<|endoftext|>


<commit_before>'use strict';

const AWS = require('aws-sdk');

const dynamoDb = new AWS.DynamoDB.DocumentClient();

module.exports.create = (event, context, callback) => {
  const timestamp = new Date().getTime();
  const data = JSON.parse(event.body);
  if (typeof data.questions !== 'string' || typeof data.id  !== 'number') {
    console.error('Validation Failed');
    callback(new Error('Could not create survey'));
    return;
  }

  const params = {
    TableName: process.env.QUESTION_SETS_TABLE,
    Item: {
      id: data.id,
      MapAttribute: data.questions,
      createdAt: timestamp,
      updatedAt: timestamp,
    },
  };

  dynamoDb.put(params, (error, result) => {
    if (error) {
      console.error(error);
      callback(new Error('Could not create questions set'));
      return;
    }

    const response = {
      statusCode: 200,
      body: JSON.stringify(params.Item),
    };
    callback(null, response);
  });
};
<commit_msg>Include validation for question sets and avoid updating existing entries<commit_after>'use strict';

const AWS = require('aws-sdk');

const dynamoDb = new AWS.DynamoDB.DocumentClient();

var validateQuestions = function(questionList){

  if (!(Array.isArray(questionList))) return false;

  for (var i=0; i < questionList.length; i++) {
    if (typeof questionList[i].question !== 'string' ||
        !(Array.isArray(questionList[i].answers)) ) return false;
    for (var j=0; j < questionList[i].answers.length; j++) {
      if (typeof questionList[i].answers[j] !== 'string') return false;
    }
  }
  return true;
}

module.exports.create = (event, context, callback) => {
  const timestamp = new Date().getTime();
  const data = JSON.parse(event.body);
  if (typeof data.surveyId  !== 'number' || !(validateQuestions(data.questions)) ) {
    console.error('Validation Failed');
    callback(new Error('Could not create question set'));
    return;
  }

  const params = {
    TableName: process.env.QUESTION_SETS_TABLE,
    Item: {
      surveyId: data.surveyId,
      MapAttribute: data.questions,
      createdAt: timestamp,
      updatedAt: timestamp,
    },
    ConditionExpression: 'attribute_not_exists(surveyId)'
  };

  dynamoDb.put(params, (error, result) => {
    if (error) {
      console.error(error);
      callback(new Error('Could not create questions set'));
      return;
    }

    const response = {
      statusCode: 200,
      body: JSON.stringify(params.Item),
    };
    callback(null, response);
  });
};
<|endoftext|>