WebRTC audio/video call and conferencing server.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

304 lines
8.1 KiB

/*
* Spreed WebRTC.
* Copyright (C) 2013-2015 struktur AG
*
* This file is part of Spreed WebRTC.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
"use strict";
define([
'require',
'jquery',
'underscore',
'angular',
'modernizr',
'moment',
'services/services',
'directives/directives',
'filters/filters',
'controllers/controllers',
'translation/languages',
'ui-bootstrap',
'angular-sanitize',
'angular-animate',
'angular-humanize',
'angular-route',
'mobile-events'
], function(require, $, _, angular, modernizr, moment, services, directives, filters, controllers, languages) {
// Simple and fast split based URL query parser based on location.search. We require this before the
// angular App is bootstrap to control initialization parameters like translation based on URL parameters.
var urlQuery = (function() {
return (function(a) {
if (a === "") {
return {};
}
var b = {};
for (var i = 0; i < a.length; ++i) {
var p = a[i].split('=');
if (p.length != 2) {
continue;
}
b[p[0]] = window.decodeURIComponent(p[1].replace(/\+/g, " "));
}
return b;
})(window.location.search.substr(1).split("&"));
}());
// Base application config shared during initialization.
var appConfig = {};
// Implement translation store.
var TranslationData = function(default_language, launcher) {
// Create data structure.
this.data = {
locale_data: {}
};
this.lang = this.default_lang = default_language;
this.getHTTP = launcher.$http.get;
};
TranslationData.prototype.language = function() {
// Return language.
return this.lang;
};
TranslationData.prototype.default_language = function() {
return this.default_lang;
};
TranslationData.prototype.add = function(domain, data) {
var src;
if (data && data.locale_data) {
src = data.locale_data[domain];
// Support older po files built for older jed (see https://github.com/SlexAxton/Jed/issues/36).
var count = 0;
var v;
for (var k in src) {
if (src.hasOwnProperty(k)) {
v = src[k];
if (v.constructor === Array && v[0] === null) {
v.shift();
} else {
count++;
}
if (count > 1) {
break;
}
}
}
}
var dst = this.data.locale_data[domain];
if (!dst) {
dst = this.data.locale_data[domain] = {
"": {
"domain": domain,
"plural_forms": "nplurals=2; plural=(n != 1);"
}
}
}
_.extend(dst, src);
};
TranslationData.prototype.load = function(domain, url) {
var that = this;
return this.getHTTP(url).
success(function(data) {
//console.log("loaded translation data", data);
that.add(domain, data);
}).
error(function(data, status) {
console.warn("Failed to load translation data: " + status);
that.add(domain, null);
});
};
TranslationData.prototype.get = function() {
return this.data;
};
var create = function(ms, launcher) {
// Create translation data instance.
var translationData = launcher.translationData = new TranslationData("en", launcher);
var modules = ['ui.bootstrap', 'ngSanitize', 'ngAnimate', 'ngHumanize', 'ngRoute'];
if (ms && ms.length) {
_.each(ms, function(module) {
modules.push(module);
});
}
var app = angular.module('app', modules);
services.initialize(app);
directives.initialize(app);
filters.initialize(app);
controllers.initialize(app);
app.config(["$compileProvider", "$locationProvider", "$routeProvider", function($compileProvider, $locationProvider, $routeProvider) {
// Allow angular to use filesystem: hrefs which would else be prefixed with unsafe:.
$compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|tel|file|filesystem|blob):/);
$compileProvider.imgSrcSanitizationWhitelist(/^\s*(https?|ftp|file|filesystem|blob):|data:image\//);
// Setup routing
$routeProvider.when("/:room*", {});
// Use HTML5 routing.
$locationProvider.html5Mode(true);
}]);
app.run(["$rootScope", "$timeout", "mediaStream", "translation", "continueConnector", function($rootScope, $timeout, mediaStream, translation, continueConnector) {
translation.inject($rootScope);
console.log("Initializing ...");
var initialize = continueConnector.defer();
mediaStream.initialize($rootScope, translation);
$timeout(function() {
console.log("Initializing complete.")
initialize.resolve();
}, 0);
}]);
app.constant("availableLanguages", languages);
app.provider("translationData", function translationDataProvider() {
// Make available functions for config phase.
this.add = _.bind(translationData.add, translationData);
this.load = _.bind(translationData.load, translationData);
this.language = _.bind(translationData.language, translationData);
this.default_language = _.bind(translationData.default_language, translationData);
// Out creater returns raw data.
this.$get = [function translationDataFactory() {
return translationData.get();
}];
});
app.directive("spreedWebrtc", [function() {
return {
restrict: "A",
scope: false,
controller: "AppController"
}
}]);
app.directive("uiLogo", ["globalContext", function(globalContext) {
return {
restrict: "A",
link: function($scope, $element, $attrs) {
$attrs.$set("title", globalContext.Cfg.Title || "");
}
}
}]);
return app;
};
// Our client side API version as float. This value is incremented on
// breaking changes to plugins can check on it.
var apiversion = 1.1;
var initialize = function(app, launcher) {
var deferred = launcher.$q.defer();
var globalContext = JSON.parse(document.getElementById("globalcontext").innerHTML);
if (!globalContext.Cfg.Version) {
globalContext.Cfg.Version = "unknown";
}
app.constant("globalContext", globalContext);
// Configure language.
var lang = (function() {
var lang = "en";
var wanted = [];
var addLanguage = function(l) {
wanted.push(l);
if (l.indexOf("-") != -1) {
wanted.push(l.split("-")[0]);
}
};
// Get from storage.
if (modernizr.localstorage) {
var lsl = localStorage.getItem("mediastream-language");
if (lsl && lsl !== "undefined") {
wanted.push(lsl);
}
}
// Get from query.
var qsl = urlQuery.lang;
if (qsl) {
addLanguage(qsl);
}
// Get from server side configuration (As provided by browser).
_.each(globalContext.Languages, addLanguage);
// Loop through requested languages and use first one we have.
for (var i = 0; i < wanted.length; i++) {
if (languages.hasOwnProperty(wanted[i])) {
lang = wanted[i];
break;
}
}
// Storage at DOM.
var html = document.getElementsByTagName("html")[0];
html.setAttribute("lang", lang);
return lang;
}());
console.info("Selected language: "+lang);
// Set language and load default translations.
launcher.translationData.lang = lang;
var translationDomain = "messages";
if (lang === launcher.translationData.default_lang) {
// No need to load default language as it is built in.
launcher.translationData.add(translationDomain, null);
deferred.resolve();
} else {
// Load default translation catalog.
var url = require.toUrl('translation/'+translationDomain+"-"+lang+'.json');
launcher.translationData.load(translationDomain, url).then(function() {
deferred.resolve();
}, function() {
// Ignore errors.
deferred.resolve();
});
}
// Set momemt language.
moment.lang(lang);
return deferred.promise;
};
return {
create: create,
initialize: initialize,
query: urlQuery,
config: appConfig,
apiversion: apiversion
};
});