<commit_before>//globals
var nick,
chat_init = false;
var chan = io.connect(window.location.origin+'/chat');
var room = window.location.pathname.slice(6);
function start(){
	elem("nickform").addEventListener("submit", function(event){
		event.stopPropagation();
		event.preventDefault();
		nick = elem("nick").value;
		chan.emit('nick', nick);
		elem("overlay").classList.add("hide");
		chat.start();
	});
	elem("chanform").addEventListener("submit", function(event){
		event.stopPropagation();
		event.preventDefault();
		var title = elem("create_title").value;
		var pass = elem("create_pass").value;
	});
}

//this is nasty and seriously insecure. in the future everyone will log in with (fb,g+,reddit,twitter,yourmom) to ensure the person you add is who they say they are. mimmicing irc is nice, but really isnt what this is about.
var chat = {
	start : function(){
		chat_init = true;
		console.log(chat_init)
		if (typeof nick != "undefined" && chat_init === true) {
			chan.emit('sub', {"room":room});
			chan.emit('users', {"room":room});
			chan.on('news', function (data) {
				console.log(data);
			});
			chan.on('sys', function(data){
				if (data.users){
					var message = 'users connected: ';
					for (var i = 0; i < data.users.length; i++) {
						message += data.users[i].nick+', ';
					}
					chat.sysmsg(message);
				} else if(data.msg){
					chat.sysmsg(data.msg);
				}
			});

			chan.on('message', function(data){
				console.log("hmm");
				if (chat_init === true){
					console.log(data);
					var time = new Date();
					time = time.toLocaleTimeString('en-US', {hour:"numeric", minute:"numeric"});
					elem("log").insertAdjacentHTML('beforeend', '' + time +''+ data.nick +': '+ data.msg + '');
					render("log");
					scroll();
				}
			});
		}
	},
	sendmessage : function(msg){
		if (typeof nick != "undefined" && chat_init === true) {
			chan.emit('message', {'msg': msg, 'nick':nick, 'room':'test'});
			var time = new Date();
			time = time.toLocaleTimeString('en-US', {hour:"numeric", minute:"numeric"});
			elem("log").insertAdjacentHTML('beforeend', '' + time +''+ nick +': '+ msg + '');
			render("log");
			scroll();
		}
	},
	sysmsg : function(msg){
		elem("log").insertAdjacentHTML('beforeend', 'sys: '+ msg + '');
		scroll();
	}
};

//utility functions.
function math(event){
	if (AMnames.length==0) initSymbols();//"symbolizes" math
	var input = document.getElementById("in").value;
	var out = document.getElementById("out");
	if (event.keyCode === 13 && event.shiftKey === false) {
		input = input.replace(/\n/g, '
');
		elem("out").innerHTML = "";
		elem("in").value = "";
		chat.sendmessage(input);
		return false;
	} else{
		input = input.replace(/\n/g, '
');
		out.innerHTML = input;
		AMprocessNode(out);
	}
}

function render(elem){
	if (AMnames.length==0) initSymbols();//"symbolizes" math
	var out = document.getElementById(elem);
	AMprocessNode(out);//renders basic math
}

function elem(el){
	return document.getElementById(el);
}
function scroll(){
	var scroll = elem("log").scrollHeight - elem("log").offsetHeight;
	var scrolltop = elem("log").scrollTop;
	if (scrolltop < scroll - 100 && scroll > 100) {
	} else{
		elem("log").scrollTop = scroll;
	}
}
//end utility functions

//kick off the party when the DOM is ready.
document.addEventListener("DOMContentLoaded", function(event) {
	//and now a bunch of render calls so the basic help doesnt look SUPER DUMB
	render("demo_eq");
	render("demo_sy");
	//go go
	start();
});<commit_msg>tfw: remember to change almost all of your test<commit_after>//globals
var nick,
chat_init = false;
var chan = io.connect(window.location.origin+'/chat');
var room = window.location.pathname.slice(6);
function start(){
	elem("nickform").addEventListener("submit", function(event){
		event.stopPropagation();
		event.preventDefault();
		nick = elem("nick").value;
		chan.emit('nick', nick);
		elem("overlay").classList.add("hide");
		chat.start();
	});
}

//this is nasty and seriously insecure. in the future everyone will log in with (fb,g+,reddit,twitter,yourmom) to ensure the person you add is who they say they are. mimmicing irc is nice, but really isnt what this is about.
var chat = {
	start : function(){
		chat_init = true;
		console.log(chat_init)
		if (typeof nick != "undefined" && chat_init === true) {
			chan.emit('sub', {"room":room});
			chan.emit('users', {"room":room});
			chan.on('news', function (data) {
				console.log(data);
			});
			chan.on('sys', function(data){
				if (data.users){
					var message = 'users connected: ';
					for (var i = 0; i < data.users.length; i++) {
						message += data.users[i].nick+', ';
					}
					chat.sysmsg(message);
				} else if(data.msg){
					chat.sysmsg(data.msg);
				}
			});

			chan.on('message', function(data){
				console.log("hmm");
				if (chat_init === true){
					console.log(data);
					var time = new Date();
					time = time.toLocaleTimeString('en-US', {hour:"numeric", minute:"numeric"});
					elem("log").insertAdjacentHTML('beforeend', '' + time +''+ data.nick +': '+ data.msg + '');
					render("log");
					scroll();
				}
			});
		}
	},
	sendmessage : function(msg){
		if (typeof nick != "undefined" && chat_init === true) {
			chan.emit('message', {'msg': msg, 'nick':nick, 'room':room});
			var time = new Date();
			time = time.toLocaleTimeString('en-US', {hour:"numeric", minute:"numeric"});
			elem("log").insertAdjacentHTML('beforeend', '' + time +''+ nick +': '+ msg + '');
			render("log");
			scroll();
		}
	},
	sysmsg : function(msg){
		elem("log").insertAdjacentHTML('beforeend', 'sys: '+ msg + '');
		scroll();
	}
};

//utility functions.
function math(event){
	if (AMnames.length==0) initSymbols();//"symbolizes" math
	var input = document.getElementById("in").value;
	var out = document.getElementById("out");
	if (event.keyCode === 13 && event.shiftKey === false) {
		input = input.replace(/\n/g, '
');
		elem("out").innerHTML = "";
		elem("in").value = "";
		chat.sendmessage(input);
		return false;
	} else{
		input = input.replace(/\n/g, '
');
		out.innerHTML = input;
		AMprocessNode(out);
	}
}

function render(elem){
	if (AMnames.length==0) initSymbols();//"symbolizes" math
	var out = document.getElementById(elem);
	AMprocessNode(out);//renders basic math
}

function elem(el){
	return document.getElementById(el);
}
function scroll(){
	var scroll = elem("log").scrollHeight - elem("log").offsetHeight;
	var scrolltop = elem("log").scrollTop;
	if (scrolltop < scroll - 100 && scroll > 100) {
	} else{
		elem("log").scrollTop = scroll;
	}
}
//end utility functions

//kick off the party when the DOM is ready.
document.addEventListener("DOMContentLoaded", function(event) {
	//and now a bunch of render calls so the basic help doesnt look SUPER DUMB
	render("demo_eq");
	render("demo_sy");
	//go go
	start();
});<|endoftext|>


<commit_before>// Copyright (c) 2012-2016, Matt Godbolt
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

require.config({
    paths: {
        bootstrap: 'ext/bootstrap/dist/js/bootstrap',
        jquery: 'ext/jquery/dist/jquery',
        underscore: 'ext/underscore/underscore',
        goldenlayout: 'ext/golden-layout/dist/goldenlayout',
        selectize: 'ext/selectize/dist/js/selectize',
        sifter: 'ext/sifter/sifter',
        microplugin: 'ext/microplugin/src/microplugin',
        events: 'ext/eventEmitter/EventEmitter',
        lzstring: 'ext/lz-string/libs/lz-string',
        clipboard: 'ext/clipboard/dist/clipboard',
        'raven-js': 'ext/raven-js/dist/raven'
    },
    packages: [{
        name: "codemirror",
        location: "ext/codemirror",
        main: "lib/codemirror"
    }],
    shim: {
        underscore: {exports: '_'},
        bootstrap: ['jquery']
    }
});

define(function (require) {
    "use strict";
    require('bootstrap');
    var analytics = require('analytics');
    var sharing = require('sharing');
    var _ = require('underscore');
    var $ = require('jquery');
    var GoldenLayout = require('goldenlayout');
    var compiler = require('compiler');
    var editor = require('editor');
    var url = require('url');
    var clipboard = require('clipboard');
    var Hub = require('hub');
    var shortenURL = require('urlshorten-google');
    var Raven = require('raven-js');

    analytics.initialise();
    sharing.initialise();

    var options = require('options');
    $('.language-name').text(options.language);

    var safeLang = options.language.toLowerCase().replace(/[^a-z_]+/g, '');
    var defaultSrc = $('.template .lang.' + safeLang).text().trim();
    var defaultConfig = {
        settings: {showPopoutIcon: false},
        content: [{type: 'row', content: [editor.getComponent(1), compiler.getComponent(1)]}]
    };
    var root = $("#root");
    var config = url.deserialiseState(window.location.hash.substr(1));
    if (config) {
        // replace anything in the default config with that from the hash
        config = _.extend(defaultConfig, config);
    }
    $(window).bind('hashchange', function () {
        // punt on hash events and just reload the page if there's a hash
        if (window.location.hash.substr(1))
            window.location.reload();
    });

    if (!config) {
        var savedState = localStorage.getItem('gl');
        config = savedState !== null ? JSON.parse(savedState) : defaultConfig;
    }

    var layout, hub;
    try {
        layout = new GoldenLayout(config, root);
        hub = new Hub(layout, defaultSrc);
    } catch (e) {
        Raven.captureException(e);
        layout = new GoldenLayout(defaultConfig, root);
        hub = new Hub(layout, defaultSrc);
    }
    layout.on('stateChanged', function () {
        var state = JSON.stringify(layout.toConfig());
        localStorage.setItem('gl', state);
    });

    function sizeRoot() {
        var height = $(window).height() - root.position().top;
        root.height(height);
        layout.updateSize();
    }

    $(window).resize(sizeRoot);
    sizeRoot();

    new clipboard('.btn.clippy');

    function initPopover(getLink, provider) {
        var html = $('.template .urls').html();

        getLink.popover({
            container: 'body',
            content: html,
            html: true,
            placement: 'bottom',
            trigger: 'manual'
        }).click(function () {
            getLink.popover('show');
        }).on('inserted.bs.popover', function () {
            provider(function (url) {
                $(".permalink:visible").val(url);
            });
        });

        // Dismiss the popover on escape.
        $(document).on('keyup.editable', function (e) {
            if (e.which === 27) {
                getLink.popover("hide");
            }
        });

        // Dismiss on any click that isn't either on the opening element, or inside
        // the popover.
        $(document).on('click.editable', function (e) {
            var target = $(e.target);
            if (!target.is(getLink) && target.closest('.popover').length === 0)
                getLink.popover("hide");
        });
    }

    function permalink() {
        var config = layout.toConfig();
        return window.location.href.split('#')[0] + '#' + url.serialiseState(config);
    }

    initPopover($("#get-full-link"), function (done) {
        done(permalink);
    });
    initPopover($("#get-short-link"), function (done) {
        shortenURL(permalink(), done);
    });
});
<commit_msg>Catch and ignore exceptions when accessing localStorage.<commit_after>// Copyright (c) 2012-2016, Matt Godbolt
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

require.config({
    paths: {
        bootstrap: 'ext/bootstrap/dist/js/bootstrap',
        jquery: 'ext/jquery/dist/jquery',
        underscore: 'ext/underscore/underscore',
        goldenlayout: 'ext/golden-layout/dist/goldenlayout',
        selectize: 'ext/selectize/dist/js/selectize',
        sifter: 'ext/sifter/sifter',
        microplugin: 'ext/microplugin/src/microplugin',
        events: 'ext/eventEmitter/EventEmitter',
        lzstring: 'ext/lz-string/libs/lz-string',
        clipboard: 'ext/clipboard/dist/clipboard',
        'raven-js': 'ext/raven-js/dist/raven'
    },
    packages: [{
        name: "codemirror",
        location: "ext/codemirror",
        main: "lib/codemirror"
    }],
    shim: {
        underscore: {exports: '_'},
        bootstrap: ['jquery']
    }
});

define(function (require) {
    "use strict";
    require('bootstrap');
    var analytics = require('analytics');
    var sharing = require('sharing');
    var _ = require('underscore');
    var $ = require('jquery');
    var GoldenLayout = require('goldenlayout');
    var compiler = require('compiler');
    var editor = require('editor');
    var url = require('url');
    var clipboard = require('clipboard');
    var Hub = require('hub');
    var shortenURL = require('urlshorten-google');
    var Raven = require('raven-js');

    analytics.initialise();
    sharing.initialise();

    var options = require('options');
    $('.language-name').text(options.language);

    var safeLang = options.language.toLowerCase().replace(/[^a-z_]+/g, '');
    var defaultSrc = $('.template .lang.' + safeLang).text().trim();
    var defaultConfig = {
        settings: {showPopoutIcon: false},
        content: [{type: 'row', content: [editor.getComponent(1), compiler.getComponent(1)]}]
    };
    var root = $("#root");
    var config = url.deserialiseState(window.location.hash.substr(1));
    if (config) {
        // replace anything in the default config with that from the hash
        config = _.extend(defaultConfig, config);
    }
    $(window).bind('hashchange', function () {
        // punt on hash events and just reload the page if there's a hash
        if (window.location.hash.substr(1))
            window.location.reload();
    });

    if (!config) {
        var savedState = null;
        try {
            savedState = window.localStorage.getItem('gl');
        } catch (e) {
            // Some browsers in secure modes can throw exceptions here...
        }
        config = savedState !== null ? JSON.parse(savedState) : defaultConfig;
    }

    var layout, hub;
    try {
        layout = new GoldenLayout(config, root);
        hub = new Hub(layout, defaultSrc);
    } catch (e) {
        Raven.captureException(e);
        layout = new GoldenLayout(defaultConfig, root);
        hub = new Hub(layout, defaultSrc);
    }
    layout.on('stateChanged', function () {
        var state = JSON.stringify(layout.toConfig());
        try {
            window.localStorage.setItem('gl', state);
        } catch (e) {
            // Some browsers in secure modes may throw
        }
    });

    function sizeRoot() {
        var height = $(window).height() - root.position().top;
        root.height(height);
        layout.updateSize();
    }

    $(window).resize(sizeRoot);
    sizeRoot();

    new clipboard('.btn.clippy');

    function initPopover(getLink, provider) {
        var html = $('.template .urls').html();

        getLink.popover({
            container: 'body',
            content: html,
            html: true,
            placement: 'bottom',
            trigger: 'manual'
        }).click(function () {
            getLink.popover('show');
        }).on('inserted.bs.popover', function () {
            provider(function (url) {
                $(".permalink:visible").val(url);
            });
        });

        // Dismiss the popover on escape.
        $(document).on('keyup.editable', function (e) {
            if (e.which === 27) {
                getLink.popover("hide");
            }
        });

        // Dismiss on any click that isn't either on the opening element, or inside
        // the popover.
        $(document).on('click.editable', function (e) {
            var target = $(e.target);
            if (!target.is(getLink) && target.closest('.popover').length === 0)
                getLink.popover("hide");
        });
    }

    function permalink() {
        var config = layout.toConfig();
        return window.location.href.split('#')[0] + '#' + url.serialiseState(config);
    }

    initPopover($("#get-full-link"), function (done) {
        done(permalink);
    });
    initPopover($("#get-short-link"), function (done) {
        shortenURL(permalink(), done);
    });
});
<|endoftext|>


<commit_before>// Copyright (c) 2016, Matt Godbolt
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE
"use strict";

// setup analytics before anything else so we can capture any future errors in sentry
var analytics = require('./analytics');

require('popper.js');
require('bootstrap');
require('bootstrap-slider');

var sharing = require('./sharing');
var _ = require('underscore');
var $ = require('jquery');
var GoldenLayout = require('golden-layout');
var Components = require('./components');
var url = require('./url');
var clipboard = require('clipboard');
var Hub = require('./hub');
var Sentry = require('@sentry/browser');
var settings = require('./settings');
var local = require('./local');
var Alert = require('./alert');
var themer = require('./themes');
var motd = require('./motd');
var jsCookie = require('js-cookie');
var SimpleCook = require('./simplecook');
var History = require('./history');
var HistoryWidget = require('./history-widget').HistoryWidget;

//css
require("bootstrap/dist/css/bootstrap.min.css");
require("golden-layout/src/css/goldenlayout-base.css");
require("selectize/dist/css/selectize.bootstrap2.css");
require("bootstrap-slider/dist/css/bootstrap-slider.css");
require("./colours.css");
require("./explorer.css");

// Check to see if the current unload is a UI reset.
// Forgive me the global usage here
var hasUIBeenReset = false;
var simpleCooks = new SimpleCook();
var historyWidget = new HistoryWidget();

// Polyfill includes for IE11 - From MDN
if (!String.prototype.includes) {
    String.prototype.includes = function (search, start) {
        if (search instanceof RegExp) {
            throw TypeError('first argument must not be a RegExp');
        }
        if (start === undefined) { start = 0; }
        return this.indexOf(search, start) !== -1;
    };
}

function setupSettings(hub) {
    var eventHub = hub.layout.eventHub;
    var defaultSettings = {
        defaultLanguage: hub.defaultLangId
    };
    var currentSettings = JSON.parse(local.get('settings', null)) || defaultSettings;

    function onChange(newSettings) {
        if (currentSettings.theme !== newSettings.theme) {
            analytics.proxy('send', {
                hitType: 'event',
                eventCategory: 'ThemeChange',
                eventAction: newSettings.theme
            });
        }
        if (currentSettings.colourScheme !== newSettings.colourScheme) {
            analytics.proxy('send', {
                hitType: 'event',
                eventCategory: 'ColourSchemeChange',
                eventAction: newSettings.colourScheme
            });
        }
        currentSettings = newSettings;
        local.set('settings', JSON.stringify(newSettings));
        eventHub.emit('settingsChange', newSettings);
    }

    new themer.Themer(eventHub, currentSettings);

    eventHub.on('requestSettings', function () {
        eventHub.emit('settingsChange', currentSettings);
    });

    var setSettings = settings($('#settings'), currentSettings, onChange, hub.subdomainLangId);
    eventHub.on('modifySettings', function (newSettings) {
        setSettings(_.extend(currentSettings, newSettings));
    });
    return currentSettings;
}

function hasCookieConsented(options) {
    return jsCookie.get(options.policies.cookies.key) === options.policies.cookies.hash;
}

function setupButtons(options) {
    var alertSystem = new Alert();

    // I'd like for this to be the only function used, but it gets messy to pass the callback function around,
    // so we instead trigger a click here when we want it to open with this effect. Sorry!
    if (options.policies.privacy.enabled) {
        $('#privacy').click(function (event, data) {
            alertSystem.alert(
                data && data.title ? data.title : "Privacy policy",
                require('./policies/privacy.html')
            );
            // I can't remember why this check is here as it seems superfluous
            if (options.policies.privacy.enabled) {
                jsCookie.set(options.policies.privacy.key, options.policies.privacy.hash, {expires: 365});
            }
        });
    }

    if (options.policies.cookies.enabled) {
        var getCookieTitle = function () {
            return 'Cookies & related technologies policy

Current consent status: ' +
                (hasCookieConsented(options) ? 'Granted' : 'Denied') + '
';
        };
        $('#cookies').click(function () {
            alertSystem.ask(getCookieTitle(), $(require('./policies/cookies.html')), {
                yes: function () {
                    simpleCooks.callDoConsent.apply(simpleCooks);
                },
                yesHtml: 'Consent',
                no: function () {
                    simpleCooks.callDontConsent.apply(simpleCooks);
                },
                noHtml: 'Do NOT consent'
            });
        });
    }

    $('#ui-reset').click(function () {
        local.remove('gl');
        hasUIBeenReset = true;
        window.history.replaceState(null, null, window.httpRoot);
        window.location.reload();
    });

    $('#ui-duplicate').click(function () {
        window.open('/', '_blank');
    });

    $('#thanks-to').click(function () {
        alertSystem.alert("Special thanks to", $(require('./thanks.html')));
    });
    $('#changes').click(function () {
        alertSystem.alert("Changelog", $(require('./changelog.html')));
    });

    $('#ui-history').click(function () {
        historyWidget.run(function (data) {
            local.set('gl', JSON.stringify(data.config));
            hasUIBeenReset = true;
            window.history.replaceState(null, null, window.httpRoot);
            window.location.reload();
        });

        $('#history').modal();
    });
}

function findConfig(defaultConfig, options) {
    var config = null;
    if (!options.embedded) {
        if (options.config) {
            config = options.config;
        } else {
            config = url.deserialiseState(window.location.hash.substr(1));
        }

        if (config) {
            // replace anything in the default config with that from the hash
            config = _.extend(defaultConfig, config);
        }
        if (!config) {
            var savedState = local.get('gl', null);
            config = savedState !== null ? JSON.parse(savedState) : defaultConfig;
        }
    } else {
        config = _.extend(defaultConfig, {
            settings: {
                showMaximiseIcon: false,
                showCloseIcon: false,
                hasHeaders: false
            }
        }, sharing.configFromEmbedded(window.location.hash.substr(1)));
    }
    return config;
}

function initializeResetLayoutLink() {
    var currentUrl = document.URL;
    if (currentUrl.includes("/z/")) {
        $("#ui-brokenlink").attr("href", currentUrl.replace("/z/", "/resetlayout/"));
        $("#ui-brokenlink").show();
    } else {
        $("#ui-brokenlink").hide();
    }
}

function initPolicies(options) {
    // Ensure old cookies are removed, to avoid user confusion

    jsCookie.remove('fs_uid');
    jsCookie.remove('cookieconsent_status');
    if (options.policies.privacy.enabled &&
        options.policies.privacy.hash !== jsCookie.get(options.policies.privacy.key)) {
        $('#privacy').trigger('click', {
            title: 'New Privacy Policy. Please take a moment to read it'
        });
    }
    simpleCooks.onDoConsent = function () {
        jsCookie.set(options.policies.cookies.key, options.policies.cookies.hash, {expires: 365});
        analytics.toggle(true);
    };
    simpleCooks.onDontConsent = function () {
        analytics.toggle(false);
        jsCookie.set(options.policies.cookies.key, '');
    };
    simpleCooks.onHide = function () {
        $(window).trigger('resize');
    };
    // '' means no consent. Hash match means consent of old. Null means new user!
    var storedCookieConsent = jsCookie.get(options.policies.cookies.key);
    if (options.policies.cookies.enabled && storedCookieConsent !== '' &&
        options.policies.cookies.hash !== storedCookieConsent) {
        simpleCooks.show();
    } else if (options.policies.cookies.enabled && hasCookieConsented(options)) {
        analytics.initialise();
    }
}

// eslint-disable-next-line max-statements
function start() {
    initializeResetLayoutLink();

    var options = require('options');

    var hostnameParts = window.location.hostname.split('.');
    var subLangId = undefined;
    // Only set the subdomain lang id if it makes sense to do so
    if (hostnameParts.length > 0) {
        var subdomainPart = hostnameParts[0];
        var langBySubdomain = _.find(options.languages, function (lang) {
            return lang.id === subdomainPart || lang.alias.indexOf(subdomainPart) !== -1;
        });
        if (langBySubdomain) {
            subLangId = langBySubdomain.id;
        }
    }
    var defaultLangId = subLangId;
    if (!defaultLangId) {
        if (options.languages["c++"]) {
            defaultLangId = "c++";
        } else {
            defaultLangId = _.keys(options.languages)[0];
        }
    }

    // Cookie domains are matched as a RE against the window location. This allows a flexible
    // way that works across multiple domains (e.g. godbolt.org and compiler-explorer.com).
    // We allow this to be configurable so that (for example), gcc.godbolt.org and d.godbolt.org
    // share the same cookie domain for some settings.
    var cookieDomain = new RegExp(options.cookieDomainRe).exec(window.location.hostname);
    if (cookieDomain && cookieDomain[0]) {
        cookieDomain = cookieDomain[0];
        jsCookie.defaults.domain = cookieDomain;
    }

    var defaultConfig = {
        settings: {showPopoutIcon: false},
        content: [{
            type: 'row',
            content: [
                Components.getEditor(1, defaultLangId),
                Components.getCompiler(1, defaultLangId)
            ]
        }]
    };

    $(window).bind('hashchange', function () {
        // punt on hash events and just reload the page if there's a hash
        if (window.location.hash.substr(1)) window.location.reload();
    });

    // Which buttons act as a linkable popup
    var linkablePopups = ['#thanks-to', '#changes', '#cookies', '#setting', '#privacy'];
    var hashPart = linkablePopups.indexOf(window.location.hash) > -1 ? window.location.hash : null;
    if (hashPart) {
        window.location.hash = "";
    }

    var config = findConfig(defaultConfig, options);

    var root = $("#root");

    var layout;
    var hub;
    try {
        layout = new GoldenLayout(config, root);
        hub = new Hub(layout, subLangId, defaultLangId);
    } catch (e) {
        Sentry.captureException(e);

        if (document.URL.includes("/z/")) {
            document.location = document.URL.replace("/z/", "/resetlayout/");
        }

        layout = new GoldenLayout(defaultConfig, root);
        hub = new Hub(layout, subLangId, defaultLangId);
    }

    var lastState = null;
    var storedPaths = {};  // TODO maybe make this an LRU cache?

    layout.on('stateChanged', function () {
        var config = layout.toConfig();
        var stringifiedConfig = JSON.stringify(config);
        if (stringifiedConfig !== lastState) {
            if (storedPaths[config]) {
                window.history.replaceState(null, null, storedPaths[stringifiedConfig]);
            } else if (window.location.pathname !== window.httpRoot) {
                window.history.replaceState(null, null, window.httpRoot);
                // TODO: Add this state to storedPaths, but with a upper bound on the stored state count
            }
            lastState = stringifiedConfig;

            History.push(stringifiedConfig);
        }
        if (options.embedded) {
            var strippedToLast = window.location.pathname;
            strippedToLast = strippedToLast.substr(0, strippedToLast.lastIndexOf('/') + 1);
            $('a.link').attr('href', strippedToLast + '#' + url.serialiseState(config));
        }
    });

    function sizeRoot() {
        var height = $(window).height() - (root.position().top || 0) - ($('#simplecook:visible').height() || 0);
        root.height(height);
        layout.updateSize();
    }

    $(window)
        .resize(sizeRoot)
        .on('beforeunload', function () {
            // Only preserve state in localStorage in non-embedded mode.
            if (!options.embedded && !hasUIBeenReset) {
                local.set('gl', JSON.stringify(layout.toConfig()));
            }
        });

    new clipboard('.btn.clippy');

    var settings = setupSettings(hub);

    // We assume no consent for embed users
    if (!options.embedded) {
        setupButtons(options);
    }

    sharing.initShareButton($('#share'), layout, function (config, extra) {
        window.history.pushState(null, null, extra);
        storedPaths[JSON.stringify(config)] = extra;
    });

    function setupAdd(thing, func) {
        layout.createDragSource(thing, func);
        thing.click(function () {
            hub.addAtRoot(func());
        });
    }

    setupAdd($('#add-editor'), function () {
        return Components.getEditor();
    });
    setupAdd($('#add-diff'), function () {
        return Components.getDiff();
    });

    if (hashPart) {
        var element = $(hashPart);
        if (element) element.click();
    }
    initPolicies(options);

    // Skip some steps if using embedded mode
    if (!options.embedded) {
        // Only fetch MOTD when not embedded.
        motd.initialise(options.motdUrl, $('#motd'), subLangId, settings.enableCommunityAds,
            function (data) {
                var sendMotd = function () {
                    hub.layout.eventHub.emit('motd', data);
                };
                hub.layout.eventHub.on('requestMotd', sendMotd);
                sendMotd();
            },
            function () {
                hub.layout.eventHub.emit('modifySettings', {
                    enableCommunityAds: false
                });
            });

        // Don't try to update Version tree link
        var release = window.compilerExplorerOptions.gitReleaseCommit;
        var versionLink = 'https://github.com/mattgodbolt/compiler-explorer/';
        if (release) {
            versionLink += 'tree/' + release;
        }
        $('#version-tree').prop('href', versionLink);
    }

    if (options.hideEditorToolbars) {
        $('[name="editor-btn-toolbar"]').addClass("d-none");
    }

    sizeRoot();
    lastState = JSON.stringify(layout.toConfig());
}

$(start);
<commit_msg>Escape an ampersand<commit_after>// Copyright (c) 2016, Matt Godbolt
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE
"use strict";

// setup analytics before anything else so we can capture any future errors in sentry
var analytics = require('./analytics');

require('popper.js');
require('bootstrap');
require('bootstrap-slider');

var sharing = require('./sharing');
var _ = require('underscore');
var $ = require('jquery');
var GoldenLayout = require('golden-layout');
var Components = require('./components');
var url = require('./url');
var clipboard = require('clipboard');
var Hub = require('./hub');
var Sentry = require('@sentry/browser');
var settings = require('./settings');
var local = require('./local');
var Alert = require('./alert');
var themer = require('./themes');
var motd = require('./motd');
var jsCookie = require('js-cookie');
var SimpleCook = require('./simplecook');
var History = require('./history');
var HistoryWidget = require('./history-widget').HistoryWidget;

//css
require("bootstrap/dist/css/bootstrap.min.css");
require("golden-layout/src/css/goldenlayout-base.css");
require("selectize/dist/css/selectize.bootstrap2.css");
require("bootstrap-slider/dist/css/bootstrap-slider.css");
require("./colours.css");
require("./explorer.css");

// Check to see if the current unload is a UI reset.
// Forgive me the global usage here
var hasUIBeenReset = false;
var simpleCooks = new SimpleCook();
var historyWidget = new HistoryWidget();

// Polyfill includes for IE11 - From MDN
if (!String.prototype.includes) {
    String.prototype.includes = function (search, start) {
        if (search instanceof RegExp) {
            throw TypeError('first argument must not be a RegExp');
        }
        if (start === undefined) { start = 0; }
        return this.indexOf(search, start) !== -1;
    };
}

function setupSettings(hub) {
    var eventHub = hub.layout.eventHub;
    var defaultSettings = {
        defaultLanguage: hub.defaultLangId
    };
    var currentSettings = JSON.parse(local.get('settings', null)) || defaultSettings;

    function onChange(newSettings) {
        if (currentSettings.theme !== newSettings.theme) {
            analytics.proxy('send', {
                hitType: 'event',
                eventCategory: 'ThemeChange',
                eventAction: newSettings.theme
            });
        }
        if (currentSettings.colourScheme !== newSettings.colourScheme) {
            analytics.proxy('send', {
                hitType: 'event',
                eventCategory: 'ColourSchemeChange',
                eventAction: newSettings.colourScheme
            });
        }
        currentSettings = newSettings;
        local.set('settings', JSON.stringify(newSettings));
        eventHub.emit('settingsChange', newSettings);
    }

    new themer.Themer(eventHub, currentSettings);

    eventHub.on('requestSettings', function () {
        eventHub.emit('settingsChange', currentSettings);
    });

    var setSettings = settings($('#settings'), currentSettings, onChange, hub.subdomainLangId);
    eventHub.on('modifySettings', function (newSettings) {
        setSettings(_.extend(currentSettings, newSettings));
    });
    return currentSettings;
}

function hasCookieConsented(options) {
    return jsCookie.get(options.policies.cookies.key) === options.policies.cookies.hash;
}

function setupButtons(options) {
    var alertSystem = new Alert();

    // I'd like for this to be the only function used, but it gets messy to pass the callback function around,
    // so we instead trigger a click here when we want it to open with this effect. Sorry!
    if (options.policies.privacy.enabled) {
        $('#privacy').click(function (event, data) {
            alertSystem.alert(
                data && data.title ? data.title : "Privacy policy",
                require('./policies/privacy.html')
            );
            // I can't remember why this check is here as it seems superfluous
            if (options.policies.privacy.enabled) {
                jsCookie.set(options.policies.privacy.key, options.policies.privacy.hash, {expires: 365});
            }
        });
    }

    if (options.policies.cookies.enabled) {
        var getCookieTitle = function () {
            return 'Cookies & related technologies policy

Current consent status: ' +
                (hasCookieConsented(options) ? 'Granted' : 'Denied') + '
';
        };
        $('#cookies').click(function () {
            alertSystem.ask(getCookieTitle(), $(require('./policies/cookies.html')), {
                yes: function () {
                    simpleCooks.callDoConsent.apply(simpleCooks);
                },
                yesHtml: 'Consent',
                no: function () {
                    simpleCooks.callDontConsent.apply(simpleCooks);
                },
                noHtml: 'Do NOT consent'
            });
        });
    }

    $('#ui-reset').click(function () {
        local.remove('gl');
        hasUIBeenReset = true;
        window.history.replaceState(null, null, window.httpRoot);
        window.location.reload();
    });

    $('#ui-duplicate').click(function () {
        window.open('/', '_blank');
    });

    $('#thanks-to').click(function () {
        alertSystem.alert("Special thanks to", $(require('./thanks.html')));
    });
    $('#changes').click(function () {
        alertSystem.alert("Changelog", $(require('./changelog.html')));
    });

    $('#ui-history').click(function () {
        historyWidget.run(function (data) {
            local.set('gl', JSON.stringify(data.config));
            hasUIBeenReset = true;
            window.history.replaceState(null, null, window.httpRoot);
            window.location.reload();
        });

        $('#history').modal();
    });
}

function findConfig(defaultConfig, options) {
    var config = null;
    if (!options.embedded) {
        if (options.config) {
            config = options.config;
        } else {
            config = url.deserialiseState(window.location.hash.substr(1));
        }

        if (config) {
            // replace anything in the default config with that from the hash
            config = _.extend(defaultConfig, config);
        }
        if (!config) {
            var savedState = local.get('gl', null);
            config = savedState !== null ? JSON.parse(savedState) : defaultConfig;
        }
    } else {
        config = _.extend(defaultConfig, {
            settings: {
                showMaximiseIcon: false,
                showCloseIcon: false,
                hasHeaders: false
            }
        }, sharing.configFromEmbedded(window.location.hash.substr(1)));
    }
    return config;
}

function initializeResetLayoutLink() {
    var currentUrl = document.URL;
    if (currentUrl.includes("/z/")) {
        $("#ui-brokenlink").attr("href", currentUrl.replace("/z/", "/resetlayout/"));
        $("#ui-brokenlink").show();
    } else {
        $("#ui-brokenlink").hide();
    }
}

function initPolicies(options) {
    // Ensure old cookies are removed, to avoid user confusion

    jsCookie.remove('fs_uid');
    jsCookie.remove('cookieconsent_status');
    if (options.policies.privacy.enabled &&
        options.policies.privacy.hash !== jsCookie.get(options.policies.privacy.key)) {
        $('#privacy').trigger('click', {
            title: 'New Privacy Policy. Please take a moment to read it'
        });
    }
    simpleCooks.onDoConsent = function () {
        jsCookie.set(options.policies.cookies.key, options.policies.cookies.hash, {expires: 365});
        analytics.toggle(true);
    };
    simpleCooks.onDontConsent = function () {
        analytics.toggle(false);
        jsCookie.set(options.policies.cookies.key, '');
    };
    simpleCooks.onHide = function () {
        $(window).trigger('resize');
    };
    // '' means no consent. Hash match means consent of old. Null means new user!
    var storedCookieConsent = jsCookie.get(options.policies.cookies.key);
    if (options.policies.cookies.enabled && storedCookieConsent !== '' &&
        options.policies.cookies.hash !== storedCookieConsent) {
        simpleCooks.show();
    } else if (options.policies.cookies.enabled && hasCookieConsented(options)) {
        analytics.initialise();
    }
}

// eslint-disable-next-line max-statements
function start() {
    initializeResetLayoutLink();

    var options = require('options');

    var hostnameParts = window.location.hostname.split('.');
    var subLangId = undefined;
    // Only set the subdomain lang id if it makes sense to do so
    if (hostnameParts.length > 0) {
        var subdomainPart = hostnameParts[0];
        var langBySubdomain = _.find(options.languages, function (lang) {
            return lang.id === subdomainPart || lang.alias.indexOf(subdomainPart) !== -1;
        });
        if (langBySubdomain) {
            subLangId = langBySubdomain.id;
        }
    }
    var defaultLangId = subLangId;
    if (!defaultLangId) {
        if (options.languages["c++"]) {
            defaultLangId = "c++";
        } else {
            defaultLangId = _.keys(options.languages)[0];
        }
    }

    // Cookie domains are matched as a RE against the window location. This allows a flexible
    // way that works across multiple domains (e.g. godbolt.org and compiler-explorer.com).
    // We allow this to be configurable so that (for example), gcc.godbolt.org and d.godbolt.org
    // share the same cookie domain for some settings.
    var cookieDomain = new RegExp(options.cookieDomainRe).exec(window.location.hostname);
    if (cookieDomain && cookieDomain[0]) {
        cookieDomain = cookieDomain[0];
        jsCookie.defaults.domain = cookieDomain;
    }

    var defaultConfig = {
        settings: {showPopoutIcon: false},
        content: [{
            type: 'row',
            content: [
                Components.getEditor(1, defaultLangId),
                Components.getCompiler(1, defaultLangId)
            ]
        }]
    };

    $(window).bind('hashchange', function () {
        // punt on hash events and just reload the page if there's a hash
        if (window.location.hash.substr(1)) window.location.reload();
    });

    // Which buttons act as a linkable popup
    var linkablePopups = ['#thanks-to', '#changes', '#cookies', '#setting', '#privacy'];
    var hashPart = linkablePopups.indexOf(window.location.hash) > -1 ? window.location.hash : null;
    if (hashPart) {
        window.location.hash = "";
    }

    var config = findConfig(defaultConfig, options);

    var root = $("#root");

    var layout;
    var hub;
    try {
        layout = new GoldenLayout(config, root);
        hub = new Hub(layout, subLangId, defaultLangId);
    } catch (e) {
        Sentry.captureException(e);

        if (document.URL.includes("/z/")) {
            document.location = document.URL.replace("/z/", "/resetlayout/");
        }

        layout = new GoldenLayout(defaultConfig, root);
        hub = new Hub(layout, subLangId, defaultLangId);
    }

    var lastState = null;
    var storedPaths = {};  // TODO maybe make this an LRU cache?

    layout.on('stateChanged', function () {
        var config = layout.toConfig();
        var stringifiedConfig = JSON.stringify(config);
        if (stringifiedConfig !== lastState) {
            if (storedPaths[config]) {
                window.history.replaceState(null, null, storedPaths[stringifiedConfig]);
            } else if (window.location.pathname !== window.httpRoot) {
                window.history.replaceState(null, null, window.httpRoot);
                // TODO: Add this state to storedPaths, but with a upper bound on the stored state count
            }
            lastState = stringifiedConfig;

            History.push(stringifiedConfig);
        }
        if (options.embedded) {
            var strippedToLast = window.location.pathname;
            strippedToLast = strippedToLast.substr(0, strippedToLast.lastIndexOf('/') + 1);
            $('a.link').attr('href', strippedToLast + '#' + url.serialiseState(config));
        }
    });

    function sizeRoot() {
        var height = $(window).height() - (root.position().top || 0) - ($('#simplecook:visible').height() || 0);
        root.height(height);
        layout.updateSize();
    }

    $(window)
        .resize(sizeRoot)
        .on('beforeunload', function () {
            // Only preserve state in localStorage in non-embedded mode.
            if (!options.embedded && !hasUIBeenReset) {
                local.set('gl', JSON.stringify(layout.toConfig()));
            }
        });

    new clipboard('.btn.clippy');

    var settings = setupSettings(hub);

    // We assume no consent for embed users
    if (!options.embedded) {
        setupButtons(options);
    }

    sharing.initShareButton($('#share'), layout, function (config, extra) {
        window.history.pushState(null, null, extra);
        storedPaths[JSON.stringify(config)] = extra;
    });

    function setupAdd(thing, func) {
        layout.createDragSource(thing, func);
        thing.click(function () {
            hub.addAtRoot(func());
        });
    }

    setupAdd($('#add-editor'), function () {
        return Components.getEditor();
    });
    setupAdd($('#add-diff'), function () {
        return Components.getDiff();
    });

    if (hashPart) {
        var element = $(hashPart);
        if (element) element.click();
    }
    initPolicies(options);

    // Skip some steps if using embedded mode
    if (!options.embedded) {
        // Only fetch MOTD when not embedded.
        motd.initialise(options.motdUrl, $('#motd'), subLangId, settings.enableCommunityAds,
            function (data) {
                var sendMotd = function () {
                    hub.layout.eventHub.emit('motd', data);
                };
                hub.layout.eventHub.on('requestMotd', sendMotd);
                sendMotd();
            },
            function () {
                hub.layout.eventHub.emit('modifySettings', {
                    enableCommunityAds: false
                });
            });

        // Don't try to update Version tree link
        var release = window.compilerExplorerOptions.gitReleaseCommit;
        var versionLink = 'https://github.com/mattgodbolt/compiler-explorer/';
        if (release) {
            versionLink += 'tree/' + release;
        }
        $('#version-tree').prop('href', versionLink);
    }

    if (options.hideEditorToolbars) {
        $('[name="editor-btn-toolbar"]').addClass("d-none");
    }

    sizeRoot();
    lastState = JSON.stringify(layout.toConfig());
}

$(start);
<|endoftext|>


<commit_before>"use strict";

class PokemonStuff {

	constructor() {
		this.headerSection = new HeaderSection()
		this.infoSection = new InfoSection()
		this.listSection = new ListSection()
		this.optionsSection = new OptionsSection()
		this.state = new State()
		this.settings = new Settings()
		this.data = new PokemonData()
		this.collection = new Collection()
		this.spreadsheetParser = new SpreadsheetParser()
	}

	update() {
		this.optionsSection.updateOptions()
		this.headerSection.updateNavPokemonTabs()
		this.updatePokemons()
		this.show()
	}

	updatePokemons() {
		if (!this.state.loaded)
			return
		this.state.currentPokemons = this.data.getFilteredPokemons()
		this.listSection.show()
		this.headerSection.updateFilterTabs()
	}

	selectPokemon(pokemon, element) {
		if (!pokemon || this.state.currentPokemon == pokemon) {
			this.infoSection.closeInfo()
			return
		}
		this.infoSection.closeInfo(() => {
			this.infoSection.showInfo(pokemon, element)
		})
	}

	selectTab(tab) {
		window.location.hash = ""
		if (stuff.collection.pokemons.includes(tab) || stuff.collection.lookingFor.includes(tab))
			window.location.hash = tab.id
		this.state.currentTab = tab
		this.updatePokemons()
	}

	load() {
		this.loadBaseData()
		this.loadCollectionData()
		this.loadDestination()
		this.settings.load()
	}

	loadBaseData() {
		this.loadJSONData("pokemons")
		this.loadJSONData("moves")
		this.loadJSONData("abilities")
		this.loadJSONData("natures")
		this.loadJSONData("eggGroups", "egg-groups")
		requestJSON("https://armienn.github.io/pokemon/data-sumo/types.json", (types) => {
			this.data.types = types
			this.data.typeNames = Object.keys(types)
			this.state.thingsLoaded.types = true
			this.tryLoad()
		})
	}

	loadJSONData(thing, file) {
		if (!file)
			file = thing
		requestJSON("https://armienn.github.io/pokemon/data-sumo/" + file + ".json", (data) => {
			this.data[thing] = data
			this.state.thingsLoaded[thing] = true
			this.tryLoad()
		})
	}

	loadCollectionData() {
		if (!window.location.search)
			return
		var argument = window.location.search.substring(1)
		this.state.externalInventory.load = true
		var args = argument.split(":")
		for (var i in this.optionsSection.importMethods)
			if (i.toLowerCase() == args[0].toLowerCase()) {
				request("https://" + args[1], (response) => {
					this.state.script = { type: args[0].toLowerCase(), content: response }
					this.tryLoad()
				})
				return
			}
		requestJSON(this.spreadsheetParser.getSpreadsheetUrl(argument), (response) => {
			this.state.spreadsheet = { id: argument, spreadsheet: response }
			this.tryLoad()
		})
	}

	loadDestination() {
		if (window.location.hash)
			this.state.destination = window.location.hash.substring(1)
	}

	tryLoad() {
		if (!this.state.thingsAreLoaded)
			return
		if (this.state.externalInventory.load) {
			this.headerSection.showLocal = false
			if (this.state.script)
				for (var i in this.optionsSection.importMethods) {
					if (i.toLowerCase() == this.state.script.type){
						this.loadScript((content) => this.optionsSection.importMethods[i].method(content))
						break
					}
				}
			else if (this.state.spreadsheet)
				this.loadSpreadsheet()
			if (!this.state.externalInventory.isLoaded)
				return
		}
		this.state.loaded = true
		this.headerSection.setup()
		this.collection.loadLocalTabs()
		this.settings.loadLocalScript()
		this.update()
		if (!this.collection.pokemons.length && this.state.destination)
			this.selectPokemonBasedOn(this.state.destination)
		setInterval(() => { this.listSection.loadMoreWhenScrolledDown() }, 500)
	}

	selectPokemonBasedOn(destination) {
		for (var n in this.data.pokemons) {
			var pokemon = this.data.pokemons[n]
			var name = pokemon.name.toLowerCase().replace(" ", "-").replace("♀", "-f").replace("♂", "-m").replace("'", "").replace(".", "").replace("ébé", "ebe").replace(":", "")
			if (pokemon.id == destination || name == destination.toLowerCase()) {
				this.selectPokemon(pokemon)
				return
			}
		}
	}

	loadScript(parser) {
		var pokemons
		try {
			pokemons = parser(this.state.script.content)
		}
		catch (e) {
			document.getElementById("loading").innerHTML = "Failed to load external collection: " + e.message
			document.getElementById("loading").onclick = () => {
				this.state.externalInventory.load = false
				this.tryLoad()
			}
			return
		}
		this.state.script = undefined
		if (!pokemons)
			return
		var tab = this.collection.addTab("Pokémon list", pokemons)
		this.selectTab(tab)
		this.state.externalInventory.isLoaded = true
	}

	loadSpreadsheet() {
		this.spreadsheetParser.parse(this.state.spreadsheet)
		this.state.spreadsheet = undefined
	}

	show() {
		this.headerSection.show()
		this.updateColors()
		setTimeout(function () { fade(document.getElementById("loading")) }, 500)
	}

	updateColors() {
		document.getElementsByTagName("body")[0].style.backgroundColor = this.settings.colors.backgroundColor
		document.getElementsByTagName("body")[0].style.color = this.settings.colors.textColor
		document.getElementsByTagName("section")[0].style.backgroundColor = this.settings.colors.headerColor
		document.getElementsByTagName("header")[0].style.backgroundColor = this.settings.colors.headerColor
	}
}

// some utility functions

function requestJSON(url, callback) {
	request(url, function (response) {
		callback(JSON.parse(response))
	})
}

function request(url, callback) {
	var xmlHttp = new XMLHttpRequest();
	xmlHttp.onreadystatechange = function () {
		if (xmlHttp.readyState == 4) {
			if (xmlHttp.status == 200)
				callback(xmlHttp.responseText)
			else {
				document.getElementById("loading").innerHTML = "Failed to load external data"
				document.getElementById("loading").onclick = () => {
					stuff.state.externalInventory.load = false
					stuff.tryLoad()
				}
			}
		}
	}
	xmlHttp.onerror = function () {
		document.getElementById("loading").innerHTML = "Failed to load external data"
		document.getElementById("loading").onclick = () => {
			stuff.state.externalInventory.load = false
			stuff.tryLoad()
		}
	}
	xmlHttp.open("GET", url, true)
	xmlHttp.send()
}

function newTag(tag, parentElement, options = {}) {
	var newElement = document.createElement(tag)
	if (parentElement) {
		if (options.first)
			parentElement.insertBefore(newElement, parentElement.firstChild)
		else
			parentElement.appendChild(newElement)
	}
	for (var style in options.style)
		newElement.style[style] = options.style[style]
	if (options.text)
		newElement.innerHTML = options.text
	return newElement
}

function fade(element) {
	var opacity = 1;
	var timer = setInterval(function () {
		if (opacity <= 0.01) {
			clearInterval(timer)
			element.style.display = 'none'
		}
		element.style.opacity = opacity
		element.style.filter = 'alpha(opacity=' + opacity * 100 + ")"
		opacity -= 0.15
	}, 50)
}

function textContains(text, substring) {
	return text.toLowerCase().indexOf(substring.toLowerCase()) > -1
}

function prependZeroes(number, characters) {
	number = number.toString()
	while (number.length < characters) {
		number = "0" + number
	}
	return number
}

function parseStatType(text) {
	if (["hp", "health"].indexOf(text.trim().toLowerCase()) > -1)
		return "hp"
	if (["atk", "attack"].indexOf(text.trim().toLowerCase()) > -1)
		return "atk"
	if (["def", "defense"].indexOf(text.trim().toLowerCase()) > -1)
		return "def"
	if (["spa", "sp. atk", "sp. attack", "special attack"].indexOf(text.trim().toLowerCase()) > -1)
		return "spa"
	if (["spd", "sp. def", "sp. defense", "special defense"].indexOf(text.trim().toLowerCase()) > -1)
		return "spd"
	if (["spe", "speed"].indexOf(text.trim().toLowerCase()))
		return "spe"
}

function HSVtoRGB(h, s, v) {
	var r, g, b, i, f, p, q, t
	i = Math.floor(h * 6)
	f = h * 6 - i
	p = v * (1 - s)
	q = v * (1 - f * s)
	t = v * (1 - (1 - f) * s)
	switch (i % 6) {
		case 0: r = v, g = t, b = p; break;
		case 1: r = q, g = v, b = p; break;
		case 2: r = p, g = v, b = t; break;
		case 3: r = p, g = q, b = v; break;
		case 4: r = t, g = p, b = v; break;
		case 5: r = v, g = p, b = q; break;
	}
	return Math.round(r * 255) + "," + Math.round(g * 255) + "," + Math.round(b * 255)
}

var stuff = new PokemonStuff()
stuff.load()
<commit_msg>Bugfix<commit_after>"use strict";

class PokemonStuff {

	constructor() {
		this.headerSection = new HeaderSection()
		this.infoSection = new InfoSection()
		this.listSection = new ListSection()
		this.optionsSection = new OptionsSection()
		this.state = new State()
		this.settings = new Settings()
		this.data = new PokemonData()
		this.collection = new Collection()
		this.spreadsheetParser = new SpreadsheetParser()
	}

	update() {
		this.optionsSection.updateOptions()
		this.headerSection.updateNavPokemonTabs()
		this.updatePokemons()
		this.show()
	}

	updatePokemons() {
		if (!this.state.loaded)
			return
		this.state.currentPokemons = this.data.getFilteredPokemons()
		this.listSection.show()
		this.headerSection.updateFilterTabs()
	}

	selectPokemon(pokemon, element) {
		if (!pokemon || this.state.currentPokemon == pokemon) {
			this.infoSection.closeInfo()
			return
		}
		this.infoSection.closeInfo(() => {
			this.infoSection.showInfo(pokemon, element)
		})
	}

	selectTab(tab) {
		window.location.hash = ""
		if (stuff.collection.pokemons.includes(tab) || stuff.collection.lookingFor.includes(tab))
			window.location.hash = tab.id
		this.state.currentTab = tab
		this.updatePokemons()
	}

	load() {
		this.loadBaseData()
		this.loadCollectionData()
		this.loadDestination()
		this.settings.load()
	}

	loadBaseData() {
		this.loadJSONData("pokemons")
		this.loadJSONData("moves")
		this.loadJSONData("abilities")
		this.loadJSONData("natures")
		this.loadJSONData("eggGroups", "egg-groups")
		requestJSON("https://armienn.github.io/pokemon/data-sumo/types.json", (types) => {
			this.data.types = types
			this.data.typeNames = Object.keys(types)
			this.state.thingsLoaded.types = true
			this.tryLoad()
		})
	}

	loadJSONData(thing, file) {
		if (!file)
			file = thing
		requestJSON("https://armienn.github.io/pokemon/data-sumo/" + file + ".json", (data) => {
			this.data[thing] = data
			this.state.thingsLoaded[thing] = true
			this.tryLoad()
		})
	}

	loadCollectionData() {
		if (!window.location.search)
			return
		var argument = window.location.search.substring(1)
		this.state.externalInventory.load = true
		var args = argument.split(":")
		for (var i in this.optionsSection.importMethods)
			if (i.toLowerCase() == args[0].toLowerCase()) {
				request("https://" + args[1], (response) => {
					this.state.script = { type: args[0].toLowerCase(), content: response }
					this.tryLoad()
				})
				return
			}
		requestJSON(this.spreadsheetParser.getSpreadsheetUrl(argument), (response) => {
			this.state.spreadsheet = { id: argument, spreadsheet: response }
			this.tryLoad()
		})
	}

	loadDestination() {
		if (window.location.hash)
			this.state.destination = window.location.hash.substring(1)
	}

	tryLoad() {
		if (!this.state.thingsAreLoaded)
			return
		if (this.state.externalInventory.load) {
			this.headerSection.showLocal = false
			if (this.state.script)
				for (var i in this.optionsSection.importMethods) {
					if (i.toLowerCase() == this.state.script.type){
						this.loadScript((content) => this.optionsSection.importMethods[i].method(content))
						break
					}
				}
			else if (this.state.spreadsheet)
				this.loadSpreadsheet()
			if (!this.state.externalInventory.isLoaded)
				return
		}
		this.state.loaded = true
		this.headerSection.setup()
		this.collection.loadLocalTabs()
		this.settings.loadLocalScript()
		this.update()
		if (!this.collection.pokemons.length && this.state.destination)
			this.selectPokemonBasedOn(this.state.destination)
		setInterval(() => { this.listSection.loadMoreWhenScrolledDown() }, 500)
	}

	selectPokemonBasedOn(destination) {
		for (var n in this.data.pokemons) {
			var pokemon = this.data.pokemons[n]
			var name = pokemon.name.toLowerCase().replace(" ", "-").replace("♀", "-f").replace("♂", "-m").replace("'", "").replace(".", "").replace("ébé", "ebe").replace(":", "")
			if (pokemon.id == destination || name == destination.toLowerCase()) {
				this.selectPokemon(pokemon)
				return
			}
		}
	}

	loadScript(parser) {
		var pokemons
		try {
			pokemons = parser(this.state.script.content)
		}
		catch (e) {
			document.getElementById("loading").innerHTML = "Failed to load external collection: " + e.message
			document.getElementById("loading").onclick = () => {
				this.state.externalInventory.load = false
				this.tryLoad()
			}
			return
		}
		this.state.script = undefined
		this.state.externalInventory.isLoaded = true
		if (!pokemons)
			return
		var tab = this.collection.addTab("Pokémon list", pokemons)
		this.selectTab(tab)
	}

	loadSpreadsheet() {
		this.spreadsheetParser.parse(this.state.spreadsheet)
		this.state.spreadsheet = undefined
	}

	show() {
		this.headerSection.show()
		this.updateColors()
		setTimeout(function () { fade(document.getElementById("loading")) }, 500)
	}

	updateColors() {
		document.getElementsByTagName("body")[0].style.backgroundColor = this.settings.colors.backgroundColor
		document.getElementsByTagName("body")[0].style.color = this.settings.colors.textColor
		document.getElementsByTagName("section")[0].style.backgroundColor = this.settings.colors.headerColor
		document.getElementsByTagName("header")[0].style.backgroundColor = this.settings.colors.headerColor
	}
}

// some utility functions

function requestJSON(url, callback) {
	request(url, function (response) {
		callback(JSON.parse(response))
	})
}

function request(url, callback) {
	var xmlHttp = new XMLHttpRequest();
	xmlHttp.onreadystatechange = function () {
		if (xmlHttp.readyState == 4) {
			if (xmlHttp.status == 200)
				callback(xmlHttp.responseText)
			else {
				document.getElementById("loading").innerHTML = "Failed to load external data"
				document.getElementById("loading").onclick = () => {
					stuff.state.externalInventory.load = false
					stuff.tryLoad()
				}
			}
		}
	}
	xmlHttp.onerror = function () {
		document.getElementById("loading").innerHTML = "Failed to load external data"
		document.getElementById("loading").onclick = () => {
			stuff.state.externalInventory.load = false
			stuff.tryLoad()
		}
	}
	xmlHttp.open("GET", url, true)
	xmlHttp.send()
}

function newTag(tag, parentElement, options = {}) {
	var newElement = document.createElement(tag)
	if (parentElement) {
		if (options.first)
			parentElement.insertBefore(newElement, parentElement.firstChild)
		else
			parentElement.appendChild(newElement)
	}
	for (var style in options.style)
		newElement.style[style] = options.style[style]
	if (options.text)
		newElement.innerHTML = options.text
	return newElement
}

function fade(element) {
	var opacity = 1;
	var timer = setInterval(function () {
		if (opacity <= 0.01) {
			clearInterval(timer)
			element.style.display = 'none'
		}
		element.style.opacity = opacity
		element.style.filter = 'alpha(opacity=' + opacity * 100 + ")"
		opacity -= 0.15
	}, 50)
}

function textContains(text, substring) {
	return text.toLowerCase().indexOf(substring.toLowerCase()) > -1
}

function prependZeroes(number, characters) {
	number = number.toString()
	while (number.length < characters) {
		number = "0" + number
	}
	return number
}

function parseStatType(text) {
	if (["hp", "health"].indexOf(text.trim().toLowerCase()) > -1)
		return "hp"
	if (["atk", "attack"].indexOf(text.trim().toLowerCase()) > -1)
		return "atk"
	if (["def", "defense"].indexOf(text.trim().toLowerCase()) > -1)
		return "def"
	if (["spa", "sp. atk", "sp. attack", "special attack"].indexOf(text.trim().toLowerCase()) > -1)
		return "spa"
	if (["spd", "sp. def", "sp. defense", "special defense"].indexOf(text.trim().toLowerCase()) > -1)
		return "spd"
	if (["spe", "speed"].indexOf(text.trim().toLowerCase()))
		return "spe"
}

function HSVtoRGB(h, s, v) {
	var r, g, b, i, f, p, q, t
	i = Math.floor(h * 6)
	f = h * 6 - i
	p = v * (1 - s)
	q = v * (1 - f * s)
	t = v * (1 - (1 - f) * s)
	switch (i % 6) {
		case 0: r = v, g = t, b = p; break;
		case 1: r = q, g = v, b = p; break;
		case 2: r = p, g = v, b = t; break;
		case 3: r = p, g = q, b = v; break;
		case 4: r = t, g = p, b = v; break;
		case 5: r = v, g = p, b = q; break;
	}
	return Math.round(r * 255) + "," + Math.round(g * 255) + "," + Math.round(b * 255)
}

var stuff = new PokemonStuff()
stuff.load()
<|endoftext|>


<commit_before>js.io.require('js.io.protocols.xmpp')

function MessageWindow(jid, username) {
    this.remoteUsername = username;
    this.remoteJid = jid;
}

MessageWindow.prototype.onMessage = function (user, text) {
    this.chatPanel.addChatMessage({username:user, text:text});
};

// QUIRKS FLAG, FOR BOX MODEL
var IE_QUIRKS = (YAHOO.env.ua.ie && document.compatMode == "BackCompat");

// UNDERLAY/IFRAME SYNC REQUIRED
var IE_SYNC = (YAHOO.env.ua.ie == 6 || (YAHOO.env.ua.ie == 7 && IE_QUIRKS));

// PADDING USED FOR BODY ELEMENT (Hardcoded for example)
var PANEL_BODY_PADDING = (10*2) // 10px top/bottom padding applied to Panel body element. The top/bottom border width is 0

/** Display the window. */
MessageWindow.prototype.render = function () {
    this.panel = new YAHOO.widget.Panel("dialog_" + this.remoteUsername, {
        xy: [Math.random() * 250 + 250,Math.random() * 250 + 50],
        width: "380px",
        effect: {effect:YAHOO.widget.ContainerEffect.FADE, duration:0.5},
        constraintoviewport: true,
        close: true
    });

    this.panel.setHeader("Chat with " + this.remoteUsername);
    this.panel.setBody('');
    this.panel.renderEvent.subscribe(function () {
        this.layout.render();

    }, this, true);

    this.layout = new YAHOO.widget.Layout(this.panel.body, {
        height: 300,
        units: [
            { // Chat Window
                position: 'center',
                gutter: '0'
            }
      ]
    });

    /** chat panel */
    this.chatPanel = new gp.ChatPanel();
    this.chatPanel.sendEvent.subscribe(function (type, args) {
        /** Call the global function for now */
        onSendMessage(this.remoteJid, this.remoteUsername, args[0]);
    }, this, true);

    // rendering
    this.layout.on('render', function () {

        var centerUnit = this.layout.getUnitByPosition('center').get('wrap');
        this.chatPanel.render(centerUnit, this.layout);

    }, this, true);

    this.panel.render(document.body);

    var resize = new YAHOO.util.Resize("dialog_" + this.remoteUsername, {
        handles: ['br'],
        autoRatio: true,
        minWidth: 100,
        minHeight: 200
    });

    resize.on('resize', function(args) {
       var panelHeight = args.height;
       var headerHeight = this.panel.header.offsetHeight; // Content + Padding + Border
       var bodyHeight = (panelHeight - headerHeight);

        if(!IE_QUIRKS) { bodyHeight -= 20; }
        YAHOO.util.Dom.setStyle(this.panel.header, 'width',
                                args.width-20+ 'px');
        YAHOO.util.Dom.setStyle(this.panel.body, 'height', bodyHeight + 'px');
        if (IE_SYNC) {
            this.panel.sizeUnderlay();
            this.panel.syncIframe();
        }

       this.layout.set('height', bodyHeight);
       this.layout.set('width', args.width-20);
       this.layout.resize();
    }, this, true);

    if (IE_SYNC) {
        YAHOO.util.Dom.setStyle(this.panel.header, 'width',
                                this.panel.body.clientWidth-20+ 'px');
        this.panel.sizeUnderlay();
        this.panel.syncIframe();
    }
};

// MAIN GLOBAL VARIABLES
var windowManager = new YAHOO.widget.OverlayManager();
var userList = new UserListWindow();

YAHOO.util.Event.onDOMReady(function () {
    // Show the User List
    userList.render();
    windowManager.register(userList.panel);
});

/********************************************
 *          MAIN CONTROL FUNCTIONS
 */

function openMessageWindow(jid, username) {
    if(!messageWindows.hasOwnProperty(jid)) {
        messageWindows[jid] = new MessageWindow(jid, username);
        messageWindows[jid].render();
        windowManager.register(messageWindows[jid].panel);
    }
    messageWindows[jid].panel.show();
}

////
// create xmpp client
// register callbacks
// connect to xmpp server
xmpp = new js.io.protocols.xmpp.Client();
xmpp.onPresence = function(ntype, from, to) {
    if (! ntype) {
        userList.onUserAvailable(from, from);
    }
    else if (ntype == "unavailable") {
        userList.onUserUnavailable(from);
    }
    else if (ntype == "subscribe") {
        xmpp.sendSubscribed(from, to);
    }
    else if (ntype == "subscribed") {
        alert(from + " added to your buddy list!");
    }
    else if (ntype == "unsubscribed") {
        userList.onUserUnavailable(from);
    }
}
xmpp.onMessage = onMessage;
xmpp.onSocketConnect = function() {
    domain = prompt("Domain","marionet");
    if (domain) {
        xmpp.connectServer(domain, connectSuccess, connectFailure);
    }
}
////
// 'localhost' is the machine running the ejabberd server
xmpp.connect('localhost', 5222);
////
// success / failure callbacks
function registerSuccess() {
    alert("Welcome!");
}
function registerFailure() {
    if (confirm("That user name is taken. Try again?")) {
        prompt_register();
    }
}
function loginSuccess() {
    alert("Welcome!");
}
function loginFailure() {
    if (confirm("Login failed. Register a new user account?")) {
        prompt_register();
    }
    else {
        prompt_login();
    }
}
function connectSuccess() {
    prompt_login();
}
function connectFailure() {
    alert("Unknown domain");
}
////
// helpers
function prompt_login() {
    var u = prompt("User name","frank");
    if (u) {
        var p = prompt("Password","pass");
        if (p) {
            xmpp.login(u, p, loginSuccess, loginFailure);
        }
    }
}
function prompt_register() {
    var u = prompt("New user name","ariel");
    if (u) {
        var p = prompt("New password","pass");
        if (p) {
            xmpp.register(u, p, registerSuccess, registerFailure);
        }
    }
}
////

/** Used to track the open message windows, keyed by JID */
var messageWindows = {};

/** Called when a message is received */
function onMessage(jid, username, text) {
    openMessageWindow(jid, username);
    messageWindows[jid].onMessage(username, text);
}

/** Called when the user clicks on a name in the user list */
function onUsernameClicked(user) {
    openMessageWindow(user.user_id, user.username);
}

/** Called when the user types a message to be sent */
function onSendMessage(toJid, toUsername, text) {
    // echo it in the window
    // TODO: I don't know how you'd track your own JID, so I put "Me"
    messageWindows[toJid].onMessage("Me", text);
    xmpp.msg(toJid, text);
}

/** Called when the user wants to add that contact */
function onAddContact(jid) {
    xmpp.subscribe(jid);
    alert("Buddy request sent.");
}

/** Called when the user clicks the user list's remove contact button */
function onRemoveContact(jid, username) {
    xmpp.unsubscribe(jid);
    userList.onUserUnavailable(jid);
}

/// SAMPLE DATA

//setTimeout(function() {
//    onMessage("foo@foo", "ASDFSADF", "Hello There");
//}, 3000);

//setTimeout(function(){
//    userList.onUserAvailable("marcus@jid.com", "Marcus Cavanaugh");
//    userList.onUserAvailable("asdf@asdf.com", "Michael Carter");
//}, 2000);
//setTimeout(function(){
//    userList.onUserUnavailable("marcus@jid.com");
//    userList.onUserAvailable("ggggg@ggggg.com", "Mario Balibrera");
//}, 4000);
//setTimeout(function(){
//    userList.onUserAvailable("marcus@jid.com", "Marcus Cavanaugh");
//    userList.onUserAvailable("steve@apple.com", "Steve Jobs");
//}, 5000);
//setTimeout(function(){
//    userList.onUserUnavailable("asdf@asdf.com");
//}, 7000);

// END SAMPLE DATA

/////////////////////////////////////////////////////////

/** @constructor */
function UserListWindow() {
}

UserListWindow.prototype.onUserAvailable = function (jid, username) {
    this.userList.addUser(new gp.User(jid, username));
    this.userList.update();
}
UserListWindow.prototype.onUserUnavailable = function (jid) {
    this.userList.removeUserID(jid);
    this.userList.update();
}

UserListWindow.prototype.render = function () {
    this.panel = new YAHOO.widget.Panel("userlist", {
        xy: [10,10],
        width: "200px",
        effect: {effect:YAHOO.widget.ContainerEffect.FADE, duration:0.5},
        constraintoviewport: true,
        close: true
    });

    this.panel.setHeader("User List");
    this.panel.setBody('');
    this.panel.renderEvent.subscribe(function () {
        this.layout.render();
    }, this, true);

    this.layout = new YAHOO.widget.Layout(this.panel.body, {
        height: 300,
        units: [
            {
                position: 'top',
                height: 35
            },
            { // User List
                position: 'center',
                gutter: '0'
            }
      ]
    });

    // rendering
    this.layout.on('render', function () {

        var topUnit = this.layout.getUnitByPosition('top').get('wrap');

        var addButton = new YAHOO.widget.Button({
                                id: "add",
                                type: "push",
                                label: "Add",
                                container: topUnit
                            });
        var removeButton = new YAHOO.widget.Button({
                                id: "remove",
                                type: "push",
                                label: "Remove",
                                container: topUnit
                            });

        addButton.get("element").firstChild.firstChild.hideFocus = true;
        removeButton.get("element").firstChild.firstChild.hideFocus = true;

        addButton.on("click", function (e) {
            addButton.blur();
            var jid = window.prompt("Enter the JID of the contact to add:", "");
            if(jid) {
                onAddContact(jid);
            }
        }, this, true);

        removeButton.on("click", function (e) {
            removeButton.blur();
            for(var i in this.userList.users) {
                var user = this.userList.users[i];
                if (user.selected) {
                    onRemoveContact(user.user_id, user.username);
                }
            }
        }, this, true);

        var centerUnit = this.layout.getUnitByPosition('center').get('wrap');
        this.userList = new gp.UserList(centerUnit);
        this.userList.render();

    }, this, true);

    this.panel.render(document.body);

    var resize = new YAHOO.util.Resize("userlist", {
        handles: ['br'],
        autoRatio: true,
        minWidth: 100,
        minHeight: 200
    });

    resize.on('resize', function(args) {
       var panelHeight = args.height;
       var headerHeight = this.panel.header.offsetHeight; // Content + Padding + Border
       var bodyHeight = (panelHeight - headerHeight);

        if(!IE_QUIRKS) { bodyHeight -= 20; }
        YAHOO.util.Dom.setStyle(this.panel.header, 'width', args.width-20+ 'px');
        YAHOO.util.Dom.setStyle(this.panel.body, 'height', bodyHeight + 'px');
        if (IE_SYNC) {
            this.panel.sizeUnderlay();
            this.panel.syncIframe();
        }

       this.layout.set('height', bodyHeight);
       this.layout.set('width', args.width-20);
       this.layout.resize();
    }, this, true);

    if (IE_SYNC) {
        YAHOO.util.Dom.setStyle(this.panel.header, 'width',
                                this.panel.body.clientWidth-20+ 'px');
        this.panel.sizeUnderlay();
        this.panel.syncIframe();
    }
}
<commit_msg>clarifying xmpp demo<commit_after>js.io.require('js.io.protocols.xmpp')

function MessageWindow(jid, username) {
    this.remoteUsername = username;
    this.remoteJid = jid;
}

MessageWindow.prototype.onMessage = function (user, text) {
    this.chatPanel.addChatMessage({username:user, text:text});
};

// QUIRKS FLAG, FOR BOX MODEL
var IE_QUIRKS = (YAHOO.env.ua.ie && document.compatMode == "BackCompat");

// UNDERLAY/IFRAME SYNC REQUIRED
var IE_SYNC = (YAHOO.env.ua.ie == 6 || (YAHOO.env.ua.ie == 7 && IE_QUIRKS));

// PADDING USED FOR BODY ELEMENT (Hardcoded for example)
var PANEL_BODY_PADDING = (10*2) // 10px top/bottom padding applied to Panel body element. The top/bottom border width is 0

/** Display the window. */
MessageWindow.prototype.render = function () {
    this.panel = new YAHOO.widget.Panel("dialog_" + this.remoteUsername, {
        xy: [Math.random() * 250 + 250,Math.random() * 250 + 50],
        width: "380px",
        effect: {effect:YAHOO.widget.ContainerEffect.FADE, duration:0.5},
        constraintoviewport: true,
        close: true
    });

    this.panel.setHeader("Chat with " + this.remoteUsername);
    this.panel.setBody('');
    this.panel.renderEvent.subscribe(function () {
        this.layout.render();

    }, this, true);

    this.layout = new YAHOO.widget.Layout(this.panel.body, {
        height: 300,
        units: [
            { // Chat Window
                position: 'center',
                gutter: '0'
            }
      ]
    });

    /** chat panel */
    this.chatPanel = new gp.ChatPanel();
    this.chatPanel.sendEvent.subscribe(function (type, args) {
        /** Call the global function for now */
        onSendMessage(this.remoteJid, this.remoteUsername, args[0]);
    }, this, true);

    // rendering
    this.layout.on('render', function () {

        var centerUnit = this.layout.getUnitByPosition('center').get('wrap');
        this.chatPanel.render(centerUnit, this.layout);

    }, this, true);

    this.panel.render(document.body);

    var resize = new YAHOO.util.Resize("dialog_" + this.remoteUsername, {
        handles: ['br'],
        autoRatio: true,
        minWidth: 100,
        minHeight: 200
    });

    resize.on('resize', function(args) {
       var panelHeight = args.height;
       var headerHeight = this.panel.header.offsetHeight; // Content + Padding + Border
       var bodyHeight = (panelHeight - headerHeight);

        if(!IE_QUIRKS) { bodyHeight -= 20; }
        YAHOO.util.Dom.setStyle(this.panel.header, 'width',
                                args.width-20+ 'px');
        YAHOO.util.Dom.setStyle(this.panel.body, 'height', bodyHeight + 'px');
        if (IE_SYNC) {
            this.panel.sizeUnderlay();
            this.panel.syncIframe();
        }

       this.layout.set('height', bodyHeight);
       this.layout.set('width', args.width-20);
       this.layout.resize();
    }, this, true);

    if (IE_SYNC) {
        YAHOO.util.Dom.setStyle(this.panel.header, 'width',
                                this.panel.body.clientWidth-20+ 'px');
        this.panel.sizeUnderlay();
        this.panel.syncIframe();
    }
};

// MAIN GLOBAL VARIABLES
var windowManager = new YAHOO.widget.OverlayManager();
var userList = new UserListWindow();

YAHOO.util.Event.onDOMReady(function () {
    // Show the User List
    userList.render();
    windowManager.register(userList.panel);
});

/********************************************
 *          MAIN CONTROL FUNCTIONS
 */

function openMessageWindow(jid, username) {
    if(!messageWindows.hasOwnProperty(jid)) {
        messageWindows[jid] = new MessageWindow(jid, username);
        messageWindows[jid].render();
        windowManager.register(messageWindows[jid].panel);
    }
    messageWindows[jid].panel.show();
}

////
// create xmpp client
// register callbacks
// connect to xmpp server
xmpp = new js.io.protocols.xmpp.Client();
xmpp.onPresence = function(ntype, from, to) {
    if (! ntype) {
        userList.onUserAvailable(from, from);
    }
    else if (ntype == "unavailable") {
        userList.onUserUnavailable(from);
    }
    else if (ntype == "subscribe") {
        xmpp.sendSubscribed(from, to);
    }
    else if (ntype == "subscribed") {
        alert(from + " added to your buddy list!");
    }
    else if (ntype == "unsubscribed") {
        userList.onUserUnavailable(from);
    }
}
xmpp.onMessage = onMessage;
xmpp.onSocketConnect = function() {
    domain = prompt("Domain","yourjabberdomain");
    if (domain) {
        xmpp.connectServer(domain, connectSuccess, connectFailure);
    }
}
////
// 'localhost' is the machine running the ejabberd server
xmpp.connect('localhost', 5222);
////
// success / failure callbacks
function registerSuccess() {
    alert("Welcome!");
}
function registerFailure() {
    if (confirm("That user name is taken. Try again?")) {
        prompt_register();
    }
}
function loginSuccess() {
    alert("Welcome!");
}
function loginFailure() {
    if (confirm("Login failed. Register a new user account?")) {
        prompt_register();
    }
    else {
        prompt_login();
    }
}
function connectSuccess() {
    prompt_login();
}
function connectFailure() {
    alert("Unknown domain");
}
////
// helpers
function prompt_login() {
    var u = prompt("User name","frank");
    if (u) {
        var p = prompt("Password","pass");
        if (p) {
            xmpp.login(u, p, loginSuccess, loginFailure);
        }
    }
}
function prompt_register() {
    var u = prompt("New user name","ariel");
    if (u) {
        var p = prompt("New password","pass");
        if (p) {
            xmpp.register(u, p, registerSuccess, registerFailure);
        }
    }
}
////

/** Used to track the open message windows, keyed by JID */
var messageWindows = {};

/** Called when a message is received */
function onMessage(jid, username, text) {
    openMessageWindow(jid, username);
    messageWindows[jid].onMessage(username, text);
}

/** Called when the user clicks on a name in the user list */
function onUsernameClicked(user) {
    openMessageWindow(user.user_id, user.username);
}

/** Called when the user types a message to be sent */
function onSendMessage(toJid, toUsername, text) {
    // echo it in the window
    // TODO: I don't know how you'd track your own JID, so I put "Me"
    messageWindows[toJid].onMessage("Me", text);
    xmpp.msg(toJid, text);
}

/** Called when the user wants to add that contact */
function onAddContact(jid) {
    xmpp.subscribe(jid);
    alert("Buddy request sent.");
}

/** Called when the user clicks the user list's remove contact button */
function onRemoveContact(jid, username) {
    xmpp.unsubscribe(jid);
    userList.onUserUnavailable(jid);
}

/// SAMPLE DATA

//setTimeout(function() {
//    onMessage("foo@foo", "ASDFSADF", "Hello There");
//}, 3000);

//setTimeout(function(){
//    userList.onUserAvailable("marcus@jid.com", "Marcus Cavanaugh");
//    userList.onUserAvailable("asdf@asdf.com", "Michael Carter");
//}, 2000);
//setTimeout(function(){
//    userList.onUserUnavailable("marcus@jid.com");
//    userList.onUserAvailable("ggggg@ggggg.com", "Mario Balibrera");
//}, 4000);
//setTimeout(function(){
//    userList.onUserAvailable("marcus@jid.com", "Marcus Cavanaugh");
//    userList.onUserAvailable("steve@apple.com", "Steve Jobs");
//}, 5000);
//setTimeout(function(){
//    userList.onUserUnavailable("asdf@asdf.com");
//}, 7000);

// END SAMPLE DATA

/////////////////////////////////////////////////////////

/** @constructor */
function UserListWindow() {
}

UserListWindow.prototype.onUserAvailable = function (jid, username) {
    this.userList.addUser(new gp.User(jid, username));
    this.userList.update();
}
UserListWindow.prototype.onUserUnavailable = function (jid) {
    this.userList.removeUserID(jid);
    this.userList.update();
}

UserListWindow.prototype.render = function () {
    this.panel = new YAHOO.widget.Panel("userlist", {
        xy: [10,10],
        width: "200px",
        effect: {effect:YAHOO.widget.ContainerEffect.FADE, duration:0.5},
        constraintoviewport: true,
        close: true
    });

    this.panel.setHeader("User List");
    this.panel.setBody('');
    this.panel.renderEvent.subscribe(function () {
        this.layout.render();
    }, this, true);

    this.layout = new YAHOO.widget.Layout(this.panel.body, {
        height: 300,
        units: [
            {
                position: 'top',
                height: 35
            },
            { // User List
                position: 'center',
                gutter: '0'
            }
      ]
    });

    // rendering
    this.layout.on('render', function () {

        var topUnit = this.layout.getUnitByPosition('top').get('wrap');

        var addButton = new YAHOO.widget.Button({
                                id: "add",
                                type: "push",
                                label: "Add",
                                container: topUnit
                            });
        var removeButton = new YAHOO.widget.Button({
                                id: "remove",
                                type: "push",
                                label: "Remove",
                                container: topUnit
                            });

        addButton.get("element").firstChild.firstChild.hideFocus = true;
        removeButton.get("element").firstChild.firstChild.hideFocus = true;

        addButton.on("click", function (e) {
            addButton.blur();
            var jid = window.prompt("Enter the JID of the contact to add:", "");
            if(jid) {
                onAddContact(jid);
            }
        }, this, true);

        removeButton.on("click", function (e) {
            removeButton.blur();
            for(var i in this.userList.users) {
                var user = this.userList.users[i];
                if (user.selected) {
                    onRemoveContact(user.user_id, user.username);
                }
            }
        }, this, true);

        var centerUnit = this.layout.getUnitByPosition('center').get('wrap');
        this.userList = new gp.UserList(centerUnit);
        this.userList.render();

    }, this, true);

    this.panel.render(document.body);

    var resize = new YAHOO.util.Resize("userlist", {
        handles: ['br'],
        autoRatio: true,
        minWidth: 100,
        minHeight: 200
    });

    resize.on('resize', function(args) {
       var panelHeight = args.height;
       var headerHeight = this.panel.header.offsetHeight; // Content + Padding + Border
       var bodyHeight = (panelHeight - headerHeight);

        if(!IE_QUIRKS) { bodyHeight -= 20; }
        YAHOO.util.Dom.setStyle(this.panel.header, 'width', args.width-20+ 'px');
        YAHOO.util.Dom.setStyle(this.panel.body, 'height', bodyHeight + 'px');
        if (IE_SYNC) {
            this.panel.sizeUnderlay();
            this.panel.syncIframe();
        }

       this.layout.set('height', bodyHeight);
       this.layout.set('width', args.width-20);
       this.layout.resize();
    }, this, true);

    if (IE_SYNC) {
        YAHOO.util.Dom.setStyle(this.panel.header, 'width',
                                this.panel.body.clientWidth-20+ 'px');
        this.panel.sizeUnderlay();
        this.panel.syncIframe();
    }
}
<|endoftext|>