<commit_before>/*global DocumentTouch, FB */

function ShareBar(options) {
    'use strict';
    return this.init(options);
}

(function (window, document) {
    'use strict';

    var FACEBOOK = 'facebook',
        TWITTER = 'twitter',
        WHATSAPP = 'whatsapp',
        GOOGLE = 'google',
        PINTEREST = 'pinterest',
        EMAIL = 'email',
        BUTTON_WIDTH = 34,
        BUTTON_FULL_WIDTH = 110,
        BUTTON_PADDING = 4,
        MAX_SOCIAL_BUTTONS = 6,
        SHARE_BUTTON = 'share-button',
        SVG_CONTAINER = 'sharebar-svg-container';

    function preventDefault(e) {
        if (e && e.preventDefault) {
            e.preventDefault();
        } else if (window.event) {
            window.event.returnValue = false;
        }
    }

    function addEventListener(element, event, handler) {
        if (element.addEventListener) {
            return element.addEventListener(event, handler, false);
        }
        if (element.attachEvent) {
            return element.attachEvent('on' + event, function () { handler.call(element); });
        }
    }

    ShareBar.prototype = {
        init: function init(options) {
            this.eventName = this.getActionName();
            this.verifyTouch();
            this.createSVG();
            this.mergeOptions(options);
            this.containers = document.querySelectorAll(this.selector);
            this.createBars();
        },

        getActionName: function getActionName() {
            return this.isTouch() ? 'mouseup' : 'click';
        },

        // https://github.com/Modernizr/Modernizr/blob/master/feature-detects/touchevents.js
        verifyTouch: function verifyTouch() {
            var html = document.querySelector('html'),
                isTouch = this.isTouch(),
                touch = ' touch',
                noTouch = ' no-touch';

            if (isTouch && html.className.indexOf(touch) === -1) {
                html.className += touch;

            } else if (!isTouch && html.className.indexOf(noTouch) === -1) {
                html.className += noTouch;
            }
        },

        isTouch: function isTouch() {
            var bool = false;

            if (window.ontouchstart !== undefined || (window.DocumentTouch && document instanceof DocumentTouch)) {
                bool = true;
            }
            return bool;
        },

        createSVG: function createSVG() {
            var hasSvg = document.querySelector('.sharebar-svg-container'),
                svg;

            if (!hasSvg) {
                svg = document.createElement('div');
                svg.innerHTML = '[[X_SVG_X]]';
                svg.classList.add(SVG_CONTAINER);
                svg.style.display = 'none';

                document.body.appendChild(svg);
            }
        },

        mergeOptions: function mergeOptions(options) {
            var option,
                defaultOptions = {
                    // Selector to open lightbox
                    selector: '.share-bar',
                    campaign: 'share-bar',
                    classPopup: 'share-popup',
                    facebookAppId: '',
                    networks: [
                        FACEBOOK, TWITTER, WHATSAPP, GOOGLE, PINTEREST, EMAIL
                    ],
                    theme: 'natural',
                    buttonWidth: BUTTON_WIDTH,
                    buttonFullWidth: BUTTON_FULL_WIDTH,
                    buttonPadding: BUTTON_PADDING,
                    maxSocialButtons: MAX_SOCIAL_BUTTONS,
                    context: 'desktop',
                    onCreateBar: function (bar) { return false; },
                    onCreateButton: function (button) { return false; },
                    onShare: function (button) { return false; }
                };

            if (!options) {
                options = {};
            }

            for (option in defaultOptions) {
                if (defaultOptions.hasOwnProperty(option)) {
                    this[option] = options[option] || defaultOptions[option];
                }
            }
        },

        validateNetworks: function validateNetworks(networks) {
            var msg = 'The list of networks passed on initialization is wrong',
                i = 0,
                networkName = '',
                method = '';

            if (Object.prototype.toString.call(networks) !== '[object Array]') {
                throw new Error(msg + ' [Should be an Array]');
            }

            for (i; i < networks.length; i++) {
                if (typeof networks[i] === 'string') {
                    networkName = networks[i];
                    networkName = networkName.substr(0, 1).toUpperCase() + networkName.substr(1);
                    method = ShareBar.prototype['create' + networkName + 'Button'];

                    if (method) {
                        networks[i] = method;
                    } else {
                        throw new Error(msg + ' [Network name "' + networks[i] + '" is wrong, should be ' + FACEBOOK + ' or ' + TWITTER + ' or ' + WHATSAPP + ' or ' + GOOGLE + ' or ' + PINTEREST + ' or ' + EMAIL + ']');
                    }

                } else if (typeof networks[i] !== 'function') {
                    throw new Error(msg + ' [Should be string or function]');
                }
            }

            return networks;
        },

        createBars: function createBars() {
            var items = this.containers,
                element = 0;

            for (element = 0; element < items.length; element++) {
                this.createBar(items[element]);
            }

        },

        createBar: function createBar(element, networks) {
            var theme = ' share-theme-',
                i = 0,
                count = 0,
                buttonClasses = [];

            networks = this.validateNetworks(networks || this.networks);
            networks = networks.slice(0, this.maxSocialButtons);

            count = networks.length;
            buttonClasses = this.getButtonsSize(element.offsetWidth, count);

            for (i; i < count; i++) {
                networks[i].call(this, element, buttonClasses[i]);
            }

            theme += element.getAttribute('data-theme') || this.theme;
            element.className += ' share-bar-container' + theme;
            this.bindOpenPopup(element);
            this.bindShare(element);
            this.onCreateBar(element);
        },

        getButtonsSize: function getButtonsSize(containerWidth, numberOfButtons) {
            var fullButtonWidth = this.buttonFullWidth + this.buttonPadding,
                smallButtonWidth = this.buttonWidth + this.buttonPadding,
                isSmallScreen = this.isSmallScreen();

            if ((numberOfButtons * smallButtonWidth) > containerWidth) {
                return this.getButtonsSmall(
                    numberOfButtons,
                    smallButtonWidth,
                    containerWidth
                );
            }

            if (isSmallScreen) {
                return ['', '', '', '', '', ''];
            }

            return this.getButtonsFull(
                numberOfButtons,
                fullButtonWidth,
                smallButtonWidth,
                containerWidth
            );
        },

        getButtonsSmall: function getButtonsSmall(numberOfButtons, smallButtonWidth, containerWidth) {
            var result = [],
                i = 1,
                totalOfSmallButtons = 0,
                isSmallScreen = this.isSmallScreen();

            for (i; i <= numberOfButtons; i++) {
                totalOfSmallButtons = i * smallButtonWidth;

                if (totalOfSmallButtons <= containerWidth) {
                    result[i - 1] = isSmallScreen ? '' : ' share-small';
                } else {
                    result[i - 1] = ' share-hidden';
                }
            }

            return result;
        },

        getButtonsFull: function getButtonsFull(numberOfButtons, fullButtonWidth, smallButtonWidth, containerWidth) {
            var result = [],
                i = 1,
                totalOfFullButtons = 0,
                totalOfSmallButtons = 0;

            for (i; i <= numberOfButtons; i++) {
                totalOfFullButtons = i * fullButtonWidth;
                totalOfSmallButtons = (numberOfButtons - i) * smallButtonWidth;

                if ((totalOfSmallButtons + totalOfFullButtons) <= containerWidth) {
                    result[i - 1] = ' share-full';
                } else {
                    result[i - 1] = ' share-small';
                }
            }

            return result;
        },

        bindOpenPopup: function bindOpenPopup(element) {
            var linksPopup = element.querySelectorAll('.' + this.classPopup),
                i = 0,
                self = this,
                onShareClick = function (e) {
                    self.openPopup.call(this, e);
                };

            for (i; i < linksPopup.length; i++) {
                addEventListener(linksPopup[i], this.eventName, onShareClick);
                addEventListener(linksPopup[i], 'click', preventDefault);
            }
        },

        bindShare: function bindShare(element) {
            var shareButtons = element.querySelectorAll('.' + SHARE_BUTTON),
                i = 0,
                self = this,
                onShareClick = function (e) {
                    self.onShare(this);
                };

            for (i; i < shareButtons.length; i++) {
                addEventListener(shareButtons[i], this.eventName, onShareClick);
            }
        },

        openPopup: function openPopup(e) {
            var win = window.open(
                this.getAttribute('href'),
                'popup',
                'height=400,width=500,left=10,top=10,resizable=yes,scrollbars=no,toolbar=no,menubar=no,location=no,directories=no,status=no'
            );

            win.focus();
        },

        getMetadataFromElement: function getMetadataFromElement(element) {
            var encode = window.encodeURIComponent,
                url = element.getAttribute('data-url') || '',
                urlToShare,
                splitUrl = url.split('#'),
                queryString = '?utm_source=#source#&utm_medium=share-bar-' + this.context + '&utm_campaign=' + this.campaign;

            if (splitUrl.length > 1) {
                urlToShare = splitUrl[0] + queryString + '&#' + splitUrl[1];
            } else {
                urlToShare = url + queryString;
            }

            return {
                'url': encode(urlToShare),
                'title': encode(element.getAttribute('data-title') || ''),
                'imageUrl': encode(element.getAttribute('data-image-url') || ''),
                'hashtags': encode(element.getAttribute('data-hashtags') || '')
            };
        },

        isSmallScreen: function isSmallScreen() {
            var desktopMinWidth = 768,
                width = window.innerWidth || screen.width;
            return width < desktopMinWidth;
        },

        createButton: function createButton(container, socialNetworkClass, className, url, socialNetworkTitle, openInPage) {
            var shareContainer = document.createElement('div'),
                classPopup = '';
            socialNetworkTitle = socialNetworkTitle || socialNetworkClass;
            className = className || '';
            shareContainer.className = SHARE_BUTTON + ' share-' + socialNetworkClass + className;
            socialNetworkTitle = socialNetworkTitle[0].toUpperCase() + socialNetworkTitle.slice(1);
            url = url.replace('%23source%23', socialNetworkClass);

            if (!openInPage) {
                classPopup = this.classPopup;
            }

            shareContainer.innerHTML = [
                '',
                this.createContentButton(socialNetworkClass, socialNetworkTitle),
                ''
            ].join('');

            container.appendChild(shareContainer);
            this.onCreateButton(shareContainer);

            return shareContainer;
        },

        createContentButton: function createContentButton(name, title) {
            var iconElement;
            title = title || name;

            iconElement = [
                '
',
                '      <svg viewBox="0 0 100 100" class="share-icon">',
                '           <use xlink:href="#icon-' + name + '"></use>',
                '       </svg>',
                '
',
                '' + title + ''
            ].join('');

            return iconElement;
        },

        createFacebookButton: function createFacebookButton(container, buttonClass) {
            var onShare = '',
                button = '',
                data = this.getMetadataFromElement(container),
                url = data.url.replace('%23source%23', FACEBOOK);

            button = this.createButton(
                container,
                FACEBOOK,
                buttonClass,
                'http://www.facebook.com/',
                '',
                true
            );

            this.getFacebookUi();

            onShare = function () {
                var decode = window.decodeURIComponent;

                FB.ui({
                    method: 'feed',
                    display: 'popup',
                    link: decode(url),
                    name: decode(data.title),
                    picture: decode(data.imageUrl)
                });
            };

            addEventListener(button, this.eventName, onShare);
            addEventListener(button, 'click', preventDefault);
        },

        getFacebookUi: function getFacebookUi() {
            var facebookAppId = this.facebookAppId || this.getOgFbAppId();

            if (window.FB) {
                return false;
            }

            if (facebookAppId) {
                window.fbAsyncInit = function () {
                    FB.init({
                        appId: facebookAppId,
                        xfbml: true,
                        version: 'v2.8'
                    });
                };
                (function (d, s, id) {
                    var js, fjs = d.getElementsByTagName(s)[0];
                    if (d.getElementById(id)) { return; }
                    js = d.createElement(s);
                    js.id = id;
                    js.src = "//connect.facebook.net/en_US/sdk.js";
                    fjs.parentNode.insertBefore(js, fjs);
                }(document, 'script', 'facebook-jssdk'));
            }

        },

        getOgFbAppId: function () {
            var el = document.querySelector("meta[property='fb:app_id']");

            if (el !== null) {
                return el.getAttribute('content');
            }
            return;
        },

        createTwitterButton: function createTwitterButton(container, buttonClass) {
            var data = this.getMetadataFromElement(container);

            this.createButton(
                container,
                TWITTER,
                buttonClass,
                'https://twitter.com/share?url=' + data.url + '&text=' + data.title + ' ' + data.hashtags
            );
        },

        createGoogleButton: function createGoogleButton(container, buttonClass) {
            var data = this.getMetadataFromElement(container);

            this.createButton(
                container,
                GOOGLE + 'plus',
                buttonClass,
                'https://plus.google.com/share?url=' + data.url,
                GOOGLE + '+'
            );
        },

        createPinterestButton: function createPinterestButton(container, buttonClass) {
            var data = this.getMetadataFromElement(container);

            this.createButton(
                container,
                PINTEREST,
                buttonClass,
                'http://br.pinterest.com/pin/create/button/?url=' + data.url + '&media=' + data.imageUrl + '&description=' + data.title
            );
        },

        createWhatsappButton: function createWhatsappButton(container, buttonClass) {
            var data = this.getMetadataFromElement(container);

            if (!this.isSmallScreen() || !this.isTouch()) {
                return false;
            }

            this.createButton(
                container,
                WHATSAPP,
                buttonClass,
                'whatsapp://send?text=' + data.title + '%20' + data.url,
                '',
                true
            );
        },

        createEmailButton: function createEmailButton(container, buttonClass) {
            var data = this.getMetadataFromElement(container);

            if (!this.isTouch()) {
                return false;
            }

            this.createButton(
                container,
                EMAIL,
                buttonClass,
                'mailto:?subject=' + data.title + '&body=' + data.url,
                'e-mail',
                true
            );
        }
    };

}(window, document));
<commit_msg>Adding passive event listeners to events<commit_after>/*global DocumentTouch, FB */

function ShareBar(options) {
    'use strict';
    return this.init(options);
}

(function (window, document) {
    'use strict';

    var FACEBOOK = 'facebook',
        TWITTER = 'twitter',
        WHATSAPP = 'whatsapp',
        GOOGLE = 'google',
        PINTEREST = 'pinterest',
        EMAIL = 'email',
        BUTTON_WIDTH = 34,
        BUTTON_FULL_WIDTH = 110,
        BUTTON_PADDING = 4,
        MAX_SOCIAL_BUTTONS = 6,
        SHARE_BUTTON = 'share-button',
        SVG_CONTAINER = 'sharebar-svg-container';

    function preventDefault(e) {
        if (e && e.preventDefault) {
            e.preventDefault();
        }
    }

    function supportsPassive() {
        var supportsPassive = false;
        try {
            var opts = Object.defineProperty({}, 'passive', {
                get: function() {
                    supportsPassive = true;
                }
            });
            window.addEventListener("test", null, opts);
        } catch (e) {}

        return supportsPassive;
    }

    function addEventListener(element, event, handler) {
        return element.addEventListener(event, handler, supportsPassive() ? { passive: true } : false);
    }

    ShareBar.prototype = {
        init: function init(options) {
            this.eventName = this.getActionName();
            this.verifyTouch();
            this.createSVG();
            this.mergeOptions(options);
            this.containers = document.querySelectorAll(this.selector);
            this.createBars();
        },

        getActionName: function getActionName() {
            return this.isTouch() ? 'mouseup' : 'click';
        },

        // https://github.com/Modernizr/Modernizr/blob/master/feature-detects/touchevents.js
        verifyTouch: function verifyTouch() {
            var html = document.querySelector('html'),
                isTouch = this.isTouch(),
                touch = ' touch',
                noTouch = ' no-touch';

            if (isTouch && html.className.indexOf(touch) === -1) {
                html.className += touch;

            } else if (!isTouch && html.className.indexOf(noTouch) === -1) {
                html.className += noTouch;
            }
        },

        isTouch: function isTouch() {
            var bool = false;

            if (window.ontouchstart !== undefined || (window.DocumentTouch && document instanceof DocumentTouch)) {
                bool = true;
            }
            return bool;
        },

        createSVG: function createSVG() {
            var hasSvg = document.querySelector('.sharebar-svg-container'),
                svg;

            if (!hasSvg) {
                svg = document.createElement('div');
                svg.innerHTML = '[[X_SVG_X]]';
                svg.classList.add(SVG_CONTAINER);
                svg.style.display = 'none';

                document.body.appendChild(svg);
            }
        },

        mergeOptions: function mergeOptions(options) {
            var option,
                defaultOptions = {
                    // Selector to open lightbox
                    selector: '.share-bar',
                    campaign: 'share-bar',
                    classPopup: 'share-popup',
                    facebookAppId: '',
                    networks: [
                        FACEBOOK, TWITTER, WHATSAPP, GOOGLE, PINTEREST, EMAIL
                    ],
                    theme: 'natural',
                    buttonWidth: BUTTON_WIDTH,
                    buttonFullWidth: BUTTON_FULL_WIDTH,
                    buttonPadding: BUTTON_PADDING,
                    maxSocialButtons: MAX_SOCIAL_BUTTONS,
                    context: 'desktop',
                    onCreateBar: function (bar) { return false; },
                    onCreateButton: function (button) { return false; },
                    onShare: function (button) { return false; }
                };

            if (!options) {
                options = {};
            }

            for (option in defaultOptions) {
                if (defaultOptions.hasOwnProperty(option)) {
                    this[option] = options[option] || defaultOptions[option];
                }
            }
        },

        validateNetworks: function validateNetworks(networks) {
            var msg = 'The list of networks passed on initialization is wrong',
                i = 0,
                networkName = '',
                method = '';

            if (Object.prototype.toString.call(networks) !== '[object Array]') {
                throw new Error(msg + ' [Should be an Array]');
            }

            for (i; i < networks.length; i++) {
                if (typeof networks[i] === 'string') {
                    networkName = networks[i];
                    networkName = networkName.substr(0, 1).toUpperCase() + networkName.substr(1);
                    method = ShareBar.prototype['create' + networkName + 'Button'];

                    if (method) {
                        networks[i] = method;
                    } else {
                        throw new Error(msg + ' [Network name "' + networks[i] + '" is wrong, should be ' + FACEBOOK + ' or ' + TWITTER + ' or ' + WHATSAPP + ' or ' + GOOGLE + ' or ' + PINTEREST + ' or ' + EMAIL + ']');
                    }

                } else if (typeof networks[i] !== 'function') {
                    throw new Error(msg + ' [Should be string or function]');
                }
            }

            return networks;
        },

        createBars: function createBars() {
            var items = this.containers,
                element = 0;

            for (element = 0; element < items.length; element++) {
                this.createBar(items[element]);
            }

        },

        createBar: function createBar(element, networks) {
            var theme = ' share-theme-',
                i = 0,
                count = 0,
                buttonClasses = [];

            networks = this.validateNetworks(networks || this.networks);
            networks = networks.slice(0, this.maxSocialButtons);

            count = networks.length;
            buttonClasses = this.getButtonsSize(element.offsetWidth, count);

            for (i; i < count; i++) {
                networks[i].call(this, element, buttonClasses[i]);
            }

            theme += element.getAttribute('data-theme') || this.theme;
            element.className += ' share-bar-container' + theme;
            this.bindOpenPopup(element);
            this.bindShare(element);
            this.onCreateBar(element);
        },

        getButtonsSize: function getButtonsSize(containerWidth, numberOfButtons) {
            var fullButtonWidth = this.buttonFullWidth + this.buttonPadding,
                smallButtonWidth = this.buttonWidth + this.buttonPadding,
                isSmallScreen = this.isSmallScreen();

            if ((numberOfButtons * smallButtonWidth) > containerWidth) {
                return this.getButtonsSmall(
                    numberOfButtons,
                    smallButtonWidth,
                    containerWidth
                );
            }

            if (isSmallScreen) {
                return ['', '', '', '', '', ''];
            }

            return this.getButtonsFull(
                numberOfButtons,
                fullButtonWidth,
                smallButtonWidth,
                containerWidth
            );
        },

        getButtonsSmall: function getButtonsSmall(numberOfButtons, smallButtonWidth, containerWidth) {
            var result = [],
                i = 1,
                totalOfSmallButtons = 0,
                isSmallScreen = this.isSmallScreen();

            for (i; i <= numberOfButtons; i++) {
                totalOfSmallButtons = i * smallButtonWidth;

                if (totalOfSmallButtons <= containerWidth) {
                    result[i - 1] = isSmallScreen ? '' : ' share-small';
                } else {
                    result[i - 1] = ' share-hidden';
                }
            }

            return result;
        },

        getButtonsFull: function getButtonsFull(numberOfButtons, fullButtonWidth, smallButtonWidth, containerWidth) {
            var result = [],
                i = 1,
                totalOfFullButtons = 0,
                totalOfSmallButtons = 0;

            for (i; i <= numberOfButtons; i++) {
                totalOfFullButtons = i * fullButtonWidth;
                totalOfSmallButtons = (numberOfButtons - i) * smallButtonWidth;

                if ((totalOfSmallButtons + totalOfFullButtons) <= containerWidth) {
                    result[i - 1] = ' share-full';
                } else {
                    result[i - 1] = ' share-small';
                }
            }

            return result;
        },

        bindOpenPopup: function bindOpenPopup(element) {
            var linksPopup = element.querySelectorAll('.' + this.classPopup),
                i = 0,
                self = this,
                onShareClick = function (e) {
                    self.openPopup.call(this, e);
                };

            for (i; i < linksPopup.length; i++) {
                addEventListener(linksPopup[i], this.eventName, onShareClick);
                addEventListener(linksPopup[i], 'click', preventDefault);
            }
        },

        bindShare: function bindShare(element) {
            var shareButtons = element.querySelectorAll('.' + SHARE_BUTTON),
                i = 0,
                self = this,
                onShareClick = function (e) {
                    self.onShare(this);
                };

            for (i; i < shareButtons.length; i++) {
                addEventListener(shareButtons[i], this.eventName, onShareClick);
            }
        },

        openPopup: function openPopup(e) {
            var win = window.open(
                this.getAttribute('href'),
                'popup',
                'height=400,width=500,left=10,top=10,resizable=yes,scrollbars=no,toolbar=no,menubar=no,location=no,directories=no,status=no'
            );

            win.focus();
        },

        getMetadataFromElement: function getMetadataFromElement(element) {
            var encode = window.encodeURIComponent,
                url = element.getAttribute('data-url') || '',
                urlToShare,
                splitUrl = url.split('#'),
                queryString = '?utm_source=#source#&utm_medium=share-bar-' + this.context + '&utm_campaign=' + this.campaign;

            if (splitUrl.length > 1) {
                urlToShare = splitUrl[0] + queryString + '&#' + splitUrl[1];
            } else {
                urlToShare = url + queryString;
            }

            return {
                'url': encode(urlToShare),
                'title': encode(element.getAttribute('data-title') || ''),
                'imageUrl': encode(element.getAttribute('data-image-url') || ''),
                'hashtags': encode(element.getAttribute('data-hashtags') || '')
            };
        },

        isSmallScreen: function isSmallScreen() {
            var desktopMinWidth = 768,
                width = window.innerWidth || screen.width;
            return width < desktopMinWidth;
        },

        createButton: function createButton(container, socialNetworkClass, className, url, socialNetworkTitle, openInPage) {
            var shareContainer = document.createElement('div'),
                classPopup = '';
            socialNetworkTitle = socialNetworkTitle || socialNetworkClass;
            className = className || '';
            shareContainer.className = SHARE_BUTTON + ' share-' + socialNetworkClass + className;
            socialNetworkTitle = socialNetworkTitle[0].toUpperCase() + socialNetworkTitle.slice(1);
            url = url.replace('%23source%23', socialNetworkClass);

            if (!openInPage) {
                classPopup = this.classPopup;
            }

            shareContainer.innerHTML = [
                '',
                this.createContentButton(socialNetworkClass, socialNetworkTitle),
                ''
            ].join('');

            container.appendChild(shareContainer);
            this.onCreateButton(shareContainer);

            return shareContainer;
        },

        createContentButton: function createContentButton(name, title) {
            var iconElement;
            title = title || name;

            iconElement = [
                '
',
                '      <svg viewBox="0 0 100 100" class="share-icon">',
                '           <use xlink:href="#icon-' + name + '"></use>',
                '       </svg>',
                '
',
                '' + title + ''
            ].join('');

            return iconElement;
        },

        createFacebookButton: function createFacebookButton(container, buttonClass) {
            var onShare = '',
                button = '',
                data = this.getMetadataFromElement(container),
                url = data.url.replace('%23source%23', FACEBOOK);

            button = this.createButton(
                container,
                FACEBOOK,
                buttonClass,
                'http://www.facebook.com/',
                '',
                true
            );

            this.getFacebookUi();

            onShare = function () {
                var decode = window.decodeURIComponent;

                FB.ui({
                    method: 'feed',
                    display: 'popup',
                    link: decode(url),
                    name: decode(data.title),
                    picture: decode(data.imageUrl)
                });
            };

            addEventListener(button, this.eventName, onShare);
            addEventListener(button, 'click', preventDefault);
        },

        getFacebookUi: function getFacebookUi() {
            var facebookAppId = this.facebookAppId || this.getOgFbAppId();

            if (window.FB) {
                return false;
            }

            if (facebookAppId) {
                window.fbAsyncInit = function () {
                    FB.init({
                        appId: facebookAppId,
                        xfbml: true,
                        version: 'v2.8'
                    });
                };
                (function (d, s, id) {
                    var js, fjs = d.getElementsByTagName(s)[0];
                    if (d.getElementById(id)) { return; }
                    js = d.createElement(s);
                    js.id = id;
                    js.src = "//connect.facebook.net/en_US/sdk.js";
                    fjs.parentNode.insertBefore(js, fjs);
                }(document, 'script', 'facebook-jssdk'));
            }

        },

        getOgFbAppId: function () {
            var el = document.querySelector("meta[property='fb:app_id']");

            if (el !== null) {
                return el.getAttribute('content');
            }
            return;
        },

        createTwitterButton: function createTwitterButton(container, buttonClass) {
            var data = this.getMetadataFromElement(container);

            this.createButton(
                container,
                TWITTER,
                buttonClass,
                'https://twitter.com/share?url=' + data.url + '&text=' + data.title + ' ' + data.hashtags
            );
        },

        createGoogleButton: function createGoogleButton(container, buttonClass) {
            var data = this.getMetadataFromElement(container);

            this.createButton(
                container,
                GOOGLE + 'plus',
                buttonClass,
                'https://plus.google.com/share?url=' + data.url,
                GOOGLE + '+'
            );
        },

        createPinterestButton: function createPinterestButton(container, buttonClass) {
            var data = this.getMetadataFromElement(container);

            this.createButton(
                container,
                PINTEREST,
                buttonClass,
                'http://br.pinterest.com/pin/create/button/?url=' + data.url + '&media=' + data.imageUrl + '&description=' + data.title
            );
        },

        createWhatsappButton: function createWhatsappButton(container, buttonClass) {
            var data = this.getMetadataFromElement(container);

            if (!this.isSmallScreen() || !this.isTouch()) {
                return false;
            }

            this.createButton(
                container,
                WHATSAPP,
                buttonClass,
                'whatsapp://send?text=' + data.title + '%20' + data.url,
                '',
                true
            );
        },

        createEmailButton: function createEmailButton(container, buttonClass) {
            var data = this.getMetadataFromElement(container);

            if (!this.isTouch()) {
                return false;
            }

            this.createButton(
                container,
                EMAIL,
                buttonClass,
                'mailto:?subject=' + data.title + '&body=' + data.url,
                'e-mail',
                true
            );
        }
    };

}(window, document));
<|endoftext|>


<commit_before>'use strict'

const fs = require('fs')

module.exports = JSON.parse(fs.readFileSync('./.eslintrc', 'utf-8'))
<commit_msg>fix eslintrc export again<commit_after>'use strict'

const fs = require('fs')
const path = require('path')
const ESLINTRC_PATH = path.join(__dirname, '.eslintrc')

module.exports = JSON.parse(fs.readFileSync(ESLINTRC_PATH, 'utf-8'))
<|endoftext|>


<commit_before>/*
Copyright (c) 2013 William Malone (www.williammalone.com)

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

/*global window, document, Image, Float32Array */

var BLOCKS;

if (BLOCKS === undefined) {
	BLOCKS = {};
}

BLOCKS.slice = function (options) {

	"use strict";

	var slice = BLOCKS.eventDispatcher(),

		// Private Properties
		numberOfFrames = (options && options.numberOfFrames) || 1,
		curFrameIndex = 0,
		imageResource,
		paused = false,
		frameCnt = 0,
		resetOnComplete = options && options.resetOnComplete,
		loopIndex = 0,
		texture,
		centerRegistrationPoint = options && options.centerRegistrationPoint,
		drawBounds = false, // This is used for debug only
		tmpCtx, // Used when colorizing

		// Private Methods
		onResourceLoaded = function () {

			// Will be used for webGL enabled contexts
			//if (slice.layer && slice.layer.webGLEnabled) {
			//	prepareWebGLContext(slice.layer.ctx);
			//}

			// Set the sprite dimensions to the image dimensions
			// Note: Divide the width by the number of frames in the sprite sheet if an animation. If the sprite is only an image then the number of frames will be 1.

			if (imageResource) {
				slice.width = imageResource.image.width / numberOfFrames;
				slice.height = imageResource.image.height;
			}

			// If the registration point should be centered
			if (centerRegistrationPoint) {
				slice.offsetX = -slice.width / 2;
				slice.offsetY = -slice.height / 2;
			}
		};

	// Public Properties
	slice.name = (options && options.name !== undefined) ? options.name : undefined;
	slice.width = (options && options.width) || 0;
	slice.height = (options && options.height) || 0;
	slice.x = 0;
	slice.y = 0;
	slice.offsetX = (options && options.offsetX) || 0;
	slice.offsetY = (options && options.offsetY) || 0;
	slice.frameOffsetX = (options && options.frameOffsetX) || 0;
	slice.frameOffsetY = (options && options.frameOffsetY) || 0;
	slice.loop = options && options.loop;
	slice.visible = true;
	slice.dirty = true;
	slice.hotspots = options && options.hotspots;
	slice.minHotspot = options && options.minHotspot;
	slice.layer = options && options.layer;
	slice.cropWidth = (options && options.cropWidth);
	slice.cropHeight = (options && options.cropHeight);
	slice.frameDelay = (options && options.frameDelay !== undefined) ? options.frameDelay : 4;
	slice.angle = (options && options.angle);
	slice.alpha = (options && options.alpha) || 1;
	slice.scale = (options && options.scale) || 1;

	// Public Methods
	slice.update = function () {

		if (!paused) {

			// If the slice has an image associated with it
			if (imageResource) {

				// If the sprite is an animation
				if (numberOfFrames > 1) {

					frameCnt += 1;

					// If the current frame is the last frame
					if (curFrameIndex >= numberOfFrames - 1) {

						if (frameCnt >= slice.frameDelay) {

							frameCnt = 0;
							loopIndex += 1;

							if (slice.loop === true || (typeof slice.loop === "number" && loopIndex < slice.loop)) {
								// Reset the frame back to the first frame
								curFrameIndex = 0;
								slice.dirty = true;

							} else {

								if (resetOnComplete) {
									// Reset the frame back to the first frame
									curFrameIndex = 0;
									slice.dirty = true;
								}
								paused = true;
								slice.dispatchEvent("complete");
							}
						}
					} else {

						if (frameCnt >= slice.frameDelay) {
							// Go to the next frame
							curFrameIndex += 1;
							frameCnt = 0;

							slice.dirty = true;
						}
					}
				}
			}
		}

		// Go to the next frame in the animation
	};

	slice.pause = function () {
		paused = true;
	};

	slice.unpause = function () {
		paused = false;
	};

	slice.reset = function () {
		frameCnt = 0;
		curFrameIndex = 0;
		loopIndex = 0;
		slice.dirty = true;
	};

	slice.stop = function () {
		paused = true;
		slice.reset();
	};

	slice.play = function () {

		// If on the last frame then start over
		if (curFrameIndex >= numberOfFrames - 1) {
			slice.stop();
		}
		paused = false;
	};

	slice.render = function () {

		var i, bounds, restoreNeeded, context;

		// Prevent alpha from being negative
		if (slice.alpha < 0) {
			slice.alpha = 0;
		} else if (slice.alpha > 1) {
			slice.alpha = 1;
		}

		if (slice.dirty && slice.visible && slice.alpha !== 0 && slice.cropWidth !== 0 && slice.cropHeight !== 0) {

			// If the slice has an image associated with it
			if (imageResource) {

				context = slice.layer.ctx;

				// Using webGL
				if (slice.layer && slice.layer.webGLEnabled) {

					//context.bindTexture(context.TEXTURE_2D, texture);

					//setBufferData(
					//	slice.x,
					//	slice.y,
					//	slice.cropWidth || slice.width,
					//	slice.cropHeight || slice.height);

					//context.drawArrays(context.TRIANGLES, 0, 6);

					//context.bindTexture(context.TEXTURE_2D, null);

				// Using 2d Canvas
				} else {

					if (slice.angle || slice.alpha !== 1 || slice.colorize) {
						context.save();
						restoreNeeded = true;
					}

					if (slice.alpha !== 1) {
						context.globalAlpha = slice.alpha;
					}

					if (slice.angle) {
						context.translate(slice.x, slice.y);
						context.rotate(slice.angle * Math.PI / 180);
						context.translate(-slice.x, -slice.y);
					}

					if (slice.colorize) {
						if (!tmpCtx) {
							tmpCtx = document.createElement("canvas").getContext("2d");
							tmpCtx.canvas.width = context.canvas.width;
							tmpCtx.canvas.height = context.canvas.height;
						}
						context = tmpCtx;
						context.globalCompositeOperation = "copy";
					}

					// If the sprite is an animation
					if (numberOfFrames > 1) {
						context.drawImage(
							imageResource.image,
							curFrameIndex * slice.width + slice.frameOffsetX,
							slice.frameOffsetY,
							slice.cropWidth || slice.width,
							slice.cropHeight || slice.height,
							slice.x + slice.offsetX,
							slice.y + slice.offsetY,
							slice.cropWidth || slice.width * slice.scale,
							slice.cropHeight || slice.height * slice.scale
						);
					// If the sprite is not an animation
					} else {
						context.drawImage(imageResource.image,
							slice.frameOffsetX,
							slice.frameOffsetY,
							slice.cropWidth || slice.width,
							slice.cropHeight || slice.height,
							slice.x + slice.offsetX,
							slice.y + slice.offsetY,
							slice.cropWidth || slice.width * slice.scale,
							slice.cropHeight || slice.height * slice.scale);
					}

					if (slice.colorize) {
						// Draw the color that should be overlayed over the image
						context.fillStyle = slice.colorize;
						context.globalCompositeOperation = "source-in";
						context.fillRect(slice.x, slice.y, slice.width, slice.height);
						context = slice.layer.ctx; // Change back from the temp context
						context.drawImage(tmpCtx.canvas, 0, 0);
					}

					if (restoreNeeded) {
						context.restore();
					}
				}

				if (drawBounds && context) {
					bounds = slice.getBounds();
					if (!bounds.length) {
						bounds = [bounds];
					}

					context.lineWidth = 4;

					for (i = 0; i < bounds.length; i += 1) {

						if (slice.dragging) {
							context.beginPath();
							context.fillStyle = "rgba(10, 255, 50, 0.4)";
							context.fillRect(bounds[i].x, bounds[i].y, bounds[i].width, bounds[i].height);
							context.closePath();
						} else if (slice.justTapped) {
							context.beginPath();
							context.fillStyle = "rgba(255, 10, 50, 0.4)";
							context.fillRect(bounds[i].x, bounds[i].y, bounds[i].width, bounds[i].height);
							context.closePath();
						} else if (slice.justNotTapped) {
							context.beginPath();
							context.fillStyle = "rgba(255, 10, 255, 0.4)";
							context.fillRect(bounds[i].x, bounds[i].y, bounds[i].width, bounds[i].height);
							context.closePath();
						} else if (slice.justReleased) {
							context.beginPath();
							context.fillStyle = "rgba(125, 10, 255, 0.4)";
							context.fillRect(bounds[i].x, bounds[i].y, bounds[i].width, bounds[i].height);
							context.closePath();
							slice.justReleased = false;
						}

						context.beginPath();
						context.strokeStyle = "rgba(96, 255, 0, 0.5)";
						context.strokeRect(bounds[i].x, bounds[i].y, bounds[i].width, bounds[i].height);
						context.closePath();
					}

					context.beginPath();
					context.arc(slice.x, slice.y, 7, 0, 2 * Math.PI, false);
					context.fillStyle = "rgba(96, 255, 0, 0.5)";
					context.fill();
				}
			}
		}
		slice.dirty = false;
	};

	slice.isPointInside = function (point) {

		var i,
			bounds = slice.getBounds(),
			collision = false;

		if (!point) {
			BLOCKS.warn("slice.isPointInside point is falsy: " + point);
			return;
		}

		if (!bounds.length) {
			bounds = [bounds];
		}

		for (i = 0; i < bounds.length; i += 1) {

			if (point.x >= bounds[i].x && point.x <= bounds[i].x + bounds[i].width && point.y >= bounds[i].y && point.y <= bounds[i].y + bounds[i].height) {

				collision = true;
				break;
			}
		}

		return collision;
	};

	// - boundingRectOnly returns only the bounding rectangle
	slice.getBounds = function (boundingRectOnly) {

		var i, bounds, extraWidth, extraHeight;

		if (boundingRectOnly || (!slice.hotspots && !slice.minHotspot)) {
			bounds =  {
				x: slice.x + slice.offsetX,
				y: slice.y + slice.offsetY,
				width: slice.width,
				height: slice.height
			};
		} else {
			bounds = [];
			if (slice.hotspots) {
				for (i = 0; i < slice.hotspots.length; i += 1) {
					bounds.push({
						x: slice.x + slice.offsetX + slice.hotspots[i].x,
						y: slice.y + slice.offsetY + slice.hotspots[i].y,
						width: slice.hotspots[i].width,
						height: slice.hotspots[i].height
					});
				}
			}
			if (slice.minHotspot) {

				extraWidth = slice.width < slice.minHotspot ? slice.minHotspot - slice.width : 0;
				extraHeight = slice.height < slice.minHotspot ? slice.minHotspot - slice.height : 0;

				bounds.push({
					x: slice.x + slice.offsetX - extraWidth / 2,
					y: slice.y + slice.offsetY - extraHeight / 2,
					width: slice.width + extraWidth,
					height: slice.height + extraHeight
				});
			}
			if (bounds.length === 1) {
				bounds = bounds[0];
			}
		}

		return bounds;
	};

	slice.isRectInside = function (rect) {

		var i, result, bounds;

		if (!rect) {
			BLOCKS.warn("slice.isRectangleInside rect is falsy: " + rect);
			return false;
		}

		bounds = slice.getBounds();
		if (!bounds.length) {
			bounds = [bounds];
		}

		for (i = 0; i < bounds.length; i += 1) {

			if (rect.x + rect.width > bounds[i].x &&
				rect.x < bounds[i].x + bounds[i].width &&
				rect.y + rect.height > bounds[i].y &&
				rect.y < bounds[i].y + bounds[i].height) {

				result = true;
				break;
			}
		}

		return result;
	};

	slice.gotoLastFrame = function () {

		if (curFrameIndex !== numberOfFrames - 1) {
			curFrameIndex = numberOfFrames - 1;
			slice.dirty = true;
		}
	};

	slice.gotoFrame = function (frameIndex) {

		if (curFrameIndex !== frameIndex) {
			curFrameIndex = frameIndex;
			frameCnt = 0;
			slice.dirty = true;
		}
	};

	slice.show = function () {

		if (!slice.visible) {
			slice.dirty = true;
		}
		slice.visible = true;
	};

	slice.hide = function () {

		if (slice.visible) {
			slice.dirty = true;
		}
		slice.visible = false;

	};

	slice.destroy = function () {

		imageResource = null;
		options = null;
		slice = null;
	};

	(function () {

		var image = options.image,
			imageSrc = options.imageSrc || (options.image && options.src),
			imagePreloaded = image ? true : false;

		if (image || imageSrc) {

			imageResource = {
				image: image,
				imageSrc: imageSrc,
				loaded: imagePreloaded
			};

			// If the image is already loaded
			if (imageResource.loaded) {
				onResourceLoaded();
			} else {

				// If there is no image object
				if (!imageResource.image) {
					// Instantiate a new image
					imageResource.image = new Image();
				}
				imageResource.image.addEventListener("load", onResourceLoaded);
				imageResource.image.src = imageResource.imageSrc;
			}
		} else {
			onResourceLoaded();
		}
	}());

	return slice;
};<commit_msg>Made Slice numberOfFrames Property Public<commit_after>/*
Copyright (c) 2013 William Malone (www.williammalone.com)

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

/*global window, document, Image, Float32Array */

var BLOCKS;

if (BLOCKS === undefined) {
	BLOCKS = {};
}

BLOCKS.slice = function (options) {

	"use strict";

	var slice = BLOCKS.eventDispatcher(),

		// Private Properties
		curFrameIndex = 0,
		imageResource,
		paused = false,
		frameCnt = 0,
		resetOnComplete = options && options.resetOnComplete,
		loopIndex = 0,
		texture,
		centerRegistrationPoint = options && options.centerRegistrationPoint,
		drawBounds = false, // This is used for debug only
		tmpCtx, // Used when colorizing

		// Private Methods
		onResourceLoaded = function () {

			// Will be used for webGL enabled contexts
			//if (slice.layer && slice.layer.webGLEnabled) {
			//	prepareWebGLContext(slice.layer.ctx);
			//}

			// Set the sprite dimensions to the image dimensions
			// Note: Divide the width by the number of frames in the sprite sheet if an animation. If the sprite is only an image then the number of frames will be 1.

			if (imageResource) {
				slice.width = imageResource.image.width / slice.numberOfFrames;
				slice.height = imageResource.image.height;
			}

			// If the registration point should be centered
			if (centerRegistrationPoint) {
				slice.offsetX = -slice.width / 2;
				slice.offsetY = -slice.height / 2;
			}
		};

	// Public Properties
	slice.name = (options && options.name !== undefined) ? options.name : undefined;
	slice.width = (options && options.width) || 0;
	slice.height = (options && options.height) || 0;
	slice.x = 0;
	slice.y = 0;
	slice.offsetX = (options && options.offsetX) || 0;
	slice.offsetY = (options && options.offsetY) || 0;
	slice.frameOffsetX = (options && options.frameOffsetX) || 0;
	slice.frameOffsetY = (options && options.frameOffsetY) || 0;
	slice.loop = options && options.loop;
	slice.visible = true;
	slice.dirty = true;
	slice.hotspots = options && options.hotspots;
	slice.minHotspot = options && options.minHotspot;
	slice.layer = options && options.layer;
	slice.cropWidth = (options && options.cropWidth);
	slice.cropHeight = (options && options.cropHeight);
	slice.frameDelay = (options && options.frameDelay !== undefined) ? options.frameDelay : 4;
	slice.numberOfFrames = (options && options.numberOfFrames) || 1;
	slice.angle = (options && options.angle);
	slice.alpha = (options && options.alpha) || 1;
	slice.scale = (options && options.scale) || 1;

	// Public Methods
	slice.update = function () {

		if (!paused) {

			// If the slice has an image associated with it
			if (imageResource) {

				// If the sprite is an animation
				if (slice.numberOfFrames > 1) {

					frameCnt += 1;

					// If the current frame is the last frame
					if (curFrameIndex >= slice.numberOfFrames - 1) {

						if (frameCnt >= slice.frameDelay) {

							frameCnt = 0;
							loopIndex += 1;

							if (slice.loop === true || (typeof slice.loop === "number" && loopIndex < slice.loop)) {
								// Reset the frame back to the first frame
								curFrameIndex = 0;
								slice.dirty = true;

							} else {

								if (resetOnComplete) {
									// Reset the frame back to the first frame
									curFrameIndex = 0;
									slice.dirty = true;
								}
								paused = true;
								slice.dispatchEvent("complete");
							}
						}
					} else {

						if (frameCnt >= slice.frameDelay) {
							// Go to the next frame
							curFrameIndex += 1;
							frameCnt = 0;

							slice.dirty = true;
						}
					}
				}
			}
		}

		// Go to the next frame in the animation
	};

	slice.pause = function () {
		paused = true;
	};

	slice.unpause = function () {
		paused = false;
	};

	slice.reset = function () {
		frameCnt = 0;
		curFrameIndex = 0;
		loopIndex = 0;
		slice.dirty = true;
	};

	slice.stop = function () {
		paused = true;
		slice.reset();
	};

	slice.play = function () {

		// If on the last frame then start over
		if (curFrameIndex >= slice.numberOfFrames - 1) {
			slice.stop();
		}
		paused = false;
	};

	slice.render = function () {

		var i, bounds, restoreNeeded, context;

		// Prevent alpha from being negative
		if (slice.alpha < 0) {
			slice.alpha = 0;
		} else if (slice.alpha > 1) {
			slice.alpha = 1;
		}

		if (slice.dirty && slice.visible && slice.alpha !== 0 && slice.cropWidth !== 0 && slice.cropHeight !== 0) {

			// If the slice has an image associated with it
			if (imageResource) {

				context = slice.layer.ctx;

				// Using webGL
				if (slice.layer && slice.layer.webGLEnabled) {

					//context.bindTexture(context.TEXTURE_2D, texture);

					//setBufferData(
					//	slice.x,
					//	slice.y,
					//	slice.cropWidth || slice.width,
					//	slice.cropHeight || slice.height);

					//context.drawArrays(context.TRIANGLES, 0, 6);

					//context.bindTexture(context.TEXTURE_2D, null);

				// Using 2d Canvas
				} else {

					if (slice.angle || slice.alpha !== 1 || slice.colorize) {
						context.save();
						restoreNeeded = true;
					}

					if (slice.alpha !== 1) {
						context.globalAlpha = slice.alpha;
					}

					if (slice.angle) {
						context.translate(slice.x, slice.y);
						context.rotate(slice.angle * Math.PI / 180);
						context.translate(-slice.x, -slice.y);
					}

					if (slice.colorize) {
						if (!tmpCtx) {
							tmpCtx = document.createElement("canvas").getContext("2d");
							tmpCtx.canvas.width = context.canvas.width;
							tmpCtx.canvas.height = context.canvas.height;
						}
						context = tmpCtx;
						context.globalCompositeOperation = "copy";
					}

					// If the sprite is an animation
					if (slice.numberOfFrames > 1) {
						context.drawImage(
							imageResource.image,
							curFrameIndex * slice.width + slice.frameOffsetX,
							slice.frameOffsetY,
							slice.cropWidth || slice.width,
							slice.cropHeight || slice.height,
							slice.x + slice.offsetX,
							slice.y + slice.offsetY,
							slice.cropWidth || slice.width * slice.scale,
							slice.cropHeight || slice.height * slice.scale
						);
					// If the sprite is not an animation
					} else {
						context.drawImage(imageResource.image,
							slice.frameOffsetX,
							slice.frameOffsetY,
							slice.cropWidth || slice.width,
							slice.cropHeight || slice.height,
							slice.x + slice.offsetX,
							slice.y + slice.offsetY,
							slice.cropWidth || slice.width * slice.scale,
							slice.cropHeight || slice.height * slice.scale);
					}

					if (slice.colorize) {
						// Draw the color that should be overlayed over the image
						context.fillStyle = slice.colorize;
						context.globalCompositeOperation = "source-in";
						context.fillRect(slice.x, slice.y, slice.width, slice.height);
						context = slice.layer.ctx; // Change back from the temp context
						context.drawImage(tmpCtx.canvas, 0, 0);
					}

					if (restoreNeeded) {
						context.restore();
					}
				}

				if (drawBounds && context) {
					bounds = slice.getBounds();
					if (!bounds.length) {
						bounds = [bounds];
					}

					context.lineWidth = 4;

					for (i = 0; i < bounds.length; i += 1) {

						if (slice.dragging) {
							context.beginPath();
							context.fillStyle = "rgba(10, 255, 50, 0.4)";
							context.fillRect(bounds[i].x, bounds[i].y, bounds[i].width, bounds[i].height);
							context.closePath();
						} else if (slice.justTapped) {
							context.beginPath();
							context.fillStyle = "rgba(255, 10, 50, 0.4)";
							context.fillRect(bounds[i].x, bounds[i].y, bounds[i].width, bounds[i].height);
							context.closePath();
						} else if (slice.justNotTapped) {
							context.beginPath();
							context.fillStyle = "rgba(255, 10, 255, 0.4)";
							context.fillRect(bounds[i].x, bounds[i].y, bounds[i].width, bounds[i].height);
							context.closePath();
						} else if (slice.justReleased) {
							context.beginPath();
							context.fillStyle = "rgba(125, 10, 255, 0.4)";
							context.fillRect(bounds[i].x, bounds[i].y, bounds[i].width, bounds[i].height);
							context.closePath();
							slice.justReleased = false;
						}

						context.beginPath();
						context.strokeStyle = "rgba(96, 255, 0, 0.5)";
						context.strokeRect(bounds[i].x, bounds[i].y, bounds[i].width, bounds[i].height);
						context.closePath();
					}

					context.beginPath();
					context.arc(slice.x, slice.y, 7, 0, 2 * Math.PI, false);
					context.fillStyle = "rgba(96, 255, 0, 0.5)";
					context.fill();
				}
			}
		}
		slice.dirty = false;
	};

	slice.isPointInside = function (point) {

		var i,
			bounds = slice.getBounds(),
			collision = false;

		if (!point) {
			BLOCKS.warn("slice.isPointInside point is falsy: " + point);
			return;
		}

		if (!bounds.length) {
			bounds = [bounds];
		}

		for (i = 0; i < bounds.length; i += 1) {

			if (point.x >= bounds[i].x && point.x <= bounds[i].x + bounds[i].width && point.y >= bounds[i].y && point.y <= bounds[i].y + bounds[i].height) {

				collision = true;
				break;
			}
		}

		return collision;
	};

	// - boundingRectOnly returns only the bounding rectangle
	slice.getBounds = function (boundingRectOnly) {

		var i, bounds, extraWidth, extraHeight;

		if (boundingRectOnly || (!slice.hotspots && !slice.minHotspot)) {
			bounds =  {
				x: slice.x + slice.offsetX,
				y: slice.y + slice.offsetY,
				width: slice.width,
				height: slice.height
			};
		} else {
			bounds = [];
			if (slice.hotspots) {
				for (i = 0; i < slice.hotspots.length; i += 1) {
					bounds.push({
						x: slice.x + slice.offsetX + slice.hotspots[i].x,
						y: slice.y + slice.offsetY + slice.hotspots[i].y,
						width: slice.hotspots[i].width,
						height: slice.hotspots[i].height
					});
				}
			}
			if (slice.minHotspot) {

				extraWidth = slice.width < slice.minHotspot ? slice.minHotspot - slice.width : 0;
				extraHeight = slice.height < slice.minHotspot ? slice.minHotspot - slice.height : 0;

				bounds.push({
					x: slice.x + slice.offsetX - extraWidth / 2,
					y: slice.y + slice.offsetY - extraHeight / 2,
					width: slice.width + extraWidth,
					height: slice.height + extraHeight
				});
			}
			if (bounds.length === 1) {
				bounds = bounds[0];
			}
		}

		return bounds;
	};

	slice.isRectInside = function (rect) {

		var i, result, bounds;

		if (!rect) {
			BLOCKS.warn("slice.isRectangleInside rect is falsy: " + rect);
			return false;
		}

		bounds = slice.getBounds();
		if (!bounds.length) {
			bounds = [bounds];
		}

		for (i = 0; i < bounds.length; i += 1) {

			if (rect.x + rect.width > bounds[i].x &&
				rect.x < bounds[i].x + bounds[i].width &&
				rect.y + rect.height > bounds[i].y &&
				rect.y < bounds[i].y + bounds[i].height) {

				result = true;
				break;
			}
		}

		return result;
	};

	slice.gotoLastFrame = function () {

		if (curFrameIndex !== slice.numberOfFrames - 1) {
			curFrameIndex = slice.numberOfFrames - 1;
			slice.dirty = true;
		}
	};

	slice.gotoFrame = function (frameIndex) {

		if (curFrameIndex !== frameIndex) {
			curFrameIndex = frameIndex;
			frameCnt = 0;
			slice.dirty = true;
		}
	};

	slice.show = function () {

		if (!slice.visible) {
			slice.dirty = true;
		}
		slice.visible = true;
	};

	slice.hide = function () {

		if (slice.visible) {
			slice.dirty = true;
		}
		slice.visible = false;

	};

	slice.destroy = function () {

		imageResource = null;
		options = null;
		slice = null;
	};

	(function () {

		var image = options.image,
			imageSrc = options.imageSrc || (options.image && options.src),
			imagePreloaded = image ? true : false;

		if (image || imageSrc) {

			imageResource = {
				image: image,
				imageSrc: imageSrc,
				loaded: imagePreloaded
			};

			// If the image is already loaded
			if (imageResource.loaded) {
				onResourceLoaded();
			} else {

				// If there is no image object
				if (!imageResource.image) {
					// Instantiate a new image
					imageResource.image = new Image();
				}
				imageResource.image.addEventListener("load", onResourceLoaded);
				imageResource.image.src = imageResource.imageSrc;
			}
		} else {
			onResourceLoaded();
		}
	}());

	return slice;
};<|endoftext|>


<commit_before>function Browser(parameters) {

	this.id = window.location.hash.substring(1);
	this.isFirstLoad = true;

	this.isHandleDisplayed = ipcRenderer.sendSync('get-preference', 'show_title_bar');
	this.webPluginsEnabled = ipcRenderer.sendSync('get-preference', 'enable_web_plugins');
	this.frame = document.querySelectorAll('#frame')[0];
	this.dragCount = 0;

	this.view = new View({
		'id' : this.id,
		'onDidFinishLoad' : this.onDidFinishLoad.bind(this),
		'onDOMReady' : this.onDOMReady.bind(this),
		'onPageTitleUpdated' : this.onPageTitleUpdated.bind(this),
		'onConsoleMessage' : this.onConsoleMessage.bind(this)
	});

	this.omnibox = new Omnibox({
		'mode' : 'url',
		'onsubmit' : this.onSubmit.bind(this)
	});

	this.handle = new Handle({

	});

	this.console = new Console({
		'id' : this.id
	});

	this.dragOverlay = document.querySelectorAll('#dragOverlay')[0];
	this.draggingOverlay = false;

	this.resize();

	this.windowHelper = new WindowHelper({
		'id' : this.id
	});

	this.attachEvents();

}

Browser.prototype.attachEvents = function() {

	window.addEventListener('resize', this.resize.bind(this));

	ipcRenderer.on('hideHandle', this.hideHandle.bind(this));
	ipcRenderer.on('showHandle', this.showHandle.bind(this));

	ipcRenderer.on('showOmnibox', this.showOmnibox.bind(this));
	ipcRenderer.on('hideOmnibox', this.hideOmnibox.bind(this));

	ipcRenderer.on('showConsole', this.showConsole.bind(this));
	ipcRenderer.on('hideConsole', this.hideConsole.bind(this));

	ipcRenderer.on('load', this.load.bind(this));
	ipcRenderer.on('reload', this.reload.bind(this));
	ipcRenderer.on('reloadIgnoringCache', this.reloadIgnoringCache.bind(this));

	ipcRenderer.on('toggleDevTools', this.toggleDevTools.bind(this));

	ipcRenderer.on('get_handle_title', this.getHandleTitle.bind(this));

	ipcRenderer.on('recordingBegin', this.hideDragOverlay.bind(this));
	ipcRenderer.on('recordingEnd', this.showDragOverlay.bind(this));

	ipcRenderer.on('enableWebPlugins', this.enableWebPlugins.bind(this));
	ipcRenderer.on('disableWebPlugins', this.disableWebPlugins.bind(this));

	ipcRenderer.on('get-url', function(e) {

		// Reply with url
		ipcRenderer.send('take-screenshot', this.id, this.view.webview.src);

	}.bind(this));

	window.addEventListener('keydown', this.onKeyDown.bind(this));
	window.addEventListener('keyup', this.onKeyUp.bind(this));

	window.addEventListener('blur', this.onBlur.bind(this));
	window.addEventListener('focus', this.onFocus.bind(this));

	this.omnibox.el.ondragover = (e) => {
		e.preventDefault();
	}

	this.omnibox.el.ondragenter = (e) => {

		e.preventDefault();

	}

	this.omnibox.el.ondragleave = (e) => {

		e.preventDefault();

	}

	this.omnibox.el.ondrop = (e) => {

		ipcRenderer.send('open-file', this.id, e.dataTransfer.files[0].path);
		e.preventDefault();

	}

}

Browser.prototype.resize = function() {

	if(this.isHandleDisplayed) {
		this.frame.style.width = window.innerWidth+"px";
		this.frame.style.height = (window.innerHeight - this.handle.el.offsetHeight+1) + 'px';
	}
	else {
		this.frame.style.width = window.innerWidth+"px";
		this.frame.style.height = window.innerHeight+"px";
	}

}

Browser.prototype.onKeyDown = function(e) {

	if(e.altKey && !e.shiftKey && !e.metaKey && !e.ctrlKey) {
		if(ipcRenderer.sendSync('get-preference', 'use_alt_drag') && !ipcRenderer.sendSync('is-fullscreen', this.id)) {
			addClass(this.dragOverlay, 'active');
		}
	}
	else if(e.shiftKey || e.metaKey || e.ctrlKey) {
		removeClass(this.dragOverlay, 'active');
	}

}

Browser.prototype.onKeyUp = function(e) {

	if(!e) var e = window.event;
	if(e.keyCode == 18) {
		// ALT
		removeClass(this.dragOverlay, 'active');
	}

}

Browser.prototype.onSubmit = function(input) {

	console.log('[BROWSER] Submit');

	if(StatusManager.isFrozen) StatusManager.unFreeze();
	this.view.load(input);

}

Browser.prototype.onDOMReady = function() {

	console.log('[BROWSER] DOM Ready');

	if (this.webPluginsEnabled) {
		var url = new URL(this.view.webview.src);
		var host = url.host.replace('www.', '');
		var webPluginsFolder = ipcRenderer.sendSync('get-user-path', 'webPlugins');
		var pluginPath = path.resolve(webPluginsFolder, host + '.js');

		console.log('Looking for plugin:', pluginPath);

		fs.readFile(pluginPath, 'utf8', function(err, contents) {
			if (err) {
				console.log('[PLUGINS] Couldn\'t find plugin for ' + host + ' at ' + pluginPath);
			} else {
				this.view.webview.executeJavaScript(contents);
			}
		}.bind(this));
	}

	this.handle.changeTitle(this.view.getTitle());

}

Browser.prototype.onDidFinishLoad = function() {

	if(this.isFirstLoad) {
		this.isFirstLoad = false;
		ipcRenderer.send('onDidFinishFirstLoad', this.id);
	}

	this.omnibox.hide();

}

Browser.prototype.onPageTitleUpdated = function(newTitle) {
	this.handle.changeTitle(newTitle);
}

Browser.prototype.onConsoleMessage = function(e) {
	this.console.updateMessage(e);
}

Browser.prototype.onFocus = function() {

	this.handle.enable();

}

Browser.prototype.onBlur = function() {

	this.handle.disable();

}

Browser.prototype.hideHandle = function() {
	this.handle.hide();
	this.isHandleDisplayed = false;
	this.resize();
}

Browser.prototype.showHandle = function() {
	this.handle.show();
	this.isHandleDisplayed = true;
	this.resize();
}

Browser.prototype.getHandleTitle = function() {
	return this.handle.getTitle();
}

Browser.prototype.showOmnibox = function() {
	this.omnibox.show();
}

Browser.prototype.hideOmnibox = function() {
	this.omnibox.hide();
}

Browser.prototype.showConsole = function() {
	this.console.show();
}

Browser.prototype.hideConsole = function() {
	this.console.hide();
}

Browser.prototype.enableWebPlugins = function() {
	this.webPluginsEnabled = true;
}

Browser.prototype.disableWebPlugins = function() {
	this.webPluginsEnabled = false;
}

Browser.prototype.load = function(e, url) {
	console.log('[BROWSER] Loading new window url: ', url);
	this.omnibox.hide();
	this.view.load(url);
}

Browser.prototype.reload = function() {
	this.view.webview.reload();
}

Browser.prototype.reloadIgnoringCache = function() {
	if(StatusManager.isFrozen) StatusManager.unFreeze();
	this.view.webview.reloadIgnoringCache();
}

Browser.prototype.toggleDevTools = function() {
	this.view.toggleDevTools();
}

Browser.prototype.hideDragOverlay = function() {

	removeClass(this.dragOverlay, 'invisible');
	addClass(this.dragOverlay, 'invisible');

}

Browser.prototype.showDragOverlay = function() {

	removeClass(this.dragOverlay, 'invisible');

}<commit_msg>Dont wait for everything to load to show view<commit_after>function Browser(parameters) {

	this.id = window.location.hash.substring(1);
	this.isFirstLoad = true;

	this.isHandleDisplayed = ipcRenderer.sendSync('get-preference', 'show_title_bar');
	this.webPluginsEnabled = ipcRenderer.sendSync('get-preference', 'enable_web_plugins');
	this.frame = document.querySelectorAll('#frame')[0];
	this.dragCount = 0;

	this.view = new View({
		'id' : this.id,
		'onDidFinishLoad' : this.onDidFinishLoad.bind(this),
		'onDOMReady' : this.onDOMReady.bind(this),
		'onPageTitleUpdated' : this.onPageTitleUpdated.bind(this),
		'onConsoleMessage' : this.onConsoleMessage.bind(this)
	});

	this.omnibox = new Omnibox({
		'mode' : 'url',
		'onsubmit' : this.onSubmit.bind(this)
	});

	this.handle = new Handle({

	});

	this.console = new Console({
		'id' : this.id
	});

	this.dragOverlay = document.querySelectorAll('#dragOverlay')[0];
	this.draggingOverlay = false;

	this.resize();

	this.windowHelper = new WindowHelper({
		'id' : this.id
	});

	this.attachEvents();

}

Browser.prototype.attachEvents = function() {

	window.addEventListener('resize', this.resize.bind(this));

	ipcRenderer.on('hideHandle', this.hideHandle.bind(this));
	ipcRenderer.on('showHandle', this.showHandle.bind(this));

	ipcRenderer.on('showOmnibox', this.showOmnibox.bind(this));
	ipcRenderer.on('hideOmnibox', this.hideOmnibox.bind(this));

	ipcRenderer.on('showConsole', this.showConsole.bind(this));
	ipcRenderer.on('hideConsole', this.hideConsole.bind(this));

	ipcRenderer.on('load', this.load.bind(this));
	ipcRenderer.on('reload', this.reload.bind(this));
	ipcRenderer.on('reloadIgnoringCache', this.reloadIgnoringCache.bind(this));

	ipcRenderer.on('toggleDevTools', this.toggleDevTools.bind(this));

	ipcRenderer.on('get_handle_title', this.getHandleTitle.bind(this));

	ipcRenderer.on('recordingBegin', this.hideDragOverlay.bind(this));
	ipcRenderer.on('recordingEnd', this.showDragOverlay.bind(this));

	ipcRenderer.on('enableWebPlugins', this.enableWebPlugins.bind(this));
	ipcRenderer.on('disableWebPlugins', this.disableWebPlugins.bind(this));

	ipcRenderer.on('get-url', function(e) {

		// Reply with url
		ipcRenderer.send('take-screenshot', this.id, this.view.webview.src);

	}.bind(this));

	window.addEventListener('keydown', this.onKeyDown.bind(this));
	window.addEventListener('keyup', this.onKeyUp.bind(this));

	window.addEventListener('blur', this.onBlur.bind(this));
	window.addEventListener('focus', this.onFocus.bind(this));

	this.omnibox.el.ondragover = (e) => {
		e.preventDefault();
	}

	this.omnibox.el.ondragenter = (e) => {

		e.preventDefault();

	}

	this.omnibox.el.ondragleave = (e) => {

		e.preventDefault();

	}

	this.omnibox.el.ondrop = (e) => {

		ipcRenderer.send('open-file', this.id, e.dataTransfer.files[0].path);
		e.preventDefault();

	}

}

Browser.prototype.resize = function() {

	if(this.isHandleDisplayed) {
		this.frame.style.width = window.innerWidth+"px";
		this.frame.style.height = (window.innerHeight - this.handle.el.offsetHeight+1) + 'px';
	}
	else {
		this.frame.style.width = window.innerWidth+"px";
		this.frame.style.height = window.innerHeight+"px";
	}

}

Browser.prototype.onKeyDown = function(e) {

	if(e.altKey && !e.shiftKey && !e.metaKey && !e.ctrlKey) {
		if(ipcRenderer.sendSync('get-preference', 'use_alt_drag') && !ipcRenderer.sendSync('is-fullscreen', this.id)) {
			addClass(this.dragOverlay, 'active');
		}
	}
	else if(e.shiftKey || e.metaKey || e.ctrlKey) {
		removeClass(this.dragOverlay, 'active');
	}

}

Browser.prototype.onKeyUp = function(e) {

	if(!e) var e = window.event;
	if(e.keyCode == 18) {
		// ALT
		removeClass(this.dragOverlay, 'active');
	}

}

Browser.prototype.onSubmit = function(input) {

	console.log('[BROWSER] Submit');

	if(StatusManager.isFrozen) StatusManager.unFreeze();
	this.view.load(input);
	this.omnibox.hide();

}

Browser.prototype.onDOMReady = function() {

	console.log('[BROWSER] DOM Ready');

	if (this.webPluginsEnabled) {
		var url = new URL(this.view.webview.src);
		var host = url.host.replace('www.', '');
		var webPluginsFolder = ipcRenderer.sendSync('get-user-path', 'webPlugins');
		var pluginPath = path.resolve(webPluginsFolder, host + '.js');

		console.log('Looking for plugin:', pluginPath);

		fs.readFile(pluginPath, 'utf8', function(err, contents) {
			if (err) {
				console.log('[PLUGINS] Couldn\'t find plugin for ' + host + ' at ' + pluginPath);
			} else {
				this.view.webview.executeJavaScript(contents);
			}
		}.bind(this));
	}

	this.handle.changeTitle(this.view.getTitle());

}

Browser.prototype.onDidFinishLoad = function() {

	if(this.isFirstLoad) {
		this.isFirstLoad = false;
		ipcRenderer.send('onDidFinishFirstLoad', this.id);
	}

}

Browser.prototype.onPageTitleUpdated = function(newTitle) {
	this.handle.changeTitle(newTitle);
}

Browser.prototype.onConsoleMessage = function(e) {
	this.console.updateMessage(e);
}

Browser.prototype.onFocus = function() {

	this.handle.enable();

}

Browser.prototype.onBlur = function() {

	this.handle.disable();

}

Browser.prototype.hideHandle = function() {
	this.handle.hide();
	this.isHandleDisplayed = false;
	this.resize();
}

Browser.prototype.showHandle = function() {
	this.handle.show();
	this.isHandleDisplayed = true;
	this.resize();
}

Browser.prototype.getHandleTitle = function() {
	return this.handle.getTitle();
}

Browser.prototype.showOmnibox = function() {
	this.omnibox.show();
}

Browser.prototype.hideOmnibox = function() {
	this.omnibox.hide();
}

Browser.prototype.showConsole = function() {
	this.console.show();
}

Browser.prototype.hideConsole = function() {
	this.console.hide();
}

Browser.prototype.enableWebPlugins = function() {
	this.webPluginsEnabled = true;
}

Browser.prototype.disableWebPlugins = function() {
	this.webPluginsEnabled = false;
}

Browser.prototype.load = function(e, url) {
	console.log('[BROWSER] Loading new window url: ', url);
	this.omnibox.hide();
	this.view.load(url);
}

Browser.prototype.reload = function() {
	this.view.webview.reload();
}

Browser.prototype.reloadIgnoringCache = function() {
	if(StatusManager.isFrozen) StatusManager.unFreeze();
	this.view.webview.reloadIgnoringCache();
}

Browser.prototype.toggleDevTools = function() {
	this.view.toggleDevTools();
}

Browser.prototype.hideDragOverlay = function() {

	removeClass(this.dragOverlay, 'invisible');
	addClass(this.dragOverlay, 'invisible');

}

Browser.prototype.showDragOverlay = function() {

	removeClass(this.dragOverlay, 'invisible');

}<|endoftext|>


<commit_before>import {elt} from "../dom"
import insertCSS from "insert-css"

const prefix = "ProseMirror-tooltip"

export class Tooltip {
  constructor(pm, dir) {
    this.pm = pm
    this.dir = dir || "above"
    this.knownSizes = Object.create(null)
    this.pointer = pm.wrapper.appendChild(elt("div", {class: prefix + "-pointer-" + this.dir + " " + prefix + "-pointer"}))
    this.pointerWidth = this.pointerHeight = null
    this.dom = pm.wrapper.appendChild(elt("div", {class: prefix}))
    this.dom.addEventListener("transitionend", () => {
      if (this.dom.style.opacity == "0")
        this.dom.style.display = this.pointer.style.display = ""
    })

    this.open = false
    this.lastLeft = this.lastRight = null
  }

  detach() {
    this.dom.parentNode.removeChild(this.dom)
    this.pointer.parentNode.removeChild(this.pointer)
  }

  getSize(type, node) {
    let known = type && this.knownSizes[type]
    if (!known) {
      let wrap = this.pm.wrapper.appendChild(elt("div", {class: prefix}, node))
      wrap.style.display = "block"
      known = {width: wrap.offsetWidth, height: wrap.offsetHeight}
      if (type) this.knownSizes[type] = known
      wrap.parentNode.removeChild(wrap)
    }
    return known
  }

  show(type, node, pos) {
    if (this.pm.mod.tooltip && this.pm.mod.tooltip != this)
      this.pm.mod.tooltip.close()
    this.pm.mod.tooltip = this

    let left = this.lastLeft = pos ? pos.left : this.lastLeft
    let top = this.lastTop = pos ? pos.top : this.lastTop

    let size = this.getSize(type, node)

    let around = this.pm.wrapper.getBoundingClientRect()

    for (let child = this.dom.firstChild, next; child; child = next) {
      next = child.nextSibling
      if (child != this.pointer) this.dom.removeChild(child)
    }
    this.dom.appendChild(node)

    this.dom.style.display = this.pointer.style.display = "block"

    if (this.pointerWidth == null) {
      this.pointerWidth = this.pointer.offsetWidth - 1
      this.pointerHeight = this.pointer.offsetHeight - 1
    }

    this.dom.style.width = size.width + "px"
    this.dom.style.height = size.height + "px"

    const margin = 5
    if (this.dir == "above" || this.dir == "below") {
      let tipLeft = Math.max(0, Math.min(left - size.width / 2, window.innerWidth - size.width))
      this.dom.style.left = (tipLeft - around.left) + "px"
      this.pointer.style.left = (left - around.left - this.pointerWidth / 2) + "px"
      if (this.dir == "above") {
        let tipTop = top - around.top - margin - this.pointerHeight - size.height
        this.dom.style.top = tipTop + "px"
        this.pointer.style.top = (tipTop + size.height) + "px"
      } else { // below
        let tipTop = top - around.top + margin
        this.pointer.style.top = tipTop + "px"
        this.dom.style.top = (tipTop + this.pointerHeight) + "px"
      }
    } else { // left/right
      this.dom.style.top = (top - around.top - size.height / 2) + "px"
      this.pointer.style.top = (top - this.pointerHeight / 2 - around.top) + "px"
      if (this.dir == "left") {
        let pointerLeft = left - around.left - margin - this.pointerWidth
        this.dom.style.left = (pointerLeft - size.width) + "px"
        this.pointer.style.left = pointerLeft + "px"
      } else { // right
        let pointerLeft = left - around.left + margin
        this.dom.style.left = (pointerLeft + this.pointerWidth) + "px"
        this.pointer.style.left = pointerLeft + "px"
      }
    }

    getComputedStyle(this.dom).opacity
    getComputedStyle(this.pointer).opacity
    this.dom.style.opacity = this.pointer.style.opacity = 1
    this.open = true
  }

  close() {
    if (this.open) {
      this.open = false
      if (this.pm.mod.tooltip == this) this.pm.mod.tooltip = null
      this.dom.style.opacity = this.pointer.style.opacity = 0
    }
  }
}

insertCSS(`

.ProseMirror-tooltip {
  position: absolute;
  display: none;
  box-sizing: border-box;
  -moz-box-sizing: border- box;
  overflow: hidden;

  -webkit-transition: width 0.4s ease-out, height 0.4s ease-out, left 0.4s ease-out, top 0.4s ease-out, opacity 0.2s;
  -moz-transition: width 0.4s ease-out, height 0.4s ease-out, left 0.4s ease-out, top 0.4s ease-out, opacity 0.2s;
  transition: width 0.4s ease-out, height 0.4s ease-out, left 0.4s ease-out, top 0.4s ease-out, opacity 0.2s;
  opacity: 0;

  border-radius: 5px;
  padding: 5px 7px;
  margin: 0;
  background: #333;
  color: white;

  z-index: 5;
}

.ProseMirror-tooltip-pointer {
  content: "";
  position: absolute;
  display: none;
  width: 0; height: 0;

  -webkit-transition: left 0.4s ease-out, top 0.4s ease-out, opacity 0.2s;
  -moz-transition: left 0.4s ease-out, top 0.4s ease-out, opacity 0.2s;
  transition: left 0.4s ease-out, top 0.4s ease-out, opacity 0.2s;
  opacity: 0;

  z-index: 5;
}

.ProseMirror-tooltip-pointer-above {
  border-left: 6px solid transparent;
  border-right: 6px solid transparent;
  border-top: 6px solid #333;
}

.ProseMirror-tooltip-pointer-below {
  border-left: 6px solid transparent;
  border-right: 6px solid transparent;
  border-bottom: 6px solid #333;
}

.ProseMirror-tooltip-pointer-right {
  border-top: 6px solid transparent;
  border-bottom: 6px solid transparent;
  border-right: 6px solid #333;
}

.ProseMirror-tooltip-pointer-left {
  border-top: 6px solid transparent;
  border-bottom: 6px solid transparent;
  border-left: 6px solid #333;
}

.ProseMirror-tooltip input[type="text"],
.ProseMirror-tooltip textarea {
  background: #555;
  color: white;
  border: none;
  outline: none;
}

.ProseMirror-tooltip input[type="text"] {
  padding: 0 4px;
}

`)
<commit_msg>Start on new menu implementation<commit_after>import {elt} from "../dom"
import insertCSS from "insert-css"

const prefix = "ProseMirror-tooltip"

export class Tooltip {
  constructor(pm, dir) {
    this.pm = pm
    this.dir = dir || "above"
    this.pointer = pm.wrapper.appendChild(elt("div", {class: prefix + "-pointer-" + this.dir + " " + prefix + "-pointer"}))
    this.pointerWidth = this.pointerHeight = null
    this.dom = pm.wrapper.appendChild(elt("div", {class: prefix}))
    this.dom.addEventListener("transitionend", () => {
      if (this.dom.style.opacity == "0")
        this.dom.style.display = this.pointer.style.display = ""
    })

    this.open = false
    this.lastLeft = this.lastRight = null
  }

  detach() {
    this.dom.parentNode.removeChild(this.dom)
    this.pointer.parentNode.removeChild(this.pointer)
  }

  getSize(node) {
    let wrap = this.pm.wrapper.appendChild(elt("div", {
      class: prefix,
      style: "display: block; position: absolute"
    }, node))
    let size = {width: wrap.offsetWidth, height: wrap.offsetHeight}
    wrap.parentNode.removeChild(wrap)
    return size
  }

  show(node, pos) {
    if (this.pm.mod.tooltip && this.pm.mod.tooltip != this)
      this.pm.mod.tooltip.close()
    this.pm.mod.tooltip = this

    let left = this.lastLeft = pos ? pos.left : this.lastLeft
    let top = this.lastTop = pos ? pos.top : this.lastTop

    let size = this.getSize(node)

    let around = this.pm.wrapper.getBoundingClientRect()

    for (let child = this.dom.firstChild, next; child; child = next) {
      next = child.nextSibling
      if (child != this.pointer) this.dom.removeChild(child)
    }
    this.dom.appendChild(node)

    this.dom.style.display = this.pointer.style.display = "block"

    if (this.pointerWidth == null) {
      this.pointerWidth = this.pointer.offsetWidth - 1
      this.pointerHeight = this.pointer.offsetHeight - 1
    }

    this.dom.style.width = size.width + "px"
    this.dom.style.height = size.height + "px"

    const margin = 5
    if (this.dir == "above" || this.dir == "below") {
      let tipLeft = Math.max(0, Math.min(left - size.width / 2, window.innerWidth - size.width))
      this.dom.style.left = (tipLeft - around.left) + "px"
      this.pointer.style.left = (left - around.left - this.pointerWidth / 2) + "px"
      if (this.dir == "above") {
        let tipTop = top - around.top - margin - this.pointerHeight - size.height
        this.dom.style.top = tipTop + "px"
        this.pointer.style.top = (tipTop + size.height) + "px"
      } else { // below
        let tipTop = top - around.top + margin
        this.pointer.style.top = tipTop + "px"
        this.dom.style.top = (tipTop + this.pointerHeight) + "px"
      }
    } else { // left/right
      this.dom.style.top = (top - around.top - size.height / 2) + "px"
      this.pointer.style.top = (top - this.pointerHeight / 2 - around.top) + "px"
      if (this.dir == "left") {
        let pointerLeft = left - around.left - margin - this.pointerWidth
        this.dom.style.left = (pointerLeft - size.width) + "px"
        this.pointer.style.left = pointerLeft + "px"
      } else { // right
        let pointerLeft = left - around.left + margin
        this.dom.style.left = (pointerLeft + this.pointerWidth) + "px"
        this.pointer.style.left = pointerLeft + "px"
      }
    }

    getComputedStyle(this.dom).opacity
    getComputedStyle(this.pointer).opacity
    this.dom.style.opacity = this.pointer.style.opacity = 1
    this.open = true
  }

  close() {
    if (this.open) {
      this.open = false
      if (this.pm.mod.tooltip == this) this.pm.mod.tooltip = null
      this.dom.style.opacity = this.pointer.style.opacity = 0
    }
  }
}

insertCSS(`

.ProseMirror-tooltip {
  position: absolute;
  display: none;
  box-sizing: border-box;
  -moz-box-sizing: border- box;
  overflow: hidden;

  -webkit-transition: width 0.4s ease-out, height 0.4s ease-out, left 0.4s ease-out, top 0.4s ease-out, opacity 0.2s;
  -moz-transition: width 0.4s ease-out, height 0.4s ease-out, left 0.4s ease-out, top 0.4s ease-out, opacity 0.2s;
  transition: width 0.4s ease-out, height 0.4s ease-out, left 0.4s ease-out, top 0.4s ease-out, opacity 0.2s;
  opacity: 0;

  border-radius: 5px;
  padding: 5px 7px;
  margin: 0;
  background: #333;
  color: white;

  z-index: 5;
}

.ProseMirror-tooltip-pointer {
  content: "";
  position: absolute;
  display: none;
  width: 0; height: 0;

  -webkit-transition: left 0.4s ease-out, top 0.4s ease-out, opacity 0.2s;
  -moz-transition: left 0.4s ease-out, top 0.4s ease-out, opacity 0.2s;
  transition: left 0.4s ease-out, top 0.4s ease-out, opacity 0.2s;
  opacity: 0;

  z-index: 5;
}

.ProseMirror-tooltip-pointer-above {
  border-left: 6px solid transparent;
  border-right: 6px solid transparent;
  border-top: 6px solid #333;
}

.ProseMirror-tooltip-pointer-below {
  border-left: 6px solid transparent;
  border-right: 6px solid transparent;
  border-bottom: 6px solid #333;
}

.ProseMirror-tooltip-pointer-right {
  border-top: 6px solid transparent;
  border-bottom: 6px solid transparent;
  border-right: 6px solid #333;
}

.ProseMirror-tooltip-pointer-left {
  border-top: 6px solid transparent;
  border-bottom: 6px solid transparent;
  border-left: 6px solid #333;
}

.ProseMirror-tooltip input[type="text"],
.ProseMirror-tooltip textarea {
  background: #555;
  color: white;
  border: none;
  outline: none;
}

.ProseMirror-tooltip input[type="text"] {
  padding: 0 4px;
}

`)
<|endoftext|>


<commit_before>'use strict'

const fs = require('fs')
const express = require('express')
const Jimp = require('jimp')
const os = require('os')
const https = require('https')
const chalk = require('chalk')
const shortid = require('shortid')
const multer = require('multer')
const upload = multer()
const svg2png = require('svg2png')

let app = express()
app.set('trust proxy', true)

// root, welcome page
app.get('/', function(req, res) {
	res.sendFile(__dirname + '/public/index.html')
})

// upload an image form
app.get('/upload', function(req, res) {
	res.sendFile(__dirname + '/public/upload.html')
})

// the main attraction
app.post('/upload', upload.single('file'), function(req, res) {
	if(req.file.mimetype == 'image/svg+xml') {
		// svg uploads
		svg2png(req.file.buffer, {
			width: 640,
			height: 720
		}).then(function(buffer) {
			req.file.buffer = buffer
			fileUpload(req, res)
		}).catch(function(e) {
			console.log(`[  ${chalk.red.bold('err!')}  ] ${e}`)
			res.redirect('/upload/fail')
		})
	} else {
		// png, jpeg, bmp uploads
		fileUpload(req, res)
	}
})

function fileUpload(req, res) {
	let id = shortid.generate()
	Jimp.read(req.file.buffer).then(function(img) {
		img.contain(640, 720) // fit to scratch forums max image size
		img.autocrop() // crop same-color borders from image (if any)

		img.write(__dirname + '/uploads/' + id + '.png', function(e) {
			if(e) {
				console.log(`[  ${chalk.red.bold('err!')}  ] ${e}`)
				res.redirect('/upload/fail')
			} else res.redirect('/' + id)
		})
	}).catch(function(e) {
		console.log(`[  ${chalk.red.bold('err!')}  ] ${e}`)
		res.redirect('/upload/fail')
	})
}

// get and display raw image
app.get('/:id', function(req, res) {
	let file = __dirname + `/uploads/${req.params.id}.png`

	// only allow displaying on Scratch or OpenSprites
	if(os.hostname() == 'opensprites.org') {
		if(req.get('host') !== 'scratch.mit.edu' || req.get('host') !== 'opensprites.org') {
			res.sendFile(__dirname + '/public/404.html')
		}
	}

	fs.stat(file, function(err, stat) {
		if(err) res.sendFile(__dirname + '/public/404.html')
		else res.sendFile(file)
	})
})

app.use('/dist', express.static('dist'))
app.use(express.static('public'))

app.get('*', function(req, res) {
	res.sendFile(__dirname + '/public/404.html')
})

// ssl for opensprites.org *only*
if(os.hostname() == 'opensprites.org') {
	https.createServer({
		key: fs.readFileSync('/home/admin/conf/web/ssl.opensprites.org.key'),
		cert: fs.readFileSync('/home/admin/conf/web/ssl.opensprites.org.crt')
	}, app).listen(3000, function() {
		console.log('[  ----  ] ' + chalk.blue('Listening on ' + chalk.bold('https://opensprites.org:3000') + '...'))
	})
} else {
	app.listen(3000, function() {
		console.log('[  ----  ] ' + chalk.blue('Listening on ' + chalk.bold('localhost:3000') + '...'))
	})
}
<commit_msg>// hotfix++<commit_after>'use strict'

const fs = require('fs')
const express = require('express')
const Jimp = require('jimp')
const os = require('os')
const https = require('https')
const chalk = require('chalk')
const shortid = require('shortid')
const multer = require('multer')
const upload = multer()
const svg2png = require('svg2png')

fs.makedirSync(__dirname + '/uploads')

let app = express()
app.set('trust proxy', true)

// root, welcome page
app.get('/', function(req, res) {
	res.sendFile(__dirname + '/public/index.html')
})

// upload an image form
app.get('/upload', function(req, res) {
	res.sendFile(__dirname + '/public/upload.html')
})

// the main attraction
app.post('/upload', upload.single('file'), function(req, res) {
	if(req.file.mimetype == 'image/svg+xml') {
		// svg uploads
		svg2png(req.file.buffer, {
			width: 640,
			height: 720
		}).then(function(buffer) {
			req.file.buffer = buffer
			fileUpload(req, res)
		}).catch(function(e) {
			console.log(`[  ${chalk.red.bold('err!')}  ] ${e}`)
			res.redirect('/upload/fail')
		})
	} else {
		// png, jpeg, bmp uploads
		fileUpload(req, res)
	}
})

function fileUpload(req, res) {
	let id = shortid.generate()
	Jimp.read(req.file.buffer).then(function(img) {
		img.contain(640, 720) // fit to scratch forums max image size
		img.autocrop() // crop same-color borders from image (if any)

		img.write(__dirname + '/uploads/' + id + '.png', function(e) {
			if(e) {
				console.log(`[  ${chalk.red.bold('err!')}  ] ${e}`)
				res.redirect('/upload/fail')
			} else res.redirect('/' + id)
		})
	}).catch(function(e) {
		console.log(`[  ${chalk.red.bold('err!')}  ] ${e}`)
		res.redirect('/upload/fail')
	})
}

// get and display raw image
app.get('/:id', function(req, res) {
	let file = __dirname + `/uploads/${req.params.id}.png`

	// only allow displaying on Scratch or OpenSprites
	if(os.hostname() == 'opensprites.org') {
		if(req.get('host') !== 'scratch.mit.edu' || req.get('host') !== 'opensprites.org') {
			res.sendFile(__dirname + '/public/404.html')
		}
	}

	fs.stat(file, function(err, stat) {
		if(err) res.sendFile(__dirname + '/public/404.html')
		else res.sendFile(file)
	})
})

app.use('/dist', express.static('dist'))
app.use(express.static('public'))

app.get('*', function(req, res) {
	res.sendFile(__dirname + '/public/404.html')
})

// ssl for opensprites.org *only*
if(os.hostname() == 'opensprites.org') {
	https.createServer({
		key: fs.readFileSync('/home/admin/conf/web/ssl.opensprites.org.key'),
		cert: fs.readFileSync('/home/admin/conf/web/ssl.opensprites.org.crt')
	}, app).listen(3000, function() {
		console.log('[  ----  ] ' + chalk.blue('Listening on ' + chalk.bold('https://opensprites.org:3000') + '...'))
	})
} else {
	app.listen(3000, function() {
		console.log('[  ----  ] ' + chalk.blue('Listening on ' + chalk.bold('localhost:3000') + '...'))
	})
}
<|endoftext|>


<commit_before>exports.path = function () {};
<commit_msg>add object utils methods<commit_after>/**
 * Get a value from a property "path" (dot.notation).
 * path('Object.key.key.value', {'key': {'key': {'value': 123}}});
 *
 * @public
 * @param {string} The path in "dot" notation.
 * @param {array} The data objects, which are used to search the path.
 */
exports.path = function getPathValue (path, object) {

    if (!path || !object) {
        return;
    }

    // prepare path
    path = path.split('.');

    // find keys in paths or return
    for (var i = 0; i < path.length; ++i) {
        if ((object = object[path[i]]) === undefined) {
            return;
        }
    }

    return object;
};

/**
 * Create a flat object {key1: {key2: "value"}} => {"key1.key2": "value"}
 *
 * @public
 * @param {string} The object, which is flattened.
 */
exports.flat = function (object) {
    var output = {};
    var value;
    var newKey;

    // recusrive handler
    function step(obj, prev) {
        for (var key in obj) {
            value = obj[key];
            newKey = prev + key;

            if (typeof value === 'object' && value !== null && !Array.isArray(value)) {

                if (Object.keys(value).length) {
                    step(value, newKey + '.');
                    continue;
                }
            }

            output[newKey] = value;
        }
    }

    // start recursive loop
    step(object, '');

    return output;
};

/**
 * Unflatten dot-notation keys {"key1.key2": "value"} => {key1: {key2: "value"}}
 *
 * @public
 * @param {string} The object, which is unflattened.
 */
exports.deep = function (object) {
    var result = {};
    var parentObj = result;
    var key;
    var subkeys;
    var subkey;
    var last;
    var keys = Object.keys(object);

    for (var i = 0; i < keys.length; ++i) {

        key = keys[i];
        subkeys = key.split('.');
        last = subkeys.pop();

        for (var ii = 0; ii < subkeys.length; ++ii) {
            subkey = subkeys[ii];
            parentObj[subkey] = parentObj[subkey] === undefined ? ((subkeys[ii + 1] || last) === "0" ? [] : {}) : parentObj[subkey];
            parentObj = parentObj[subkey];
        }

        parentObj[last] = object[key];
        parentObj = result;
    }

    return result;
};
<|endoftext|>