<commit_before>import React from 'react';
import ReactDOM from 'react-dom';
import { observer as globalObserver } from 'binary-common-utils/lib/observer';
import {
    getTokenList,
    removeAllTokens,
    get as getStorage,
    set as setStorage,
    getToken,
} from 'binary-common-utils/lib/storageManager';
import 'jquery-ui/ui/widgets/dialog';
import _Blockly from './blockly';
import { translate } from '../../common/i18n';
import Save from './Dialogs/Save';
import Limits from './Dialogs/Limits';
import Chart from './Dialogs/Chart';
import TradingView from './Dialogs/TradingView';
import { getLanguage } from '../../common/lang';
import { roundBalance, isVirtual } from '../common/tools';
import { symbolPromise } from './shared';
import logHandler from './logger';
import Tour from './tour';
import OfficialVersionWarning from './react-components/OfficialVersionWarning';
import LogTable from './LogTable';
import TradeInfoPanel from './TradeInfoPanel';
import { logoutAllTokens, getOAuthURL, generateLiveApiInstance, AppConstants } from '../../common/appId';
import { updateConfigCurrencies } from '../common/const';

let realityCheckTimeout;

const api = generateLiveApiInstance();

api.events.on('balance', response => {
    const { balance: { balance: b, currency } } = response;

    const balance = roundBalance({ currency, balance: b });
    $('.topMenuBalance').text(`${balance} ${currency}`);
});

const addBalanceForToken = token => {
    api.authorize(token).then(() => {
        api.send({ forget_all: 'balance' }).then(() => {
            api.subscribeToBalance();
        });
    });
};

const chart = new Chart();
const tradingView = new TradingView();

const setBeforeUnload = off => {
    if (off) {
        window.onbeforeunload = null;
    } else {
        window.onbeforeunload = () => 'You have some unsaved blocks, do you want to save them before you exit?';
    }
};

const showRealityCheck = () => {
    $('.blocker').show();
    $('.reality-check').show();
};

const hideRealityCheck = () => {
    $('#rc-err').hide();
    $('.blocker').hide();
    $('.reality-check').hide();
};

const stopRealityCheck = () => {
    clearInterval(realityCheckTimeout);
    realityCheckTimeout = null;
};

const realityCheckInterval = () => {
    realityCheckTimeout = setInterval(() => {
        const now = parseInt(new Date().getTime() / 1000);
        const checkTime = +getStorage('realityCheckTime');
        if (checkTime && now >= checkTime) {
            showRealityCheck();
            stopRealityCheck();
        }
    }, 1000);
};

const startRealityCheck = (time, token) => {
    stopRealityCheck();
    if (time) {
        const start = parseInt(new Date().getTime() / 1000) + time * 60;
        setStorage('realityCheckTime', start);
        realityCheckInterval();
    } else {
        const tokenObj = getToken(token);
        if (tokenObj.hasRealityCheck) {
            const checkTime = +getStorage('realityCheckTime');
            if (!checkTime) {
                showRealityCheck();
            } else {
                realityCheckInterval();
            }
        }
    }
};

const clearRealityCheck = () => {
    setStorage('realityCheckTime', null);
    stopRealityCheck();
};

const resetRealityCheck = token => {
    clearRealityCheck();
    startRealityCheck(null, token);
};

const limits = new Limits();
const saveDialog = new Save();
// const chart = new Chart();

const getActiveToken = (tokenList, activeToken) => {
    const activeTokenObject = tokenList.filter(tokenObject => tokenObject.token === activeToken);
    return activeTokenObject.length ? activeTokenObject[0] : tokenList[0];
};

const updateTokenList = () => {
    const tokenList = getTokenList();
    const loginButton = $('#login');
    const accountList = $('#account-list');
    if (tokenList.length === 0) {
        loginButton.show();
        accountList.hide();
        $('.account-id')
            .removeAttr('value')
            .text('');
        $('.account-type').text('');
        $('.login-id-list')
            .children()
            .remove();
    } else {
        loginButton.hide();
        accountList.show();

        const activeToken = getActiveToken(tokenList, getStorage(AppConstants.STORAGE_ACTIVE_TOKEN));
        addBalanceForToken(activeToken.token);
        if (!('loginInfo' in activeToken)) {
            removeAllTokens();
            updateTokenList();
        }
        tokenList.forEach(tokenInfo => {
            const prefix = isVirtual(tokenInfo) ? 'Virtual Account' : `${tokenInfo.loginInfo.currency} Account`;

            if (tokenInfo === activeToken) {
                $('.account-id')
                    .attr('value', `${tokenInfo.token}`)
                    .text(`${tokenInfo.accountName}`);
                $('.account-type').text(`${prefix}`);
            } else {
                $('.login-id-list').append(
                    `
${prefix}
${
                        tokenInfo.accountName
                    }

`
                );
            }
        });
    }
};

const applyToolboxPermissions = () => {
    if (getTokenList().length) {
        $('#runButton').show();
        $('#showSummary').show();
        $('#logButton').show();
    } else {
        $('#runButton').hide();
        $('#showSummary').hide();
        $('#logButton').hide();
    }
};

const showReloadPopup = () =>
    new Promise((resolve, reject) => {
        setBeforeUnload(true);
        $('#reloadPanel').dialog({
            height : 'auto',
            width  : 400,
            modal  : true,
            buttons: [
                {
                    text : 'No',
                    class: 'button-primary',
                    click() {
                        $(this).dialog('close');
                        reject();
                    },
                },
                {
                    text : 'Yes',
                    class: 'button-primary',
                    click() {
                        $(this).dialog('close');
                        resolve();
                    },
                },
            ],
        });
        $('#reloadPanel').dialog('open');
    });

export default class View {
    constructor() {
        logHandler();
        this.initPromise = new Promise(resolve => {
            updateConfigCurrencies().then(() => {
                symbolPromise.then(() => {
                    updateTokenList();
                    this.blockly = new _Blockly();
                    this.blockly.initPromise.then(() => {
                        this.setElementActions();
                        initRealityCheck();
                        applyToolboxPermissions();
                        renderReactComponents();
                        resolve();
                    });
                });
            });
        });
    }

    setFileBrowser() {
        const readFile = (f, dropEvent = {}) => {
            const reader = new FileReader();
            reader.onload = e => this.blockly.load(e.target.result, dropEvent);
            reader.readAsText(f);
        };

        const handleFileSelect = e => {
            let files;
            let dropEvent;
            if (e.type === 'drop') {
                e.stopPropagation();
                e.preventDefault();
                ({ files } = e.dataTransfer);
                dropEvent = e;
            } else {
                ({ files } = e.target);
            }
            files = Array.from(files);
            files.forEach(file => {
                if (file.type.match('text/xml')) {
                    readFile(file, dropEvent);
                } else {
                    globalObserver.emit('ui.log.info', `${translate('File is not supported:')} ${file.name}`);
                }
            });
        };

        const handleDragOver = e => {
            e.stopPropagation();
            e.preventDefault();
            e.dataTransfer.dropEffect = 'copy'; // eslint-disable-line no-param-reassign
        };

        const dropZone = document.body;

        dropZone.addEventListener('dragover', handleDragOver, false);
        dropZone.addEventListener('drop', handleFileSelect, false);

        $('#files').on('change', handleFileSelect);

        $('#open_btn')
            .on('click', () => {
                $.FileDialog({
                    // eslint-disable-line new-cap
                    accept       : '.xml',
                    cancelButton : 'Close',
                    dragMessage  : 'Drop files here',
                    dropheight   : 400,
                    errorMessage : 'An error occured while loading file',
                    multiple     : false,
                    okButton     : 'OK',
                    readAs       : 'DataURL',
                    removeMessage: 'Remove file',
                    title        : 'Load file',
                });
            })
            .on('files.bs.filedialog', ev => {
                handleFileSelect(ev.files);
            })
            .on('cancel.bs.filedialog', ev => {
                handleFileSelect(ev);
            });
    }
    setElementActions() {
        this.setFileBrowser();
        this.addBindings();
        this.addEventHandlers();
    }
    addBindings() {
        const stop = e => {
            if (e) {
                e.preventDefault();
            }
            stopRealityCheck();
            this.stop();
        };

        const logout = () => {
            showReloadPopup()
                .then(() => {
                    logoutAllTokens().then(() => {
                        updateTokenList();
                        globalObserver.emit('ui.log.info', translate('Logged you out!'));
                        clearRealityCheck();
                        clearActiveTokens();
                        location.reload();
                    });
                })
                .catch(() => {});
        };

        const clearActiveTokens = () => {
            setStorage(AppConstants.STORAGE_ACTIVE_TOKEN, '');
        };

        $('.panelExitButton').click(function onClick() {
            $(this)
                .parent()
                .hide();
        });

        $('.draggable-dialog')
            .hide()
            .dialog({
                resizable: false,
                autoOpen : false,
                width    : Math.min(document.body.offsetWidth, 700),
                height   : Math.min(document.body.offsetHeight, 600),
                closeText: '',
                classes  : { 'ui-dialog-titlebar-close': 'icon-close' },
            });

        $('#save-xml').click(() => saveDialog.save().then(arg => this.blockly.save(arg)));

        $('#undo').click(() => {
            this.blockly.undo();
        });

        $('#redo').click(() => {
            this.blockly.redo();
        });

        $('#zoomIn').click(() => {
            this.blockly.zoomOnPlusMinus(true);
        });

        $('#zoomOut').click(() => {
            this.blockly.zoomOnPlusMinus(false);
        });

        $('#rearrange').click(() => {
            this.blockly.cleanUp();
        });

        $('#chartButton').click(() => {
            chart.open();
        });

        $('#tradingViewButton').click(() => {
            tradingView.open();
        });
        const exportContent = {};
        exportContent.summaryPanel = () => {
            globalObserver.emit('summary.export');
        };
        exportContent.logPanel = () => {
            globalObserver.emit('log.export');
        };
        const addExportButtonToPanel = panelId => {
            const buttonHtml =
                '<button class="icon-save" style="position:absolute;top:50%;margin:-10px 0 0 0;right:2em;padding:0.2em"></button>';
            const $button = $(buttonHtml);
            const panelSelector = `[aria-describedby="${panelId}"]`;
            if (!$(`${panelSelector} .icon-save`).length) {
                $button.insertBefore(`${panelSelector} .icon-close`);
                $(`${panelSelector} .icon-close`).blur();
                $($(`${panelSelector} .icon-save`)).click(() => {
                    exportContent[panelId]();
                });
            }
        };
        const showSummary = () => {
            $('#summaryPanel').dialog('open');
            addExportButtonToPanel('summaryPanel');
        };
        const showLog = () => {
            $('#logPanel').dialog('open');
            addExportButtonToPanel('logPanel');
        };

        $('#logButton').click(showLog);

        $('#showSummary').click(showSummary);

        $('#loadXml').click(() => {
            $('#files').click();
        });

        $('#logout, #logout-reality-check').click(() => {
            logout();
            hideRealityCheck();
        });

        const submitRealityCheck = () => {
            const time = parseInt($('#realityDuration').val());
            if (time >= 10 && time <= 60) {
                hideRealityCheck();
                startRealityCheck(time);
            } else {
                $('#rc-err').show();
            }
        };

        $('#continue-trading').click(() => {
            submitRealityCheck();
        });

        $('#realityDuration').keypress(e => {
            const char = String.fromCharCode(e.which);
            if (e.keyCode === 13) {
                submitRealityCheck();
            }
            /* Unicode check is for firefox because it
             * trigger this event when backspace, arrow keys are pressed
             * in chrome it is not triggered
             */
            const unicodeStrings = /[\u0008|\u0000]/;
            if (unicodeStrings.test(char)) return;

            if (!/([0-9])/.test(char)) {
                e.preventDefault();
            }
        });

        const startBot = limitations => {
            $('#stopButton').show();
            $('#runButton').hide();
            showSummary();
            this.blockly.run(limitations);
        };

        $('#runButton').click(() => {
            const token = $('.account-id')
                .first()
                .attr('value');
            const tokenObj = getToken(token);
            if (tokenObj && tokenObj.hasTradeLimitation) {
                limits.getLimits().then(startBot);
            } else {
                startBot();
            }
        });

        $('#stopButton')
            .click(e => stop(e))
            .hide();

        $('#resetButton').click(() => {
            this.blockly.resetWorkspace();
            setTimeout(() => this.blockly.cleanUp(), 0);
        });

        $('.login-id-list').on('click', 'a', e => {
            showReloadPopup()
                .then(() => {
                    setStorage(AppConstants.STORAGE_ACTIVE_TOKEN, $(e.currentTarget).attr('value'));
                    location.reload();
                })
                .catch(() => {});
        });

        $('#login')
            .bind('click.login', () => {
                document.location = getOAuthURL();
            })
            .text('Log in');

        $('#statement-reality-check').click(() => {
            document.location = `https://www.binary.com/${getLanguage()}/user/statementws.html#no-reality-check`;
        });
        $(document).keydown(e => {
            if (e.which === 189) {
                // Ctrl + -
                if (e.ctrlKey) {
                    this.blockly.zoomOnPlusMinus(false);
                    e.preventDefault();
                }
            } else if (e.which === 187) {
                // Ctrl + +
                if (e.ctrlKey) {
                    this.blockly.zoomOnPlusMinus(true);
                    e.preventDefault();
                }
            }
        });
    }
    stop() {
        this.blockly.stop();
    }
    addEventHandlers() {
        globalObserver.register('Error', error => {
            if (error.error && error.error.error.code === 'InvalidToken') {
                removeAllTokens();
                updateTokenList();
                this.stop();
            }
        });

        globalObserver.register('bot.info', info => {
            if ('profit' in info) {
                const token = $('.account-id')
                    .first()
                    .attr('value');
                const user = getToken(token);
                globalObserver.emit('log.revenue', {
                    user,
                    profit  : info.profit,
                    contract: info.contract,
                });
            }
        });
    }
}

function initRealityCheck() {
    startRealityCheck(
        null,
        $('.account-id')
            .first()
            .attr('value')
    );
}
function renderReactComponents() {
    ReactDOM.render(<Tour />, $('#tour')[0]);
    ReactDOM.render(
        <OfficialVersionWarning
            show={
                !(
                    typeof window.location !== 'undefined' &&
                    window.location.host === 'bot.binary.com' &&
                    window.location.pathname === '/bot.html'
                )
            }
        />,
        $('#footer')[0]
    );
    ReactDOM.render(<TradeInfoPanel />, $('#summaryPanel')[0]);
    ReactDOM.render(<LogTable />, $('#logTable')[0]);
}
<commit_msg>Remove default style<commit_after>import React from 'react';
import ReactDOM from 'react-dom';
import { observer as globalObserver } from 'binary-common-utils/lib/observer';
import {
    getTokenList,
    removeAllTokens,
    get as getStorage,
    set as setStorage,
    getToken,
} from 'binary-common-utils/lib/storageManager';
import 'jquery-ui/ui/widgets/dialog';
import _Blockly from './blockly';
import { translate } from '../../common/i18n';
import Save from './Dialogs/Save';
import Limits from './Dialogs/Limits';
import Chart from './Dialogs/Chart';
import TradingView from './Dialogs/TradingView';
import { getLanguage } from '../../common/lang';
import { roundBalance, isVirtual } from '../common/tools';
import { symbolPromise } from './shared';
import logHandler from './logger';
import Tour from './tour';
import OfficialVersionWarning from './react-components/OfficialVersionWarning';
import LogTable from './LogTable';
import TradeInfoPanel from './TradeInfoPanel';
import { logoutAllTokens, getOAuthURL, generateLiveApiInstance, AppConstants } from '../../common/appId';
import { updateConfigCurrencies } from '../common/const';

let realityCheckTimeout;

const api = generateLiveApiInstance();

api.events.on('balance', response => {
    const { balance: { balance: b, currency } } = response;

    const balance = roundBalance({ currency, balance: b });
    $('.topMenuBalance').text(`${balance} ${currency}`);
});

const addBalanceForToken = token => {
    api.authorize(token).then(() => {
        api.send({ forget_all: 'balance' }).then(() => {
            api.subscribeToBalance();
        });
    });
};

const chart = new Chart();
const tradingView = new TradingView();

const setBeforeUnload = off => {
    if (off) {
        window.onbeforeunload = null;
    } else {
        window.onbeforeunload = () => 'You have some unsaved blocks, do you want to save them before you exit?';
    }
};

const showRealityCheck = () => {
    $('.blocker').show();
    $('.reality-check').show();
};

const hideRealityCheck = () => {
    $('#rc-err').hide();
    $('.blocker').hide();
    $('.reality-check').hide();
};

const stopRealityCheck = () => {
    clearInterval(realityCheckTimeout);
    realityCheckTimeout = null;
};

const realityCheckInterval = () => {
    realityCheckTimeout = setInterval(() => {
        const now = parseInt(new Date().getTime() / 1000);
        const checkTime = +getStorage('realityCheckTime');
        if (checkTime && now >= checkTime) {
            showRealityCheck();
            stopRealityCheck();
        }
    }, 1000);
};

const startRealityCheck = (time, token) => {
    stopRealityCheck();
    if (time) {
        const start = parseInt(new Date().getTime() / 1000) + time * 60;
        setStorage('realityCheckTime', start);
        realityCheckInterval();
    } else {
        const tokenObj = getToken(token);
        if (tokenObj.hasRealityCheck) {
            const checkTime = +getStorage('realityCheckTime');
            if (!checkTime) {
                showRealityCheck();
            } else {
                realityCheckInterval();
            }
        }
    }
};

const clearRealityCheck = () => {
    setStorage('realityCheckTime', null);
    stopRealityCheck();
};

const resetRealityCheck = token => {
    clearRealityCheck();
    startRealityCheck(null, token);
};

const limits = new Limits();
const saveDialog = new Save();
// const chart = new Chart();

const getActiveToken = (tokenList, activeToken) => {
    const activeTokenObject = tokenList.filter(tokenObject => tokenObject.token === activeToken);
    return activeTokenObject.length ? activeTokenObject[0] : tokenList[0];
};

const updateTokenList = () => {
    const tokenList = getTokenList();
    const loginButton = $('#login');
    const accountList = $('#account-list');
    if (tokenList.length === 0) {
        loginButton.show();
        accountList.hide();
        $('.account-id')
            .removeAttr('value')
            .text('');
        $('.account-type').text('');
        $('.login-id-list')
            .children()
            .remove();
    } else {
        loginButton.hide();
        accountList.show();

        const activeToken = getActiveToken(tokenList, getStorage(AppConstants.STORAGE_ACTIVE_TOKEN));
        addBalanceForToken(activeToken.token);
        if (!('loginInfo' in activeToken)) {
            removeAllTokens();
            updateTokenList();
        }
        tokenList.forEach(tokenInfo => {
            const prefix = isVirtual(tokenInfo) ? 'Virtual Account' : `${tokenInfo.loginInfo.currency} Account`;

            if (tokenInfo === activeToken) {
                $('.account-id')
                    .attr('value', `${tokenInfo.token}`)
                    .text(`${tokenInfo.accountName}`);
                $('.account-type').text(`${prefix}`);
            } else {
                $('.login-id-list').append(
                    `
${prefix}
${
                        tokenInfo.accountName
                    }

`
                );
            }
        });
    }
};

const applyToolboxPermissions = () => {
    if (getTokenList().length) {
        $('#runButton').show();
        $('#showSummary').show();
        $('#logButton').show();
    } else {
        $('#runButton').hide();
        $('#showSummary').hide();
        $('#logButton').hide();
    }
};

const showReloadPopup = () =>
    new Promise((resolve, reject) => {
        setBeforeUnload(true);
        $('#reloadPanel').dialog({
            height: 'auto',
            width : 400,
            modal : true,
            open() {
                $(this)
                    .parent()
                    .find('.ui-dialog-buttonset > button')
                    .removeClass('ui-button ui-corner-all ui-widget');
            },
            buttons: [
                {
                    text : 'No',
                    class: 'button-secondary',
                    click() {
                        $(this).dialog('close');
                        reject();
                    },
                },
                {
                    text : 'Yes',
                    class: 'button-primary',
                    click() {
                        $(this).dialog('close');
                        resolve();
                    },
                },
            ],
        });
        $('#reloadPanel').dialog('open');
    });

export default class View {
    constructor() {
        logHandler();
        this.initPromise = new Promise(resolve => {
            updateConfigCurrencies().then(() => {
                symbolPromise.then(() => {
                    updateTokenList();
                    this.blockly = new _Blockly();
                    this.blockly.initPromise.then(() => {
                        this.setElementActions();
                        initRealityCheck();
                        applyToolboxPermissions();
                        renderReactComponents();
                        resolve();
                    });
                });
            });
        });
    }

    setFileBrowser() {
        const readFile = (f, dropEvent = {}) => {
            const reader = new FileReader();
            reader.onload = e => this.blockly.load(e.target.result, dropEvent);
            reader.readAsText(f);
        };

        const handleFileSelect = e => {
            let files;
            let dropEvent;
            if (e.type === 'drop') {
                e.stopPropagation();
                e.preventDefault();
                ({ files } = e.dataTransfer);
                dropEvent = e;
            } else {
                ({ files } = e.target);
            }
            files = Array.from(files);
            files.forEach(file => {
                if (file.type.match('text/xml')) {
                    readFile(file, dropEvent);
                } else {
                    globalObserver.emit('ui.log.info', `${translate('File is not supported:')} ${file.name}`);
                }
            });
        };

        const handleDragOver = e => {
            e.stopPropagation();
            e.preventDefault();
            e.dataTransfer.dropEffect = 'copy'; // eslint-disable-line no-param-reassign
        };

        const dropZone = document.body;

        dropZone.addEventListener('dragover', handleDragOver, false);
        dropZone.addEventListener('drop', handleFileSelect, false);

        $('#files').on('change', handleFileSelect);

        $('#open_btn')
            .on('click', () => {
                $.FileDialog({
                    // eslint-disable-line new-cap
                    accept       : '.xml',
                    cancelButton : 'Close',
                    dragMessage  : 'Drop files here',
                    dropheight   : 400,
                    errorMessage : 'An error occured while loading file',
                    multiple     : false,
                    okButton     : 'OK',
                    readAs       : 'DataURL',
                    removeMessage: 'Remove file',
                    title        : 'Load file',
                });
            })
            .on('files.bs.filedialog', ev => {
                handleFileSelect(ev.files);
            })
            .on('cancel.bs.filedialog', ev => {
                handleFileSelect(ev);
            });
    }
    setElementActions() {
        this.setFileBrowser();
        this.addBindings();
        this.addEventHandlers();
    }
    addBindings() {
        const stop = e => {
            if (e) {
                e.preventDefault();
            }
            stopRealityCheck();
            this.stop();
        };

        const logout = () => {
            showReloadPopup()
                .then(() => {
                    logoutAllTokens().then(() => {
                        updateTokenList();
                        globalObserver.emit('ui.log.info', translate('Logged you out!'));
                        clearRealityCheck();
                        clearActiveTokens();
                        location.reload();
                    });
                })
                .catch(() => {});
        };

        const clearActiveTokens = () => {
            setStorage(AppConstants.STORAGE_ACTIVE_TOKEN, '');
        };

        $('.panelExitButton').click(function onClick() {
            $(this)
                .parent()
                .hide();
        });

        $('.draggable-dialog')
            .hide()
            .dialog({
                resizable: false,
                autoOpen : false,
                width    : Math.min(document.body.offsetWidth, 700),
                height   : Math.min(document.body.offsetHeight, 600),
                closeText: '',
                classes  : { 'ui-dialog-titlebar-close': 'icon-close' },
            });

        $('#save-xml').click(() => saveDialog.save().then(arg => this.blockly.save(arg)));

        $('#undo').click(() => {
            this.blockly.undo();
        });

        $('#redo').click(() => {
            this.blockly.redo();
        });

        $('#zoomIn').click(() => {
            this.blockly.zoomOnPlusMinus(true);
        });

        $('#zoomOut').click(() => {
            this.blockly.zoomOnPlusMinus(false);
        });

        $('#rearrange').click(() => {
            this.blockly.cleanUp();
        });

        $('#chartButton').click(() => {
            chart.open();
        });

        $('#tradingViewButton').click(() => {
            tradingView.open();
        });
        const exportContent = {};
        exportContent.summaryPanel = () => {
            globalObserver.emit('summary.export');
        };
        exportContent.logPanel = () => {
            globalObserver.emit('log.export');
        };
        const addExportButtonToPanel = panelId => {
            const buttonHtml =
                '<button class="icon-save" style="position:absolute;top:50%;margin:-10px 0 0 0;right:2em;padding:0.2em"></button>';
            const $button = $(buttonHtml);
            const panelSelector = `[aria-describedby="${panelId}"]`;
            if (!$(`${panelSelector} .icon-save`).length) {
                $button.insertBefore(`${panelSelector} .icon-close`);
                $(`${panelSelector} .icon-close`).blur();
                $($(`${panelSelector} .icon-save`)).click(() => {
                    exportContent[panelId]();
                });
            }
        };
        const showSummary = () => {
            $('#summaryPanel').dialog('open');
            addExportButtonToPanel('summaryPanel');
        };
        const showLog = () => {
            $('#logPanel').dialog('open');
            addExportButtonToPanel('logPanel');
        };

        $('#logButton').click(showLog);

        $('#showSummary').click(showSummary);

        $('#loadXml').click(() => {
            $('#files').click();
        });

        $('#logout, #logout-reality-check').click(() => {
            logout();
            hideRealityCheck();
        });

        const submitRealityCheck = () => {
            const time = parseInt($('#realityDuration').val());
            if (time >= 10 && time <= 60) {
                hideRealityCheck();
                startRealityCheck(time);
            } else {
                $('#rc-err').show();
            }
        };

        $('#continue-trading').click(() => {
            submitRealityCheck();
        });

        $('#realityDuration').keypress(e => {
            const char = String.fromCharCode(e.which);
            if (e.keyCode === 13) {
                submitRealityCheck();
            }
            /* Unicode check is for firefox because it
             * trigger this event when backspace, arrow keys are pressed
             * in chrome it is not triggered
             */
            const unicodeStrings = /[\u0008|\u0000]/;
            if (unicodeStrings.test(char)) return;

            if (!/([0-9])/.test(char)) {
                e.preventDefault();
            }
        });

        const startBot = limitations => {
            $('#stopButton').show();
            $('#runButton').hide();
            showSummary();
            this.blockly.run(limitations);
        };

        $('#runButton').click(() => {
            const token = $('.account-id')
                .first()
                .attr('value');
            const tokenObj = getToken(token);
            if (tokenObj && tokenObj.hasTradeLimitation) {
                limits.getLimits().then(startBot);
            } else {
                startBot();
            }
        });

        $('#stopButton')
            .click(e => stop(e))
            .hide();

        $('#resetButton').click(() => {
            this.blockly.resetWorkspace();
            setTimeout(() => this.blockly.cleanUp(), 0);
        });

        $('.login-id-list').on('click', 'a', e => {
            showReloadPopup()
                .then(() => {
                    setStorage(AppConstants.STORAGE_ACTIVE_TOKEN, $(e.currentTarget).attr('value'));
                    location.reload();
                })
                .catch(() => {});
        });

        $('#login')
            .bind('click.login', () => {
                document.location = getOAuthURL();
            })
            .text('Log in');

        $('#statement-reality-check').click(() => {
            document.location = `https://www.binary.com/${getLanguage()}/user/statementws.html#no-reality-check`;
        });
        $(document).keydown(e => {
            if (e.which === 189) {
                // Ctrl + -
                if (e.ctrlKey) {
                    this.blockly.zoomOnPlusMinus(false);
                    e.preventDefault();
                }
            } else if (e.which === 187) {
                // Ctrl + +
                if (e.ctrlKey) {
                    this.blockly.zoomOnPlusMinus(true);
                    e.preventDefault();
                }
            }
        });
    }
    stop() {
        this.blockly.stop();
    }
    addEventHandlers() {
        globalObserver.register('Error', error => {
            if (error.error && error.error.error.code === 'InvalidToken') {
                removeAllTokens();
                updateTokenList();
                this.stop();
            }
        });

        globalObserver.register('bot.info', info => {
            if ('profit' in info) {
                const token = $('.account-id')
                    .first()
                    .attr('value');
                const user = getToken(token);
                globalObserver.emit('log.revenue', {
                    user,
                    profit  : info.profit,
                    contract: info.contract,
                });
            }
        });
    }
}

function initRealityCheck() {
    startRealityCheck(
        null,
        $('.account-id')
            .first()
            .attr('value')
    );
}
function renderReactComponents() {
    ReactDOM.render(<Tour />, $('#tour')[0]);
    ReactDOM.render(
        <OfficialVersionWarning
            show={
                !(
                    typeof window.location !== 'undefined' &&
                    window.location.host === 'bot.binary.com' &&
                    window.location.pathname === '/bot.html'
                )
            }
        />,
        $('#footer')[0]
    );
    ReactDOM.render(<TradeInfoPanel />, $('#summaryPanel')[0]);
    ReactDOM.render(<LogTable />, $('#logTable')[0]);
}
<|endoftext|>


<commit_before>process.env.NODE_ENV = 'test';

var _ = require('underscore');
var assert = require('chai').expect;
var expect = require('chai').expect;
var mongoose = require('mongoose');
var path = require('path');
var request = require('supertest');

var db = require(path.join(__dirname, '../../db/db'));
var server = require(path.join(__dirname, '../../app/server/server'));
var testUtil = require(path.join(__dirname, '../testUtil'));
// Models
var Group = require(path.join(__dirname, '../../app/server/models/group'));
var User = require(path.join(__dirname, '../../app/server/models/user'));
var Venue = require(path.join(__dirname, '../../app/server/models/venue'));

describe('server controllers', function () {
  var newHotelInfo, greenwichHotel, greenwichHotelInfo, group, testGroupDestination,
      testGroupDestination2, testGroupName,
      testUser, testUser2;

  before(function (done) {
    // TravisCI has been timing out at the default 2000
    this.timeout(5000);

    newHotelInfo = {
      "id": "2",
      "venue_type_id": 1,
      "name": "Crosby Street Hotel",
      "tripexpert_score": 98,
      "rank_in_destination": 2,
      "score": 98,
      "description": "Opened in SoHo in 2009, this Kit Kemp–designed 11-story brownstone has floor-to-ceiling windows throughout and is environmentally certified as an LEED Gold property.",
      "index_photo": "http://static.tripexpert.com/images/venues/index_photos/index_retina/636532.jpg"
    };
    greenwichHotelInfo = {
      "id": "1",
      "venue_type_id": 1,
      "name": "Greenwich Hotel",
      "tripexpert_score": 99,
      "rank_in_destination": 1,
      "score": 99,
      "description": "Robert DeNiro and partners spared nothing in their luxurious eight-story hotel, which opened in 2008.",
      "index_photo": "http://static.tripexpert.com/images/venues/index_photos/index_retina/637972.jpg"
    };
    request = request(server);
    nycId = 6;
    testGroupDestination2 = 'portland';
    testGroupName = 'test group';

    // TODO Refactor how how con is set?
    con = mongoose.createConnection('mongodb://localhost/tripapptest');
    // con = mongoose.connection;

    // TODO Refactor to use promise
    setTimeout(function () {
      testUtil.dropDb(con, done);
    }, 1000); // on @ZacharyRSmith's machine, connection needs ~15ms to set up
  });

  beforeEach(function (done) {
    testUtil.dropDb(con, function () {

      User.create({ username: 'test user' }, function (err, user) {
        if (err) console.error(err);

        testUser = user;

        User.create({ username: 'test user 2'}, function (err, user2) {
          if (err) console.error(err);

          testUser2 = user2;

          Venue.create({
            lookUpId: greenwichHotelInfo.id,
            name: greenwichHotelInfo.name,
            venue_type_id: greenwichHotelInfo.venue_type_id,
            tripexpert_score: greenwichHotelInfo.tripexpert_score,
            rank: greenwichHotelInfo.rank_in_destination,
            score: greenwichHotelInfo.score,
            description: greenwichHotelInfo.description,
            photo: greenwichHotelInfo.index_photo
          }, function (err, greenwichHotel) {
            if (err) console.error(err);

            greenwichHotel = greenwichHotel;

            request
              .post('/api/group')
              .send({
                groupName: testGroupName,
                destId: nycId,
                userId: testUser._id,
              })
              .end(function (err, res) {

                group = res.body;
                done();
              });
          });
        });
      });
    });
  });

  after(function (done) {
    testUtil.dropDb(con, function () {
      con.close(done);
    });
  });

  afterEach(function (done) {
    testUtil.dropDb(con, done);
  });

  describe('destController', function () {

    describe('getDestinations()', function () {

      it('defaults to returning 100 destinations', function (done) {
        request
          .get('/api/dest/')
          .expect(200)
          .end(function (err, res) {
            if (err) return done(err);

            expect(res.body.destinations.length).to.equal(100);
            done();
          });
      });

      it('can get moar destinations', function (done) {
        request
          .get('/api/dest/')
          .query({ limit: 200 })
          .expect(200)
          .end(function (err, res) {
            if (err) return done(err);

            expect(res.body.destinations.length).to.equal(200);
            done();
          });
      });
    });
  });

  describe('groupController', function () {

    describe('addMember()', function () {

      it('does not re-add user to group and vice versa if already in group', function (done) {
        request
          .post('/api/group/add')
          .send({
            groupId: group._id,
            username: testUser.username
          })
          .end(function (err, res) {
            var updatedGroup = res.body;

            expect(updatedGroup.members.length).to.equal(1);
            done();
          });
      });

      it('adds user to group and vice versa if not already in group', function (done) {
        request
          .post('/api/group/add')
          .send({
            groupId: group._id,
            username: testUser2.username
          })
          .end(function (err, res) {
            var updatedGroup = res.body;

            expect(updatedGroup.members.length).to.equal(2);
            done();
          });
      });
    });

    describe('createGroup()', function () {

      it('should err when provided with invalid userId', function (done) {
        request
          .post('/api/group')
          .send({
            groupName: 'new group name',
            destination: 'new group destination',
            userInfo: 'fakeUserId',
          })
          .expect(400, done);
      });

      it('should not create if no group destination is provided', function (done) {
        request
          .post('/api/group')
          .send({
            groupName: 'new group name',
            destination: '            ',
            userInfo: testUser._id,
          })
          .end(function (err, res) {
            expect(res.ok).to.be.false;
            done();
          });
      });

      it('should not create if no group title is provided', function (done) {
        request
          .post('/api/group')
          .send({
            groupName: '          ',
            destination: testGroupDestination,
            userInfo: testUser._id,
          })
          .end(function (err, res) {
            expect(res.ok).to.be.false;
            done();
          });
      });

      it('should set provided userId as group host', function () {
        expect(group.host._id).to.equal(testUser._id + '');
      });

      it('should set title and destination', function () {
        expect(group.title).to.equal(testGroupName);
        expect(group.destination).to.equal(testGroupDestination);
      });

      it('should add group\'s host to group.members', function () {
        expect(_.contains(group.members, testUser._id + ''));
      });

      it('should add the new group to the host\'s groupId', function (done) {
        // Update testUser
        User.findOne({ _id: testUser._id }, function (err, user) {
          expect(_.contains(user.groupIds, group._id));
          done();
        });
      });
    });

    describe('getInfo()', function () {

      beforeEach(function (done) {
        request
          .get('/api/group/all?groupId=' + group._id)
          .end(function (err, res) {
            group = res.body;
            done();
          });
      });

      it('returns a plain JS object', function () {
        expect(group.constructor).to.equal(Object);
      });

      // Need test favorites to check this
      xit('populates favorites', function () {
        expect(group.favorites[0].constructor).to.equal(Object);
      });

      // Need test favorites to check this
      xit('populates favorite\'s ratings', function () {
        // body...
      });

      it('populates members', function () {
        expect(group.members[0].constructor).to.equal(Object);
      });
    });

    describe('getMembers()', function () {

      beforeEach(function (done) {
        request
          .post('/api/group/add')
          .send({
            groupId: group._id,
            username: testUser2.username
          })
          .end(function (err, res) {
            var group = JSON.parse(res.text);
            done();
          });
      });

      it('returns members as JSON', function (done) {

        request
          .get('/api/group/users?groupId=' + group._id)
          .end(function (err, res) {
            var membersIds = res.body.map(function (member) {
              return member._id + '';
            });

            expect(membersIds.length).to.equal(2);
            expect(_.contains(membersIds, testUser._id + ''));
            expect(_.contains(membersIds, testUser2._id + ''));
            done();
          });
      });
    });

    describe('removeMember()', function () {

      beforeEach(function (done) {
        request
          .del('/api/group/user')
          .send({
            groupId: group._id,
            userId: testUser._id
          })
          .expect(200)
          .end(function (err, res) {

            // Update group
            Group.findById(group._id, function (err, _group_) {
              group = _group_;
              done();
            });
          });
      });

      it('removes user from group.members', function (done) {
        expect(group.members.length).to.equal(0);
        done();
      });

      it('removes group from user.groupIds', function (done) {
        User.findById(testUser._id, function (err, user) {
          var userHasGroup = user.groupIds.some(function (id) {
            return id.equals(group._id);
          });

          expect(userHasGroup).to.equal(false);
          done();
        });
      });
    });

    describe('setDestination()', function () {

      it('changes group\'s destination and returns updated group', function (done) {
        var parisId = 5;

        request
          .post('/api/group/set')
          .send({
            destination: parisId,
            groupId: group._id,
          })
          .expect(200)
          .end(function (err, res) {
            if (err) console.error(err);

            var actualDestination = res.body.destination;

            expect(actualDestination).to.equal(parisId);
            done();
          });
      });
    });
  });

  describe('indexController', function () {

    it('getInfo() returns user info', function (done) {
      request
        .get('/api/info')
        .query({
          userId: testUser._id + '' // cast BSON to str
        })
        .end(function (err, res) {
          expect(res.body.username).to.equal(testUser.username);
          done();
        });
    });
  });

  describe('ratingController', function () {

    describe('addRating()', function () {

      it('adds venue to user.favorites', function (done) {
        request
          .post('/api/rating/')
          .send({
            groupId: group._id,
            rating: 10,
            userId: testUser._id,
            venue: greenwichHotelInfo,
          })
          .end(function (err, res) {
            User.findById(testUser._id, function (err, user) {
              expect(user.favorites.length).to.equal(1);
              done();
            });
          });
      });

      it('creates venue if it does not exist, and adds it to user.favorites', function (done) {
        request
          .post('/api/rating/')
          .send({
            groupId: group._id,
            rating: 10,
            userId: testUser._id,
            venue: newHotelInfo,
          })
          .end(function (err, res) {
            Venue.count({ lookUpId: newHotelInfo.id }, function (err, c) {
              expect(c).to.equal(1);

              User.findById(testUser._id, function (err, user) {
                expect(user.favorites.length).to.equal(1);
                done();
              });
            });
          });
      });

      it('just $set updates user\'s rating when it exists', function (done) {
        // add rating
        request
          .post('/api/rating/')
          .send({
            groupId: group._id,
            rating: 10,
            userId: testUser._id,
            venue: greenwichHotelInfo,
          })
          .end(function (err, res) {
            // update rating
            request
              .post('/api/rating/')
              .send({
                groupId: group._id,
                rating: 7,
                userId: testUser._id,
                venue: greenwichHotelInfo,
              })
              .end(function (err, res) {
                User.findById(testUser._id, function (err, user) {
                  // there should still be only 1 rating
                  expect(user.favorites.length).to.equal(1);
                  // rating val should be updated
                  expect(user.favorites[0].rating).to.equal(7);
                  done();
                });
              });
          });
      });

      it('creates group rating for venue when it does not exist', function (done) {
        request
          .post('/api/rating/')
          .send({
            groupId: group._id,
            rating: 10,
            userId: testUser._id,
            venue: greenwichHotelInfo,
          })
          .end(function (err, res) {
            Group.findById(group._id, function (err, group) {
              // A rating should've been added by last request
              expect(group.favorites.length).to.equal(1);

              request
                .post('/api/rating/')
                .send({
                  groupId: group._id,
                  rating: 7,
                  userId: testUser._id,
                  venue: greenwichHotelInfo,
                })
                .end(function (err, res) {
                  Group.findById(group._id, function (err, group) {
                    // No rating should've been added by last request
                    expect(group.favorites.length).to.equal(1);
                    done();
                  });
                });
            });
          });
      });

      it('adds user rating to group\'s ratings', function (done) {
        request
          .post('/api/rating/')
          .send({
            groupId: group._id,
            rating: 10,
            userId: testUser._id,
            venue: greenwichHotelInfo,
          })
          .end(function (err, res) {
            Group.findById(group._id)
              .populate({
                path: 'favorites',
                populate: { path: 'venue' }
              })
              .exec(function (err, group) {
                var groupVenueRatings = group.favorites[0];
                var userRating = groupVenueRatings.allRatings[0].userRating;

                expect(userRating).to.equal(10);
                done();
              });
          });
      });

      it('returns group.favorites, populated', function (done) {
        request
          .post('/api/rating/')
          .send({
            groupId: group._id,
            rating: 10,
            userId: testUser._id,
            venue: greenwichHotelInfo,
          })
          .end(function (err, res) {
            var favorites = res.body;
            var groupVenueRatings = favorites[0];
            var userRating = groupVenueRatings.allRatings[0].userRating;

            expect(userRating).to.equal(10);
            done();
          });
      });

      it('just $set updates group\'s ratings when the user already rated it', function (done) {
        // add rating
        request
          .post('/api/rating/')
          .send({
            groupId: group._id,
            rating: 10,
            userId: testUser._id,
            venue: greenwichHotelInfo,
          })
          .end(function (err, res) {
            // update rating
            request
              .post('/api/rating/')
              .send({
                groupId: group._id,
                rating: 7,
                userId: testUser._id,
                venue: greenwichHotelInfo,
              })
              .end(function (err, res) {
                var favorites = res.body;
                var groupVenueRatings = favorites[0];

                // Last request should not have added another rating
                expect(groupVenueRatings.allRatings.length).to.equal(1);

                var userRating = groupVenueRatings.allRatings[0].userRating;

                // userRating should've been updated by last request
                expect(userRating).to.equal(7);
                done();
              });
          });
      });
    });
  });
});
<commit_msg>(test) Test indexController#isLoggedIn when not authenticated<commit_after>process.env.NODE_ENV = 'test';

var _ = require('underscore');
var assert = require('chai').expect;
var expect = require('chai').expect;
var mongoose = require('mongoose');
var path = require('path');
var request = require('supertest');

var db = require(path.join(__dirname, '../../db/db'));
var server = require(path.join(__dirname, '../../app/server/server'));
var testUtil = require(path.join(__dirname, '../testUtil'));
// Models
var Group = require(path.join(__dirname, '../../app/server/models/group'));
var User = require(path.join(__dirname, '../../app/server/models/user'));
var Venue = require(path.join(__dirname, '../../app/server/models/venue'));

describe('server controllers', function () {
  var newHotelInfo, greenwichHotel, greenwichHotelInfo, group, testGroupDestination,
      testGroupDestination2, testGroupName,
      testUser, testUser2;

  before(function (done) {
    // TravisCI has been timing out at the default 2000
    this.timeout(5000);

    newHotelInfo = {
      "id": "2",
      "venue_type_id": 1,
      "name": "Crosby Street Hotel",
      "tripexpert_score": 98,
      "rank_in_destination": 2,
      "score": 98,
      "description": "Opened in SoHo in 2009, this Kit Kemp–designed 11-story brownstone has floor-to-ceiling windows throughout and is environmentally certified as an LEED Gold property.",
      "index_photo": "http://static.tripexpert.com/images/venues/index_photos/index_retina/636532.jpg"
    };
    greenwichHotelInfo = {
      "id": "1",
      "venue_type_id": 1,
      "name": "Greenwich Hotel",
      "tripexpert_score": 99,
      "rank_in_destination": 1,
      "score": 99,
      "description": "Robert DeNiro and partners spared nothing in their luxurious eight-story hotel, which opened in 2008.",
      "index_photo": "http://static.tripexpert.com/images/venues/index_photos/index_retina/637972.jpg"
    };
    request = request(server);
    nycId = 6;
    testGroupDestination2 = 'portland';
    testGroupName = 'test group';

    // TODO Refactor how how con is set?
    con = mongoose.createConnection('mongodb://localhost/tripapptest');
    // con = mongoose.connection;

    // TODO Refactor to use promise
    setTimeout(function () {
      testUtil.dropDb(con, done);
    }, 1000); // on @ZacharyRSmith's machine, connection needs ~15ms to set up
  });

  beforeEach(function (done) {
    testUtil.dropDb(con, function () {

      User.create({ username: 'test user' }, function (err, user) {
        if (err) console.error(err);

        testUser = user;

        User.create({ username: 'test user 2'}, function (err, user2) {
          if (err) console.error(err);

          testUser2 = user2;

          Venue.create({
            lookUpId: greenwichHotelInfo.id,
            name: greenwichHotelInfo.name,
            venue_type_id: greenwichHotelInfo.venue_type_id,
            tripexpert_score: greenwichHotelInfo.tripexpert_score,
            rank: greenwichHotelInfo.rank_in_destination,
            score: greenwichHotelInfo.score,
            description: greenwichHotelInfo.description,
            photo: greenwichHotelInfo.index_photo
          }, function (err, greenwichHotel) {
            if (err) console.error(err);

            greenwichHotel = greenwichHotel;

            request
              .post('/api/group')
              .send({
                groupName: testGroupName,
                destId: nycId,
                userId: testUser._id,
              })
              .end(function (err, res) {

                group = res.body;
                done();
              });
          });
        });
      });
    });
  });

  after(function (done) {
    testUtil.dropDb(con, function () {
      con.close(done);
    });
  });

  afterEach(function (done) {
    testUtil.dropDb(con, done);
  });

  describe('destController', function () {

    describe('getDestinations()', function () {

      it('defaults to returning 100 destinations', function (done) {
        request
          .get('/api/dest/')
          .expect(200)
          .end(function (err, res) {
            if (err) return done(err);

            expect(res.body.destinations.length).to.equal(100);
            done();
          });
      });

      it('can get moar destinations', function (done) {
        request
          .get('/api/dest/')
          .query({ limit: 200 })
          .expect(200)
          .end(function (err, res) {
            if (err) return done(err);

            expect(res.body.destinations.length).to.equal(200);
            done();
          });
      });
    });
  });

  describe('groupController', function () {

    describe('addMember()', function () {

      it('does not re-add user to group and vice versa if already in group', function (done) {
        request
          .post('/api/group/add')
          .send({
            groupId: group._id,
            username: testUser.username
          })
          .end(function (err, res) {
            var updatedGroup = res.body;

            expect(updatedGroup.members.length).to.equal(1);
            done();
          });
      });

      it('adds user to group and vice versa if not already in group', function (done) {
        request
          .post('/api/group/add')
          .send({
            groupId: group._id,
            username: testUser2.username
          })
          .end(function (err, res) {
            var updatedGroup = res.body;

            expect(updatedGroup.members.length).to.equal(2);
            done();
          });
      });
    });

    describe('createGroup()', function () {

      it('should err when provided with invalid userId', function (done) {
        request
          .post('/api/group')
          .send({
            groupName: 'new group name',
            destination: 'new group destination',
            userInfo: 'fakeUserId',
          })
          .expect(400, done);
      });

      it('should not create if no group destination is provided', function (done) {
        request
          .post('/api/group')
          .send({
            groupName: 'new group name',
            destination: '            ',
            userInfo: testUser._id,
          })
          .end(function (err, res) {
            expect(res.ok).to.be.false;
            done();
          });
      });

      it('should not create if no group title is provided', function (done) {
        request
          .post('/api/group')
          .send({
            groupName: '          ',
            destination: testGroupDestination,
            userInfo: testUser._id,
          })
          .end(function (err, res) {
            expect(res.ok).to.be.false;
            done();
          });
      });

      it('should set provided userId as group host', function () {
        expect(group.host._id).to.equal(testUser._id + '');
      });

      it('should set title and destination', function () {
        expect(group.title).to.equal(testGroupName);
        expect(group.destination).to.equal(testGroupDestination);
      });

      it('should add group\'s host to group.members', function () {
        expect(_.contains(group.members, testUser._id + ''));
      });

      it('should add the new group to the host\'s groupId', function (done) {
        // Update testUser
        User.findOne({ _id: testUser._id }, function (err, user) {
          expect(_.contains(user.groupIds, group._id));
          done();
        });
      });
    });

    describe('getInfo()', function () {

      beforeEach(function (done) {
        request
          .get('/api/group/all?groupId=' + group._id)
          .end(function (err, res) {
            group = res.body;
            done();
          });
      });

      it('returns a plain JS object', function () {
        expect(group.constructor).to.equal(Object);
      });

      // Need test favorites to check this
      xit('populates favorites', function () {
        expect(group.favorites[0].constructor).to.equal(Object);
      });

      // Need test favorites to check this
      xit('populates favorite\'s ratings', function () {
        // body...
      });

      it('populates members', function () {
        expect(group.members[0].constructor).to.equal(Object);
      });
    });

    describe('getMembers()', function () {

      beforeEach(function (done) {
        request
          .post('/api/group/add')
          .send({
            groupId: group._id,
            username: testUser2.username
          })
          .end(function (err, res) {
            var group = JSON.parse(res.text);
            done();
          });
      });

      it('returns members as JSON', function (done) {

        request
          .get('/api/group/users?groupId=' + group._id)
          .end(function (err, res) {
            var membersIds = res.body.map(function (member) {
              return member._id + '';
            });

            expect(membersIds.length).to.equal(2);
            expect(_.contains(membersIds, testUser._id + ''));
            expect(_.contains(membersIds, testUser2._id + ''));
            done();
          });
      });
    });

    describe('removeMember()', function () {

      beforeEach(function (done) {
        request
          .del('/api/group/user')
          .send({
            groupId: group._id,
            userId: testUser._id
          })
          .expect(200)
          .end(function (err, res) {

            // Update group
            Group.findById(group._id, function (err, _group_) {
              group = _group_;
              done();
            });
          });
      });

      it('removes user from group.members', function (done) {
        expect(group.members.length).to.equal(0);
        done();
      });

      it('removes group from user.groupIds', function (done) {
        User.findById(testUser._id, function (err, user) {
          var userHasGroup = user.groupIds.some(function (id) {
            return id.equals(group._id);
          });

          expect(userHasGroup).to.equal(false);
          done();
        });
      });
    });

    describe('setDestination()', function () {

      it('changes group\'s destination and returns updated group', function (done) {
        var parisId = 5;

        request
          .post('/api/group/set')
          .send({
            destination: parisId,
            groupId: group._id,
          })
          .expect(200)
          .end(function (err, res) {
            if (err) console.error(err);

            var actualDestination = res.body.destination;

            expect(actualDestination).to.equal(parisId);
            done();
          });
      });
    });
  });

  describe('indexController', function () {

    it('getInfo() returns user info', function (done) {
      request
        .get('/api/info')
        .query({
          userId: testUser._id + '' // cast BSON to str
        })
        .end(function (err, res) {
          expect(res.body.username).to.equal(testUser.username);
          done();
        });
    });

    it('isLoggedIn() responds with false if !req.isAuthenticated', function (done) {
      request
        .get('/api/check') // indexController#isLoggedIn
        .end(function (err, res) {
          expect(res.body.status).to.equal(false);
          done();
        });
    });
  });

  describe('ratingController', function () {

    describe('addRating()', function () {

      it('adds venue to user.favorites', function (done) {
        request
          .post('/api/rating/')
          .send({
            groupId: group._id,
            rating: 10,
            userId: testUser._id,
            venue: greenwichHotelInfo,
          })
          .end(function (err, res) {
            User.findById(testUser._id, function (err, user) {
              expect(user.favorites.length).to.equal(1);
              done();
            });
          });
      });

      it('creates venue if it does not exist, and adds it to user.favorites', function (done) {
        request
          .post('/api/rating/')
          .send({
            groupId: group._id,
            rating: 10,
            userId: testUser._id,
            venue: newHotelInfo,
          })
          .end(function (err, res) {
            Venue.count({ lookUpId: newHotelInfo.id }, function (err, c) {
              expect(c).to.equal(1);

              User.findById(testUser._id, function (err, user) {
                expect(user.favorites.length).to.equal(1);
                done();
              });
            });
          });
      });

      it('just $set updates user\'s rating when it exists', function (done) {
        // add rating
        request
          .post('/api/rating/')
          .send({
            groupId: group._id,
            rating: 10,
            userId: testUser._id,
            venue: greenwichHotelInfo,
          })
          .end(function (err, res) {
            // update rating
            request
              .post('/api/rating/')
              .send({
                groupId: group._id,
                rating: 7,
                userId: testUser._id,
                venue: greenwichHotelInfo,
              })
              .end(function (err, res) {
                User.findById(testUser._id, function (err, user) {
                  // there should still be only 1 rating
                  expect(user.favorites.length).to.equal(1);
                  // rating val should be updated
                  expect(user.favorites[0].rating).to.equal(7);
                  done();
                });
              });
          });
      });

      it('creates group rating for venue when it does not exist', function (done) {
        request
          .post('/api/rating/')
          .send({
            groupId: group._id,
            rating: 10,
            userId: testUser._id,
            venue: greenwichHotelInfo,
          })
          .end(function (err, res) {
            Group.findById(group._id, function (err, group) {
              // A rating should've been added by last request
              expect(group.favorites.length).to.equal(1);

              request
                .post('/api/rating/')
                .send({
                  groupId: group._id,
                  rating: 7,
                  userId: testUser._id,
                  venue: greenwichHotelInfo,
                })
                .end(function (err, res) {
                  Group.findById(group._id, function (err, group) {
                    // No rating should've been added by last request
                    expect(group.favorites.length).to.equal(1);
                    done();
                  });
                });
            });
          });
      });

      it('adds user rating to group\'s ratings', function (done) {
        request
          .post('/api/rating/')
          .send({
            groupId: group._id,
            rating: 10,
            userId: testUser._id,
            venue: greenwichHotelInfo,
          })
          .end(function (err, res) {
            Group.findById(group._id)
              .populate({
                path: 'favorites',
                populate: { path: 'venue' }
              })
              .exec(function (err, group) {
                var groupVenueRatings = group.favorites[0];
                var userRating = groupVenueRatings.allRatings[0].userRating;

                expect(userRating).to.equal(10);
                done();
              });
          });
      });

      it('returns group.favorites, populated', function (done) {
        request
          .post('/api/rating/')
          .send({
            groupId: group._id,
            rating: 10,
            userId: testUser._id,
            venue: greenwichHotelInfo,
          })
          .end(function (err, res) {
            var favorites = res.body;
            var groupVenueRatings = favorites[0];
            var userRating = groupVenueRatings.allRatings[0].userRating;

            expect(userRating).to.equal(10);
            done();
          });
      });

      it('just $set updates group\'s ratings when the user already rated it', function (done) {
        // add rating
        request
          .post('/api/rating/')
          .send({
            groupId: group._id,
            rating: 10,
            userId: testUser._id,
            venue: greenwichHotelInfo,
          })
          .end(function (err, res) {
            // update rating
            request
              .post('/api/rating/')
              .send({
                groupId: group._id,
                rating: 7,
                userId: testUser._id,
                venue: greenwichHotelInfo,
              })
              .end(function (err, res) {
                var favorites = res.body;
                var groupVenueRatings = favorites[0];

                // Last request should not have added another rating
                expect(groupVenueRatings.allRatings.length).to.equal(1);

                var userRating = groupVenueRatings.allRatings[0].userRating;

                // userRating should've been updated by last request
                expect(userRating).to.equal(7);
                done();
              });
          });
      });
    });
  });
});
<|endoftext|>


<commit_before>/*
	parse.js
	Reads the incoming message and chooses the appropriate response.
	The "mouth" of Dank
*/

const login = require("facebook-chat-api");
const cool = require('cool-ascii-faces');
const http = require('http');
const Firebase = require("firebase");
const cows = require('cows');
const url = require('url');
const Client = require('node-rest-client').Client;
const predict = require('eightball');
const greetings = require('greetings');
const shake_insult = require('shakespeare-insult');
const emoji = require('node-emoji');

var db = new Firebase(process.env.DANK_SINATRA_FIREBASE);
var message_reqs = db.child("Requests");
var usersDB = db.child("users");
var chatsDB = db.child("chats");

// All commands go here
var choices = {
	help: /\\help/,

	greet: /\\howdy/,
	magic8: /\\magic8/,

	weather: /\\weather/,
	date: /\\date/,

	insult: /\\insult/,

	cool: /\\face/,
	cow: /\\cow/,
	blaze: /\\blaze/,

	senate: /\\senate/,

	type: /\\type/,

	love: /\\love/
};

/*
	TODO:
	1. Simulate conversation. Use IDs and DB
	2. Give a random greeting
	2. Magic 8 ball
*/
function parse(api, message){
	var response = '';

	// Add child for the threadID and append message there
	chatsDB.child(message.threadID).set(message);
	usersDB.child(message.senderID).set(message);

	// Send list of commands
	if (choices.help.test(message.body)){
		response = "Type '\\help' for a list of commands.\n";
		response += "\\howdy: Send a greeting.\n";
		response += "\\magic8 (yes/no question): Answer a yes/no question with complete accuracy.\n";
		response += "\\weather (ZIP code): Send the current weather in the given ZIP code.\n";
		response += "\\date: Send the current date.\n";
		response += "\\face: Send a cool ascii face.\n";
		response += "\\cow: Send an ascii cow.\n";
		response += "\\senate: Send a fact about the United States Senate.\n";
		response += "\\type: Send the 3 dots.";

		message_reqs.push(message);
		console.log("Sending " + response);
		api.sendMessage(response, message.threadID);
	}

	// Send a face
	else if (choices.cool.test(message.body)){
		response = cool();

		message_reqs.push(message);
		console.log("Sending " + response);
		api.sendMessage(response, message.threadID);
	}

	// Send the weather at a ZIP code
	else if (choices.weather.test(message.body)){
		var zip_code = message.body.replace(choices.weather,"");
		zip_code = zip_code.trim();
		console.log(zip_code);

		http.get('http://api.wunderground.com/api/'+process.env.WEATHER_API_KEY+'/conditions/q/' + zip_code + '.json',function(res){
			var body = '';
			var temp = '';
			var status = '';
			var city = '';

			res.on('data', function(chunk){
				body += chunk;
			});

			res.on('error', function(error){
				console.error(error.message);
				api.sendMessage("Invalid argument!",message.threadID);
			});

			res.on('end', function(){
				var weather_data = JSON.parse(body);
				console.log(weather_data);

				if (!weather_data.response.error){
					temp = weather_data.current_observation.temp_f;
					status = weather_data.current_observation.weather;
					city = weather_data.current_observation.display_location.city;

					response += "The current temperature in " + city + " is " + temp + ".\n";
					response += "The weather is " + status + ".";

					message_reqs.push(message);
					console.dir("Sending " + response);
					api.sendMessage(response, message.threadID);
				}
				else{
					response = JSON.stringify(weather_data.response.error);
					api.sendMessage(response,message.threadID);
				}
			});
		});
	}

	// Send the date
	else if (choices.date.test(message.body)){
		//var date = new Date();
		response = "The date is " + Date() + ".";
		message_reqs.push(message);
		console.log("Sending " + response);
		api.sendMessage(response, message.threadID);
	}

	// Send a cow
	else if (choices.cow.test(message.body)){
		response = cows()[Math.floor(Math.random()*418)];
		message_reqs.push(message);
		console.log("Sending " + response);
		api.sendMessage(response, message.threadID);
	}

	// Send an insult
	else if (choices.insult.test(message.body)){
		//response = "Fuck you " + message.senderName + "!";
		response = message.senderName + " is a " + shake_insult.random() + "!";
		message_reqs.push(message);
		console.log("Sending " + response);
		api.sendMessage(response, message.threadID);
	}

	// Send the senator with the fewest votes
	else if (choices.senate.test(message.body)){

		var client = new Client();
		var nyt_url = url.format({
			protocol: 'http',
			host: 'api.nytimes.com',
			pathname: '/svc/politics/v3/us/legislative/congress/113/senate/members.json',
			query: {
				'api-key': process.env.NYT_CONGRESS
			}
		});
		client.get(nyt_url, function(data, response) {
			// Sort by total votes
			data.results[0].members.sort(function(a, b){
				return a.total_votes - b.total_votes;
			});
			//console.log(data.results[0].members[0]);
			response = "The senator with the fewest total votes cast is ";
			response += data.results[0].members[0].first_name + ' ' + data.results[0].members[0].last_name;
			response += " with " + data.results[0].members[0].total_votes + " total votes.";

			message_reqs.push(message);
			console.log("Sending " + response);
			api.sendMessage(response, message.threadID);

		});
	}

	// Send a random greeting
	else if (choices.greet.test(message.body)){
		response = greetings.random() + ", " + message.senderName + "!";
		message_reqs.push(message);
		console.log("Sending " + response);
		api.sendMessage(response, message.threadID);
	}

	// Answer a yes/no question
	else if (choices.magic8.test(message.body)){
		response = predict();
		message_reqs.push(message);
		console.log("Sending " + response);
		api.sendMessage(response, message.threadID);
	}

	// Send a cigarette
	else if (choices.blaze.test(message.body)){
		response = emoji.get('smoking');
		message_reqs.push(message);
		console.log("Sending " + response);
		api.sendMessage(response, message.threadID);
	}

	// Send the 3 dots
	else if (choices.type.test(message.body)){
		message_reqs.push(message);
		api.sendTypingIndicator(message.threadID, function(){
			console.log("Typing");
		});
	}

	else if (choices.love.test(message.body)){
		message_reqs.push(message);
		response = "Don't worry, " + message.senderName + ", I love you!";
		console.log("Sending " + response);
		api.sendMessage(response,message.threadID);
	}
}

module.exports.parse = parse;
<commit_msg>Updated help function to send url to users<commit_after>/*
	parse.js
	Reads the incoming message and chooses the appropriate response.
	The "mouth" of Dank
*/

const login = require("facebook-chat-api");
const cool = require('cool-ascii-faces');
const http = require('http');
const Firebase = require("firebase");
const cows = require('cows');
const url = require('url');
const Client = require('node-rest-client').Client;
const predict = require('eightball');
const greetings = require('greetings');
const shake_insult = require('shakespeare-insult');
const emoji = require('node-emoji');

var db = new Firebase(process.env.DANK_SINATRA_FIREBASE);
var message_reqs = db.child("Requests");
var usersDB = db.child("users");
var chatsDB = db.child("chats");

// All commands go here
var choices = {
	help: /\\help/,

	greet: /\\howdy/,
	magic8: /\\magic8/,

	weather: /\\weather/,
	date: /\\date/,

	insult: /\\insult/,

	cool: /\\face/,
	cow: /\\cow/,
	blaze: /\\blaze/,

	senate: /\\senate/,

	type: /\\type/,

	love: /\\love/
};

/*
	TODO:
	1. Simulate conversation. Use IDs and DB
	2. Give a random greeting
	2. Magic 8 ball
*/
function parse(api, message){
	var response = '';

	// Add child for the threadID and append message there
	chatsDB.child(message.threadID).set(message);
	usersDB.child(message.senderID).set(message);

	// Send list of commands
	if (choices.help.test(message.body)){
		/*
		response = "Type '\\help' for a list of commands.\n";
		response += "\\howdy: Send a greeting.\n";
		response += "\\magic8 (yes/no question): Answer a yes/no question with complete accuracy.\n";
		response += "\\weather (ZIP code): Send the current weather in the given ZIP code.\n";
		response += "\\date: Send the current date.\n";
		response += "\\face: Send a cool ascii face.\n";
		response += "\\cow: Send an ascii cow.\n";
		response += "\\senate: Send a fact about the United States Senate.\n";
		response += "\\type: Send the 3 dots.";
		*/
		response = "Check out https://bitbucket.org/gaikema/danksinatra/wiki/Home for help and a list of commands!";

		message_reqs.push(message);
		console.log("Sending " + response);
		api.sendMessage(response, message.threadID);
	}

	// Send a face
	else if (choices.cool.test(message.body)){
		response = cool();

		message_reqs.push(message);
		console.log("Sending " + response);
		api.sendMessage(response, message.threadID);
	}

	// Send the weather at a ZIP code
	else if (choices.weather.test(message.body)){
		var zip_code = message.body.replace(choices.weather,"");
		zip_code = zip_code.trim();
		console.log(zip_code);

		http.get('http://api.wunderground.com/api/'+process.env.WEATHER_API_KEY+'/conditions/q/' + zip_code + '.json',function(res){
			var body = '';
			var temp = '';
			var status = '';
			var city = '';

			res.on('data', function(chunk){
				body += chunk;
			});

			res.on('error', function(error){
				console.error(error.message);
				api.sendMessage("Invalid argument!",message.threadID);
			});

			res.on('end', function(){
				var weather_data = JSON.parse(body);
				console.log(weather_data);

				if (!weather_data.response.error){
					temp = weather_data.current_observation.temp_f;
					status = weather_data.current_observation.weather;
					city = weather_data.current_observation.display_location.city;

					response += "The current temperature in " + city + " is " + temp + ".\n";
					response += "The weather is " + status + ".";

					message_reqs.push(message);
					console.dir("Sending " + response);
					api.sendMessage(response, message.threadID);
				}
				else{
					response = JSON.stringify(weather_data.response.error);
					api.sendMessage(response,message.threadID);
				}
			});
		});
	}

	// Send the date
	else if (choices.date.test(message.body)){
		//var date = new Date();
		response = "The date is " + Date() + ".";
		message_reqs.push(message);
		console.log("Sending " + response);
		api.sendMessage(response, message.threadID);
	}

	// Send a cow
	else if (choices.cow.test(message.body)){
		response = cows()[Math.floor(Math.random()*418)];
		message_reqs.push(message);
		console.log("Sending " + response);
		api.sendMessage(response, message.threadID);
	}

	// Send an insult
	else if (choices.insult.test(message.body)){
		//response = "Fuck you " + message.senderName + "!";
		response = message.senderName + " is a " + shake_insult.random() + "!";
		message_reqs.push(message);
		console.log("Sending " + response);
		api.sendMessage(response, message.threadID);
	}

	// Send the senator with the fewest votes
	else if (choices.senate.test(message.body)){

		var client = new Client();
		var nyt_url = url.format({
			protocol: 'http',
			host: 'api.nytimes.com',
			pathname: '/svc/politics/v3/us/legislative/congress/113/senate/members.json',
			query: {
				'api-key': process.env.NYT_CONGRESS
			}
		});
		client.get(nyt_url, function(data, response) {
			// Sort by total votes
			data.results[0].members.sort(function(a, b){
				return a.total_votes - b.total_votes;
			});
			//console.log(data.results[0].members[0]);
			response = "The senator with the fewest total votes cast is ";
			response += data.results[0].members[0].first_name + ' ' + data.results[0].members[0].last_name;
			response += " with " + data.results[0].members[0].total_votes + " total votes.";

			message_reqs.push(message);
			console.log("Sending " + response);
			api.sendMessage(response, message.threadID);

		});
	}

	// Send a random greeting
	else if (choices.greet.test(message.body)){
		response = greetings.random() + ", " + message.senderName + "!";
		message_reqs.push(message);
		console.log("Sending " + response);
		api.sendMessage(response, message.threadID);
	}

	// Answer a yes/no question
	else if (choices.magic8.test(message.body)){
		response = predict();
		message_reqs.push(message);
		console.log("Sending " + response);
		api.sendMessage(response, message.threadID);
	}

	// Send a cigarette
	else if (choices.blaze.test(message.body)){
		response = emoji.get('smoking');
		message_reqs.push(message);
		console.log("Sending " + response);
		api.sendMessage(response, message.threadID);
	}

	// Send the 3 dots
	else if (choices.type.test(message.body)){
		message_reqs.push(message);
		api.sendTypingIndicator(message.threadID, function(){
			console.log("Typing");
		});
	}

	else if (choices.love.test(message.body)){
		message_reqs.push(message);
		response = "Don't worry, " + message.senderName + ", I love you!";
		console.log("Sending " + response);
		api.sendMessage(response,message.threadID);
	}
}

module.exports.parse = parse;
<|endoftext|>


<commit_before>(function (root, factory) {

    if (typeof define === 'function' && define.amd) {
        define(['marionette', 'underscore'], function (Marionette, _) {
            return factory(Marionette, _);
        });
    }
    else if (typeof exports !== 'undefined') {
        var Marionette = require('marionette');
        var _ = require('underscore');
        module.exports = factory(Marionette, _);
    }
    else {
        root.Marionette.Tooltip = factory(root.Marionette, root._);
    }
}(this, function (Marionette, _) {
    'use strict';

    var ContainerView = Marionette.LayoutView.extend({
        template: _.template('

'),
        className: 'tooltip',

        regions: {
            region: '.js-tooltip'
        },

        events: {},

        initialize: function () {
            var prevents = this.prevents;

            if (_.isString(prevents)) {
                this.events[prevents] = 'preventPropagation';
            }
            else if (_.isArray(prevents)) {
                _.each(prevents, function (event) {
                    this.events[event] = 'preventPropagation';
                }, this);
            }
        },

        preventPropagation: function (event) {
            event.stopPropagation();
        }
    });

    return Marionette.Behavior.extend({
        defaults: {
            direction: 'top'
        },

        initialize: function () {
            var Container = ContainerView.extend({
                className: this.options.className || 'tooltip',
                prevents: this.options.prevents
            });

            this.tooltip = new Container;
        },

        onShow: function () {
            var View = _.result(this.view, 'getTooltip');

            if (View === void 0) {
                throw new Marionette.Error({
                    name: 'TooltipException',
                    message: 'tooltip is not defined'
                });
            }

            this.tooltip.render();
            this.tooltip.region.show(new View);

            this.tooltip.$el.addClass('direction-' + this.options.direction);

            if (this.view.ui && this.view.ui.tooltipTarget !== void 0) {
                this.view.ui.tooltipTarget.after(this.tooltip.el);
            }
            else {
                this.el.insertBefore(this.tooltip.el, null);
            }
        },

        onDestroy: function () {
            this.tooltip.destroy();
        },

        setPosition: function () {
            var target;

            if (this.view.ui && this.view.ui.tooltipTarget !== void 0) {
                target = this.view.ui.tooltipTarget;
            }
            else {
                target = this.$el;
            }

            // tooltip target
            var parentPosition = target.position();
            var parentWidth = target.outerWidth();
            var parentHeight = target.outerHeight();

            // tooltip element
            var height = this.tooltip.$el.outerHeight();
            var width = this.tooltip.$el.outerWidth();

            // tooltip default offset
            var top = parentPosition.top - height / 2 + parentHeight / 2;
            var left = parentPosition.left - width / 2 + parentWidth / 2;

            // ajust tooltip position based on tooltip direction
            switch (this.options.direction) {
                case 'top': {
                    top = parentPosition.top - height;
                    break;
                }
                case 'bottom': {
                    top = parentHeight + parentPosition.top;
                    break;
                }
                case 'left': {
                    left = parentPosition.left - width;
                    break;
                }
                case 'right': {
                    left = parentPosition.left + parentWidth;
                    break;
                }
            }

            this.tooltip.$el.css({
                top: top,
                left: left
            });
        },

        onShowTooltip: function () {
            this.setPosition();
            this.tooltip.$el.stop(true).fadeIn(200);
        },

        onHideTooltip: function () {
            this.tooltip.$el.stop(true).fadeOut(200);
        },

        onToggleTooltip: function () {
            if (this.tooltip.$el.css('display') === 'none') {
                this.onShowTooltip();
            }
            else {
                this.onHideTooltip();
            }
        }
    });
}));
<commit_msg>fix code style<commit_after>(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        define(['marionette', 'underscore'], function (Marionette, _) {
            return factory(Marionette, _);
        });
    }
    else if (typeof exports !== 'undefined') {
        var Marionette = require('marionette');
        var _ = require('underscore');

        module.exports = factory(Marionette, _);
    }
    else {
        root.Marionette.Tooltip = factory(root.Marionette, root._);
    }
}(this, function (Marionette, _) {
    'use strict';

    var ContainerView = Marionette.LayoutView.extend({
        template: _.template('

'),
        className: 'tooltip',

        regions: {
            region: '.js-tooltip'
        },

        events: {},

        initialize: function () {
            var prevents = this.prevents;

            if (_.isString(prevents)) {
                this.events[prevents] = 'preventPropagation';
            }
            else if (_.isArray(prevents)) {
                _.each(prevents, function (event) {
                    this.events[event] = 'preventPropagation';
                }, this);
            }
        },

        preventPropagation: function (event) {
            event.stopPropagation();
        }
    });

    return Marionette.Behavior.extend({
        defaults: {
            direction: 'top'
        },

        initialize: function () {
            var Container = ContainerView.extend({
                className: this.options.className || 'tooltip',
                prevents: this.options.prevents
            });

            this.tooltip = new Container;
        },

        onShow: function () {
            var View = _.result(this.view, 'getTooltip');

            if (View === void 0) {
                throw new Marionette.Error({
                    name: 'TooltipException',
                    message: 'tooltip is not defined'
                });
            }

            this.tooltip.render();
            this.tooltip.region.show(new View);

            this.tooltip.$el.addClass('direction-' + this.options.direction);

            if (this.view.ui && this.view.ui.tooltipTarget !== void 0) {
                this.view.ui.tooltipTarget.after(this.tooltip.el);
            }
            else {
                this.el.insertBefore(this.tooltip.el, null);
            }
        },

        onDestroy: function () {
            this.tooltip.destroy();
        },

        setPosition: function () {
            var target;

            if (this.view.ui && this.view.ui.tooltipTarget !== void 0) {
                target = this.view.ui.tooltipTarget;
            }
            else {
                target = this.$el;
            }

            // tooltip target
            var parentPosition = target.position();
            var parentWidth = target.outerWidth();
            var parentHeight = target.outerHeight();

            // tooltip element
            var height = this.tooltip.$el.outerHeight();
            var width = this.tooltip.$el.outerWidth();

            // tooltip default offset
            var top = parentPosition.top - height / 2 + parentHeight / 2;
            var left = parentPosition.left - width / 2 + parentWidth / 2;

            // ajust tooltip position based on tooltip direction
            switch (this.options.direction) {
                case 'top': {
                    top = parentPosition.top - height;
                    break;
                }
                case 'bottom': {
                    top = parentHeight + parentPosition.top;
                    break;
                }
                case 'left': {
                    left = parentPosition.left - width;
                    break;
                }
                case 'right': {
                    left = parentPosition.left + parentWidth;
                    break;
                }
            }

            this.tooltip.$el.css({
                top: top,
                left: left
            });
        },

        onShowTooltip: function () {
            this.setPosition();
            this.tooltip.$el.stop(true).fadeIn(200);
        },

        onHideTooltip: function () {
            this.tooltip.$el.stop(true).fadeOut(200);
        },

        onToggleTooltip: function () {
            if (this.tooltip.$el.css('display') === 'none') {
                this.onShowTooltip();
            }
            else {
                this.onHideTooltip();
            }
        }
    });
}));
<|endoftext|>


<commit_before>/* global document */

import React from 'react';
import ReactDOM from 'react-dom';
import { stripIndents } from 'common-tags';
import ErrorDisplay from './error_display';

// check whether we're running on node/browser
const isBrowser = typeof window !== 'undefined';

const logger = console;

let rootEl = null;
let previousKind = '';
let previousStory = '';

if (isBrowser) {
  rootEl = document.getElementById('root');
}

export function renderError(error) {
  const properError = new Error(error.title);
  properError.stack = error.description;

  const redBox = (<ErrorDisplay error={properError} />);
  ReactDOM.render(redBox, rootEl);
}

export function renderException(error) {
  // We always need to render redbox in the mainPage if we get an error.
  // Since this is an error, this affects to the main page as well.
  const realError = new Error(error.message);
  realError.stack = error.stack;
  const redBox = (<ErrorDisplay error={realError} />);
  ReactDOM.render(redBox, rootEl);

  // Log the stack to the console. So, user could check the source code.
  logger.error(error.stack);
}

export function renderMain(data, storyStore) {
  if (storyStore.size() === 0) return null;

  const NoPreview = () => (
No Preview Available!
);
  const noPreview = (<NoPreview />);
  const { selectedKind, selectedStory } = data;

  const story = storyStore.getStory(selectedKind, selectedStory);
  if (!story) {
    ReactDOM.render(noPreview, rootEl);
    return null;
  }

  // Unmount the previous story only if selectedKind or selectedStory has changed.
  // renderMain() gets executed after each action. Actions will cause the whole
  // story to re-render without this check.
  //    https://github.com/kadirahq/react-storybook/issues/116
  if (selectedKind !== previousKind || previousStory !== selectedStory) {
    // We need to unmount the existing set of components in the DOM node.
    // Otherwise, React may not recrease instances for every story run.
    // This could leads to issues like below:
    //    https://github.com/kadirahq/react-storybook/issues/81
    previousKind = selectedKind;
    previousStory = selectedStory;
    ReactDOM.unmountComponentAtNode(rootEl);
  }

  const context = {
    kind: selectedKind,
    story: selectedStory,
  };

  const element = story(context);

  if (!element) {
    const error = {
      title: `Expecting a React element from the story: "${selectedStory}" of "${selectedKind}".`,
      /* eslint-disable */
      description: stripIndents`
        Did you forget to return the React element from the story?
        Use "() => (<MyComp/>)" or "() => { return <MyComp/>; }" when defining the story.
      `,
      /* eslint-enable */
    };
    return renderError(error);
  }

  if (element.type === undefined) {
    const error = {
      title: `Expecting a valid React element from the story: "${selectedStory}" of "${selectedKind}".`,
      description: stripIndents`
        Seems like you are not returning a correct React element form the story.
        Could you double check that?
      `,
    };
    return renderError(error);
  }

  ReactDOM.render(element, rootEl);
  return null;
}

export default function renderPreview({ reduxStore, storyStore }) {
  const state = reduxStore.getState();
  if (state.error) {
    return renderException(state.error);
  }

  try {
    return renderMain(state, storyStore);
  } catch (ex) {
    return renderException(ex);
  }
}
<commit_msg>Fix spelling mistake<commit_after>/* global document */

import React from 'react';
import ReactDOM from 'react-dom';
import { stripIndents } from 'common-tags';
import ErrorDisplay from './error_display';

// check whether we're running on node/browser
const isBrowser = typeof window !== 'undefined';

const logger = console;

let rootEl = null;
let previousKind = '';
let previousStory = '';

if (isBrowser) {
  rootEl = document.getElementById('root');
}

export function renderError(error) {
  const properError = new Error(error.title);
  properError.stack = error.description;

  const redBox = (<ErrorDisplay error={properError} />);
  ReactDOM.render(redBox, rootEl);
}

export function renderException(error) {
  // We always need to render redbox in the mainPage if we get an error.
  // Since this is an error, this affects to the main page as well.
  const realError = new Error(error.message);
  realError.stack = error.stack;
  const redBox = (<ErrorDisplay error={realError} />);
  ReactDOM.render(redBox, rootEl);

  // Log the stack to the console. So, user could check the source code.
  logger.error(error.stack);
}

export function renderMain(data, storyStore) {
  if (storyStore.size() === 0) return null;

  const NoPreview = () => (
No Preview Available!
);
  const noPreview = (<NoPreview />);
  const { selectedKind, selectedStory } = data;

  const story = storyStore.getStory(selectedKind, selectedStory);
  if (!story) {
    ReactDOM.render(noPreview, rootEl);
    return null;
  }

  // Unmount the previous story only if selectedKind or selectedStory has changed.
  // renderMain() gets executed after each action. Actions will cause the whole
  // story to re-render without this check.
  //    https://github.com/kadirahq/react-storybook/issues/116
  if (selectedKind !== previousKind || previousStory !== selectedStory) {
    // We need to unmount the existing set of components in the DOM node.
    // Otherwise, React may not recrease instances for every story run.
    // This could leads to issues like below:
    //    https://github.com/kadirahq/react-storybook/issues/81
    previousKind = selectedKind;
    previousStory = selectedStory;
    ReactDOM.unmountComponentAtNode(rootEl);
  }

  const context = {
    kind: selectedKind,
    story: selectedStory,
  };

  const element = story(context);

  if (!element) {
    const error = {
      title: `Expecting a React element from the story: "${selectedStory}" of "${selectedKind}".`,
      /* eslint-disable */
      description: stripIndents`
        Did you forget to return the React element from the story?
        Use "() => (<MyComp/>)" or "() => { return <MyComp/>; }" when defining the story.
      `,
      /* eslint-enable */
    };
    return renderError(error);
  }

  if (element.type === undefined) {
    const error = {
      title: `Expecting a valid React element from the story: "${selectedStory}" of "${selectedKind}".`,
      description: stripIndents`
        Seems like you are not returning a correct React element from the story.
        Could you double check that?
      `,
    };
    return renderError(error);
  }

  ReactDOM.render(element, rootEl);
  return null;
}

export default function renderPreview({ reduxStore, storyStore }) {
  const state = reduxStore.getState();
  if (state.error) {
    return renderException(state.error);
  }

  try {
    return renderMain(state, storyStore);
  } catch (ex) {
    return renderException(ex);
  }
}
<|endoftext|>