<commit_before>var React   = require('react/addons'),
    scroll  = require('scroll'),
    Beacon  = require('./Beacon'),
    Tooltip = require('./Tooltip');

var joyride = {
    browser: undefined,
    initialized: false,
    mixin: false,
    steps: [],

    getBrowser: function () {
        // Return cached result if avalible, else get result then cache it.
        if (this.browser) {
            return this.browser;
        }

        var isOpera = Boolean(window.opera) || navigator.userAgent.indexOf(' OPR/') >= 0;
        // Opera 8.0+ (UA detection to detect Blink/v8-powered Opera)
        var isFirefox = typeof InstallTrigger !== 'undefined';// Firefox 1.0+
        var isSafari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0;
        // At least Safari 3+: "[object HTMLElementConstructor]"
        var isChrome = Boolean(window.chrome) && !isOpera;// Chrome 1+
        var isIE = /*@cc_on!@*/false || Boolean(document.documentMode); // At least IE6

        return (this.browser =
            isOpera ? 'opera' :
                isFirefox ? 'firefox' :
                    isSafari ? 'safari' :
                        isChrome ? 'chrome' :
                            isIE ? 'ie' :
                                '');
    },

    getElementDimensions: function (el) {
        // Get the DOM Node if you pass in a string
        el = (typeof el === 'string') ? document.querySelector(el) : el;

        var styles = window.getComputedStyle(el),
            height = el.clientHeight + parseInt(styles.marginTop, 10) + parseInt(styles.marginBottom, 10),
            width  = el.clientWidth + parseInt(styles.marginLeft, 10) + parseInt(styles.marginRight, 10);

        return {
            height: height,
            width: width
        };
    },

    getScrollTop: function (state) {
        var step      = joyride.steps[state.joyrideCurrentIndex],
            position  = state.joyrideOverridePosition || step.position,
            target    = document.querySelector(step.selector),
            targetTop = target.getBoundingClientRect().top + document.body.scrollTop,
            scrollTop = 0;

        if (/^top/.test(position)) {
            scrollTop = Math.floor(state.joyrideYPos - state.joyrideScrollOffset);
        }
        else if (/^bottom|^left|^right/.test(position)) {
            scrollTop = Math.floor(targetTop - state.joyrideScrollOffset);
        }

        return scrollTop;
    },

    keyboardNavigation: function (e) {
        var intKey = (window.Event) ? e.which : e.keyCode,
            hasSteps;

        if (this.state.joyrideShowTooltip) {
            if ([32, 38, 40].indexOf(intKey) > -1) {
                e.preventDefault();
            }

            if (intKey === 27) {
                joyride.toggleTooltip(false, this.state.joyrideCurrentIndex + 1);
            }
            else if ([13, 32].indexOf(intKey) > -1) {
                hasSteps = Boolean(joyride.steps[this.state.joyrideCurrentIndex + 1]);
                joyride.toggleTooltip(hasSteps, this.state.joyrideCurrentIndex + 1);
            }
        }
    },

    onClickBeacon: function (e) {
        e.preventDefault();
        joyride.toggleTooltip(true, this.state.joyrideCurrentIndex);
    },

    onClickTooltip: function (e) {
        e.preventDefault();
        e.stopPropagation();

        var state    = this.state,
            type     = e.currentTarget.getAttribute('data-type'),
            newIndex = state.joyrideCurrentIndex + (type === 'back' ? -1 : 1);

        if (e.target === e.currentTarget) {
            joyride.toggleTooltip(state.joyrideType === 'guided' && type !== 'close' && Boolean(joyride.steps[newIndex]), newIndex);
        }
    },

    calcPlacement: function () {
        var mixin     = this.mixin || this,
            state     = mixin.state,
            step      = joyride.steps[state.joyrideCurrentIndex],
            component = document.querySelector((state.joyrideShowTooltip ? '.joyride-tooltip' : '.joyride-beacon')),
            position,
            body,
            target,
            placement = {
                x: -1000,
                y: -1000
            };

        if (step && (!/animate/.test(component.className) || state.joyrideXPos < 0)) {
            position = step.position;
            body = document.body.getBoundingClientRect();
            target = document.querySelector(step.selector).getBoundingClientRect();
            component = joyride.getElementDimensions((state.joyrideShowTooltip ? '.joyride-tooltip' : '.joyride-beacon'));

            // Change the step position in the tooltip won't fit in the window
            if (/^left/.test(position) && target.left - (component.width + state.joyrideTooltipOffset) < 0) {
                position = 'top';
            }
            else if (/^right/.test(position) && target.left + target.width + (component.width + state.joyrideTooltipOffset) > body.width) {
                position = 'bottom';
            }

            // Calculate x position
            if (/^left/.test(position)) {
                placement.x = target.left - (state.joyrideShowTooltip ? component.width + state.joyrideTooltipOffset : component.width / 2);
            }
            else if (/^right/.test(position)) {
                placement.x = target.left + target.width - (state.joyrideShowTooltip ? -state.joyrideTooltipOffset : component.width / 2);
            }
            else {
                placement.x = target.left + target.width / 2 - component.width / 2;
            }

            // Calculate y position
            if (/^top/.test(position)) {
                placement.y = (target.top - body.top) - (state.joyrideShowTooltip ? component.height + state.joyrideTooltipOffset : component.height / 2);
            }
            else if (/^bottom/.test(position)) {
                placement.y = (target.top - body.top) + target.height - (state.joyrideShowTooltip ? -state.joyrideTooltipOffset : component.height / 2);
            }
            else {
                placement.y = (target.top - body.top) + target.height / 2 - component.height / 2 + (state.joyrideShowTooltip ? state.joyrideTooltipOffset : 0);
            }

            if (/^bottom|^top/.test(position)) {
                if (/left/.test(position)) {
                    placement.x = target.left - (state.joyrideShowTooltip ? state.joyrideTooltipOffset : component.width / 2);
                }
                else if (/right/.test(position)) {
                    placement.x = target.left + target.width - (state.joyrideShowTooltip ? component.width - state.joyrideTooltipOffset : component.width / 2);
                }
            }

            mixin.setState({
                joyrideXPos: joyride.preventWindowOverflow(Math.ceil(placement.x), 'x', component.width, component.height),
                joyrideYPos: joyride.preventWindowOverflow(Math.ceil(placement.y), 'y', component.width, component.height),
                joyrideOverridePosition: step.position !== position ? position : false
            });
        }
    },
    preventWindowOverflow: function (value, axis, elWidth, elHeight) {
        var winWidth  = window.innerWidth,
            docHeight = document.body.offsetHeight,
            newValue  = value;

        if (axis === 'x') {
            if (value + elWidth >= winWidth) {
                newValue = winWidth - elWidth - 15;
            }
            else if (value < 0) {
                newValue = 15;
            }
        }
        else if (axis === 'y') {
            if (value + elHeight >= docHeight) {
                newValue = docHeight - elHeight - 15;
            }
            else if (value < 0) {
                newValue = 15;
            }
        }

        return newValue;
    },

    toggleTooltip: function (show, index) {
        this.mixin.setState({
            joyrideShowTooltip: show,
            joyrideCurrentIndex: index,
            joyrideXPos: -1000,
            joyrideYPos: -1000
        });
    }
};

var Mixin = {
    getInitialState: function () {
        return {
            joyrideCurrentIndex: 0,
            joyrideKeyboardNavigation: true,
            joyrideLocale: {
                back: 'Back',
                close: 'Close',
                last: 'Last',
                next: 'Next'
            },
            joyrideOverridePosition: false,
            joyridePlay: false,
            joyrideScrollToSteps: true,
            joyrideScrollOffset: 20,
            joyrideShowBackButton: true,<commit_msg>add JSdoc comments for `joyride`<commit_after>var React   = require('react/addons'),
    scroll  = require('scroll'),
    Beacon  = require('./Beacon'),
    Tooltip = require('./Tooltip');

var joyride = {
    browser: undefined,
    initialized: false,
    mixin: false,
    steps: [],

    /**
     * Returns the current browser
     * @returns {String}
     */
    getBrowser: function () {
        // Return cached result if avalible, else get result then cache it.
        if (this.browser) {
            return this.browser;
        }

        var isOpera = Boolean(window.opera) || navigator.userAgent.indexOf(' OPR/') >= 0;
        // Opera 8.0+ (UA detection to detect Blink/v8-powered Opera)
        var isFirefox = typeof InstallTrigger !== 'undefined';// Firefox 1.0+
        var isSafari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0;
        // At least Safari 3+: "[object HTMLElementConstructor]"
        var isChrome = Boolean(window.chrome) && !isOpera;// Chrome 1+
        var isIE = /*@cc_on!@*/false || Boolean(document.documentMode); // At least IE6

        return (this.browser =
            isOpera ? 'opera' :
                isFirefox ? 'firefox' :
                    isSafari ? 'safari' :
                        isChrome ? 'chrome' :
                            isIE ? 'ie' :
                                '');
    },

    /**
     * Get an element actual dimensions with margin
     * @param el {String|@type {HTMLElement}} - Element node or selector
     * @returns {{height: number, width: number}}
     */
    getElementDimensions: function (el) {
        // Get the DOM Node if you pass in a string
        el = (typeof el === 'string') ? document.querySelector(el) : el;

        var styles = window.getComputedStyle(el),
            height = el.clientHeight + parseInt(styles.marginTop, 10) + parseInt(styles.marginBottom, 10),
            width  = el.clientWidth + parseInt(styles.marginLeft, 10) + parseInt(styles.marginRight, 10);

        return {
            height: height,
            width: width
        };
    },

    /**
     * Get the scrollTop position
     * @returns {number}
     */
    getScrollTop: function () {
        var state     = this.mixin.state,
            step      = joyride.steps[state.joyrideCurrentIndex],
            position  = state.joyrideOverridePosition || step.position,
            target    = document.querySelector(step.selector),
            targetTop = target.getBoundingClientRect().top + document.body.scrollTop,
            scrollTop = 0;

        if (/^top/.test(position)) {
            scrollTop = Math.floor(state.joyrideYPos - state.joyrideScrollOffset);
        }
        else if (/^bottom|^left|^right/.test(position)) {
            scrollTop = Math.floor(targetTop - state.joyrideScrollOffset);
        }

        return scrollTop;
    },

    /**
     * Keydown event listener
     * @this {Mixin}
     * @param e {Event} - Keyboard event
     */
    keyboardNavigation: function (e) {
        var intKey = (window.Event) ? e.which : e.keyCode,
            hasSteps;

        if (this.state.joyrideShowTooltip) {
            if ([32, 38, 40].indexOf(intKey) > -1) {
                e.preventDefault();
            }

            if (intKey === 27) {
                joyride.toggleTooltip(false, this.state.joyrideCurrentIndex + 1);
            }
            else if ([13, 32].indexOf(intKey) > -1) {
                hasSteps = Boolean(joyride.steps[this.state.joyrideCurrentIndex + 1]);
                joyride.toggleTooltip(hasSteps, this.state.joyrideCurrentIndex + 1);
            }
        }
    },

    /**
     * Beacon click event listener
     * @this {Mixin}
     * @param e {Event} - Keyboard event
     */
    onClickBeacon: function (e) {
        e.preventDefault();
        joyride.toggleTooltip(true, this.state.joyrideCurrentIndex);
    },

    /**
     * Tooltip click event listener
     * @this {Mixin}
     * @param e {Event} - Keyboard event
     */
    onClickTooltip: function (e) {
        e.preventDefault();
        e.stopPropagation();

        var state    = this.state,
            type     = e.currentTarget.getAttribute('data-type'),
            newIndex = state.joyrideCurrentIndex + (type === 'back' ? -1 : 1);

        if (e.target === e.currentTarget) {
            joyride.toggleTooltip(state.joyrideType === 'guided' && type !== 'close' && Boolean(joyride.steps[newIndex]), newIndex);
        }
    },

    /**
     * Position absolute elements next to its target based on
     * the step position and window size
     * @this {Mixin|this}
     */
    calcPlacement: function () {
        var mixin     = this.mixin || this,
            state     = mixin.state,
            step      = joyride.steps[state.joyrideCurrentIndex],
            component = document.querySelector((state.joyrideShowTooltip ? '.joyride-tooltip' : '.joyride-beacon')),
            position,
            body,
            target,
            placement = {
                x: -1000,
                y: -1000
            };

        if (step && (!/animate/.test(component.className) || state.joyrideXPos < 0)) {
            position = step.position;
            body = document.body.getBoundingClientRect();
            target = document.querySelector(step.selector).getBoundingClientRect();
            component = joyride.getElementDimensions((state.joyrideShowTooltip ? '.joyride-tooltip' : '.joyride-beacon'));

            // Change the step position in the tooltip won't fit in the window
            if (/^left/.test(position) && target.left - (component.width + state.joyrideTooltipOffset) < 0) {
                position = 'top';
            }
            else if (/^right/.test(position) && target.left + target.width + (component.width + state.joyrideTooltipOffset) > body.width) {
                position = 'bottom';
            }

            // Calculate x position
            if (/^left/.test(position)) {
                placement.x = target.left - (state.joyrideShowTooltip ? component.width + state.joyrideTooltipOffset : component.width / 2);
            }
            else if (/^right/.test(position)) {
                placement.x = target.left + target.width - (state.joyrideShowTooltip ? -state.joyrideTooltipOffset : component.width / 2);
            }
            else {
                placement.x = target.left + target.width / 2 - component.width / 2;
            }

            // Calculate y position
            if (/^top/.test(position)) {
                placement.y = (target.top - body.top) - (state.joyrideShowTooltip ? component.height + state.joyrideTooltipOffset : component.height / 2);
            }
            else if (/^bottom/.test(position)) {
                placement.y = (target.top - body.top) + target.height - (state.joyrideShowTooltip ? -state.joyrideTooltipOffset : component.height / 2);
            }
            else {
                placement.y = (target.top - body.top) + target.height / 2 - component.height / 2 + (state.joyrideShowTooltip ? state.joyrideTooltipOffset : 0);
            }

            if (/^bottom|^top/.test(position)) {
                if (/left/.test(position)) {
                    placement.x = target.left - (state.joyrideShowTooltip ? state.joyrideTooltipOffset : component.width / 2);
                }
                else if (/right/.test(position)) {
                    placement.x = target.left + target.width - (state.joyrideShowTooltip ? component.width - state.joyrideTooltipOffset : component.width / 2);
                }
            }

            mixin.setState({
                joyrideXPos: joyride.preventWindowOverflow(Math.ceil(placement.x), 'x', component.width, component.height),
                joyrideYPos: joyride.preventWindowOverflow(Math.ceil(placement.y), 'y', component.width, component.height),
                joyrideOverridePosition: step.position !== position ? position : false
            });
        }
    },

    /**
     * Prevent tooltip to render outside the window
     * @param value {Number} - The axis position
     * @param axis {String} - The Axis X or Y
     * @param elWidth {Number} - The target element width
     * @param elHeight {Number} - The target element height
     * @returns {Number}
     */
    preventWindowOverflow: function (value, axis, elWidth, elHeight) {
        var winWidth  = window.innerWidth,
            docHeight = document.body.offsetHeight,
            newValue  = value;

        if (axis === 'x') {
            if (value + elWidth >= winWidth) {
                newValue = winWidth - elWidth - 15;
            }
            else if (value < 0) {
                newValue = 15;
            }
        }
        else if (axis === 'y') {
            if (value + elHeight >= docHeight) {
                newValue = docHeight - elHeight - 15;
            }
            else if (value < 0) {
                newValue = 15;
            }
        }

        return newValue;
    },

    /**
     *
     * @param show {Boolean} Render the tooltip directly or the beacon
     * @param index {Number} The tour's new index
     */
    toggleTooltip: function (show, index) {
        this.mixin.setState({
            joyrideShowTooltip: show,
            joyrideCurrentIndex: index,
            joyrideXPos: -1000,
            joyrideYPos: -1000
        });
    }
};

var Mixin = {
    getInitialState: function () {
        return {
            joyrideCurrentIndex: 0,
            joyrideKeyboardNavigation: true,
            joyrideLocale: {
                back: 'Back',
                close: 'Close',
                last: 'Last',
                next: 'Next'
            },
            joyrideOverridePosition: false,
            joyridePlay: false,
            joyrideScrollToSteps: true,
            joyrideScrollOffset: 20,
            joyrideShowBackButton: true,
{'fraction_non_alphanumeric': 0.12030647177090692, 'fraction_numerical': 0.00869423463565723, 'mean_word_length': 1.7374683920868659, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2444509', 'n_tokens_mistral': 5184, 'n_tokens_neox': 4977, 'n_words': 1105}