123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929 |
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
- /*jshint scripturl:true */
- (function () {
- var defaultConfiguration = {
- // Disables clicks for a certain element.
- // (e.g., 'canvas' would not show clicks on canvas elements.)
- // Setting this to true will disable clicks globally.
- dontShowClicks: false,
- // Experimental feature to echo clicks to certain elements across clients:
- cloneClicks: false,
- // Enable Mozilla or Google analytics on the page when TogetherJS is activated:
- // FIXME: these don't seem to be working, and probably should be removed in favor
- // of the hub analytics
- enableAnalytics: false,
- // The code to enable (this is defaulting to a Mozilla code):
- analyticsCode: "UA-35433268-28",
- // The base URL of the hub (gets filled in below):
- hubBase: null,
- // A function that will return the name of the user:
- getUserName: null,
- // A function that will return the color of the user:
- getUserColor: null,
- // A function that will return the avatar of the user:
- getUserAvatar: null,
- // The siteName is used in the walkthrough (defaults to document.title):
- siteName: null,
- // Whether to use the minimized version of the code (overriding the built setting)
- useMinimizedCode: undefined,
- // Append cache-busting queries (useful for development!)
- cacheBust: true,
- // Any events to bind to
- on: {},
- // Hub events to bind to
- hub_on: {},
- // Enables the alt-T alt-T TogetherJS shortcut; however, this setting
- // must be enabled early as TogetherJSConfig_enableShortcut = true;
- enableShortcut: false,
- // The name of this tool as provided to users. The UI is updated to use this.
- // Because of how it is used in text it should be a proper noun, e.g.,
- // "MySite's Collaboration Tool"
- toolName: null,
- // Used to auto-start TogetherJS with a {prefix: pageName, max: participants}
- // Also with findRoom: "roomName" it will connect to the given room name
- findRoom: null,
- // If true, starts TogetherJS automatically (of course!)
- autoStart: false,
- // If true, then the "Join TogetherJS Session?" confirmation dialog
- // won't come up
- suppressJoinConfirmation: false,
- // If true, then the "Invite a friend" window won't automatically come up
- suppressInvite: false,
- // A room in which to find people to invite to this session,
- inviteFromRoom: null,
- // This is used to keep sessions from crossing over on the same
- // domain, if for some reason you want sessions that are limited
- // to only a portion of the domain:
- storagePrefix: "togetherjs",
- // When true, we treat the entire URL, including the hash, as the identifier
- // of the page; i.e., if you one person is on `http://example.com/#view1`
- // and another person is at `http://example.com/#view2` then these two people
- // are considered to be at completely different URLs
- includeHashInUrl: false,
- // When true, the WebRTC-based mic/chat will be disabled
- disableWebRTC: false,
- // When true, youTube videos will synchronize
- youtube: true,
- // Ignores the following console messages, disables all messages if set to true
- ignoreMessages: ["cursor-update", "keydown", "scroll-update"],
- // Ignores the following forms (will ignore all forms if set to true):
- ignoreForms: [":password"],
- // When undefined, attempts to use the browser's language
- lang: undefined,
- fallbackLang: "en-US"
- };
- var styleSheet = "/togetherjs/togetherjs.css";
- var baseUrl = "";
- if (baseUrl == "__" + "baseUrl__") {
- // Reset the variable if it doesn't get substituted
- baseUrl = "";
- }
- // Allow override of baseUrl (this is done separately because it needs
- // to be done very early)
- if (window.TogetherJSConfig && window.TogetherJSConfig.baseUrl) {
- baseUrl = window.TogetherJSConfig.baseUrl;
- }
- if (window.TogetherJSConfig_baseUrl) {
- baseUrl = window.TogetherJSConfig_baseUrl;
- }
- defaultConfiguration.baseUrl = baseUrl;
- // True if this file should use minimized sub-resources:
- var min = "yes" == "__" + "min__" ? false : "yes" == "yes";
- var baseUrlOverride = localStorage.getItem("togetherjs.baseUrlOverride");
- if (baseUrlOverride) {
- try {
- baseUrlOverride = JSON.parse(baseUrlOverride);
- } catch (e) {
- baseUrlOverride = null;
- }
- if ((! baseUrlOverride) || baseUrlOverride.expiresAt < Date.now()) {
- // Ignore because it has expired
- localStorage.removeItem("togetherjs.baseUrlOverride");
- } else {
- baseUrl = baseUrlOverride.baseUrl;
- var logger = console.warn || console.log;
- logger.call(console, "Using TogetherJS baseUrlOverride:", baseUrl);
- logger.call(console, "To undo run: localStorage.removeItem('togetherjs.baseUrlOverride')");
- }
- }
- var configOverride = localStorage.getItem("togetherjs.configOverride");
- if (configOverride) {
- try {
- configOverride = JSON.parse(configOverride);
- } catch (e) {
- configOverride = null;
- }
- if ((! configOverride) || configOverride.expiresAt < Date.now()) {
- localStorage.removeItem("togetherjs.configOverride");
- } else {
- var shownAny = false;
- for (var attr in configOverride) {
- if (! configOverride.hasOwnProperty(attr)) {
- continue;
- }
- if (attr == "expiresAt" || ! configOverride.hasOwnProperty(attr)) {
- continue;
- }
- if (! shownAny) {
- console.warn("Using TogetherJS configOverride");
- console.warn("To undo run: localStorage.removeItem('togetherjs.configOverride')");
- }
- window["TogetherJSConfig_" + attr] = configOverride[attr];
- console.log("Config override:", attr, "=", configOverride[attr]);
- }
- }
- }
- var version = "unknown";
- // FIXME: we could/should use a version from the checkout, at least
- // for production
- var cacheBust = "";
- if ((! cacheBust) || cacheBust == "") {
- cacheBust = Date.now() + "";
- } else {
- version = cacheBust;
- }
- // Make sure we have all of the console.* methods:
- if (typeof console == "undefined") {
- console = {};
- }
- if (! console.log) {
- console.log = function () {};
- }
- ["debug", "info", "warn", "error"].forEach(function (method) {
- if (! console[method]) {
- console[method] = console.log;
- }
- });
- if (! baseUrl) {
- var scripts = document.getElementsByTagName("script");
- for (var i=0; i<scripts.length; i++) {
- var src = scripts[i].src;
- if (src && src.search(/togetherjs(-min)?.js(\?.*)?$/) !== -1) {
- baseUrl = src.replace(/\/*togetherjs(-min)?.js(\?.*)?$/, "");
- console.warn("Detected baseUrl as", baseUrl);
- break;
- } else if (src && src.search(/togetherjs-min.js(\?.*)?$/) !== -1) {
- baseUrl = src.replace(/\/*togetherjs-min.js(\?.*)?$/, "");
- console.warn("Detected baseUrl as", baseUrl);
- break;
- }
- }
- }
- if (! baseUrl) {
- console.warn("Could not determine TogetherJS's baseUrl (looked for a <script> with togetherjs.js and togetherjs-min.js)");
- }
- function addStyle() {
- var existing = document.getElementById("togetherjs-stylesheet");
- if (! existing) {
- var link = document.createElement("link");
- link.id = "togetherjs-stylesheet";
- link.setAttribute("rel", "stylesheet");
- link.href = baseUrl + styleSheet +
- (cacheBust ? ("?bust=" + cacheBust) : '');
- document.head.appendChild(link);
- }
- }
- function addScript(url) {
- var script = document.createElement("script");
- script.src = baseUrl + url +
- (cacheBust ? ("?bust=" + cacheBust) : '');
- document.head.appendChild(script);
- }
- var TogetherJS = window.TogetherJS = function TogetherJS(event) {
- var session;
- if (TogetherJS.running) {
- session = TogetherJS.require("session");
- session.close();
- return;
- }
- TogetherJS.startup.button = null;
- try {
- if (event && typeof event == "object") {
- if (event.target && typeof event) {
- TogetherJS.startup.button = event.target;
- } else if (event.nodeType == 1) {
- TogetherJS.startup.button = event;
- } else if (event[0] && event[0].nodeType == 1) {
- // Probably a jQuery element
- TogetherJS.startup.button = event[0];
- }
- }
- } catch (e) {
- console.warn("Error determining starting button:", e);
- }
- if (window.TowTruckConfig) {
- console.warn("TowTruckConfig is deprecated; please use TogetherJSConfig");
- if (window.TogetherJSConfig) {
- console.warn("Ignoring TowTruckConfig in favor of TogetherJSConfig");
- } else {
- window.TogetherJSConfig = TowTruckConfig;
- }
- }
- if (window.TogetherJSConfig && (! window.TogetherJSConfig.loaded)) {
- TogetherJS.config(window.TogetherJSConfig);
- window.TogetherJSConfig.loaded = true;
- }
- // This handles loading configuration from global variables. This
- // includes TogetherJSConfig_on_*, which are attributes folded into
- // the "on" configuration value.
- var attr;
- var attrName;
- var globalOns = {};
- for (attr in window) {
- if (attr.indexOf("TogetherJSConfig_on_") === 0) {
- attrName = attr.substr(("TogetherJSConfig_on_").length);
- globalOns[attrName] = window[attr];
- } else if (attr.indexOf("TogetherJSConfig_") === 0) {
- attrName = attr.substr(("TogetherJSConfig_").length);
- TogetherJS.config(attrName, window[attr]);
- } else if (attr.indexOf("TowTruckConfig_on_") === 0) {
- attrName = attr.substr(("TowTruckConfig_on_").length);
- console.warn("TowTruckConfig_* is deprecated, please rename", attr, "to TogetherJSConfig_on_" + attrName);
- globalOns[attrName] = window[attr];
- } else if (attr.indexOf("TowTruckConfig_") === 0) {
- attrName = attr.substr(("TowTruckConfig_").length);
- console.warn("TowTruckConfig_* is deprecated, please rename", attr, "to TogetherJSConfig_" + attrName);
- TogetherJS.config(attrName, window[attr]);
- }
- }
- // FIXME: copy existing config?
- // FIXME: do this directly in TogetherJS.config() ?
- // FIXME: close these configs?
- var ons = TogetherJS.config.get("on");
- for (attr in globalOns) {
- if (globalOns.hasOwnProperty(attr)) {
- // FIXME: should we avoid overwriting? Maybe use arrays?
- ons[attr] = globalOns[attr];
- }
- }
- TogetherJS.config("on", ons);
- for (attr in ons) {
- TogetherJS.on(attr, ons[attr]);
- }
- var hubOns = TogetherJS.config.get("hub_on");
- if (hubOns) {
- for (attr in hubOns) {
- if (hubOns.hasOwnProperty(attr)) {
- TogetherJS.hub.on(attr, hubOns[attr]);
- }
- }
- }
- if (!TogetherJS.config.close('cacheBust')) {
- cacheBust = '';
- delete TogetherJS.requireConfig.urlArgs;
- }
- if (! TogetherJS.startup.reason) {
- // Then a call to TogetherJS() from a button must be started TogetherJS
- TogetherJS.startup.reason = "started";
- }
- // FIXME: maybe I should just test for TogetherJS.require:
- if (TogetherJS._loaded) {
- session = TogetherJS.require("session");
- addStyle();
- session.start();
- return;
- }
- // A sort of signal to session.js to tell it to actually
- // start itself (i.e., put up a UI and try to activate)
- TogetherJS.startup._launch = true;
- addStyle();
- var minSetting = TogetherJS.config.get("useMinimizedCode");
- TogetherJS.config.close("useMinimizedCode");
- if (minSetting !== undefined) {
- min = !! minSetting;
- }
- var requireConfig = TogetherJS._extend(TogetherJS.requireConfig);
- var deps = ["session", "jquery"];
- var lang = TogetherJS.getConfig("lang");
- // [igoryen]: We should generate this value in Gruntfile.js, based on the available translations
- var availableTranslations = {
- "en-US": true,
- "en": "en-US",
- "es": "es-BO",
- "es-BO": true,
- "ru": true,
- "ru-RU": "ru",
- "pl": "pl-PL",
- "pl-PL": true,
- "de-DE": true,
- "de": "de-DE"
- };
- if(lang === undefined) {
- // BCP 47 mandates hyphens, not underscores, to separate lang parts
- lang = navigator.language.replace(/_/g, "-");
- }
- if (/-/.test(lang) && !availableTranslations[lang]) {
- lang = lang.replace(/-.*$/, '');
- }
- if (!availableTranslations[lang]) {
- lang = TogetherJS.config.get("fallbackLang");
- } else if (availableTranslations[lang] !== true) {
- lang = availableTranslations[lang];
- }
- TogetherJS.config("lang", lang);
- var localeTemplates = "templates-" + lang;
- deps.splice(0, 0, localeTemplates);
- function callback(session, jquery) {
- TogetherJS._loaded = true;
- if (! min) {
- TogetherJS.require = require.config({context: "togetherjs"});
- TogetherJS._requireObject = require;
- }
- }
- if (! min) {
- if (typeof require == "function") {
- if (! require.config) {
- console.warn("The global require (", require, ") is not requirejs; please use togetherjs-min.js");
- throw new Error("Conflict with window.require");
- }
- TogetherJS.require = require.config(requireConfig);
- }
- }
- if (typeof TogetherJS.require == "function") {
- // This is an already-configured version of require
- TogetherJS.require(deps, callback);
- } else {
- requireConfig.deps = deps;
- requireConfig.callback = callback;
- if (! min) {
- window.require = requireConfig;
- }
- }
- if (min) {
- addScript("/togetherjs/togetherjsPackage.js");
- } else {
- addScript("/togetherjs/libs/require.js");
- }
- };
- TogetherJS.pageLoaded = Date.now();
- TogetherJS._extend = function (base, extensions) {
- if (! extensions) {
- extensions = base;
- base = {};
- }
- for (var a in extensions) {
- if (extensions.hasOwnProperty(a)) {
- base[a] = extensions[a];
- }
- }
- return base;
- };
- TogetherJS._startupInit = {
- // What element, if any, was used to start the session:
- button: null,
- // The startReason is the reason TogetherJS was started. One of:
- // null: not started
- // started: hit the start button (first page view)
- // joined: joined the session (first page view)
- reason: null,
- // Also, the session may have started on "this" page, or maybe is continued
- // from a past page. TogetherJS.continued indicates the difference (false the
- // first time TogetherJS is started or joined, true on later page loads).
- continued: false,
- // This is set to tell the session what shareId to use, if the boot
- // code knows (mostly because the URL indicates the id).
- _joinShareId: null,
- // This tells session to start up immediately (otherwise it would wait
- // for session.start() to be run)
- _launch: false
- };
- TogetherJS.startup = TogetherJS._extend(TogetherJS._startupInit);
- TogetherJS.running = false;
- TogetherJS.requireConfig = {
- context: "togetherjs",
- baseUrl: baseUrl + "/togetherjs",
- urlArgs: "bust=" + cacheBust,
- paths: {
- jquery: "libs/jquery-1.11.1.min",
- walkabout: "libs/walkabout/walkabout",
- esprima: "libs/walkabout/lib/esprima",
- falafel: "libs/walkabout/lib/falafel",
- tinycolor: "libs/tinycolor",
- whrandom: "libs/whrandom/random"
- }
- };
- TogetherJS._mixinEvents = function (proto) {
- proto.on = function on(name, callback) {
- if (typeof callback != "function") {
- console.warn("Bad callback for", this, ".once(", name, ", ", callback, ")");
- throw "Error: .once() called with non-callback";
- }
- if (name.search(" ") != -1) {
- var names = name.split(/ +/g);
- names.forEach(function (n) {
- this.on(n, callback);
- }, this);
- return;
- }
- if (this._knownEvents && this._knownEvents.indexOf(name) == -1) {
- var thisString = "" + this;
- if (thisString.length > 20) {
- thisString = thisString.substr(0, 20) + "...";
- }
- console.warn(thisString + ".on('" + name + "', ...): unknown event");
- if (console.trace) {
- console.trace();
- }
- }
- if (! this._listeners) {
- this._listeners = {};
- }
- if (! this._listeners[name]) {
- this._listeners[name] = [];
- }
- if (this._listeners[name].indexOf(callback) == -1) {
- this._listeners[name].push(callback);
- }
- };
- proto.once = function once(name, callback) {
- if (typeof callback != "function") {
- console.warn("Bad callback for", this, ".once(", name, ", ", callback, ")");
- throw "Error: .once() called with non-callback";
- }
- var attr = "onceCallback_" + name;
- // FIXME: maybe I should add the event name to the .once attribute:
- if (! callback[attr]) {
- callback[attr] = function onceCallback() {
- callback.apply(this, arguments);
- this.off(name, onceCallback);
- delete callback[attr];
- };
- }
- this.on(name, callback[attr]);
- };
- proto.off = proto.removeListener = function off(name, callback) {
- if (this._listenerOffs) {
- // Defer the .off() call until the .emit() is done.
- this._listenerOffs.push([name, callback]);
- return;
- }
- if (name.search(" ") != -1) {
- var names = name.split(/ +/g);
- names.forEach(function (n) {
- this.off(n, callback);
- }, this);
- return;
- }
- if ((! this._listeners) || ! this._listeners[name]) {
- return;
- }
- var l = this._listeners[name], _len = l.length;
- for (var i=0; i<_len; i++) {
- if (l[i] == callback) {
- l.splice(i, 1);
- break;
- }
- }
- };
- proto.emit = function emit(name) {
- var offs = this._listenerOffs = [];
- if ((! this._listeners) || ! this._listeners[name]) {
- return;
- }
- var args = Array.prototype.slice.call(arguments, 1);
- var l = this._listeners[name];
- l.forEach(function (callback) {
- callback.apply(this, args);
- }, this);
- delete this._listenerOffs;
- if (offs.length) {
- offs.forEach(function (item) {
- this.off(item[0], item[1]);
- }, this);
- }
- };
- return proto;
- };
- /* This finalizes the unloading of TogetherJS, including unloading modules */
- TogetherJS._teardown = function () {
- var requireObject = TogetherJS._requireObject || window.require;
- // FIXME: this doesn't clear the context for min-case
- if (requireObject.s && requireObject.s.contexts) {
- delete requireObject.s.contexts.togetherjs;
- }
- TogetherJS._loaded = false;
- TogetherJS.startup = TogetherJS._extend(TogetherJS._startupInit);
- TogetherJS.running = false;
- };
- TogetherJS._mixinEvents(TogetherJS);
- TogetherJS._knownEvents = ["ready", "close"];
- TogetherJS.toString = function () {
- return "TogetherJS";
- };
- var defaultHubBase = "https://togetherjs-hub.glitch.me/";
- if (defaultHubBase == "__" + "hubUrl"+ "__") {
- // Substitution wasn't made
- defaultHubBase = "https://hub.togetherjs.mozillalabs.com";
- }
- defaultConfiguration.hubBase = defaultHubBase;
- TogetherJS._configuration = {};
- TogetherJS._defaultConfiguration = {
- // Disables clicks for a certain element.
- // (e.g., 'canvas' would not show clicks on canvas elements.)
- // Setting this to true will disable clicks globally.
- dontShowClicks: false,
- // Experimental feature to echo clicks to certain elements across clients:
- cloneClicks: false,
- // Enable Mozilla or Google analytics on the page when TogetherJS is activated:
- // FIXME: these don't seem to be working, and probably should be removed in favor
- // of the hub analytics
- enableAnalytics: false,
- // The code to enable (this is defaulting to a Mozilla code):
- analyticsCode: "UA-35433268-28",
- // The base URL of the hub
- hubBase: defaultHubBase,
- // A function that will return the name of the user:
- getUserName: null,
- // A function that will return the color of the user:
- getUserColor: null,
- // A function that will return the avatar of the user:
- getUserAvatar: null,
- // The siteName is used in the walkthrough (defaults to document.title):
- siteName: null,
- // Whether to use the minimized version of the code (overriding the built setting)
- useMinimizedCode: undefined,
- // Any events to bind to
- on: {},
- // Hub events to bind to
- hub_on: {},
- // Enables the alt-T alt-T TogetherJS shortcut; however, this setting
- // must be enabled early as TogetherJSConfig_enableShortcut = true;
- enableShortcut: false,
- // The name of this tool as provided to users. The UI is updated to use this.
- // Because of how it is used in text it should be a proper noun, e.g.,
- // "MySite's Collaboration Tool"
- toolName: null,
- // Used to auto-start TogetherJS with a {prefix: pageName, max: participants}
- // Also with findRoom: "roomName" it will connect to the given room name
- findRoom: null,
- // If true, starts TogetherJS automatically (of course!)
- autoStart: false,
- // If true, then the "Join TogetherJS Session?" confirmation dialog
- // won't come up
- suppressJoinConfirmation: false,
- // If true, then the "Invite a friend" window won't automatically come up
- suppressInvite: false,
- // A room in which to find people to invite to this session,
- inviteFromRoom: null,
- // This is used to keep sessions from crossing over on the same
- // domain, if for some reason you want sessions that are limited
- // to only a portion of the domain:
- storagePrefix: "togetherjs",
- // When true, we treat the entire URL, including the hash, as the identifier
- // of the page; i.e., if you one person is on `http://example.com/#view1`
- // and another person is at `http://example.com/#view2` then these two people
- // are considered to be at completely different URLs
- includeHashInUrl: false,
- // The language to present the tool in, such as "en-US" or "ru-RU"
- // Note this must be set as TogetherJSConfig_lang, as it effects the loader
- // and must be set as soon as this file is included
- lang: null
- };
- // FIXME: there's a point at which configuration can't be updated
- // (e.g., hubBase after the TogetherJS has loaded). We should keep
- // track of these and signal an error if someone attempts to
- // reconfigure too late
- TogetherJS.getConfig = function (name) { // rename into TogetherJS.config.get()?
- var value = TogetherJS._configuration[name];
- if (value === undefined) {
- if (! TogetherJS._defaultConfiguration.hasOwnProperty(name)) {
- console.error("Tried to load unknown configuration value:", name);
- }
- value = TogetherJS._defaultConfiguration[name];
- }
- return value;
- };
- TogetherJS._defaultConfiguration = defaultConfiguration;
- TogetherJS._configTrackers = {};
- TogetherJS._configClosed = {};
- /* TogetherJS.config(configurationObject)
- or: TogetherJS.config(configName, value)
- Adds configuration to TogetherJS. You may also set the global variable TogetherJSConfig
- and when TogetherJS is started that configuration will be loaded.
- Unknown configuration values will lead to console error messages.
- */
- TogetherJS.config = function (name, maybeValue) {
- var settings;
- if (arguments.length == 1) {
- if (typeof name != "object") {
- throw new Error('TogetherJS.config(value) must have an object value (not: ' + name + ')');
- }
- settings = name;
- } else {
- settings = {};
- settings[name] = maybeValue;
- }
- var i;
- var tracker;
- var attr;
- for (attr in settings) {
- if (settings.hasOwnProperty(attr)) {
- if (TogetherJS._configClosed[attr] && TogetherJS.running) {
- throw new Error("The configuration " + attr + " is finalized and cannot be changed");
- }
- }
- }
- for (attr in settings) {
- if (! settings.hasOwnProperty(attr)) {
- continue;
- }
- if (attr == "loaded" || attr == "callToStart") {
- continue;
- }
- if (! TogetherJS._defaultConfiguration.hasOwnProperty(attr)) {
- console.warn("Unknown configuration value passed to TogetherJS.config():", attr);
- }
- var previous = TogetherJS._configuration[attr];
- var value = settings[attr];
- TogetherJS._configuration[attr] = value;
- var trackers = TogetherJS._configTrackers[name] || [];
- var failed = false;
- for (i=0; i<trackers.length; i++) {
- try {
- tracker = trackers[i];
- tracker(value, previous);
- } catch (e) {
- console.warn("Error setting configuration", name, "to", value,
- ":", e, "; reverting to", previous);
- failed = true;
- break;
- }
- }
- if (failed) {
- TogetherJS._configuration[attr] = previous;
- for (i=0; i<trackers.length; i++) {
- try {
- tracker = trackers[i];
- tracker(value);
- } catch (e) {
- console.warn("Error REsetting configuration", name, "to", previous,
- ":", e, "(ignoring)");
- }
- }
- }
- }
- };
- TogetherJS.config.get = function (name) {
- var value = TogetherJS._configuration[name];
- if (value === undefined) {
- if (! TogetherJS._defaultConfiguration.hasOwnProperty(name)) {
- console.error("Tried to load unknown configuration value:", name);
- }
- value = TogetherJS._defaultConfiguration[name];
- }
- return value;
- };
- TogetherJS.config.track = function (name, callback) {
- if (! TogetherJS._defaultConfiguration.hasOwnProperty(name)) {
- throw new Error("Configuration is unknown: " + name);
- }
- callback(TogetherJS.config.get(name));
- if (! TogetherJS._configTrackers[name]) {
- TogetherJS._configTrackers[name] = [];
- }
- TogetherJS._configTrackers[name].push(callback);
- return callback;
- };
- TogetherJS.config.close = function (name) {
- if (! TogetherJS._defaultConfiguration.hasOwnProperty(name)) {
- throw new Error("Configuration is unknown: " + name);
- }
- TogetherJS._configClosed[name] = true;
- return this.get(name);
- };
- TogetherJS.reinitialize = function () {
- if (TogetherJS.running && typeof TogetherJS.require == "function") {
- TogetherJS.require(["session"], function (session) {
- session.emit("reinitialize");
- });
- }
- // If it's not set, TogetherJS has not been loaded, and reinitialization is not needed
- };
- TogetherJS.refreshUserData = function () {
- if (TogetherJS.running && typeof TogetherJS.require == "function") {
- TogetherJS.require(["session"], function (session) {
- session.emit("refresh-user-data");
- });
- }
- };
- // This should contain the output of "git describe --always --dirty"
- // FIXME: substitute this on the server (and update make-static-client)
- TogetherJS.version = version;
- TogetherJS.baseUrl = baseUrl;
- TogetherJS.hub = TogetherJS._mixinEvents({});
- TogetherJS._onmessage = function (msg) {
- var type = msg.type;
- if (type.search(/^app\./) === 0) {
- type = type.substr("app.".length);
- } else {
- type = "togetherjs." + type;
- }
- msg.type = type;
- TogetherJS.hub.emit(msg.type, msg);
- };
- TogetherJS.send = function (msg) {
- if (! TogetherJS.require) {
- throw "You cannot use TogetherJS.send() when TogetherJS is not running";
- }
- var session = TogetherJS.require("session");
- session.appSend(msg);
- };
- TogetherJS.shareUrl = function () {
- if (! TogetherJS.require) {
- return null;
- }
- var session = TogetherJS.require("session");
- return session.shareUrl();
- };
- var listener = null;
- TogetherJS.listenForShortcut = function () {
- console.warn("Listening for alt-T alt-T to start TogetherJS");
- TogetherJS.removeShortcut();
- listener = function listener(event) {
- if (event.which == 84 && event.altKey) {
- if (listener.pressed) {
- // Second hit
- TogetherJS();
- } else {
- listener.pressed = true;
- }
- } else {
- listener.pressed = false;
- }
- };
- TogetherJS.once("ready", TogetherJS.removeShortcut);
- document.addEventListener("keyup", listener, false);
- };
- TogetherJS.removeShortcut = function () {
- if (listener) {
- document.addEventListener("keyup", listener, false);
- listener = null;
- }
- };
- TogetherJS.config.track("enableShortcut", function (enable, previous) {
- if (enable) {
- TogetherJS.listenForShortcut();
- } else if (previous) {
- TogetherJS.removeShortcut();
- }
- });
- TogetherJS.checkForUsersOnChannel = function (address, callback) {
- if (address.search(/^https?:/i) === 0) {
- address = address.replace(/^http/i, 'ws');
- }
- var socket = new WebSocket(address);
- var gotAnswer = false;
- socket.onmessage = function (event) {
- var msg = JSON.parse(event.data);
- if (msg.type != "init-connection") {
- console.warn("Got unexpected first message (should be init-connection):", msg);
- return;
- }
- if (gotAnswer) {
- console.warn("Somehow received two responses from channel; ignoring second");
- socket.close();
- return;
- }
- gotAnswer = true;
- socket.close();
- callback(msg.peerCount);
- };
- socket.onclose = socket.onerror = function () {
- if (! gotAnswer) {
- console.warn("Socket was closed without receiving answer");
- gotAnswer = true;
- callback(undefined);
- }
- };
- };
- // It's nice to replace this early, before the load event fires, so we conflict
- // as little as possible with the app we are embedded in:
- var hash = location.hash.replace(/^#/, "");
- var m = /&?togetherjs=([^&]*)/.exec(hash);
- if (m) {
- TogetherJS.startup._joinShareId = m[1];
- TogetherJS.startup.reason = "joined";
- var newHash = hash.substr(0, m.index) + hash.substr(m.index + m[0].length);
- location.hash = newHash;
- }
- if (window._TogetherJSShareId) {
- // A weird hack for something the addon does, to force a shareId.
- // FIXME: probably should remove, it's a wonky feature.
- TogetherJS.startup._joinShareId = window._TogetherJSShareId;
- delete window._TogetherJSShareId;
- }
- function conditionalActivate() {
- if (window.TogetherJSConfig_noAutoStart) {
- return;
- }
- // A page can define this function to defer TogetherJS from starting
- var callToStart = window.TogetherJSConfig_callToStart;
- if (! callToStart && window.TowTruckConfig_callToStart) {
- callToStart = window.TowTruckConfig_callToStart;
- console.warn("Please rename TowTruckConfig_callToStart to TogetherJSConfig_callToStart");
- }
- if (window.TogetherJSConfig && window.TogetherJSConfig.callToStart) {
- callToStart = window.TogetherJSConfig.callToStart;
- }
- if (callToStart) {
- // FIXME: need to document this:
- callToStart(onload);
- } else {
- onload();
- }
- }
- // FIXME: can we push this up before the load event?
- // Do we need to wait at all?
- function onload() {
- if (TogetherJS.startup._joinShareId) {
- TogetherJS();
- } else if (window._TogetherJSBookmarklet) {
- delete window._TogetherJSBookmarklet;
- TogetherJS();
- } else {
- // FIXME: this doesn't respect storagePrefix:
- var key = "togetherjs-session.status";
- var value = sessionStorage.getItem(key);
- if (value) {
- value = JSON.parse(value);
- if (value && value.running) {
- TogetherJS.startup.continued = true;
- TogetherJS.startup.reason = value.startupReason;
- TogetherJS();
- }
- } else if (window.TogetherJSConfig_autoStart ||
- (window.TogetherJSConfig && window.TogetherJSConfig.autoStart)) {
- TogetherJS.startup.reason = "joined";
- TogetherJS();
- }
- }
- }
- conditionalActivate();
- // FIXME: wait until load event to double check if this gets set?
- if (window.TogetherJSConfig_enableShortcut) {
- TogetherJS.listenForShortcut();
- }
- // For compatibility:
- window.TowTruck = TogetherJS;
- })();
|