<commit_before>import scrollbarWidth from 'scrollbarwidth';
import debounce from 'lodash.debounce';
import ResizeObserver from 'resize-observer-polyfill';

import './simplebar.css';

export default class SimpleBar {
    constructor(element, options) {
        this.el = element;
        this.track;
        this.scrollbar;
        this.flashTimeout;
        this.contentEl;
        this.scrollContentEl;
        this.dragOffset         = { x: 0, y: 0 };
        this.isVisible          = { x: true, y: true };
        this.scrollOffsetAttr   = { x: 'scrollLeft', y: 'scrollTop' };
        this.sizeAttr           = { x: 'offsetWidth', y: 'offsetHeight' };
        this.scrollSizeAttr     = { x: 'scrollWidth', y: 'scrollHeight' };
        this.offsetAttr         = { x: 'left', y: 'top' };
        this.globalObserver;
        this.mutationObserver;
        this.resizeObserver;
        this.currentAxis;
        this.options = Object.assign({}, SimpleBar.defaultOptions, options);
        this.classNames = this.options.classNames;
        this.scrollbarWidth = scrollbarWidth();
        this.offsetSize = 20;
        // If scrollbar is a floating scrollbar, disable the plugin
        this.enabled = this.scrollbarWidth !== 0 || this.options.forceEnabled;
        this.flashScrollbar = this.flashScrollbar.bind(this);
        this.onDragY = this.onDragY.bind(this);
        this.onDragX = this.onDragX.bind(this);
        this.onScrollY = this.onScrollY.bind(this);
        this.onScrollX = this.onScrollX.bind(this);
        this.drag = this.drag.bind(this);
        this.onEndDrag = this.onEndDrag.bind(this);
        this.onMouseEnter = this.onMouseEnter.bind(this);

        this.recalculate = debounce(this.recalculate, 100, { leading: true, trailing: false });

        this.init();
    }

    static get defaultOptions() {
        return {
            wrapContent: true,
            autoHide: true,
            forceEnabled: false,
            classNames: {
                content: 'simplebar-content',
                scrollContent: 'simplebar-scroll-content',
                scrollbar: 'simplebar-scrollbar',
                track: 'simplebar-track'
            },
            scrollbarMinSize: 10
        }
    }

    static get htmlAttributes() {
        return {
            autoHide: 'data-simplebar-autohide',
            forceEnabled: 'data-simplebar-force-enabled',
            scrollbarMinSize: 'data-simplebar-scrollbar-min-size'
        }
    }

    static initHtmlApi() {
        this.initDOMLoadedElements = this.initDOMLoadedElements.bind(this);

        // MutationObserver is IE11+
        if (typeof MutationObserver !== 'undefined') {
            // Mutation observer to observe dynamically added elements
            this.globalObserver = new MutationObserver(mutations => {
                mutations.forEach(mutation => {
                    Array.from(mutation.addedNodes).forEach(addedNode => {
                        if (addedNode.nodeType === 1) {
                            if (addedNode.SimpleBar) return;

                            if (addedNode.hasAttribute('data-simplebar')) {
                                new SimpleBar(addedNode, SimpleBar.getElOptions(addedNode));
                            } else {
                                Array.from(addedNode.querySelectorAll('[data-simplebar]')).forEach(el => {
                                    new SimpleBar(el, SimpleBar.getElOptions(el));
                                });
                            }
                        }
                    });

                    Array.from(mutation.removedNodes).forEach(removedNode => {
                        if (removedNode.nodeType === 1) {
                            if (removedNode.hasAttribute('data-simplebar')) {
                                removedNode.SimpleBar && removedNode.SimpleBar.unMount();
                            } else {
                                Array.from(removedNode.querySelectorAll('[data-simplebar]')).forEach(el => {
                                    el.SimpleBar && el.SimpleBar.unMount();
                                });
                            }
                        }
                    });
                });
            });

            this.globalObserver.observe(document, { childList: true, subtree: true });
        }

        // Taken from jQuery `ready` function
        // Instantiate elements already present on the page
        if (document.readyState === 'complete' ||
                (document.readyState !== 'loading' && !document.documentElement.doScroll)) {
            // Handle it asynchronously to allow scripts the opportunity to delay init
            window.setTimeout(this.initDOMLoadedElements.bind(this));
        } else {
            document.addEventListener('DOMContentLoaded', this.initDOMLoadedElements);
            window.addEventListener('load', this.initDOMLoadedElements);
        }
    }

    // Helper function to retrieve options from element attributes
    static getElOptions(el) {
        const options = Object.keys(SimpleBar.htmlAttributes).reduce((acc, obj) => {
            const attribute = SimpleBar.htmlAttributes[obj];
            if (el.hasAttribute(attribute)) {
                acc[obj] = JSON.parse(el.getAttribute(attribute) || true);
            }
            return acc;
        }, {});

        return options;
    }

    static removeObserver() {
        this.globalObserver.disconnect();
    }

    static initDOMLoadedElements() {
        document.removeEventListener('DOMContentLoaded', this.initDOMLoadedElements);
        window.removeEventListener('load', this.initDOMLoadedElements);

        Array.from(document.querySelectorAll('[data-simplebar]')).forEach(el => {
            if (!el.SimpleBar)
                new SimpleBar(el, SimpleBar.getElOptions(el));
        });
    }

    init() {
        // Save a reference to the instance, so we know this DOM node has already been instancied
        this.el.SimpleBar = this;

        if (!this.enabled) {
            return;
        }

        this.initDOM();

        this.scrollContentEl = this.el.querySelector(`.${this.classNames.scrollContent}`);
        this.contentEl = this.el.querySelector(`.${this.classNames.content}`);

        this.trackX = this.el.querySelector(`.${this.classNames.track}.horizontal`);
        this.trackY = this.el.querySelector(`.${this.classNames.track}.vertical`);

        this.scrollbarX = this.trackX.querySelector(`.${this.classNames.scrollbar}`);
        this.scrollbarY = this.trackY.querySelector(`.${this.classNames.scrollbar}`);

        this.scrollContentEl.style.marginRight = `-${this.offsetSize}px`;
        this.scrollContentEl.style.paddingRight = `${this.offsetSize}px`;
        this.scrollContentEl.style.marginBottom = `-${this.offsetSize}px`;
        this.contentEl.style.paddingBottom = `${this.offsetSize}px`;

        if (this.enabled && this.scrollbarWidth !== 0) {
            this.scrollContentEl.style.marginBottom = `-${this.scrollbarWidth*2}px`;
            this.contentEl.style.marginRight = `-${this.scrollbarWidth}px`;
        }

        // Calculate content size
        this.recalculate();

        this.initListeners();
    }

    initDOM() {
        // Prepare DOM
        if (this.options.wrapContent) {
            this.scrollContentEl = document.createElement('div');
            this.contentEl = document.createElement('div');

            this.scrollContentEl.classList.add(this.classNames.scrollContent);
            this.contentEl.classList.add(this.classNames.content);

            while (this.el.firstChild)
                this.contentEl.appendChild(this.el.firstChild)

            this.scrollContentEl.appendChild(this.contentEl);
            this.el.appendChild(this.scrollContentEl);
        }

        const track = document.createElement('div');
        const scrollbar = document.createElement('div');

        track.classList.add(this.classNames.track);
        scrollbar.classList.add(this.classNames.scrollbar);

        track.appendChild(scrollbar);

        this.trackX = track.cloneNode(true);
        this.trackX.classList.add('horizontal');

        this.trackY = track.cloneNode(true);
        this.trackY.classList.add('vertical');

        this.el.insertBefore(this.trackX, this.el.firstChild);
        this.el.insertBefore(this.trackY, this.el.firstChild);
        this.el.setAttribute('data-simplebar', 'init');
    }

    initListeners() {
        // Event listeners
        if (this.options.autoHide) {
            this.el.addEventListener('mouseenter', this.onMouseEnter);
        }

        this.scrollbarY.addEventListener('mousedown', this.onDragY);
        this.scrollbarX.addEventListener('mousedown', this.onDragX);

        this.scrollContentEl.addEventListener('scroll', this.onScrollY);
        this.contentEl.addEventListener('scroll', this.onScrollX);

        // MutationObserver is IE11+
        if (typeof MutationObserver !== 'undefined') {
            // create an observer instance
            this.mutationObserver = new MutationObserver(mutations => {
                mutations.forEach(mutation => {
                    if (this.isChildNode(mutation.target) || mutation.addedNodes.length) {
                        this.recalculate();
                    }
                });
            });

            // pass in the target node, as well as the observer options
            this.mutationObserver.observe(this.el, { attributes: true, childList: true, characterData: true, subtree: true });
        }

        this.resizeObserver = new ResizeObserver(this.recalculate.bind(this));
        this.resizeObserver.observe(this.el);
    }

    removeListeners() {
        if (!this.enabled) {
            return;
        }

        // Event listeners
        if (this.options.autoHide) {
            this.el.removeEventListener('mouseenter', this.onMouseEnter);
        }

        this.scrollbarX.removeEventListener('mousedown', this.onDragX);
        this.scrollbarY.removeEventListener('mousedown', this.onDragY);

        this.scrollContentEl.removeEventListener('scroll', this.onScrollY);
        this.contentEl.removeEventListener('scroll', this.onScrollX);

        this.mutationObserver.disconnect();
        this.resizeObserver.disconnect();
    }

    onDragX(e) {
        this.onDrag(e, 'x');
    }

    onDragY(e) {
        this.onDrag(e, 'y');
    }

    /**
     * on scrollbar handle drag
     */
    onDrag(e, axis = 'y') {
        // Preventing the event's default action stops text being
        // selectable during the drag.
        e.preventDefault();

        const scrollbar = axis === 'y' ? this.scrollbarY : this.scrollbarX;

        // Measure how far the user's mouse is from the top of the scrollbar drag handle.
        const eventOffset = axis === 'y' ? e.pageY : e.pageX;

        this.dragOffset[axis] = eventOffset - scrollbar.getBoundingClientRect()[this.offsetAttr[axis]];
        this.currentAxis = axis;

        document.addEventListener('mousemove', this.drag);
        document.addEventListener('mouseup', this.onEndDrag);
    }

    /**
     * Drag scrollbar handle
     */
    drag(e) {
        let eventOffset, track, scrollEl;

        e.preventDefault();

        if (this.currentAxis === 'y') {
            eventOffset = e.pageY;
            track = this.trackY;
            scrollEl = this.scrollContentEl;
        } else {
            eventOffset = e.pageX;
            track = this.trackX;
            scrollEl = this.contentEl;
        }

        // Calculate how far the user's mouse is from the top/left of the scrollbar (minus the dragOffset).
        let dragPos = eventOffset - track.getBoundingClientRect()[this.offsetAttr[this.currentAxis]] - this.dragOffset[this.currentAxis];

        // Convert the mouse position into a percentage of the scrollbar height/width.
        let dragPerc = dragPos / track[this.sizeAttr[this.currentAxis]];

        // Scroll the content by the same percentage.
        let scrollPos = dragPerc * this.contentEl[this.scrollSizeAttr[this.currentAxis]];

        scrollEl[this.scrollOffsetAttr[this.currentAxis]] = scrollPos;
    }

    /**
     * End scroll handle drag
     */
    onEndDrag() {
        document.removeEventListener('mousemove', this.drag);
        document.removeEventListener('mouseup', this.onEndDrag);
    }

    /**
     * Resize scrollbar
     */
    resizeScrollbar(axis = 'y') {
        let track;
        let scrollbar;
        let scrollOffset;
        let contentSize;

        if (axis === 'x') {
            track = this.trackX;
            scrollbar = this.scrollbarX;
            scrollOffset = this.contentEl[this.scrollOffsetAttr[axis]]; // Either scrollTop() or scrollLeft().
            contentSize = this.contentEl[this.scrollSizeAttr[axis]];
        } else { // 'y'
            track = this.trackY;
            scrollbar = this.scrollbarY;
            scrollOffset = this.scrollContentEl[this.scrollOffsetAttr[axis]]; // Either scrollTop() or scrollLeft().
            contentSize = this.contentEl[this.scrollSizeAttr[axis]] - 15;
        }

        let scrollbarSize   = track[this.sizeAttr[axis]];
        let scrollbarRatio  = scrollbarSize / contentSize;
        let scrollPourcent  = scrollOffset / (contentSize - scrollbarSize);
            // Calculate new height/position of drag handle.
            // Offset of 2px allows for a small top/bottom or left/right margin around handle.
        let handleSize      = Math.max(~~(scrollbarRatio * (scrollbarSize - 2)) - 2, this.options.scrollbarMinSize);
        let handleOffset    = ~~((scrollbarSize - 4 - handleSize) * scrollPourcent + 2);

        // Set isVisible to false if scrollbar is not necessary (content is shorter than wrapper)
        this.isVisible[axis] = scrollbarSize < contentSize

        if (this.isVisible[axis]) {
            track.style.visibility = 'visible';

            if (axis === 'x') {
                scrollbar.style.left = `${handleOffset}px`;
                scrollbar.style.width = `${handleSize}px`;
            } else {
                scrollbar.style.top = `${handleOffset}px`;
                scrollbar.style.height = `${handleSize}px`;
            }
        } else {
            track.style.visibility = 'hidden';
        }
    }

    /**
     * On scroll event handling
     */
    onScrollX() {
        this.flashScrollbar('x');
    }

    onScrollY() {
        this.flashScrollbar('y');
    }

    /**
     * On mouseenter event handling
     */
    onMouseEnter() {
        this.flashScrollbar('x');
        this.flashScrollbar('y');
    }

    /**
     * Flash scrollbar visibility
     */
    flashScrollbar(axis = 'y') {
        this.resizeScrollbar(axis);
        this.showScrollbar(axis);
    }

    /**
     * Show scrollbar
     */
    showScrollbar(axis = 'y') {
        if (!this.isVisible[axis]) {
            return
        }

        if (axis === 'x') {
            this.scrollbarX.classList.add('visible');
        } else {
            this.scrollbarY.classList.add('visible');
        }

        if (!this.options.autoHide) {
            return
        }
        if(typeof this.flashTimeout === 'number') {
            window.clearTimeout(this.flashTimeout);
        }

        this.flashTimeout = window.setTimeout(this.hideScrollbar.bind(this), 1000);
    }

    /**
     * Hide Scrollbar
     */
    hideScrollbar() {
        this.scrollbarX.classList.remove('visible');
        this.scrollbarY.classList.remove('visible');

        if(typeof this.flashTimeout === 'number') {
            window.clearTimeout(this.flashTimeout);
        }
    }

    /**
     * Recalculate scrollbar
     */
    recalculate() {
        if (!this.enabled) return;

        this.resizeScrollbar('x');
        this.resizeScrollbar('y');

        if (!this.options.autoHide) {
            this.showScrollbar('x');
            this.showScrollbar('y');
        }
    }

    /**
     * Getter for original scrolling element
     */
    getScrollElement() {
        return this.scrollContentEl;
    }

    /**
     * Getter for content element
     */
    getContentElement() {
        return this.contentEl;
    }

    /**
     * UnMount mutation observer and delete SimpleBar instance from DOM element
     */
    unMount() {
        this.removeListeners();
        this.el.SimpleBar = null;
    }

    /**
     * Recursively walks up the parent nodes looking for this.el
     */
    isChildNode(el) {
        if (el === null) return false;
        if (el === this.el) return true;

        return this.isChildNode(el.parentNode);
    }
}

/**
 * HTML API
 */
SimpleBar.initHtmlApi();
<commit_msg>remove unused references<commit_after>import scrollbarWidth from 'scrollbarwidth';
import debounce from 'lodash.debounce';
import ResizeObserver from 'resize-observer-polyfill';

import './simplebar.css';

export default class SimpleBar {
    constructor(element, options) {
        this.el = element;
        this.flashTimeout;
        this.contentEl;
        this.scrollContentEl;
        this.dragOffset         = { x: 0, y: 0 };
        this.isVisible          = { x: true, y: true };
        this.scrollOffsetAttr   = { x: 'scrollLeft', y: 'scrollTop' };
        this.sizeAttr           = { x: 'offsetWidth', y: 'offsetHeight' };
        this.scrollSizeAttr     = { x: 'scrollWidth', y: 'scrollHeight' };
        this.offsetAttr         = { x: 'left', y: 'top' };
        this.globalObserver;
        this.mutationObserver;
        this.resizeObserver;
        this.currentAxis;
        this.options = Object.assign({}, SimpleBar.defaultOptions, options);
        this.classNames = this.options.classNames;
        this.scrollbarWidth = scrollbarWidth();
        this.offsetSize = 20;
        // If scrollbar is a floating scrollbar, disable the plugin
        this.enabled = this.scrollbarWidth !== 0 || this.options.forceEnabled;
        this.flashScrollbar = this.flashScrollbar.bind(this);
        this.onDragY = this.onDragY.bind(this);
        this.onDragX = this.onDragX.bind(this);
        this.onScrollY = this.onScrollY.bind(this);
        this.onScrollX = this.onScrollX.bind(this);
        this.drag = this.drag.bind(this);
        this.onEndDrag = this.onEndDrag.bind(this);
        this.onMouseEnter = this.onMouseEnter.bind(this);

        this.recalculate = debounce(this.recalculate, 100, { leading: true, trailing: false });

        this.init();
    }

    static get defaultOptions() {
        return {
            wrapContent: true,
            autoHide: true,
            forceEnabled: false,
            classNames: {
                content: 'simplebar-content',
                scrollContent: 'simplebar-scroll-content',
                scrollbar: 'simplebar-scrollbar',
                track: 'simplebar-track'
            },
            scrollbarMinSize: 10
        }
    }

    static get htmlAttributes() {
        return {
            autoHide: 'data-simplebar-autohide',
            forceEnabled: 'data-simplebar-force-enabled',
            scrollbarMinSize: 'data-simplebar-scrollbar-min-size'
        }
    }

    static initHtmlApi() {
        this.initDOMLoadedElements = this.initDOMLoadedElements.bind(this);

        // MutationObserver is IE11+
        if (typeof MutationObserver !== 'undefined') {
            // Mutation observer to observe dynamically added elements
            this.globalObserver = new MutationObserver(mutations => {
                mutations.forEach(mutation => {
                    Array.from(mutation.addedNodes).forEach(addedNode => {
                        if (addedNode.nodeType === 1) {
                            if (addedNode.SimpleBar) return;

                            if (addedNode.hasAttribute('data-simplebar')) {
                                new SimpleBar(addedNode, SimpleBar.getElOptions(addedNode));
                            } else {
                                Array.from(addedNode.querySelectorAll('[data-simplebar]')).forEach(el => {
                                    new SimpleBar(el, SimpleBar.getElOptions(el));
                                });
                            }
                        }
                    });

                    Array.from(mutation.removedNodes).forEach(removedNode => {
                        if (removedNode.nodeType === 1) {
                            if (removedNode.hasAttribute('data-simplebar')) {
                                removedNode.SimpleBar && removedNode.SimpleBar.unMount();
                            } else {
                                Array.from(removedNode.querySelectorAll('[data-simplebar]')).forEach(el => {
                                    el.SimpleBar && el.SimpleBar.unMount();
                                });
                            }
                        }
                    });
                });
            });

            this.globalObserver.observe(document, { childList: true, subtree: true });
        }

        // Taken from jQuery `ready` function
        // Instantiate elements already present on the page
        if (document.readyState === 'complete' ||
                (document.readyState !== 'loading' && !document.documentElement.doScroll)) {
            // Handle it asynchronously to allow scripts the opportunity to delay init
            window.setTimeout(this.initDOMLoadedElements.bind(this));
        } else {
            document.addEventListener('DOMContentLoaded', this.initDOMLoadedElements);
            window.addEventListener('load', this.initDOMLoadedElements);
        }
    }

    // Helper function to retrieve options from element attributes
    static getElOptions(el) {
        const options = Object.keys(SimpleBar.htmlAttributes).reduce((acc, obj) => {
            const attribute = SimpleBar.htmlAttributes[obj];
            if (el.hasAttribute(attribute)) {
                acc[obj] = JSON.parse(el.getAttribute(attribute) || true);
            }
            return acc;
        }, {});

        return options;
    }

    static removeObserver() {
        this.globalObserver.disconnect();
    }

    static initDOMLoadedElements() {
        document.removeEventListener('DOMContentLoaded', this.initDOMLoadedElements);
        window.removeEventListener('load', this.initDOMLoadedElements);

        Array.from(document.querySelectorAll('[data-simplebar]')).forEach(el => {
            if (!el.SimpleBar)
                new SimpleBar(el, SimpleBar.getElOptions(el));
        });
    }

    init() {
        // Save a reference to the instance, so we know this DOM node has already been instancied
        this.el.SimpleBar = this;

        if (!this.enabled) {
            return;
        }

        this.initDOM();

        this.scrollContentEl = this.el.querySelector(`.${this.classNames.scrollContent}`);
        this.contentEl = this.el.querySelector(`.${this.classNames.content}`);

        this.trackX = this.el.querySelector(`.${this.classNames.track}.horizontal`);
        this.trackY = this.el.querySelector(`.${this.classNames.track}.vertical`);

        this.scrollbarX = this.trackX.querySelector(`.${this.classNames.scrollbar}`);
        this.scrollbarY = this.trackY.querySelector(`.${this.classNames.scrollbar}`);

        this.scrollContentEl.style.marginRight = `-${this.offsetSize}px`;
        this.scrollContentEl.style.paddingRight = `${this.offsetSize}px`;
        this.scrollContentEl.style.marginBottom = `-${this.offsetSize}px`;
        this.contentEl.style.paddingBottom = `${this.offsetSize}px`;

        if (this.enabled && this.scrollbarWidth !== 0) {
            this.scrollContentEl.style.marginBottom = `-${this.scrollbarWidth*2}px`;
            this.contentEl.style.marginRight = `-${this.scrollbarWidth}px`;
        }

        // Calculate content size
        this.recalculate();

        this.initListeners();
    }

    initDOM() {
        // Prepare DOM
        if (this.options.wrapContent) {
            this.scrollContentEl = document.createElement('div');
            this.contentEl = document.createElement('div');

            this.scrollContentEl.classList.add(this.classNames.scrollContent);
            this.contentEl.classList.add(this.classNames.content);

            while (this.el.firstChild)
                this.contentEl.appendChild(this.el.firstChild)

            this.scrollContentEl.appendChild(this.contentEl);
            this.el.appendChild(this.scrollContentEl);
        }

        const track = document.createElement('div');
        const scrollbar = document.createElement('div');

        track.classList.add(this.classNames.track);
        scrollbar.classList.add(this.classNames.scrollbar);

        track.appendChild(scrollbar);

        this.trackX = track.cloneNode(true);
        this.trackX.classList.add('horizontal');

        this.trackY = track.cloneNode(true);
        this.trackY.classList.add('vertical');

        this.el.insertBefore(this.trackX, this.el.firstChild);
        this.el.insertBefore(this.trackY, this.el.firstChild);
        this.el.setAttribute('data-simplebar', 'init');
    }

    initListeners() {
        // Event listeners
        if (this.options.autoHide) {
            this.el.addEventListener('mouseenter', this.onMouseEnter);
        }

        this.scrollbarY.addEventListener('mousedown', this.onDragY);
        this.scrollbarX.addEventListener('mousedown', this.onDragX);

        this.scrollContentEl.addEventListener('scroll', this.onScrollY);
        this.contentEl.addEventListener('scroll', this.onScrollX);

        // MutationObserver is IE11+
        if (typeof MutationObserver !== 'undefined') {
            // create an observer instance
            this.mutationObserver = new MutationObserver(mutations => {
                mutations.forEach(mutation => {
                    if (this.isChildNode(mutation.target) || mutation.addedNodes.length) {
                        this.recalculate();
                    }
                });
            });

            // pass in the target node, as well as the observer options
            this.mutationObserver.observe(this.el, { attributes: true, childList: true, characterData: true, subtree: true });
        }

        this.resizeObserver = new ResizeObserver(this.recalculate.bind(this));
        this.resizeObserver.observe(this.el);
    }

    removeListeners() {
        if (!this.enabled) {
            return;
        }

        // Event listeners
        if (this.options.autoHide) {
            this.el.removeEventListener('mouseenter', this.onMouseEnter);
        }

        this.scrollbarX.removeEventListener('mousedown', this.onDragX);
        this.scrollbarY.removeEventListener('mousedown', this.onDragY);

        this.scrollContentEl.removeEventListener('scroll', this.onScrollY);
        this.contentEl.removeEventListener('scroll', this.onScrollX);

        this.mutationObserver.disconnect();
        this.resizeObserver.disconnect();
    }

    onDragX(e) {
        this.onDrag(e, 'x');
    }

    onDragY(e) {
        this.onDrag(e, 'y');
    }

    /**
     * on scrollbar handle drag
     */
    onDrag(e, axis = 'y') {
        // Preventing the event's default action stops text being
        // selectable during the drag.
        e.preventDefault();

        const scrollbar = axis === 'y' ? this.scrollbarY : this.scrollbarX;

        // Measure how far the user's mouse is from the top of the scrollbar drag handle.
        const eventOffset = axis === 'y' ? e.pageY : e.pageX;

        this.dragOffset[axis] = eventOffset - scrollbar.getBoundingClientRect()[this.offsetAttr[axis]];
        this.currentAxis = axis;

        document.addEventListener('mousemove', this.drag);
        document.addEventListener('mouseup', this.onEndDrag);
    }

    /**
     * Drag scrollbar handle
     */
    drag(e) {
        let eventOffset, track, scrollEl;

        e.preventDefault();

        if (this.currentAxis === 'y') {
            eventOffset = e.pageY;
            track = this.trackY;
            scrollEl = this.scrollContentEl;
        } else {
            eventOffset = e.pageX;
            track = this.trackX;
            scrollEl = this.contentEl;
        }

        // Calculate how far the user's mouse is from the top/left of the scrollbar (minus the dragOffset).
        let dragPos = eventOffset - track.getBoundingClientRect()[this.offsetAttr[this.currentAxis]] - this.dragOffset[this.currentAxis];

        // Convert the mouse position into a percentage of the scrollbar height/width.
        let dragPerc = dragPos / track[this.sizeAttr[this.currentAxis]];

        // Scroll the content by the same percentage.
        let scrollPos = dragPerc * this.contentEl[this.scrollSizeAttr[this.currentAxis]];

        scrollEl[this.scrollOffsetAttr[this.currentAxis]] = scrollPos;
    }

    /**
     * End scroll handle drag
     */
    onEndDrag() {
        document.removeEventListener('mousemove', this.drag);
        document.removeEventListener('mouseup', this.onEndDrag);
    }

    /**
     * Resize scrollbar
     */
    resizeScrollbar(axis = 'y') {
        let track;
        let scrollbar;
        let scrollOffset;
        let contentSize;

        if (axis === 'x') {
            track = this.trackX;
            scrollbar = this.scrollbarX;
            scrollOffset = this.contentEl[this.scrollOffsetAttr[axis]]; // Either scrollTop() or scrollLeft().
            contentSize = this.contentEl[this.scrollSizeAttr[axis]];
        } else { // 'y'
            track = this.trackY;
            scrollbar = this.scrollbarY;
            scrollOffset = this.scrollContentEl[this.scrollOffsetAttr[axis]]; // Either scrollTop() or scrollLeft().
            contentSize = this.contentEl[this.scrollSizeAttr[axis]] - 15;
        }

        let scrollbarSize   = track[this.sizeAttr[axis]];
        let scrollbarRatio  = scrollbarSize / contentSize;
        let scrollPourcent  = scrollOffset / (contentSize - scrollbarSize);
            // Calculate new height/position of drag handle.
            // Offset of 2px allows for a small top/bottom or left/right margin around handle.
        let handleSize      = Math.max(~~(scrollbarRatio * (scrollbarSize - 2)) - 2, this.options.scrollbarMinSize);
        let handleOffset    = ~~((scrollbarSize - 4 - handleSize) * scrollPourcent + 2);

        // Set isVisible to false if scrollbar is not necessary (content is shorter than wrapper)
        this.isVisible[axis] = scrollbarSize < contentSize

        if (this.isVisible[axis]) {
            track.style.visibility = 'visible';

            if (axis === 'x') {
                scrollbar.style.left = `${handleOffset}px`;
                scrollbar.style.width = `${handleSize}px`;
            } else {
                scrollbar.style.top = `${handleOffset}px`;
                scrollbar.style.height = `${handleSize}px`;
            }
        } else {
            track.style.visibility = 'hidden';
        }
    }

    /**
     * On scroll event handling
     */
    onScrollX() {
        this.flashScrollbar('x');
    }

    onScrollY() {
        this.flashScrollbar('y');
    }

    /**
     * On mouseenter event handling
     */
    onMouseEnter() {
        this.flashScrollbar('x');
        this.flashScrollbar('y');
    }

    /**
     * Flash scrollbar visibility
     */
    flashScrollbar(axis = 'y') {
        this.resizeScrollbar(axis);
        this.showScrollbar(axis);
    }

    /**
     * Show scrollbar
     */
    showScrollbar(axis = 'y') {
        if (!this.isVisible[axis]) {
            return
        }

        if (axis === 'x') {
            this.scrollbarX.classList.add('visible');
        } else {
            this.scrollbarY.classList.add('visible');
        }

        if (!this.options.autoHide) {
            return
        }
        if(typeof this.flashTimeout === 'number') {
            window.clearTimeout(this.flashTimeout);
        }

        this.flashTimeout = window.setTimeout(this.hideScrollbar.bind(this), 1000);
    }

    /**
     * Hide Scrollbar
     */
    hideScrollbar() {
        this.scrollbarX.classList.remove('visible');
        this.scrollbarY.classList.remove('visible');

        if(typeof this.flashTimeout === 'number') {
            window.clearTimeout(this.flashTimeout);
        }
    }

    /**
     * Recalculate scrollbar
     */
    recalculate() {
        if (!this.enabled) return;

        this.resizeScrollbar('x');
        this.resizeScrollbar('y');

        if (!this.options.autoHide) {
            this.showScrollbar('x');
            this.showScrollbar('y');
        }
    }

    /**
     * Getter for original scrolling element
     */
    getScrollElement() {
        return this.scrollContentEl;
    }

    /**
     * Getter for content element
     */
    getContentElement() {
        return this.contentEl;
    }

    /**
     * UnMount mutation observer and delete SimpleBar instance from DOM element
     */
    unMount() {
        this.removeListeners();
        this.el.SimpleBar = null;
    }

    /**
     * Recursively walks up the parent nodes looking for this.el
     */
    isChildNode(el) {
        if (el === null) return false;
        if (el === this.el) return true;

        return this.isChildNode(el.parentNode);
    }
}

/**
 * HTML API
 */
SimpleBar.initHtmlApi();
<|endoftext|>


<commit_before>const url = require('url');
const _ = require('lodash');
const faker = require('faker');
const server = require('json-server');
const proxy = require('proxy-middleware');

const port = 3002;

const data = {
  repos: _.times(5, index => {
    const name = faker.random.word();
    return {
      id: index,
      name: name,
      description: faker.lorem.sentence(),
      html_url: `https://github.com/jas-chen/${name}`
    };
  })
};

const app = server.create();
const router = server.router(data);

// Mock API
app.use(server.defaults());
app.use('/users/jas-chen', router);
app.use('/', proxy(url.parse(`https://api.github.com/`)));

app.listen(port, (error) => {
  if (error) throw error;
  console.info(`server running at http://localhost:${port}`);
});
<commit_msg>update api server<commit_after>const url = require('url');
const _ = require('lodash');
const faker = require('faker');
const server = require('json-server');
const proxy = require('proxy-middleware');

const port = 3002;

const app = server.create();

// mock endpoint
const repoRouter = server.router({
  repos: _.times(5, index => {
    const name = faker.random.word();
    return {
      id: index,
      name: name,
      description: faker.lorem.sentence(),
      html_url: `https://github.com/jas-chen/${name}`
    };
  })
});

// proxy to real api server
const proxyRouter = proxy(url.parse(`https://api.github.com/`));

app.use(server.defaults());

app.use((req, res, next) => {
  if (req.originalUrl === '/users/jas-chen/repos') {
    repoRouter(req, res, next);
    return;
  }

  proxyRouter(req, res, next);
});

app.listen(port, (error) => {
  if (error) throw error;
  console.info(`server running at http://localhost:${port}`);
});
<|endoftext|>


<commit_before>/* Tooling
/* ========================================================================== */

import { $assign as $, $dispatch, $replaceAll } from 'esri-global-shared';

/* Brand
/* ========================================================================== */

const prefix = 'esri-header-brand';

export default () => {
	/* Brand: Image
	/* ====================================================================== */

	const $targetImage = $(
		document.createElementNS('http://www.w3.org/2000/svg', 'svg'),
		{ class: `${prefix}-image` }
	);

	/* Brand
	/* ====================================================================== */

	const $target = $('a', { class: prefix, id: prefix },
		$targetImage
	);

	// On Click
	$target.addEventListener('click', (event) => {
		$dispatch($target, 'header:click:brand', { event });
	});

	/* Brand: On Update
	/* ====================================================================== */

	$target.addEventListener('header:update:brand', ({ detail }) => {
		$($target, { href: detail.href, aria: { label: detail.label } });

		$($targetImage, { viewBox: `0 0 ${detail.width} ${detail.height}` });

		$replaceAll($targetImage,
			...detail.image.map(
				(d) => $(
					document.createElementNS('http://www.w3.org/2000/svg', 'path'),
					{ d }
				)
			)
		);
	});

	return $target;
}
<commit_msg>Include width and height in brand image<commit_after>/* Tooling
/* ========================================================================== */

import { $assign as $, $dispatch, $replaceAll } from 'esri-global-shared';

/* Brand
/* ========================================================================== */

const prefix = 'esri-header-brand';

export default () => {
	/* Brand: Image
	/* ====================================================================== */

	const $targetImage = $(
		document.createElementNS('http://www.w3.org/2000/svg', 'svg'),
		{ class: `${prefix}-image` }
	);

	/* Brand
	/* ====================================================================== */

	const $target = $('a', { class: prefix, id: prefix },
		$targetImage
	);

	// On Click
	$target.addEventListener('click', (event) => {
		$dispatch($target, 'header:click:brand', { event });
	});

	/* Brand: On Update
	/* ====================================================================== */

	$target.addEventListener('header:update:brand', ({ detail }) => {
		$($target, { href: detail.href, aria: { label: detail.label } });

		$($targetImage, { viewBox: `0 0 ${detail.width} ${detail.height}`, width: `${detail.width}`, height: `${detail.height}` });

		$replaceAll($targetImage,
			...detail.image.map(
				(d) => $(
					document.createElementNS('http://www.w3.org/2000/svg', 'path'),
					{ d }
				)
			)
		);
	});

	return $target;
}
<|endoftext|>


<commit_before>function addNewEntryButton() {
	$("#dial").append('

');
	$("#new_entry").on("click", function() {
		showBookmarkEntryForm("New Bookmark or Folder", "", "", "");
	});
	scaleSpeedDialEntry($("#new_entry"));
}

function addSpeedDialEntry(bookmark, index) {
	if (bookmark.hasOwnProperty("title") && bookmark.hasOwnProperty("url")) {
		$("#dial").append('
' +
							'' +
								'

' +
								'

' +
								'	' +
								'' + bookmark.title + '	' +
								'

	' +
								'

' +
							'' +
						'
');

		var entry = $("#" + bookmark.id);
		entry.find(".image").css("background-image", "url(" + getThumbnailUrl(bookmark) + ")");
		entry.find(".edit").on("click", function(event) {
			event.preventDefault();
			showBookmarkEntryForm("Edit Bookmark: " + bookmark.title, bookmark.title, bookmark.url, bookmark.id);
		});
		entry.find(".remove").on("click", function(event) {
			event.preventDefault();
			if (confirm("Are you sure you want to remove this bookmark?")) {
				removeBookmark(bookmark.id);
				var old_url = entry.find(".bookmark").attr("href");
				updateCustomIcon("", old_url);
			}
		});

		//If custom icon for the URL exists, evaluates to true & centers it on the dial
		if (JSON.parse(localStorage.getItem("custom_icon_data"))[bookmark.url]) {
			entry.find(".image").css({
				"background-size": "contain",
				"background-position": "center"
			});
		}

		scaleSpeedDialEntry(entry);

	} else if (bookmark.hasOwnProperty("children") && localStorage.getItem("show_subfolder_icons") === "true") {
		$("#dial").append('
' +
							'' +
								'

' +
								'

' +
									'	' +
									'
' + bookmark.title + '
	' +
									'

' +
								'
' +
							'' +
						'
');

		entry = $("#" + bookmark.id);
		entry.find(".edit").on("click", function(event) {
			event.preventDefault();
			showBookmarkEntryForm("Edit Folder: " + bookmark.title, bookmark.title, bookmark.url, bookmark.id);
		});
		entry.find(".remove").on("click", function(event) {
			event.preventDefault();
			if (confirm("Are you sure you want to remove this folder including all of it's bookmarks?")) {
				removeFolder(bookmark.id);
			}
		});
		entry.find(".foundicon-folder").css("color", localStorage.getItem("folder_color"));

		scaleSpeedDialEntry(entry);
	}
}

// Figures out how big the dial and its elements should be
// Needs to be called before the dial and entries are created
function calculateSpeedDialSize() {
	var dialColumns = localStorage.getItem("dial_columns");
	var dialWidth = localStorage.getItem("dial_width");

	var borderWidth = 14;
	var minEntryWidth = 120 - borderWidth;
	var adjustedDialWidth = window.innerWidth * 0.01 * dialWidth |0;

	var entryWidth = adjustedDialWidth / dialColumns - borderWidth;
	if (entryWidth < minEntryWidth) {
		entryWidth = minEntryWidth;
		adjustedDialWidth = (adjustedDialWidth / (minEntryWidth + borderWidth)) * (minEntryWidth + borderWidth);
	}
	$("#dial").css("width", adjustedDialWidth|0 +"px");
	$("#dial").attr("entry-width", entryWidth|0)
}

/* Retrieve the bookmarks bar node and use it to generate speed dials */
function createSpeedDial(folderId) {
	// Removes all entries under the current view and sets the new folderId
	$("#dial").attr("folder", folderId).html("");
	calculateSpeedDialSize();

	chrome.bookmarks.getSubTree(folderId, function(node) {
		var folder = {
			"folderId": folderId,
			"folderName": node[0].title,
			"folderNode": node[0]
		};

		// Loop over bookmarks in folder and add to the dial
		for (var i = 0; i < folder.folderNode.children.length; i++) {
			addSpeedDialEntry(folder.folderNode.children[i], i+1);
		}

		// Adds the + button to the dom only if enabled
		if (localStorage.getItem("show_new_entry") === "true") {
			addNewEntryButton();
		}

		// Show the options gear icon only if enabled and doesn't already exist
		if (localStorage.getItem("show_options_gear") === "true" && $("#options").length === 0) {
			$("#content").append('

');
		}

		if (localStorage.getItem("drag_and_drop") === "true") {
			$("#dial").sortable({
				distance: 20,
				forcePlaceholderSize: true,
				cursor: "move",
				containment: "document",
				tolerance: "pointer",
				items: "> div:not(#new_entry)",
				stop: function() {
					updateBookmarksOrder()
				}
			});
		}
		alignVertical();
	});
}

function getThumbnailUrl(bookmark) {
	if (JSON.parse(localStorage.getItem("custom_icon_data"))[bookmark.url]) {
		return JSON.parse(localStorage.getItem("custom_icon_data"))[bookmark.url];
	} else {
		if (localStorage.getItem("force_http") === "true") {
			bookmark.url = bookmark.url.replace("https", "http");
		}
		return localStorage.getItem("thumbnailing_service").replace("[URL]", bookmark.url);
	}
}

// Scales a single speed dial entry to the specified size
function scaleSpeedDialEntry(entry) {
	var entryWidth = $("#dial").attr("entry-width");
	var entryHeight = entryWidth*0.75|0;

	entry.css({"height": entryHeight +"px", "width": entryWidth +"px"});

	if (entry[0].id !== "new_entry") {
		var title = entry.find(".bookmark").attr("title");
		var titleLimit = entryWidth / 10;
		if (title.length > titleLimit) {
			title = title.substr(0, titleLimit - 3) + "...";
		}
		entry.find(".title").text(title);
		entry.find(".image").css("height", entryHeight - 20 +"px");
	}

	entry.find(".foundicon-folder").css({ "font-size": entryWidth*0.5|0 +"px", "top": entryWidth*0.05|0 +"px" });
	entry.find(".foundicon-plus").css({ "font-size": entryWidth*0.3|0 +"px", "top": entryWidth*0.18|0 +"px" });
}

function showBookmarkEntryForm(heading, title, url, target) {
	var form = $("#bookmark_form");

	form.find("h1").text(heading);
	form.find(".title").val(title);
	form.find(".url").val(url);
	form.find(".icon").val(JSON.parse(localStorage.getItem("custom_icon_data"))[url]);
	form.attr("target", target);

	// Selectors to hide URL & custom icon fields when editing a folder name
	if (!$("h1").text().indexOf("Edit Folder")){
		form.find("p").eq(1).hide();
		form.find("p").eq(2).hide();
	}
	// Selectors to hide the cusom icon field when adding a new entry
	if (!$("h1").text().indexOf("New")) {
		form.find("p").eq(2).hide()
	}

	form.reveal();
	form.find(".title").focus();
	form.on("reveal:close", function(){
		$("p").show();
	});
}

function updateCustomIcon(url, old_url) {
	var icon_object = JSON.parse(localStorage.getItem("custom_icon_data"));
	var custom_icon = $(".icon").val();

	//Creates a new key:value pair and merges it into JSON from localStorage
	var new_icon = {};
	new_icon[url] = custom_icon;
	var temp_object = $.extend(icon_object, new_icon);

	//Makes sure thumbnail URL changes along with the bookmark URL
	if (url !== old_url) {
		delete temp_object[old_url];
	}

	//Removes empty URL entries from localStorag
	if (custom_icon.trim().length === 0 || url.trim().length === 0) {
		delete temp_object[url];
		delete temp_object[old_url];
	}

	localStorage.setItem("custom_icon_data", JSON.stringify(temp_object));
	if (localStorage.getItem("enable_sync") === "true") {
		syncToStorage();
	}
	createSpeedDial(getStartingFolder());
}

function updateSpeedDialEntry(bookmark) {
	var entry = $("#" + bookmark.id);

	entry.find(".bookmark").attr("href", bookmark.url);
	entry.find(".bookmark").attr("title", bookmark.title);
	entry.find(".title").text(bookmark.title);
}

function alignVertical() {
	$("#dial").css("padding-top", "");
	if (localStorage.getItem("show_folder_list") === "true") {
		$("#dial").css("padding-top", ((window.innerHeight - $("#dial").height())/2)-50|0  + "px");
	} else {
		$("#dial").css("padding-top",  (window.innerHeight - $("#dial").height())/2|0 + "px");
	}
}

document.addEventListener("DOMContentLoaded", function() {
	initialize();
	createSpeedDial(getStartingFolder());

	$("#bookmark_form .title, #bookmark_form .url, #bookmark_form .icon").on("keydown", function(e) {
		if (e.which === 13) {
			$("#bookmark_form button").trigger("click");
		}
	});

	$("#bookmark_form button").on("click", function() {
		var target = $("#bookmark_form").attr("target");
		var title = $("#bookmark_form .title").val();
		var url = $("#bookmark_form .url").val();

		if (target.length > 0) {
			updateBookmark(target, title, url);
		} else {
			addBookmark(title, url);
		}
	});

	// Navigates to the entry corresponding to the single digit number between 1-9
	$(window).on("keypress", function(e) {
		// Prevents navigation while typing numbers in #bookmark_form input fields
		if (document.activeElement.type !== "text") {
			var key = String.fromCharCode(e.which);
			if (key >= 1 && key <= 9) {
				if ($('.entry[index="' + key + '"]').length !== 0) {
					window.location = $('.entry[index="' + key + '"]').find(".bookmark").attr("href");
				}
			}
			// Navigates to options page when letter "o"(options) or "s"(settings) is pressed.
			if (key === "o" || key === "s") {
				window.location = "options.html";
			}
		}
	});

	$(window).on("resize", function() {
		calculateSpeedDialSize();
		$(".entry").each(function() {
			scaleSpeedDialEntry($(this));
		});
		alignVertical();
	});

	// Change the current dial if the page hash changes
	$(window).on("hashchange", function() {
		var newFolder = getStartingFolder();
		createSpeedDial(newFolder);
		$("#folder_list").val(newFolder);
	});

	// Load the .css that refrences the .woff font file asynchronously in ajax request, halves render speed of dial
	$.ajax({ success: function() {
		$("head").append('<link type="text/css" rel="stylesheet" href="css/general_foundicons.css" />');
	}});
});
<commit_msg>Fixed bug of inaccurate entry index values when folders were in the list but option was set to not show folders<commit_after>function addNewEntryButton() {
	$("#dial").append('

');
	$("#new_entry").on("click", function() {
		showBookmarkEntryForm("New Bookmark or Folder", "", "", "");
	});
	scaleSpeedDialEntry($("#new_entry"));
}

function addSpeedDialEntry(bookmark) {
	if (bookmark.hasOwnProperty("title") && bookmark.hasOwnProperty("url")) {
		$("#dial").append('
' +
							'' +
								'

' +
								'

' +
								'	' +
								'' + bookmark.title + '	' +
								'

	' +
								'

' +
							'' +
						'
');

		var entry = $("#" + bookmark.id);
		entry.find(".image").css("background-image", "url(" + getThumbnailUrl(bookmark) + ")");
		entry.find(".edit").on("click", function(event) {
			event.preventDefault();
			showBookmarkEntryForm("Edit Bookmark: " + bookmark.title, bookmark.title, bookmark.url, bookmark.id);
		});
		entry.find(".remove").on("click", function(event) {
			event.preventDefault();
			if (confirm("Are you sure you want to remove this bookmark?")) {
				removeBookmark(bookmark.id);
				var old_url = entry.find(".bookmark").attr("href");
				updateCustomIcon("", old_url);
			}
		});

		//If custom icon for the URL exists, evaluates to true & centers it on the dial
		if (JSON.parse(localStorage.getItem("custom_icon_data"))[bookmark.url]) {
			entry.find(".image").css({
				"background-size": "contain",
				"background-position": "center"
			});
		}

		scaleSpeedDialEntry(entry);

	} else if (bookmark.hasOwnProperty("children") && localStorage.getItem("show_subfolder_icons") === "true") {
		$("#dial").append('
' +
							'' +
								'

' +
								'

' +
									'	' +
									'
' + bookmark.title + '
	' +
									'

' +
								'
' +
							'' +
						'
');

		entry = $("#" + bookmark.id);
		entry.find(".edit").on("click", function(event) {
			event.preventDefault();
			showBookmarkEntryForm("Edit Folder: " + bookmark.title, bookmark.title, bookmark.url, bookmark.id);
		});
		entry.find(".remove").on("click", function(event) {
			event.preventDefault();
			if (confirm("Are you sure you want to remove this folder including all of it's bookmarks?")) {
				removeFolder(bookmark.id);
			}
		});
		entry.find(".foundicon-folder").css("color", localStorage.getItem("folder_color"));

		scaleSpeedDialEntry(entry);
	}
}

// Figures out how big the dial and its elements should be
// Needs to be called before the dial and entries are created
function calculateSpeedDialSize() {
	var dialColumns = localStorage.getItem("dial_columns");
	var dialWidth = localStorage.getItem("dial_width");

	var borderWidth = 14;
	var minEntryWidth = 120 - borderWidth;
	var adjustedDialWidth = window.innerWidth * 0.01 * dialWidth |0;

	var entryWidth = adjustedDialWidth / dialColumns - borderWidth;
	if (entryWidth < minEntryWidth) {
		entryWidth = minEntryWidth;
		adjustedDialWidth = (adjustedDialWidth / (minEntryWidth + borderWidth)) * (minEntryWidth + borderWidth);
	}
	$("#dial").css("width", adjustedDialWidth|0 +"px");
	$("#dial").attr("entry-width", entryWidth|0)
}

/* Retrieve the bookmarks bar node and use it to generate speed dials */
function createSpeedDial(folderId) {
	// Removes all entries under the current view and sets the new folderId
	$("#dial").attr("folder", folderId).html("");
	calculateSpeedDialSize();

	chrome.bookmarks.getSubTree(folderId, function(node) {
		var folder = {
			"folderId": folderId,
			"folderName": node[0].title,
			"folderNode": node[0]
		};

		// Loop over bookmarks in folder and add to the dial
		for (var i = 0; i < folder.folderNode.children.length; i++) {
			addSpeedDialEntry(folder.folderNode.children[i]);
		}

		// Adds the + button to the dom only if enabled
		if (localStorage.getItem("show_new_entry") === "true") {
			addNewEntryButton();
		}

		// Show the options gear icon only if enabled and doesn't already exist
		if (localStorage.getItem("show_options_gear") === "true" && $("#options").length === 0) {
			$("#content").append('

');
		}

		if (localStorage.getItem("drag_and_drop") === "true") {
			$("#dial").sortable({
				distance: 20,
				forcePlaceholderSize: true,
				cursor: "move",
				containment: "document",
				tolerance: "pointer",
				items: "> div:not(#new_entry)",
				stop: function() {
					updateBookmarksOrder()
				}
			});
		}
		alignVertical();
	});
}

function getThumbnailUrl(bookmark) {
	if (JSON.parse(localStorage.getItem("custom_icon_data"))[bookmark.url]) {
		return JSON.parse(localStorage.getItem("custom_icon_data"))[bookmark.url];
	} else {
		if (localStorage.getItem("force_http") === "true") {
			bookmark.url = bookmark.url.replace("https", "http");
		}
		return localStorage.getItem("thumbnailing_service").replace("[URL]", bookmark.url);
	}
}

// Scales a single speed dial entry to the specified size
function scaleSpeedDialEntry(entry) {
	var entryWidth = $("#dial").attr("entry-width");
	var entryHeight = entryWidth*0.75|0;

	entry.css({"height": entryHeight +"px", "width": entryWidth +"px"});

	if (entry[0].id !== "new_entry") {
		var title = entry.find(".bookmark").attr("title");
		var titleLimit = entryWidth / 10;
		if (title.length > titleLimit) {
			title = title.substr(0, titleLimit - 3) + "...";
		}
		entry.find(".title").text(title);
		entry.find(".image").css("height", entryHeight - 20 +"px");
	}

	entry.find(".foundicon-folder").css({ "font-size": entryWidth*0.5|0 +"px", "top": entryWidth*0.05|0 +"px" });
	entry.find(".foundicon-plus").css({ "font-size": entryWidth*0.3|0 +"px", "top": entryWidth*0.18|0 +"px" });
}

function showBookmarkEntryForm(heading, title, url, target) {
	var form = $("#bookmark_form");

	form.find("h1").text(heading);
	form.find(".title").val(title);
	form.find(".url").val(url);
	form.find(".icon").val(JSON.parse(localStorage.getItem("custom_icon_data"))[url]);
	form.attr("target", target);

	// Selectors to hide URL & custom icon fields when editing a folder name
	if (!$("h1").text().indexOf("Edit Folder")){
		form.find("p").eq(1).hide();
		form.find("p").eq(2).hide();
	}
	// Selectors to hide the cusom icon field when adding a new entry
	if (!$("h1").text().indexOf("New")) {
		form.find("p").eq(2).hide()
	}

	form.reveal();
	form.find(".title").focus();
	form.on("reveal:close", function(){
		$("p").show();
	});
}

function updateCustomIcon(url, old_url) {
	var icon_object = JSON.parse(localStorage.getItem("custom_icon_data"));
	var custom_icon = $(".icon").val();

	//Creates a new key:value pair and merges it into JSON from localStorage
	var new_icon = {};
	new_icon[url] = custom_icon;
	var temp_object = $.extend(icon_object, new_icon);

	//Makes sure thumbnail URL changes along with the bookmark URL
	if (url !== old_url) {
		delete temp_object[old_url];
	}

	//Removes empty URL entries from localStorag
	if (custom_icon.trim().length === 0 || url.trim().length === 0) {
		delete temp_object[url];
		delete temp_object[old_url];
	}

	localStorage.setItem("custom_icon_data", JSON.stringify(temp_object));
	if (localStorage.getItem("enable_sync") === "true") {
		syncToStorage();
	}
	createSpeedDial(getStartingFolder());
}

function updateSpeedDialEntry(bookmark) {
	var entry = $("#" + bookmark.id);

	entry.find(".bookmark").attr("href", bookmark.url);
	entry.find(".bookmark").attr("title", bookmark.title);
	entry.find(".title").text(bookmark.title);
}

function alignVertical() {
	$("#dial").css("padding-top", "");
	if (localStorage.getItem("show_folder_list") === "true") {
		$("#dial").css("padding-top", ((window.innerHeight - $("#dial").height())/2)-50|0  + "px");
	} else {
		$("#dial").css("padding-top",  (window.innerHeight - $("#dial").height())/2|0 + "px");
	}
}

document.addEventListener("DOMContentLoaded", function() {
	initialize();
	createSpeedDial(getStartingFolder());

	$("#bookmark_form .title, #bookmark_form .url, #bookmark_form .icon").on("keydown", function(e) {
		if (e.which === 13) {
			$("#bookmark_form button").trigger("click");
		}
	});

	$("#bookmark_form button").on("click", function() {
		var target = $("#bookmark_form").attr("target");
		var title = $("#bookmark_form .title").val();
		var url = $("#bookmark_form .url").val();

		if (target.length > 0) {
			updateBookmark(target, title, url);
		} else {
			addBookmark(title, url);
		}
	});

	// Navigates to the entry corresponding to the single digit number between 1-9
	$(window).on("keypress", function(e) {
		// Prevents navigation while typing numbers in #bookmark_form input fields
		if (document.activeElement.type !== "text") {
			var key = String.fromCharCode(e.which);
			if (key >= 1 && key <= 9) {
				if ($('.entry[index="' + key + '"]').length !== 0) {
					window.location = $('.entry[index="' + key + '"]').find(".bookmark").attr("href");
				}
			}
			// Navigates to options page when letter "o"(options) or "s"(settings) is pressed.
			if (key === "o" || key === "s") {
				window.location = "options.html";
			}
		}
	});

	$(window).on("resize", function() {
		calculateSpeedDialSize();
		$(".entry").each(function() {
			scaleSpeedDialEntry($(this));
		});
		alignVertical();
	});

	// Change the current dial if the page hash changes
	$(window).on("hashchange", function() {
		var newFolder = getStartingFolder();
		createSpeedDial(newFolder);
		$("#folder_list").val(newFolder);
	});

	// Load the .css that refrences the .woff font file asynchronously in ajax request, halves render speed of dial
	$.ajax({ success: function() {
		$("head").append('<link type="text/css" rel="stylesheet" href="css/general_foundicons.css" />');
	}});
});
<|endoftext|>


<commit_before>var CharacterCreator = function(game, callback) {
    slickUI.add(this.panel = new SlickUI.Element.Panel(8, 8, game.width - 16, game.height - 16));
    this.panel.add(new SlickUI.Element.Text(10,10, "Style yourself!")).centerHorizontally().text.alpha = 0.5;

    var female = [];
    female.push(game.make.sprite(0, 0, 'female_base', 131));
    female.push(game.make.sprite(0, 0, 'female_shoes', 131));
    female.push(game.make.sprite(0, 0, 'female_pants', 131));
    female.push(game.make.sprite(0, 0, 'female_shoulderl', 131));
    female.push(game.make.sprite(0, 0, 'female_shirt', 131));

    var male = [];
    male.push(game.make.sprite(0, 0, 'male_base', 131));
    male.push(game.make.sprite(0, 0, 'male_shoes', 131));
    male.push(game.make.sprite(0, 0, 'male_pants', 131));
    male.push(game.make.sprite(0, 0, 'male_xlongknot', 131));
    male.push(game.make.sprite(0, 0, 'male_shirt', 131));

    var skeleton = [];
    skeleton.push(game.make.sprite(0, 0, 'skeleton_base', 131));
    skeleton.push(game.make.sprite(0, 0, 'male_shoes', 131));
    skeleton.push(game.make.sprite(0, 0, 'male_pants', 131));
    skeleton.push(game.make.sprite(0, 0, 'male_xlongknot', 131));
    skeleton.push(game.make.sprite(0, 0, 'male_shirt', 131));

    var hairValue = Math.random();
    var hairTint = valueToColor(hairValue);
    female[3].tint = hairTint;
    male[3].tint = hairTint;
    skeleton[3].tint = hairTint;

    var skinValue = Math.random();
    var skinTint = valueToColor(skinValue);
    female[0].tint = skinTint;
    male[0].tint = skinTint;
    skeleton[0].tint = skinTint;

    var shirtValue = Math.random();
    var shirtTint = valueToColor(shirtValue);
    female[4].tint = shirtTint;
    male[4].tint = shirtTint;
    skeleton[4].alpha = 0;

    var pantsValue = Math.random();
    var pantsTint = valueToColor(pantsValue);
    female[2].tint = pantsTint;
    male[2].tint = pantsTint;
    skeleton[2].tint = pantsTint;

    skeleton[1].alpha = 0;

    this.panel.add(new SlickUI.Element.Text(16,90, "Skin: ")).text.alpha = 0.5;
    var skinSlider = new SlickUI.Element.Slider(100,100, game.width - 150, skinValue);
    this.panel.add(skinSlider);

    this.panel.add(new SlickUI.Element.Text(16,160, "Hair: ")).text.alpha = 0.5;
    var hairSlider = new SlickUI.Element.Slider(100,170, game.width - 150, hairValue);
    this.panel.add(hairSlider);

    this.panel.add(new SlickUI.Element.Text(16,230, "Shirt: ")).text.alpha = 0.5;
    var shirtSlider = new SlickUI.Element.Slider(100,240, game.width - 150, shirtValue);
    this.panel.add(shirtSlider);

    this.panel.add(new SlickUI.Element.Text(16,300, "Pants: ")).text.alpha = 0.5;
    var pantsSlider = new SlickUI.Element.Slider(100,310, game.width - 150, pantsValue);
    this.panel.add(pantsSlider);

	this.panel.add(new SlickUI.Element.Text(10,350, "Body")).centerHorizontally().text.alpha = 0.5;

    var multiplier = 2;
    smallHeight = female[0].height*.75;
    smallWidth = female[0].width*.75;
    largeHeight = female[0].height*1.50;
    largeWidth = female[0].width*1.50;

    for(var i in female) {
    	female[i].height = largeHeight;
    	female[i].width = largeWidth;
    	female[i].anchor.setTo(0.5);
    	this.panel.add(new SlickUI.Element.DisplayObject(this.panel.width / 2 - 200, 430, female[i]));

        female[i].animations.add('down', [131,132,133,134,135,136,137,138], 15, true);
        female[i].play('down');
    }

    for(var i in male) {
    	male[i].anchor.setTo(0.5);
    	male[i].height = smallHeight;
    	male[i].width = smallWidth;
    	this.panel.add(new SlickUI.Element.DisplayObject(this.panel.width / 2, 430, male[i]));

        male[i].animations.add('down', [131,132,133,134,135,136,137,138], 15, true);
    }

    for(var i in skeleton) {
    	skeleton[i].anchor.setTo(0.5);
    	skeleton[i].height = smallHeight;
    	skeleton[i].width = smallWidth;
    	this.panel.add(new SlickUI.Element.DisplayObject(this.panel.width / 2 + 200, 430, skeleton[i]));

        skeleton[i].animations.add('down', [131,132,133,134,135,136,137,138], 15, true);
    }

    skinSlider.onDrag.add(function (value) {
    	skinValue = value;
    	var color = valueToColor(skinValue);
    	female[0].tint = color;
    	male[0].tint = color;
    	skeleton[0].tint = color;
    });

    hairSlider.onDrag.add(function (value) {
    	hairValue = value;
    	var color = valueToColor(hairValue);
    	female[3].tint = color;
    	male[3].tint = color;
    	skeleton[3].tint = color;
    });

    shirtSlider.onDrag.add(function (value) {
    	shirtValue = value;
    	var color = valueToColor(shirtValue);
    	female[4].tint = color;
    	male[4].tint = color;
    });

    pantsSlider.onDrag.add(function (value) {
    	pantsValue = value;
    	var color = valueToColor(pantsValue);
    	female[2].tint = color;
    	male[2].tint = color;
    	skeleton[2].tint = color;
    });

    var bodyType = 0;
    female[0].inputEnabled = true;
    female[0].events.onInputDown.add(function() {
    	bodyType = 0;
    	startAnimations(female, largeHeight, largeWidth);
    	stopAnimations(male, smallHeight, smallWidth);
    	stopAnimations(skeleton, smallHeight, smallWidth);
    }, this);

    male[0].inputEnabled = true;
    male[0].events.onInputDown.add(function() {
    	bodyType = 1;
    	stopAnimations(female, smallHeight, smallWidth);
    	startAnimations(male, largeHeight, largeWidth);
    	stopAnimations(skeleton, smallHeight, smallWidth);
    }, this);

    skeleton[0].inputEnabled = true;
    skeleton[0].events.onInputDown.add(function() {
    	bodyType = 2;
    	stopAnimations(female, smallHeight, smallWidth);
    	stopAnimations(male, smallHeight, smallHeight);
    	startAnimations(skeleton, largeHeight, largeWidth);
    }, this);

    this.panel.add(button = new SlickUI.Element.Button(game.width/2-60,550, 120, 50)).events.onInputUp.add(function () {
            callback({
				b:bodyType,
				n:"bleh",
				sk:skinValue,
				h:hairValue,
				sh:shirtValue,
				p:pantsValue});
        });
    button.add(new SlickUI.Element.Text(0,0, "Go!")).center();
};

function startAnimations(model, height, width) {
	for(var i in model) {
        model[i].play('down');
    	model[i].height = height;
    	model[i].width = largeWidth;
    }
}

function stopAnimations(model, height, width) {
	for(var i in model) {
        model[i].animations.stop();
    	model[i].height = height;
    	model[i].width = width;
    }
}

function valueToColor(value) {
	value *= 7;
	var r = 0;
	var g = 0;
	var b = 0;
	if (value <= 1) {	// 255		0      255    2/7
		r = 255;
		g = 0;
		b = Math.round(value*255);
	}
	else if (value <= 2) {	// 0        0      255    3/7
		r = Math.round(255-((value-1)*255));
		g = 0;
		b = 255;
	}
	else if (value <= 3) {	// 0       255    255    4/7
		r = 0;
		g = Math.round((value-2)*255);
		b = 255;
	}
	else if (value <= 4) {	// 0       255    0      5/7
		r = 0;
		g = 255;
		b = Math.round(255-((value-3)*255));
	}
	else if (value <= 5) {	// 255     255    0      6/7
		r = Math.round((value-4)*255);
		g = 255;
		b = 0;
	}
	else if(value <= 6) {					// 255     0      0      7/7
		r = 255;
		g = Math.round(255-((value-5)*255));
		b = 0;
		if(g < 127) {
			r = g*2;
		}
	}
	else {
		r = Math.round((value-6)*255);
		g = Math.round((value-6)*255);
		b = Math.round((value-6)*255);
	}
	return Phaser.Color.getColor(r, g, b);
}

CharacterCreator.prototype = {
	destroy: function() {
		this.panel.destroy();
	},
	bringToTop: function() {
		this.panel.bringToTop();
	}
};<commit_msg>update char creator ui<commit_after>var CharacterCreator = function(game, callback) {
    slickUI.add(this.panel = new SlickUI.Element.Panel(8, 8, game.width - 16, game.height - 16));
    this.panel.add(new SlickUI.Element.Text(10,10, "Style yourself!")).centerHorizontally().text.alpha = 0.5;

    var female = [];
    female.push(game.make.sprite(0, 0, 'female_base', 131));
    female.push(game.make.sprite(0, 0, 'female_shoes', 131));
    female.push(game.make.sprite(0, 0, 'female_pants', 131));
    female.push(game.make.sprite(0, 0, 'female_shoulderl', 131));
    female.push(game.make.sprite(0, 0, 'female_shirt', 131));

    var male = [];
    male.push(game.make.sprite(0, 0, 'male_base', 131));
    male.push(game.make.sprite(0, 0, 'male_shoes', 131));
    male.push(game.make.sprite(0, 0, 'male_pants', 131));
    male.push(game.make.sprite(0, 0, 'male_xlongknot', 131));
    male.push(game.make.sprite(0, 0, 'male_shirt', 131));

    var skeleton = [];
    skeleton.push(game.make.sprite(0, 0, 'skeleton_base', 131));
    skeleton.push(game.make.sprite(0, 0, 'male_shoes', 131));
    skeleton.push(game.make.sprite(0, 0, 'male_pants', 131));
    skeleton.push(game.make.sprite(0, 0, 'male_xlongknot', 131));
    skeleton.push(game.make.sprite(0, 0, 'male_shirt', 131));

    var hairValue = Math.random();
    var hairTint = valueToColor(hairValue);
    female[3].tint = hairTint;
    male[3].tint = hairTint;
    skeleton[3].tint = hairTint;

    var skinValue = Math.random();
    var skinTint = valueToColor(skinValue);
    female[0].tint = skinTint;
    male[0].tint = skinTint;
    skeleton[0].tint = skinTint;

    var shirtValue = Math.random();
    var shirtTint = valueToColor(shirtValue);
    female[4].tint = shirtTint;
    male[4].tint = shirtTint;
    skeleton[4].alpha = 0;

    var pantsValue = Math.random();
    var pantsTint = valueToColor(pantsValue);
    female[2].tint = pantsTint;
    male[2].tint = pantsTint;
    skeleton[2].tint = pantsTint;

    skeleton[1].alpha = 0;

    this.panel.add(new SlickUI.Element.Text(16,50, "Skin: ")).text.alpha = 0.5;
    var skinSlider = new SlickUI.Element.Slider(100,60, game.width - 150, skinValue);
    this.panel.add(skinSlider);

    this.panel.add(new SlickUI.Element.Text(16,110, "Hair: ")).text.alpha = 0.5;
    var hairSlider = new SlickUI.Element.Slider(100,120, game.width - 150, hairValue);
    this.panel.add(hairSlider);

    this.panel.add(new SlickUI.Element.Text(16,170, "Shirt: ")).text.alpha = 0.5;
    var shirtSlider = new SlickUI.Element.Slider(100,180, game.width - 150, shirtValue);
    this.panel.add(shirtSlider);

    this.panel.add(new SlickUI.Element.Text(16,230, "Pants: ")).text.alpha = 0.5;
    var pantsSlider = new SlickUI.Element.Slider(100,240, game.width - 150, pantsValue);
    this.panel.add(pantsSlider);

	this.panel.add(new SlickUI.Element.Text(10,290, "Body")).centerHorizontally().text.alpha = 0.5;

    var multiplier = 2;
    smallHeight = female[0].height*.75;
    smallWidth = female[0].width*.75;
    largeHeight = female[0].height*1.50;
    largeWidth = female[0].width*1.50;

    for(var i in female) {
    	female[i].height = largeHeight;
    	female[i].width = largeWidth;
    	female[i].anchor.setTo(0.5);
    	this.panel.add(new SlickUI.Element.DisplayObject(this.panel.width / 2 - 100, 360, female[i]));

        female[i].animations.add('down', [131,132,133,134,135,136,137,138], 15, true);
        female[i].play('down');
    }

    for(var i in male) {
    	male[i].anchor.setTo(0.5);
    	male[i].height = smallHeight;
    	male[i].width = smallWidth;
    	this.panel.add(new SlickUI.Element.DisplayObject(this.panel.width / 2, 360, male[i]));

        male[i].animations.add('down', [131,132,133,134,135,136,137,138], 15, true);
    }

    for(var i in skeleton) {
    	skeleton[i].anchor.setTo(0.5);
    	skeleton[i].height = smallHeight;
    	skeleton[i].width = smallWidth;
    	this.panel.add(new SlickUI.Element.DisplayObject(this.panel.width / 2 + 100, 360, skeleton[i]));

        skeleton[i].animations.add('down', [131,132,133,134,135,136,137,138], 15, true);
    }

    skinSlider.onDrag.add(function (value) {
    	skinValue = value;
    	var color = valueToColor(skinValue);
    	female[0].tint = color;
    	male[0].tint = color;
    	skeleton[0].tint = color;
    });

    hairSlider.onDrag.add(function (value) {
    	hairValue = value;
    	var color = valueToColor(hairValue);
    	female[3].tint = color;
    	male[3].tint = color;
    	skeleton[3].tint = color;
    });

    shirtSlider.onDrag.add(function (value) {
    	shirtValue = value;
    	var color = valueToColor(shirtValue);
    	female[4].tint = color;
    	male[4].tint = color;
    });

    pantsSlider.onDrag.add(function (value) {
    	pantsValue = value;
    	var color = valueToColor(pantsValue);
    	female[2].tint = color;
    	male[2].tint = color;
    	skeleton[2].tint = color;
    });

    var bodyType = 0;
    female[0].inputEnabled = true;
    female[0].events.onInputDown.add(function() {
    	bodyType = 0;
    	startAnimations(female, largeHeight, largeWidth);
    	stopAnimations(male, smallHeight, smallWidth);
    	stopAnimations(skeleton, smallHeight, smallWidth);
    }, this);

    male[0].inputEnabled = true;
    male[0].events.onInputDown.add(function() {
    	bodyType = 1;
    	stopAnimations(female, smallHeight, smallWidth);
    	startAnimations(male, largeHeight, largeWidth);
    	stopAnimations(skeleton, smallHeight, smallWidth);
    }, this);

    skeleton[0].inputEnabled = true;
    skeleton[0].events.onInputDown.add(function() {
    	bodyType = 2;
    	stopAnimations(female, smallHeight, smallWidth);
    	stopAnimations(male, smallHeight, smallHeight);
    	startAnimations(skeleton, largeHeight, largeWidth);
    }, this);

    this.panel.add(button = new SlickUI.Element.Button(0,game.height-80, game.width, 50)).events.onInputUp.add(function () {
            callback({
				b:bodyType,
				n:"bleh",
				sk:skinValue,
				h:hairValue,
				sh:shirtValue,
				p:pantsValue});
        });
    button.add(new SlickUI.Element.Text(0,0, "Go!")).center();
};

function startAnimations(model, height, width) {
	for(var i in model) {
        model[i].play('down');
    	model[i].height = height;
    	model[i].width = largeWidth;
    }
}

function stopAnimations(model, height, width) {
	for(var i in model) {
        model[i].animations.stop();
    	model[i].height = height;
    	model[i].width = width;
    }
}

function valueToColor(value) {
	value *= 7;
	var r = 0;
	var g = 0;
	var b = 0;
	if (value <= 1) {	// 255		0      255    2/7
		r = 255;
		g = 0;
		b = Math.round(value*255);
	}
	else if (value <= 2) {	// 0        0      255    3/7
		r = Math.round(255-((value-1)*255));
		g = 0;
		b = 255;
	}
	else if (value <= 3) {	// 0       255    255    4/7
		r = 0;
		g = Math.round((value-2)*255);
		b = 255;
	}
	else if (value <= 4) {	// 0       255    0      5/7
		r = 0;
		g = 255;
		b = Math.round(255-((value-3)*255));
	}
	else if (value <= 5) {	// 255     255    0      6/7
		r = Math.round((value-4)*255);
		g = 255;
		b = 0;
	}
	else if(value <= 6) {					// 255     0      0      7/7
		r = 255;
		g = Math.round(255-((value-5)*255));
		b = 0;
		if(g < 127) {
			r = g*2;
		}
	}
	else {
		r = Math.round((value-6)*255);
		g = Math.round((value-6)*255);
		b = Math.round((value-6)*255);
	}
	return Phaser.Color.getColor(r, g, b);
}

CharacterCreator.prototype = {
	destroy: function() {
		this.panel.destroy();
	},
	bringToTop: function() {
		this.panel.bringToTop();
	}
};<|endoftext|>


<commit_before>module.exports = function(React) {
  var { Base, Cata } = require('adt-simple');

  var { PropTypes: T, addons: { classSet }} = React;

  data RadioItem {
    label: String,
    value: String
  } deriving (Base, Cata)

  return React.createClass({

    statics: {
      RadioItem: RadioItem
    }

    propTypes: {
      // A list of additional classes for the radio group
      classNames: T.arrayOf(T.string),

      // Name of the radio group
      name: T.string.isRequired,

      // Items in the Radio Group
      items: T.arrayOf(T.instanceOf(RadioItem)).isRequired,

      // Initial value for the radio group
      initialValue: T.string,

      // Whether the radio group can be modified or not
      readOnly: T.bool,

      // Label for the field
      label: T.string,

      // Description of the value expected in the field
      description: T.string,

      // Fired whenever the value of the radio group changes
      onChange: T.func
    },

    getDefaultProps: function() {
      return {
        classNames: [],
        initialValue: '',
        readOnly: false,
        label: '',
        description: '',
        onChange: function(){ }
      }
    },

    getInitialState: function() {
      return {
        value: this.props.initialValue
      }
    },

    renderRadioItem: function(item) {

    },

    render: function() {
      var classes = classSet({
        'jsk-field': true,
        'jsk-radio-group': true,
        'jsk-non-editable': this.props.readOnly
      }) + ' ' + this.props.classNames.join(' ');

      return (

          <input type="hidden" name={ this.props.name } value={ this.state.value } />
          { this.props.label }

            { this.props.items.map(this.renderRadioItem) }

{ this.props.description }

      )
    }

  });
}
<commit_msg>Fixes missing semicolon<commit_after>module.exports = function(React) {
  var { Base, Cata } = require('adt-simple');

  var { PropTypes: T, addons: { classSet }} = React;

  data RadioItem {
    label: String,
    value: String
  } deriving (Base, Cata)

  return React.createClass({

    statics: {
      RadioItem: RadioItem
    },

    propTypes: {
      // A list of additional classes for the radio group
      classNames: T.arrayOf(T.string),

      // Name of the radio group
      name: T.string.isRequired,

      // Items in the Radio Group
      items: T.arrayOf(T.instanceOf(RadioItem)).isRequired,

      // Initial value for the radio group
      initialValue: T.string,

      // Whether the radio group can be modified or not
      readOnly: T.bool,

      // Label for the field
      label: T.string,

      // Description of the value expected in the field
      description: T.string,

      // Fired whenever the value of the radio group changes
      onChange: T.func
    },

    getDefaultProps: function() {
      return {
        classNames: [],
        initialValue: '',
        readOnly: false,
        label: '',
        description: '',
        onChange: function(){ }
      }
    },

    getInitialState: function() {
      return {
        value: this.props.initialValue
      }
    },

    renderRadioItem: function(item) {

    },

    render: function() {
      var classes = classSet({
        'jsk-field': true,
        'jsk-radio-group': true,
        'jsk-non-editable': this.props.readOnly
      }) + ' ' + this.props.classNames.join(' ');

      return (

          <input type="hidden" name={ this.props.name } value={ this.state.value } />
          { this.props.label }

            { this.props.items.map(this.renderRadioItem) }

{ this.props.description }

      )
    }

  });
}
<|endoftext|>


<commit_before>;(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        factory(require('jquery'), window, document);
    } else {
        factory(window.jQuery, window, document);
    }
}(function ( $, window, document, undefined ) {

    /**
     * Calculate scrollbar width
     *
     * Called only once as a constant variable: we assume that scrollbar width never change
     *
     * Original function by Jonathan Sharp:
     * http://jdsharp.us/jQuery/minute/calculate-scrollbar-width.php
     */
    var SCROLLBAR_WIDTH;

    function scrollbarWidth () {
        // Append a temporary scrolling element to the DOM, then measure
        // the difference between its outer and inner elements.
        var tempEl  = $('

'),
            width   = 0,
            widthMinusScrollbars = 0;

        $('body').append(tempEl);

        width = $(tempEl).innerWidth(),
        widthMinusScrollbars = $('div', tempEl).innerWidth();

        tempEl.remove();

        return (width - widthMinusScrollbars);
    }

    var IS_WEBKIT = 'WebkitAppearance' in document.documentElement.style;

    // SimpleBar Constructor
    function SimpleBar (element, options) {
        this.el = element,
        this.$el = $(element),
        this.$track,
        this.$scrollbar,
        this.dragOffset,
        this.flashTimeout,
        this.$contentEl         = this.$el,
        this.$scrollContentEl   = this.$el,
        this.scrollDirection    = 'vert',
        this.scrollOffsetAttr   = 'scrollTop',
        this.sizeAttr           = 'height',
        this.scrollSizeAttr     = 'scrollHeight',
        this.offsetAttr         = 'top';

        this.options = $.extend({}, SimpleBar.DEFAULTS, options);
        this.theme   = this.options.css;

        this.init();
    }

    SimpleBar.DEFAULTS = {
        wrapContent: true,
        autoHide: true,
        css: {
          container: 'simplebar',
          content: 'simplebar-content',
          scrollContent: 'simplebar-scroll-content',
          scrollbar: 'simplebar-scrollbar',
          scrollbarTrack: 'simplebar-track'
        }
    };

    SimpleBar.prototype.init = function () {
        // Measure scrollbar width
        if(typeof SCROLLBAR_WIDTH === 'undefined') {
            SCROLLBAR_WIDTH = scrollbarWidth();
        }

        // If scrollbar is a floating scrollbar, disable the plugin
        if(SCROLLBAR_WIDTH === 0) {
          this.$el.css('overflow', 'auto');

          return;
        }

        if (this.$el.data('simplebar-direction') === 'horizontal' || this.$el.hasClass(this.theme.container + ' horizontal')){
            this.scrollDirection    = 'horiz';
            this.scrollOffsetAttr   = 'scrollLeft';
            this.sizeAttr           = 'width';
            this.scrollSizeAttr     = 'scrollWidth';
            this.offsetAttr         = 'left';
        }

        if (this.options.wrapContent) {
            this.$el.wrapInner('

');
        }

        this.$contentEl = this.$el.find('.' + this.theme.content);

        this.$el.prepend('

');
        this.$track = this.$el.find('.' + this.theme.scrollbarTrack);
        this.$scrollbar = this.$el.find('.' + this.theme.scrollbar);

        this.$scrollContentEl = this.$el.find('.' + this.theme.scrollContent);

        this.resizeScrollContent();

        if (this.options.autoHide) {
            this.$el.on('mouseenter', $.proxy(this.flashScrollbar, this));
        }

        this.$scrollbar.on('mousedown', $.proxy(this.startDrag, this));
        this.$scrollContentEl.on('scroll', $.proxy(this.startScroll, this));

        this.resizeScrollbar();

        if (!this.options.autoHide) {
            this.showScrollbar();
        }
    };

    /**
     * Start scrollbar handle drag
     */
    SimpleBar.prototype.startDrag = function (e) {
        // Preventing the event's default action stops text being
        // selectable during the drag.
        e.preventDefault();

        // Measure how far the user's mouse is from the top of the scrollbar drag handle.
        var eventOffset = e.pageY;
        if (this.scrollDirection === 'horiz') {
            eventOffset = e.pageX;
        }
        this.dragOffset = eventOffset - this.$scrollbar.offset()[this.offsetAttr];

        $(document).on('mousemove', $.proxy(this.drag, this));
        $(document).on('mouseup', $.proxy(this.endDrag, this));
    };

    /**
     * Drag scrollbar handle
     */
    SimpleBar.prototype.drag = function (e) {
        e.preventDefault();

        // Calculate how far the user's mouse is from the top/left of the scrollbar (minus the dragOffset).
        var eventOffset = e.pageY,
            dragPos     = null,
            dragPerc    = null,
            scrollPos   = null;

        if (this.scrollDirection === 'horiz') {
          eventOffset = e.pageX;
        }

        dragPos = eventOffset - this.$track.offset()[this.offsetAttr] - this.dragOffset;
        // Convert the mouse position into a percentage of the scrollbar height/width.
        dragPerc = dragPos / this.$track[this.sizeAttr]();
        // Scroll the content by the same percentage.
        scrollPos = dragPerc * this.$contentEl[0][this.scrollSizeAttr];

        this.$scrollContentEl[this.scrollOffsetAttr](scrollPos);
    };

    /**
     * End scroll handle drag
     */
    SimpleBar.prototype.endDrag = function () {
        $(document).off('mousemove', this.drag);
        $(document).off('mouseup', this.endDrag);
    };

    /**
     * Resize scrollbar
     */
    SimpleBar.prototype.resizeScrollbar = function () {
        if(SCROLLBAR_WIDTH === 0) {
            return;
        }

        var contentSize     = this.$contentEl[0][this.scrollSizeAttr],
            scrollOffset    = this.$scrollContentEl[this.scrollOffsetAttr](), // Either scrollTop() or scrollLeft().
            scrollbarSize   = this.$track[this.sizeAttr](),
            scrollbarRatio  = scrollbarSize / contentSize,
            // Calculate new height/position of drag handle.
            // Offset of 2px allows for a small top/bottom or left/right margin around handle.
            handleOffset    = Math.round(scrollbarRatio * scrollOffset) + 2,
            handleSize      = Math.floor(scrollbarRatio * (scrollbarSize - 2)) - 2;

        if (scrollbarSize < contentSize) {
            if (this.scrollDirection === 'vert'){
                this.$scrollbar.css({'top': handleOffset, 'height': handleSize});
            } else {
                this.$scrollbar.css({'left': handleOffset, 'width': handleSize});
            }
            this.$track.show();
        } else {
            this.$track.hide();
        }
    };

    /**
     * On scroll event handling
     */
    SimpleBar.prototype.startScroll = function(e) {
        // Simulate event bubbling to root element
        this.$el.trigger(e);

        this.flashScrollbar();
    };

    /**
     * Flash scrollbar visibility
     */
    SimpleBar.prototype.flashScrollbar = function () {
        this.resizeScrollbar();
        this.showScrollbar();
    };

    /**
     * Show scrollbar
     */
    SimpleBar.prototype.showScrollbar = function () {
        this.$scrollbar.addClass('visible');

        if (!this.options.autoHide) {
            return;
        }
        if(typeof this.flashTimeout === 'number') {
            window.clearTimeout(this.flashTimeout);
        }

        this.flashTimeout = window.setTimeout($.proxy(this.hideScrollbar, this), 1000);
    };

    /**
     * Hide Scrollbar
     */
    SimpleBar.prototype.hideScrollbar = function () {
        this.$scrollbar.removeClass('visible');
        if(typeof this.flashTimeout === 'number') {
            window.clearTimeout(this.flashTimeout);
        }
    };

    /**
     * Resize content element
     */
    SimpleBar.prototype.resizeScrollContent = function () {
        if (IS_WEBKIT) {
            return;
        }

        if (this.scrollDirection === 'vert'){
            this.$scrollContentEl.width(this.$el.width()+SCROLLBAR_WIDTH);
            this.$scrollContentEl.height(this.$el.height());
        } else {
            this.$scrollContentEl.width(this.$el.width());
            this.$scrollContentEl.height(this.$el.height()+SCROLLBAR_WIDTH);
        }
    };

    /**
     * Recalculate scrollbar
     */
    SimpleBar.prototype.recalculate = function () {
        this.resizeScrollContent();
        this.resizeScrollbar();
    };

    /**
     * Getter for original scrolling element
     */
    SimpleBar.prototype.getScrollElement = function () {
        return this.$scrollContentEl;
    };

    /**
     * Getter for content element
     */
    SimpleBar.prototype.getContentElement = function () {
        return this.$contentEl;
    };

    /**
     * Data API
     */
    $(window).on('load', function () {
        $('[data-simplebar-direction]').each(function () {
            $(this).simplebar();
        });
    });

    /**
     * Plugin definition
     */
    var old = $.fn.simplebar;

    $.fn.simplebar = function (options) {
        var args = arguments,
            returns;

        // If the first parameter is an object (options), or was omitted,
        // instantiate a new instance of the plugin.
        if (typeof options === 'undefined' || typeof options === 'object') {
            return this.each(function () {

                // Only allow the plugin to be instantiated once,
                // so we check that the element has no plugin instantiation yet
                if (!$.data(this, 'simplebar')) { $.data(this, 'simplebar', new SimpleBar(this, options)); }
            });

        // If the first parameter is a string
        // treat this as a call to a public method.
        } else if (typeof options === 'string') {
            this.each(function () {
                var instance = $.data(this, 'simplebar');

                // Tests that there's already a plugin-instance
                // and checks that the requested public method exists
                if (instance instanceof SimpleBar && typeof instance[options] === 'function') {

                    // Call the method of our plugin instance,
                    // and pass it the supplied arguments.
                    returns = instance[options].apply( instance, Array.prototype.slice.call( args, 1 ) );
                }

                // Allow instances to be destroyed via the 'destroy' method
                if (options === 'destroy') {
                  $.data(this, 'simplebar', null);
                }
            });

            // If the earlier cached method
            // gives a value back return the value,
            // otherwise return this to preserve chainability.
            return returns !== undefined ? returns : this;
        }
    };

    $.fn.simplebar.Constructor = SimpleBar;

    /**
     * No conflict
     */
    $.fn.simplebar.noConflict = function () {
        $.fn.simplebar = old;
        return this;
    };

}));
<commit_msg>fix indentation + fix typo<commit_after>;(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        factory(require('jquery'), window, document);
    } else {
        factory(window.jQuery, window, document);
    }
}(function ( $, window, document, undefined ) {

    /**
     * Calculate scrollbar width
     *
     * Called only once as a constant variable: we assume that scrollbar width never change
     *
     * Original function by Jonathan Sharp:
     * http://jdsharp.us/jQuery/minute/calculate-scrollbar-width.php
     */
    var SCROLLBAR_WIDTH;

    function scrollbarWidth () {
        // Append a temporary scrolling element to the DOM, then measure
        // the difference between its outer and inner elements.
        var tempEl  = $('

'),
            width   = 0,
            widthMinusScrollbars = 0;

        $('body').append(tempEl);

        width = $(tempEl).innerWidth(),
        widthMinusScrollbars = $('div', tempEl).innerWidth();

        tempEl.remove();

        return (width - widthMinusScrollbars);
    }

    var IS_WEBKIT = 'WebkitAppearance' in document.documentElement.style;

    // SimpleBar Constructor
    function SimpleBar (element, options) {
        this.el = element,
        this.$el = $(element),
        this.$track,
        this.$scrollbar,
        this.dragOffset,
        this.flashTimeout,
        this.$contentEl         = this.$el,
        this.$scrollContentEl   = this.$el,
        this.scrollDirection    = 'vert',
        this.scrollOffsetAttr   = 'scrollTop',
        this.sizeAttr           = 'height',
        this.scrollSizeAttr     = 'scrollHeight',
        this.offsetAttr         = 'top';

        this.options = $.extend({}, SimpleBar.DEFAULTS, options);
        this.theme   = this.options.css;

        this.init();
    }

    SimpleBar.DEFAULTS = {
        wrapContent: true,
        autoHide: true,
        css: {
            container: 'simplebar',
            content: 'simplebar-content',
            scrollContent: 'simplebar-scroll-content',
            scrollbar: 'simplebar-scrollbar',
            scrollbarTrack: 'simplebar-track'
        }
    };

    SimpleBar.prototype.init = function () {
        // Measure scrollbar width
        if(typeof SCROLLBAR_WIDTH === 'undefined') {
            SCROLLBAR_WIDTH = scrollbarWidth();
        }

        // If scrollbar is a floating scrollbar, disable the plugin
        if(SCROLLBAR_WIDTH === 0) {
          this.$el.css('overflow', 'auto');

          return;
        }

        if (this.$el.data('simplebar-direction') === 'horizontal' || this.$el.hasClass(this.theme.container + ' horizontal')){
            this.scrollDirection    = 'horiz';
            this.scrollOffsetAttr   = 'scrollLeft';
            this.sizeAttr           = 'width';
            this.scrollSizeAttr     = 'scrollWidth';
            this.offsetAttr         = 'left';
        }

        if (this.options.wrapContent) {
            this.$el.wrapInner('

');
        }

        this.$contentEl = this.$el.find('.' + this.theme.content);

        this.$el.prepend('

');
        this.$track = this.$el.find('.' + this.theme.scrollbarTrack);
        this.$scrollbar = this.$el.find('.' + this.theme.scrollbar);

        this.$scrollContentEl = this.$el.find('.' + this.theme.scrollContent);

        this.resizeScrollContent();

        if (this.options.autoHide) {
            this.$el.on('mouseenter', $.proxy(this.flashScrollbar, this));
        }

        this.$scrollbar.on('mousedown', $.proxy(this.startDrag, this));
        this.$scrollContentEl.on('scroll', $.proxy(this.startScroll, this));

        this.resizeScrollbar();

        if (!this.options.autoHide) {
            this.showScrollbar();
        }
    };

    /**
     * Start scrollbar handle drag
     */
    SimpleBar.prototype.startDrag = function (e) {
        // Preventing the event's default action stops text being
        // selectable during the drag.
        e.preventDefault();

        // Measure how far the user's mouse is from the top of the scrollbar drag handle.
        var eventOffset = e.pageY;
        if (this.scrollDirection === 'horiz') {
            eventOffset = e.pageX;
        }
        this.dragOffset = eventOffset - this.$scrollbar.offset()[this.offsetAttr];

        $(document).on('mousemove', $.proxy(this.drag, this));
        $(document).on('mouseup', $.proxy(this.endDrag, this));
    };

    /**
     * Drag scrollbar handle
     */
    SimpleBar.prototype.drag = function (e) {
        e.preventDefault();

        // Calculate how far the user's mouse is from the top/left of the scrollbar (minus the dragOffset).
        var eventOffset = e.pageY,
            dragPos     = null,
            dragPerc    = null,
            scrollPos   = null;

        if (this.scrollDirection === 'horiz') {
          eventOffset = e.pageX;
        }

        dragPos = eventOffset - this.$track.offset()[this.offsetAttr] - this.dragOffset;
        // Convert the mouse position into a percentage of the scrollbar height/width.
        dragPerc = dragPos / this.$track[this.sizeAttr]();
        // Scroll the content by the same percentage.
        scrollPos = dragPerc * this.$contentEl[0][this.scrollSizeAttr];

        this.$scrollContentEl[this.scrollOffsetAttr](scrollPos);
    };

    /**
     * End scroll handle drag
     */
    SimpleBar.prototype.endDrag = function () {
        $(document).off('mousemove', this.drag);
        $(document).off('mouseup', this.endDrag);
    };

    /**
     * Resize scrollbar
     */
    SimpleBar.prototype.resizeScrollbar = function () {
        if(SCROLLBAR_WIDTH === 0) {
            return;
        }

        var contentSize     = this.$contentEl[0][this.scrollSizeAttr],
            scrollOffset    = this.$scrollContentEl[this.scrollOffsetAttr](), // Either scrollTop() or scrollLeft().
            scrollbarSize   = this.$track[this.sizeAttr](),
            scrollbarRatio  = scrollbarSize / contentSize,
            // Calculate new height/position of drag handle.
            // Offset of 2px allows for a small top/bottom or left/right margin around handle.
            handleOffset    = Math.round(scrollbarRatio * scrollOffset) + 2,
            handleSize      = Math.floor(scrollbarRatio * (scrollbarSize - 2)) - 2;

        if (scrollbarSize < contentSize) {
            if (this.scrollDirection === 'vert'){
                this.$scrollbar.css({'top': handleOffset, 'height': handleSize});
            } else {
                this.$scrollbar.css({'left': handleOffset, 'width': handleSize});
            }
            this.$track.show();
        } else {
            this.$track.hide();
        }
    };

    /**
     * On scroll event handling
     */
    SimpleBar.prototype.startScroll = function(e) {
        // Simulate event bubbling to root element
        this.$el.trigger(e);

        this.flashScrollbar();
    };

    /**
     * Flash scrollbar visibility
     */
    SimpleBar.prototype.flashScrollbar = function () {
        this.resizeScrollbar();
        this.showScrollbar();
    };

    /**
     * Show scrollbar
     */
    SimpleBar.prototype.showScrollbar = function () {
        this.$scrollbar.addClass('visible');

        if (!this.options.autoHide) {
            return;
        }
        if(typeof this.flashTimeout === 'number') {
            window.clearTimeout(this.flashTimeout);
        }

        this.flashTimeout = window.setTimeout($.proxy(this.hideScrollbar, this), 1000);
    };

    /**
     * Hide Scrollbar
     */
    SimpleBar.prototype.hideScrollbar = function () {
        this.$scrollbar.removeClass('visible');
        if(typeof this.flashTimeout === 'number') {
            window.clearTimeout(this.flashTimeout);
        }
    };

    /**
     * Resize content element
     */
    SimpleBar.prototype.resizeScrollContent = function () {
        if (IS_WEBKIT) {
            return;
        }

        if (this.scrollDirection === 'vert'){
            this.$scrollContentEl.width(this.$el.width()+SCROLLBAR_WIDTH);
            this.$scrollContentEl.height(this.$el.height());
        } else {
            this.$scrollContentEl.width(this.$el.width());
            this.$scrollContentEl.height(this.$el.height()+SCROLLBAR_WIDTH);
        }
    };

    /**
     * Recalculate scrollbar
     */
    SimpleBar.prototype.recalculate = function () {
        this.resizeScrollContent();
        this.resizeScrollbar();
    };

    /**
     * Getter for original scrolling element
     */
    SimpleBar.prototype.getScrollElement = function () {
        return this.$scrollContentEl;
    };

    /**
     * Getter for content element
     */
    SimpleBar.prototype.getContentElement = function () {
        return this.$contentEl;
    };

    /**
     * Data API
     */
    $(window).on('load', function () {
        $('[data-simplebar-direction]').each(function () {
            $(this).simplebar();
        });
    });

    /**
     * Plugin definition
     */
    var old = $.fn.simplebar;

    $.fn.simplebar = function (options) {
        var args = arguments,
            returns;

        // If the first parameter is an object (options), or was omitted,
        // instantiate a new instance of the plugin.
        if (typeof options === 'undefined' || typeof options === 'object') {
            return this.each(function () {

                // Only allow the plugin to be instantiated once,
                // so we check that the element has no plugin instantiation yet
                if (!$.data(this, 'simplebar')) { $.data(this, 'simplebar', new SimpleBar(this, options)); }
            });

        // If the first parameter is a string
        // treat this as a call to a public method.
        } else if (typeof options === 'string') {
            this.each(function () {
                var instance = $.data(this, 'simplebar');

                // Tests that there's already a plugin-instance
                // and checks that the requested public method exists
                if (instance instanceof SimpleBar && typeof instance[options] === 'function') {

                    // Call the method of our plugin instance,
                    // and pass it the supplied arguments.
                    returns = instance[options].apply( instance, Array.prototype.slice.call( args, 1 ) );
                }

                // Allow instances to be destroyed via the 'destroy' method
                if (options === 'destroy') {
                  $.data(this, 'simplebar', null);
                }
            });

            // If the earlier cached method
            // gives a value back return the value,
            // otherwise return this to preserve chainability.
            return returns !== undefined ? returns : this;
        }
    };

    $.fn.simplebar.Constructor = SimpleBar;

    /**
     * No conflict
     */
    $.fn.simplebar.noConflict = function () {
        $.fn.simplebar = old;
        return this;
    };

}));
<|endoftext|>