<commit_before>/*
Copyright 2019 New Vector Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import FixedDistributor from "./fixed";

// const allowWhitespace = true;
const handleHeight = 1;

function log(...params) {
    console.log.apply(console, params);
}

function clamp(height, min, max) {
    //log(`clamping ${height} between ${min} and ${max}`);
    if (height > max) return max;
    if (height < min) return min;
    return height;
}

export class Layout {
    constructor(applyHeight, initialSizes, collapsedState) {
        this._applyHeight = applyHeight;
        this._sections = [];
        this._collapsedState = Object.assign({}, collapsedState);
        this._availableHeight = 0;
        // heights stored by section section id
        this._sectionHeights = Object.assign({}, initialSizes);
        // in-progress heights, while dragging. Committed on mouse-up.
        this._heights = [];
    }

    setAvailableHeight(newSize) {
        this._availableHeight = newSize;
        // needs more work
        this._applyNewSize();
    }

    expandSection(id, height) {
        this._collapsedState[id] = false;
        this._applyNewSize();
        this.openHandle(id).setHeight(height).finish();
    }

    collapseSection(id) {
        this._collapsedState[id] = true;
        this._applyNewSize();
    }

    // [{id, count}]
    update(sections, availableHeight) {
        if (Number.isFinite(availableHeight)) {
            this._availableHeight = availableHeight;
        }
        const totalHeight = this._getAvailableHeight();
        this._sections.forEach((section, i) => {
            if (!this._sectionHeights.hasOwnProperty(section.id)) {
                this._sectionHeights[section.id] = clamp(
                    totalHeight / this._sections.length,
                    this._getMinHeight(i),
                    this._getMaxHeight(i),
                );
            }
        });
        this._sections = sections;
        this._applyNewSize();
    }

    openHandle(id) {
        const index = this._getSectionIndex(id);
        //log(`openHandle resolved ${id} to ${index}`);
        return new Handle(this, index, this._sectionHeights[id]);
    }

    _getAvailableHeight() {
        const nonCollapsedSectionCount = this._sections.reduce((count, section) => {
            const collapsed = this._collapsedState[section.id];
            return count + (collapsed ? 0 : 1);
        }, 0);
        return this._availableHeight - ((nonCollapsedSectionCount - 1) * handleHeight);
    }

    _applyNewSize() {
        const newHeight = this._getAvailableHeight();
        const currHeight = this._sections.reduce((sum, section) => {
            return sum + this._sectionHeights[section.id];
        }, 0);
        const offset = newHeight - currHeight;
        this._heights = this._sections.map((section) => this._sectionHeights[section.id]);
        const sections = this._sections.map((_, i) => i);
        this._applyOverflow(-offset, sections, true);
        this._applyHeights();
        this._commitHeights();
    }

    _getSectionIndex(id) {
        return this._sections.findIndex((s) => s.id === id);
    }

    _getMaxHeight(i) {
        const section = this._sections[i];
        const collapsed = this._collapsedState[section.id];

        if (collapsed) {
            return this._sectionHeight(0);
        } else {
            return 100000;
            // return this._sectionHeight(section.count);
        }
    }

    _sectionHeight(count) {
        return 36 + (count === 0 ? 0 : 4 + (count * 34));
    }

    _getMinHeight(i) {
        const section = this._sections[i];
        const collapsed = this._collapsedState[section.id];
        const maxItems = collapsed ? 0 : 1;
        // log("_getMinHeight", i, section);
        return this._sectionHeight(Math.min(section.count, maxItems));
    }

    _applyOverflow(overflow, sections, blend) {
        //log("applyOverflow", overflow, sections);
        // take the given overflow amount, and applies it to the given sections.
        // calls itself recursively until it has distributed all the overflow
        // or run out of unclamped sections.

        const unclampedSections = [];

        let overflowPerSection = blend ? (overflow / sections.length) : overflow;
        for (const i of sections) {
            const newHeight = clamp(
                this._heights[i] - overflowPerSection,
                this._getMinHeight(i),
                this._getMaxHeight(i),
            );
            if (newHeight == this._heights[i] - overflowPerSection) {
                unclampedSections.push(i);
            }
            // when section is growing, overflow increases?
            // 100 -= 200 - 300
            // 100 -= -100
            // 200
            overflow -= this._heights[i] - newHeight;
            // console.log(`this._heights[${i}] (${this._heights[i]}) - newHeight (${newHeight}) = ${this._heights[i] - newHeight}`);
            // console.log(`changing ${this._heights[i]} to ${newHeight}`);
            this._heights[i] = newHeight;
            // console.log(`for section ${i} overflow is ${overflow}`);
            if (!blend) {
                overflowPerSection = overflow;
                if (Math.abs(overflow) < 1.0) break;
            }
        }

        if (Math.abs(overflow) > 1.0 && unclampedSections.length > 0) {
            // we weren't able to distribute all the overflow so recurse and try again
            // log("recursing with", overflow, unclampedSections);
            overflow = this._applyOverflow(overflow, unclampedSections, blend);
        }

        return overflow;
    }

    _rebalanceAbove(anchor, overflowAbove) {
        if (Math.abs(overflowAbove) > 1.0) {
            // log(`trying to rebalance upstream with ${overflowAbove}`);
            const sections = [];
            for (let i = anchor - 1; i >= 0; i--) {
                sections.push(i);
            }
            overflowAbove = this._applyOverflow(overflowAbove, sections);
        }
        return overflowAbove;
    }

    _rebalanceBelow(anchor, overflowBelow) {
        if (Math.abs(overflowBelow) > 1.0) {
            // log(`trying to rebalance downstream with ${overflowBelow}`);
            const sections = [];
            for (let i = anchor + 1; i < this._sections.length; i++) {
                sections.push(i);
            }
            overflowBelow = this._applyOverflow(overflowBelow, sections);
            //log(`rebalanced downstream with ${overflowBelow}`);
        }
        return overflowBelow;
    }

    // @param offset the amount the anchor is moved from what is stored in _sectionHeights, positive if downwards
    // if we're clamped, return the offset we should be clamped at.
    _relayout(anchor = 0, offset = 0, clamped = false) {
        this._heights = this._sections.map((section) => this._sectionHeights[section.id]);
        // are these the amounts the items above/below shrank/grew and need to be relayouted?
        let overflowAbove;
        let overflowBelow;
        const maxHeight = this._getMaxHeight(anchor);
        const minHeight = this._getMinHeight(anchor);
        // new height > max ?
        if (this._heights[anchor] + offset > maxHeight) {
            // we're pulling downwards and clamped
            // overflowAbove = minus how much are we above max height?
            overflowAbove = (maxHeight - this._heights[anchor]) - offset;
            overflowBelow = offset;
            // log(`pulling downwards clamped at max: ${overflowAbove} ${overflowBelow}`);
        } else if (this._heights[anchor] + offset < minHeight) { // new height < min?
            // we're pulling upwards and clamped
            // overflowAbove = ??? (offset is negative here, so - offset will add)
            overflowAbove = (minHeight - this._heights[anchor]) - offset;
            overflowBelow = offset;
            // log(`pulling upwards clamped at min: ${overflowAbove} ${overflowBelow}`);
        } else {
            overflowAbove = 0;
            overflowBelow = offset;
            // log(`resizing the anchor: ${overflowAbove} ${overflowBelow}`);
        }
        this._heights[anchor] = clamp(this._heights[anchor] + offset, minHeight, maxHeight);

        // these are reassigned the amount of overflow that could not be rebalanced
        // meaning we dragged the handle too far and it can't follow the cursor anymore
        overflowAbove = this._rebalanceAbove(anchor, overflowAbove);
        overflowBelow = this._rebalanceBelow(anchor, overflowBelow);

        if (!clamped) { // to avoid risk of infinite recursion
            // clamp to avoid overflowing or underflowing the page
            if (Math.abs(overflowAbove) > 1.0) {
                // log(`clamping with overflowAbove ${overflowAbove}`);
                // here we do the layout again with offset - the amount of space we took too much
                this._relayout(anchor, offset + overflowAbove, true);
                return offset + overflowAbove;
            }

            if (Math.abs(overflowBelow) > 1.0) {
                // here we do the layout again with offset - the amount of space we took too much
                // log(`clamping with overflowBelow ${overflowBelow}`);
                this._relayout(anchor, offset - overflowBelow, true);
                return offset - overflowBelow;
            }
        }

        this._applyHeights();
        return undefined;
    }

    _applyHeights() {
        log("updating layout, heights are now", this._heights);
        // apply the heights
        for (let i = 0; i < this._sections.length; i++) {
            const section = this._sections[i];
            this._applyHeight(section.id, this._heights[i]);
        }
    }

    _commitHeights() {
        this._sections.forEach((section, i) => {
            this._sectionHeights[section.id] = this._heights[i];
        });
    }
}

class Handle {
    constructor(layout, anchor, height) {
        this._layout = layout;
        this._anchor = anchor;
        this._initialHeight = height;
    }

    setHeight(height) {
        this._layout._relayout(this._anchor, height - this._initialHeight);
        return this;
    }

    finish() {
        this._layout._commitHeights();
        return this;
    }
}

export class Distributor extends FixedDistributor {
    constructor(item, cfg) {
        super(item);
        const layout = cfg.layout;
        this._handle = layout.openHandle(item.id);
    }

    finish() {
        this._handle.finish();
    }

    resize(height) {
        this._handle.setHeight(height);
    }
}
<commit_msg>fix lint - bis<commit_after>/*
Copyright 2019 New Vector Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import FixedDistributor from "./fixed";

// const allowWhitespace = true;
const handleHeight = 1;

function log() {
    // console.log.apply(console, ["LAYOUT: "].concat(params));
}

function clamp(height, min, max) {
    //log(`clamping ${height} between ${min} and ${max}`);
    if (height > max) return max;
    if (height < min) return min;
    return height;
}

export class Layout {
    constructor(applyHeight, initialSizes, collapsedState) {
        this._applyHeight = applyHeight;
        this._sections = [];
        this._collapsedState = Object.assign({}, collapsedState);
        this._availableHeight = 0;
        // heights stored by section section id
        this._sectionHeights = Object.assign({}, initialSizes);
        // in-progress heights, while dragging. Committed on mouse-up.
        this._heights = [];
    }

    setAvailableHeight(newSize) {
        this._availableHeight = newSize;
        // needs more work
        this._applyNewSize();
    }

    expandSection(id, height) {
        this._collapsedState[id] = false;
        this._applyNewSize();
        this.openHandle(id).setHeight(height).finish();
    }

    collapseSection(id) {
        this._collapsedState[id] = true;
        this._applyNewSize();
    }

    // [{id, count}]
    update(sections, availableHeight) {
        if (Number.isFinite(availableHeight)) {
            this._availableHeight = availableHeight;
        }
        const totalHeight = this._getAvailableHeight();
        this._sections.forEach((section, i) => {
            if (!this._sectionHeights.hasOwnProperty(section.id)) {
                this._sectionHeights[section.id] = clamp(
                    totalHeight / this._sections.length,
                    this._getMinHeight(i),
                    this._getMaxHeight(i),
                );
            }
        });
        this._sections = sections;
        this._applyNewSize();
    }

    openHandle(id) {
        const index = this._getSectionIndex(id);
        //log(`openHandle resolved ${id} to ${index}`);
        return new Handle(this, index, this._sectionHeights[id]);
    }

    _getAvailableHeight() {
        const nonCollapsedSectionCount = this._sections.reduce((count, section) => {
            const collapsed = this._collapsedState[section.id];
            return count + (collapsed ? 0 : 1);
        }, 0);
        return this._availableHeight - ((nonCollapsedSectionCount - 1) * handleHeight);
    }

    _applyNewSize() {
        const newHeight = this._getAvailableHeight();
        const currHeight = this._sections.reduce((sum, section) => {
            return sum + this._sectionHeights[section.id];
        }, 0);
        const offset = newHeight - currHeight;
        this._heights = this._sections.map((section) => this._sectionHeights[section.id]);
        const sections = this._sections.map((_, i) => i);
        this._applyOverflow(-offset, sections, true);
        this._applyHeights();
        this._commitHeights();
    }

    _getSectionIndex(id) {
        return this._sections.findIndex((s) => s.id === id);
    }

    _getMaxHeight(i) {
        const section = this._sections[i];
        const collapsed = this._collapsedState[section.id];

        if (collapsed) {
            return this._sectionHeight(0);
        } else {
            return 100000;
            // return this._sectionHeight(section.count);
        }
    }

    _sectionHeight(count) {
        return 36 + (count === 0 ? 0 : 4 + (count * 34));
    }

    _getMinHeight(i) {
        const section = this._sections[i];
        const collapsed = this._collapsedState[section.id];
        const maxItems = collapsed ? 0 : 1;
        // log("_getMinHeight", i, section);
        return this._sectionHeight(Math.min(section.count, maxItems));
    }

    _applyOverflow(overflow, sections, blend) {
        //log("applyOverflow", overflow, sections);
        // take the given overflow amount, and applies it to the given sections.
        // calls itself recursively until it has distributed all the overflow
        // or run out of unclamped sections.

        const unclampedSections = [];

        let overflowPerSection = blend ? (overflow / sections.length) : overflow;
        for (const i of sections) {
            const newHeight = clamp(
                this._heights[i] - overflowPerSection,
                this._getMinHeight(i),
                this._getMaxHeight(i),
            );
            if (newHeight == this._heights[i] - overflowPerSection) {
                unclampedSections.push(i);
            }
            // when section is growing, overflow increases?
            // 100 -= 200 - 300
            // 100 -= -100
            // 200
            overflow -= this._heights[i] - newHeight;
            // console.log(`this._heights[${i}] (${this._heights[i]}) - newHeight (${newHeight}) = ${this._heights[i] - newHeight}`);
            // console.log(`changing ${this._heights[i]} to ${newHeight}`);
            this._heights[i] = newHeight;
            // console.log(`for section ${i} overflow is ${overflow}`);
            if (!blend) {
                overflowPerSection = overflow;
                if (Math.abs(overflow) < 1.0) break;
            }
        }

        if (Math.abs(overflow) > 1.0 && unclampedSections.length > 0) {
            // we weren't able to distribute all the overflow so recurse and try again
            // log("recursing with", overflow, unclampedSections);
            overflow = this._applyOverflow(overflow, unclampedSections, blend);
        }

        return overflow;
    }

    _rebalanceAbove(anchor, overflowAbove) {
        if (Math.abs(overflowAbove) > 1.0) {
            // log(`trying to rebalance upstream with ${overflowAbove}`);
            const sections = [];
            for (let i = anchor - 1; i >= 0; i--) {
                sections.push(i);
            }
            overflowAbove = this._applyOverflow(overflowAbove, sections);
        }
        return overflowAbove;
    }

    _rebalanceBelow(anchor, overflowBelow) {
        if (Math.abs(overflowBelow) > 1.0) {
            // log(`trying to rebalance downstream with ${overflowBelow}`);
            const sections = [];
            for (let i = anchor + 1; i < this._sections.length; i++) {
                sections.push(i);
            }
            overflowBelow = this._applyOverflow(overflowBelow, sections);
            //log(`rebalanced downstream with ${overflowBelow}`);
        }
        return overflowBelow;
    }

    // @param offset the amount the anchor is moved from what is stored in _sectionHeights, positive if downwards
    // if we're clamped, return the offset we should be clamped at.
    _relayout(anchor = 0, offset = 0, clamped = false) {
        this._heights = this._sections.map((section) => this._sectionHeights[section.id]);
        // are these the amounts the items above/below shrank/grew and need to be relayouted?
        let overflowAbove;
        let overflowBelow;
        const maxHeight = this._getMaxHeight(anchor);
        const minHeight = this._getMinHeight(anchor);
        // new height > max ?
        if (this._heights[anchor] + offset > maxHeight) {
            // we're pulling downwards and clamped
            // overflowAbove = minus how much are we above max height?
            overflowAbove = (maxHeight - this._heights[anchor]) - offset;
            overflowBelow = offset;
            // log(`pulling downwards clamped at max: ${overflowAbove} ${overflowBelow}`);
        } else if (this._heights[anchor] + offset < minHeight) { // new height < min?
            // we're pulling upwards and clamped
            // overflowAbove = ??? (offset is negative here, so - offset will add)
            overflowAbove = (minHeight - this._heights[anchor]) - offset;
            overflowBelow = offset;
            // log(`pulling upwards clamped at min: ${overflowAbove} ${overflowBelow}`);
        } else {
            overflowAbove = 0;
            overflowBelow = offset;
            // log(`resizing the anchor: ${overflowAbove} ${overflowBelow}`);
        }
        this._heights[anchor] = clamp(this._heights[anchor] + offset, minHeight, maxHeight);

        // these are reassigned the amount of overflow that could not be rebalanced
        // meaning we dragged the handle too far and it can't follow the cursor anymore
        overflowAbove = this._rebalanceAbove(anchor, overflowAbove);
        overflowBelow = this._rebalanceBelow(anchor, overflowBelow);

        if (!clamped) { // to avoid risk of infinite recursion
            // clamp to avoid overflowing or underflowing the page
            if (Math.abs(overflowAbove) > 1.0) {
                // log(`clamping with overflowAbove ${overflowAbove}`);
                // here we do the layout again with offset - the amount of space we took too much
                this._relayout(anchor, offset + overflowAbove, true);
                return offset + overflowAbove;
            }

            if (Math.abs(overflowBelow) > 1.0) {
                // here we do the layout again with offset - the amount of space we took too much
                // log(`clamping with overflowBelow ${overflowBelow}`);
                this._relayout(anchor, offset - overflowBelow, true);
                return offset - overflowBelow;
            }
        }

        this._applyHeights();
        return undefined;
    }

    _applyHeights() {
        log("updating layout, heights are now", this._heights);
        // apply the heights
        for (let i = 0; i < this._sections.length; i++) {
            const section = this._sections[i];
            this._applyHeight(section.id, this._heights[i]);
        }
    }

    _commitHeights() {
        this._sections.forEach((section, i) => {
            this._sectionHeights[section.id] = this._heights[i];
        });
    }
}

class Handle {
    constructor(layout, anchor, height) {
        this._layout = layout;
        this._anchor = anchor;
        this._initialHeight = height;
    }

    setHeight(height) {
        this._layout._relayout(this._anchor, height - this._initialHeight);
        return this;
    }

    finish() {
        this._layout._commitHeights();
        return this;
    }
}

export class Distributor extends FixedDistributor {
    constructor(item, cfg) {
        super(item);
        const layout = cfg.layout;
        this._handle = layout.openHandle(item.id);
    }

    finish() {
        this._handle.finish();
    }

    resize(height) {
        this._handle.setHeight(height);
    }
}
<|endoftext|>


<commit_before><commit_msg>Update cli for script<commit_after><|endoftext|>


<commit_before>class RoughSpriteGenerator
{
  constructor(game) {
    this.game = game;
  }

  getRectangle(bmd, width, height, config) {
    let rc = rough.canvas(bmd.canvas);
    rc.rectangle(0, 0, width, height, config);
  }

  getCircle(bmd, center, radius, config) {
    let rc = rough.canvas(bmd.canvas);
    rc.circle(center.x, center.y, radius * 2, config);
  }

  getLine(bmd, dist, config) {
    this.getRectangle(bmd, dist, 2, config);
  }

  getPolygon(bmd, data, config) {
    let rc = rough.canvas(bmd.canvas);
    rc.path(data, config);
  }

  getCircleSprite(x, y, radius, config = {}) {
    const defaultConfig = {
      fill: "rgb(10,150,10)",
      fillWeight: 5 // thicker lines for hachure
    };
    const configs = Object.assign({}, defaultConfig, config);
    const realRadius = radius + (config.fillWeight|| 0);
    let bmd = this.game.add.bitmapData(realRadius * 2, realRadius * 2);
    this.getCircle(bmd, {x: realRadius, y: realRadius}, radius, configs);
    return new Phaser.Sprite(this.game, x, y, bmd);
  }

  getRectangleSprite(x, y, width, height, config = {}) {
    let bmd = this.game.add.bitmapData(width, height);
    const defaultConfig = {
        fill: 'black',
        stroke: 'black',
        hachureAngle: 60,
        hachureGap: 10,
        fillWeight: 5,
        strokeWidth: 5
      };
    const configs = Object.assign({}, defaultConfig, config);
    this.getRectangle(bmd, width, height, configs);
    return new Phaser.Sprite(this.game, x, y, bmd);
  }

  getLineSprite(x, y, x1, y1, x2, y2, config = {}) {
    const dist = this.lengthFromPoints(x1, y1, x2, y2);
    let bmd = this.game.add.bitmapData(dist, 2);
    this.getLine(bmd, dist, config);
    const angle = Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI;
    let sprite = new Phaser.Sprite(this.game, x, y, bmd);
    sprite.angle =- angle;
    return sprite;
  }

  getPolygonSprite(x,y, data, config) {
    let bmd = this.game.add.bitmapData(500, 500);
    this.getPolygon(bmd, data, config);
    return new Phaser.Sprite(this.game, x, y, bmd);
  }

  lengthFromPoints(x1, y1, x2, y2) {
     return Math.sqrt( ((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1)) );
  }

}
export default RoughSpriteGenerator;<commit_msg>add path<commit_after>class RoughSpriteGenerator
{
  constructor(game) {
    this.game = game;
  }

  getRectangle(bmd, width, height, config) {
    let rc = rough.canvas(bmd.canvas);
    rc.rectangle(0, 0, width, height, config);
  }

  getCircle(bmd, center, radius, config) {
    let rc = rough.canvas(bmd.canvas);
    rc.circle(center.x, center.y, radius * 2, config);
  }

  getLine(bmd, dist, config) {
    this.getRectangle(bmd, dist, 2, config);
  }

  getPolygon(bmd, data, config) {
    let rc = rough.canvas(bmd.canvas);
    rc.path(data, config);
  }

  getCircleSprite(x, y, radius, config = {}) {
    const defaultConfig = {
      fill: "rgb(10,150,10)",
      fillWeight: 5 // thicker lines for hachure
    };
    const configs = Object.assign({}, defaultConfig, config);
    const realRadius = radius + (config.fillWeight|| 0);
    let bmd = this.game.add.bitmapData(realRadius * 2, realRadius * 2);
    this.getCircle(bmd, {x: realRadius, y: realRadius}, radius, configs);
    return new Phaser.Sprite(this.game, x, y, bmd);
  }

  getRectangleSprite(x, y, width, height, config = {}) {
    let bmd = this.game.add.bitmapData(width, height);
    const defaultConfig = {
        fill: 'black',
        stroke: 'black',
        hachureAngle: 60,
        hachureGap: 10,
        fillWeight: 5,
        strokeWidth: 5
      };
    const configs = Object.assign({}, defaultConfig, config);
    this.getRectangle(bmd, width, height, configs);
    return new Phaser.Sprite(this.game, x, y, bmd);
  }

  getLineSprite(x, y, x1, y1, x2, y2, config = {}) {
    const dist = this.lengthFromPoints(x1, y1, x2, y2);
    let bmd = this.game.add.bitmapData(dist, 2);
    this.getLine(bmd, dist, config);
    const angle = Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI;
    let sprite = new Phaser.Sprite(this.game, x, y, bmd);
    sprite.angle =- angle;
    return sprite;
  }

  getPolygonSprite(x,y, data, width, height, config) {
    let bmd = this.game.add.bitmapData(width, height);
    this.getPolygon(bmd, data, config);
    return new Phaser.Sprite(this.game, x, y, bmd);
  }

  lengthFromPoints(x1, y1, x2, y2) {
     return Math.sqrt( ((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1)) );
  }

}
export default RoughSpriteGenerator;<|endoftext|>


<commit_before>import React from 'react'
import PropTypes from 'prop-types'

export const Counter = ({ counter, increment, doubleAsync }) => (

Counter: {counter}

    <button className='btn btn-primary' onClick={increment}>
      Increment
    </button>
    {' '}
    <button className='btn btn-secondary' onClick={doubleAsync}>
      Double (Async)
    </button>

)
Counter.propTypes = {
  counter: PropTypes.number.isRequired,
  increment: PropTypes.func.isRequired,
  doubleAsync: PropTypes.func.isRequired,
}

export default Counter
<commit_msg>correção da div<commit_after>import React from 'react'
import PropTypes from 'prop-types'

export const Counter = ({ counter, increment, doubleAsync }) => (

Counter: {counter}

    <button className='btn btn-primary' onClick={increment}>
      Increment
    </button>
    {' '}
    <button className='btn btn-secondary' onClick={doubleAsync}>
      Double (Async)
    </button>

)
Counter.propTypes = {
  counter: PropTypes.number.isRequired,
  increment: PropTypes.func.isRequired,
  doubleAsync: PropTypes.func.isRequired,
}

export default Counter
<|endoftext|>


<commit_before>/*!
 * ${copyright}
 */

// Provides control sap.m.ProgressIndicator.
sap.ui.define([
	'./library',
	'sap/ui/core/Control',
	"sap/ui/Device",
	'sap/ui/core/Icon',
	'sap/ui/core/ResizeHandler',
	'sap/ui/core/ValueStateSupport',
	'sap/ui/core/library',
	'./ProgressIndicatorRenderer',
	"sap/base/Log",
	"sap/m/Popover",
	"sap/m/Text"
],
	function(
	library,
	Control,
	Device,
	Icon,
	ResizeHandler,
	ValueStateSupport,
	coreLibrary,
	ProgressIndicatorRenderer,
	Log,
	Popover,
	Text
	) {
	"use strict";

	// shortcut for sap.ui.core.TextDirection
	var TextDirection = coreLibrary.TextDirection;

	// shortcut for sap.ui.core.ValueState
	var ValueState = coreLibrary.ValueState;

	// shortcut for sap.m.PlacementType
	var PlacementType = library.PlacementType;

	/**
	 * Constructor for a new ProgressIndicator.
	 *
	 * @param {string} [sId] ID for the new control, generated automatically if no ID is given
	 * @param {object} [mSettings] Initial settings for the new control
	 *
	 * @class
	 * Shows the progress of a process in a graphical way. To indicate the progress, the inside of the ProgressIndicator is filled with a color.
	 * Additionally, a user-defined string can be displayed on the ProgressIndicator.
	 *
	 * @see {@link fiori:https://experience.sap.com/fiori-design-web/progress-indicator/ Progress Indicator}
	 *
	 * @extends sap.ui.core.Control
	 *
	 * @author SAP SE
	 * @version ${version}
	 *
	 * @constructor
	 * @public
	 * @since 1.13.1
	 * @alias sap.m.ProgressIndicator
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var ProgressIndicator = Control.extend("sap.m.ProgressIndicator", /** @lends sap.m.ProgressIndicator.prototype */ { metadata : {

		interfaces : ["sap.ui.core.IFormContent"],
		library : "sap.m",
		properties : {
			/**
			 * Switches enabled state of the control. Disabled fields have different colors, and cannot be focused.
			 */
			enabled : {type : "boolean", group : "Behavior", defaultValue : true},

			/**
			 * Specifies the state of the bar. Enumeration sap.ui.core.ValueState provides Error, Warning, Success, Information, None (default value).
			 * The color for each state depends on the theme.
			 */
			state : {type : "sap.ui.core.ValueState", group : "Appearance", defaultValue : ValueState.None},

			/**
			 * Specifies the text value to be displayed in the bar.
			 */
			displayValue : {type : "string", group : "Appearance", defaultValue : null},

			/**
			 * Specifies the numerical value in percent for the length of the progress bar.
			 *
			 * Note: If a value greater than 100 is provided, the percentValue is set to 100.
			 * In other cases of invalid value, percentValue is set to its default of 0.
			 */
			percentValue : {type : "float", group : "Data", defaultValue : 0},

			/**
			 * Indicates whether the displayValue should be shown in the ProgressIndicator.
			 */
			showValue : {type : "boolean", group : "Appearance", defaultValue : true},

			/**
			 * Specifies the width of the control.
			 */
			width : {type : "sap.ui.core.CSSSize", group : "Dimension", defaultValue : '100%'},

			/**
			 * Specifies the height of the control. The default value depends on the theme. Suggested size for normal use is 2.5rem (40px). Suggested size for small size (like for use in ObjectHeader) is 1.375rem (22px).
			 * @since 1.15.0
			 */
			height : {type : "sap.ui.core.CSSSize", group : "Dimension", defaultValue : null},

			/**
			 * Specifies the element's text directionality with enumerated options (RTL or LTR). By default, the control inherits text direction from the DOM.
			 * @since 1.28.0
			 */
			textDirection : {type : "sap.ui.core.TextDirection", group : "Appearance", defaultValue : TextDirection.Inherit},

			/**
			 * Determines whether the control is in display-only state where the control has different visualization and cannot be focused.
			 * @since 1.50
			 */
			displayOnly : {type : "boolean", group : "Behavior", defaultValue : false},

			/**
			 * Determines whether a percentage change is displayed with animation.
			 * @since 1.73
			 */
			displayAnimation : {type : "boolean", group : "Behavior", defaultValue : true}
		},
		aggregations: {
			_popover: {type: "sap.m.Popover", multiple: false, visibility: "hidden"}
		},
		associations : {
			/**
			 * Association to controls / IDs which describe this control (see WAI-ARIA attribute aria-describedby).
			 * @since 1.69
			 */
			ariaDescribedBy : {type : "sap.ui.core.Control", multiple : true, singularName : "ariaDescribedBy"},

			/**
			 * Association to controls / IDs which label this control (see WAI-ARIA attribute aria-labelledBy).
			 * @since 1.69
			 */
			ariaLabelledBy: {type : "sap.ui.core.Control", multiple : true, singularName : "ariaLabelledBy"}
		},
		designtime: "sap/m/designtime/ProgressIndicator.designtime"
	}});

	ProgressIndicator.RESIZE_HANDLER_ID = {
		SELF: "_sResizeHandlerId"
	};

	var bUseAnimations = sap.ui.getCore().getConfiguration().getAnimation();

	ProgressIndicator.prototype.init = function () {
		this._bIEBrowser = Device.browser.internet_explorer;
	};

	ProgressIndicator.prototype.onBeforeRendering = function () {
		this._deRegisterResizeHandler(ProgressIndicator.RESIZE_HANDLER_ID.SELF);
	};

	ProgressIndicator.prototype.onAfterRendering = function () {
		this._updateHoverableScenario();
		this._registerResizeHandler(ProgressIndicator.RESIZE_HANDLER_ID.SELF, this, this._onResize.bind(this));
	};

	ProgressIndicator.prototype.exit = function () {
		if (this._oPopoverText) {
			this._oPopoverText.destroy();
			this._oPopoverText = null;
		}

		this._deRegisterResizeHandler(ProgressIndicator.RESIZE_HANDLER_ID.SELF);
	};

	/**
	 * Registers resize handler.
	 * @param {string} sHandler the handler ID
	 * @param {Object} oObject
	 * @param {Function} fnHandler
	 * @private
	 */
	ProgressIndicator.prototype._registerResizeHandler = function (sHandler, oObject, fnHandler) {
		if (!this[sHandler]) {
			this[sHandler] = ResizeHandler.register(oObject, fnHandler);
		}
	};

	/**
	 * De-registers resize handler.
	 * @param {string} sHandler the handler ID
	 * @private
	 */
	ProgressIndicator.prototype._deRegisterResizeHandler = function (sHandler) {
		if (this[sHandler]) {
			ResizeHandler.deregister(this[sHandler]);
			this[sHandler] = null;
		}
	};

	/**
	 * Handles the resize event of the ProgressIndicator.
	 * @param {jQuery.Event} oEvent
	 * @private
	 */
	ProgressIndicator.prototype._onResize = function (oEvent) {
		this._updateHoverableScenario();
	};

	/**
	 * Handles the ProgressIndicator press event.
	 * @param {jQuery.Event} oEvent The tap event object
	 */
	ProgressIndicator.prototype.ontap = function (oEvent) {
		var oPopover;

		// By UX in ordeer to open the helper popover, we should have
		// displayValue text and the text should be truncated (hoverable scenario).
		if (this._isHoverable()) {
			oPopover = this._getPopover();
			if (oPopover.isOpen()) {
				oPopover.close();
			} else {
				oPopover.openBy(this);
			}
		}
	};

	/**
	 * Updates the hoverable scenario.
	 * If we have a hoverable scenario we toggle on the "sapMPIHoverable" CSS class and vice-versa.
	 * @private
	 */
	ProgressIndicator.prototype._updateHoverableScenario = function () {
		var oDOMPIDisplayValueText = this.$(this.getPercentValue() > 50 ? "textLeft" : "textRight")[0],
			iOffsetWidth = oDOMPIDisplayValueText && oDOMPIDisplayValueText.offsetWidth,
			iScrollWidth = oDOMPIDisplayValueText && oDOMPIDisplayValueText.scrollWidth;

		// TODO: IE specific code - adding 1px tolerance, because of a know issue with difference b/w offsetWidth and scrollWidth
		if (this._bIEBrowser) {
			iOffsetWidth += 1;
		}

		// By VD if we have displayValue text and the text is truncated, we
		// need to change the cursor of the ProgressIndicator to "pointer" on hover.
		this.toggleStyleClass("sapMPIHoverable", this.getDisplayValue() !== "" && iOffsetWidth < iScrollWidth);
	};

	/**
	 * Whether or not the ProgressIndicator is hoverable.
	 * @returns {boolean} True if ProgressIndicator has "sapMPIHoverable" CSS class.
	 * @private
	 */
	ProgressIndicator.prototype._isHoverable = function () {
		return this.hasStyleClass("sapMPIHoverable");
	};

	/**
	 * Lazy loader for the popover.
	 * @returns {sap.m.Popover}
	 * @private
	 */
	ProgressIndicator.prototype._getPopover = function () {
		var oPopover;

		if (!this.getAggregation("_popover")) {
			this._oPopoverText = new Text({
				text: this.getDisplayValue()
			});
			// Create the Popover
			oPopover = new Popover(this.getId() + "-popover", {
				showHeader: false,
				placement: PlacementType.Bottom,
				content: [this._oPopoverText,
					new Icon({
						src: "sap-icon://decline",
						press: this._onPopoverCloseIconPress.bind(this)
					})
				]
			}).addStyleClass('sapMPIPopover');

			this.setAggregation("_popover", oPopover, true);
		}

		return this.getAggregation("_popover");
	};

	ProgressIndicator.prototype._onPopoverCloseIconPress = function() {
		this._getPopover().close();
	};

	ProgressIndicator.prototype.setDisplayValue = function(sDisplayValue) {
		this.setProperty("displayValue", sDisplayValue);

		if (this._oPopoverText) {
			this._oPopoverText.setText(sDisplayValue);
		}

		return this;
	};

	ProgressIndicator.prototype.setPercentValue = function(fPercentValue) {
		var that = this,
			$progressBar,
			fPercentDiff,
			$progressIndicator = this.$(),
			fAnimationDuration,
			fOriginalValue = fPercentValue;

		fPercentValue = parseFloat(fPercentValue);

		if (!isValidPercentValue(fPercentValue)) {
			if (fPercentValue > 100) {
				fPercentValue = 100;
			} else if (fPercentValue < 0) {
				fPercentValue = 0;
			} else {
				Log.warning(this + ": percentValue (" + fOriginalValue + ") is not a valid number! The provided value will not be set!");
				return this;
			}
			Log.warning(this + ": percentValue (" + fOriginalValue + ") is not correct! Setting the percentValue to " + fPercentValue);
		}

		if (this.getPercentValue() !== fPercentValue) {
			fPercentDiff = this.getPercentValue() - fPercentValue;
			this.setProperty("percentValue", fPercentValue, true);

			if (!$progressIndicator.length) {
				return this;
			}

			["sapMPIValueMax", "sapMPIValueMin", "sapMPIValueNormal", "sapMPIValueGreaterHalf"].forEach(function (sClass){
				$progressIndicator.removeClass(sClass);
			});

			$progressIndicator.addClass(this._getCSSClassByPercentValue(fPercentValue).join(" "));
			$progressIndicator.addClass("sapMPIAnimate")
				.attr("aria-valuenow", fPercentValue)
				.attr("aria-valuetext", this._getAriaValueText({fPercent: fPercentValue}));

			fAnimationDuration = bUseAnimations && this.getDisplayAnimation() ? Math.abs(fPercentDiff) * 20 : 0;
			$progressBar = this.$("bar");
			// Stop currently running animation and start new one.
			// In case of multiple setPercentValue calls all animations will run and it will take some time until the last value is animated,
			// which is the one, actually valuable.
			$progressBar.stop();
			$progressBar.animate({
				"flex-basis" : fPercentValue + "%"
			}, fAnimationDuration, "linear", function() {
				that._setText.apply(that);
				that.$().removeClass("sapMPIAnimate");
			});
		}

		return this;
	};

	ProgressIndicator.prototype._setText = function() {
		this.$().toggleClass("sapMPIValueGreaterHalf", this.getPercentValue() > 50);
		return this;
	};

	/**
	 * Determines the CSS class, which should be applied to the ProgressIndicator
	 * for the given percentValue.
	 * @param {Number} fPercentValue
	 * @return {String} the CSS class
	 * @since 1.44
	 * @private
	 */
	ProgressIndicator.prototype._getCSSClassByPercentValue = function(fPercentValue) {
		if (fPercentValue === 100) {
			return ["sapMPIValueMax", "sapMPIValueGreaterHalf"];
		}

		if (fPercentValue === 0) {
			return ["sapMPIValueMin"];
		}

		if (fPercentValue <= 50) {
			return ["sapMPIValueNormal"];
		}

		return ["sapMPIValueNormal", "sapMPIValueGreaterHalf"];
	};

	ProgressIndicator.prototype._getAriaValueText = function (oParams) {
		oParams.sText = oParams.sText || this.getDisplayValue();
		oParams.fPercent = oParams.fPercent || this.getPercentValue();
		oParams.sStateText = oParams.sStateText || this._getStateText();

		var sAriaValueText = oParams.sText || oParams.fPercent + "%";
		if (oParams.sStateText) {
			sAriaValueText += " " + oParams.sStateText;
		}

		return sAriaValueText;
	};

	ProgressIndicator.prototype._getStateText = function () {
		return this.getEnabled() ? ValueStateSupport.getAdditionalText(this.getState()) : "";
	};

	/**
	 * Returns the sap.m.ProgressIndicator  accessibility information.
	 *
	 * @see sap.ui.core.Control#getAccessibilityInfo
	 * @protected
	 * @returns {object} The sap.m.ProgressIndicator accessibility information
	 */
	ProgressIndicator.prototype.getAccessibilityInfo = function() {
		var oBundle = sap.ui.getCore().getLibraryResourceBundle("sap.m"),
			sDisplayValue = this.getDisplayValue(),
			sDescription = sDisplayValue ? sDisplayValue : oBundle.getText("ACC_CTR_STATE_PROGRESS", [this.getPercentValue()]);

		return {
			role: "progressbar",
			type: oBundle.getText("ACC_CTR_TYPE_PROGRESS"),
			description: sDescription,
			focusable: this.getEnabled(),
			enabled: this.getEnabled()
		};
	};

	function isValidPercentValue(value) {
		return !isNaN(value) && value >= 0 && value <= 100;
	}

	return ProgressIndicator;

});<commit_msg>[INTERNAL][FIX] sap.m.ProgressIndicator: Fixed wrong event bubbling<commit_after>/*!
 * ${copyright}
 */

// Provides control sap.m.ProgressIndicator.
sap.ui.define([
	'./library',
	'sap/ui/core/Control',
	"sap/ui/Device",
	'sap/ui/core/Icon',
	'sap/ui/core/ResizeHandler',
	'sap/ui/core/ValueStateSupport',
	'sap/ui/core/library',
	'./ProgressIndicatorRenderer',
	"sap/base/Log",
	"sap/m/Popover",
	"sap/m/Text"
],
	function(
	library,
	Control,
	Device,
	Icon,
	ResizeHandler,
	ValueStateSupport,
	coreLibrary,
	ProgressIndicatorRenderer,
	Log,
	Popover,
	Text
	) {
	"use strict";

	// shortcut for sap.ui.core.TextDirection
	var TextDirection = coreLibrary.TextDirection;

	// shortcut for sap.ui.core.ValueState
	var ValueState = coreLibrary.ValueState;

	// shortcut for sap.m.PlacementType
	var PlacementType = library.PlacementType;

	/**
	 * Constructor for a new ProgressIndicator.
	 *
	 * @param {string} [sId] ID for the new control, generated automatically if no ID is given
	 * @param {object} [mSettings] Initial settings for the new control
	 *
	 * @class
	 * Shows the progress of a process in a graphical way. To indicate the progress, the inside of the ProgressIndicator is filled with a color.
	 * Additionally, a user-defined string can be displayed on the ProgressIndicator.
	 *
	 * @see {@link fiori:https://experience.sap.com/fiori-design-web/progress-indicator/ Progress Indicator}
	 *
	 * @extends sap.ui.core.Control
	 *
	 * @author SAP SE
	 * @version ${version}
	 *
	 * @constructor
	 * @public
	 * @since 1.13.1
	 * @alias sap.m.ProgressIndicator
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var ProgressIndicator = Control.extend("sap.m.ProgressIndicator", /** @lends sap.m.ProgressIndicator.prototype */ { metadata : {

		interfaces : ["sap.ui.core.IFormContent"],
		library : "sap.m",
		properties : {
			/**
			 * Switches enabled state of the control. Disabled fields have different colors, and cannot be focused.
			 */
			enabled : {type : "boolean", group : "Behavior", defaultValue : true},

			/**
			 * Specifies the state of the bar. Enumeration sap.ui.core.ValueState provides Error, Warning, Success, Information, None (default value).
			 * The color for each state depends on the theme.
			 */
			state : {type : "sap.ui.core.ValueState", group : "Appearance", defaultValue : ValueState.None},

			/**
			 * Specifies the text value to be displayed in the bar.
			 */
			displayValue : {type : "string", group : "Appearance", defaultValue : null},

			/**
			 * Specifies the numerical value in percent for the length of the progress bar.
			 *
			 * Note: If a value greater than 100 is provided, the percentValue is set to 100.
			 * In other cases of invalid value, percentValue is set to its default of 0.
			 */
			percentValue : {type : "float", group : "Data", defaultValue : 0},

			/**
			 * Indicates whether the displayValue should be shown in the ProgressIndicator.
			 */
			showValue : {type : "boolean", group : "Appearance", defaultValue : true},

			/**
			 * Specifies the width of the control.
			 */
			width : {type : "sap.ui.core.CSSSize", group : "Dimension", defaultValue : '100%'},

			/**
			 * Specifies the height of the control. The default value depends on the theme. Suggested size for normal use is 2.5rem (40px). Suggested size for small size (like for use in ObjectHeader) is 1.375rem (22px).
			 * @since 1.15.0
			 */
			height : {type : "sap.ui.core.CSSSize", group : "Dimension", defaultValue : null},

			/**
			 * Specifies the element's text directionality with enumerated options (RTL or LTR). By default, the control inherits text direction from the DOM.
			 * @since 1.28.0
			 */
			textDirection : {type : "sap.ui.core.TextDirection", group : "Appearance", defaultValue : TextDirection.Inherit},

			/**
			 * Determines whether the control is in display-only state where the control has different visualization and cannot be focused.
			 * @since 1.50
			 */
			displayOnly : {type : "boolean", group : "Behavior", defaultValue : false},

			/**
			 * Determines whether a percentage change is displayed with animation.
			 * @since 1.73
			 */
			displayAnimation : {type : "boolean", group : "Behavior", defaultValue : true}
		},
		aggregations: {
			_popover: {type: "sap.m.Popover", multiple: false, visibility: "hidden"}
		},
		associations : {
			/**
			 * Association to controls / IDs which describe this control (see WAI-ARIA attribute aria-describedby).
			 * @since 1.69
			 */
			ariaDescribedBy : {type : "sap.ui.core.Control", multiple : true, singularName : "ariaDescribedBy"},

			/**
			 * Association to controls / IDs which label this control (see WAI-ARIA attribute aria-labelledBy).
			 * @since 1.69
			 */
			ariaLabelledBy: {type : "sap.ui.core.Control", multiple : true, singularName : "ariaLabelledBy"}
		},
		designtime: "sap/m/designtime/ProgressIndicator.designtime"
	}});

	ProgressIndicator.RESIZE_HANDLER_ID = {
		SELF: "_sResizeHandlerId"
	};

	var bUseAnimations = sap.ui.getCore().getConfiguration().getAnimation();

	ProgressIndicator.prototype.init = function () {
		this._bIEBrowser = Device.browser.internet_explorer;
	};

	ProgressIndicator.prototype.onBeforeRendering = function () {
		this._deRegisterResizeHandler(ProgressIndicator.RESIZE_HANDLER_ID.SELF);
	};

	ProgressIndicator.prototype.onAfterRendering = function () {
		this._updateHoverableScenario();
		this._registerResizeHandler(ProgressIndicator.RESIZE_HANDLER_ID.SELF, this, this._onResize.bind(this));
	};

	ProgressIndicator.prototype.exit = function () {
		if (this._oPopoverText) {
			this._oPopoverText.destroy();
			this._oPopoverText = null;
		}

		this._deRegisterResizeHandler(ProgressIndicator.RESIZE_HANDLER_ID.SELF);
	};

	/**
	 * Registers resize handler.
	 * @param {string} sHandler the handler ID
	 * @param {Object} oObject
	 * @param {Function} fnHandler
	 * @private
	 */
	ProgressIndicator.prototype._registerResizeHandler = function (sHandler, oObject, fnHandler) {
		if (!this[sHandler]) {
			this[sHandler] = ResizeHandler.register(oObject, fnHandler);
		}
	};

	/**
	 * De-registers resize handler.
	 * @param {string} sHandler the handler ID
	 * @private
	 */
	ProgressIndicator.prototype._deRegisterResizeHandler = function (sHandler) {
		if (this[sHandler]) {
			ResizeHandler.deregister(this[sHandler]);
			this[sHandler] = null;
		}
	};

	/**
	 * Handles the resize event of the ProgressIndicator.
	 * @param {jQuery.Event} oEvent
	 * @private
	 */
	ProgressIndicator.prototype._onResize = function (oEvent) {
		this._updateHoverableScenario();
	};

	/**
	 * Handles the start of ProgressIndicator press event and marks the event as handled
	 * by ProgressIndicator to prevent event bubbling when the information popover should be opened.
	 * @param {jQuery.Event} oEvent The tap event object
	 * @private
	 */
	ProgressIndicator.prototype.ontouchstart = function (oEvent) {
		if (this._isHoverable()) {
			oEvent.setMarked();
		}
	};

	/**
	 * Handles the ProgressIndicator press event.
	 * @param {jQuery.Event} oEvent The tap event object
	 */
	ProgressIndicator.prototype.ontap = function (oEvent) {
		var oPopover;

		// By UX in ordeer to open the helper popover, we should have
		// displayValue text and the text should be truncated (hoverable scenario).
		if (this._isHoverable()) {
			oPopover = this._getPopover();
			if (oPopover.isOpen()) {
				oPopover.close();
			} else {
				oPopover.openBy(this);
			}
		}
	};

	/**
	 * Updates the hoverable scenario.
	 * If we have a hoverable scenario we toggle on the "sapMPIHoverable" CSS class and vice-versa.
	 * @private
	 */
	ProgressIndicator.prototype._updateHoverableScenario = function () {
		var oDOMPIDisplayValueText = this.$(this.getPercentValue() > 50 ? "textLeft" : "textRight")[0],
			iOffsetWidth = oDOMPIDisplayValueText && oDOMPIDisplayValueText.offsetWidth,
			iScrollWidth = oDOMPIDisplayValueText && oDOMPIDisplayValueText.scrollWidth;

		// TODO: IE specific code - adding 1px tolerance, because of a know issue with difference b/w offsetWidth and scrollWidth
		if (this._bIEBrowser) {
			iOffsetWidth += 1;
		}

		// By VD if we have displayValue text and the text is truncated, we
		// need to change the cursor of the ProgressIndicator to "pointer" on hover.
		this.toggleStyleClass("sapMPIHoverable", this.getDisplayValue() !== "" && iOffsetWidth < iScrollWidth);
	};

	/**
	 * Whether or not the ProgressIndicator is hoverable.
	 * @returns {boolean} True if ProgressIndicator has "sapMPIHoverable" CSS class.
	 * @private
	 */
	ProgressIndicator.prototype._isHoverable = function () {
		return this.hasStyleClass("sapMPIHoverable");
	};

	/**
	 * Lazy loader for the popover.
	 * @returns {sap.m.Popover}
	 * @private
	 */
	ProgressIndicator.prototype._getPopover = function () {
		var oPopover;

		if (!this.getAggregation("_popover")) {
			this._oPopoverText = new Text({
				text: this.getDisplayValue()
			});
			// Create the Popover
			oPopover = new Popover(this.getId() + "-popover", {
				showHeader: false,
				placement: PlacementType.Bottom,
				content: [this._oPopoverText,
					new Icon({
						src: "sap-icon://decline",
						press: this._onPopoverCloseIconPress.bind(this)
					})
				]
			}).addStyleClass('sapMPIPopover');

			this.setAggregation("_popover", oPopover, true);
		}

		return this.getAggregation("_popover");
	};

	ProgressIndicator.prototype._onPopoverCloseIconPress = function() {
		this._getPopover().close();
	};

	ProgressIndicator.prototype.setDisplayValue = function(sDisplayValue) {
		this.setProperty("displayValue", sDisplayValue);

		if (this._oPopoverText) {
			this._oPopoverText.setText(sDisplayValue);
		}

		return this;
	};

	ProgressIndicator.prototype.setPercentValue = function(fPercentValue) {
		var that = this,
			$progressBar,
			fPercentDiff,
			$progressIndicator = this.$(),
			fAnimationDuration,
			fOriginalValue = fPercentValue;

		fPercentValue = parseFloat(fPercentValue);

		if (!isValidPercentValue(fPercentValue)) {
			if (fPercentValue > 100) {
				fPercentValue = 100;
			} else if (fPercentValue < 0) {
				fPercentValue = 0;
			} else {
				Log.warning(this + ": percentValue (" + fOriginalValue + ") is not a valid number! The provided value will not be set!");
				return this;
			}
			Log.warning(this + ": percentValue (" + fOriginalValue + ") is not correct! Setting the percentValue to " + fPercentValue);
		}

		if (this.getPercentValue() !== fPercentValue) {
			fPercentDiff = this.getPercentValue() - fPercentValue;
			this.setProperty("percentValue", fPercentValue, true);

			if (!$progressIndicator.length) {
				return this;
			}

			["sapMPIValueMax", "sapMPIValueMin", "sapMPIValueNormal", "sapMPIValueGreaterHalf"].forEach(function (sClass){
				$progressIndicator.removeClass(sClass);
			});

			$progressIndicator.addClass(this._getCSSClassByPercentValue(fPercentValue).join(" "));
			$progressIndicator.addClass("sapMPIAnimate")
				.attr("aria-valuenow", fPercentValue)
				.attr("aria-valuetext", this._getAriaValueText({fPercent: fPercentValue}));

			fAnimationDuration = bUseAnimations && this.getDisplayAnimation() ? Math.abs(fPercentDiff) * 20 : 0;
			$progressBar = this.$("bar");
			// Stop currently running animation and start new one.
			// In case of multiple setPercentValue calls all animations will run and it will take some time until the last value is animated,
			// which is the one, actually valuable.
			$progressBar.stop();
			$progressBar.animate({
				"flex-basis" : fPercentValue + "%"
			}, fAnimationDuration, "linear", function() {
				that._setText.apply(that);
				that.$().removeClass("sapMPIAnimate");
			});
		}

		return this;
	};

	ProgressIndicator.prototype._setText = function() {
		this.$().toggleClass("sapMPIValueGreaterHalf", this.getPercentValue() > 50);
		return this;
	};

	/**
	 * Determines the CSS class, which should be applied to the ProgressIndicator
	 * for the given percentValue.
	 * @param {Number} fPercentValue
	 * @return {String} the CSS class
	 * @since 1.44
	 * @private
	 */
	ProgressIndicator.prototype._getCSSClassByPercentValue = function(fPercentValue) {
		if (fPercentValue === 100) {
			return ["sapMPIValueMax", "sapMPIValueGreaterHalf"];
		}

		if (fPercentValue === 0) {
			return ["sapMPIValueMin"];
		}

		if (fPercentValue <= 50) {
			return ["sapMPIValueNormal"];
		}

		return ["sapMPIValueNormal", "sapMPIValueGreaterHalf"];
	};

	ProgressIndicator.prototype._getAriaValueText = function (oParams) {
		oParams.sText = oParams.sText || this.getDisplayValue();
		oParams.fPercent = oParams.fPercent || this.getPercentValue();
		oParams.sStateText = oParams.sStateText || this._getStateText();

		var sAriaValueText = oParams.sText || oParams.fPercent + "%";
		if (oParams.sStateText) {
			sAriaValueText += " " + oParams.sStateText;
		}

		return sAriaValueText;
	};

	ProgressIndicator.prototype._getStateText = function () {
		return this.getEnabled() ? ValueStateSupport.getAdditionalText(this.getState()) : "";
	};

	/**
	 * Returns the sap.m.ProgressIndicator  accessibility information.
	 *
	 * @see sap.ui.core.Control#getAccessibilityInfo
	 * @protected
	 * @returns {object} The sap.m.ProgressIndicator accessibility information
	 */
	ProgressIndicator.prototype.getAccessibilityInfo = function() {
		var oBundle = sap.ui.getCore().getLibraryResourceBundle("sap.m"),
			sDisplayValue = this.getDisplayValue(),
			sDescription = sDisplayValue ? sDisplayValue : oBundle.getText("ACC_CTR_STATE_PROGRESS", [this.getPercentValue()]);

		return {
			role: "progressbar",
			type: oBundle.getText("ACC_CTR_TYPE_PROGRESS"),
			description: sDescription,
			focusable: this.getEnabled(),
			enabled: this.getEnabled()
		};
	};

	function isValidPercentValue(value) {
		return !isNaN(value) && value >= 0 && value <= 100;
	}

	return ProgressIndicator;

});<|endoftext|>


<commit_before>var program = require('commander');
var fs = require('fs');
var path = require('path');
var ncp = require('ncp').ncp;
var rimraf = require('rimraf');

ncp.limit = 16;

replaceHrefInIndex = (href) => {
    fs.readFile(`demo-shell/dist/${href}/index.html`, 'utf8', function (err, data) {
        if (err) {
            return console.log(err);
        }

        let result = data.replace(`base href="/"`, `base href=\"/${href}/\"`);

        fs.writeFile(`demo-shell/dist/${href}/index.html`, result, 'utf8', function (err) {
            if (err) return console.log(err);
        });
    });
};

async function main() {

    program
        .version('0.1.0')
        .option('--base-href  [type]', '')
        .parse(process.argv);

    let outputTemp = path.resolve(__dirname, '../demo-shell/', program.baseHref);
    console.log('output ' + outputTemp);

    let distFolder = path.resolve(__dirname, '../demo-shell/dist');

    fs.rename(distFolder, outputTemp, (err) => {
        if (err) throw err;
        console.log('renamed complete');

        let distFolderNew = path.resolve(__dirname, '../demo-shell/dist', program.baseHref);

        if (!fs.existsSync(distFolderNew)){
            fs.mkdirSync(distFolder);
            fs.mkdirSync(distFolderNew);
        }

        ncp(outputTemp, distFolderNew, (err) => {
            if (err) {
                return console.error(err);
            }

            replaceHrefInIndex(program.baseHref);

            rimraf(outputTemp,  ()=> { console.log('output temp removed'); });

        });

    });

}

main();

<commit_msg>fix pr deploy script<commit_after>var program = require('commander');
var fs = require('fs');
var path = require('path');
var ncp = require('ncp').ncp;
var rimraf = require('rimraf');

ncp.limit = 16;

replaceHrefInIndex = (href) => {
    fs.readFile(`demo-shell/dist/${href}/index.html`, 'utf8', function (err, data) {
        if (err) {
            return console.log(err);
        }

        let result = data.replace(`base href="/"`, `base href=\"/${href}/\"`);

        fs.writeFile(`demo-shell/dist/${href}/index.html`, result, 'utf8', function (err) {
            if (err) return console.log(err);
        });
    });
};

async function main() {

    program
        .version('0.1.0')
        .option('--base-href  [type]', '')
        .parse(process.argv);

    let outputTemp = path.resolve(__dirname, '../../../demo-shell/', program.baseHref);
    console.log('output ' + outputTemp);

    let distFolder = path.resolve(__dirname, '../../../demo-shell/dist');

    fs.rename(distFolder, outputTemp, (err) => {
        if (err) throw err;
        console.log('renamed complete');

        let distFolderNew = path.resolve(__dirname, '../../../demo-shell/dist', program.baseHref);

        if (!fs.existsSync(distFolderNew)){
            fs.mkdirSync(distFolder);
            fs.mkdirSync(distFolderNew);
        }

        ncp(outputTemp, distFolderNew, (err) => {
            if (err) {
                return console.error(err);
            }

            replaceHrefInIndex(program.baseHref);

            rimraf(outputTemp,  ()=> { console.log('output temp removed'); });

        });

    });

}

main();

<|endoftext|>


<commit_before>import levels from '../data/levels';

class LevelManager {

  constructor (game) {
    this.game = game;

    this.definitions = this._createLevelDefinitions();
  }

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

  getLevel (name) {
    return this.definitions[name] || null;
  }

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

  _createLevelDefinitions () {
    const getTilemapDefinitions = (tilemap) =>
      Phaser.TilemapParser.parse(this.game, tilemap);
    const { objects } = getTilemapDefinitions('tilemaps');

    return levels
      .map((level) => [ level, level.name, objects[level.name] ])
      .reduce((definitions, [ level, name, objects ]) => {
        definitions[name] = this._makeLevel(objects);
        return definitions;
      }, Object.create(null));
  }

  _makeLevel (objects) {
    const type  = (t) => ({ type }) => type === t;
    const find = (t, o) => o.find(type(t));
    const filter = (t, o) => o.filter(type(t));

    const shift = (ox, oy) => (x, y) => ({ x: x + ox, y: y + oy });

    const parseMeta =
      ({ properties: { heart, star, next = null, tutorial = null } }) => ({
        layers: { heart, star }, next, tutorial
      });

    const parseObject = (f = shift(0, 0)) => ({ x, y, properties }) => ({
      position: f(x, y), properties
    });

    const parseActor = parseObject(shift(8, 24));

    return {
      meta: parseMeta(find('meta', objects)),
      heart: parseActor(find('heart', objects)),
      star: parseActor(find('star', objects)),
      goal: parseObject()(find('goal', objects)),
      traps: filter('trap', objects).map(parseObject(shift(0, -8))),
      platforms: filter('platform', objects).map(parseObject()),
      buttons: filter('button', objects).map(parseObject(shift(8, 8))),
      gates: filter('gate', objects).map(parseObject(shift(8, 0)))
    };
  }

}

export default LevelManager;
<commit_msg>Enumerate level definitions from the tilemap object layers only.<commit_after>class LevelManager {

  constructor (game) {
    this.game = game;

    this.definitions = this._createLevelDefinitions();
  }

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

  getLevel (name) {
    return this.definitions[name] || null;
  }

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

  _createLevelDefinitions () {
    const { objects } = Phaser.TilemapParser.parse(this.game, 'tilemaps');

    return Object.keys(objects)
      .map((name) => [ name, objects[name] ])
      .reduce((definitions, [ name, objects ]) => {
        definitions[name] = this._makeLevel(objects);
        return definitions;
      }, Object.create(null));
  }

  _makeLevel (objects) {
    const type  = (t) => ({ type }) => type === t;
    const find = (t, o) => o.find(type(t));
    const filter = (t, o) => o.filter(type(t));

    const shift = (ox, oy) => (x, y) => ({ x: x + ox, y: y + oy });

    const parseMeta =
      ({ properties: { heart, star, next = null, tutorial = null } }) => ({
        layers: { heart, star }, next, tutorial
      });

    const parseObject = (f = shift(0, 0)) => ({ x, y, properties }) => ({
      position: f(x, y), properties
    });

    const parseActor = parseObject(shift(8, 24));

    return {
      meta: parseMeta(find('meta', objects)),
      heart: parseActor(find('heart', objects)),
      star: parseActor(find('star', objects)),
      goal: parseObject()(find('goal', objects)),
      traps: filter('trap', objects).map(parseObject(shift(0, -8))),
      platforms: filter('platform', objects).map(parseObject()),
      buttons: filter('button', objects).map(parseObject(shift(8, 8))),
      gates: filter('gate', objects).map(parseObject(shift(8, 0)))
    };
  }

}

export default LevelManager;
<|endoftext|>


<commit_before>/*!
Cloud4all Preferences Management Tools

Copyright 2013 OCAD University
Copyright 2013 CERTH/HIT

Licensed under the New BSD license. You may not use this file except in
compliance with this License.

You may obtain a copy of the License at
https://github.com/GPII/prefsEditors/LICENSE.txt
*/

/*global fluid, jQuery*/
/*jslint white: true, onevar: true, funcinvoke: true, forvar: true, undef: true, newcap: true, nomen: true, regexp: true, plusplus: true, bitwise: true, maxerr: 50, indent: 4 */

(function ($, fluid) {

    fluid.defaults("gpii.adjuster.cursorSizePCP", {
        gradeNames: ["fluid.prefs.panel", "autoInit"],
        preferenceMap: {
            "gpii.primarySchema.cursorSize": {
                "model.value": "default",
                "controlValues.cursorSize.min": "minimum",
                "controlValues.cursorSize.max": "maximum",
                "controlValues.cursorSize.divisibleBy": "divisibleBy"
            }
        },
        selectors: {
            cursorSizeSlider: ".gpiic-increaseSize-cursor-size-slider",
            cursorSizeLabel: ".gpiic-increaseSize-cursor-size-label"
        },
        selectorsToIgnore: ["cursorSizeSlider"],
        components: {
            cursorSizeSlider: {
                type: "fluid.textfieldSlider",
                container: "{that}.dom.cursorSizeSlider",
                createOnEvent: "afterRender",
                options: {
                    rules: {
                        "value": "value"
                    },
                    model: {
                        value: "{cursorSizePCP}.model.value"
                    },
                    sourceApplier: "{cursorSizePCP}.applier",
                    range: "{cursorSizePCP}.options.controlValues.cursorSize",
                    sliderOptions: "{cursorSizePCP}.options.sliderOptions"
                }
            }
        },
        protoTree: {
            cursorSizeLabel: {messagekey: "cursorSizeLabel"}
        },
        sliderOptions: {
            orientation: "horizontal",
            step: 0.2,
            range: "min"
        }
    });
})(jQuery, fluid);
<commit_msg>GPII-600: Added aria label for the cursor size slider.<commit_after>/*!
Cloud4all Preferences Management Tools

Copyright 2013 OCAD University
Copyright 2013 CERTH/HIT

Licensed under the New BSD license. You may not use this file except in
compliance with this License.

You may obtain a copy of the License at
https://github.com/GPII/prefsEditors/LICENSE.txt
*/

/*global fluid, jQuery*/
/*jslint white: true, onevar: true, funcinvoke: true, forvar: true, undef: true, newcap: true, nomen: true, regexp: true, plusplus: true, bitwise: true, maxerr: 50, indent: 4 */

(function ($, fluid) {

    fluid.defaults("gpii.adjuster.cursorSizePCP", {
        gradeNames: ["fluid.prefs.panel", "autoInit"],
        preferenceMap: {
            "gpii.primarySchema.cursorSize": {
                "model.value": "default",
                "controlValues.cursorSize.min": "minimum",
                "controlValues.cursorSize.max": "maximum",
                "controlValues.cursorSize.divisibleBy": "divisibleBy"
            }
        },
        selectors: {
            cursorSizeSlider: ".gpiic-increaseSize-cursor-size-slider",
            cursorSizeLabel: ".gpiic-increaseSize-cursor-size-label"
        },
        selectorsToIgnore: ["cursorSizeSlider"],
        components: {
            cursorSizeSlider: {
                type: "fluid.textfieldSlider",
                container: "{that}.dom.cursorSizeSlider",
                createOnEvent: "afterRender",
                options: {
                    rules: {
                        "value": "value"
                    },
                    model: {
                        value: "{cursorSizePCP}.model.value"
                    },
                    sourceApplier: "{cursorSizePCP}.applier",
                    range: "{cursorSizePCP}.options.controlValues.cursorSize",
                    sliderOptions: "{cursorSizePCP}.options.sliderOptions",
                    listeners: {
                        "afterRender.setAria": {
                            "this": "{that}.slider.dom.thumb",
                            method: "attr",
                            args: ["aria-labelledby", {expander: {funcName: "gpii.utility.getLabelId", args: "{cursorSizePCP}.dom.cursorSizeLabel"}}]
                        }
                    }
                }
            }
        },
        protoTree: {
            cursorSizeLabel: {messagekey: "cursorSizeLabel"}
        },
        sliderOptions: {
            orientation: "horizontal",
            step: 0.2,
            range: "min"
        }
    });
})(jQuery, fluid);
<|endoftext|>


<commit_before>import React, { Component } from "react";

import Dropzone from "react-dropzone";

export default class ThesisUploadWidget extends Component {
    constructor(props) {
        super(props);
        this.state = {
            fileName: "",
        }
    }

    componentWillReceiveProps(newProps) {
        console.log("newProps: " + JSON.stringify(newProps));
        if (newProps.currentFile) {
            console.log("IFFF");
            this.setState({ fileName: newProps.currentFile.name})
        }
        console.log("Tiedoston nimi " + this.state.fileName);
    }

    getLabel = () => {
        switch (this.props.type) {
            case "reviewFile":
                return "Upload Thesis review as PDF (max. 1 MB)";
            case "abstractFile":
                return "Upload Thesis with abstract on 2nd page (max. 40 MB)";
            default:
                return "Error ThesisUploadWidget getLabel";
        }
    }

    onDrop = (files) => {
        console.log("FILU " + JSON.stringify(files[0]));
        console.log("filun nimi " + files[0].name);
        this.componentWillReceiveProps({currentFile: files[0]});
        this.props.sendChange(this.props.type, files[0]);
    }

    render() {
        return (

                {this.getLabel()}
                    <Dropzone className="field upload-box" onDrop={this.onDrop} multiple={false}>

Click to navigate to the file or drop them from your file system.

Current file: {this.state.fileName}

                    </Dropzone>

        );
    }
}<commit_msg>started to work on the structure<commit_after>import React, { Component } from "react";

import Dropzone from "react-dropzone";

export default class ThesisUploadWidget extends Component {
    constructor(props) {
        super(props);
    }

    componentWillReceiveProps(newProps) {
        console.log("newProps: " + JSON.stringify(newProps));
        if (newProps.currentFile) {
            console.log("IFFF");
        }
        console.log("Tiedoston nimi " + this.state.fileName);
    }

    getLabel = () => {
        switch (this.props.type) {
            case "reviewFile":
                return "Upload Thesis review as PDF (max. 1 MB)";
            case "abstractFile":
                return "Upload Thesis with abstract on 2nd page (max. 40 MB)";
            case "attachment":
                return "Upload attachments to agreement"
            default:
                return "Error ThesisUploadWidget getLabel";
        }
    }

    onDrop = (files) => {
        console.log("FILU " + JSON.stringify(files[0]));
        console.log("filun nimi " + files[0].name);
        this.props.sendChange(this.props.type, files[0]);
    }

    getFileList = () => {

    return
asdsad
;
    }

    render() {
        return (

                {this.getLabel()}
                    <Dropzone className="field upload-box" onDrop={this.onDrop} multiple={false}>

Click to navigate to the file or drop them from your file system.

                    </Dropzone>

            {this.getFileList()}

        );
    }
}<|endoftext|>


<commit_before>require('./styles/app.scss');
require('bootstrap');

window.cookieconsent_options = {
    container: "#cookieConsentHolder",
    message: "Wir verwenden Cookies, um die Anzahl der Besucher zu ermitteln. Es werden natürlich keine Daten an Dritte weitergegeben.",
    dismiss: "OK",
    learnMore: "",
    link: null,
    theme: "dark-bottom"
};

require('cookieconsent');

const winterTheme = require('../config').settings.winterTheme;
if (winterTheme) {
    require("./snowFall")
}

var io = require('socket.io-client');
var Swipe = require('swipejs');

var dayStr = location.href.substring(location.href.lastIndexOf("/") + 1)
var day = dayStr.length ? +dayStr : null;
var overallVisitors = $('#overallVisitors');
var dailyVisitors = $('#dailyVisitors');

var socket = io();
socket.on('newVisitor', function (data) {
    console.log(data);
    dailyVisitors.text(data.dailyVisitors);
    overallVisitors.text(data.overallVisitors);
});

initSlider();
initNameShuffling();

var mailPre = "contact", mailDomain = "felf.io";
$("#mail").text(mailPre + "@" + mailDomain);

function initSlider() {
    var swipe = new Swipe(document.getElementById('slider'), {
        startSlide: sanitizeDay(day),
        speed: 400,
        continuous: false,
        disableScroll: false,
        transitionEnd: toggleSlideButtons //"callback" gives better results, but lags on both desktop and mobile devices
    });

    var leftSlideButtons = $('.nav-icon.left');
    var rightSlideButtons = $('.nav-icon.right');
    toggleSlideButtons(sanitizeDay(day));

    /**
     * Slide buttons should look disabled when no button-press is possible
     */
    function toggleSlideButtons(day) {
        if (day == 0) {
            leftSlideButtons.addClass('disabled');
        } else {
            leftSlideButtons.removeClass('disabled');
        }
        if (day == 6) {
            rightSlideButtons.addClass('disabled');
        } else {
            rightSlideButtons.removeClass('disabled');
        }
    }

    leftSlideButtons.click(swipe.prev);
    rightSlideButtons.click(swipe.next);

    window.onkeyup = function (e) {
        var key = e.keyCode ? e.keyCode : e.which;

        if (key == 37) {
            swipe.prev();
        } else if (key == 39) {
            swipe.next();
        }
    };

    function sanitizeDay(incDay) {
        if (incDay == null || isNaN(incDay)) {
            return ((new Date()).getDay() + 6) % 7;
        } else {
            if (incDay < 0) {
                incDay = 7 + (incDay % 7);
            }
            return incDay % 7;
        }
    }
}

function initNameShuffling() {
    var names = [
        'Kristina',
        'Markus',
        'Fabian'];

    var additionalNames = [
        'Benjamin',
        'Philipp'];

    swapNames();
    if (window.location.pathname.indexOf("/about") === 0) {
        setInterval(swapNames, 5000);
    }

    function swapNames() {
        shuffle(names);
        $("#name0").html(names[0]);
        $("#name1").html(names[1]);
        $("#name2").html(names[2]);

        shuffle(additionalNames);
        $("#additionalName0").html(additionalNames[0]);
        $("#additionalName1").html(additionalNames[1]);
    }

    /**
     * Shuffles array in place.
     * @param {Array} a items The array containing the items.
     */
    function shuffle(a) {
        var j, x, i;
        for (i = a.length; i; i--) {
            j = Math.floor(Math.random() * i);
            x = a[i - 1];
            a[i - 1] = a[j];
            a[j] = x;
        }
    }
}
<commit_msg>initialize slider with correct width<commit_after>require('./styles/app.scss');
require('bootstrap');

window.cookieconsent_options = {
    container: "#cookieConsentHolder",
    message: "Wir verwenden Cookies, um die Anzahl der Besucher zu ermitteln. Es werden natürlich keine Daten an Dritte weitergegeben.",
    dismiss: "OK",
    learnMore: "",
    link: null,
    theme: "dark-bottom"
};

require('cookieconsent');

const winterTheme = require('../config').settings.winterTheme;
if (winterTheme) {
    require("./snowFall")
}

var io = require('socket.io-client');
var Swipe = require('swipejs');

var dayStr = location.href.substring(location.href.lastIndexOf("/") + 1)
var day = dayStr.length ? +dayStr : null;
var overallVisitors = $('#overallVisitors');
var dailyVisitors = $('#dailyVisitors');

var socket = io();
socket.on('newVisitor', function (data) {
    console.log(data);
    dailyVisitors.text(data.dailyVisitors);
    overallVisitors.text(data.overallVisitors);
});

$(document).ready(() => {
    requestAnimationFrame(initSlider);
    initNameShuffling();
});

var mailPre = "contact", mailDomain = "felf.io";
$("#mail").text(mailPre + "@" + mailDomain);

function initSlider() {
    var swipe = new Swipe(document.getElementById('slider'), {
        startSlide: sanitizeDay(day),
        speed: 400,
        continuous: false,
        disableScroll: false,
        transitionEnd: toggleSlideButtons //"callback" gives better results, but lags on both desktop and mobile devices
    });

    var leftSlideButtons = $('.nav-icon.left');
    var rightSlideButtons = $('.nav-icon.right');
    toggleSlideButtons(sanitizeDay(day));

    /**
     * Slide buttons should look disabled when no button-press is possible
     */
    function toggleSlideButtons(day) {
        if (day == 0) {
            leftSlideButtons.addClass('disabled');
        } else {
            leftSlideButtons.removeClass('disabled');
        }
        if (day == 6) {
            rightSlideButtons.addClass('disabled');
        } else {
            rightSlideButtons.removeClass('disabled');
        }
    }

    leftSlideButtons.click(swipe.prev);
    rightSlideButtons.click(swipe.next);

    window.onkeyup = function (e) {
        var key = e.keyCode ? e.keyCode : e.which;

        if (key == 37) {
            swipe.prev();
        } else if (key == 39) {
            swipe.next();
        }
    };

    function sanitizeDay(incDay) {
        if (incDay == null || isNaN(incDay)) {
            return ((new Date()).getDay() + 6) % 7;
        } else {
            if (incDay < 0) {
                incDay = 7 + (incDay % 7);
            }
            return incDay % 7;
        }
    }
}

function initNameShuffling() {
    var names = [
        'Kristina',
        'Markus',
        'Fabian'];

    var additionalNames = [
        'Benjamin',
        'Philipp'];

    swapNames();
    if (window.location.pathname.indexOf("/about") === 0) {
        setInterval(swapNames, 5000);
    }

    function swapNames() {
        shuffle(names);
        $("#name0").html(names[0]);
        $("#name1").html(names[1]);
        $("#name2").html(names[2]);

        shuffle(additionalNames);
        $("#additionalName0").html(additionalNames[0]);
        $("#additionalName1").html(additionalNames[1]);
    }

    /**
     * Shuffles array in place.
     * @param {Array} a items The array containing the items.
     */
    function shuffle(a) {
        var j, x, i;
        for (i = a.length; i; i--) {
            j = Math.floor(Math.random() * i);
            x = a[i - 1];
            a[i - 1] = a[j];
            a[j] = x;
        }
    }
}
<|endoftext|>


<commit_before>/*jslint browser: true, indent: 2, plusplus: true, vars: true */

(function (window) {
  "use strict";

  var ahoy = window.ahoy || window.Ahoy || {};
  var $ = window.jQuery || window.Zepto || window.$;
  var visitToken, visitorToken;
  var visitTtl = 4 * 60; // 4 hours
  var visitorTtl = 2 * 365 * 24 * 60; // 2 years
  var isReady = false;
  var queue = [];
  var canStringify = typeof(JSON) !== "undefined" && typeof(JSON.stringify) !== "undefined";
  var eventQueue = [];

  // cookies

  // http://www.quirksmode.org/js/cookies.html
  function setCookie(name, value, ttl) {
    var expires = "";
    var cookieDomain = "";
    if (ttl) {
      var date = new Date();
      date.setTime(date.getTime() + (ttl * 60 * 1000));
      expires = "; expires=" + date.toGMTString();
    }
    if (ahoy.domain) {
      cookieDomain = "; domain=" + ahoy.domain;
    }
    document.cookie = name + "=" + value + expires + cookieDomain + "; path=/";
  }

  function getCookie(name) {
    var i, c;
    var nameEQ = name + "=";
    var ca = document.cookie.split(';');
    for (i = 0; i < ca.length; i++) {
      c = ca[i];
      while (c.charAt(0) === ' ') {
        c = c.substring(1, c.length);
      }
      if (c.indexOf(nameEQ) === 0) {
        return c.substring(nameEQ.length, c.length);
      }
    }
    return null;
  }

  function destroyCookie(name) {
    setCookie(name, "", -1);
  }

  function log(message) {
    if (getCookie("ahoy_debug")) {
      window.console.log(message);
    }
  }

  function setReady() {
    var callback;
    while (callback = queue.shift()) {
      callback();
    }
    isReady = true;
  }

  function ready(callback) {
    if (isReady) {
      callback();
    } else {
      queue.push(callback);
    }
  }

  // https://github.com/klughammer/node-randomstring
  function generateId() {
    var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghiklmnopqrstuvwxyz';
    var length = 32;
    var string = '';

    for (var i = 0; i < length; i++) {
      var randomNumber = Math.floor(Math.random() * chars.length);
      string += chars.substring(randomNumber, randomNumber + 1);
    }

    return string;
  }

  function saveEventQueue() {
    // TODO add stringify method for IE 7 and under
    if (canStringify) {
      setCookie("ahoy_events", JSON.stringify(eventQueue), 1);
    }
  }

  function trackEvent(event) {
    ready( function () {
      // ensure JSON is defined
      if (canStringify) {
        $.ajax({
          type: "POST",
          url: "/ahoy/events",
          data: JSON.stringify(event),
          contentType: "application/json; charset=utf-8",
          dataType: "json",
          success: function() {
            // remove from queue
            for (var i = 0; i < eventQueue.length; i++) {
              if (eventQueue[i].id == event.id) {
                eventQueue.splice(i, 1);
                break;
              }
            }
            saveEventQueue();
          }
        });
      }
    });
  }

  function eventProperties(e) {
    var $target = $(e.currentTarget);
    return {
      tag: $target.get(0).tagName.toLowerCase(),
      id: $target.attr("id"),
      class: $target.attr("class")
    };
  }

  // main

  visitToken = getCookie("ahoy_visit");
  visitorToken = getCookie("ahoy_visitor");

  if (visitToken && visitorToken && visitToken != "test") {
    // TODO keep visit alive?
    log("Active visit");
    setReady();
  } else {
    setCookie("ahoy_visit", "test", 1);

    // make sure cookies are enabled
    if (getCookie("ahoy_visit")) {
      log("Visit started");

      visitorToken = visitorToken || generateId();
      visitToken = generateId();

      setCookie("ahoy_visit", visitToken, visitTtl);
      setCookie("ahoy_visitor", visitorToken, visitorTtl);

      var data = {
        visit_token: visitToken,
        visitor_token: visitorToken,
        platform: ahoy.platform || "Web",
        landing_page: window.location.href,
        screen_width: window.screen.width,
        screen_height: window.screen.height

      };

      // referrer
      if (document.referrer.length > 0) {
        data.referrer = document.referrer;
      }

      log(data);

      $.post("/ahoy/visits", data, setReady, "json");
    } else {
      log("Cookies disabled");
      setReady();
    }
  }

  ahoy.reset = function () {
    destroyCookie("ahoy_visit");
    destroyCookie("ahoy_visitor");
    return true;
  };

  ahoy.debug = function (enabled) {
    if (enabled === false) {
      destroyCookie("ahoy_debug");
    } else {
      setCookie("ahoy_debug", "t", 365 * 24 * 60); // 1 year
    }
    return true;
  };

  ahoy.track = function (name, properties) {
    // generate unique id
    var event = {
      id: generateId(),
      name: name,
      properties: properties,
      time: (new Date()).getTime() / 1000.0
    };
    log(event);

    eventQueue.push(event);
    saveEventQueue();

    // wait in case navigating to reduce duplicate events
    setTimeout( function () {
      trackEvent(event);
    }, 1000);
  };

  ahoy.trackView = function () {
    var properties = {
      url: window.location.href,
      title: document.title
    };
    ahoy.track("$view", properties);
  };

  ahoy.trackClicks = function () {
    $(document).on("click", "a, button, input[type=submit]", function (e) {
      var $target = $(e.currentTarget);
      var properties = eventProperties(e);
      properties.text = properties.tag == "input" ? $target.val() : $.trim($target.text());
      properties.href = $target.attr("href");
      ahoy.track("$click", properties);
    });
  };

  ahoy.trackSubmits = function () {
    $(document).on("submit", "form", function (e) {
      var properties = eventProperties(e);
      ahoy.track("$submit", properties);
    });
  };

  ahoy.trackChanges = function () {
    $(document).on("change", "input, textarea, select", function (e) {
      var properties = eventProperties(e);
      ahoy.track("$change", properties);
    });
  };

  ahoy.trackAll = function() {
    ahoy.trackView();
    ahoy.trackClicks();
    ahoy.trackSubmits();
    ahoy.trackChanges();
  };

  // push events from queue
  try {
    eventQueue = JSON.parse(getCookie("ahoy_events") || "[]");
  } catch (e) {
    // do nothing
  }

  for (var i = 0; i < eventQueue.length; i++) {
    trackEvent(eventQueue[i]);
  }

  window.ahoy = ahoy;
}(window));
<commit_msg>Better token logic<commit_after>/*jslint browser: true, indent: 2, plusplus: true, vars: true */

(function (window) {
  "use strict";

  var ahoy = window.ahoy || window.Ahoy || {};
  var $ = window.jQuery || window.Zepto || window.$;
  var visitToken, visitorToken;
  var visitTtl = 4 * 60; // 4 hours
  var visitorTtl = 2 * 365 * 24 * 60; // 2 years
  var isReady = false;
  var queue = [];
  var canStringify = typeof(JSON) !== "undefined" && typeof(JSON.stringify) !== "undefined";
  var eventQueue = [];

  // cookies

  // http://www.quirksmode.org/js/cookies.html
  function setCookie(name, value, ttl) {
    var expires = "";
    var cookieDomain = "";
    if (ttl) {
      var date = new Date();
      date.setTime(date.getTime() + (ttl * 60 * 1000));
      expires = "; expires=" + date.toGMTString();
    }
    if (ahoy.domain) {
      cookieDomain = "; domain=" + ahoy.domain;
    }
    document.cookie = name + "=" + value + expires + cookieDomain + "; path=/";
  }

  function getCookie(name) {
    var i, c;
    var nameEQ = name + "=";
    var ca = document.cookie.split(';');
    for (i = 0; i < ca.length; i++) {
      c = ca[i];
      while (c.charAt(0) === ' ') {
        c = c.substring(1, c.length);
      }
      if (c.indexOf(nameEQ) === 0) {
        return c.substring(nameEQ.length, c.length);
      }
    }
    return null;
  }

  function destroyCookie(name) {
    setCookie(name, "", -1);
  }

  function log(message) {
    if (getCookie("ahoy_debug")) {
      window.console.log(message);
    }
  }

  function setReady() {
    var callback;
    while (callback = queue.shift()) {
      callback();
    }
    isReady = true;
  }

  function ready(callback) {
    if (isReady) {
      callback();
    } else {
      queue.push(callback);
    }
  }

  // https://github.com/klughammer/node-randomstring
  function generateId() {
    var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghiklmnopqrstuvwxyz';
    var length = 32;
    var string = '';

    for (var i = 0; i < length; i++) {
      var randomNumber = Math.floor(Math.random() * chars.length);
      string += chars.substring(randomNumber, randomNumber + 1);
    }

    return string;
  }

  function saveEventQueue() {
    // TODO add stringify method for IE 7 and under
    if (canStringify) {
      setCookie("ahoy_events", JSON.stringify(eventQueue), 1);
    }
  }

  function trackEvent(event) {
    ready( function () {
      // ensure JSON is defined
      if (canStringify) {
        $.ajax({
          type: "POST",
          url: "/ahoy/events",
          data: JSON.stringify(event),
          contentType: "application/json; charset=utf-8",
          dataType: "json",
          success: function() {
            // remove from queue
            for (var i = 0; i < eventQueue.length; i++) {
              if (eventQueue[i].id == event.id) {
                eventQueue.splice(i, 1);
                break;
              }
            }
            saveEventQueue();
          }
        });
      }
    });
  }

  function eventProperties(e) {
    var $target = $(e.currentTarget);
    return {
      tag: $target.get(0).tagName.toLowerCase(),
      id: $target.attr("id"),
      class: $target.attr("class")
    };
  }

  // main

  visitToken = getCookie("ahoy_visit");
  visitorToken = getCookie("ahoy_visitor");

  if (visitToken && visitorToken) {
    // TODO keep visit alive?
    log("Active visit");
    setReady();
  } else {
    visitToken = generateId();
    setCookie("ahoy_visit", visitToken, visitTtl);

    // make sure cookies are enabled
    if (getCookie("ahoy_visit")) {
      log("Visit started");

      if (!visitorToken) {
        visitorToken = generateId();
        setCookie("ahoy_visitor", visitorToken, visitorTtl);
      }

      var data = {
        visit_token: visitToken,
        visitor_token: visitorToken,
        platform: ahoy.platform || "Web",
        landing_page: window.location.href,
        screen_width: window.screen.width,
        screen_height: window.screen.height
      };

      // referrer
      if (document.referrer.length > 0) {
        data.referrer = document.referrer;
      }

      log(data);

      $.post("/ahoy/visits", data, setReady, "json");
    } else {
      log("Cookies disabled");
      setReady();
    }
  }

  ahoy.reset = function () {
    destroyCookie("ahoy_visit");
    destroyCookie("ahoy_visitor");
    return true;
  };

  ahoy.debug = function (enabled) {
    if (enabled === false) {
      destroyCookie("ahoy_debug");
    } else {
      setCookie("ahoy_debug", "t", 365 * 24 * 60); // 1 year
    }
    return true;
  };

  ahoy.track = function (name, properties) {
    // generate unique id
    var event = {
      id: generateId(),
      name: name,
      properties: properties,
      time: (new Date()).getTime() / 1000.0
    };
    log(event);

    eventQueue.push(event);
    saveEventQueue();

    // wait in case navigating to reduce duplicate events
    setTimeout( function () {
      trackEvent(event);
    }, 1000);
  };

  ahoy.trackView = function () {
    var properties = {
      url: window.location.href,
      title: document.title
    };
    ahoy.track("$view", properties);
  };

  ahoy.trackClicks = function () {
    $(document).on("click", "a, button, input[type=submit]", function (e) {
      var $target = $(e.currentTarget);
      var properties = eventProperties(e);
      properties.text = properties.tag == "input" ? $target.val() : $.trim($target.text());
      properties.href = $target.attr("href");
      ahoy.track("$click", properties);
    });
  };

  ahoy.trackSubmits = function () {
    $(document).on("submit", "form", function (e) {
      var properties = eventProperties(e);
      ahoy.track("$submit", properties);
    });
  };

  ahoy.trackChanges = function () {
    $(document).on("change", "input, textarea, select", function (e) {
      var properties = eventProperties(e);
      ahoy.track("$change", properties);
    });
  };

  ahoy.trackAll = function() {
    ahoy.trackView();
    ahoy.trackClicks();
    ahoy.trackSubmits();
    ahoy.trackChanges();
  };

  // push events from queue
  try {
    eventQueue = JSON.parse(getCookie("ahoy_events") || "[]");
  } catch (e) {
    // do nothing
  }

  for (var i = 0; i < eventQueue.length; i++) {
    trackEvent(eventQueue[i]);
  }

  window.ahoy = ahoy;
}(window));
<|endoftext|>